Carry a room loading state in the page bar instead of the transcript (#569)
This commit is contained in:
parent
74a914eb5b
commit
5d40a9bdc5
3 changed files with 24 additions and 16 deletions
|
|
@ -44,7 +44,8 @@
|
||||||
prependParent,
|
prependParent,
|
||||||
} from "@app/rooms"
|
} from "@app/rooms"
|
||||||
import {userSettingsValues} from "@app/settings"
|
import {userSettingsValues} from "@app/settings"
|
||||||
import {makeFeed, makeFeedContext, makeScrollLoader} from "@app/feeds"
|
import {isFeedLoading, makeFeed, makeFeedContext, makeScrollLoader} from "@app/feeds"
|
||||||
|
import {pageLoading} from "@app/loading"
|
||||||
import {checked, deferredRoomPath, setChecked} from "@app/notifications"
|
import {checked, deferredRoomPath, setChecked} from "@app/notifications"
|
||||||
import {makeRoomPath} from "@app/routes"
|
import {makeRoomPath} from "@app/routes"
|
||||||
import {pendingShare, type Share} from "@app/share"
|
import {pendingShare, type Share} from "@app/share"
|
||||||
|
|
@ -396,11 +397,16 @@
|
||||||
// held back for that frame rather than showing the wrong end of the conversation and jumping.
|
// held back for that frame rather than showing the wrong end of the conversation and jumping.
|
||||||
const awaitingJump = $derived(!isNaN(at) && !jumpSettled)
|
const awaitingJump = $derived(!isNaN(at) && !jumpSettled)
|
||||||
|
|
||||||
// There is always more history until the feed says otherwise, so this stays up rather than
|
|
||||||
// blinking between spans while it walks a quiet room.
|
|
||||||
const loadingBackward = $derived($older?.status !== "exhausted")
|
|
||||||
const reachedStartOfHistory = $derived($older?.status === "exhausted")
|
const reachedStartOfHistory = $derived($older?.status === "exhausted")
|
||||||
|
|
||||||
|
// A room paged from an anchor walks in both directions at once, and neither walk is worth a
|
||||||
|
// loader of its own in the transcript — the page bar carries one for the pair of them.
|
||||||
|
$effect(() => {
|
||||||
|
pageLoading.set(isFeedLoading($older) || isFeedLoading($newer))
|
||||||
|
|
||||||
|
return () => pageLoading.set(false)
|
||||||
|
})
|
||||||
|
|
||||||
// Claim the share once we're on screen. Sharing into the room you're already looking at
|
// Claim the share once we're on screen. Sharing into the room you're already looking at
|
||||||
// doesn't re-create this component, so this can't be read once on mount.
|
// doesn't re-create this component, so this can't be read once on mount.
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
|
@ -440,10 +446,6 @@
|
||||||
// from here on arrives through the repository rather than through a forward walk.
|
// from here on arrives through the repository rather than through a forward walk.
|
||||||
const windowStopsShort = $derived(!isNaN(at) && $newer?.status !== "exhausted")
|
const windowStopsShort = $derived(!isNaN(at) && $newer?.status !== "exhausted")
|
||||||
|
|
||||||
// With no messages between them the two loaders would sit against each other, so this one yields
|
|
||||||
// while the other is still running.
|
|
||||||
const loadingForward = $derived(windowStopsShort && !(elements.length === 0 && loadingBackward))
|
|
||||||
|
|
||||||
// While the window stops short, the bottom of the container is not the bottom of the
|
// While the window stops short, the bottom of the container is not the bottom of the
|
||||||
// conversation, so the button is the way back to the live end rather than a scroll — which is
|
// conversation, so the button is the way back to the live end rather than a scroll — which is
|
||||||
// why it clears `at` instead of scrolling. Once the two are the same place, scroll position is
|
// why it clears `at` instead of scrolling. Once the two are the same place, scroll position is
|
||||||
|
|
@ -636,11 +638,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
{#if loadingForward}
|
|
||||||
<p class="py-20 flex justify-center">
|
|
||||||
<Spinner loading={loadingForward}>Looking for messages...</Spinner>
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
<VirtualList
|
<VirtualList
|
||||||
items={elements}
|
items={elements}
|
||||||
getKey={getElementKey}
|
getKey={getElementKey}
|
||||||
|
|
@ -678,9 +675,7 @@
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</VirtualList>
|
</VirtualList>
|
||||||
<p class="flex h-10 items-center justify-center py-20">
|
<p class="flex h-10 items-center justify-center py-20">
|
||||||
{#if loadingBackward}
|
{#if reachedStartOfHistory}
|
||||||
<Spinner loading>Looking for messages...</Spinner>
|
|
||||||
{:else if reachedStartOfHistory}
|
|
||||||
End of message history
|
End of message history
|
||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,12 @@
|
||||||
import {page} from "$app/stores"
|
import {page} from "$app/stores"
|
||||||
import {displayRelayUrl} from "@welshman/util"
|
import {displayRelayUrl} from "@welshman/util"
|
||||||
import ArrowLeft from "@assets/icons/arrow-left.svg?dataurl"
|
import ArrowLeft from "@assets/icons/arrow-left.svg?dataurl"
|
||||||
|
import {fade} from "@lib/transition"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import PageBar from "@lib/components/PageBar.svelte"
|
import PageBar from "@lib/components/PageBar.svelte"
|
||||||
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
|
import {pageLoading} from "@app/loading"
|
||||||
import {decodeRelay} from "@app/relays"
|
import {decodeRelay} from "@app/relays"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -37,6 +40,11 @@
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
{@render title?.()}
|
{@render title?.()}
|
||||||
</div>
|
</div>
|
||||||
|
{#if $pageLoading}
|
||||||
|
<div transition:fade={{duration: 200}} class="shrink-0 place-self-center">
|
||||||
|
<Spinner size="xs" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="truncate text-xs text-primary md:hidden">
|
<div class="truncate text-xs text-primary md:hidden">
|
||||||
{displayRelayUrl(url)}
|
{displayRelayUrl(url)}
|
||||||
|
|
|
||||||
5
src/app/loading.ts
Normal file
5
src/app/loading.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import {writable} from "svelte/store"
|
||||||
|
|
||||||
|
// Whether the page is still waiting on content. The page bar is where that shows, so a view
|
||||||
|
// says so here rather than putting a loader among its own rows.
|
||||||
|
export const pageLoading = writable(false)
|
||||||
Loading…
Reference in a new issue