feat: enhance shortcut management and add new commands
- Removed the `$mod` replacement for `Meta` in shortcut handling to ensure proper cross-platform functionality. - Introduced new commands for "Open in Browser" and "Open Site in Browser" with corresponding shortcuts. - Updated the `useFeedActions` and `useListActions` hooks to utilize the new command shortcuts. - Improved the `transformShortcut` function for better platform-specific shortcut handling. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
0f5a0ad8b0
commit
6be20f483c
|
|
@ -56,7 +56,6 @@ export type FollowMenuItem = MenuItemText | MenuItemSeparator
|
|||
export type MenuItemInput = MenuItemText | MenuItemSeparator | NilValue
|
||||
|
||||
function sortShortcutsString(shortcut: string) {
|
||||
shortcut = shortcut.replace("$mod", "Meta")
|
||||
const order = ["Shift", "Ctrl", "Meta", "Alt"]
|
||||
const nextShortcut = transformShortcut(shortcut)
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ const shortcutConfigs = {
|
|||
name: tShortcuts("keys.subscriptions.openInBrowser"),
|
||||
key: "O",
|
||||
},
|
||||
openSiteInBrowser: {
|
||||
name: tShortcuts("keys.subscriptions.openSiteInBrowser"),
|
||||
key: "$mod+O",
|
||||
},
|
||||
markAllAsRead: {
|
||||
name: tShortcuts("keys.entries.markAllAsRead"),
|
||||
key: "Shift+$mod+A",
|
||||
|
|
|
|||
|
|
@ -13,11 +13,12 @@ import { MenuItemSeparator, MenuItemText } from "~/atoms/context-menu"
|
|||
import { useIsInMASReview } from "~/atoms/server-configs"
|
||||
import { whoami } from "~/atoms/user"
|
||||
import { useModalStack } from "~/components/ui/modal/stacked/hooks"
|
||||
import { shortcuts } from "~/constants/shortcuts"
|
||||
import { apiClient } from "~/lib/api-fetch"
|
||||
import { UrlBuilder } from "~/lib/url-builder"
|
||||
import { useBoostModal } from "~/modules/boost/hooks"
|
||||
import { useFeedClaimModal } from "~/modules/claim"
|
||||
import { COMMAND_ID } from "~/modules/command/commands/id"
|
||||
import { useCommandShortcuts } from "~/modules/command/hooks/use-command-binding"
|
||||
import { FeedForm } from "~/modules/discover/FeedForm"
|
||||
import { InboxForm } from "~/modules/discover/InboxForm"
|
||||
import { ListForm } from "~/modules/discover/ListForm"
|
||||
|
|
@ -46,11 +47,11 @@ const ConfirmDestroyModalContent = ({ onConfirm }: { onConfirm: () => void }) =>
|
|||
return (
|
||||
<div className="w-[540px]">
|
||||
<div className="mb-4">
|
||||
<i className="i-mingcute-warning-fill -mb-1 mr-1 size-5 text-red-500" />
|
||||
<i className="i-mingcute-warning-fill text-red -mb-1 mr-1 size-5" />
|
||||
{t("sidebar.feed_actions.unfollow_feed_many_warning")}
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<Button buttonClassName="bg-red-600" onClick={onConfirm}>
|
||||
<Button buttonClassName="bg-red" onClick={onConfirm}>
|
||||
{t("words.confirm")}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
@ -107,6 +108,8 @@ export const useFeedActions = ({
|
|||
|
||||
const isInMASReview = useIsInMASReview()
|
||||
|
||||
const shortcuts = useCommandShortcuts()
|
||||
|
||||
const items = useMemo(() => {
|
||||
const related = feed || inbox
|
||||
if (!related) return []
|
||||
|
|
@ -116,7 +119,7 @@ export const useFeedActions = ({
|
|||
const items: MenuItemInput[] = [
|
||||
new MenuItemText({
|
||||
label: t("sidebar.feed_actions.mark_all_as_read"),
|
||||
shortcut: "$mod+Shift+A",
|
||||
shortcut: shortcuts[COMMAND_ID.subscription.markAllAsRead],
|
||||
disabled: isEntryList,
|
||||
click: () =>
|
||||
subscriptionActions.markReadByFeedIds({
|
||||
|
|
@ -138,8 +141,10 @@ export const useFeedActions = ({
|
|||
}),
|
||||
...(isFeedOwner
|
||||
? [
|
||||
MenuItemSeparator.default,
|
||||
new MenuItemText({
|
||||
label: t("sidebar.feed_actions.feed_owned_by_you"),
|
||||
disabled: true,
|
||||
}),
|
||||
new MenuItemText({
|
||||
label: t("sidebar.feed_actions.reset_feed"),
|
||||
|
|
@ -147,6 +152,7 @@ export const useFeedActions = ({
|
|||
resetFeed(feedId)
|
||||
},
|
||||
}),
|
||||
MenuItemSeparator.default,
|
||||
]
|
||||
: []),
|
||||
...(!isInMASReview
|
||||
|
|
@ -294,7 +300,7 @@ export const useFeedActions = ({
|
|||
new MenuItemText({
|
||||
label: t("sidebar.feed_actions.navigate_to_feed"),
|
||||
shortcut: "$mod+G",
|
||||
disabled: isInbox || !isEntryList || getRouteParams().feedId === feedId,
|
||||
disabled: getRouteParams().feedId === feedId,
|
||||
click: () => {
|
||||
navigateEntry({ feedId })
|
||||
},
|
||||
|
|
@ -305,14 +311,14 @@ export const useFeedActions = ({
|
|||
which: t(IN_ELECTRON ? "words.browser" : "words.newTab"),
|
||||
}),
|
||||
disabled: isEntryList,
|
||||
shortcut: "O",
|
||||
shortcut: shortcuts[COMMAND_ID.subscription.openInBrowser],
|
||||
click: () => window.open(UrlBuilder.shareFeed(feedId, view), "_blank"),
|
||||
}),
|
||||
new MenuItemText({
|
||||
label: t("sidebar.feed_actions.open_site_in_browser", {
|
||||
which: t(IN_ELECTRON ? "words.browser" : "words.newTab"),
|
||||
}),
|
||||
shortcut: "$mod+O",
|
||||
shortcut: shortcuts[COMMAND_ID.subscription.openSiteInBrowser],
|
||||
disabled: isEntryList,
|
||||
click: () => {
|
||||
const feed = getFeedById(feedId)
|
||||
|
|
@ -364,7 +370,9 @@ export const useFeedActions = ({
|
|||
feed,
|
||||
inbox,
|
||||
t,
|
||||
shortcuts,
|
||||
isEntryList,
|
||||
isInMASReview,
|
||||
isInbox,
|
||||
listByView,
|
||||
categories,
|
||||
|
|
@ -396,18 +404,33 @@ export const useListActions = ({ listId, view }: { listId: string; view?: FeedVi
|
|||
const { present } = useModalStack()
|
||||
const { mutateAsync: deleteSubscription } = useDeleteSubscription({})
|
||||
|
||||
const shortcuts = useCommandShortcuts()
|
||||
const navigateEntry = useNavigateEntry()
|
||||
|
||||
const items = useMemo(() => {
|
||||
if (!list) return []
|
||||
|
||||
const items: MenuItemInput[] = [
|
||||
list.ownerUserId === whoami()?.id &&
|
||||
new MenuItemText({
|
||||
label: t("sidebar.feed_actions.list_owned_by_you"),
|
||||
}),
|
||||
list.ownerUserId !== whoami()?.id && MenuItemSeparator.default,
|
||||
...(list.ownerUserId === whoami()?.id
|
||||
? [
|
||||
new MenuItemText({
|
||||
label: t("sidebar.feed_actions.list_owned_by_you"),
|
||||
disabled: true,
|
||||
}),
|
||||
MenuItemSeparator.default,
|
||||
]
|
||||
: []),
|
||||
|
||||
new MenuItemText({
|
||||
label: t("sidebar.feed_actions.mark_all_as_read"),
|
||||
shortcut: shortcuts[COMMAND_ID.subscription.markAllAsRead],
|
||||
click: () => {
|
||||
subscriptionActions.markReadByFeedIds({
|
||||
feedIds: list.feedIds,
|
||||
})
|
||||
},
|
||||
}),
|
||||
MenuItemSeparator.default,
|
||||
new MenuItemText({
|
||||
label: t("sidebar.feed_actions.edit"),
|
||||
shortcut: "E",
|
||||
|
|
@ -436,7 +459,7 @@ export const useListActions = ({ listId, view }: { listId: string; view?: FeedVi
|
|||
label: t("sidebar.feed_actions.open_list_in_browser", {
|
||||
which: t(IN_ELECTRON ? "words.browser" : "words.newTab"),
|
||||
}),
|
||||
shortcut: shortcuts.subscriptions.openInBrowser.key,
|
||||
shortcut: shortcuts[COMMAND_ID.subscription.openInBrowser],
|
||||
click: () => window.open(UrlBuilder.shareList(listId, view), "_blank"),
|
||||
}),
|
||||
MenuItemSeparator.default,
|
||||
|
|
@ -457,7 +480,7 @@ export const useListActions = ({ listId, view }: { listId: string; view?: FeedVi
|
|||
]
|
||||
|
||||
return items
|
||||
}, [list, t, present, deleteSubscription, subscription, navigateEntry, listId, view])
|
||||
}, [list, t, shortcuts, listId, present, deleteSubscription, subscription, navigateEntry, view])
|
||||
|
||||
return items
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,5 +77,7 @@ export const COMMAND_ID = {
|
|||
|
||||
toggleFolderCollapse: "subscription:toggle-folder-collapse",
|
||||
markAllAsRead: "subscription:mark-all-as-read",
|
||||
openInBrowser: "subscription:open-in-browser",
|
||||
openSiteInBrowser: "subscription:open-site-in-browser",
|
||||
},
|
||||
} as const
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ declare module "@follow/utils/event-bus" {
|
|||
"subscription:previous": never
|
||||
"subscription:toggle-folder-collapse": never
|
||||
"subscription:mark-all-as-read": BizRouteParams
|
||||
"subscription:open-in-browser": never
|
||||
"subscription:open-site-in-browser": never
|
||||
}
|
||||
}
|
||||
const LABEL_PREFIX = "Subscription"
|
||||
|
|
@ -112,6 +114,20 @@ export const useRegisterSubscriptionCommands = () => {
|
|||
EventBus.dispatch(COMMAND_ID.subscription.markAllAsRead, routeParams)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: COMMAND_ID.subscription.openInBrowser,
|
||||
label: `${LABEL_PREFIX}: Open in Browser`,
|
||||
run: () => {
|
||||
EventBus.dispatch(COMMAND_ID.subscription.openInBrowser)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: COMMAND_ID.subscription.openSiteInBrowser,
|
||||
label: `${LABEL_PREFIX}: Open site in Browser`,
|
||||
run: () => {
|
||||
EventBus.dispatch(COMMAND_ID.subscription.openSiteInBrowser)
|
||||
},
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -175,6 +191,16 @@ type MarkAllAsReadCommand = Command<{
|
|||
fn: () => void
|
||||
}>
|
||||
|
||||
type OpenInBrowserCommand = Command<{
|
||||
id: typeof COMMAND_ID.subscription.openInBrowser
|
||||
fn: () => void
|
||||
}>
|
||||
|
||||
type OpenSiteInBrowserCommand = Command<{
|
||||
id: typeof COMMAND_ID.subscription.openSiteInBrowser
|
||||
fn: () => void
|
||||
}>
|
||||
|
||||
export type SubscriptionCommand =
|
||||
| SwitchTabToNextCommand
|
||||
| SwitchTabToPreviousCommand
|
||||
|
|
@ -188,3 +214,5 @@ export type SubscriptionCommand =
|
|||
| PreviousSubscriptionCommand
|
||||
| ToggleFolderCollapseCommand
|
||||
| MarkAllAsReadCommand
|
||||
| OpenInBrowserCommand
|
||||
| OpenSiteInBrowserCommand
|
||||
|
|
|
|||
|
|
@ -35,17 +35,23 @@ const defaultCommandShortcuts = {
|
|||
|
||||
[COMMAND_ID.subscription.toggleFolderCollapse]: shortcuts.subscriptions.toggleFolderCollapse.key,
|
||||
[COMMAND_ID.subscription.markAllAsRead]: shortcuts.subscriptions.markAllAsRead.key,
|
||||
[COMMAND_ID.subscription.openInBrowser]: shortcuts.subscriptions.openInBrowser.key,
|
||||
[COMMAND_ID.subscription.openSiteInBrowser]: shortcuts.subscriptions.openSiteInBrowser.key,
|
||||
} as const
|
||||
|
||||
export type BindingCommandId = keyof typeof defaultCommandShortcuts
|
||||
|
||||
// eslint-disable-next-line @eslint-react/hooks-extra/no-unnecessary-use-prefix, @eslint-react/hooks-extra/ensure-custom-hooks-using-other-hooks
|
||||
export const useCommandShortcut = (commandId: BindingCommandId): string => {
|
||||
const useCommandShortcut = (commandId: BindingCommandId): string => {
|
||||
const commandShortcut = defaultCommandShortcuts[commandId]
|
||||
|
||||
return commandShortcut
|
||||
}
|
||||
|
||||
export const useCommandShortcuts = () => {
|
||||
return defaultCommandShortcuts
|
||||
}
|
||||
|
||||
export const useCommandBinding = <T extends BindingCommandId>({
|
||||
commandId,
|
||||
when = true,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
"keys.subscriptions.add": "Add Subscription",
|
||||
"keys.subscriptions.nextSubscription": "Next Subscription",
|
||||
"keys.subscriptions.openInBrowser": "Open in Browser",
|
||||
"keys.subscriptions.openSiteInBrowser": "Open site in Browser",
|
||||
"keys.subscriptions.previousSubscription": "Previous Subscription",
|
||||
"keys.subscriptions.switchBetweenViews": "Switch Between Views",
|
||||
"keys.subscriptions.switchNextView": "Switch to Next View",
|
||||
|
|
|
|||
|
|
@ -345,10 +345,10 @@ export const toScientificNotation = (
|
|||
}
|
||||
|
||||
export function transformShortcut(shortcut: string, platform: OS = getOS()): string {
|
||||
if (platform === "Windows") {
|
||||
return shortcut.replace("Meta", "Ctrl").replace("meta", "ctrl")
|
||||
if (platform === "macOS") {
|
||||
return shortcut.replace("$mod", "Meta")
|
||||
}
|
||||
return shortcut
|
||||
return shortcut.replace("$mod", "Ctrl")
|
||||
}
|
||||
|
||||
// time like 1:30:00
|
||||
|
|
|
|||
Loading…
Reference in New Issue