diff --git a/web/src/components/timeline/EventSegment.tsx b/web/src/components/timeline/EventSegment.tsx index 67adda5b8..5ce8d65fa 100644 --- a/web/src/components/timeline/EventSegment.tsx +++ b/web/src/components/timeline/EventSegment.tsx @@ -196,13 +196,16 @@ export function EventSegment({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [startTimestamp]); - const [segmentVisible, setSegmentVisible] = useState(false); + const [segmentRendered, setSegmentRendered] = useState(false); const segmentObserverRef = useRef(null); - const segmentRef = useRef(null); + const segmentRef = useRef(null); + useEffect(() => { const segmentObserver = new IntersectionObserver( ([entry]) => { - setSegmentVisible(entry.isIntersecting); + if (entry.isIntersecting && !segmentRendered) { + setSegmentRendered(true); + } }, { threshold: 0 }, ); @@ -218,7 +221,18 @@ export function EventSegment({ segmentObserverRef.current.disconnect(); } }; - }, []); + }, [segmentRendered]); + + if (!segmentRendered) { + return ( +
+ ); + } return (
handleTouchStart(event, segmentClick)} > - {segmentVisible && ( - <> - {showMinimap && ( - - )} + {showMinimap && ( + + )} - + - + - {severity.map((severityValue: number, index: number) => ( - - {severityValue === displaySeverityType && ( - - -
-
-
-
-
-
-
+ {severity.map((severityValue: number, index: number) => ( + + {severityValue === displaySeverityType && ( + + +
+
+
+
+
- - - - - - - - )} - - ))} - - )} +
+
+
+ + + + + +
+ )} +
+ ))}
); } diff --git a/web/src/components/timeline/MotionReviewTimeline.tsx b/web/src/components/timeline/MotionReviewTimeline.tsx index 2834437cd..157e53749 100644 --- a/web/src/components/timeline/MotionReviewTimeline.tsx +++ b/web/src/components/timeline/MotionReviewTimeline.tsx @@ -1,9 +1,8 @@ -import { useEffect, useCallback, useMemo, useRef, RefObject } from "react"; +import { useCallback, useMemo, useRef, RefObject } from "react"; import MotionSegment from "./MotionSegment"; import { useTimelineUtils } from "@/hooks/use-timeline-utils"; import { MotionData, ReviewSegment, ReviewSeverity } from "@/types/review"; import ReviewTimeline from "./ReviewTimeline"; -import { isDesktop } from "react-device-detect"; import { useMotionSegmentUtils } from "@/hooks/use-motion-segment-utils"; export type MotionReviewTimelineProps = { @@ -165,42 +164,6 @@ export function MotionReviewTimeline({ ], ); - const segmentsObserver = useRef(null); - useEffect(() => { - if (selectedTimelineRef.current && segments && isDesktop) { - segmentsObserver.current = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - const segmentId = entry.target.getAttribute("data-segment-id"); - - const segmentElements = - internalTimelineRef.current?.querySelectorAll( - `[data-segment-id="${segmentId}"] .motion-segment`, - ); - segmentElements?.forEach((segmentElement) => { - segmentElement.classList.remove("hidden"); - segmentElement.classList.add("animate-in"); - }); - } - }); - }, - { threshold: 0 }, - ); - - // Get all segment divs and observe each one - const segmentDivs = - selectedTimelineRef.current.querySelectorAll(".segment.has-data"); - segmentDivs.forEach((segmentDiv) => { - segmentsObserver.current?.observe(segmentDiv); - }); - } - - return () => { - segmentsObserver.current?.disconnect(); - }; - }, [selectedTimelineRef, segments]); - return ( 0 ? "hidden" : ""} - zoom-in-[0.2] ${secondHalfSegmentWidth < 5 ? "duration-200" : "duration-1000"}`; - const animationClassesFirstHalf = `motion-segment ${firstHalfSegmentWidth > 0 ? "hidden" : ""} - zoom-in-[0.2] ${firstHalfSegmentWidth < 5 ? "duration-200" : "duration-1000"}`; - const severityColorsBg: { [key: number]: string } = { 1: reviewed ? "from-severity_significant_motion-dimmed/10 to-severity_significant_motion/10" @@ -162,6 +163,44 @@ export function MotionSegment({ } }, [segmentTime, setHandlebarTime]); + const [segmentRendered, setSegmentRendered] = useState(false); + const segmentObserverRef = useRef(null); + const segmentRef = useRef(null); + + useEffect(() => { + const segmentObserver = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting && !segmentRendered) { + setSegmentRendered(true); + } + }, + { threshold: 0 }, + ); + + if (segmentRef.current) { + segmentObserver.observe(segmentRef.current); + } + + segmentObserverRef.current = segmentObserver; + + return () => { + if (segmentObserverRef.current) { + segmentObserverRef.current.disconnect(); + } + }; + }, [segmentRendered]); + + if (!segmentRendered) { + return ( +
+ ); + } + return ( <> {(((firstHalfSegmentWidth > 0 || secondHalfSegmentWidth > 0) && @@ -171,6 +210,7 @@ export function MotionSegment({