From 5d41ca72ca53bd6c37faf550fa913f4737015220 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 03:08:12 +0000 Subject: [PATCH] Move Load more into the top toolbar; auto-fetch when a delete empties the page Two changes to the collection record list: - Relocate the "Load more" control from below the list into the top toolbar alongside Edit and Go live, restyled as a matching chip. - When a delete empties the loaded page while the PDS still has more records, fetch the next page automatically instead of showing a false "No records" / 0-count state. A new effect pulls the next page whenever the list is empty but not exhausted (guarded against the initial load and against spinning on a fetch error). The empty-state placeholder and the record count now key off `done` rather than `loading`, so nothing false flashes in the gap between the page clearing and the refetch. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_0162M8cx8jXKS1S4gwrDempX --- src/components/explore/CollectionExplorer.tsx | 76 ++++++++++++------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/src/components/explore/CollectionExplorer.tsx b/src/components/explore/CollectionExplorer.tsx index b01761b..fee2906 100644 --- a/src/components/explore/CollectionExplorer.tsx +++ b/src/components/explore/CollectionExplorer.tsx @@ -3,7 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; -import { Pause, Play, FilePenLine, Trash2, X } from 'lucide-react'; +import { Pause, Play, FilePenLine, Trash2, X, Plus } from 'lucide-react'; import { listRecordsPage, type AtRecord } from '@/utils/atproto/pdsClient'; import { msUntilBudget, @@ -247,6 +247,20 @@ function CollectionList({ loadPage(undefined); }, [loadPage]); + // If a delete empties the loaded set while the PDS still has more pages, + // pull the next page automatically instead of flashing a false "No records" + // / 0-count state when the collection isn't actually empty. The cursor sits + // at the end of what we've fetched, so deleting earlier rows never + // invalidates it. Guarded on `!error` so a failed fetch doesn't spin here, + // and on `cursor` so it stays dormant during the initial load (cursor is + // still undefined then — that first page is the other effect's job). + useEffect(() => { + if (loading || error) return; + if (records.length > 0 || done) return; + if (cursor === undefined) return; + loadPage(cursor); + }, [records.length, loading, error, done, cursor, loadPage]); + // Live mode: jetstream subscription filtered to this collection+DID. New // commits are prepended to the list (capped to a sensible window). useEffect(() => { @@ -624,8 +638,33 @@ function CollectionList({ {live ? : } {live ? 'Live' : 'Go live'} + {!done && records.length > 0 && ( + + )} - {records.length} record{records.length === 1 ? '' : 's'} + {records.length === 0 && !done + ? 'Loading…' + : `${records.length} record${records.length === 1 ? '' : 's'}`} @@ -791,10 +830,15 @@ function CollectionList({ {error &&

{error}

} - {records.length === 0 && !loading && !error && ( + {/* Only claim the collection is empty once we've actually exhausted it + (done). While records is empty but more pages remain — the initial + load, or the gap after a delete clears the page before the auto-fetch + refills it — keep showing "Loading" so we never flash a false empty + state. */} + {records.length === 0 && done && !error && (

No records in this collection.

)} - {loading && records.length === 0 && ( + {records.length === 0 && !done && !error && (

Loading records…

)} @@ -938,30 +982,6 @@ function CollectionList({ ); })} - - {!done && records.length > 0 && ( - - )}
); -- 2.51.2