diff options
Diffstat (limited to 'apps/web/src/hooks')
| -rw-r--r-- | apps/web/src/hooks/use-editor-actions.ts | 1 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-keyboard-shortcuts-help.ts | 4 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-timeline-element-resize.ts | 56 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-timeline-zoom-actions.ts | 38 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-timeline-zoom.ts | 72 |
5 files changed, 48 insertions, 123 deletions
diff --git a/apps/web/src/hooks/use-editor-actions.ts b/apps/web/src/hooks/use-editor-actions.ts index e0d9b9eb..4e8f6aef 100644 --- a/apps/web/src/hooks/use-editor-actions.ts +++ b/apps/web/src/hooks/use-editor-actions.ts @@ -102,7 +102,6 @@ export function useEditorActions() { useActionHandler("delete-selected", () => { if (selectedElements.length === 0) { - toast.error("No elements selected"); return; } selectedElements.forEach( diff --git a/apps/web/src/hooks/use-keyboard-shortcuts-help.ts b/apps/web/src/hooks/use-keyboard-shortcuts-help.ts index d0f177f6..c7de8466 100644 --- a/apps/web/src/hooks/use-keyboard-shortcuts-help.ts +++ b/apps/web/src/hooks/use-keyboard-shortcuts-help.ts @@ -60,10 +60,6 @@ const actionDescriptions: Record< category: "Selection", }, "toggle-snapping": { description: "Toggle snapping", category: "Editing" }, - "zoom-in": { description: "Zoom in timeline", category: "View" }, - "zoom-out": { description: "Zoom out timeline", category: "View" }, - "zoom-reset": { description: "Reset timeline zoom", category: "View" }, - "zoom-fit": { description: "Fit timeline to window", category: "View" }, undo: { description: "Undo", category: "History" }, redo: { description: "Redo", category: "History" }, }; diff --git a/apps/web/src/hooks/use-timeline-element-resize.ts b/apps/web/src/hooks/use-timeline-element-resize.ts index f16ca8e2..3afa637b 100644 --- a/apps/web/src/hooks/use-timeline-element-resize.ts +++ b/apps/web/src/hooks/use-timeline-element-resize.ts @@ -29,7 +29,12 @@ export function useTimelineElementResize({ }: UseTimelineElementResizeProps) { const [resizing, setResizing] = useState<ResizeState | null>(null); const { mediaItems } = useMediaStore(); - const { updateElementStartTime } = useTimelineStore(); + const { + updateElementStartTime, + updateElementTrim, + updateElementDuration, + pushHistory, + } = useTimelineStore(); // Set up document-level mouse listeners during resize (like proper drag behavior) useEffect(() => { @@ -61,6 +66,9 @@ export function useTimelineElementResize({ e.stopPropagation(); e.preventDefault(); + // Push history once at the start of the resize operation + pushHistory(); + setResizing({ elementId, side, @@ -112,13 +120,14 @@ export function useTimelineElementResize({ const trimDelta = newTrimStart - resizing.initialTrimStart; const newStartTime = element.startTime + trimDelta; - onUpdateTrim( + updateElementTrim( track.id, element.id, newTrimStart, - resizing.initialTrimEnd + resizing.initialTrimEnd, + false ); - updateElementStartTime(track.id, element.id, newStartTime); + updateElementStartTime(track.id, element.id, newStartTime, false); } else { // Trying to extend beyond trimStart = 0 if (canExtendElementDuration()) { @@ -128,22 +137,29 @@ export function useTimelineElementResize({ const newDuration = element.duration + extensionAmount; // Keep trimStart at 0 and extend the element - onUpdateTrim(track.id, element.id, 0, resizing.initialTrimEnd); - onUpdateDuration(track.id, element.id, newDuration); - updateElementStartTime(track.id, element.id, newStartTime); + updateElementTrim( + track.id, + element.id, + 0, + resizing.initialTrimEnd, + false + ); + updateElementDuration(track.id, element.id, newDuration, false); + updateElementStartTime(track.id, element.id, newStartTime, false); } else { // Video/Audio: can't extend beyond original content - limit to trimStart = 0 const newTrimStart = 0; const trimDelta = newTrimStart - resizing.initialTrimStart; const newStartTime = element.startTime + trimDelta; - onUpdateTrim( + updateElementTrim( track.id, element.id, newTrimStart, - resizing.initialTrimEnd + resizing.initialTrimEnd, + false ); - updateElementStartTime(track.id, element.id, newStartTime); + updateElementStartTime(track.id, element.id, newStartTime, false); } } } else { @@ -159,27 +175,35 @@ export function useTimelineElementResize({ const newTrimEnd = 0; // Reset trimEnd to 0 since we're extending // Update duration first, then trim - onUpdateDuration(track.id, element.id, newDuration); - onUpdateTrim( + updateElementDuration(track.id, element.id, newDuration, false); + updateElementTrim( track.id, element.id, resizing.initialTrimStart, - newTrimEnd + newTrimEnd, + false ); } else { // Can't extend - just set trimEnd to 0 (maximum possible extension) - onUpdateTrim(track.id, element.id, resizing.initialTrimStart, 0); + updateElementTrim( + track.id, + element.id, + resizing.initialTrimStart, + 0, + false + ); } } else { // Normal trimming within original duration const maxTrimEnd = element.duration - resizing.initialTrimStart - 0.1; // Leave at least 0.1s visible const newTrimEnd = Math.max(0, Math.min(maxTrimEnd, calculated)); - onUpdateTrim( + updateElementTrim( track.id, element.id, resizing.initialTrimStart, - newTrimEnd + newTrimEnd, + false ); } } diff --git a/apps/web/src/hooks/use-timeline-zoom-actions.ts b/apps/web/src/hooks/use-timeline-zoom-actions.ts deleted file mode 100644 index c6f9c50c..00000000 --- a/apps/web/src/hooks/use-timeline-zoom-actions.ts +++ /dev/null @@ -1,38 +0,0 @@ -"use client"; - -import { useActionHandler } from "@/constants/actions"; -import { MIN_ZOOM, MAX_ZOOM /*, ZOOM_STEP */ } from "../constants/timeline-constants"; - -interface UseTimelineZoomActionsProps { - zoomLevel: number; - setZoomLevel: (zoomLevel: number | ((prev: number) => number)) => void; - onFitToWindow?: () => void; -} - -export function useTimelineZoomActions({ - zoomLevel, - setZoomLevel, - onFitToWindow, -}: UseTimelineZoomActionsProps) { - // Zoom in action - useActionHandler("zoom-in", () => { - setZoomLevel((prev) => Math.min(MAX_ZOOM, prev + /*ZOOM_STEP*/ 0.2)); - }); - - // Zoom out action - useActionHandler("zoom-out", () => { - setZoomLevel((prev) => Math.max(MIN_ZOOM, prev - /*ZOOM_STEP*/ 0.2)); - }); - - // Reset zoom action - useActionHandler("zoom-reset", () => { - setZoomLevel(1); - }); - - // Fit to window action - useActionHandler("zoom-fit", () => { - if (onFitToWindow) { - onFitToWindow(); - } - }); -} diff --git a/apps/web/src/hooks/use-timeline-zoom.ts b/apps/web/src/hooks/use-timeline-zoom.ts index 1031e4a0..4f5e0af0 100644 --- a/apps/web/src/hooks/use-timeline-zoom.ts +++ b/apps/web/src/hooks/use-timeline-zoom.ts @@ -3,7 +3,6 @@ import { useState, useCallback, useEffect, RefObject } from "react"; interface UseTimelineZoomProps {
containerRef: RefObject<HTMLDivElement>;
isInTimeline?: boolean;
- onFitToWindow?: () => void;
}
interface UseTimelineZoomReturn {
@@ -12,83 +11,28 @@ interface UseTimelineZoomReturn { handleWheel: (e: React.WheelEvent) => void;
}
-const ZOOM_STORAGE_KEY = 'opencut-timeline-zoom';
-const MIN_ZOOM = 0.5; // Minimum zoom to keep element borders visible
-const MAX_ZOOM = 5;
-
export function useTimelineZoom({
containerRef,
isInTimeline = false,
- onFitToWindow,
}: UseTimelineZoomProps): UseTimelineZoomReturn {
- // Load initial zoom level from localStorage
- const [zoomLevel, setZoomLevel] = useState(() => {
- if (typeof window !== 'undefined') {
- const stored = localStorage.getItem(ZOOM_STORAGE_KEY);
- if (stored) {
- const parsed = parseFloat(stored);
- if (!isNaN(parsed) && parsed >= MIN_ZOOM && parsed <= MAX_ZOOM) {
- return parsed;
- }
- }
- }
- return 1;
- });
-
- // Save zoom level to localStorage whenever it changes
- useEffect(() => {
- if (typeof window !== 'undefined') {
- localStorage.setItem(ZOOM_STORAGE_KEY, zoomLevel.toString());
- }
- }, [zoomLevel]);
+ 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.15 : 0.15;
- setZoomLevel((prev) => Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, prev + delta)));
+ setZoomLevel((prev) => Math.max(0.1, Math.min(10, prev + delta)));
+ }
+ // For horizontal scrolling (when shift is held or horizontal wheel movement),
+ // let the event bubble up to allow ScrollArea to handle it
+ else if (e.shiftKey || Math.abs(e.deltaX) > Math.abs(e.deltaY)) {
+ // Don't prevent default - let ScrollArea handle horizontal scrolling
+ return;
}
// Otherwise, allow normal scrolling
}, []);
- // Keyboard shortcuts for zoom
- useEffect(() => {
- const handleKeyDown = (e: KeyboardEvent) => {
- // Only handle zoom shortcuts when in timeline or when timeline is focused
- if (!isInTimeline) return;
-
- if ((e.ctrlKey || e.metaKey) && !e.shiftKey) {
- switch (e.key) {
- case '=':
- case '+':
- e.preventDefault();
- setZoomLevel((prev) => Math.min(MAX_ZOOM, prev + 0.2));
- break;
- case '-':
- e.preventDefault();
- setZoomLevel((prev) => Math.max(MIN_ZOOM, prev - 0.2));
- break;
- case '0':
- e.preventDefault();
- setZoomLevel(1);
- break;
- case '9':
- e.preventDefault();
- if (onFitToWindow) {
- onFitToWindow();
- }
- break;
- }
- }
- };
-
- if (isInTimeline) {
- document.addEventListener('keydown', handleKeyDown);
- return () => document.removeEventListener('keydown', handleKeyDown);
- }
- }, [isInTimeline, setZoomLevel, onFitToWindow]);
-
// Prevent browser zooming in/out when in timeline
useEffect(() => {
const preventZoom = (e: WheelEvent) => {
|
