diff --git a/src/components/NoteList/index.tsx b/src/components/NoteList/index.tsx index 13092cdd..0affb438 100644 --- a/src/components/NoteList/index.tsx +++ b/src/components/NoteList/index.tsx @@ -41,6 +41,7 @@ import PullToRefresh from 'react-simple-pull-to-refresh' import { formatPubkey, pubkeyToNpub } from '@/lib/pubkey' import { NoteFeedProfileContext, type NoteFeedProfileContextValue } from '@/providers/NoteFeedProfileContext' import type { TProfile } from '@/types' +import { Loader2 } from 'lucide-react' import NoteCard, { NoteCardLoadingSkeleton } from '../NoteCard' const LIMIT = 100 // Increased from 200 to load more events per request @@ -87,7 +88,8 @@ const NoteList = forwardRef( */ preserveTimelineOnSubRequestsChange = false, /** - * Spells page: after this many ms, clear the loading skeleton so the list area renders; subscription keeps running. + * Spells / one-shot feeds: when the initial fetch finishes with zero rows, show explicit empty copy + * (see list footer). Does not end loading early — loading stays until EOSE, first events, or safety timeouts. */ spellFetchTimeoutMs, /** Spells page: bumps when user picks a feed; used with {@link onSpellFeedFirstPaint}. */ @@ -117,7 +119,7 @@ const NoteList = forwardRef( extraShouldHideEvent?: (evt: Event) => boolean feedSubscriptionKey?: string preserveTimelineOnSubRequestsChange?: boolean - /** When set (spells), max time to show the initial loading skeleton (ms). */ + /** When set (e.g. spells), use explicit empty-feed copy after load completes with no rows. */ spellFetchTimeoutMs?: number spellFeedInstrumentToken?: number onSpellFeedFirstPaint?: (detail: { eventCount: number; firstEventId: string }) => void @@ -732,7 +734,6 @@ const NoteList = forwardRef( showKind1111, useFilterAsIs, areAlgoRelays, - spellFetchTimeoutMs, oneShotFetch ]) @@ -758,21 +759,6 @@ const NoteList = forwardRef( } }, [timelineSubscriptionKey, refreshCount]) - /** Spells: drop loading skeleton quickly so rows (or empty + reload) appear while REQ continues. */ - useEffect(() => { - if (spellFetchTimeoutMs == null || spellFetchTimeoutMs <= 0) return - if (!subRequestsRef.current.length) return - let cancelled = false - const id = window.setTimeout(() => { - if (cancelled) return - setLoading(false) - }, spellFetchTimeoutMs) - return () => { - cancelled = true - clearTimeout(id) - } - }, [timelineSubscriptionKey, refreshCount, spellFetchTimeoutMs]) - // Use refs to avoid dependency issues and ensure latest values in async callbacks const showCountRef = useRef(showCount) const loadingRef = useRef(loading) @@ -1132,8 +1118,15 @@ const NoteList = forwardRef( /> ))} {events.length === 0 && loading ? ( -
- +
+ +

{t('Loading...')}

) : events.length > 0 && (hasMore || loading) ? (
diff --git a/src/constants.ts b/src/constants.ts index 89f4c6bb..aacac831 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -29,10 +29,10 @@ export const MAX_REQ_RELAY_URLS = MAX_CONCURRENT_RELAY_CONNECTIONS /** Multi-relay queries and timeline initial REQ: after the first event, wait this long then close (query) or finalize EOSE (live feed) while keeping the subscription open for new events. */ export const FIRST_RELAY_RESULT_GRACE_MS = 2000 -/** Spells page NoteList: drop the loading skeleton after this long so the feed can render; REQ stays open and rows stream in. */ +/** Legacy name: was used to cap spell NoteList skeleton time; loading now ends on EOSE / first events / safety timeouts. Kept for forks. */ export const SPELL_FEED_LOADING_MAX_MS = 1000 -/** @deprecated Use {@link SPELL_FEED_LOADING_MAX_MS}; kept so old imports do not break. */ +/** @deprecated Alias of {@link SPELL_FEED_LOADING_MAX_MS}. */ export const SPELL_FEED_FIRST_RELAY_GRACE_MS = SPELL_FEED_LOADING_MAX_MS /** diff --git a/src/pages/primary/SpellsPage/index.tsx b/src/pages/primary/SpellsPage/index.tsx index 0cfb8d96..80d078e9 100644 --- a/src/pages/primary/SpellsPage/index.tsx +++ b/src/pages/primary/SpellsPage/index.tsx @@ -37,8 +37,7 @@ import { ExtendedKind, FAUX_SPELL_ORDER, FIRST_RELAY_RESULT_GRACE_MS, - PROFILE_FEED_KINDS, - SPELL_FEED_LOADING_MAX_MS + PROFILE_FEED_KINDS } from '@/constants' import { isUserInEventMentions } from '@/lib/event' import { formatPubkey } from '@/lib/pubkey' @@ -1334,7 +1333,7 @@ const SpellsPage = forwardRef(function SpellsPage( subRequests={subRequests} feedSubscriptionKey={spellFeedSubscriptionKey} showKinds={showKinds} - spellFetchTimeoutMs={SPELL_FEED_LOADING_MAX_MS} + spellFetchTimeoutMs={1} spellFeedInstrumentToken={spellFeedInstrumentToken} onSpellFeedFirstPaint={handleSpellFeedFirstPaint} useFilterAsIs={fauxNoteListUseFilterAsIs} @@ -1361,7 +1360,7 @@ const SpellsPage = forwardRef(function SpellsPage( subRequests={subRequests} feedSubscriptionKey={spellFeedSubscriptionKey} showKinds={showKinds} - spellFetchTimeoutMs={SPELL_FEED_LOADING_MAX_MS} + spellFetchTimeoutMs={1} spellFeedInstrumentToken={spellFeedInstrumentToken} onSpellFeedFirstPaint={handleSpellFeedFirstPaint} useFilterAsIs