Major new version #2

Merged
LeoVasanko merged 86 commits from vol002 into main 2025-08-26 05:58:24 +01:00
2 changed files with 90 additions and 91 deletions
Showing only changes of commit 10c9cedc8e - Show all commits

View File

@ -115,20 +115,25 @@ const contentHeight = computed(() => {
const visibleWeeks = ref([])
let lastScrollRange = { startVW: null, endVW: null }
let pendingRebuild = false
let rebuildTimer = null
let lastReason = null
const REBUILD_DEBOUNCE_MS = 40
function scheduleRebuild(reason) {
if (pendingRebuild) return
pendingRebuild = true
const cb = () => {
pendingRebuild = false
rebuildVisibleWeeks(reason)
}
lastReason = lastReason ? lastReason + ',' + reason : reason
if (rebuildTimer) return
rebuildTimer = setTimeout(() => {
const r = lastReason
rebuildTimer = null
lastReason = null
const fn = () => rebuildVisibleWeeks(r)
if ('requestIdleCallback' in window) {
requestIdleCallback(cb, { timeout: 120 })
requestIdleCallback(fn, { timeout: 120 })
} else {
requestAnimationFrame(cb)
requestAnimationFrame(fn)
}
}, REBUILD_DEBOUNCE_MS)
}
const scrollManager = createScrollManager({ viewport, scheduleRebuild })
@ -152,7 +157,7 @@ const monthScrollManager = createMonthScrollManager({
setScrollTop,
})
const { handleMonthScrollMouseDown, handleMonthScrollTouchStart, handleMonthScrollWheel } =
const { handleMonthScrollPointerDown, handleMonthScrollTouchStart, handleMonthScrollWheel } =
monthScrollManager
const initialScrollTop = computed(() => {
@ -178,7 +183,7 @@ function rebuildVisibleWeeks(reason) {
)
const startVW = Math.max(minVirtualWeek.value, startIdx + minVirtualWeek.value)
const endVW = Math.min(maxVirtualWeek.value, endIdx + minVirtualWeek.value)
console.log('[CalendarView] rebuildVisibleWeeks', {
console.debug('[CalendarView] rebuildVisibleWeeks', {
reason,
currentScrollTop,
startIdx,
@ -229,13 +234,6 @@ function measureFromProbe() {
const topVirtualWeek = Math.floor(scrollTop.value / oldH) + minVirtualWeek.value
rowHeight.value = newH
const newScrollTop = (topVirtualWeek - minVirtualWeek.value) * newH
console.log('[CalendarView] measureFromProbe rowHeight change', {
oldH,
newH,
topVirtualWeek,
oldScrollTop: scrollTop.value,
newScrollTop,
})
setScrollTop(newScrollTop, 'row-height-change')
}
}
@ -712,8 +710,8 @@ window.addEventListener('resize', () => {
height: `calc(var(--row-h) * ${monthWeek.monthLabel?.weeksSpan || 1})`,
top: (monthWeek.top || 0) + 'px',
}"
@mousedown="handleMonthScrollMouseDown"
@touchstart="handleMonthScrollTouchStart"
@pointerdown="handleMonthScrollPointerDown"
@touchstart.prevent="handleMonthScrollTouchStart"
@wheel="handleMonthScrollWheel"
>
<span :class="{ bottomup: shouldRotateMonth(monthWeek.monthLabel?.text) }">{{
@ -805,6 +803,7 @@ header h1 {
overflow: hidden;
cursor: ns-resize;
user-select: none;
touch-action: none;
}
.month-label > span {

View File

@ -156,79 +156,79 @@ export function createMonthScrollManager({
contentHeight,
setScrollTop,
}) {
let isMonthScrolling = false
let monthScrollStartY = 0
let monthScrollStartScroll = 0
let dragging = false
let startY = 0
let startScroll = 0
const SPEED = 10
const handleMonthScrollMouseDown = (e) => {
if (e.button !== 0) return
isMonthScrolling = true
monthScrollStartY = e.clientY
monthScrollStartScroll = viewport.value?.scrollTop || 0
const handleMouseMove = (e) => {
if (!isMonthScrolling) return
const deltaY = e.clientY - monthScrollStartY
const newScrollTop = monthScrollStartScroll - deltaY * 10
function applyDrag(clientY, reason) {
const deltaY = clientY - startY
const newScrollTop = startScroll - deltaY * SPEED
const maxScroll = Math.max(0, contentHeight.value - viewportHeight.value)
const clampedScroll = Math.max(0, Math.min(newScrollTop, maxScroll))
const clamped = Math.max(0, Math.min(newScrollTop, maxScroll))
setScrollTop(clamped, reason)
}
setScrollTop(clampedScroll, 'month-scroll-drag')
function endDrag() {
dragging = false
window.removeEventListener('pointermove', onPointerMove, true)
window.removeEventListener('pointerup', onPointerUp, true)
window.removeEventListener('pointercancel', onPointerUp, true)
window.removeEventListener('touchmove', onTouchMove)
window.removeEventListener('touchend', onTouchEnd)
window.removeEventListener('touchcancel', onTouchEnd)
}
function onPointerMove(e) {
if (!dragging) return
applyDrag(e.clientY, 'month-scroll-drag')
e.preventDefault()
}
const handleMouseUp = () => {
isMonthScrolling = false
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseup', handleMouseUp)
function onPointerUp() {
if (dragging) endDrag()
}
document.addEventListener('mousemove', handleMouseMove)
document.addEventListener('mouseup', handleMouseUp)
function onTouchMove(e) {
if (!dragging) return
const t = e.touches[0]
applyDrag(t.clientY, 'month-scroll-touch')
e.preventDefault()
}
function onTouchEnd() {
if (dragging) endDrag()
}
const handleMonthScrollTouchStart = (e) => {
function handleMonthScrollPointerDown(e) {
if (e.button !== undefined && e.button !== 0) return
e.preventDefault()
dragging = true
startY = e.clientY
startScroll = viewport.value?.scrollTop || 0
window.addEventListener('pointermove', onPointerMove, true)
window.addEventListener('pointerup', onPointerUp, true)
window.addEventListener('pointercancel', onPointerUp, true)
}
function handleMonthScrollTouchStart(e) {
if (e.touches.length !== 1) return
isMonthScrolling = true
monthScrollStartY = e.touches[0].clientY
monthScrollStartScroll = viewport.value?.scrollTop || 0
const handleTouchMove = (e) => {
if (!isMonthScrolling || e.touches.length !== 1) return
const deltaY = e.touches[0].clientY - monthScrollStartY
const newScrollTop = monthScrollStartScroll - deltaY * 10
const maxScroll = Math.max(0, contentHeight.value - viewportHeight.value)
const clampedScroll = Math.max(0, Math.min(newScrollTop, maxScroll))
setScrollTop(clampedScroll, 'month-scroll-touch')
dragging = true
const t = e.touches[0]
startY = t.clientY
startScroll = viewport.value?.scrollTop || 0
window.addEventListener('touchmove', onTouchMove, { passive: false })
window.addEventListener('touchend', onTouchEnd, { passive: false })
window.addEventListener('touchcancel', onTouchEnd, { passive: false })
e.preventDefault()
}
const handleTouchEnd = () => {
isMonthScrolling = false
document.removeEventListener('touchmove', handleTouchMove)
document.removeEventListener('touchend', handleTouchEnd)
}
document.addEventListener('touchmove', handleTouchMove, { passive: false })
document.addEventListener('touchend', handleTouchEnd)
e.preventDefault()
}
const handleMonthScrollWheel = (e) => {
function handleMonthScrollWheel(e) {
const currentScroll = viewport.value?.scrollTop || 0
const newScrollTop = currentScroll + e.deltaY * 10
const newScrollTop = currentScroll + e.deltaY * SPEED
const maxScroll = Math.max(0, contentHeight.value - viewportHeight.value)
const clampedScroll = Math.max(0, Math.min(newScrollTop, maxScroll))
setScrollTop(clampedScroll, 'month-scroll-wheel')
const clamped = Math.max(0, Math.min(newScrollTop, maxScroll))
setScrollTop(clamped, 'month-scroll-wheel')
e.preventDefault()
}
return {
handleMonthScrollMouseDown,
handleMonthScrollTouchStart,
handleMonthScrollWheel,
}
return { handleMonthScrollPointerDown, handleMonthScrollTouchStart, handleMonthScrollWheel }
}