diff options
| author | Simon Orzel <simonorzel@gmail.com> | 2025-07-17 01:59:39 +0200 |
|---|---|---|
| committer | Simon Orzel <simonorzel@gmail.com> | 2025-07-17 01:59:39 +0200 |
| commit | 9fa9f406fe2722cec1e0d65d9b3868acd1e99f87 (patch) | |
| tree | 8d6eebabf99941c970a36dc271da9e9d63128f42 /apps/web/src/components/editor/timeline/timeline-tracks-area.tsx | |
| parent | 0d2894feda369d518f650ac2c832edb0bb8b9254 (diff) | |
| download | opencut-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.tsx | 99 |
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> + </> + ); +} |
