summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/timeline/timeline-tracks-area.tsx
diff options
context:
space:
mode:
authorSimon Orzel <simonorzel@gmail.com>2025-07-17 01:59:39 +0200
committerSimon Orzel <simonorzel@gmail.com>2025-07-17 01:59:39 +0200
commit9fa9f406fe2722cec1e0d65d9b3868acd1e99f87 (patch)
tree8d6eebabf99941c970a36dc271da9e9d63128f42 /apps/web/src/components/editor/timeline/timeline-tracks-area.tsx
parent0d2894feda369d518f650ac2c832edb0bb8b9254 (diff)
downloadopencut-9fa9f406fe2722cec1e0d65d9b3868acd1e99f87.tar.gz
feat: splits working code
Diffstat (limited to 'apps/web/src/components/editor/timeline/timeline-tracks-area.tsx')
-rw-r--r--apps/web/src/components/editor/timeline/timeline-tracks-area.tsx99
1 files changed, 99 insertions, 0 deletions
diff --git a/apps/web/src/components/editor/timeline/timeline-tracks-area.tsx b/apps/web/src/components/editor/timeline/timeline-tracks-area.tsx
new file mode 100644
index 00000000..293c8cc9
--- /dev/null
+++ b/apps/web/src/components/editor/timeline/timeline-tracks-area.tsx
@@ -0,0 +1,99 @@
+import { Fragment } from "react";
+import { Plus } from "lucide-react";
+import {
+ ContextMenu,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuTrigger,
+} from "../../ui/context-menu";
+import { useTimelineStore } from "@/stores/timeline-store";
+import { TimelineTrackContent } from "../timeline-track";
+import { TrackIcon } from "./track-icon";
+import { getTrackHeight } from "@/constants/timeline-constants";
+import type { TimelineTrack } from "@/types/timeline";
+import type { SnapPoint } from "@/hooks/use-timeline-snapping";
+
+export interface TimelineTracksAreaProps {
+ tracks: TimelineTrack[];
+ zoomLevel: number;
+ handleSnapPointChange: (snapPoint: SnapPoint | null) => void;
+ clearSelectedElements: () => void;
+}
+
+export function TimelineTracksArea({
+ tracks,
+ zoomLevel,
+ handleSnapPointChange,
+ clearSelectedElements,
+}: TimelineTracksAreaProps) {
+ const { addTrack, toggleTrackMute } = useTimelineStore();
+
+ return (
+ <>
+ {/* Track Rows */}
+ {tracks.map((track, index) => (
+ <Fragment key={track.id}>
+ {/* Left Column (Sticky Track Labels) */}
+ <div
+ className="sticky left-0 flex items-center border-b border-panel border-inset group bg-card/[0.99] z-[90]"
+ style={{ height: `${getTrackHeight(track.type)}px` }}
+ >
+ <div className="flex items-center gap-2 px-2">
+ <TrackIcon track={track} />
+ </div>
+ {track.muted && (
+ <span className="text-xs text-red-500 font-semibold">
+ Muted
+ </span>
+ )}
+ </div>
+
+ {/* Scrollable Track Content */}
+ <ContextMenu>
+ <ContextMenuTrigger asChild>
+ <div
+ className=" h-full"
+ onClick={(e) => {
+ // If clicking empty area (not on a element), deselect all elements
+ if (
+ !(e.target as HTMLElement).closest(
+ ".timeline-element"
+ )
+ ) {
+ clearSelectedElements();
+ }
+ }}
+ >
+ <TimelineTrackContent
+ track={track}
+ zoomLevel={zoomLevel}
+ onSnapPointChange={handleSnapPointChange}
+ />
+ </div>
+ </ContextMenuTrigger>
+ <ContextMenuContent>
+ <ContextMenuItem
+ onClick={() => toggleTrackMute(track.id)}
+ >
+ {track.muted ? "Unmute Track" : "Mute Track"}
+ </ContextMenuItem>
+ <ContextMenuItem>
+ Track settings (soon)
+ </ContextMenuItem>
+ </ContextMenuContent>
+ </ContextMenu>
+ </Fragment>
+ ))}
+ {/* Add Track Button - spans full width */}
+ <div
+ onClick={() => addTrack('media')}
+ className="col-span-1 sticky left-0 w-full flex items-center border-b border-muted bg-card/[0.99] hover:bg-card/50 transition-colors cursor-pointer z-[89]"
+ style={{ height: `${getTrackHeight("media")}px` }}
+ >
+ <div className="w-full flex justify-center items-center">
+ <Plus className="w-4 h-4 text-muted-foreground" />
+ </div>
+ </div>
+ </>
+ );
+}