diff --git a/apps/desktop/layer/renderer/src/modules/subscription-column/SubscriptionTabButton.tsx b/apps/desktop/layer/renderer/src/modules/subscription-column/SubscriptionTabButton.tsx index 7062b8228..611fc27d3 100644 --- a/apps/desktop/layer/renderer/src/modules/subscription-column/SubscriptionTabButton.tsx +++ b/apps/desktop/layer/renderer/src/modules/subscription-column/SubscriptionTabButton.tsx @@ -7,12 +7,16 @@ import type { FC } from "react" import { startTransition, useCallback } from "react" import { useTranslation } from "react-i18next" -import { useUISettingKey } from "~/atoms/settings/ui" +import { MenuItemText, useShowContextMenu } from "~/atoms/context-menu" +import { setUISetting, useUISettingKey } from "~/atoms/settings/ui" import { FocusablePresets } from "~/components/common/Focusable" import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry" import { parseView, useRouteParamsSelector } from "~/hooks/biz/useRouteParams" +import { useTimelineList } from "~/hooks/biz/useTimelineList" +import { useContextMenu } from "~/hooks/common/useContextMenu" import { resetSelectedFeedIds } from "./atom" +import { useShowTimelineTabsSettingsModal } from "./TimelineTabsSettingsModal" export function SubscriptionTabButton({ timelineId, @@ -25,35 +29,125 @@ export function SubscriptionTabButton({ const isActive = activeTimelineId === timelineId const navigate = useNavigateEntry() + const navigateToTimeline = useCallback( + (nextTimelineId: string) => { + navigate({ + timelineId: nextTimelineId, + feedId: null, + entryId: null, + }) + resetSelectedFeedIds() + }, + [navigate], + ) const setActive = useCallback(() => { - navigate({ - timelineId, - feedId: null, - entryId: null, - }) - resetSelectedFeedIds() - }, [navigate, timelineId]) + navigateToTimeline(timelineId) + }, [navigateToTimeline, timelineId]) const view = parseView(timelineId) if (view === FeedViewType.All) { - return + return ( + + ) } else if (typeof view === "number") { return ( - + ) } } +const useSubscriptionTabContextMenu = ({ + timelineId, + isActive, + navigateToTimeline, +}: { + timelineId: string + isActive: boolean + navigateToTimeline: (timelineId: string) => void +}) => { + const { t } = useTranslation() + const showContextMenu = useShowContextMenu() + const showTimelineTabsSettingsModal = useShowTimelineTabsSettingsModal() + const visibleTimelineList = useTimelineList({ withAll: true, visible: true }) + const hiddenTimelineList = useTimelineList({ withAll: true, hidden: true }) + + const canHide = visibleTimelineList.filter((id) => id !== timelineId).length > 0 + + const handleHide = useCallback(() => { + if (!canHide) return + + const nextVisible = visibleTimelineList.filter((id) => id !== timelineId) + const nextHidden = hiddenTimelineList.filter((id) => id !== timelineId).concat(timelineId) + setUISetting("timelineTabs", { + visible: nextVisible, + hidden: nextHidden, + }) + + if (isActive) { + const currentIndex = visibleTimelineList.indexOf(timelineId) + const fallbackTimelineId = + nextVisible[currentIndex] ?? nextVisible[currentIndex - 1] ?? nextVisible[0] + + if (fallbackTimelineId) { + navigateToTimeline(fallbackTimelineId) + } + } + }, [canHide, hiddenTimelineList, isActive, navigateToTimeline, timelineId, visibleTimelineList]) + + const contextMenuProps = useContextMenu({ + onContextMenu: async (event) => { + event.preventDefault() + event.stopPropagation() + await showContextMenu( + [ + new MenuItemText({ + label: t("sidebar.timeline_tabs.hide_tab"), + click: handleHide, + disabled: !canHide, + }), + new MenuItemText({ + label: t("sidebar.timeline_tabs.customize"), + click: showTimelineTabsSettingsModal, + }), + ], + event, + ) + }, + }) + + return contextMenuProps +} + const ViewAllSwitchButton: FC<{ + timelineId: string isActive: boolean setActive: () => void shortcut: string -}> = ({ isActive, setActive, shortcut }) => { + navigateToTimeline: (timelineId: string) => void +}> = ({ timelineId, isActive, setActive, shortcut, navigateToTimeline }) => { const unreadByView = useUnreadByView(FeedViewType.All) const { t } = useTranslation() const showSidebarUnreadCount = useUISettingKey("sidebarShowUnreadCount") const item = getView(FeedViewType.All) + const contextMenuProps = useSubscriptionTabContextMenu({ + timelineId, + isActive, + navigateToTimeline, + }) return ( { startTransition(() => { setActive() @@ -92,10 +187,12 @@ const ViewAllSwitchButton: FC<{ const ViewSwitchButton: FC<{ view: FeedViewType + timelineId: string isActive: boolean setActive: () => void shortcut: string -}> = ({ view, isActive, setActive, shortcut }) => { + navigateToTimeline: (timelineId: string) => void +}> = ({ view, timelineId, isActive, setActive, shortcut, navigateToTimeline }) => { const unreadByView = useUnreadByView(view) const { t } = useTranslation() const showSidebarUnreadCount = useUISettingKey("sidebarShowUnreadCount") @@ -107,6 +204,11 @@ const ViewSwitchButton: FC<{ view: item.view, }, }) + const contextMenuProps = useSubscriptionTabContextMenu({ + timelineId, + isActive, + navigateToTimeline, + }) return ( { startTransition(() => { setActive() diff --git a/apps/desktop/layer/renderer/src/modules/subscription-column/TimelineTabsSettingsModal.tsx b/apps/desktop/layer/renderer/src/modules/subscription-column/TimelineTabsSettingsModal.tsx index 1b562f7a1..6e44b8487 100644 --- a/apps/desktop/layer/renderer/src/modules/subscription-column/TimelineTabsSettingsModal.tsx +++ b/apps/desktop/layer/renderer/src/modules/subscription-column/TimelineTabsSettingsModal.tsx @@ -228,7 +228,7 @@ export const useShowTimelineTabsSettingsModal = () => { return useCallback(() => { present({ id: "timeline-tabs-settings", - title: "Customize Timeline Tabs", + title: "Customize View Tabs", content: () => , overlay: true, clickOutsideToDismiss: true, diff --git a/locales/app/en.json b/locales/app/en.json index 562a97568..b884c6a01 100644 --- a/locales/app/en.json +++ b/locales/app/en.json @@ -392,6 +392,8 @@ "sidebar.feed_column.context_menu.rename_category_success": "Category renamed successfully", "sidebar.feed_column.context_menu.title": "Move to New Category", "sidebar.select_sort_method": "Select a sort method", + "sidebar.timeline_tabs.customize": "Customize View Tabs...", + "sidebar.timeline_tabs.hide_tab": "Hide this view", "signin.continue_with": "Continue with {{provider}}", "signin.sign_in_to": "Sign in to", "signin.sign_up_to": "Sign up to", diff --git a/locales/app/ja.json b/locales/app/ja.json index 27ce764c1..e60c93dc0 100644 --- a/locales/app/ja.json +++ b/locales/app/ja.json @@ -387,6 +387,8 @@ "sidebar.feed_column.context_menu.rename_category_success": "カテゴリーのリネームに成功しました", "sidebar.feed_column.context_menu.title": "新規カテゴリーに移動する", "sidebar.select_sort_method": "並べ替え方法を選択", + "sidebar.timeline_tabs.customize": "ビュータブをカスタマイズ...", + "sidebar.timeline_tabs.hide_tab": "このビューを非表示にする", "signin.continue_with": "{{provider}} で続ける", "signin.sign_in_to": "サインイン", "signin.sign_up_to": "サインアップ", diff --git a/locales/app/zh-CN.json b/locales/app/zh-CN.json index be9c649ac..ae1353754 100644 --- a/locales/app/zh-CN.json +++ b/locales/app/zh-CN.json @@ -390,6 +390,8 @@ "sidebar.feed_column.context_menu.rename_category_success": "分类重命名成功", "sidebar.feed_column.context_menu.title": "移动至新分类", "sidebar.select_sort_method": "选择排序方法", + "sidebar.timeline_tabs.customize": "自定义视图标签...", + "sidebar.timeline_tabs.hide_tab": "隐藏此视图", "signin.continue_with": "使用 {{provider}} 登录", "signin.sign_in_to": "登录", "signin.sign_up_to": "注册", diff --git a/locales/settings/en.json b/locales/settings/en.json index 577cd811c..2f4c5c75e 100644 --- a/locales/settings/en.json +++ b/locales/settings/en.json @@ -129,7 +129,7 @@ "appearance.custom_font": "Custom Font", "appearance.customization.title": "Customization", "appearance.customize_sub_tabs.description": "Customize the subscription tabs to your liking.", - "appearance.customize_sub_tabs.label": "Customize Subscription Tabs", + "appearance.customize_sub_tabs.label": "Customize View Tabs", "appearance.customize_toolbar.description": "Customize the entry content toolbar to your liking.", "appearance.customize_toolbar.label": "Customize Toolbar", "appearance.date_format.description": "Adjust the display date format.",