refactor: move timeline zoom to custom hook
This commit is contained in:
@ -32,6 +32,7 @@ import { useTimelineStore } from "@/stores/timeline-store";
|
|||||||
import { useMediaStore } from "@/stores/media-store";
|
import { useMediaStore } from "@/stores/media-store";
|
||||||
import { usePlaybackStore } from "@/stores/playback-store";
|
import { usePlaybackStore } from "@/stores/playback-store";
|
||||||
import { useProjectStore } from "@/stores/project-store";
|
import { useProjectStore } from "@/stores/project-store";
|
||||||
|
import { useTimelineZoom } from "@/hooks/use-timeline-zoom";
|
||||||
import { processMediaFiles } from "@/lib/media-processing";
|
import { processMediaFiles } from "@/lib/media-processing";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useState, useRef, useEffect, useCallback } from "react";
|
import { useState, useRef, useEffect, useCallback } from "react";
|
||||||
@ -87,11 +88,16 @@ export function Timeline() {
|
|||||||
const [isDragOver, setIsDragOver] = useState(false);
|
const [isDragOver, setIsDragOver] = useState(false);
|
||||||
const [isProcessing, setIsProcessing] = useState(false);
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
const [progress, setProgress] = useState(0);
|
const [progress, setProgress] = useState(0);
|
||||||
const [zoomLevel, setZoomLevel] = useState(1);
|
|
||||||
const dragCounterRef = useRef(0);
|
const dragCounterRef = useRef(0);
|
||||||
const timelineRef = useRef<HTMLDivElement>(null);
|
const timelineRef = useRef<HTMLDivElement>(null);
|
||||||
const [isInTimeline, setIsInTimeline] = useState(false);
|
const [isInTimeline, setIsInTimeline] = useState(false);
|
||||||
|
|
||||||
|
// Timeline zoom functionality
|
||||||
|
const { zoomLevel, setZoomLevel, handleWheel } = useTimelineZoom({
|
||||||
|
containerRef: timelineRef,
|
||||||
|
isInTimeline,
|
||||||
|
});
|
||||||
|
|
||||||
// Marquee selection state
|
// Marquee selection state
|
||||||
const [marquee, setMarquee] = useState<{
|
const [marquee, setMarquee] = useState<{
|
||||||
startX: number;
|
startX: number;
|
||||||
@ -432,16 +438,6 @@ export function Timeline() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleWheel = (e: React.WheelEvent) => {
|
|
||||||
// Only zoom if user is using pinch gesture (ctrlKey or metaKey is true)
|
|
||||||
if (e.ctrlKey || e.metaKey) {
|
|
||||||
e.preventDefault();
|
|
||||||
const delta = e.deltaY > 0 ? -0.05 : 0.05;
|
|
||||||
setZoomLevel((prev) => Math.max(0.1, Math.min(10, prev + delta)));
|
|
||||||
}
|
|
||||||
// Otherwise, allow normal scrolling
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- Playhead Scrubbing Handlers ---
|
// --- Playhead Scrubbing Handlers ---
|
||||||
const handlePlayheadMouseDown = useCallback(
|
const handlePlayheadMouseDown = useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
@ -667,26 +663,6 @@ export function Timeline() {
|
|||||||
clearSelectedElements();
|
clearSelectedElements();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prevent explorer zooming in/out when in timeline
|
|
||||||
useEffect(() => {
|
|
||||||
const preventZoom = (e: WheelEvent) => {
|
|
||||||
// if (isInTimeline && (e.ctrlKey || e.metaKey)) {
|
|
||||||
if (
|
|
||||||
isInTimeline &&
|
|
||||||
(e.ctrlKey || e.metaKey) &&
|
|
||||||
timelineRef.current?.contains(e.target as Node)
|
|
||||||
) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener("wheel", preventZoom, { passive: false });
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener("wheel", preventZoom);
|
|
||||||
};
|
|
||||||
}, [isInTimeline]);
|
|
||||||
|
|
||||||
// --- Scroll synchronization effect ---
|
// --- Scroll synchronization effect ---
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const rulerViewport = rulerScrollRef.current?.querySelector(
|
const rulerViewport = rulerScrollRef.current?.querySelector(
|
||||||
|
54
apps/web/src/hooks/use-timeline-zoom.ts
Normal file
54
apps/web/src/hooks/use-timeline-zoom.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { useState, useCallback, useEffect, RefObject } from "react";
|
||||||
|
|
||||||
|
interface UseTimelineZoomProps {
|
||||||
|
containerRef: RefObject<HTMLDivElement>;
|
||||||
|
isInTimeline?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UseTimelineZoomReturn {
|
||||||
|
zoomLevel: number;
|
||||||
|
setZoomLevel: (zoomLevel: number | ((prev: number) => number)) => void;
|
||||||
|
handleWheel: (e: React.WheelEvent) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTimelineZoom({
|
||||||
|
containerRef,
|
||||||
|
isInTimeline = false,
|
||||||
|
}: UseTimelineZoomProps): UseTimelineZoomReturn {
|
||||||
|
const [zoomLevel, setZoomLevel] = useState(1);
|
||||||
|
|
||||||
|
const handleWheel = useCallback((e: React.WheelEvent) => {
|
||||||
|
// Only zoom if user is using pinch gesture (ctrlKey or metaKey is true)
|
||||||
|
if (e.ctrlKey || e.metaKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
const delta = e.deltaY > 0 ? -0.05 : 0.05;
|
||||||
|
setZoomLevel((prev) => Math.max(0.1, Math.min(10, prev + delta)));
|
||||||
|
}
|
||||||
|
// Otherwise, allow normal scrolling
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Prevent browser zooming in/out when in timeline
|
||||||
|
useEffect(() => {
|
||||||
|
const preventZoom = (e: WheelEvent) => {
|
||||||
|
if (
|
||||||
|
isInTimeline &&
|
||||||
|
(e.ctrlKey || e.metaKey) &&
|
||||||
|
containerRef.current?.contains(e.target as Node)
|
||||||
|
) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("wheel", preventZoom, { passive: false });
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("wheel", preventZoom);
|
||||||
|
};
|
||||||
|
}, [isInTimeline, containerRef]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
zoomLevel,
|
||||||
|
setZoomLevel,
|
||||||
|
handleWheel,
|
||||||
|
};
|
||||||
|
}
|
Reference in New Issue
Block a user