commit c1d7fa44f26113fefa296bb655b00c0226445378
parent 502c48f60df2203ab681b270f9bcd0fb0a65223b
Author: Hunter Irving
Date:   Tue,  1 Apr 2025 00:12:48 -0400

Merge pull request #1 from hunterirving/scrolling-enhancements

Scrolling enhancements
Diffstat:
M.gitignore | 3++-
Mindex.html | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -1 +1 @@ -CLAUDE.md +CLAUDE.md +\ No newline at end of file diff --git a/index.html b/index.html @@ -261,6 +261,10 @@ } }); document.addEventListener('DOMContentLoaded', function() { + // Variables for scroll handling + let lastScrollPosition = 0; + let isScrolling = false; + let scrollDebounceTimer; const appContainer = document.getElementById('app-container'); let rootTask = loadTasksFromLocalStorage(); let currentTask = rootTask; @@ -912,6 +916,19 @@ updateBreadcrumbs(task); lastSubtaskDownArrowReleased = isLastSubtask(task); input.focus(); + + // Center the active task in the viewport + setTimeout(() => { + const activeTaskElement = document.querySelector('.task-container.active'); + if (activeTaskElement && activeTaskElement.parentElement && activeTaskElement.parentElement.tagName === 'LI') { + // Use scrollIntoView with block: "center" to center the element vertically + activeTaskElement.scrollIntoView({ + behavior: 'auto', // Use 'auto' for immediate scrolling + block: 'center', // Center vertically + inline: 'nearest' // Don't change horizontal scroll + }); + } + }, 10); } function updateBreadcrumbs(selectedTask) { @@ -1080,6 +1097,79 @@ document.addEventListener('keydown', handleSave); document.addEventListener('keydown', handleOpen); + + // Add scroll handling to navigate tasks with inertia + window.addEventListener('wheel', handleScroll, { passive: false }); + + // Scroll inertia implementation + const scrollState = { + momentum: 0, + isAnimating: false, + lastScrollTime: Date.now(), + scrollAccumulator: 0, + taskNavigationThreshold: 250 // Pixels needed to move one task + }; + + function handleScroll(e) { + // Prevent the default scroll behavior + e.preventDefault(); + + // Get scroll delta and update time + const now = Date.now(); + const timeDelta = now - scrollState.lastScrollTime; + scrollState.lastScrollTime = now; + + // Calculate momentum (higher for faster scrolls) + const rawDelta = e.deltaY || e.detail || -e.wheelDelta; + const delta = Math.sign(rawDelta) * Math.min(Math.abs(rawDelta), 100); // Cap delta + + // Add to momentum based on time between scrolls (faster scrolls = more momentum) + if (timeDelta < 100) { + // Rapid scrolling gets more momentum + scrollState.momentum += delta * (1 + (100 - timeDelta) / 100); + } else { + // Slower scrolling gets normal momentum + scrollState.momentum += delta; + } + + // Start animation if not already running + if (!scrollState.isAnimating) { + scrollState.isAnimating = true; + animateMomentumScroll(); + } + } + + function animateMomentumScroll() { + // If momentum is close to zero, stop animation + if (Math.abs(scrollState.momentum) < 0.5) { + scrollState.momentum = 0; + scrollState.isAnimating = false; + return; + } + + // Add momentum to accumulator + scrollState.scrollAccumulator += scrollState.momentum; + + // Check if we've crossed the threshold to move tasks + if (Math.abs(scrollState.scrollAccumulator) >= scrollState.taskNavigationThreshold) { + const tasksToMove = Math.floor(Math.abs(scrollState.scrollAccumulator) / scrollState.taskNavigationThreshold); + const direction = scrollState.scrollAccumulator > 0 ? 'down' : 'up'; + + // Move the specified number of tasks + for (let i = 0; i < tasksToMove; i++) { + navigateTasks(direction); + } + + // Remove the used part from accumulator + scrollState.scrollAccumulator = scrollState.scrollAccumulator % scrollState.taskNavigationThreshold; + } + + // Apply friction to slow down momentum + scrollState.momentum *= 0.6; + + // Continue animation + requestAnimationFrame(animateMomentumScroll); + } getThemesFromCSS(); setInitialTheme();