From d0dd8d11ece9d39b25c0dcdc8d98602847dffdf3 Mon Sep 17 00:00:00 2001 From: ameer2468 <33054370+ameer2468@users.noreply.github.com> Date: Tue, 19 Sep 2023 18:34:35 +0300 Subject: [PATCH] [ENG-1126] Key matcher hook (#1358) * key matcher hook * Update TopBarOptions.tsx --- .../app/$libraryId/Explorer/TopBarOptions.tsx | 21 ++++------- .../app/$libraryId/Explorer/View/index.tsx | 7 ++-- .../app/$libraryId/Layout/Sidebar/Footer.tsx | 22 +++--------- .../$libraryId/TopBar/NavigationButtons.tsx | 12 +++---- .../app/$libraryId/TopBar/TopBarOptions.tsx | 10 +++--- interface/hooks/index.ts | 1 + interface/hooks/useKeyMatcher.ts | 36 +++++++++++++++++++ 7 files changed, 60 insertions(+), 49 deletions(-) create mode 100644 interface/hooks/useKeyMatcher.ts diff --git a/interface/app/$libraryId/Explorer/TopBarOptions.tsx b/interface/app/$libraryId/Explorer/TopBarOptions.tsx index 51b6c9798..a26087c3b 100644 --- a/interface/app/$libraryId/Explorer/TopBarOptions.tsx +++ b/interface/app/$libraryId/Explorer/TopBarOptions.tsx @@ -11,8 +11,7 @@ import { import clsx from 'clsx'; import { useEffect, useRef } from 'react'; import { useRspcLibraryContext } from '@sd/client'; -import { ModifierKeys, modifierSymbols } from '@sd/ui'; -import { useOperatingSystem } from '~/hooks'; +import { useKeyMatcher } from '~/hooks'; import { KeyManager } from '../KeyManager'; import TopBarOptions, { ToolOption, TOP_BAR_ICON_STYLE } from '../TopBar/TopBarOptions'; @@ -24,15 +23,7 @@ import { useExplorerSearchParams } from './util'; export const useExplorerTopBarOptions = () => { const explorerStore = useExplorerStore(); const explorer = useExplorerContext(); - const os = useOperatingSystem(); - const controlSymbol = (letter: string) => { - return [ - os === 'macOS' - ? modifierSymbols[ModifierKeys.Meta][os] - : modifierSymbols[ModifierKeys.Control]['Other'], - letter - ] as string[]; - }; + const controlIcon = useKeyMatcher('Meta').icon; const settings = explorer.useSettingsSnapshot(); @@ -40,7 +31,7 @@ export const useExplorerTopBarOptions = () => { { toolTipLabel: 'Grid view', icon: , - keybinds: controlSymbol('V'), + keybinds: [controlIcon, 'V'], topBarActive: settings.layoutMode === 'grid', onClick: () => (explorer.settingsStore.layoutMode = 'grid'), showAtResolution: 'sm:flex' @@ -48,7 +39,7 @@ export const useExplorerTopBarOptions = () => { { toolTipLabel: 'List view', icon: , - keybinds: controlSymbol('V'), + keybinds: [controlIcon, 'V'], topBarActive: settings.layoutMode === 'list', onClick: () => (explorer.settingsStore.layoutMode = 'list'), showAtResolution: 'sm:flex' @@ -63,7 +54,7 @@ export const useExplorerTopBarOptions = () => { { toolTipLabel: 'Media view', icon: , - keybinds: controlSymbol('V'), + keybinds: [controlIcon, 'V'], topBarActive: settings.layoutMode === 'media', onClick: () => (explorer.settingsStore.layoutMode = 'media'), showAtResolution: 'sm:flex' @@ -80,7 +71,7 @@ export const useExplorerTopBarOptions = () => { }, { toolTipLabel: 'Show Inspector', - keybinds: controlSymbol('I'), + keybinds: [controlIcon, 'I'], onClick: () => (getExplorerStore().showInspector = !explorerStore.showInspector), icon: ( { const navigate = useNavigate(); const { library } = useLibraryContext(); const { openFilePaths } = usePlatform(); - const os = useOperatingSystem(); const updateAccessTime = useLibraryMutation('files.updateAccessTime'); - const metaCtrlKey = os === 'macOS' ? ModifierKeys.Meta : ModifierKeys.Control; + const metaCtrlKey = useKeyMatcher('Meta').key; useKeys([metaCtrlKey, 'ArrowUp'], async (e) => { e.stopPropagation(); @@ -287,7 +286,7 @@ export const EmptyNotice = (props: { icon?: Icon | ReactNode; message?: ReactNod }; return ( -
+
{props.icon ? isValidElement(props.icon) ? props.icon diff --git a/interface/app/$libraryId/Layout/Sidebar/Footer.tsx b/interface/app/$libraryId/Layout/Sidebar/Footer.tsx index 53f1b2be8..e55558214 100644 --- a/interface/app/$libraryId/Layout/Sidebar/Footer.tsx +++ b/interface/app/$libraryId/Layout/Sidebar/Footer.tsx @@ -1,16 +1,8 @@ import { Gear } from '@phosphor-icons/react'; import { useNavigate } from 'react-router'; import { JobManagerContextProvider, useClientContext, useDebugState } from '@sd/client'; -import { - Button, - ButtonLink, - dialogManager, - ModifierKeys, - modifierSymbols, - Popover, - Tooltip -} from '@sd/ui'; -import { useKeyBind, useOperatingSystem } from '~/hooks'; +import { Button, ButtonLink, dialogManager, ModifierKeys, Popover, Tooltip } from '@sd/ui'; +import { useKeyBind, useKeyMatcher, useOperatingSystem } from '~/hooks'; import DebugPopover from './DebugPopover'; import FeedbackDialog from './FeedbackDialog'; @@ -22,10 +14,6 @@ export default () => { const os = useOperatingSystem(); const navigate = useNavigate(); const jobManagerKeys = [os === 'macOS' ? ModifierKeys.Meta : ModifierKeys.Control, 'j']; - const recentJobsSymbol = - os === 'macOS' - ? modifierSymbols[ModifierKeys.Meta][os] - : modifierSymbols[ModifierKeys.Control]['Other']; useKeyBind(['g', 's'], (e) => { e.stopPropagation(); @@ -34,7 +22,7 @@ export default () => { return (
-
+
{ className="text-sidebar-inkFaint ring-offset-sidebar" > - + @@ -59,7 +47,7 @@ export default () => { {library && ( diff --git a/interface/app/$libraryId/TopBar/NavigationButtons.tsx b/interface/app/$libraryId/TopBar/NavigationButtons.tsx index 6fbd260b6..00a4aecb0 100644 --- a/interface/app/$libraryId/TopBar/NavigationButtons.tsx +++ b/interface/app/$libraryId/TopBar/NavigationButtons.tsx @@ -1,8 +1,7 @@ import { ArrowLeft, ArrowRight } from '@phosphor-icons/react'; import { useNavigate } from 'react-router'; -import { ModifierKeys, Tooltip } from '@sd/ui'; -import { useOperatingSystem, useSearchStore } from '~/hooks'; -import { keybindForOs } from '~/util/keybinds'; +import { Tooltip } from '@sd/ui'; +import { useKeyMatcher, useSearchStore } from '~/hooks'; import TopBarButton from './TopBarButton'; @@ -10,12 +9,11 @@ export const NavigationButtons = () => { const navigate = useNavigate(); const { isFocused } = useSearchStore(); const idx = history.state.idx as number; - const os = useOperatingSystem(); - const keybind = keybindForOs(os); + const controlIcon = useKeyMatcher('Meta').icon; return (
- + { - + { const toolsNotSmFlex = options ?.flatMap((group) => group) .filter((t) => t.showAtResolution !== 'sm:flex'); - const os = useOperatingSystem(); - const keys = [os === 'macOS' ? ModifierKeys.Meta : ModifierKeys.Control, 'v']; + const metaCtrlKey = useKeyMatcher('Meta').key; - useKeyBind(keys, (e) => { + useKeyBind([metaCtrlKey, 'v'], (e) => { e.stopPropagation(); const explorerLayouts: ExplorerLayout[] = ['grid', 'list', 'media']; //based on the order of the icons const currentLayout = explorerLayouts.indexOf( @@ -59,7 +57,7 @@ export default ({ options }: TopBarChildrenProps) => { }, []); return ( -
+
{options?.map((group, groupIndex) => { return group.map( diff --git a/interface/hooks/index.ts b/interface/hooks/index.ts index 0ca47b00e..5f2689ca1 100644 --- a/interface/hooks/index.ts +++ b/interface/hooks/index.ts @@ -19,3 +19,4 @@ export * from './useTheme'; export * from './useZodRouteParams'; export * from './useZodSearchParams'; export * from './useIsTextTruncated'; +export * from './useKeyMatcher'; diff --git a/interface/hooks/useKeyMatcher.ts b/interface/hooks/useKeyMatcher.ts new file mode 100644 index 000000000..5e1be0082 --- /dev/null +++ b/interface/hooks/useKeyMatcher.ts @@ -0,0 +1,36 @@ +import { ModifierKeys, modifierSymbols } from "@sd/ui"; +import { OperatingSystem } from ".."; +import { useOperatingSystem } from "./useOperatingSystem"; + +type keysToMatch = 'Meta' | 'Alt' +type keysOsMap = Record +type osKeys = Record, icon: string}> + +//This is a helper function to handle the possibility of a modifier key being undefined due to OS initial check +const modifierKey = (key: keyof typeof ModifierKeys, os: 'Windows' | 'macOS' | 'Other') => { + return modifierSymbols[key][os] ?? modifierSymbols[key]['Other']; +} + +//Match macOS keys to Windows keys and others +const keysOsMap: keysOsMap = { + 'Meta': { + 'macOS': {key: 'Meta', icon: modifierKey(ModifierKeys.Meta, 'macOS') }, + 'windows': {key: 'Control', icon: modifierKey(ModifierKeys.Control, 'Windows') }, + 'browser': {key: 'Control', icon: modifierKey(ModifierKeys.Control, 'Windows') }, + 'linux': {key: 'Control', icon: modifierKey(ModifierKeys.Control, 'Windows') }, + 'unknown': {key: 'Control', icon: modifierKey(ModifierKeys.Control, 'Windows') }, + }, + 'Alt': { + 'macOS': {key: 'Alt', icon: modifierKey(ModifierKeys.Alt, 'macOS') }, + 'windows': {key: 'Alt', icon: modifierKey(ModifierKeys.Alt, 'Other') }, + 'browser': {key: 'Alt', icon: modifierKey(ModifierKeys.Alt, 'Other') }, + 'linux': {key: 'Alt', icon: modifierKey(ModifierKeys.Alt, 'Other') }, + 'unknown': {key: 'Alt', icon: modifierKey(ModifierKeys.Alt, 'Other') }, + }, +} as const + +export function useKeyMatcher(arg: keyof typeof keysOsMap): osKeys[OperatingSystem] { + const os = useOperatingSystem(); + const key = keysOsMap[arg][os]; + return key; +}