summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/timeline
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2025-08-04 12:35:14 +0200
committerMaze Winther <mazewinther@gmail.com>2025-08-04 12:35:14 +0200
commit0386624ff5fd6d82d64d6b103ddc1a7e5045f45b (patch)
tree6388c96212a3574defff08ac76cfa9baa8675d00 /apps/web/src/components/editor/timeline
parentefa5be2ab8fd5be095995378caddd0784fc3fbd3 (diff)
downloadopencut-0386624ff5fd6d82d64d6b103ddc1a7e5045f45b.tar.gz
fix: click empty area on timeline to move playhead
Diffstat (limited to 'apps/web/src/components/editor/timeline')
-rw-r--r--apps/web/src/components/editor/timeline/index.tsx117
1 files changed, 102 insertions, 15 deletions
diff --git a/apps/web/src/components/editor/timeline/index.tsx b/apps/web/src/components/editor/timeline/index.tsx
index 7a2cc7f2..dd81b7b3 100644
--- a/apps/web/src/components/editor/timeline/index.tsx
+++ b/apps/web/src/components/editor/timeline/index.tsx
@@ -167,11 +167,32 @@ export function Timeline() {
const handleTimelineMouseDown = useCallback((e: React.MouseEvent) => {
// Only track mouse down on timeline background areas (not elements)
const target = e.target as HTMLElement;
+ console.log(
+ JSON.stringify({
+ debug_mousedown: "START",
+ target_class: target.className,
+ target_parent_class: target.parentElement?.className,
+ clientX: e.clientX,
+ clientY: e.clientY,
+ timeStamp: e.timeStamp,
+ })
+ );
+
const isTimelineBackground =
!target.closest(".timeline-element") &&
!playheadRef.current?.contains(target) &&
!target.closest("[data-track-labels]");
+ console.log(
+ JSON.stringify({
+ debug_mousedown: "CHECK",
+ isTimelineBackground,
+ hasTimelineElement: !!target.closest(".timeline-element"),
+ hasPlayhead: !!playheadRef.current?.contains(target),
+ hasTrackLabels: !!target.closest("[data-track-labels]"),
+ })
+ );
+
if (isTimelineBackground) {
mouseTrackingRef.current = {
isMouseDown: true,
@@ -179,12 +200,38 @@ export function Timeline() {
downY: e.clientY,
downTime: e.timeStamp,
};
+ console.log(
+ JSON.stringify({
+ debug_mousedown: "TRACKED",
+ mouseTracking: mouseTrackingRef.current,
+ })
+ );
+ } else {
+ console.log(
+ JSON.stringify({
+ debug_mousedown: "IGNORED - not timeline background",
+ })
+ );
}
}, []);
// Timeline content click to seek handler
const handleTimelineContentClick = useCallback(
(e: React.MouseEvent) => {
+ console.log(
+ JSON.stringify({
+ debug_click: "START",
+ target: (e.target as HTMLElement).className,
+ target_parent: (e.target as HTMLElement).parentElement?.className,
+ mouseTracking: mouseTrackingRef.current,
+ isSelecting,
+ justFinishedSelecting,
+ clickX: e.clientX,
+ clickY: e.clientY,
+ timeStamp: e.timeStamp,
+ })
+ );
+
const { isMouseDown, downX, downY, downTime } = mouseTrackingRef.current;
// Reset mouse tracking
@@ -199,8 +246,8 @@ export function Timeline() {
if (!isMouseDown) {
console.log(
JSON.stringify({
- ignoredClickWithoutMouseDown: true,
- timeStamp: e.timeStamp,
+ debug_click: "REJECTED - no mousedown",
+ mouseTracking: mouseTrackingRef.current,
})
);
return;
@@ -214,11 +261,10 @@ export function Timeline() {
if (deltaX > 5 || deltaY > 5 || deltaTime > 500) {
console.log(
JSON.stringify({
- ignoredDragNotClick: true,
+ debug_click: "REJECTED - movement too large",
deltaX,
deltaY,
deltaTime,
- timeStamp: e.timeStamp,
})
);
return;
@@ -226,27 +272,54 @@ export function Timeline() {
// Don't seek if this was a selection box operation
if (isSelecting || justFinishedSelecting) {
+ console.log(
+ JSON.stringify({
+ debug_click: "REJECTED - selection operation",
+ isSelecting,
+ justFinishedSelecting,
+ })
+ );
return;
}
// Don't seek if clicking on timeline elements, but still deselect
if ((e.target as HTMLElement).closest(".timeline-element")) {
+ console.log(
+ JSON.stringify({
+ debug_click: "REJECTED - clicked timeline element",
+ })
+ );
return;
}
// Don't seek if clicking on playhead
if (playheadRef.current?.contains(e.target as Node)) {
+ console.log(
+ JSON.stringify({
+ debug_click: "REJECTED - clicked playhead",
+ })
+ );
return;
}
// Don't seek if clicking on track labels
if ((e.target as HTMLElement).closest("[data-track-labels]")) {
+ console.log(
+ JSON.stringify({
+ debug_click: "REJECTED - clicked track labels",
+ })
+ );
clearSelectedElements();
return;
}
// Clear selected elements when clicking empty timeline area
- console.log(JSON.stringify({ clearingSelectedElements: true }));
+ console.log(
+ JSON.stringify({
+ debug_click: "PROCEEDING - clearing elements",
+ clearingSelectedElements: true,
+ })
+ );
clearSelectedElements();
// Determine if we're clicking in ruler or tracks area
@@ -254,24 +327,39 @@ export function Timeline() {
"[data-ruler-area]"
);
+ console.log(
+ JSON.stringify({
+ debug_click: "CALCULATING POSITION",
+ isRulerClick,
+ clientX: e.clientX,
+ clientY: e.clientY,
+ target_element: (e.target as HTMLElement).tagName,
+ target_class: (e.target as HTMLElement).className,
+ })
+ );
+
let mouseX: number;
let scrollLeft = 0;
if (isRulerClick) {
// Calculate based on ruler position
- const rulerContent = rulerScrollRef.current?.querySelector(
- "[data-radix-scroll-area-viewport]"
- ) as HTMLElement;
- if (!rulerContent) return;
+ const rulerContent = rulerScrollRef.current;
+ if (!rulerContent) {
+ console.log(
+ JSON.stringify({
+ debug_click: "ERROR - no ruler container found",
+ })
+ );
+ return;
+ }
const rect = rulerContent.getBoundingClientRect();
mouseX = e.clientX - rect.left;
scrollLeft = rulerContent.scrollLeft;
} else {
- // Calculate based on tracks content position
- const tracksContent = tracksScrollRef.current?.querySelector(
- "[data-radix-scroll-area-viewport]"
- ) as HTMLElement;
- if (!tracksContent) return;
+ const tracksContent = tracksScrollRef.current;
+ if (!tracksContent) {
+ return;
+ }
const rect = tracksContent.getBoundingClientRect();
mouseX = e.clientX - rect.left;
scrollLeft = tracksContent.scrollLeft;
@@ -289,7 +377,6 @@ export function Timeline() {
// Use frame snapping for timeline clicking
const projectFps = activeProject?.fps || 30;
const time = snapTimeToFrame(rawTime, projectFps);
-
seek(time);
},
[