diff --git a/src/app/feeds.ts b/src/app/feeds.ts index fb9e8e56..0272ad5d 100644 --- a/src/app/feeds.ts +++ b/src/app/feeds.ts @@ -415,14 +415,21 @@ const makeFeedLoader = (load: () => Promise) => { if (found > 0) break } - - state.set({status: "idle"}) } finally { running = false } } - return {subscribe: state.subscribe, run} + // A run covers a few spans and the scroller starts another one a moment later, so settling at + // the end of a run blinks the spinner once per page. What ends a load is the trigger going + // quiet — the list grown long enough that nothing more is wanted. + const settle = () => { + if (!running && isFeedLoading(get(state))) { + state.set({status: "idle"}) + } + } + + return {subscribe: state.subscribe, run, settle} } // A loader triggered by proximity to the end of a scroll container, which is how every list in @@ -441,6 +448,7 @@ export const makeScrollLoader = ( threshold: 5000, ...options, onScroll: loader.run, + onSettle: loader.settle, }) return {subscribe: loader.subscribe, stop: scroller.stop} diff --git a/src/lib/html.ts b/src/lib/html.ts index 9a3b526e..975e3106 100644 --- a/src/lib/html.ts +++ b/src/lib/html.ts @@ -90,6 +90,9 @@ export const copyToClipboard = (text: string) => { export type ScrollerOpts = { onScroll: () => any + // Called by a check that decides nothing more is wanted, which is the only signal that paging + // has stopped rather than paused between requests. + onSettle?: () => any element: Element threshold?: number reverse?: boolean @@ -103,6 +106,7 @@ export type Scroller = { export const createScroller = ({ onScroll, + onSettle, element, delay = 1000, threshold = 2000, @@ -134,6 +138,8 @@ export const createScroller = ({ // Only trigger loading the first time we reach the threshold if (shouldLoad) { await onScroll() + } else { + onSettle?.() } } } catch (error) {