Closed
Description
Description
Implement keyboard shortcuts for common GhostPaste actions to improve power user experience.
Core Keyboard Shortcuts
Gist Creation/Editing
-
Cmd/Ctrl + S: Save/Update gist (when in edit mode)
- Prevents default browser save dialog
- Shows loading state during save
- Displays success/error toast
-
Cmd/Ctrl + Enter: Create new gist / Update existing gist
- On create page: Creates new gist
- On edit page: Updates current gist
- Validates form before submission
Navigation & UI
-
Escape: Close any open dialog/modal
- PIN entry dialog
- Help dialog
- Mobile menu
- Any future modals
-
Tab / Shift+Tab: Navigate between elements
- Proper tab order through form fields
- Skip links for accessibility
- Focus visible indicators
-
Cmd/Ctrl + K: Open command palette (future feature)
- Quick navigation
- Search gists (if implemented)
- Toggle settings
Editor Shortcuts (CodeMirror)
- These work within the code editor:
- Cmd/Ctrl + A: Select all
- Cmd/Ctrl + Z/Y: Undo/Redo
- Cmd/Ctrl + F: Find in file
- Tab: Insert tab/spaces (based on settings)
Help System
- Cmd/Ctrl + ? or Cmd/Ctrl + /: Show keyboard shortcuts help
- Modal with all available shortcuts
- Platform-specific keys (Cmd for Mac, Ctrl for others)
- Organized by category
Implementation
Global Shortcut Hook
export function useGlobalShortcuts() {
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const isMeta = e.metaKey || e.ctrlKey;
// Cmd/Ctrl + S
if (isMeta && e.key === 's') {
e.preventDefault();
// Trigger save action
}
// Cmd/Ctrl + Enter
if (isMeta && e.key === 'Enter') {
e.preventDefault();
// Trigger create/update
}
// Escape
if (e.key === 'Escape') {
// Close modals/dialogs
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, []);
}
Platform Detection
const getPlatformKey = () => {
const isMac = /Mac|iPhone|iPad/.test(navigator.platform);
return isMac ? '⌘' : 'Ctrl';
};
Help Dialog Component
export function KeyboardShortcutsHelp() {
const platformKey = getPlatformKey();
const shortcuts = [
{ keys: `${platformKey} + S`, action: "Save gist" },
{ keys: `${platformKey} + Enter`, action: "Create/Update gist" },
{ keys: "Escape", action: "Close dialog" },
// ... more shortcuts
];
return (
<Dialog>
<DialogContent>
<DialogHeader>
<DialogTitle>Keyboard Shortcuts</DialogTitle>
</DialogHeader>
<div className="space-y-4">
{shortcuts.map(({ keys, action }) => (
<div key={keys} className="flex justify-between">
<kbd className="px-2 py-1 bg-muted rounded text-sm">
{keys}
</kbd>
<span>{action}</span>
</div>
))}
</div>
</DialogContent>
</Dialog>
);
}
Acceptance Criteria
- Cmd/Ctrl + S saves when in edit mode with feedback
- Cmd/Ctrl + Enter creates/updates gist based on context
- Escape closes all dialogs and mobile menu
- Tab navigation works with visible focus indicators
- Help dialog shows with Cmd/Ctrl + ?
- Platform-specific keys shown correctly (⌘ vs Ctrl)
- Shortcuts don't conflict with browser defaults
- Shortcuts work in both light and dark themes
- Screen reader announces shortcut actions
- Mobile alternative interactions documented
Conflict Prevention
- Test shortcuts in major browsers (Chrome, Firefox, Safari, Edge)
- Avoid overriding critical browser shortcuts
- Provide option to disable shortcuts if needed
- Document any browser-specific limitations
Accessibility
- Announce shortcut actions to screen readers
- Provide non-keyboard alternatives for all actions
- Ensure help dialog is keyboard navigable
- Include shortcuts in main navigation
Technical Notes
- Use React hooks for event handling
- Consider using a library like
react-hotkeys-hook
for complex scenarios - Store shortcut preferences in localStorage
- Test on both Mac and Windows/Linux
- Ensure shortcuts work with different keyboard layouts
Related
- Enhances all form interactions
- Works with PIN dialog (Implement FileEditor component for single file editing #55)
- Integrates with editor component (feat: implement PIN authentication with PBKDF2-SHA256 #46)
- Part of Phase 4 UI Components