add redo undo shortcuts

This commit is contained in:
Guy Ben-Aharon
2024-09-01 22:28:19 +03:00
committed by Guy Ben-Aharon
parent 635bd57d1a
commit f9c088e4ee
8 changed files with 161 additions and 5 deletions

11
package-lock.json generated
View File

@@ -43,6 +43,7 @@
"react": "^18.3.1",
"react-code-blocks": "^0.1.6",
"react-dom": "^18.3.1",
"react-hotkeys-hook": "^4.5.0",
"react-resizable-panels": "^2.0.22",
"react-responsive": "^10.0.0",
"react-router-dom": "^6.26.0",
@@ -8019,6 +8020,16 @@
"react": "^18.3.1"
}
},
"node_modules/react-hotkeys-hook": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.5.0.tgz",
"integrity": "sha512-Samb85GSgAWFQNvVt3PS90LPPGSf9mkH/r4au81ZP1yOIFayLC3QAvqTgGtJ8YEDMXtPmaVBs6NgipHO6h4Mug==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8.1",
"react-dom": ">=16.8.1"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",

View File

@@ -47,6 +47,7 @@
"react": "^18.3.1",
"react-code-blocks": "^0.1.6",
"react-dom": "^18.3.1",
"react-hotkeys-hook": "^4.5.0",
"react-resizable-panels": "^2.0.22",
"react-responsive": "^10.0.0",
"react-router-dom": "^6.26.0",

View File

@@ -0,0 +1,7 @@
import { createContext } from 'react';
export interface KeyboardShortcutsContext {}
export const keyboardShortcutsContext = createContext<KeyboardShortcutsContext>(
{}
);

View File

@@ -0,0 +1,29 @@
import React from 'react';
import { keyboardShortcutsContext } from './keyboard-shortcuts-context';
import { useHotkeys } from 'react-hotkeys-hook';
import {
KeyboardShortcutAction,
keyboardShortcutsForOS,
} from './keyboard-shortcuts';
import { useHistory } from '@/hooks/use-history';
export const KeyboardShortcutsProvider: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const { redo, undo } = useHistory();
useHotkeys(
keyboardShortcutsForOS[KeyboardShortcutAction.REDO].keyCombination,
redo,
[redo]
);
useHotkeys(
keyboardShortcutsForOS[KeyboardShortcutAction.UNDO].keyCombination,
undo,
[undo]
);
return (
<keyboardShortcutsContext.Provider value={{}}>
{children}
</keyboardShortcutsContext.Provider>
);
};

View File

@@ -0,0 +1,70 @@
import { getOperatingSystem } from '@/lib/utils';
export enum KeyboardShortcutAction {
REDO = 'redo',
UNDO = 'undo',
}
export interface KeyboardShortcut {
action: KeyboardShortcutAction;
keyCombinationLabelMac: string;
keyCombinationLabelWin: string;
keyCombinationMac: string;
keyCombinationWin: string;
}
export const keyboardShortcuts: Record<
KeyboardShortcutAction,
KeyboardShortcut
> = {
[KeyboardShortcutAction.REDO]: {
action: KeyboardShortcutAction.REDO,
keyCombinationLabelMac: '⇧⌘Z',
keyCombinationLabelWin: 'Ctrl+Shift+Z',
keyCombinationMac: 'meta+shift+z',
keyCombinationWin: 'ctrl+shift+z',
},
[KeyboardShortcutAction.UNDO]: {
action: KeyboardShortcutAction.UNDO,
keyCombinationLabelMac: '⌘Z',
keyCombinationLabelWin: 'Ctrl+Z',
keyCombinationMac: 'meta+z',
keyCombinationWin: 'ctrl+z',
},
};
export interface KeyboardShortcutForOS {
action: KeyboardShortcutAction;
keyCombinationLabel: string;
keyCombination: string;
}
const operatingSystem = getOperatingSystem();
export const keyboardShortcutsForOS: Record<
KeyboardShortcutAction,
KeyboardShortcutForOS
> = Object.keys(keyboardShortcuts).reduce(
(acc, action) => {
const keyboardShortcut =
keyboardShortcuts[action as KeyboardShortcutAction];
const keyCombinationLabel =
operatingSystem === 'mac'
? keyboardShortcut.keyCombinationLabelMac
: keyboardShortcut.keyCombinationLabelWin;
const keyCombination =
operatingSystem === 'mac'
? keyboardShortcut.keyCombinationMac
: keyboardShortcut.keyCombinationWin;
return {
...acc,
[action]: {
action: keyboardShortcut.action,
keyCombinationLabel,
keyCombination,
},
};
},
{} as Record<KeyboardShortcutAction, KeyboardShortcutForOS>
);

