diff options
| author | Fuwn <[email protected]> | 2026-02-10 01:29:36 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-10 01:29:36 -0800 |
| commit | eb4674514acaaa57885057e0446aacc8660b6708 (patch) | |
| tree | 9e86312d1d03723090fb5416a47de7c74d5baa52 /apps/web/lib/hooks | |
| parent | feat: scoped mark-all-read, share enhancements, notification z-index (diff) | |
| download | asa.news-eb4674514acaaa57885057e0446aacc8660b6708.tar.xz asa.news-eb4674514acaaa57885057e0446aacc8660b6708.zip | |
feat: add automatic timeline refresh with scroll position preservation
New appearance setting (disabled by default) that silently refreshes
the entry list when new entries arrive, provided the user is scrolled
to the top. Falls back to notification when scrolled down to avoid
disrupting reading position.
Diffstat (limited to 'apps/web/lib/hooks')
| -rw-r--r-- | apps/web/lib/hooks/use-realtime-entries.ts | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/apps/web/lib/hooks/use-realtime-entries.ts b/apps/web/lib/hooks/use-realtime-entries.ts index 3fec9f6..22551f9 100644 --- a/apps/web/lib/hooks/use-realtime-entries.ts +++ b/apps/web/lib/hooks/use-realtime-entries.ts @@ -6,6 +6,7 @@ import { createSupabaseBrowserClient } from "@/lib/supabase/client" import { queryKeys } from "@/lib/queries/query-keys" import { toast } from "sonner" import { useNotificationStore } from "@/lib/stores/notification-store" +import { useUserInterfaceStore } from "@/lib/stores/user-interface-store" const DEBOUNCE_MILLISECONDS = 3000 @@ -16,6 +17,15 @@ export function useRealtimeEntries() { const debounceTimerReference = useRef<ReturnType<typeof setTimeout> | null>(null) useEffect(() => { + function invalidateTimelineQueries() { + queryClient.invalidateQueries({ + queryKey: queryKeys.timeline.all, + }) + queryClient.invalidateQueries({ + queryKey: queryKeys.unreadCounts.all, + }) + } + function flushPendingNotifications() { const count = pendingCountReference.current if (count === 0) return @@ -23,6 +33,14 @@ export function useRealtimeEntries() { pendingCountReference.current = 0 debounceTimerReference.current = null + const autoRefresh = useUserInterfaceStore.getState().autoRefreshTimeline + const isAtTop = useUserInterfaceStore.getState().isEntryListAtTop + + if (autoRefresh && isAtTop) { + invalidateTimelineQueries() + return + } + const message = count === 1 ? "1 new entry" : `${count} new entries` @@ -31,9 +49,7 @@ export function useRealtimeEntries() { action: { label: "refresh", onClick: () => { - queryClient.invalidateQueries({ - queryKey: queryKeys.timeline.all, - }) + invalidateTimelineQueries() }, }, }) |