From 737d40c8519cf7fd3568925951a2ce7afdf32ec4 Mon Sep 17 00:00:00 2001 From: Jerry Wong Date: Tue, 15 Oct 2024 18:48:21 +0800 Subject: [PATCH] refactor: improve native menu item handling * Refactor useFeedActions component to conditionally add a separator in the menu list based on the length of listByView array. Refactor FeedCategoryImpl component to conditionally add a separator in the menu list based on the length of listList array. * update * fix: type Signed-off-by: Innei --------- Signed-off-by: Innei Co-authored-by: Innei --- .../renderer/src/hooks/biz/useFeedActions.tsx | 4 +- apps/renderer/src/lib/native-menu.ts | 64 +++++++++++++------ .../src/modules/feed-column/category.tsx | 30 +++++---- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/apps/renderer/src/hooks/biz/useFeedActions.tsx b/apps/renderer/src/hooks/biz/useFeedActions.tsx index 02420b565..d66e65ef0 100644 --- a/apps/renderer/src/hooks/biz/useFeedActions.tsx +++ b/apps/renderer/src/hooks/biz/useFeedActions.tsx @@ -116,9 +116,7 @@ export const useFeedActions = ({ }, } }), - { - type: "separator", - }, + listByView.length > 0 && { type: "separator" as const }, { label: t("sidebar.feed_actions.create_list"), type: "text" as const, diff --git a/apps/renderer/src/lib/native-menu.ts b/apps/renderer/src/lib/native-menu.ts index f09f83f55..c49e13bb0 100644 --- a/apps/renderer/src/lib/native-menu.ts +++ b/apps/renderer/src/lib/native-menu.ts @@ -4,22 +4,39 @@ import { get } from "lodash-es" import { tipcClient } from "./client" import { getOS } from "./utils" -export type NativeMenuItem = ( - | { - type: "text" - label: string - click?: () => void - /** only work in web app */ - icon?: React.ReactNode - shortcut?: string - disabled?: boolean - submenu?: NativeMenuItem[] - checked?: boolean - } - | { type: "separator"; disabled?: boolean } -) & { hide?: boolean } +type MenuItemWithHide = T & { + hide?: boolean +} -export type NullableNativeMenuItem = NativeMenuItem | null | undefined | false | "" +type BaseMenuItemText = MenuItemWithHide<{ + type: "text" + label: string + click?: () => void + /** only work in web app */ + icon?: React.ReactNode + shortcut?: string + disabled?: boolean + checked?: boolean +}> + +type BaseMenuItemSeparator = MenuItemWithHide<{ + type: "separator" + disabled?: boolean +}> + +type BaseMenuItem = BaseMenuItemText | BaseMenuItemSeparator + +export type NativeMenuItem = BaseMenuItem & { + submenu?: NativeMenuItem[] +} + +export type NullableNativeMenuItem = + | (BaseMenuItemText & { submenu?: NullableNativeMenuItem[] }) + | BaseMenuItemSeparator + | null + | undefined + | false + | "" function sortShortcutsString(shortcut: string) { const order = ["Shift", "Ctrl", "Meta", "Alt"] @@ -37,19 +54,24 @@ function sortShortcutsString(shortcut: string) { return [...sortedModifiers, ...otherKeys].join("+") } -export const showNativeMenu = async ( - items: Array, - e?: MouseEvent | React.MouseEvent, -) => { - const nextItems = (items.filter((item) => item && !item.hide) as NativeMenuItem[]).map((item) => { + +function processMenuItems(items: NullableNativeMenuItem[]): NativeMenuItem[] { + return (items.filter((item) => item && !item.hide) as NativeMenuItem[]).map((item) => { if (item.type === "text") { return { ...item, shortcut: item.shortcut ? sortShortcutsString(item.shortcut) : undefined, + submenu: item.submenu ? processMenuItems(item.submenu) : undefined, } } return item - }) as NativeMenuItem[] + }) +} +export const showNativeMenu = async ( + items: Array, + e?: MouseEvent | React.MouseEvent, +) => { + const nextItems = processMenuItems(items) const el = e && e.currentTarget diff --git a/apps/renderer/src/modules/feed-column/category.tsx b/apps/renderer/src/modules/feed-column/category.tsx index e0ab3932d..19aa458d5 100644 --- a/apps/renderer/src/modules/feed-column/category.tsx +++ b/apps/renderer/src/modules/feed-column/category.tsx @@ -14,6 +14,7 @@ import { getRouteParams, useRouteParamsSelector } from "~/hooks/biz/useRoutePara import { useAnyPointDown, useInputComposition, useRefValue } from "~/hooks/common" import { stopPropagation } from "~/lib/dom" import type { FeedViewType } from "~/lib/enum" +import type { NullableNativeMenuItem } from "~/lib/native-menu" import { showNativeMenu } from "~/lib/native-menu" import { cn, sortByAlphabet } from "~/lib/utils" import { getPreferredTitle, useAddFeedToFeedList, useFeedStore } from "~/store/feed" @@ -166,6 +167,7 @@ function FeedCategoryImpl({ data: ids, view, categoryOpenStateData }: FeedCatego }} onContextMenu={(e) => { setIsContextMenuOpen(true) + showNativeMenu( [ { @@ -181,21 +183,23 @@ function FeedCategoryImpl({ data: ids, view, categoryOpenStateData }: FeedCatego { type: "text", label: t("sidebar.feed_column.context_menu.add_feeds_to_list"), - // @ts-expect-error + submenu: listList - ?.map((list) => ({ - label: list.title || "", - type: "text", - click() { - return addMutation.mutate({ - feedIds: ids, - listId: list.id, - }) - }, - })) + ?.map( + (list) => + ({ + label: list.title || "", + type: "text", + click() { + return addMutation.mutate({ + feedIds: ids, + listId: list.id, + }) + }, + }) as NullableNativeMenuItem, + ) + .concat(listList?.length > 0 ? [{ type: "separator" as const }] : []) .concat([ - // @ts-expect-error - { type: "separator" as const }, { label: t("sidebar.feed_actions.create_list"), type: "text" as const,