Skip to content

feat: implement keyboard shortcuts #72

Closed
@nullcoder

Description

@nullcoder

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNew feature implementationpriority: lowNice to haveuiUser interface and components

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions