[ENG-1126] Key matcher hook (#1358)

* key matcher hook

* Update TopBarOptions.tsx
This commit is contained in:
ameer2468 2023-09-19 18:34:35 +03:00 committed by GitHub
parent 0382a4e48f
commit d0dd8d11ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 49 deletions

View file

@ -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: <SquaresFour className={TOP_BAR_ICON_STYLE} />,
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: <Rows className={TOP_BAR_ICON_STYLE} />,
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: <MonitorPlay className={TOP_BAR_ICON_STYLE} />,
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: (
<SidebarSimple

View file

@ -27,7 +27,7 @@ import {
} from '@sd/client';
import { ContextMenu, dialogManager, ModifierKeys, toast } from '@sd/ui';
import { Loader } from '~/components';
import { useOperatingSystem } from '~/hooks';
import { useKeyMatcher, useOperatingSystem } from '~/hooks';
import { isNonEmpty } from '~/util';
import { usePlatform } from '~/util/Platform';
@ -54,10 +54,9 @@ export const ViewItem = ({ data, children, ...props }: ViewItemProps) => {
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 (
<div className="flex flex-col items-center justify-center h-full text-ink-faint">
<div className="flex h-full flex-col items-center justify-center text-ink-faint">
{props.icon
? isValidElement(props.icon)
? props.icon

View file

@ -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 (
<div className="space-y-2">
<div className="flex items-center justify-between w-full">
<div className="flex w-full items-center justify-between">
<div className="flex">
<ButtonLink
to="settings/client/general"
@ -43,7 +31,7 @@ export default () => {
className="text-sidebar-inkFaint ring-offset-sidebar"
>
<Tooltip label="Settings" keybinds={['G', 'S']}>
<Gear className="w-5 h-5" />
<Gear className="h-5 w-5" />
</Tooltip>
</ButtonLink>
<JobManagerContextProvider>
@ -59,7 +47,7 @@ export default () => {
{library && (
<Tooltip
label="Recent Jobs"
keybinds={[recentJobsSymbol as string, 'J']}
keybinds={[useKeyMatcher('Meta').icon, 'J']}
>
<IsRunningJob />
</Tooltip>

View file

@ -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 (
<div data-tauri-drag-region className="flex">
<Tooltip keybinds={[keybind([ModifierKeys.Control], ['←'])]} label="Navigate back">
<Tooltip keybinds={[controlIcon, '←']} label="Navigate back">
<TopBarButton
rounding="left"
// className="text-[14px] text-ink-dull"
@ -25,7 +23,7 @@ export const NavigationButtons = () => {
<ArrowLeft size={14} className="m-[4px]" weight="bold" />
</TopBarButton>
</Tooltip>
<Tooltip keybinds={[keybind([ModifierKeys.Control], ['→'])]} label="Navigate forward">
<Tooltip keybinds={[controlIcon, '→']} label="Navigate forward">
<TopBarButton
rounding="right"
// className="text-[14px] text-ink-dull"

View file

@ -1,9 +1,8 @@
import clsx from 'clsx';
import { useLayoutEffect, useState } from 'react';
import { useKeys } from 'rooks';
import { ModifierKeys, Popover, Tooltip } from '@sd/ui';
import { ExplorerLayout } from '~/../packages/client/src';
import { useKeyBind, useOperatingSystem } from '~/hooks';
import { useKeyBind, useKeyMatcher } from '~/hooks';
import { useExplorerContext } from '../Explorer/Context';
import TopBarButton from './TopBarButton';
@ -34,10 +33,9 @@ export default ({ options }: TopBarChildrenProps) => {
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 (
<div data-tauri-drag-region className="flex justify-end flex-1">
<div data-tauri-drag-region className="flex flex-1 justify-end">
<div data-tauri-drag-region className={`flex gap-0`}>
{options?.map((group, groupIndex) => {
return group.map(

View file

@ -19,3 +19,4 @@ export * from './useTheme';
export * from './useZodRouteParams';
export * from './useZodSearchParams';
export * from './useIsTextTruncated';
export * from './useKeyMatcher';

View file

@ -0,0 +1,36 @@
import { ModifierKeys, modifierSymbols } from "@sd/ui";
import { OperatingSystem } from "..";
import { useOperatingSystem } from "./useOperatingSystem";
type keysToMatch = 'Meta' | 'Alt'
type keysOsMap = Record<keysToMatch,osKeys>
type osKeys = Record<OperatingSystem, {key: Partial<keyof typeof ModifierKeys>, 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;
}