From da0e768b327261ed2e63ac912d8410dd6a1ac1b5 Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 29 Jul 2025 22:23:34 -0400 Subject: [PATCH] [BUG] UI: Inactive click area on the Timeline -Made the clickable area larger by increasing the container height -Fixed lint errors. --- .../src/components/editor/preview-panel.tsx | 22 +- .../src/components/editor/timeline/index.tsx | 36 ++- .../web/src/components/landing/handlebars.tsx | 4 +- apps/web/src/hooks/use-editor-actions.ts | 286 +++++++++++------- 4 files changed, 225 insertions(+), 123 deletions(-) diff --git a/apps/web/src/components/editor/preview-panel.tsx b/apps/web/src/components/editor/preview-panel.tsx index 639858d0..6cb06061 100644 --- a/apps/web/src/components/editor/preview-panel.tsx +++ b/apps/web/src/components/editor/preview-panel.tsx @@ -211,7 +211,7 @@ export function PreviewPanel() { setDragState({ isDragging: true, elementId: element.id, - trackId: trackId, + trackId, startX: e.clientX, startY: e.clientY, initialElementX: element.x, @@ -355,8 +355,24 @@ export function PreviewPanel() { handleTextMouseDown(e, element, elementData.track.id) } style={{ - left: `${50 + ((dragState.isDragging && dragState.elementId === element.id ? dragState.currentX : element.x) / canvasSize.width) * 100}%`, - top: `${50 + ((dragState.isDragging && dragState.elementId === element.id ? dragState.currentY : element.y) / canvasSize.height) * 100}%`, + left: `${ + 50 + + ( + (dragState.isDragging && dragState.elementId === element.id + ? dragState.currentX + : element.x) / canvasSize.width + ) * + 100 + }%`, + top: `${ + 50 + + ( + (dragState.isDragging && dragState.elementId === element.id + ? dragState.currentY + : element.y) / canvasSize.height + ) * + 100 + }%`, transform: `translate(-50%, -50%) rotate(${element.rotation}deg) scale(${scaleRatio})`, opacity: element.opacity, zIndex: 100 + index, // Text elements on top diff --git a/apps/web/src/components/editor/timeline/index.tsx b/apps/web/src/components/editor/timeline/index.tsx index bdb4433c..078f1258 100644 --- a/apps/web/src/components/editor/timeline/index.tsx +++ b/apps/web/src/components/editor/timeline/index.tsx @@ -552,7 +552,7 @@ export function Timeline() { {/* Timeline Ruler */}
{ // Check if this is horizontal scrolling - if so, don't handle it here if (e.shiftKey || Math.abs(e.deltaX) > Math.abs(e.deltaY)) { @@ -567,7 +567,7 @@ export function Timeline() {
0) { - return `${hours}:${minutes.toString().padStart(2, "0")}:${Math.floor(secs).toString().padStart(2, "0")}`; + return `${hours}:${minutes + .toString() + .padStart(2, "0")}:${Math.floor(secs) + .toString() + .padStart(2, "0")}`; } if (minutes > 0) { - return `${minutes}:${Math.floor(secs).toString().padStart(2, "0")}`; + return `${minutes}:${Math.floor(secs) + .toString() + .padStart(2, "0")}`; } if (interval >= 1) { return `${Math.floor(secs)}s`; @@ -710,7 +720,10 @@ export function Timeline() {
@@ -724,7 +737,10 @@ export function Timeline() {
{ @@ -1092,7 +1108,9 @@ function TimelineToolbar({ diff --git a/apps/web/src/components/landing/handlebars.tsx b/apps/web/src/components/landing/handlebars.tsx index 26cf9254..e87d50e9 100644 --- a/apps/web/src/components/landing/handlebars.tsx +++ b/apps/web/src/components/landing/handlebars.tsx @@ -62,7 +62,7 @@ export function Handlebars({ children }: HandlebarsProps) { whileDrag={{ scale: 1.1, cursor: "grabbing" }} transition={{ type: "spring", stiffness: 400, damping: 30 }} > -
+
-
+
diff --git a/apps/web/src/hooks/use-editor-actions.ts b/apps/web/src/hooks/use-editor-actions.ts index b2fad55f..bfe9a7b9 100644 --- a/apps/web/src/hooks/use-editor-actions.ts +++ b/apps/web/src/hooks/use-editor-actions.ts @@ -26,136 +26,204 @@ export function useEditorActions() { const { activeProject } = useProjectStore(); // Playback actions - useActionHandler("toggle-play", () => { - toggle(); - }, undefined); - - useActionHandler("stop-playback", () => { - if (isPlaying) { + useActionHandler( + "toggle-play", + () => { toggle(); - } - seek(0); - }, undefined); + }, + undefined + ); - useActionHandler("seek-forward", (args) => { - const seconds = args?.seconds ?? 1; - seek(Math.min(duration, currentTime + seconds)); - }, undefined); + useActionHandler( + "stop-playback", + () => { + if (isPlaying) { + toggle(); + } + seek(0); + }, + undefined + ); - useActionHandler("seek-backward", (args) => { - const seconds = args?.seconds ?? 1; - seek(Math.max(0, currentTime - seconds)); - }, undefined); + useActionHandler( + "seek-forward", + (args) => { + const seconds = args?.seconds ?? 1; + seek(Math.min(duration, currentTime + seconds)); + }, + undefined + ); - useActionHandler("frame-step-forward", () => { - const projectFps = activeProject?.fps || 30; - seek(Math.min(duration, currentTime + 1 / projectFps)); - }, undefined); + useActionHandler( + "seek-backward", + (args) => { + const seconds = args?.seconds ?? 1; + seek(Math.max(0, currentTime - seconds)); + }, + undefined + ); - useActionHandler("frame-step-backward", () => { - const projectFps = activeProject?.fps || 30; - seek(Math.max(0, currentTime - 1 / projectFps)); - }, undefined); + useActionHandler( + "frame-step-forward", + () => { + const projectFps = activeProject?.fps || 30; + seek(Math.min(duration, currentTime + 1 / projectFps)); + }, + undefined + ); - useActionHandler("jump-forward", (args) => { - const seconds = args?.seconds ?? 5; - seek(Math.min(duration, currentTime + seconds)); - }, undefined); + useActionHandler( + "frame-step-backward", + () => { + const projectFps = activeProject?.fps || 30; + seek(Math.max(0, currentTime - 1 / projectFps)); + }, + undefined + ); - useActionHandler("jump-backward", (args) => { - const seconds = args?.seconds ?? 5; - seek(Math.max(0, currentTime - seconds)); - }, undefined); + useActionHandler( + "jump-forward", + (args) => { + const seconds = args?.seconds ?? 5; + seek(Math.min(duration, currentTime + seconds)); + }, + undefined + ); - useActionHandler("goto-start", () => { - seek(0); - }, undefined); + useActionHandler( + "jump-backward", + (args) => { + const seconds = args?.seconds ?? 5; + seek(Math.max(0, currentTime - seconds)); + }, + undefined + ); - useActionHandler("goto-end", () => { - seek(duration); - }, undefined); + useActionHandler( + "goto-start", + () => { + seek(0); + }, + undefined + ); + + useActionHandler( + "goto-end", + () => { + seek(duration); + }, + undefined + ); // Timeline editing actions - useActionHandler("split-element", () => { - if (selectedElements.length !== 1) { - toast.error("Select exactly one element to split"); - return; - } - - const { trackId, elementId } = selectedElements[0]; - const track = tracks.find((t: any) => t.id === trackId); - const element = track?.elements.find((el: any) => el.id === elementId); - - if (element) { - const effectiveStart = element.startTime; - const effectiveEnd = - element.startTime + - (element.duration - element.trimStart - element.trimEnd); - - if (currentTime > effectiveStart && currentTime < effectiveEnd) { - splitElement(trackId, elementId, currentTime); - } else { - toast.error("Playhead must be within selected element"); + useActionHandler( + "split-element", + () => { + if (selectedElements.length !== 1) { + toast.error("Select exactly one element to split"); + return; } - } - }, undefined); - useActionHandler("delete-selected", () => { - if (selectedElements.length === 0) { - return; - } - selectedElements.forEach( - ({ trackId, elementId }: { trackId: string; elementId: string }) => { - removeElementFromTrack(trackId, elementId); + const { trackId, elementId } = selectedElements[0]; + const track = tracks.find((t: any) => t.id === trackId); + const element = track?.elements.find((el: any) => el.id === elementId); + + if (element) { + const effectiveStart = element.startTime; + const effectiveEnd = + element.startTime + + (element.duration - element.trimStart - element.trimEnd); + + if (currentTime > effectiveStart && currentTime < effectiveEnd) { + splitElement(trackId, elementId, currentTime); + } else { + toast.error("Playhead must be within selected element"); + } } - ); - clearSelectedElements(); - }, undefined); + }, + undefined + ); - useActionHandler("select-all", () => { - const allElements = tracks.flatMap((track: any) => - track.elements.map((element: any) => ({ - trackId: track.id, - elementId: element.id, - })) - ); - setSelectedElements(allElements); - }, undefined); + useActionHandler( + "delete-selected", + () => { + if (selectedElements.length === 0) { + return; + } + selectedElements.forEach( + ({ trackId, elementId }: { trackId: string; elementId: string }) => { + removeElementFromTrack(trackId, elementId); + } + ); + clearSelectedElements(); + }, + undefined + ); - useActionHandler("duplicate-selected", () => { - if (selectedElements.length !== 1) { - toast.error("Select exactly one element to duplicate"); - return; - } + useActionHandler( + "select-all", + () => { + const allElements = tracks.flatMap((track: any) => + track.elements.map((element: any) => ({ + trackId: track.id, + elementId: element.id, + })) + ); + setSelectedElements(allElements); + }, + undefined + ); - const { trackId, elementId } = selectedElements[0]; - const track = tracks.find((t: any) => t.id === trackId); - const element = track?.elements.find((el: any) => el.id === elementId); + useActionHandler( + "duplicate-selected", + () => { + if (selectedElements.length !== 1) { + toast.error("Select exactly one element to duplicate"); + return; + } - if (element) { - const newStartTime = - element.startTime + - (element.duration - element.trimStart - element.trimEnd) + - 0.1; - const { id, ...elementWithoutId } = element; + const { trackId, elementId } = selectedElements[0]; + const track = tracks.find((t: any) => t.id === trackId); + const element = track?.elements.find((el: any) => el.id === elementId); - addElementToTrack(trackId, { - ...elementWithoutId, - startTime: newStartTime, - }); - } - }, undefined); + if (element) { + const newStartTime = + element.startTime + + (element.duration - element.trimStart - element.trimEnd) + + 0.1; + const { id, ...elementWithoutId } = element; - useActionHandler("toggle-snapping", () => { - toggleSnapping(); - }, undefined); + addElementToTrack(trackId, { + ...elementWithoutId, + startTime: newStartTime, + }); + } + }, + undefined + ); + + useActionHandler( + "toggle-snapping", + () => { + toggleSnapping(); + }, + undefined + ); // History actions - useActionHandler("undo", () => { - undo(); - }, undefined); + useActionHandler( + "undo", + () => { + undo(); + }, + undefined + ); - useActionHandler("redo", () => { - redo(); - }, undefined); + useActionHandler( + "redo", + () => { + redo(); + }, + undefined + ); }