diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-07-17 13:38:16 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-07-17 13:38:16 +0200 |
| commit | e577c9659f38eb9702f0c85a6bdcbc52d2720f2f (patch) | |
| tree | 569f0314338f20c3bcfe11113bfcb6f274839d40 /apps/web/src/components/editor/timeline/timeline-tracks-area.tsx | |
| parent | 8efc696dcddc94b1c248a099207ad97c932a545b (diff) | |
| parent | b1efc90157c87e93de422c900de74a3538040eed (diff) | |
| download | opencut-e577c9659f38eb9702f0c85a6bdcbc52d2720f2f.tar.gz | |
Merge branch 'staging' of https://github.com/mazeincoding/AppCut into staging
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 | 89 |
1 files changed, 89 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..9242bccd --- /dev/null +++ b/apps/web/src/components/editor/timeline/timeline-tracks-area.tsx @@ -0,0 +1,89 @@ +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-[98]" + 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> + </> + ); +} |
