Timeline fixes and export handles (#10522)

* select an export range from timeline

* height tweak
This commit is contained in:
Josh Hawkins
2024-03-18 15:58:54 -05:00
committed by GitHub
parent 880bae1eb2
commit d249e5b27f
14 changed files with 771 additions and 249 deletions

View File

@@ -1,4 +1,4 @@
import useDraggableHandler from "@/hooks/use-handle-dragging";
import useDraggableElement from "@/hooks/use-draggable-element";
import {
useEffect,
useCallback,
@@ -8,7 +8,7 @@ import {
RefObject,
} from "react";
import EventSegment from "./EventSegment";
import { useEventUtils } from "@/hooks/use-event-utils";
import { useTimelineUtils } from "@/hooks/use-timeline-utils";
import { ReviewSegment, ReviewSeverity } from "@/types/review";
import ReviewTimeline from "./ReviewTimeline";
@@ -23,6 +23,11 @@ export type EventReviewTimelineProps = {
showMinimap?: boolean;
minimapStartTime?: number;
minimapEndTime?: number;
showExportHandles?: boolean;
exportStartTime?: number;
exportEndTime?: number;
setExportStartTime?: React.Dispatch<React.SetStateAction<number>>;
setExportEndTime?: React.Dispatch<React.SetStateAction<number>>;
events: ReviewSegment[];
severityType: ReviewSeverity;
contentRef: RefObject<HTMLDivElement>;
@@ -40,47 +45,113 @@ export function EventReviewTimeline({
showMinimap = false,
minimapStartTime,
minimapEndTime,
showExportHandles = false,
exportStartTime,
exportEndTime,
setExportStartTime,
setExportEndTime,
events,
severityType,
contentRef,
onHandlebarDraggingChange,
}: EventReviewTimelineProps) {
const [isDragging, setIsDragging] = useState(false);
const handlebarRef = useRef<HTMLDivElement>(null);
const [exportStartPosition, setExportStartPosition] = useState(0);
const [exportEndPosition, setExportEndPosition] = useState(0);
const timelineRef = useRef<HTMLDivElement>(null);
const handlebarRef = useRef<HTMLDivElement>(null);
const handlebarTimeRef = useRef<HTMLDivElement>(null);
const exportStartRef = useRef<HTMLDivElement>(null);
const exportStartTimeRef = useRef<HTMLDivElement>(null);
const exportEndRef = useRef<HTMLDivElement>(null);
const exportEndTimeRef = useRef<HTMLDivElement>(null);
const timelineDuration = useMemo(
() => timelineStart - timelineEnd,
[timelineEnd, timelineStart],
);
const { alignStartDateToTimeline, alignEndDateToTimeline } = useEventUtils(
events,
segmentDuration,
);
const { alignStartDateToTimeline, alignEndDateToTimeline } =
useTimelineUtils(segmentDuration);
const timelineStartAligned = useMemo(
() => alignStartDateToTimeline(timelineStart),
[timelineStart, alignStartDateToTimeline],
);
const { handleMouseDown, handleMouseUp, handleMouseMove } =
useDraggableHandler({
contentRef,
timelineRef,
handlebarRef,
alignStartDateToTimeline,
alignEndDateToTimeline,
segmentDuration,
showHandlebar,
handlebarTime,
setHandlebarTime,
timelineDuration,
timelineStartAligned,
isDragging,
setIsDragging,
handlebarTimeRef,
});
const paddedExportStartTime = useMemo(() => {
if (exportStartTime) {
return alignStartDateToTimeline(exportStartTime) + segmentDuration;
}
}, [exportStartTime, segmentDuration, alignStartDateToTimeline]);
const paddedExportEndTime = useMemo(() => {
if (exportEndTime) {
return alignEndDateToTimeline(exportEndTime) - segmentDuration * 2;
}
}, [exportEndTime, segmentDuration, alignEndDateToTimeline]);
const {
handleMouseDown: handlebarMouseDown,
handleMouseUp: handlebarMouseUp,
handleMouseMove: handlebarMouseMove,
} = useDraggableElement({
contentRef,
timelineRef,
draggableElementRef: handlebarRef,
segmentDuration,
showDraggableElement: showHandlebar,
draggableElementTime: handlebarTime,
setDraggableElementTime: setHandlebarTime,
timelineDuration,
timelineStartAligned,
isDragging,
setIsDragging,
draggableElementTimeRef: handlebarTimeRef,
});
const {
handleMouseDown: exportStartMouseDown,
handleMouseUp: exportStartMouseUp,
handleMouseMove: exportStartMouseMove,
} = useDraggableElement({
contentRef,
timelineRef,
draggableElementRef: exportStartRef,
segmentDuration,
showDraggableElement: showExportHandles,
draggableElementTime: exportStartTime,
draggableElementLatestTime: paddedExportEndTime,
setDraggableElementTime: setExportStartTime,
timelineDuration,
timelineStartAligned,
isDragging,
setIsDragging,
draggableElementTimeRef: exportStartTimeRef,
setDraggableElementPosition: setExportStartPosition,
});
const {
handleMouseDown: exportEndMouseDown,
handleMouseUp: exportEndMouseUp,
handleMouseMove: exportEndMouseMove,
} = useDraggableElement({
contentRef,
timelineRef,
draggableElementRef: exportEndRef,
segmentDuration,
showDraggableElement: showExportHandles,
draggableElementTime: exportEndTime,
draggableElementEarliestTime: paddedExportStartTime,
setDraggableElementTime: setExportEndTime,
timelineDuration,
timelineStartAligned,
isDragging,
setIsDragging,
draggableElementTimeRef: exportEndTimeRef,
setDraggableElementPosition: setExportEndPosition,
});
// Generate segments for the timeline
const generateSegments = useCallback(() => {
@@ -145,12 +216,26 @@ export function EventReviewTimeline({
timelineRef={timelineRef}
handlebarRef={handlebarRef}
handlebarTimeRef={handlebarTimeRef}
handleMouseMove={handleMouseMove}
handleMouseUp={handleMouseUp}
handleMouseDown={handleMouseDown}
handlebarMouseMove={handlebarMouseMove}
handlebarMouseUp={handlebarMouseUp}
handlebarMouseDown={handlebarMouseDown}
segmentDuration={segmentDuration}
timelineDuration={timelineDuration}
showHandlebar={showHandlebar}
isDragging={isDragging}
exportStartMouseMove={exportStartMouseMove}
exportStartMouseUp={exportStartMouseUp}
exportStartMouseDown={exportStartMouseDown}
exportEndMouseMove={exportEndMouseMove}
exportEndMouseUp={exportEndMouseUp}
exportEndMouseDown={exportEndMouseDown}
showExportHandles={showExportHandles}
exportStartRef={exportStartRef}
exportStartTimeRef={exportStartTimeRef}
exportEndRef={exportEndRef}
exportEndTimeRef={exportEndTimeRef}
exportStartPosition={exportStartPosition}
exportEndPosition={exportEndPosition}
>
{segments}
</ReviewTimeline>

View File

@@ -1,5 +1,5 @@
import { useApiHost } from "@/api";
import { useEventUtils } from "@/hooks/use-event-utils";
import { useTimelineUtils } from "@/hooks/use-timeline-utils";
import { useEventSegmentUtils } from "@/hooks/use-event-segment-utils";
import { ReviewSegment, ReviewSeverity } from "@/types/review";
import React, {
@@ -53,10 +53,8 @@ export function EventSegment({
getEventThumbnail,
} = useEventSegmentUtils(segmentDuration, events, severityType);
const { alignStartDateToTimeline, alignEndDateToTimeline } = useEventUtils(
events,
segmentDuration,
);
const { alignStartDateToTimeline, alignEndDateToTimeline } =
useTimelineUtils(segmentDuration);
const severity = useMemo(
() => getSeverity(segmentTime, displaySeverityType),
@@ -155,7 +153,7 @@ export function EventSegment({
: ""
} ${
isFirstSegmentInMinimap || isLastSegmentInMinimap
? "relative h-2 border-b-2 border-gray-500"
? "relative h-2 border-b-2 border-neutral-600"
: ""
}`;
@@ -236,7 +234,7 @@ export function EventSegment({
key={`${segmentKey}_${index}_primary_data`}
className={`w-full h-2 bg-gradient-to-r ${roundBottomPrimary ? "rounded-bl-full rounded-br-full" : ""} ${roundTopPrimary ? "rounded-tl-full rounded-tr-full" : ""} ${severityColors[severityValue]}`}
onClick={segmentClick}
onTouchStart={(event) =>
onTouchEnd={(event) =>
handleTouchStart(event, segmentClick)
}
></div>

View File

@@ -1,4 +1,4 @@
import useDraggableHandler from "@/hooks/use-handle-dragging";
import useDraggableElement from "@/hooks/use-draggable-element";
import {
useEffect,
useCallback,
@@ -8,7 +8,7 @@ import {
RefObject,
} from "react";
import MotionSegment from "./MotionSegment";
import { useEventUtils } from "@/hooks/use-event-utils";
import { useTimelineUtils } from "@/hooks/use-timeline-utils";
import { MotionData, ReviewSegment, ReviewSeverity } from "@/types/review";
import ReviewTimeline from "./ReviewTimeline";
@@ -23,6 +23,11 @@ export type MotionReviewTimelineProps = {
showMinimap?: boolean;
minimapStartTime?: number;
minimapEndTime?: number;
showExportHandles?: boolean;
exportStartTime?: number;
exportEndTime?: number;
setExportStartTime?: React.Dispatch<React.SetStateAction<number>>;
setExportEndTime?: React.Dispatch<React.SetStateAction<number>>;
events: ReviewSegment[];
motion_events: MotionData[];
severityType: ReviewSeverity;
@@ -41,47 +46,113 @@ export function MotionReviewTimeline({
showMinimap = false,
minimapStartTime,
minimapEndTime,
showExportHandles = false,
exportStartTime,
exportEndTime,
setExportStartTime,
setExportEndTime,
events,
motion_events,
contentRef,
onHandlebarDraggingChange,
}: MotionReviewTimelineProps) {
const [isDragging, setIsDragging] = useState(false);
const handlebarRef = useRef<HTMLDivElement>(null);
const [exportStartPosition, setExportStartPosition] = useState(0);
const [exportEndPosition, setExportEndPosition] = useState(0);
const timelineRef = useRef<HTMLDivElement>(null);
const handlebarRef = useRef<HTMLDivElement>(null);
const handlebarTimeRef = useRef<HTMLDivElement>(null);
const exportStartRef = useRef<HTMLDivElement>(null);
const exportStartTimeRef = useRef<HTMLDivElement>(null);
const exportEndRef = useRef<HTMLDivElement>(null);
const exportEndTimeRef = useRef<HTMLDivElement>(null);
const timelineDuration = useMemo(
() => timelineStart - timelineEnd + 4 * segmentDuration,
[timelineEnd, timelineStart, segmentDuration],
);
const { alignStartDateToTimeline, alignEndDateToTimeline } = useEventUtils(
events,
segmentDuration,
);
const { alignStartDateToTimeline, alignEndDateToTimeline } =
useTimelineUtils(segmentDuration);
const timelineStartAligned = useMemo(
() => alignStartDateToTimeline(timelineStart) + 2 * segmentDuration,
[timelineStart, alignStartDateToTimeline, segmentDuration],
);
const { handleMouseDown, handleMouseUp, handleMouseMove } =
useDraggableHandler({
contentRef,
timelineRef,
handlebarRef,
alignStartDateToTimeline,
alignEndDateToTimeline,
segmentDuration,
showHandlebar,
handlebarTime,
setHandlebarTime,
timelineDuration,
timelineStartAligned,
isDragging,
setIsDragging,
handlebarTimeRef,
});
const paddedExportStartTime = useMemo(() => {
if (exportStartTime) {
return alignStartDateToTimeline(exportStartTime) + segmentDuration;
}
}, [exportStartTime, segmentDuration, alignStartDateToTimeline]);
const paddedExportEndTime = useMemo(() => {
if (exportEndTime) {
return alignEndDateToTimeline(exportEndTime) - segmentDuration * 2;
}
}, [exportEndTime, segmentDuration, alignEndDateToTimeline]);
const {
handleMouseDown: handlebarMouseDown,
handleMouseUp: handlebarMouseUp,
handleMouseMove: handlebarMouseMove,
} = useDraggableElement({
contentRef,
timelineRef,
draggableElementRef: handlebarRef,
segmentDuration,
showDraggableElement: showHandlebar,
draggableElementTime: handlebarTime,
setDraggableElementTime: setHandlebarTime,
timelineDuration,
timelineStartAligned,
isDragging,
setIsDragging,
draggableElementTimeRef: handlebarTimeRef,
});
const {
handleMouseDown: exportStartMouseDown,
handleMouseUp: exportStartMouseUp,
handleMouseMove: exportStartMouseMove,
} = useDraggableElement({
contentRef,
timelineRef,
draggableElementRef: exportStartRef,
segmentDuration,
showDraggableElement: showExportHandles,
draggableElementTime: exportStartTime,
draggableElementLatestTime: paddedExportEndTime,
setDraggableElementTime: setExportStartTime,
timelineDuration,
timelineStartAligned,
isDragging,
setIsDragging,
draggableElementTimeRef: exportStartTimeRef,
setDraggableElementPosition: setExportStartPosition,
});
const {
handleMouseDown: exportEndMouseDown,
handleMouseUp: exportEndMouseUp,
handleMouseMove: exportEndMouseMove,
} = useDraggableElement({
contentRef,
timelineRef,
draggableElementRef: exportEndRef,
segmentDuration,
showDraggableElement: showExportHandles,
draggableElementTime: exportEndTime,
draggableElementEarliestTime: paddedExportStartTime,
setDraggableElementTime: setExportEndTime,
timelineDuration,
timelineStartAligned,
isDragging,
setIsDragging,
draggableElementTimeRef: exportEndTimeRef,
setDraggableElementPosition: setExportEndPosition,
});
// Generate segments for the timeline
const generateSegments = useCallback(() => {
@@ -147,12 +218,26 @@ export function MotionReviewTimeline({
timelineRef={timelineRef}
handlebarRef={handlebarRef}
handlebarTimeRef={handlebarTimeRef}
handleMouseMove={handleMouseMove}
handleMouseUp={handleMouseUp}
handleMouseDown={handleMouseDown}
handlebarMouseMove={handlebarMouseMove}
handlebarMouseUp={handlebarMouseUp}
handlebarMouseDown={handlebarMouseDown}
segmentDuration={segmentDuration}
timelineDuration={timelineDuration}
showHandlebar={showHandlebar}
isDragging={isDragging}
exportStartMouseMove={exportStartMouseMove}
exportStartMouseUp={exportStartMouseUp}
exportStartMouseDown={exportStartMouseDown}
exportEndMouseMove={exportEndMouseMove}
exportEndMouseUp={exportEndMouseUp}
exportEndMouseDown={exportEndMouseDown}
showExportHandles={showExportHandles}
exportStartRef={exportStartRef}
exportStartTimeRef={exportStartTimeRef}
exportEndRef={exportEndRef}
exportEndTimeRef={exportEndTimeRef}
exportStartPosition={exportStartPosition}
exportEndPosition={exportEndPosition}
>
{segments}
</ReviewTimeline>

View File

@@ -1,4 +1,4 @@
import { useEventUtils } from "@/hooks/use-event-utils";
import { useTimelineUtils } from "@/hooks/use-timeline-utils";
import { useEventSegmentUtils } from "@/hooks/use-event-segment-utils";
import { MotionData, ReviewSegment } from "@/types/review";
import React, { useCallback, useEffect, useMemo, useRef } from "react";
@@ -42,10 +42,8 @@ export function MotionSegment({
const { getMotionSegmentValue, interpolateMotionAudioData } =
useMotionSegmentUtils(segmentDuration, motion_events);
const { alignStartDateToTimeline, alignEndDateToTimeline } = useEventUtils(
events,
segmentDuration,
);
const { alignStartDateToTimeline, alignEndDateToTimeline } =
useTimelineUtils(segmentDuration);
const { handleTouchStart } = useTapUtils();
@@ -180,7 +178,7 @@ export function MotionSegment({
key={segmentKey}
className={segmentClasses}
onClick={segmentClick}
onTouchStart={(event) => handleTouchStart(event, segmentClick)}
onTouchEnd={(event) => handleTouchStart(event, segmentClick)}
>
<MinimapBounds
isFirstSegmentInMinimap={isFirstSegmentInMinimap}

View File

@@ -1,28 +1,75 @@
import { ReactNode, RefObject } from "react";
import { DraggableElement } from "@/types/draggable-element";
import {
ReactNode,
RefObject,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { isIOS, isMobile } from "react-device-detect";
export type ReviewTimelineProps = {
timelineRef: RefObject<HTMLDivElement>;
handlebarRef: RefObject<HTMLDivElement>;
handlebarTimeRef: RefObject<HTMLDivElement>;
handleMouseMove: (
handlebarMouseMove: (
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => void;
handleMouseUp: (
handlebarMouseUp: (
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => void;
handleMouseDown: (
handlebarMouseDown: (
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => void;
segmentDuration: number;
timelineDuration: number;
showHandlebar: boolean;
showExportHandles: boolean;
exportStartRef: RefObject<HTMLDivElement>;
exportStartTimeRef: RefObject<HTMLDivElement>;
exportEndRef: RefObject<HTMLDivElement>;
exportEndTimeRef: RefObject<HTMLDivElement>;
exportStartMouseMove: (
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => void;
exportStartMouseUp: (
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => void;
exportStartMouseDown: (
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => void;
exportEndMouseMove: (
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => void;
exportEndMouseUp: (
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => void;
exportEndMouseDown: (
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => void;
isDragging: boolean;
exportStartPosition?: number;
exportEndPosition?: number;
children: ReactNode;
};
@@ -30,14 +77,156 @@ export function ReviewTimeline({
timelineRef,
handlebarRef,
handlebarTimeRef,
handleMouseMove,
handleMouseUp,
handleMouseDown,
handlebarMouseMove,
handlebarMouseUp,
handlebarMouseDown,
segmentDuration,
timelineDuration,
showHandlebar = false,
showExportHandles = false,
exportStartRef,
exportStartTimeRef,
exportEndRef,
exportEndTimeRef,
exportStartMouseMove,
exportStartMouseUp,
exportStartMouseDown,
exportEndMouseMove,
exportEndMouseUp,
exportEndMouseDown,
isDragging,
exportStartPosition,
exportEndPosition,
children,
}: ReviewTimelineProps) {
const exportSectionRef = useRef<HTMLDivElement>(null);
const segmentHeight = useMemo(() => {
if (timelineRef.current) {
const { scrollHeight: timelineHeight } =
timelineRef.current as HTMLDivElement;
return timelineHeight / (timelineDuration / segmentDuration);
}
// we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [segmentDuration, timelineDuration, timelineRef, showExportHandles]);
const [draggableElementType, setDraggableElementType] =
useState<DraggableElement>();
const handleHandlebar = useCallback(
(
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => {
setDraggableElementType("handlebar");
handlebarMouseDown(e);
},
[handlebarMouseDown],
);
const handleExportStart = useCallback(
(
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => {
setDraggableElementType("export_start");
exportStartMouseDown(e);
},
[exportStartMouseDown],
);
const handleExportEnd = useCallback(
(
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => {
setDraggableElementType("export_end");
exportEndMouseDown(e);
},
[exportEndMouseDown],
);
const handleMouseMove = useCallback(
(
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => {
switch (draggableElementType) {
case "export_start":
exportStartMouseMove(e);
break;
case "export_end":
exportEndMouseMove(e);
break;
case "handlebar":
handlebarMouseMove(e);
break;
default:
break;
}
},
[
draggableElementType,
exportStartMouseMove,
exportEndMouseMove,
handlebarMouseMove,
],
);
const handleMouseUp = useCallback(
(
e:
| React.MouseEvent<HTMLDivElement, MouseEvent>
| React.TouchEvent<HTMLDivElement>,
) => {
switch (draggableElementType) {
case "export_start":
exportStartMouseUp(e);
break;
case "export_end":
exportEndMouseUp(e);
break;
case "handlebar":
handlebarMouseUp(e);
break;
default:
break;
}
},
[
draggableElementType,
exportStartMouseUp,
exportEndMouseUp,
handlebarMouseUp,
],
);
useEffect(() => {
if (
exportSectionRef.current &&
segmentHeight &&
exportStartPosition &&
exportEndPosition
) {
exportSectionRef.current.style.top = `${exportEndPosition + segmentHeight}px`;
exportSectionRef.current.style.height = `${exportStartPosition - exportEndPosition + segmentHeight / 2}px`;
}
}, [
showExportHandles,
segmentHeight,
timelineRef,
exportStartPosition,
exportEndPosition,
]);
return (
<div
ref={timelineRef}
@@ -46,7 +235,9 @@ export function ReviewTimeline({
onMouseUp={handleMouseUp}
onTouchEnd={handleMouseUp}
className={`relative h-full overflow-y-auto no-scrollbar bg-secondary ${
isDragging && showHandlebar ? "cursor-grabbing" : "cursor-auto"
isDragging && (showHandlebar || showExportHandles)
? "cursor-grabbing"
: "cursor-auto"
}`}
>
<div className="flex flex-col relative">
@@ -62,8 +253,8 @@ export function ReviewTimeline({
>
<div
className="flex items-center justify-center touch-none select-none"
onMouseDown={handleMouseDown}
onTouchStart={handleMouseDown}
onMouseDown={handleHandlebar}
onTouchStart={handleHandlebar}
>
<div
className={`relative w-full ${
@@ -73,20 +264,90 @@ export function ReviewTimeline({
<div
className={`bg-destructive rounded-full mx-auto ${
segmentDuration < 60 ? "w-12 md:w-20" : "w-12 md:w-16"
} h-5 ${isDragging && isMobile ? "fixed top-[18px] left-1/2 transform -translate-x-1/2 z-20 w-[30%] h-[30px] bg-destructive/80" : "static"} flex items-center justify-center`}
} h-5 ${isDragging && isMobile && draggableElementType == "handlebar" ? "fixed top-[18px] left-1/2 transform -translate-x-1/2 z-20 w-[30%] h-[30px] bg-destructive/80" : "static"} flex items-center justify-center`}
>
<div
ref={handlebarTimeRef}
className={`text-white ${isDragging && isMobile ? "text-lg" : "text-[8px] md:text-xs"} z-10`}
className={`text-white pointer-events-none ${isDragging && isMobile && draggableElementType == "handlebar" ? "text-lg" : "text-[8px] md:text-xs"} z-10`}
></div>
</div>
<div
className={`absolute h-1 w-full bg-destructive ${isDragging && isMobile ? "top-1" : "top-1/2 transform -translate-y-1/2"}`}
className={`absolute h-1 w-full bg-destructive ${isDragging && isMobile && draggableElementType == "handlebar" ? "top-1" : "top-1/2 transform -translate-y-1/2"}`}
></div>
</div>
</div>
</div>
)}
{showExportHandles && (
<>
<div
className={`absolute left-0 top-0 ${isDragging && isIOS ? "" : "z-20"} w-full`}
role="scrollbar"
ref={exportEndRef}
>
<div
className="flex items-center justify-center touch-none select-none"
onMouseDown={handleExportEnd}
onTouchStart={handleExportEnd}
>
<div
className={`relative mt-[6.5px] w-full ${
isDragging ? "cursor-grabbing" : "cursor-grab"
}`}
>
<div
className={`bg-selected -mt-4 mx-auto ${
segmentDuration < 60 ? "w-12 md:w-20" : "w-12 md:w-16"
} h-5 ${isDragging && isMobile && draggableElementType == "export_end" ? "fixed mt-0 rounded-full top-[18px] left-1/2 transform -translate-x-1/2 z-20 w-[30%] h-[30px] bg-selected/80" : "rounded-tr-lg rounded-tl-lg static"} flex items-center justify-center`}
>
<div
ref={exportEndTimeRef}
className={`text-white pointer-events-none ${isDragging && isMobile && draggableElementType == "export_end" ? "text-lg mt-0" : "text-[8px] md:text-xs"} z-10`}
></div>
</div>
<div
className={`absolute h-1 w-full bg-selected ${isDragging && isMobile && draggableElementType == "export_end" ? "top-0" : "top-1/2 transform -translate-y-1/2"}`}
></div>
</div>
</div>
</div>
<div
ref={exportSectionRef}
className="bg-selected/50 absolute w-full"
></div>
<div
className={`absolute left-0 top-0 ${isDragging && isIOS ? "" : "z-20"} w-full`}
role="scrollbar"
ref={exportStartRef}
>
<div
className="flex items-center justify-center touch-none select-none"
onMouseDown={handleExportStart}
onTouchStart={handleExportStart}
>
<div
className={`relative -mt-[6.5px] w-full ${
isDragging ? "cursor-grabbing" : "cursor-grab"
}`}
>
<div
className={`absolute h-1 w-full bg-selected ${isDragging && isMobile && draggableElementType == "export_start" ? "top-[12px]" : "top-1/2 transform -translate-y-1/2"}`}
></div>
<div
className={`bg-selected mt-4 mx-auto ${
segmentDuration < 60 ? "w-12 md:w-20" : "w-12 md:w-16"
} h-5 ${isDragging && isMobile && draggableElementType == "export_start" ? "fixed mt-0 rounded-full top-[4px] left-1/2 transform -translate-x-1/2 z-20 w-[30%] h-[30px] bg-selected/80" : "rounded-br-lg rounded-bl-lg static"} flex items-center justify-center`}
>
<div
ref={exportStartTimeRef}
className={`text-white pointer-events-none ${isDragging && isMobile && draggableElementType == "export_start" ? "text-lg mt-0" : "text-[8px] md:text-xs"} z-10`}
></div>
</div>
</div>
</div>
</div>
</>
)}
</div>
);
}

View File

@@ -32,7 +32,7 @@ export function MinimapBounds({
<>
{isFirstSegmentInMinimap && (
<div
className="absolute inset-0 -bottom-7 w-full flex items-center justify-center text-primary-foreground font-medium z-20 text-center text-[10px] scroll-mt-8"
className="absolute inset-0 -bottom-7 w-full flex items-center justify-center text-primary-foreground font-medium z-20 text-center text-[10px] scroll-mt-8 pointer-events-none"
ref={firstMinimapSegmentRef}
>
{new Date(alignedMinimapStartTime * 1000).toLocaleTimeString([], {
@@ -44,7 +44,7 @@ export function MinimapBounds({
)}
{isLastSegmentInMinimap && (
<div className="absolute inset-0 -top-3 w-full flex items-center justify-center text-primary-foreground font-medium z-20 text-center text-[10px]">
<div className="absolute inset-0 -top-3 w-full flex items-center justify-center text-primary-foreground font-medium z-20 text-center text-[10px] pointer-events-none">
{new Date(alignedMinimapEndTime * 1000).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
@@ -61,14 +61,14 @@ export function Tick({ timestamp, timestampSpread }: TickSegmentProps) {
<div className="absolute">
<div className="flex items-end content-end w-[12px] h-2">
<div
className={`h-0.5 ${
className={`pointer-events-none h-0.5 ${
timestamp.getMinutes() % timestampSpread === 0 &&
timestamp.getSeconds() === 0
? "w-[12px] bg-neutral-600 dark:bg-neutral-500"
: timestamp.getMinutes() % (timestampSpread == 15 ? 5 : 1) ===
0 && timestamp.getSeconds() === 0
? "w-[8px] bg-neutral-500 dark:bg-neutral-600" // Minor tick mark
: "w-[5px] bg-neutral-400 dark:bg-neutral-700"
? "w-[8px] bg-neutral-500" // Minor tick mark
: "w-[5px] bg-neutral-400 dark:bg-neutral-600"
}`}
></div>
</div>
@@ -88,7 +88,7 @@ export function Timestamp({
{!isFirstSegmentInMinimap && !isLastSegmentInMinimap && (
<div
key={`${segmentKey}_timestamp`}
className="text-[8px] text-neutral-600 dark:text-neutral-500"
className="pointer-events-none text-[8px] text-neutral-600 dark:text-neutral-500"
>
{timestamp.getMinutes() % timestampSpread === 0 &&
timestamp.getSeconds() === 0 &&