From a1deae2650aa065d086252b0563a7225bee5d0c3 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 15 Feb 2026 20:32:32 +0200 Subject: [PATCH] feat: add keyboard shortcut help modal triggered by ? key --- src/App.tsx | 13 ++++ .../shortcuts/ShortcutHelpModal.tsx | 67 +++++++++++++++++++ src/hooks/useKeyboardShortcuts.ts | 6 ++ 3 files changed, 86 insertions(+) create mode 100644 src/components/shortcuts/ShortcutHelpModal.tsx diff --git a/src/App.tsx b/src/App.tsx index 11bc6ae..bf2a6a9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,6 +8,7 @@ import { BoardView } from "@/components/board/BoardView"; import { CommandPalette } from "@/components/command-palette/CommandPalette"; import { SettingsDialog } from "@/components/settings/SettingsDialog"; import { ToastContainer } from "@/components/toast/ToastContainer"; +import { ShortcutHelpModal } from "@/components/shortcuts/ShortcutHelpModal"; import { useKeyboardShortcuts } from "@/hooks/useKeyboardShortcuts"; export default function App() { @@ -16,6 +17,7 @@ export default function App() { const view = useAppStore((s) => s.view); const [settingsOpen, setSettingsOpen] = useState(false); + const [shortcutHelpOpen, setShortcutHelpOpen] = useState(false); useEffect(() => { init(); @@ -42,6 +44,16 @@ export default function App() { }; }, []); + useEffect(() => { + function handleOpenShortcutHelp() { + setShortcutHelpOpen(true); + } + document.addEventListener("open-shortcut-help", handleOpenShortcutHelp); + return () => { + document.removeEventListener("open-shortcut-help", handleOpenShortcutHelp); + }; + }, []); + const handleOpenSettings = useCallback(() => { setSettingsOpen(true); }, []); @@ -66,6 +78,7 @@ export default function App() { + ); } diff --git a/src/components/shortcuts/ShortcutHelpModal.tsx b/src/components/shortcuts/ShortcutHelpModal.tsx new file mode 100644 index 0000000..efdcc05 --- /dev/null +++ b/src/components/shortcuts/ShortcutHelpModal.tsx @@ -0,0 +1,67 @@ +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, +} from "@/components/ui/dialog"; + +interface ShortcutHelpModalProps { + open: boolean; + onOpenChange: (open: boolean) => void; +} + +const SHORTCUT_GROUPS = [ + { + category: "Navigation", + shortcuts: [ + { key: "Ctrl+K", description: "Open command palette" }, + { key: "?", description: "Show keyboard shortcuts" }, + { key: "Escape", description: "Close modal / cancel" }, + ], + }, + { + category: "Board", + shortcuts: [ + { key: "Ctrl+Z", description: "Undo" }, + { key: "Ctrl+Shift+Z", description: "Redo" }, + ], + }, +]; + +export function ShortcutHelpModal({ open, onOpenChange }: ShortcutHelpModalProps) { + return ( + + + + + Keyboard Shortcuts + + + Quick reference for all keyboard shortcuts. + + + +
+ {SHORTCUT_GROUPS.map((group) => ( +
+

+ {group.category} +

+
+ {group.shortcuts.map(({ key, description }) => ( +
+ {description} + + {key} + +
+ ))} +
+
+ ))} +
+
+
+ ); +} diff --git a/src/hooks/useKeyboardShortcuts.ts b/src/hooks/useKeyboardShortcuts.ts index 79bdd8d..f643580 100644 --- a/src/hooks/useKeyboardShortcuts.ts +++ b/src/hooks/useKeyboardShortcuts.ts @@ -41,6 +41,12 @@ export function useKeyboardShortcuts(): void { document.dispatchEvent(new CustomEvent("close-all-modals")); return; } + + if (e.key === "?" || (e.shiftKey && e.key === "/")) { + e.preventDefault(); + document.dispatchEvent(new CustomEvent("open-shortcut-help")); + return; + } } document.addEventListener("keydown", handleKeyDown);