From 6ff4bcd09391096e7c231a53484fd30dca939690 Mon Sep 17 00:00:00 2001 From: Simon Orzel Date: Wed, 16 Jul 2025 23:31:51 +0200 Subject: [PATCH] feat: starts to refactor timeline --- .../src/components/editor/snap-indicator.tsx | 2 +- .../components/editor/timeline-playhead.tsx | 2 +- apps/web/src/components/editor/timeline.tsx | 473 +++++++----------- 3 files changed, 175 insertions(+), 302 deletions(-) diff --git a/apps/web/src/components/editor/snap-indicator.tsx b/apps/web/src/components/editor/snap-indicator.tsx index 83a1f678..846d0bbb 100644 --- a/apps/web/src/components/editor/snap-indicator.tsx +++ b/apps/web/src/components/editor/snap-indicator.tsx @@ -40,7 +40,7 @@ export function SnapIndicator({ return (
(null); + const tracksContainerRef = useRef(null); + + // Temporary refs for compatibility (should be removed when TimelinePlayhead is updated) const rulerScrollRef = useRef(null); const tracksScrollRef = useRef(null); - const trackLabelsRef = useRef(null); - const playheadRef = useRef(null); - const trackLabelsScrollRef = useRef(null); - const isUpdatingRef = useRef(false); - const lastRulerSync = useRef(0); - const lastTracksSync = useRef(0); - const lastVerticalSync = useRef(0); - // Timeline playhead ruler handlers + // Timeline playhead ruler handlers - temporarily keeping all refs for compatibility const { handleRulerMouseDown } = useTimelinePlayheadRuler({ currentTime, duration, @@ -132,7 +129,6 @@ export function Timeline() { }); // Selection box functionality - const tracksContainerRef = useRef(null); const { selectionBox, handleMouseDown: handleSelectionMouseDown, @@ -159,7 +155,7 @@ export function Timeline() { setCurrentSnapPoint(snapPoint); }, []); - // Timeline content click to seek handler + // Timeline content click to seek handler - simplified for single scroll area const handleTimelineContentClick = useCallback( (e: React.MouseEvent) => { console.log( @@ -230,7 +226,7 @@ export function Timeline() { Math.min( duration, (mouseX + scrollLeft) / - (TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel) + (TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel) ) ); @@ -244,11 +240,10 @@ export function Timeline() { duration, zoomLevel, seek, - rulerScrollRef, - tracksScrollRef, clearSelectedElements, isSelecting, justFinishedSelecting, + activeProject?.fps, ] ); @@ -504,84 +499,23 @@ export function Timeline() { clearSelectedElements(); }; - // --- Scroll synchronization effect --- + // Add wheel event listeners with passive: false to allow preventDefault useEffect(() => { - const rulerViewport = rulerScrollRef.current?.querySelector( - "[data-radix-scroll-area-viewport]" - ) as HTMLElement; - const tracksViewport = tracksScrollRef.current?.querySelector( - "[data-radix-scroll-area-viewport]" - ) as HTMLElement; - const trackLabelsViewport = trackLabelsScrollRef.current?.querySelector( - "[data-radix-scroll-area-viewport]" - ) as HTMLElement; + const timelineContainer = timelineRef.current; + if (!timelineContainer || !isInTimeline) return; - if (!rulerViewport || !tracksViewport) return; - - // Horizontal scroll synchronization between ruler and tracks - const handleRulerScroll = () => { - const now = Date.now(); - if (isUpdatingRef.current || now - lastRulerSync.current < 16) return; - lastRulerSync.current = now; - isUpdatingRef.current = true; - tracksViewport.scrollLeft = rulerViewport.scrollLeft; - isUpdatingRef.current = false; - }; - const handleTracksScroll = () => { - const now = Date.now(); - if (isUpdatingRef.current || now - lastTracksSync.current < 16) return; - lastTracksSync.current = now; - isUpdatingRef.current = true; - rulerViewport.scrollLeft = tracksViewport.scrollLeft; - isUpdatingRef.current = false; + const handleWheelCapture = (e: WheelEvent) => { + // Call the existing handleWheel function + handleWheel(e as any); }; - rulerViewport.addEventListener("scroll", handleRulerScroll); - tracksViewport.addEventListener("scroll", handleTracksScroll); - - // Vertical scroll synchronization between track labels and tracks content - if (trackLabelsViewport) { - const handleTrackLabelsScroll = () => { - const now = Date.now(); - if (isUpdatingRef.current || now - lastVerticalSync.current < 16) - return; - lastVerticalSync.current = now; - isUpdatingRef.current = true; - tracksViewport.scrollTop = trackLabelsViewport.scrollTop; - isUpdatingRef.current = false; - }; - const handleTracksVerticalScroll = () => { - const now = Date.now(); - if (isUpdatingRef.current || now - lastVerticalSync.current < 16) - return; - lastVerticalSync.current = now; - isUpdatingRef.current = true; - trackLabelsViewport.scrollTop = tracksViewport.scrollTop; - isUpdatingRef.current = false; - }; - - trackLabelsViewport.addEventListener("scroll", handleTrackLabelsScroll); - tracksViewport.addEventListener("scroll", handleTracksVerticalScroll); - - return () => { - rulerViewport.removeEventListener("scroll", handleRulerScroll); - tracksViewport.removeEventListener("scroll", handleTracksScroll); - trackLabelsViewport.removeEventListener( - "scroll", - handleTrackLabelsScroll - ); - tracksViewport.removeEventListener( - "scroll", - handleTracksVerticalScroll - ); - }; - } + // Add wheel event listener with passive: false to allow preventDefault + timelineContainer.addEventListener("wheel", handleWheelCapture, { passive: false }); return () => { - rulerViewport.removeEventListener("scroll", handleRulerScroll); - tracksViewport.removeEventListener("scroll", handleTracksScroll); + timelineContainer.removeEventListener("wheel", handleWheelCapture); }; - }, []); + }, [handleWheel, isInTimeline]); return (
setIsInTimeline(false)} > {/* Toolbar */} -
+
- {/* Play/Pause Button */}