Lay the home dashboard out as full-width sections
This commit is contained in:
parent
d3ceaac1b9
commit
c4934db5ff
10 changed files with 178 additions and 130 deletions
|
|
@ -2,7 +2,6 @@
|
||||||
import Stars from "@assets/icons/stars.svg?dataurl"
|
import Stars from "@assets/icons/stars.svg?dataurl"
|
||||||
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 Card from "@lib/components/Card.svelte"
|
|
||||||
import type {HealthCheck} from "@app/healthChecks"
|
import type {HealthCheck} from "@app/healthChecks"
|
||||||
import {healthChecks} from "@app/healthChecks"
|
import {healthChecks} from "@app/healthChecks"
|
||||||
|
|
||||||
|
|
@ -15,13 +14,13 @@
|
||||||
const apply = () => $healthChecks.apply(healthCheck)
|
const apply = () => $healthChecks.apply(healthCheck)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Card sm class="bg-surface flex justify-between">
|
<div class="flex items-start justify-between gap-3 px-4 py-3">
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex min-w-0 flex-col gap-1">
|
||||||
<strong>{healthCheck.title}</strong>
|
<strong class="text-sm">{healthCheck.title}</strong>
|
||||||
<p class="text-sm">{healthCheck.description}</p>
|
<p class="text-sm opacity-75">{healthCheck.description}</p>
|
||||||
</div>
|
</div>
|
||||||
<Button class="button button-neutral button-sm" onclick={apply}>
|
<Button class="button button-neutral button-sm shrink-0" onclick={apply}>
|
||||||
<Icon icon={Stars} />
|
<Icon icon={Stars} size={4} />
|
||||||
{healthCheck.action}
|
{healthCheck.action}
|
||||||
</Button>
|
</Button>
|
||||||
</Card>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Badge from "@lib/components/Badge.svelte"
|
import Badge from "@lib/components/Badge.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
|
import HomeSection from "@app/components/HomeSection.svelte"
|
||||||
import HealthCheckItem from "@app/components/HealthCheckItem.svelte"
|
import HealthCheckItem from "@app/components/HealthCheckItem.svelte"
|
||||||
import {healthChecks} from "@app/healthChecks"
|
import {healthChecks} from "@app/healthChecks"
|
||||||
|
|
||||||
|
|
@ -17,30 +18,30 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card flex flex-col gap-3">
|
<HomeSection title="Health checks" icon={Stethoscope}>
|
||||||
<div class="flex items-center justify-between gap-3">
|
{#snippet action()}
|
||||||
<strong class="flex items-center gap-2 text-lg">
|
|
||||||
<Icon icon={Stethoscope} />
|
|
||||||
Health checks
|
|
||||||
</strong>
|
|
||||||
{#if $pending.length > 0}
|
{#if $pending.length > 0}
|
||||||
<Badge variant="warning">{$pending.length} open</Badge>
|
<Badge variant="warning">{$pending.length} open</Badge>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
{/snippet}
|
||||||
{#if $pending.length === 0}
|
{#if $pending.length === 0}
|
||||||
<p class="flex items-center gap-2 text-sm opacity-75">
|
<p class="flex items-center gap-2 px-4 pb-4 text-sm opacity-75">
|
||||||
<Icon icon={CheckCircle} size={4} />
|
<Icon icon={CheckCircle} size={4} />
|
||||||
Your connection to the network looks healthy.
|
Your connection to the network looks healthy.
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
{#each $pending as healthCheck (healthCheck.title)}
|
<div class="flex flex-col divide-y divide-line border-t border-line">
|
||||||
<HealthCheckItem {healthCheck} />
|
{#each $pending as healthCheck (healthCheck.title)}
|
||||||
{/each}
|
<HealthCheckItem {healthCheck} />
|
||||||
{#if $pending.length > 1}
|
{/each}
|
||||||
<Button class="button button-primary button-sm" onclick={applyAll}>
|
{#if $pending.length > 1}
|
||||||
<Icon icon={Stars} size={4} />
|
<div class="flex justify-center p-3">
|
||||||
Apply all recommendations
|
<Button class="button button-primary button-sm" onclick={applyAll}>
|
||||||
</Button>
|
<Icon icon={Stars} size={4} />
|
||||||
{/if}
|
Apply all recommendations
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</HomeSection>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Link from "@lib/components/Link.svelte"
|
import Link from "@lib/components/Link.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
|
import HomeSection from "@app/components/HomeSection.svelte"
|
||||||
import RelayListItem from "@app/components/hosting/RelayListItem.svelte"
|
import RelayListItem from "@app/components/hosting/RelayListItem.svelte"
|
||||||
import RelayCreate from "@app/components/hosting/RelayCreate.svelte"
|
import RelayCreate from "@app/components/hosting/RelayCreate.svelte"
|
||||||
import {user} from "@app/core"
|
import {user} from "@app/core"
|
||||||
|
|
@ -31,30 +32,32 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loaded}
|
{#if loaded}
|
||||||
<div class="card flex flex-col gap-3">
|
<HomeSection title="Hosting" icon={Server}>
|
||||||
<div class="flex items-center justify-between gap-3">
|
{#snippet action()}
|
||||||
<strong class="flex items-center gap-2 text-lg">
|
|
||||||
<Icon icon={Server} />
|
|
||||||
Hosting
|
|
||||||
</strong>
|
|
||||||
{#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>
|
||||||
{/if}
|
{/if}
|
||||||
|
{/snippet}
|
||||||
|
{#if relays.length > 0}
|
||||||
|
<div class="flex flex-col divide-y divide-line border-y border-line">
|
||||||
|
{#each relays as relay (relay.id)}
|
||||||
|
<RelayListItem {relay} class="px-4 py-3" />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="flex flex-col items-start gap-3 px-4 pt-3 pb-4">
|
||||||
|
<p class="text-sm opacity-75">
|
||||||
|
{#if relays.length > 0}
|
||||||
|
Spin up another hosted space — rooms, calendar and moderation included.
|
||||||
|
{:else}
|
||||||
|
Don't wait for an invite. Flotilla Hosting sets up a space with rooms, calendar and
|
||||||
|
moderation in about a minute.
|
||||||
|
{/if}
|
||||||
|
</p>
|
||||||
|
<Button class="button button-primary button-sm" onclick={openCreate}>
|
||||||
|
<Icon icon={Add} size={4} />
|
||||||
|
{relays.length > 0 ? "Add another space" : "Start a space"}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{#each relays as relay (relay.id)}
|
</HomeSection>
|
||||||
<RelayListItem {relay} />
|
|
||||||
{/each}
|
|
||||||
<p class="text-sm opacity-75">
|
|
||||||
{#if relays.length > 0}
|
|
||||||
Spin up another hosted space — rooms, calendar and moderation included.
|
|
||||||
{:else}
|
|
||||||
Don't wait for an invite. Flotilla Hosting sets up a space with rooms, calendar and
|
|
||||||
moderation in about a minute.
|
|
||||||
{/if}
|
|
||||||
</p>
|
|
||||||
<Button class="button button-primary button-sm" onclick={openCreate}>
|
|
||||||
<Icon icon={Add} size={4} />
|
|
||||||
{relays.length > 0 ? "Add another space" : "Start a space"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Link from "@lib/components/Link.svelte"
|
import Link from "@lib/components/Link.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
|
import HomeSection from "@app/components/HomeSection.svelte"
|
||||||
import HomeInboxItem from "@app/components/HomeInboxItem.svelte"
|
import HomeInboxItem from "@app/components/HomeInboxItem.svelte"
|
||||||
|
import RelayIcon from "@app/components/RelayIcon.svelte"
|
||||||
import RelayName from "@app/components/RelayName.svelte"
|
import RelayName from "@app/components/RelayName.svelte"
|
||||||
import {displayContentCount} from "@app/content"
|
import {displayContentCount} from "@app/content"
|
||||||
import {inboxConversations, inboxSpaceContent} from "@app/inbox"
|
import {inboxConversations, inboxSpaceContent} from "@app/inbox"
|
||||||
|
|
@ -27,18 +29,14 @@
|
||||||
const startChat = () => navigate("/chat")
|
const startChat = () => navigate("/chat")
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card flex flex-col gap-3">
|
<HomeSection title="Inbox" icon={Inbox}>
|
||||||
<div class="flex items-center justify-between gap-3">
|
{#snippet action()}
|
||||||
<strong class="flex items-center gap-2 text-lg">
|
|
||||||
<Icon icon={Inbox} />
|
|
||||||
Inbox
|
|
||||||
</strong>
|
|
||||||
{#if hasUnread}
|
{#if hasUnread}
|
||||||
<Button class="button button-neutral button-xs" onclick={markAllRead}>Mark all read</Button>
|
<Button class="button button-neutral button-xs" onclick={markAllRead}>Mark all read</Button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
{/snippet}
|
||||||
{#if conversations.length === 0}
|
{#if conversations.length === 0 && $inboxSpaceContent.length === 0}
|
||||||
<div class="flex flex-col items-center gap-3 py-8 text-center">
|
<div class="flex flex-col items-center gap-3 px-4 pb-8 text-center">
|
||||||
<p class="font-medium">Nothing in your inbox yet</p>
|
<p class="font-medium">Nothing in your inbox yet</p>
|
||||||
<p class="max-w-md text-sm opacity-75">
|
<p class="max-w-md text-sm opacity-75">
|
||||||
Rooms and spaces you belong to report their activity here — messages, threads, classifieds,
|
Rooms and spaces you belong to report their activity here — messages, threads, classifieds,
|
||||||
|
|
@ -56,16 +54,19 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col divide-y divide-line border-t border-line">
|
||||||
{#each conversations as conversation (conversation.path)}
|
{#each conversations as conversation (conversation.path)}
|
||||||
<HomeInboxItem {conversation} />
|
<HomeInboxItem {conversation} />
|
||||||
{/each}
|
{/each}
|
||||||
|
{#each $inboxSpaceContent as { url, countsByKind } (url)}
|
||||||
|
<Link
|
||||||
|
href={makeSpacePath(url)}
|
||||||
|
class="flex items-center gap-3 px-4 py-3 text-sm hover:bg-surface-more">
|
||||||
|
<RelayIcon {url} size={6} class="shrink-0" />
|
||||||
|
<strong class="truncate"><RelayName {url} /></strong>
|
||||||
|
<span class="truncate opacity-75">{displayContent(countsByKind)}</span>
|
||||||
|
</Link>
|
||||||
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#each $inboxSpaceContent as { url, countsByKind } (url)}
|
</HomeSection>
|
||||||
<Link href={makeSpacePath(url)} class="flex flex-wrap items-baseline gap-x-2 text-sm">
|
|
||||||
<strong><RelayName {url} /></strong>
|
|
||||||
<span class="opacity-75">{displayContent(countsByKind)}</span>
|
|
||||||
</Link>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {formatTimestamp, remove, uniq} from "@welshman/lib"
|
import {formatTimestamp, remove, uniq} from "@welshman/lib"
|
||||||
import ChatRoundDots from "@assets/icons/chat-round-dots.svg?dataurl"
|
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
|
||||||
import Link from "@lib/components/Link.svelte"
|
import Link from "@lib/components/Link.svelte"
|
||||||
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
||||||
import ProfileName from "@app/components/ProfileName.svelte"
|
import ProfileName from "@app/components/ProfileName.svelte"
|
||||||
|
import RelayIcon from "@app/components/RelayIcon.svelte"
|
||||||
import RelayName from "@app/components/RelayName.svelte"
|
import RelayName from "@app/components/RelayName.svelte"
|
||||||
import RoomName from "@app/components/RoomName.svelte"
|
import RoomName from "@app/components/RoomName.svelte"
|
||||||
import NoteContentMinimal from "@app/components/NoteContentMinimal.svelte"
|
import NoteContentMinimal from "@app/components/NoteContentMinimal.svelte"
|
||||||
|
|
@ -25,23 +24,22 @@
|
||||||
const others = $derived(uniq(remove($user.pubkey, conversation.pubkeys ?? [])))
|
const others = $derived(uniq(remove($user.pubkey, conversation.pubkeys ?? [])))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Link href={path} class="card card-sm card-interactive flex flex-col gap-2">
|
<Link href={path} class="flex items-center gap-3 px-4 py-3 hover:bg-surface-more">
|
||||||
<div class="flex min-w-0 items-center gap-2 text-sm">
|
{#if url}
|
||||||
{#if url}
|
<RelayIcon {url} size={9} class="shrink-0" />
|
||||||
|
{:else}
|
||||||
|
<ProfileCircle pubkey={others[0] || $user.pubkey} size={9} class="shrink-0" />
|
||||||
|
{/if}
|
||||||
|
<div class="flex min-w-0 flex-1 flex-col gap-0.5">
|
||||||
|
<div class="flex min-w-0 items-baseline gap-2 text-sm">
|
||||||
<strong class="truncate">
|
<strong class="truncate">
|
||||||
{#if h}
|
{#if url}
|
||||||
<RoomName {url} {h} />
|
{#if h}
|
||||||
{:else}
|
<RoomName {url} {h} />
|
||||||
Chat
|
{:else}
|
||||||
{/if}
|
Chat
|
||||||
</strong>
|
{/if}
|
||||||
<span class="truncate opacity-50">
|
{:else if others.length === 0}
|
||||||
<RelayName {url} />
|
|
||||||
</span>
|
|
||||||
{:else}
|
|
||||||
<Icon icon={ChatRoundDots} size={4} class="shrink-0 opacity-50" />
|
|
||||||
<strong class="truncate">
|
|
||||||
{#if others.length === 0}
|
|
||||||
Note to self
|
Note to self
|
||||||
{:else}
|
{:else}
|
||||||
<ProfileName pubkey={others[0]} />
|
<ProfileName pubkey={others[0]} />
|
||||||
|
|
@ -50,24 +48,29 @@
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</strong>
|
</strong>
|
||||||
<span class="truncate opacity-50">direct message</span>
|
<span class="truncate opacity-50">
|
||||||
{/if}
|
{#if url}
|
||||||
<span class="ml-auto flex shrink-0 items-center gap-2 text-xs opacity-50">
|
<RelayName {url} />
|
||||||
{formatTimestamp(event.created_at)}
|
{:else}
|
||||||
<UnreadDot {path} />
|
direct message
|
||||||
</span>
|
{/if}
|
||||||
</div>
|
</span>
|
||||||
<div class="flex min-w-0 items-center gap-2">
|
</div>
|
||||||
<ProfileCircle pubkey={event.pubkey} size={5} />
|
<div class="flex min-w-0 items-center gap-1 text-sm opacity-75">
|
||||||
<span class="shrink-0 text-xs opacity-50">
|
<span class="shrink-0">
|
||||||
{#if event.pubkey === $user.pubkey}
|
{#if event.pubkey === $user.pubkey}
|
||||||
You:
|
You:
|
||||||
{:else}
|
{:else}
|
||||||
<ProfileName pubkey={event.pubkey} {url} />:
|
<ProfileName pubkey={event.pubkey} {url} />:
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<NoteContentMinimal {event} {url} singleLine />
|
<NoteContentMinimal {event} {url} singleLine />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex shrink-0 items-center gap-2 text-xs opacity-50">
|
||||||
|
{formatTimestamp(event.created_at)}
|
||||||
|
<UnreadDot {path} />
|
||||||
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@
|
||||||
import {Feeds} from "@welshman/app"
|
import {Feeds} from "@welshman/app"
|
||||||
import {Scope, feedFromFilter, makeIntersectionFeed, makeScopeFeed} from "@welshman/feeds"
|
import {Scope, feedFromFilter, makeIntersectionFeed, makeScopeFeed} from "@welshman/feeds"
|
||||||
import Planet from "@assets/icons/planet.svg?dataurl"
|
import Planet from "@assets/icons/planet.svg?dataurl"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
|
||||||
import Link from "@lib/components/Link.svelte"
|
import Link from "@lib/components/Link.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import Spinner from "@lib/components/Spinner.svelte"
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
|
import HomeSection from "@app/components/HomeSection.svelte"
|
||||||
import NoteItem from "@app/components/NoteItem.svelte"
|
import NoteItem from "@app/components/NoteItem.svelte"
|
||||||
import {app, relayLists, user} from "@app/core"
|
import {app, relayLists, user} from "@app/core"
|
||||||
import {makeFeedContext} from "@app/feeds"
|
import {makeFeedContext} from "@app/feeds"
|
||||||
|
|
@ -60,18 +60,14 @@
|
||||||
onMount(load)
|
onMount(load)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card flex flex-col gap-3">
|
<HomeSection title="Network" icon={Planet}>
|
||||||
<strong class="flex items-center gap-2 text-lg">
|
|
||||||
<Icon icon={Planet} />
|
|
||||||
Network
|
|
||||||
</strong>
|
|
||||||
{#if events.length === 0}
|
{#if events.length === 0}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<div class="flex justify-center py-8">
|
<div class="flex justify-center px-4 pb-8">
|
||||||
<Spinner {loading}>Looking for notes from people you follow…</Spinner>
|
<Spinner {loading}>Looking for notes from people you follow…</Spinner>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex flex-col items-center gap-3 py-8 text-center">
|
<div class="flex flex-col items-center gap-3 px-4 pb-8 text-center">
|
||||||
<p class="font-medium">Follow a few people to fill this out</p>
|
<p class="font-medium">Follow a few people to fill this out</p>
|
||||||
<p class="max-w-md text-sm opacity-75">
|
<p class="max-w-md text-sm opacity-75">
|
||||||
Notes from the people you follow collect here. Spaces are a good place to find some.
|
Notes from the people you follow collect here. Spaces are a good place to find some.
|
||||||
|
|
@ -80,11 +76,13 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col divide-y divide-line border-t border-line">
|
||||||
{#each events.slice(0, limit) as event (event.id)}
|
{#each events.slice(0, limit) as event (event.id)}
|
||||||
<NoteItem {event} {context} />
|
<NoteItem {event} {context} class="cv px-4 py-3" />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<Button class="button button-neutral button-sm" onclick={showMore}>Show more</Button>
|
<div class="flex justify-center border-t border-line p-3">
|
||||||
|
<Button class="button button-neutral button-sm" onclick={showMore}>Show more</Button>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</HomeSection>
|
||||||
|
|
|
||||||
24
src/app/components/HomeSection.svelte
Normal file
24
src/app/components/HomeSection.svelte
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type {Snippet} from "svelte"
|
||||||
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title: string
|
||||||
|
icon: string
|
||||||
|
action?: Snippet
|
||||||
|
children: Snippet
|
||||||
|
}
|
||||||
|
|
||||||
|
const {title, icon, action, children}: Props = $props()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="flex min-w-0 flex-col border-b border-line last:border-b-0">
|
||||||
|
<div class="flex items-center justify-between gap-3 px-4 pt-4 pb-3">
|
||||||
|
<h2 class="flex items-center gap-2 text-xs font-bold tracking-widest uppercase opacity-75">
|
||||||
|
<Icon {icon} size={4} />
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
{@render action?.()}
|
||||||
|
</div>
|
||||||
|
{@render children()}
|
||||||
|
</section>
|
||||||
|
|
@ -19,9 +19,16 @@
|
||||||
children?: Snippet
|
children?: Snippet
|
||||||
context: FeedContext
|
context: FeedContext
|
||||||
url?: string
|
url?: string
|
||||||
|
class?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const {url, event, children, context}: Props = $props()
|
const {
|
||||||
|
url,
|
||||||
|
event,
|
||||||
|
children,
|
||||||
|
context,
|
||||||
|
class: className = "card card-interactive",
|
||||||
|
}: Props = $props()
|
||||||
|
|
||||||
const getRelays = () => (url ? [url] : $router.resolver.relays([seen(event)]))
|
const getRelays = () => (url ? [url] : $router.resolver.relays([seen(event)]))
|
||||||
|
|
||||||
|
|
@ -34,7 +41,7 @@
|
||||||
const onEmoji = (emoji: NativeEmoji) => createReaction({content: emoji.unicode, tags: []})
|
const onEmoji = (emoji: NativeEmoji) => createReaction({content: emoji.unicode, tags: []})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Cv tag={NoteCard} {event} {url} class="card card-interactive">
|
<Cv tag={NoteCard} {event} {url} class={className}>
|
||||||
<NoteContent {event} expandMode="inline" />
|
<NoteContent {event} expandMode="inline" />
|
||||||
<div class="flex w-full justify-between gap-2">
|
<div class="flex w-full justify-between gap-2">
|
||||||
<ReactionSummary
|
<ReactionSummary
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,17 @@
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
relay: HostedRelay
|
relay: HostedRelay
|
||||||
|
class?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const {relay}: Props = $props()
|
const {relay, class: className = "card p-3 sm:p-4"}: Props = $props()
|
||||||
|
|
||||||
const name = $derived(relay.info_name || relay.subdomain)
|
const name = $derived(relay.info_name || relay.subdomain)
|
||||||
const host = $derived(canonicalRelayHost(relay))
|
const host = $derived(canonicalRelayHost(relay))
|
||||||
const href = $derived(makeSpacePath(getHostedRelayUrl(relay), "admin"))
|
const href = $derived(makeSpacePath(getHostedRelayUrl(relay), "admin"))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card flex flex-row items-center justify-between gap-3 p-3 sm:p-4">
|
<div class="flex flex-row items-center justify-between gap-3 {className}">
|
||||||
<ImageIcon size={8} alt="" class="rounded-xl" src={relay.info_icon || Server} />
|
<ImageIcon size={8} alt="" class="rounded-xl" src={relay.info_icon || Server} />
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<p class="truncate text-sm font-medium">{name}</p>
|
<p class="truncate text-sm font-medium">{name}</p>
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,12 @@
|
||||||
import {HOSTING_ENABLED} from "@app/hosting"
|
import {HOSTING_ENABLED} from "@app/hosting"
|
||||||
import {PLATFORM_RELAYS} from "@app/env"
|
import {PLATFORM_RELAYS} from "@app/env"
|
||||||
|
|
||||||
|
const today = new Date().toLocaleDateString(undefined, {
|
||||||
|
weekday: "long",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
})
|
||||||
|
|
||||||
// A single-space build has no dashboard to show - everything on it is scoped to the one space.
|
// A single-space build has no dashboard to show - everything on it is scoped to the one space.
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (PLATFORM_RELAYS.length > 0) {
|
if (PLATFORM_RELAYS.length > 0) {
|
||||||
|
|
@ -23,21 +29,26 @@
|
||||||
|
|
||||||
<Page>
|
<Page>
|
||||||
<PageBar>
|
<PageBar>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center justify-between gap-2">
|
||||||
<Icon icon={Home} size={6} />
|
<div class="flex items-center gap-2">
|
||||||
<strong>Home</strong>
|
<Icon icon={Home} size={6} />
|
||||||
|
<strong>Home</strong>
|
||||||
|
</div>
|
||||||
|
<span class="hidden text-sm opacity-75 sm:inline">{today}</span>
|
||||||
</div>
|
</div>
|
||||||
</PageBar>
|
</PageBar>
|
||||||
<PageContent class="flex flex-col gap-4 p-2 sm:p-4 lg:flex-row lg:items-start">
|
<PageContent noPad class="flex flex-col">
|
||||||
<div class="flex min-w-0 flex-col gap-4 lg:flex-[2]">
|
<div class="flex min-w-0 flex-col lg:flex-row lg:items-stretch">
|
||||||
<HomeInbox />
|
<div class="flex min-w-0 flex-col bg-surface lg:flex-[2] lg:border-r lg:border-line">
|
||||||
<HomeNetwork />
|
<HomeInbox />
|
||||||
</div>
|
<HomeNetwork />
|
||||||
<div class="flex min-w-0 flex-col gap-4 lg:flex-1">
|
</div>
|
||||||
<HomeHealthChecks />
|
<div class="flex min-w-0 flex-col border-t border-line lg:w-80 lg:shrink-0 lg:border-t-0">
|
||||||
{#if HOSTING_ENABLED}
|
<HomeHealthChecks />
|
||||||
<HomeHosting />
|
{#if HOSTING_ENABLED}
|
||||||
{/if}
|
<HomeHosting />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
</Page>
|
</Page>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue