From 886cf81bd0078f8d70f89fa5290052f5b23a9a12 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Thu, 28 Aug 2025 23:59:40 +0200 Subject: feat: timeline auto-scroll for moving clips --- apps/web/src/components/editor/timeline/index.tsx | 2 ++ .../src/components/editor/timeline/timeline-track.tsx | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'apps/web/src/components/editor/timeline') diff --git a/apps/web/src/components/editor/timeline/index.tsx b/apps/web/src/components/editor/timeline/index.tsx index 49769989..c994d707 100644 --- a/apps/web/src/components/editor/timeline/index.tsx +++ b/apps/web/src/components/editor/timeline/index.tsx @@ -878,6 +878,8 @@ export function Timeline() { track={track} zoomLevel={zoomLevel} onSnapPointChange={handleSnapPointChange} + rulerScrollRef={rulerScrollRef} + tracksScrollRef={tracksScrollRef} /> diff --git a/apps/web/src/components/editor/timeline/timeline-track.tsx b/apps/web/src/components/editor/timeline/timeline-track.tsx index ad3ca9b7..42c78aa4 100644 --- a/apps/web/src/components/editor/timeline/timeline-track.tsx +++ b/apps/web/src/components/editor/timeline/timeline-track.tsx @@ -24,15 +24,20 @@ import { } from "@/constants/timeline-constants"; import { DEFAULT_FPS, useProjectStore } from "@/stores/project-store"; import { useTimelineSnapping, SnapPoint } from "@/hooks/use-timeline-snapping"; +import { useEdgeAutoScroll } from "@/hooks/use-edge-auto-scroll"; export function TimelineTrackContent({ track, zoomLevel, onSnapPointChange, + rulerScrollRef, + tracksScrollRef, }: { track: TimelineTrack; zoomLevel: number; onSnapPointChange?: (snapPoint: SnapPoint | null) => void; + rulerScrollRef: React.RefObject; + tracksScrollRef: React.RefObject; }) { const { mediaFiles } = useMediaStore(); const { @@ -54,7 +59,7 @@ export function TimelineTrackContent({ rippleEditingEnabled, } = useTimelineStore(); - const { currentTime } = usePlaybackStore(); + const { currentTime, duration } = usePlaybackStore(); // Initialize snapping hook const { snapElementPosition, snapElementEdge } = useTimelineSnapping({ @@ -126,12 +131,15 @@ export function TimelineTrackContent({ y: number; } | null>(null); + const lastMouseXRef = useRef(0); + // Set up mouse event listeners for drag useEffect(() => { if (!dragState.isDragging) return; const handleMouseMove = (e: MouseEvent) => { if (!timelineRef.current) return; + lastMouseXRef.current = e.clientX; // On first mouse move during drag, ensure the element is selected if (dragState.elementId && dragState.trackId) { @@ -402,6 +410,14 @@ export function TimelineTrackContent({ onSnapPointChange, ]); + useEdgeAutoScroll({ + isActive: dragState.isDragging, + getMouseClientX: () => lastMouseXRef.current, + rulerScrollRef, + tracksScrollRef, + contentWidth: duration * TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel, + }); + const handleElementMouseDown = ( e: React.MouseEvent, element: TimelineElementType -- cgit v1.3.1