Add a scroll to top button, reorder the home dashboard on narrow screens, and paint cards further ahead
This commit is contained in:
parent
ff3461a020
commit
0d1e60bf1d
8 changed files with 64 additions and 13 deletions
|
|
@ -8,10 +8,12 @@
|
||||||
import {displayContentCount} from "@app/content"
|
import {displayContentCount} from "@app/content"
|
||||||
import {inboxSpaceContent} from "@app/inbox"
|
import {inboxSpaceContent} from "@app/inbox"
|
||||||
import {makeSpacePath} from "@app/routes"
|
import {makeSpacePath} from "@app/routes"
|
||||||
|
|
||||||
|
const {class: className = ""}: {class?: string} = $props()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $inboxSpaceContent.length > 0}
|
{#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">
|
<div class="scroll-container flex items-stretch gap-3 overflow-x-auto px-4 pb-4">
|
||||||
{#each $inboxSpaceContent as { url, timestamp, countsByKind } (url)}
|
{#each $inboxSpaceContent as { url, timestamp, countsByKind } (url)}
|
||||||
<Link
|
<Link
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
import {HostingError, listTenantRelays, type HostedRelay} from "@app/hosting"
|
import {HostingError, listTenantRelays, type HostedRelay} from "@app/hosting"
|
||||||
|
|
||||||
|
const {class: className = ""}: {class?: string} = $props()
|
||||||
|
|
||||||
let relays = $state<HostedRelay[]>([])
|
let relays = $state<HostedRelay[]>([])
|
||||||
let loading = $state(true)
|
let loading = $state(true)
|
||||||
|
|
||||||
|
|
@ -33,7 +35,7 @@
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<HomeSection title="Hosting" icon={Server}>
|
<HomeSection title="Hosting" icon={Server} class={className}>
|
||||||
{#snippet action()}
|
{#snippet action()}
|
||||||
{#if relays.length > 0}
|
{#if relays.length > 0}
|
||||||
<Link href="/settings/hosting" class="button button-neutral button-xs">Manage</Link>
|
<Link href="/settings/hosting" class="button button-neutral button-xs">Manage</Link>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
import {followLists, relayLists, router, user} from "@app/core"
|
import {followLists, relayLists, router, user} from "@app/core"
|
||||||
import {isFeedLoading, makeFeed, makeFeedContext, makeScrollLoader} from "@app/feeds"
|
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
|
// The hubs most of the user's follows publish to, which is the same set and the same limit
|
||||||
// `syncFollowNetwork` reads their lists from.
|
// `syncFollowNetwork` reads their lists from.
|
||||||
const RELAY_LIMIT = 8
|
const RELAY_LIMIT = 8
|
||||||
|
|
@ -77,7 +79,7 @@
|
||||||
})
|
})
|
||||||
</script>
|
</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}>
|
<div class="flex flex-col gap-3 px-4 pb-4" bind:this={element}>
|
||||||
{#if isEmpty}
|
{#if isEmpty}
|
||||||
<div class="flex flex-col items-center gap-3 pb-4 text-center">
|
<div class="flex flex-col items-center gap-3 pb-4 text-center">
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import {sortBy} from "@welshman/lib"
|
import {sortBy} from "@welshman/lib"
|
||||||
import {COMMENT, NOTE} from "@welshman/util"
|
import {COMMENT, NOTE} from "@welshman/util"
|
||||||
import type {TrustedEvent} from "@welshman/util"
|
import type {TrustedEvent} from "@welshman/util"
|
||||||
|
import Cv from "@lib/components/Cv.svelte"
|
||||||
import NoteItem from "@app/components/NoteItem.svelte"
|
import NoteItem from "@app/components/NoteItem.svelte"
|
||||||
import CommentTree from "@app/components/CommentTree.svelte"
|
import CommentTree from "@app/components/CommentTree.svelte"
|
||||||
import type {FeedContext} from "@app/feeds"
|
import type {FeedContext} from "@app/feeds"
|
||||||
|
|
@ -29,7 +30,7 @@
|
||||||
)
|
)
|
||||||
</script>
|
</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="" />
|
<NoteItem {event} {context} class="" />
|
||||||
{#if nodes.length > 0}
|
{#if nodes.length > 0}
|
||||||
<div class="border-line-less flex flex-col border-t">
|
<div class="border-line-less flex flex-col border-t">
|
||||||
|
|
@ -38,4 +39,4 @@
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</Cv>
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@
|
||||||
icon: string
|
icon: string
|
||||||
action?: Snippet
|
action?: Snippet
|
||||||
children: Snippet
|
children: Snippet
|
||||||
|
class?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const {title, icon, action, children}: Props = $props()
|
const {title, icon, action, children, class: className = ""}: Props = $props()
|
||||||
</script>
|
</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">
|
<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">
|
<h2 class="flex items-center gap-2 text-base font-bold tracking-wide uppercase">
|
||||||
<Icon {icon} size={5} />
|
<Icon {icon} size={5} />
|
||||||
|
|
|
||||||
36
src/lib/components/ScrollToTop.svelte
Normal file
36
src/lib/components/ScrollToTop.svelte
Normal 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}
|
||||||
|
|
@ -103,6 +103,7 @@
|
||||||
Nothing else should reach for it. */
|
Nothing else should reach for it. */
|
||||||
@utility cv {
|
@utility cv {
|
||||||
content-visibility: auto;
|
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
|
/* 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. */
|
jump lands. Brightness rather than a background so it works over any row's own surface. */
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
import Page from "@lib/components/Page.svelte"
|
import Page from "@lib/components/Page.svelte"
|
||||||
import PageBar from "@lib/components/PageBar.svelte"
|
import PageBar from "@lib/components/PageBar.svelte"
|
||||||
import PageContent from "@lib/components/PageContent.svelte"
|
import PageContent from "@lib/components/PageContent.svelte"
|
||||||
|
import ScrollToTop from "@lib/components/ScrollToTop.svelte"
|
||||||
import HomeInbox from "@app/components/HomeInbox.svelte"
|
import HomeInbox from "@app/components/HomeInbox.svelte"
|
||||||
import HomeActivity from "@app/components/HomeActivity.svelte"
|
import HomeActivity from "@app/components/HomeActivity.svelte"
|
||||||
import HomeNetwork from "@app/components/HomeNetwork.svelte"
|
import HomeNetwork from "@app/components/HomeNetwork.svelte"
|
||||||
|
|
@ -14,6 +15,8 @@
|
||||||
import {HOSTING_ENABLED} from "@app/hosting"
|
import {HOSTING_ENABLED} from "@app/hosting"
|
||||||
import {PLATFORM_RELAYS} from "@app/env"
|
import {PLATFORM_RELAYS} from "@app/env"
|
||||||
|
|
||||||
|
let element: Element | undefined = $state()
|
||||||
|
|
||||||
const today = new Date().toLocaleDateString(undefined, {
|
const today = new Date().toLocaleDateString(undefined, {
|
||||||
weekday: "long",
|
weekday: "long",
|
||||||
month: "short",
|
month: "short",
|
||||||
|
|
@ -38,19 +41,22 @@
|
||||||
<span class="hidden text-sm opacity-75 sm:inline">{today}</span>
|
<span class="hidden text-sm opacity-75 sm:inline">{today}</span>
|
||||||
</div>
|
</div>
|
||||||
</PageBar>
|
</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-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 />
|
<HomeInbox />
|
||||||
<HomeActivity />
|
<HomeActivity class="order-last" />
|
||||||
<HomeNetwork />
|
<HomeNetwork class="order-last border-b-0" />
|
||||||
</div>
|
</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 />
|
<HomeHealthChecks />
|
||||||
{#if HOSTING_ENABLED}
|
{#if HOSTING_ENABLED}
|
||||||
<HomeHosting />
|
<HomeHosting class="border-b-0 max-lg:hidden" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
|
<ScrollToTop {element} />
|
||||||
</Page>
|
</Page>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue