Browse Source

show spinnners when fetching and loading

imwald
Silberengel 1 month ago
parent
commit
baceadf7a3
  1. 33
      src/components/NoteList/index.tsx
  2. 4
      src/constants.ts
  3. 7
      src/pages/primary/SpellsPage/index.tsx

33
src/components/NoteList/index.tsx

@ -41,6 +41,7 @@ import PullToRefresh from 'react-simple-pull-to-refresh' @@ -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( @@ -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( @@ -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( @@ -732,7 +734,6 @@ const NoteList = forwardRef(
showKind1111,
useFilterAsIs,
areAlgoRelays,
spellFetchTimeoutMs,
oneShotFetch
])
@ -758,21 +759,6 @@ const NoteList = forwardRef( @@ -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( @@ -1132,8 +1118,15 @@ const NoteList = forwardRef(
/>
))}
{events.length === 0 && loading ? (
<div ref={bottomRef}>
<NoteCardLoadingSkeleton />
<div
ref={bottomRef}
className="flex min-h-[40vh] flex-col items-center justify-center gap-3 px-4 py-8"
role="status"
aria-live="polite"
aria-busy="true"
>
<Loader2 className="size-8 shrink-0 animate-spin text-muted-foreground" aria-hidden />
<p className="text-sm text-muted-foreground">{t('Loading...')}</p>
</div>
) : events.length > 0 && (hasMore || loading) ? (
<div ref={bottomRef}>

4
src/constants.ts

@ -29,10 +29,10 @@ export const MAX_REQ_RELAY_URLS = MAX_CONCURRENT_RELAY_CONNECTIONS @@ -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
/**

7
src/pages/primary/SpellsPage/index.tsx

@ -37,8 +37,7 @@ import { @@ -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<TPageRef>(function SpellsPage( @@ -1334,7 +1333,7 @@ const SpellsPage = forwardRef<TPageRef>(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<TPageRef>(function SpellsPage( @@ -1361,7 +1360,7 @@ const SpellsPage = forwardRef<TPageRef>(function SpellsPage(
subRequests={subRequests}
feedSubscriptionKey={spellFeedSubscriptionKey}
showKinds={showKinds}
spellFetchTimeoutMs={SPELL_FEED_LOADING_MAX_MS}
spellFetchTimeoutMs={1}
spellFeedInstrumentToken={spellFeedInstrumentToken}
onSpellFeedFirstPaint={handleSpellFeedFirstPaint}
useFilterAsIs

Loading…
Cancel
Save