Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ const nextConfig: NextConfig = {
config.resolve.fallback = { fs: false };
return config;
},
// Headers for FFmpeg WASM SharedArrayBuffer support
// Note: With output: 'export', these headers are not applied by Next.js
// Use serve.json instead for static hosting
async headers() {
return [
{
source: "/(.*)",
headers: [
{ key: "Cross-Origin-Opener-Policy", value: "same-origin" },
{ key: "Cross-Origin-Embedder-Policy", value: "require-corp" },
],
},
];
},
};

export default nextConfig;
export default nextConfig;
11 changes: 11 additions & 0 deletions serve.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"headers": [
{
"source": "**",
"headers": [
{ "key": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" }
]
}
]
}
76 changes: 76 additions & 0 deletions src/components/PreviewPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"use client";

import Image from "next/image";
import { Eye } from "lucide-react";
import { cn } from "@/lib/utils";

interface PreviewPanelProps {
previewUrl: string | null;
isPreviewing: boolean;
onPreview: () => void;
isDisabled: boolean;
}

export default function PreviewPanel({
previewUrl,
isPreviewing,
onPreview,
isDisabled,
}: PreviewPanelProps) {
return (
<div className="bg-[var(--surface)] rounded-xl border border-[var(--border)] p-5 space-y-4 animate-fade-in">
<div className="flex items-center justify-between">
<h3 className="text-sm font-heading font-bold uppercase tracking-widest text-[var(--muted)]">
Preview Frame
</h3>
<button
type="button"
onClick={onPreview}
disabled={isDisabled || isPreviewing}
aria-label="Generate preview frame"
className={cn(
"flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-semibold transition-all",
isDisabled || isPreviewing
? "bg-[var(--border)] text-[var(--muted)] cursor-not-allowed"
: "bg-[var(--accent)] text-white hover:bg-[var(--accent-hover)] hover:scale-[1.02] active:scale-[0.98]"
)}
>
<Eye size={16} />
{isPreviewing ? "Generating..." : "Preview"}
</button>
</div>

{isPreviewing && (
<div className="flex items-center justify-center py-12">
<div className="flex flex-col items-center gap-3">
<div className="w-8 h-8 border-4 border-[var(--border)] border-t-[var(--accent)] rounded-full animate-spin" />
<p className="text-sm text-[var(--muted)]">Generating preview...</p>
</div>
</div>
)}

{!isPreviewing && previewUrl && (
<div className="rounded-lg overflow-hidden border border-[var(--border)]">
<Image
src={previewUrl}
alt="Preview frame"
aria-label="Generated preview frame"
width={0}
height={0}
sizes="100vw"
className="w-full h-auto"
unoptimized
/>
</div>
)}

{!isPreviewing && !previewUrl && (
<div className="flex items-center justify-center py-12 text-center">
<p className="text-sm text-[var(--muted)]">
Click Preview to see your output before exporting
</p>
</div>
)}
</div>
);
}
11 changes: 11 additions & 0 deletions src/components/VideoEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import ExportSettings from "./ExportSettings";
import ExportOverlay from "./ExportOverlay";
import DownloadResult from "./DownloadResult";
import ImageOverlay from "./ImageOverlay"
import PreviewPanel from "./PreviewPanel";
import { getPresetById } from "@/lib/presets";

import { cn } from "@/lib/utils";
Expand Down Expand Up @@ -210,6 +211,9 @@ export default function VideoEditor() {
recommendedPreset,
currentTime,
toggleSound,
previewUrl,
isPreviewing,
generatePreview,
} = useVideoEditor();

useKeyboardShortcuts({
Expand Down Expand Up @@ -689,6 +693,13 @@ export default function VideoEditor() {
</p>
)}

<PreviewPanel
previewUrl={previewUrl}
isPreviewing={isPreviewing}
onPreview={generatePreview}
isDisabled={!file || isProcessing}
/>

<button
id="export-button"
type="button"
Expand Down
Loading