diff --git a/assets/loading.js b/assets/loading.js index c72b7fc..62e5650 100644 --- a/assets/loading.js +++ b/assets/loading.js @@ -5,6 +5,7 @@ const DEBOUNCE_MS = 200 let debounceTimeout = null let historyRestoreGracePeriod = false +let savedScrollPosition = null function getIndicator() { return document.getElementById(INDICATOR_ID) @@ -28,12 +29,18 @@ function hide() { } } -function handleBeforeRequest() { +function handleBeforeRequest(event) { // Ignore requests triggered during history restore grace period if (true === historyRestoreGracePeriod) { return } + // Save scroll position of the target container before HTMX request + const target = event.detail?.target || document.getElementById('main-content') + if (target && typeof target.scrollTop === 'number') { + savedScrollPosition = { element: target, top: target.scrollTop } + } + // Don't start a new debounce if already pending if (debounceTimeout) { return @@ -45,6 +52,14 @@ function handleBeforeRequest() { }, DEBOUNCE_MS) } +function handleAfterSwap() { + // Restore scroll position after HTMX swaps content + if (savedScrollPosition !== null && savedScrollPosition.element) { + savedScrollPosition.element.scrollTop = savedScrollPosition.top + savedScrollPosition = null + } +} + function handleHistoryRestore() { hide() @@ -68,6 +83,7 @@ function handleBeforeHistorySave() { // Initialize event listeners document.body.addEventListener('htmx:beforeRequest', handleBeforeRequest) document.body.addEventListener('htmx:afterRequest', hide) +document.body.addEventListener('htmx:afterSwap', handleAfterSwap) document.body.addEventListener('htmx:timeout', handleTimeout) document.body.addEventListener('htmx:historyRestore', handleHistoryRestore) document.body.addEventListener('htmx:sendError', hide)