port profile and explore pages to useInfiniteLoader

This commit is contained in:
Justin Edmund 2025-12-20 15:20:15 -08:00
parent 1933391d38
commit 133cd9ec5b
3 changed files with 57 additions and 66 deletions

View file

@ -1,11 +1,12 @@
<script lang="ts">
import type { PageData } from './$types'
import { onDestroy } from 'svelte'
import { createInfiniteQuery } from '@tanstack/svelte-query'
import ExploreGrid from '$lib/components/explore/ExploreGrid.svelte'
import ProfileHeader from '$lib/components/profile/ProfileHeader.svelte'
import { userQueries } from '$lib/api/queries/user.queries'
import { crewStore } from '$lib/stores/crew.store.svelte'
import { IsInViewport } from 'runed'
import { useInfiniteLoader } from '$lib/stores/loaderState.svelte'
import Icon from '$lib/components/Icon.svelte'
import Button from '$lib/components/ui/Button.svelte'
import PageMeta from '$lib/components/PageMeta.svelte'
@ -18,6 +19,8 @@
const viewerCrewRole = $derived(crewStore.membership?.role ?? null)
const viewerCrewId = $derived(crewStore.crew?.id ?? null)
let sentinelEl = $state<HTMLElement>()
const partiesQuery = createInfiniteQuery(() => ({
...userQueries.parties(data.user?.username ?? ''),
enabled: !!data.user?.username,
@ -38,30 +41,18 @@
initialDataUpdatedAt: 0
}))
// State-gated infinite scroll
const loader = useInfiniteLoader(() => partiesQuery, () => sentinelEl, { rootMargin: '300px' })
// Cleanup on destroy
onDestroy(() => loader.destroy())
const items = $derived(() => {
if (!partiesQuery.data?.pages) return data.items || []
return partiesQuery.data.pages.flatMap((page) => page.results ?? [])
})
const isEmpty = $derived(!partiesQuery.isLoading && items().length === 0)
const showSentinel = $derived(partiesQuery.hasNextPage && !partiesQuery.isFetchingNextPage)
let sentinelEl = $state<HTMLElement>()
const inViewport = new IsInViewport(() => sentinelEl, {
rootMargin: '300px'
})
$effect(() => {
if (
inViewport.current &&
partiesQuery.hasNextPage &&
!partiesQuery.isFetchingNextPage &&
!partiesQuery.isLoading
) {
partiesQuery.fetchNextPage()
}
})
</script>
<PageMeta
@ -104,9 +95,11 @@
<div class="profile-grid">
<ExploreGrid items={items()} />
{#if showSentinel}
<div class="load-more-sentinel" bind:this={sentinelEl}></div>
{/if}
<div
class="load-more-sentinel"
bind:this={sentinelEl}
class:hidden={!partiesQuery.hasNextPage}
></div>
{#if partiesQuery.isFetchingNextPage}
<div class="loading-more">
@ -169,6 +162,10 @@
.load-more-sentinel {
height: 1px;
margin-top: $unit;
&.hidden {
display: none;
}
}
.loading-more {

View file

@ -2,42 +2,33 @@
<script lang="ts">
import type { PageData } from './$types'
import { onDestroy } from 'svelte'
import { createInfiniteQuery } from '@tanstack/svelte-query'
import ExploreGrid from '$lib/components/explore/ExploreGrid.svelte'
import ProfileHeader from '$lib/components/profile/ProfileHeader.svelte'
import { userQueries } from '$lib/api/queries/user.queries'
import { IsInViewport } from 'runed'
import { useInfiniteLoader } from '$lib/stores/loaderState.svelte'
import Icon from '$lib/components/Icon.svelte'
import Button from '$lib/components/ui/Button.svelte'
const { data }: { data: PageData } = $props()
let sentinelEl = $state<HTMLElement>()
const favoritesQuery = createInfiniteQuery(() => userQueries.favorites())
// State-gated infinite scroll
const loader = useInfiniteLoader(() => favoritesQuery, () => sentinelEl, { rootMargin: '300px' })
// Cleanup on destroy
onDestroy(() => loader.destroy())
const items = $derived(() => {
if (!favoritesQuery.data?.pages) return []
return favoritesQuery.data.pages.flatMap((page) => page.items ?? [])
})
const isEmpty = $derived(!favoritesQuery.isLoading && items().length === 0)
const showSentinel = $derived(favoritesQuery.hasNextPage && !favoritesQuery.isFetchingNextPage)
let sentinelEl = $state<HTMLElement>()
const inViewport = new IsInViewport(() => sentinelEl, {
rootMargin: '300px'
})
$effect(() => {
if (
inViewport.current &&
favoritesQuery.hasNextPage &&
!favoritesQuery.isFetchingNextPage &&
!favoritesQuery.isLoading
) {
favoritesQuery.fetchNextPage()
}
})
</script>
<svelte:head>
@ -77,9 +68,11 @@
<div class="profile-grid">
<ExploreGrid items={items()} />
{#if showSentinel}
<div class="load-more-sentinel" bind:this={sentinelEl}></div>
{/if}
<div
class="load-more-sentinel"
bind:this={sentinelEl}
class:hidden={!favoritesQuery.hasNextPage}
></div>
{#if favoritesQuery.isFetchingNextPage}
<div class="loading-more">
@ -142,6 +135,10 @@
.load-more-sentinel {
height: 1px;
margin-top: $unit;
&.hidden {
display: none;
}
}
.loading-more {

View file

@ -1,9 +1,10 @@
<script lang="ts">
import type { PageData } from './$types'
import { onDestroy } from 'svelte'
import { createInfiniteQuery } from '@tanstack/svelte-query'
import ExploreGrid from '$lib/components/explore/ExploreGrid.svelte'
import { partyQueries } from '$lib/api/queries/party.queries'
import { IsInViewport } from 'runed'
import { useInfiniteLoader } from '$lib/stores/loaderState.svelte'
import Icon from '$lib/components/Icon.svelte'
import Button from '$lib/components/ui/Button.svelte'
import PageMeta from '$lib/components/PageMeta.svelte'
@ -11,6 +12,8 @@
const { data } = $props() as { data: PageData }
let sentinelEl = $state<HTMLElement>()
const partiesQuery = createInfiniteQuery(() => ({
...partyQueries.list(),
initialData: data.items
@ -30,29 +33,17 @@
initialDataUpdatedAt: 0
}))
// State-gated infinite scroll
const loader = useInfiniteLoader(() => partiesQuery, () => sentinelEl, { rootMargin: '300px' })
// Cleanup on destroy
onDestroy(() => loader.destroy())
const items = $derived(
partiesQuery.data?.pages.flatMap((page) => page.results) ?? data.items ?? []
)
const isEmpty = $derived(!partiesQuery.isLoading && items.length === 0)
const showSentinel = $derived(partiesQuery.hasNextPage && !partiesQuery.isFetchingNextPage)
let sentinelEl = $state<HTMLElement>()
const inViewport = new IsInViewport(() => sentinelEl, {
rootMargin: '300px'
})
$effect(() => {
if (
inViewport.current &&
partiesQuery.hasNextPage &&
!partiesQuery.isFetchingNextPage &&
!partiesQuery.isLoading
) {
partiesQuery.fetchNextPage()
}
})
</script>
<PageMeta title={m.page_title_teams()} description={m.page_desc_teams()} />
@ -81,9 +72,11 @@
<div class="explore-grid">
<ExploreGrid items={items} />
{#if showSentinel}
<div class="load-more-sentinel" bind:this={sentinelEl}></div>
{/if}
<div
class="load-more-sentinel"
bind:this={sentinelEl}
class:hidden={!partiesQuery.hasNextPage}
></div>
{#if partiesQuery.isFetchingNextPage}
<div class="loading-more">
@ -150,6 +143,10 @@
.load-more-sentinel {
height: 1px;
margin-top: $unit;
&.hidden {
display: none;
}
}
.loading-more {