Add a scroll to top button, reorder the home dashboard on narrow screens, and paint cards further ahead

This commit is contained in:
Coracle-Bot 2026-09-09 01:14:19 +00:00 committed by hodlbod
parent ff3461a020
commit 0d1e60bf1d
8 changed files with 64 additions and 13 deletions

View file

@ -8,10 +8,12 @@
import {displayContentCount} from "@app/content"
import {inboxSpaceContent} from "@app/inbox"
import {makeSpacePath} from "@app/routes"
const {class: className = ""}: {class?: string} = $props()
</script>
{#if $inboxSpaceContent.length > 0}
<HomeSection title="Activity" icon={Feed}>
<HomeSection title="Activity" icon={Feed} class={className}>
<div class="scroll-container flex items-stretch gap-3 overflow-x-auto px-4 pb-4">
{#each $inboxSpaceContent as { url, timestamp, countsByKind } (url)}
<Link

View file

@ -13,6 +13,8 @@
import {pushModal} from "@app/modal"
import {HostingError, listTenantRelays, type HostedRelay} from "@app/hosting"
const {class: className = ""}: {class?: string} = $props()
let relays = $state<HostedRelay[]>([])
let loading = $state(true)
@ -33,7 +35,7 @@
})
</script>
<HomeSection title="Hosting" icon={Server}>
<HomeSection title="Hosting" icon={Server} class={className}>
{#snippet action()}
{#if relays.length > 0}
<Link href="/settings/hosting" class="button button-neutral button-xs">Manage</Link>

View file

@ -16,6 +16,8 @@
import {followLists, relayLists, router, user} from "@app/core"
import {isFeedLoading, makeFeed, makeFeedContext, makeScrollLoader} from "@app/feeds"
const {class: className = ""}: {class?: string} = $props()
// The hubs most of the user's follows publish to, which is the same set and the same limit
// `syncFollowNetwork` reads their lists from.
const RELAY_LIMIT = 8
@ -77,7 +79,7 @@
})
</script>
<HomeSection title="Network" icon={Planet}>
<HomeSection title="Network" icon={Planet} class={className}>
<div class="flex flex-col gap-3 px-4 pb-4" bind:this={element}>
{#if isEmpty}
<div class="flex flex-col items-center gap-3 pb-4 text-center">

View file

@ -2,6 +2,7 @@
import {sortBy} from "@welshman/lib"
import {COMMENT, NOTE} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util"
import Cv from "@lib/components/Cv.svelte"
import NoteItem from "@app/components/NoteItem.svelte"
import CommentTree from "@app/components/CommentTree.svelte"
import type {FeedContext} from "@app/feeds"
@ -29,7 +30,7 @@
)
</script>
<div class="cv card card-interactive flex flex-col gap-3">
<Cv class="card card-interactive flex flex-col gap-3">
<NoteItem {event} {context} class="" />
{#if nodes.length > 0}
<div class="border-line-less flex flex-col border-t">
@ -38,4 +39,4 @@
{/each}
</div>
{/if}
</div>
</Cv>

View file

@ -7,12 +7,13 @@
icon: string
action?: Snippet
children: Snippet
class?: string
}
const {title, icon, action, children}: Props = $props()
const {title, icon, action, children, class: className = ""}: Props = $props()
</script>
<section class="flex min-w-0 flex-col border-b border-line last:border-b-0">
<section class="flex min-w-0 flex-col border-b border-line {className}">
<div class="flex items-center justify-between gap-3 px-4 pt-4 pb-3">
<h2 class="flex items-center gap-2 text-base font-bold tracking-wide uppercase">
<Icon {icon} size={5} />

View file

@ -0,0 +1,36 @@
<script lang="ts">
import {fade} from "svelte/transition"
import AltArrowUp from "@assets/icons/alt-arrow-up.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
const {element}: {element?: Element} = $props()
let scrolled = $state(false)
const scrollToTop = () => element?.scrollTo({top: 0, behavior: "smooth"})
$effect(() => {
if (element) {
const onScroll = () => {
scrolled = element.scrollTop > 800
}
element.addEventListener("scroll", onScroll, {passive: true})
onScroll()
return () => element.removeEventListener("scroll", onScroll)
}
})
</script>
{#if scrolled}
<div transition:fade class="absolute right-4 bottom-20 z-nav mb-sai md:bottom-4 md:mb-0">
<Button
aria-label="Scroll to top"
class="button button-neutral button-circle shadow-xl"
onclick={scrollToTop}>
<Icon icon={AltArrowUp} />
</Button>
</div>
{/if}

View file

@ -103,6 +103,7 @@
Nothing else should reach for it. */
@utility cv {
content-visibility: auto;
contain-intrinsic-size: auto 16rem;
}
/* Marks the event a link pointed at, so the reader can pick it out of the conversation once the
jump lands. Brightness rather than a background so it works over any row's own surface. */

View file

@ -5,6 +5,7 @@
import Page from "@lib/components/Page.svelte"
import PageBar from "@lib/components/PageBar.svelte"
import PageContent from "@lib/components/PageContent.svelte"
import ScrollToTop from "@lib/components/ScrollToTop.svelte"
import HomeInbox from "@app/components/HomeInbox.svelte"
import HomeActivity from "@app/components/HomeActivity.svelte"
import HomeNetwork from "@app/components/HomeNetwork.svelte"
@ -14,6 +15,8 @@
import {HOSTING_ENABLED} from "@app/hosting"
import {PLATFORM_RELAYS} from "@app/env"
let element: Element | undefined = $state()
const today = new Date().toLocaleDateString(undefined, {
weekday: "long",
month: "short",
@ -38,19 +41,22 @@
<span class="hidden text-sm opacity-75 sm:inline">{today}</span>
</div>
</PageBar>
<PageContent noPad class="flex flex-col bg-surface">
<PageContent noPad bind:element class="flex flex-col bg-surface">
<div class="flex min-w-0 flex-1 flex-col lg:flex-row lg:items-stretch">
<div class="flex min-w-0 flex-col lg:flex-[2] lg:border-r lg:border-line">
<!-- The columns are `contents` below lg, which puts every section in one flow and lets the
rail's health checks sit between the inbox and the rest of the main column. -->
<div class="contents lg:flex lg:min-w-0 lg:flex-[2] lg:flex-col lg:border-r lg:border-line">
<HomeInbox />
<HomeActivity />
<HomeNetwork />
<HomeActivity class="order-last" />
<HomeNetwork class="order-last border-b-0" />
</div>
<div class="flex min-w-0 flex-col border-t border-line lg:w-96 lg:shrink-0 lg:border-t-0">
<div class="contents lg:flex lg:w-96 lg:min-w-0 lg:shrink-0 lg:flex-col">
<HomeHealthChecks />
{#if HOSTING_ENABLED}
<HomeHosting />
<HomeHosting class="border-b-0 max-lg:hidden" />
{/if}
</div>
</div>
</PageContent>
<ScrollToTop {element} />
</Page>