@@ -127,8 +158,12 @@ function KeyboardShortcutsPanel() {
className="px-4 pb-3 space-y-2 border-t border-[var(--border)]"
>
{shortcuts.map(({ keys, label }) => (
-
+
{label}
+
{keys}
))}
@@ -140,45 +175,55 @@ function KeyboardShortcutsPanel() {
export default function VideoEditor() {
const {
- file, duration, recipe, status, progress,
- result, error, updateRecipe,
- handleFileSelect, fileError, handleExport, cancelExport, reset, resetSettings,
- videoRef,
- seekTo,
- overlayFile, setOverlayFile,
- overlayPosition, setOverlayPosition,
- overlaySize, setOverlaySize,
- overlayOpacity, setOverlayOpacity,
- recommendedPreset,
- toggleSound,
- } = useVideoEditor();
-
- useKeyboardShortcuts({
file,
+ duration,
recipe,
- resetSettings,
+ status,
+ progress,
+ result,
+ error,
updateRecipe,
+ handleFileSelect,
+ fileError,
handleExport,
- status,
cancelExport,
- onToggleShortcutsModal: () => {},
- });
+ reset,
+ resetSettings,
+ videoRef,
+ seekTo,
+ overlayFile,
+ setOverlayFile,
+ overlayPosition,
+ setOverlayPosition,
+ overlaySize,
+ setOverlaySize,
+ overlayOpacity,
+ setOverlayOpacity,
+ recommendedPreset,
+ toggleSound,
+ } = useVideoEditor();
const [copied, setCopied] = useState(false);
const [shareCopied, setShareCopied] = useState(false);
+
const downloadRef = useRef
(null);
const handleCopyLink = () => {
if (typeof window === "undefined") return;
+
navigator.clipboard.writeText(window.location.href).then(() => {
setShareCopied(true);
+
setTimeout(() => setShareCopied(false), 2000);
});
};
useEffect(() => {
if (status === "done" && downloadRef.current) {
- const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
+ const prefersReducedMotion = window.matchMedia(
+ "(prefers-reduced-motion: reduce)",
+ ).matches;
+
downloadRef.current.scrollIntoView({
behavior: prefersReducedMotion ? "instant" : "smooth",
block: "center",
@@ -187,32 +232,45 @@ export default function VideoEditor() {
}, [status]);
const isProcessing = status === "loading-engine" || status === "exporting";
- const isMac = typeof navigator !== "undefined" && /Mac/i.test(navigator.platform);
+
+ const isMac =
+ typeof navigator !== "undefined" && /Mac/i.test(navigator.platform);
const videoSrc = useMemo(
() => (file ? URL.createObjectURL(file) : null),
- [file]
+ [file],
);
useEffect(() => {
return () => {
- if (videoSrc) URL.revokeObjectURL(videoSrc);
+ if (videoSrc) {
+ URL.revokeObjectURL(videoSrc);
+ }
};
}, [videoSrc]);
return (
-
-
+
+
+
{status === "exporting" && `Exporting video: ${progress}%`}
+
{status === "done" && "Export complete! Video ready to download."}
+
{status === "error" && `Export failed: ${error}`}
-
-
-
+
{!file && (
Upload a video to get started
+
Supports MP4, MOV, WebM and more
)}
{file && (
-
+
)}
+
{file && (
-
+
+ {/* LEFT COLUMN */}
-
} title="Trim" delay={50}>
+
}
+ title="Timeline"
+ delay={50}
+ >
-
} title="Rotate" delay={100}>
+
+
}
+ title="Transform"
+ delay={100}
+ >
+
+
}
+ title="Quality & Format"
+ delay={200}
+ >
+
+
+
+
+
+
+
+
}
+ title="Processing"
+ delay={225}
+ >
+
+
-
-
} title="Audio & Speed" delay={150}>
-
+ {/* RIGHT COLUMN */}
+
+
}
+ title="Playback"
+ delay={150}
+ >
+
+
}
- title="Adjustments"
+ title="Colour"
delay={175}
>
@@ -300,15 +419,20 @@ export default function VideoEditor() {
+
+
updateRecipe({ brightness: Number(e.target.value) })}
+ onChange={(e) =>
+ updateRecipe({
+ brightness: Number(e.target.value),
+ })
+ }
aria-label="Adjust brightness"
- className="w-full accent-film-600"
+ className="w-full"
/>
+
{/* Contrast */}
+
+
updateRecipe({ contrast: Number(e.target.value) })}
+ onChange={(e) =>
+ updateRecipe({
+ contrast: Number(e.target.value),
+ })
+ }
aria-label="Adjust contrast"
- className="w-full accent-film-600"
+ className="w-full"
/>
+
{/* Saturation */}
+
+
updateRecipe({ saturation: Number(e.target.value) })}
+ onChange={(e) =>
+ updateRecipe({
+ saturation: Number(e.target.value),
+ })
+ }
aria-label="Adjust saturation"
- className="w-full accent-film-600"
+ className="w-full"
/>
-
} title="Output format" delay={190}>
-
-
-
} title="Export quality" delay={200}>
-
-
-
} title="Image overlay" delay={120}>
+
+
}
+ title="Image Overlay"
+ delay={125}
+ >
-
+
+
+
+
{!error.includes("Validation Failed") && (
)}
-
-
-
} title="Output size">
+
+
+
} title="Format & size">
{recommendedPreset && (
- We detected a {recommendedPreset.label.replace(/\s/g, "")} video → Recommended: {(recommendedPreset.platform.split("·")[0] ?? "").trim()} ({recommendedPreset.label.replace(/\s/g, "")})
+ We detected a {recommendedPreset.label.replace(/\s/g, "")}{" "}
+ video → Recommended:{" "}
+ {(recommendedPreset.platform.split("·")[0] ?? "").trim()}{" "}
+ ({recommendedPreset.label.replace(/\s/g, "")})
)}
+
@@ -464,8 +635,10 @@ export default function VideoEditor() {
className="flex items-center gap-1.5 text-xs font-heading font-bold uppercase tracking-widest text-film-500 hover:text-film-600 hover:opacity-100 transition-all cursor-pointer"
>
+
{shareCopied ? "Copied!" : "Copy Link"}
+
@@ -507,4 +684,4 @@ export default function VideoEditor() {
);
-}
\ No newline at end of file
+}