"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { Loader2 } from "lucide-react"; import { EditorCore } from "@/core"; import { useEditor } from "@/editor/use-editor"; import { useKeybindingsListener } from "@/actions/use-keybindings"; import { useKeybindingsStore } from "@/actions/keybindings-store"; import { useTimelineStore } from "@/timeline/timeline-store"; import { useEditorActions } from "@/actions/use-editor-actions"; import { loadFontAtlas } from "@/fonts/google-fonts"; import { initializeGpuRenderer, isGpuAvailable, } from "@/services/renderer/gpu-renderer"; interface EditorProviderProps { projectId: string; children: React.ReactNode; } export function EditorProvider({ projectId, children }: EditorProviderProps) { const activeProject = useEditor((e) => e.project.getActiveOrNull()); const router = useRouter(); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const { setLoadingProject } = useKeybindingsStore(); useEffect(() => { setLoadingProject(isLoading); }, [isLoading, setLoadingProject]); useEffect(() => { let cancelled = false; const editor = EditorCore.getInstance(); const loadProject = async () => { try { setIsLoading(true); await initializeGpuRenderer(); editor.renderer.setDegraded(!isGpuAvailable()); await editor.project.loadProject({ id: projectId }); if (cancelled) return; setIsLoading(false); loadFontAtlas(); } catch (err) { if (cancelled) return; const isNotFound = err instanceof Error && (err.message.includes("not found") || err.message.includes("does not exist")); if (isNotFound) { try { const newProjectId = await editor.project.createNewProject({ name: "Untitled Project", }); router.replace(`/editor/${newProjectId}`); } catch (_createErr) { setError("Failed to create project"); setIsLoading(false); } } else { const wasmPanic = (window as Window & { __wasmPanic?: string }) .__wasmPanic; if (wasmPanic) { delete (window as Window & { __wasmPanic?: string }).__wasmPanic; setError(wasmPanic); } else { setError( err instanceof Error ? err.message : "Failed to load project", ); } setIsLoading(false); } } }; loadProject(); return () => { cancelled = true; }; }, [projectId, router]); if (error) { return (

{error}

); } if (isLoading) { return (

Loading project...

); } if (!activeProject) { return (

Exiting project...

); } return ( <> {children} ); } function EditorRuntimeBindings() { const editor = useEditor(); const rippleEditingEnabled = useTimelineStore( (state) => state.rippleEditingEnabled, ); useEffect(() => { editor.command.isRippleEnabled = rippleEditingEnabled; }, [editor, rippleEditingEnabled]); useEffect(() => { const handleBeforeUnload = (event: BeforeUnloadEvent) => { if (!editor.save.getIsDirty()) return; event.preventDefault(); (event as unknown as { returnValue: string }).returnValue = ""; }; window.addEventListener("beforeunload", handleBeforeUnload); return () => window.removeEventListener("beforeunload", handleBeforeUnload); }, [editor]); useEditorActions(); useKeybindingsListener(); return null; }