diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-17 11:41:50 -0800 |
|---|---|---|
| committer | Adam Mathes <adam@adammathes.com> | 2026-02-17 11:41:50 -0800 |
| commit | 3bd52a03323a9983aa7896af4d3fc3668e4c1252 (patch) | |
| tree | 408065c8f4b21030c2ae3e070447e10fc124be70 /frontend-vanilla/src/main.ts | |
| parent | ea9ec7f41c0447027b66f52c0c4cd0d5c9777bfa (diff) | |
| download | neko-3bd52a03323a9983aa7896af4d3fc3668e4c1252.tar.gz neko-3bd52a03323a9983aa7896af4d3fc3668e4c1252.tar.bz2 neko-3bd52a03323a9983aa7896af4d3fc3668e4c1252.zip | |
Fix regression: mark-as-read not triggering on window scroll
Diffstat (limited to 'frontend-vanilla/src/main.ts')
| -rw-r--r-- | frontend-vanilla/src/main.ts | 50 |
1 files changed, 21 insertions, 29 deletions
diff --git a/frontend-vanilla/src/main.ts b/frontend-vanilla/src/main.ts index aa00bd3..6a605c4 100644 --- a/frontend-vanilla/src/main.ts +++ b/frontend-vanilla/src/main.ts @@ -271,31 +271,17 @@ export function renderItems() { if (scrollRoot) { let readTimeoutId: number | null = null; scrollRoot.onscroll = () => { - // Infinite scroll: check immediately on every scroll event (cheap comparison). - // Guard: only when content actually overflows the container (scrollHeight > clientHeight). + // Infinite scroll check (container only) if (!store.loading && store.hasMore && scrollRoot.scrollHeight > scrollRoot.clientHeight) { if (scrollRoot.scrollHeight - scrollRoot.scrollTop - scrollRoot.clientHeight < 200) { loadMore(); } } - // Mark-as-read: debounced to avoid excessive DOM queries + // Mark-as-read: debounced if (readTimeoutId === null) { readTimeoutId = window.setTimeout(() => { - const containerRect = scrollRoot.getBoundingClientRect(); - - store.items.forEach((item) => { - if (item.read) return; - - const el = document.querySelector(`.feed-item[data-id="${item._id}"]`); - if (el) { - const rect = el.getBoundingClientRect(); - // Mark as read if the bottom of the item is above the top of the container - if (rect.bottom < containerRect.top) { - updateItem(item._id, { read: true }); - } - } - }); + checkReadItems(scrollRoot); readTimeoutId = null; }, 250); } @@ -303,6 +289,22 @@ export function renderItems() { } } +function checkReadItems(scrollRoot: HTMLElement) { + const containerRect = scrollRoot.getBoundingClientRect(); + store.items.forEach((item) => { + if (item.read) return; + + const el = document.querySelector(`.feed-item[data-id="${item._id}"]`); + if (el) { + const rect = el.getBoundingClientRect(); + // Mark as read if the bottom of the item is above the top of the container + if (rect.bottom < containerRect.top) { + updateItem(item._id, { read: true }); + } + } + }); +} + // Polling fallback for infinite scroll (matches V1 behavior) // This ensures that even if scroll events are missed or layout shifts occur without scroll, // we still load more items when near the bottom. @@ -319,18 +321,8 @@ if (typeof window !== 'undefined') { if (store.loading || !store.hasMore) return; if (scrollRoot) { - // DEBUG LOGGING - /* - console.log('Scroll Poll', { - scrollHeight: scrollRoot.scrollHeight, - scrollTop: scrollRoot.scrollTop, - clientHeight: scrollRoot.clientHeight, - offset: scrollRoot.scrollHeight - scrollRoot.scrollTop - scrollRoot.clientHeight, - docHeight: document.documentElement.scrollHeight, - winHeight: window.innerHeight, - winScroll: window.scrollY - }); - */ + // Check for read items periodically (robustness fallback) + checkReadItems(scrollRoot); // Check container scroll (if container is scrollable) if (scrollRoot.scrollHeight > scrollRoot.clientHeight) { |
