From 9b3b6f62a3b145aada84c5e3bd58d0698b56bce6 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Sun, 24 Aug 2025 22:51:53 -0600 Subject: [PATCH] Implement mouse-drag scrolling on both sides (alike touch drag). --- src/components/CalendarView.vue | 50 ++++++++++++++++++++++++++++ src/components/Jogwheel.vue | 59 ++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/components/CalendarView.vue b/src/components/CalendarView.vue index 8dc2247..b6e77b0 100644 --- a/src/components/CalendarView.vue +++ b/src/components/CalendarView.vue @@ -124,6 +124,10 @@ const todayString = computed(() => { const visibleWeeks = ref([]) let lastScrollRange = { startVW: null, endVW: null } let pendingRebuild = false +// Week label column drag scrolling state (no momentum) +const isWeekColDragging = ref(false) +let weekColDragStartY = 0 +let weekColDragStartScroll = 0 function scheduleRebuild(reason) { if (pendingRebuild) return @@ -498,6 +502,49 @@ function calculateSelection(anchorStr, otherStr) { } } +// ---------------- Week label column drag scrolling ---------------- +function getWeekLabelRect() { + // Prefer header year label width as stable reference + const headerYear = document.querySelector('.calendar-header .year-label') + if (headerYear) return headerYear.getBoundingClientRect() + const weekLabel = viewport.value?.querySelector('.week-row .week-label') + return weekLabel ? weekLabel.getBoundingClientRect() : null +} + +function handleWeekColMouseDown(e) { + if (e.button !== 0) return + if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) return + if (!viewport.value) return + const rect = getWeekLabelRect() + if (!rect) return + if (e.clientX < rect.left || e.clientX > rect.right) return + isWeekColDragging.value = true + weekColDragStartY = e.clientY + weekColDragStartScroll = viewport.value.scrollTop + window.addEventListener('mousemove', handleWeekColMouseMove, { passive: false }) + window.addEventListener('mouseup', handleWeekColMouseUp, { passive: false }) + e.preventDefault() + e.stopPropagation() +} + +function handleWeekColMouseMove(e) { + if (!isWeekColDragging.value || !viewport.value) return + const dy = e.clientY - weekColDragStartY + // Natural: drag down moves view to earlier content (scroll up) + viewport.value.scrollTop = Math.max(0, weekColDragStartScroll - dy) + e.preventDefault() +} + +// (momentum removed per requirements) + +function handleWeekColMouseUp(e) { + if (!isWeekColDragging.value) return + isWeekColDragging.value = false + window.removeEventListener('mousemove', handleWeekColMouseMove) + window.removeEventListener('mouseup', handleWeekColMouseUp) + e.preventDefault() +} + const onScroll = () => { if (viewport.value) scrollTop.value = viewport.value.scrollTop scheduleRebuild('scroll') @@ -517,6 +564,8 @@ onMounted(() => { viewportHeight.value = viewport.value.clientHeight viewport.value.scrollTop = initialScrollTop.value viewport.value.addEventListener('scroll', onScroll) + // Capture mousedown in viewport to allow dragging via week label column + viewport.value.addEventListener('mousedown', handleWeekColMouseDown, true) } const timer = setInterval(() => { @@ -541,6 +590,7 @@ onMounted(() => { onBeforeUnmount(() => { if (viewport.value) { viewport.value.removeEventListener('scroll', onScroll) + viewport.value.removeEventListener('mousedown', handleWeekColMouseDown, true) } if (rowProbeObserver && rowProbe.value) { try { diff --git a/src/components/Jogwheel.vue b/src/components/Jogwheel.vue index b46acce..bf81219 100644 --- a/src/components/Jogwheel.vue +++ b/src/components/Jogwheel.vue @@ -5,7 +5,7 @@