From bd5fc1ee03270c614167d0f4a7d526e977dde321 Mon Sep 17 00:00:00 2001 From: Kokila-chandrakar Date: Mon, 25 May 2026 19:55:25 +0000 Subject: [PATCH] feat: add keyboard shortcuts helper modal --- src/app/globals.css | 16 +++ src/components/KeyboardShortcutsModal.tsx | 107 +++++++++++++++++ src/components/VideoEditor.tsx | 137 ++++++++-------------- 3 files changed, 169 insertions(+), 91 deletions(-) create mode 100644 src/components/KeyboardShortcutsModal.tsx diff --git a/src/app/globals.css b/src/app/globals.css index 3c1540e0..271ae6b2 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -98,4 +98,20 @@ body { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; +} + +@keyframes scale-in { + from { + opacity: 0; + transform: scale(0.96); + } + + to { + opacity: 1; + transform: scale(1); + } +} + +.animate-scale-in { + animation: scale-in 0.2s ease-out; } \ No newline at end of file diff --git a/src/components/KeyboardShortcutsModal.tsx b/src/components/KeyboardShortcutsModal.tsx new file mode 100644 index 00000000..b095dd13 --- /dev/null +++ b/src/components/KeyboardShortcutsModal.tsx @@ -0,0 +1,107 @@ +"use client"; + +import { Keyboard, X } from "lucide-react"; + +interface KeyboardShortcutsModalProps { + open: boolean; + onClose: () => void; +} + +function Kbd({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} + +export default function KeyboardShortcutsModal({ + open, + onClose, +}: KeyboardShortcutsModalProps) { + if (!open) return null; + + const shortcuts = [ + { + keys: ["Ctrl", "Shift", "E"], + label: "Export video", + }, + { + keys: ["M"], + label: "Toggle audio mute", + }, + { + keys: ["R"], + label: "Reset all settings", + }, + { + keys: ["Esc"], + label: "Cancel export / Close modal", + }, + { + keys: ["1 - 9"], + label: "Switch presets", + }, + { + keys: ["?"], + label: "Open keyboard shortcuts", + }, + ]; + + return ( +
+
+ + +
+
+ +
+ +
+

+ Keyboard Shortcuts +

+ +

+ Speed up your workflow with shortcuts +

+
+
+ +
+ {shortcuts.map((shortcut) => ( +
+ + {shortcut.label} + + +
+ {shortcut.keys.map((key) => ( + {key} + ))} +
+
+ ))} +
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/VideoEditor.tsx b/src/components/VideoEditor.tsx index 28ef775e..5251c517 100644 --- a/src/components/VideoEditor.tsx +++ b/src/components/VideoEditor.tsx @@ -19,10 +19,20 @@ import ImageOverlay from "./ImageOverlay" import { cn } from "@/lib/utils"; import { - Layers, Crop, Scissors, RotateCw, Volume2, - SlidersHorizontal, Zap, AlertTriangle, Github, Copy + Layers, + Crop, + Scissors, + RotateCw, + Volume2, + SlidersHorizontal, + Zap, + AlertTriangle, + Github, + Copy, + Keyboard, } from "lucide-react"; import OnboardingTour from "./OnboardingTour"; +import KeyboardShortcutsModal from "./KeyboardShortcutsModal"; import { useKeyboardShortcuts } from "@/hooks/useKeyboardShortcuts"; interface SectionProps { @@ -50,93 +60,8 @@ function Section({ icon, title, children, delay = 0 }: SectionProps) { ); } -/** Inline keyboard hint badge. */ -function Kbd({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); -} /** Collapsible panel that lists all keyboard shortcuts. */ -function KeyboardShortcutsPanel() { - const [open, setOpen] = useState(false); - - const shortcuts: { keys: React.ReactNode[]; label: string }[] = [ - { - keys: [ - Ctrl, - +, - Shift, - +, - E - ], - label: "Export video", - }, - { - keys: [M], - label: "Toggle audio mute", - }, - { - keys: [R], - label: "Reset all settings", - }, - { - keys: [Esc], - label: "Cancel export", - }, - { - keys: [1, , 9], - label: "Switch preset by index", - }, - { - keys: [?], - label: "Toggle this panel", - }, -]; - - return ( -
- - - {open && ( - - )} -
- ); -} export default function VideoEditor() { const { @@ -162,10 +87,12 @@ export default function VideoEditor() { handleExport, status, cancelExport, - onToggleShortcutsModal: () => {}, + onToggleShortcutsModal: () => + setShortcutsOpen((prev) => !prev), }); const [copied, setCopied] = useState(false); + const [shortcutsOpen, setShortcutsOpen] = useState(false); const [shareCopied, setShareCopied] = useState(false); const downloadRef = useRef(null); @@ -201,10 +128,28 @@ export default function VideoEditor() { }; }, [videoSrc]); + useEffect(() => { + const handleEsc = (e: KeyboardEvent) => { + if (e.key === "Escape" && shortcutsOpen) { + setShortcutsOpen(false); + } + }; + + window.addEventListener("keydown", handleEsc); + + return () => { + window.removeEventListener("keydown", handleEsc); + }; +}, [shortcutsOpen]); + return (
+ setShortcutsOpen(false)} + />
{status === "exporting" && `Exporting video: ${progress}%`} @@ -226,9 +171,19 @@ export default function VideoEditor() { Your video, any format

-
- - No login. No ads. 100% private - your video never leaves your device. +
+ + +
+ + No login. No ads. 100% private - your video never leaves your device. +