diff options
| author | vishesh711 <mail4vishesh@gmail.com> | 2025-07-15 12:36:53 -0400 |
|---|---|---|
| committer | vishesh711 <mail4vishesh@gmail.com> | 2025-07-15 12:36:53 -0400 |
| commit | d3204f6cd7772fe63d19ef8892664335d615c9de (patch) | |
| tree | 06e86f34d73158cbb7c09406ac8bead8bbaf55c4 /apps/web/src/components/keyboard-shortcuts-help.tsx | |
| parent | 1f95bb98d6108a5fa059e0f9a08c98e5bdb72c08 (diff) | |
| download | opencut-d3204f6cd7772fe63d19ef8892664335d615c9de.tar.gz | |
feat: Add comprehensive keyboard shortcuts system for video editor
- Implement industry-standard video editing shortcuts (Space, J/K/L, arrows)
- Add playback controls: Space (play/pause), J/K/L (rewind/pause/forward)
- Add navigation: arrow keys (frame stepping), Shift+arrows (5s jumps), Home/End
- Add editing shortcuts: S (split at playhead), N (toggle snapping)
- Add selection shortcuts: Ctrl/Cmd+A (select all), Ctrl/Cmd+D (duplicate)
- Add keyboard shortcuts help dialog with categorized shortcuts display
- Integrate help button in editor header for discoverability
- Add TypeScript type declarations for better development experience
- Fix Docker build environment variable validation issues
All shortcuts follow professional video editing standards (Avid/Premiere/Final Cut).
Context-aware shortcuts that don't interfere with text input fields.
Toast notifications provide user feedback for better UX.
Diffstat (limited to 'apps/web/src/components/keyboard-shortcuts-help.tsx')
| -rw-r--r-- | apps/web/src/components/keyboard-shortcuts-help.tsx | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/apps/web/src/components/keyboard-shortcuts-help.tsx b/apps/web/src/components/keyboard-shortcuts-help.tsx new file mode 100644 index 00000000..c2087b4a --- /dev/null +++ b/apps/web/src/components/keyboard-shortcuts-help.tsx @@ -0,0 +1,220 @@ +"use client"; + +import { useState } from "react"; +import { Button } from "./ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "./ui/dialog"; +import { Badge } from "./ui/badge"; +import { Keyboard, Play, Pause, SkipBack, SkipForward } from "lucide-react"; + +interface Shortcut { + keys: string[]; + description: string; + category: string; + icon?: React.ReactNode; +} + +const shortcuts: Shortcut[] = [ + // Playback Controls + { + keys: ["Space"], + description: "Play/Pause", + category: "Playback", + icon: <Play className="w-3 h-3" /> + }, + { + keys: ["J"], + description: "Rewind 1 second", + category: "Playback", + icon: <SkipBack className="w-3 h-3" /> + }, + { + keys: ["K"], + description: "Play/Pause (alternative)", + category: "Playback", + icon: <Pause className="w-3 h-3" /> + }, + { + keys: ["L"], + description: "Fast forward 1 second", + category: "Playback", + icon: <SkipForward className="w-3 h-3" /> + }, + + // Navigation + { + keys: ["←"], + description: "Frame step backward", + category: "Navigation" + }, + { + keys: ["→"], + description: "Frame step forward", + category: "Navigation" + }, + { + keys: ["Shift", "←"], + description: "Jump back 5 seconds", + category: "Navigation" + }, + { + keys: ["Shift", "→"], + description: "Jump forward 5 seconds", + category: "Navigation" + }, + { + keys: ["Home"], + description: "Go to timeline start", + category: "Navigation" + }, + { + keys: ["End"], + description: "Go to timeline end", + category: "Navigation" + }, + + // Editing + { + keys: ["S"], + description: "Split element at playhead", + category: "Editing" + }, + { + keys: ["Delete", "Backspace"], + description: "Delete selected elements", + category: "Editing" + }, + { + keys: ["N"], + description: "Toggle snapping", + category: "Editing" + }, + + // Selection & Organization + { + keys: ["Cmd", "A"], + description: "Select all elements", + category: "Selection" + }, + { + keys: ["Cmd", "D"], + description: "Duplicate selected element", + category: "Selection" + }, + + // History + { + keys: ["Cmd", "Z"], + description: "Undo", + category: "History" + }, + { + keys: ["Cmd", "Shift", "Z"], + description: "Redo", + category: "History" + }, + { + keys: ["Cmd", "Y"], + description: "Redo (alternative)", + category: "History" + } +]; + +const KeyBadge = ({ keyName }: { keyName: string }) => { + // Replace common key names with symbols + const displayKey = keyName + .replace("Cmd", "⌘") + .replace("Shift", "⇧") + .replace("←", "◀") + .replace("→", "▶") + .replace("Space", "⎵"); + + return ( + <Badge variant="secondary" className="font-mono text-xs px-2 py-1"> + {displayKey} + </Badge> + ); +}; + +const ShortcutItem = ({ shortcut }: { shortcut: Shortcut }) => ( + <div className="flex items-center justify-between py-2 px-3 rounded-lg hover:bg-muted/50"> + <div className="flex items-center gap-3"> + {shortcut.icon && ( + <div className="text-muted-foreground">{shortcut.icon}</div> + )} + <span className="text-sm">{shortcut.description}</span> + </div> + <div className="flex items-center gap-1"> + {shortcut.keys.map((key, index) => ( + <div key={index} className="flex items-center gap-1"> + <KeyBadge keyName={key} /> + {index < shortcut.keys.length - 1 && ( + <span className="text-xs text-muted-foreground">+</span> + )} + </div> + ))} + </div> + </div> +); + +export const KeyboardShortcutsHelp = () => { + const [open, setOpen] = useState(false); + + const categories = Array.from(new Set(shortcuts.map(s => s.category))); + + return ( + <Dialog open={open} onOpenChange={setOpen}> + <DialogTrigger asChild> + <Button variant="ghost" size="sm" className="gap-2"> + <Keyboard className="w-4 h-4" /> + Shortcuts + </Button> + </DialogTrigger> + <DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto"> + <DialogHeader> + <DialogTitle className="flex items-center gap-2"> + <Keyboard className="w-5 h-5" /> + Keyboard Shortcuts + </DialogTitle> + <DialogDescription> + Speed up your video editing workflow with these keyboard shortcuts. + Most shortcuts work when the timeline is focused. + </DialogDescription> + </DialogHeader> + + <div className="space-y-6"> + {categories.map(category => ( + <div key={category}> + <h3 className="font-semibold text-sm text-muted-foreground uppercase tracking-wide mb-3"> + {category} + </h3> + <div className="space-y-1"> + {shortcuts + .filter(shortcut => shortcut.category === category) + .map((shortcut, index) => ( + <ShortcutItem key={index} shortcut={shortcut} /> + ))} + </div> + </div> + ))} + </div> + + <div className="mt-6 p-4 bg-muted/30 rounded-lg"> + <h4 className="font-medium text-sm mb-2">Tips:</h4> + <ul className="text-sm text-muted-foreground space-y-1"> + <li>• Shortcuts work when the editor is focused (not typing in inputs)</li> + <li>• J/K/L are industry-standard video editing shortcuts</li> + <li>• Use arrow keys for frame-perfect positioning</li> + <li>• Hold Shift with arrow keys for larger jumps</li> + </ul> + </div> + </DialogContent> + </Dialog> + ); +};
\ No newline at end of file |