View File

@@ -13,3 +13,14 @@ export function cn(...inputs: ClassValue[]) {
export const emptyFn = (): any => undefined;
export const generateId = () => randomId();
export const getOperatingSystem = (): 'mac' | 'windows' | 'unknown' => {
const userAgent = window.navigator.userAgent;
if (userAgent.includes('Mac OS X')) {
return 'mac';
}
if (userAgent.includes('Windows')) {
return 'windows';
}
return 'unknown';
};

View File

@@ -33,6 +33,11 @@ import { useConfig } from '@/hooks/use-config';
import { IS_CHARTDB_IO } from '@/lib/env';
import { useBreakpoint } from '@/hooks/use-breakpoint';
import { DiagramIcon } from '@/components/diagram-icon/diagram-icon';
import {
KeyboardShortcutAction,
keyboardShortcutsForOS,
} from '@/context/keyboard-shortcuts-context/keyboard-shortcuts';
import { useHistory } from '@/hooks/use-history';
export interface TopNavbarProps {}
@@ -50,6 +55,7 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
openExportSQLDialog,
showAlert,
} = useDialog();
const { redo, undo, hasRedo, hasUndo } = useHistory();
const { isMd: isDesktop } = useBreakpoint('md');
const { config, updateConfig } = useConfig();
const [editMode, setEditMode] = useState(false);
@@ -398,8 +404,26 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
<MenubarMenu>
<MenubarTrigger>Edit</MenubarTrigger>
<MenubarContent>
<MenubarItem>Undo</MenubarItem>
<MenubarItem>Redo</MenubarItem>
<MenubarItem onClick={undo} disabled={!hasUndo}>
Undo
<MenubarShortcut>
{
keyboardShortcutsForOS[
KeyboardShortcutAction.UNDO
].keyCombinationLabel
}
</MenubarShortcut>
</MenubarItem>
<MenubarItem onClick={redo} disabled={!hasRedo}>
Redo
<MenubarShortcut>
{
keyboardShortcutsForOS[
KeyboardShortcutAction.REDO
].keyCombinationLabel
}
</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem
onClick={() =>

View File

@@ -13,6 +13,7 @@ import { DialogProvider } from './context/dialog-context/dialog-provider';
import { ExportImageProvider } from './context/export-image-context/export-image-provider';
import { FullScreenLoaderProvider } from './context/full-screen-spinner-context/full-screen-spinner-provider';
import { ExamplesPage } from './pages/examples-page/examples-page';
import { KeyboardShortcutsProvider } from './context/keyboard-shortcuts-context/keyboard-shortcuts-provider';
const routes: RouteObject[] = [
...['', 'diagrams/:diagramId'].map((path) => ({
@@ -28,9 +29,11 @@ const routes: RouteObject[] = [
<DialogProvider>
<ReactFlowProvider>
<ExportImageProvider>
{/* <ThemeProvider> */}
<EditorPage />
{/* </ThemeProvider> */}
<KeyboardShortcutsProvider>
{/* <ThemeProvider> */}
<EditorPage />
{/* </ThemeProvider> */}
</KeyboardShortcutsProvider>
</ExportImageProvider>
</ReactFlowProvider>
</DialogProvider>