summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor-header.tsx
diff options
context:
space:
mode:
authornaoNao89 <90588855+naoNao89@users.noreply.github.com>2025-07-29 21:35:33 +0700
committernaoNao89 <90588855+naoNao89@users.noreply.github.com>2025-07-29 21:42:22 +0700
commit073cb817d342b0b54cf5ad156435a00c9bb91168 (patch)
tree84cab4ea8be934fe2f29a1c614c68e25349922ea /apps/web/src/components/editor-header.tsx
parent14475dc9a692aeffa8ef3caccecc1d3164ce4cfc (diff)
downloadopencut-073cb817d342b0b54cf5ad156435a00c9bb91168.tar.gz
[UI] Fix dialog accessibility and export functionality
- Add DialogTitle with VisuallyHidden to CommandDialog and onboarding - Replace YouTube redirect with functional VideoExporter implementation - Create VisuallyHidden component for screen reader accessibility Resolves GitHub issue #477 (export redirecting to YouTube) Fixes console warnings about DialogContent accessibility compliance
Diffstat (limited to 'apps/web/src/components/editor-header.tsx')
-rw-r--r--apps/web/src/components/editor-header.tsx77
1 files changed, 70 insertions, 7 deletions
diff --git a/apps/web/src/components/editor-header.tsx b/apps/web/src/components/editor-header.tsx
index 837bd97a..788ef60d 100644
--- a/apps/web/src/components/editor-header.tsx
+++ b/apps/web/src/components/editor-header.tsx
@@ -11,19 +11,79 @@ import { KeyboardShortcutsHelp } from "./keyboard-shortcuts-help";
import { useState, useRef } from "react";
import { Input } from "@/components/ui/input";
import { toast } from "sonner";
+import { useMediaStore } from "@/stores/media-store";
+import {
+ VideoExporter,
+ downloadBlob,
+ type ExportOptions,
+} from "@/lib/export-utils";
export function EditorHeader() {
- const { getTotalDuration } = useTimelineStore();
+ const { getTotalDuration, tracks } = useTimelineStore();
const { activeProject, renameProject } = useProjectStore();
+ const { mediaItems } = useMediaStore();
const [isEditing, setIsEditing] = useState(false);
const [newName, setNewName] = useState(activeProject?.name || "");
+ const [isExporting, setIsExporting] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
- const handleExport = () => {
- // TODO: Implement export functionality
- // NOTE: This is already being worked on
- console.log("Export project");
- window.open("https://youtube.com/watch?v=dQw4w9WgXcQ", "_blank");
+ const handleExport = async () => {
+ if (!activeProject) {
+ toast.error("No active project to export");
+ return;
+ }
+
+ if (tracks.length === 0) {
+ toast.error("Timeline is empty - nothing to export");
+ return;
+ }
+
+ setIsExporting(true);
+
+ try {
+ const exportOptions: ExportOptions = {
+ format: "mp4",
+ quality: "medium",
+ resolution: "1080p",
+ fps: activeProject.fps || 30,
+ };
+
+ const exporter = new VideoExporter((progress) => {
+ toast.loading(
+ `${progress.message} (${Math.round(progress.progress)}%)`,
+ {
+ id: "export-progress",
+ }
+ );
+ });
+
+ const exportedBlob = await exporter.exportProject(
+ activeProject,
+ tracks,
+ mediaItems,
+ exportOptions
+ );
+
+ // Download the exported video
+ const filename = `${activeProject.name}.${exportOptions.format}`;
+ downloadBlob(exportedBlob, filename);
+
+ toast.success("Video exported successfully!", {
+ id: "export-progress",
+ });
+
+ exporter.cleanup();
+ } catch (error) {
+ console.error("Export failed:", error);
+ toast.error(
+ `Export failed: ${error instanceof Error ? error.message : "Unknown error"}`,
+ {
+ id: "export-progress",
+ }
+ );
+ } finally {
+ setIsExporting(false);
+ }
};
const handleNameClick = () => {
@@ -109,9 +169,12 @@ export function EditorHeader() {
variant="primary"
className="h-7 text-xs"
onClick={handleExport}
+ disabled={isExporting}
>
<Download className="h-4 w-4" />
- <span className="text-sm">Export</span>
+ <span className="text-sm">
+ {isExporting ? "Exporting..." : "Export"}
+ </span>
</Button>
</nav>
);