From fca99d6126c31fbb18ed9f1034cee6f940b040e8 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Tue, 10 Feb 2026 16:28:21 +0100 Subject: refactor --- .../src/components/editor/panels/preview/index.tsx | 141 +++++++++++++++++++-- 1 file changed, 130 insertions(+), 11 deletions(-) (limited to 'apps/web/src/components/editor/panels/preview') diff --git a/apps/web/src/components/editor/panels/preview/index.tsx b/apps/web/src/components/editor/panels/preview/index.tsx index c579b15b..902547bd 100644 --- a/apps/web/src/components/editor/panels/preview/index.tsx +++ b/apps/web/src/components/editor/panels/preview/index.tsx @@ -4,11 +4,23 @@ import { useCallback, useMemo, useRef } from "react"; import useDeepCompareEffect from "use-deep-compare-effect"; import { useEditor } from "@/hooks/use-editor"; import { useRafLoop } from "@/hooks/use-raf-loop"; +import { useContainerSize } from "@/hooks/use-container-size"; +import { useFullscreen } from "@/hooks/use-fullscreen"; import { CanvasRenderer } from "@/services/renderer/canvas-renderer"; import type { RootNode } from "@/services/renderer/nodes/root-node"; import { buildScene } from "@/services/renderer/scene-builder"; -import { getLastFrameTime } from "@/lib/time"; +import { formatTimeCode, getLastFrameTime } from "@/lib/time"; import { PreviewInteractionOverlay } from "./preview-interaction-overlay"; +import { EditableTimecode } from "@/components/editable-timecode"; +import { invokeAction } from "@/lib/actions"; +import { Button } from "@/components/ui/button"; +import { + FullScreenIcon, + PauseIcon, + PlayIcon, +} from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { cn } from "@/utils/ui"; function usePreviewSize() { const editor = useEditor(); @@ -47,32 +59,134 @@ function RenderTreeController() { } export function PreviewPanel() { + const containerRef = useRef(null); + const { isFullscreen, toggleFullscreen } = useFullscreen({ containerRef }); + return ( -
-
+
+
+ +
+ ); +} + +function PreviewToolbar({ + isFullscreen, + onToggleFullscreen, +}: { + isFullscreen: boolean; + onToggleFullscreen: () => void; +}) { + const editor = useEditor(); + const isPlaying = editor.playback.getIsPlaying(); + const currentTime = editor.playback.getCurrentTime(); + const totalDuration = editor.timeline.getTotalDuration(); + const fps = editor.project.getActive().settings.fps; + + return ( +
+
+ editor.playback.seek({ time })} + className="text-center" + /> + / + + {formatTimeCode({ + timeInSeconds: totalDuration, + format: "HH:MM:SS:FF", + fps, + })} + +
+ + + +
+ +
); } function PreviewCanvas() { const canvasRef = useRef(null); + const containerRef = useRef(null); const lastFrameRef = useRef(-1); const lastSceneRef = useRef(null); const renderingRef = useRef(false); - const { width, height } = usePreviewSize(); + const { width: nativeWidth, height: nativeHeight } = usePreviewSize(); + const containerSize = useContainerSize({ containerRef }); const editor = useEditor(); const activeProject = editor.project.getActive(); const renderer = useMemo(() => { return new CanvasRenderer({ - width, - height, + width: nativeWidth, + height: nativeHeight, fps: activeProject.settings.fps, }); - }, [width, height, activeProject.settings.fps]); + }, [nativeWidth, nativeHeight, activeProject.settings.fps]); + + const displaySize = useMemo(() => { + if ( + !nativeWidth || + !nativeHeight || + containerSize.width === 0 || + containerSize.height === 0 + ) { + return { width: nativeWidth ?? 0, height: nativeHeight ?? 0 }; + } + + const paddingBuffer = 4; + const availableWidth = containerSize.width - paddingBuffer; + const availableHeight = containerSize.height - paddingBuffer; + + const aspectRatio = nativeWidth / nativeHeight; + const containerAspect = availableWidth / availableHeight; + + const displayWidth = + containerAspect > aspectRatio + ? availableHeight * aspectRatio + : availableWidth; + const displayHeight = + containerAspect > aspectRatio + ? availableHeight + : availableWidth / aspectRatio; + + return { width: displayWidth, height: displayHeight }; + }, [nativeWidth, nativeHeight, containerSize.width, containerSize.height]); const renderTree = editor.renderer.getRenderTree(); @@ -109,13 +223,18 @@ function PreviewCanvas() { useRafLoop(render); return ( -
+