From 7e3a80eb74af23a36cfff43aa61175e1630222e1 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Sun, 22 Jun 2025 22:10:50 +0200 Subject: [PATCH] improve lots of stuff around the editor --- apps/web/src/components/editor-header.tsx | 15 ++++++---- .../src/components/editor/preview-panel.tsx | 28 +++++++++++++++++-- apps/web/src/components/editor/timeline.tsx | 23 ++++++--------- apps/web/src/stores/timeline-store.ts | 18 +++++++++++- 4 files changed, 59 insertions(+), 25 deletions(-) diff --git a/apps/web/src/components/editor-header.tsx b/apps/web/src/components/editor-header.tsx index f59193d..c6cecbe 100644 --- a/apps/web/src/components/editor-header.tsx +++ b/apps/web/src/components/editor-header.tsx @@ -4,20 +4,25 @@ import Link from "next/link"; import { Button } from "./ui/button"; import { ChevronLeft, Download } from "lucide-react"; import { useProjectStore } from "@/stores/project-store"; -import { useMediaStore } from "@/stores/media-store"; import { useTimelineStore } from "@/stores/timeline-store"; import { HeaderBase } from "./header-base"; export function EditorHeader() { const { activeProject } = useProjectStore(); - const { mediaItems } = useMediaStore(); - const { tracks } = useTimelineStore(); + const { getTotalDuration } = useTimelineStore(); const handleExport = () => { // TODO: Implement export functionality console.log("Export project"); }; + // Format duration from seconds to MM:SS format + const formatDuration = (seconds: number): string => { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = Math.floor(seconds % 60); + return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`; + }; + const leftContent = ( - {mediaItems.length} media - - {tracks.length} tracks + {formatDuration(getTotalDuration())} ); diff --git a/apps/web/src/components/editor/preview-panel.tsx b/apps/web/src/components/editor/preview-panel.tsx index 488e1fc..16c808f 100644 --- a/apps/web/src/components/editor/preview-panel.tsx +++ b/apps/web/src/components/editor/preview-panel.tsx @@ -18,6 +18,9 @@ export function PreviewPanel() { ? mediaItems.find((item) => item.id === firstClip.mediaId) : null; + // Calculate dynamic aspect ratio - default to 16:9 if no media + const aspectRatio = firstMediaItem?.aspectRatio || 16 / 9; + const renderPreviewContent = () => { if (!firstMediaItem) { return ( @@ -32,7 +35,7 @@ export function PreviewPanel() { @@ -68,8 +71,17 @@ export function PreviewPanel() { }; return ( -
-
+
+
1 ? "100%" : "auto", + height: aspectRatio <= 1 ? "100%" : "auto", + maxWidth: "100%", + maxHeight: "100%", + }} + > {renderPreviewContent()} {/* Playback Controls Overlay */} @@ -103,6 +115,16 @@ export function PreviewPanel() { Preview: {firstMediaItem.name} {firstMediaItem.type === "image" && " (with CapCut-style treatment)"} +
+ + Aspect Ratio: {aspectRatio.toFixed(2)} ( + {aspectRatio > 1 + ? "Landscape" + : aspectRatio < 1 + ? "Portrait" + : "Square"} + ) +

)} diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx index 2e23bfb..4ae4266 100644 --- a/apps/web/src/components/editor/timeline.tsx +++ b/apps/web/src/components/editor/timeline.tsx @@ -472,19 +472,12 @@ function TimelineTrackComponent({ track }: { track: TimelineTrack }) { if (mediaItem.type === "image") { return ( -
-
- -
- - {clip.name} - +
+ {mediaItem.name}
); } @@ -536,9 +529,9 @@ function TimelineTrackComponent({ track }: { track: TimelineTrack }) { track.clips.map((clip, index) => (
handleClipDragStart(e, clip)} diff --git a/apps/web/src/stores/timeline-store.ts b/apps/web/src/stores/timeline-store.ts index 243ed22..12129af 100644 --- a/apps/web/src/stores/timeline-store.ts +++ b/apps/web/src/stores/timeline-store.ts @@ -33,9 +33,12 @@ interface TimelineStore { clipId: string, newIndex: number ) => void; + + // Computed values + getTotalDuration: () => number; } -export const useTimelineStore = create((set) => ({ +export const useTimelineStore = create((set, get) => ({ tracks: [], addTrack: (type) => { @@ -134,4 +137,17 @@ export const useTimelineStore = create((set) => ({ }), })); }, + + getTotalDuration: () => { + const { tracks } = get(); + if (tracks.length === 0) return 0; + + // Calculate the duration of each track (sum of all clips in that track) + const trackDurations = tracks.map((track) => + track.clips.reduce((total, clip) => total + clip.duration, 0) + ); + + // Return the maximum track duration (longest track determines project duration) + return Math.max(...trackDurations, 0); + }, }));