summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/panels/timeline/timeline-playhead.tsx
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-20 11:31:17 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-20 11:31:17 +0200
commit3e89d2998588f8e35c524e523ba2ee853f0f6475 (patch)
tree57221f96c1259b3b07e3ddf8c1adefc502b9d8eb /apps/web/src/components/editor/panels/timeline/timeline-playhead.tsx
parent729d10592f4e802f91c555c309ff3ba4b119f843 (diff)
downloadopencut-3e89d2998588f8e35c524e523ba2ee853f0f6475.tar.gz
refactor: restructure files to their domains, new preview overlay system, and dep graph
Diffstat (limited to 'apps/web/src/components/editor/panels/timeline/timeline-playhead.tsx')
-rw-r--r--apps/web/src/components/editor/panels/timeline/timeline-playhead.tsx114
1 files changed, 0 insertions, 114 deletions
diff --git a/apps/web/src/components/editor/panels/timeline/timeline-playhead.tsx b/apps/web/src/components/editor/panels/timeline/timeline-playhead.tsx
deleted file mode 100644
index d9218371..00000000
--- a/apps/web/src/components/editor/panels/timeline/timeline-playhead.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-"use client";
-
-import { useRef } from "react";
-import {
- getCenteredLineLeft,
- TIMELINE_INDICATOR_LINE_WIDTH_PX,
- timelineTimeToSnappedPixels,
-} from "@/lib/timeline";
-import { useTimelinePlayhead } from "@/hooks/timeline/use-timeline-playhead";
-import { TICKS_PER_SECOND } from "@/lib/wasm";
-import { useEditor } from "@/hooks/use-editor";
-import {
- TIMELINE_SCROLLBAR_SIZE_PX,
-} from "./layout";
-import { TIMELINE_LAYERS } from "./layers";
-
-interface TimelinePlayheadProps {
- zoomLevel: number;
- hasHorizontalScrollbar: boolean;
- rulerRef: React.RefObject<HTMLDivElement | null>;
- rulerScrollRef: React.RefObject<HTMLDivElement | null>;
- tracksScrollRef: React.RefObject<HTMLDivElement | null>;
- timelineRef: React.RefObject<HTMLDivElement | null>;
- playheadRef?: React.RefObject<HTMLDivElement | null>;
- isSnappingToPlayhead?: boolean;
-}
-
-export function TimelinePlayhead({
- zoomLevel,
- hasHorizontalScrollbar,
- rulerRef,
- rulerScrollRef,
- tracksScrollRef,
- timelineRef,
- playheadRef: externalPlayheadRef,
- isSnappingToPlayhead = false,
-}: TimelinePlayheadProps) {
- const editor = useEditor();
- const duration = editor.timeline.getTotalDuration();
- const internalPlayheadRef = useRef<HTMLDivElement>(null);
- const playheadRef = externalPlayheadRef || internalPlayheadRef;
-
- const { handlePlayheadMouseDown } = useTimelinePlayhead({
- zoomLevel,
- rulerRef,
- rulerScrollRef,
- tracksScrollRef,
- playheadRef,
- });
-
- const timelineContainerHeight =
- timelineRef.current?.clientHeight ??
- tracksScrollRef.current?.clientHeight ??
- 400;
- const totalHeight = Math.max(
- 0,
- timelineContainerHeight -
- (hasHorizontalScrollbar ? TIMELINE_SCROLLBAR_SIZE_PX - 5 : 0),
- );
-
- const currentTime = editor.playback.getCurrentTime();
- const centerPosition = timelineTimeToSnappedPixels({
- time: currentTime,
- zoomLevel,
- });
- const scrollLeft = tracksScrollRef.current?.scrollLeft ?? 0;
- const leftPosition =
- getCenteredLineLeft({ centerPixel: centerPosition }) - scrollLeft;
-
- const handlePlayheadKeyDown = (
- event: React.KeyboardEvent<HTMLDivElement>,
- ) => {
- if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
-
- event.preventDefault();
- const fps = editor.project.getActive().settings.fps;
- const ticksPerFrame = Math.round(TICKS_PER_SECOND * fps.denominator / fps.numerator);
- const direction = event.key === "ArrowRight" ? 1 : -1;
- const now = editor.playback.getCurrentTime();
- const nextTime = Math.max(0, Math.min(duration, now + direction * ticksPerFrame));
-
- editor.playback.seek({ time: nextTime });
- };
-
- return (
- <div
- ref={playheadRef}
- role="slider"
- aria-label="Timeline playhead"
- aria-valuemin={0}
- aria-valuemax={duration}
- aria-valuenow={currentTime}
- tabIndex={0}
- className="pointer-events-none absolute"
- style={{
- left: `${leftPosition}px`,
- top: 0,
- height: `${totalHeight}px`,
- width: `${TIMELINE_INDICATOR_LINE_WIDTH_PX}px`,
- zIndex: TIMELINE_LAYERS.playhead,
- }}
- onKeyDown={handlePlayheadKeyDown}
- >
- <div className="bg-primary pointer-events-none absolute left-0 h-full w-0.5" />
-
- <button
- type="button"
- aria-label="Drag playhead"
- className={`pointer-events-auto absolute top-1 left-1/2 size-3 -translate-x-1/2 transform cursor-col-resize rounded-full border-2 shadow-xs ${isSnappingToPlayhead ? "bg-primary border-primary" : "bg-primary border-primary/50"}`}
- onMouseDown={handlePlayheadMouseDown}
- />
- </div>
- );
-}