feat: one gateway port with path-mounted frontends, markdown chat, collapsible sidebars

This commit is contained in:
hh
2026-08-29 00:49:06 +02:00
parent 3ca5843868
commit 932a7a80af
32 changed files with 691 additions and 441 deletions
+89 -27
View File
@@ -1,5 +1,7 @@
<script lang="ts">
import LogOutIcon from "@lucide/svelte/icons/log-out";
import PanelLeftCloseIcon from "@lucide/svelte/icons/panel-left-close";
import PanelLeftOpenIcon from "@lucide/svelte/icons/panel-left-open";
import { goto } from "$app/navigation";
import { base } from "$app/paths";
import { page } from "$app/state";
@@ -9,9 +11,11 @@
import { gateway } from "$lib/gateway.svelte";
import { isActive, NAV } from "$lib/nav";
import { session } from "$lib/session.svelte";
import { ui } from "$lib/ui.svelte";
import { cn } from "$lib/utils";
const running = $derived(gateway.running.length);
const open = $derived(ui.nav);
async function signOut() {
await session.logout();
@@ -20,56 +24,114 @@
</script>
<aside
class="hidden w-52 shrink-0 flex-col border-r bg-sidebar text-sidebar-foreground sm:flex"
class={cn(
"hidden shrink-0 flex-col border-r bg-sidebar text-sidebar-foreground transition-[width] duration-150 sm:flex",
open ? "w-52" : "w-12"
)}
>
<a
class="flex h-12 items-center gap-2 border-b px-4 font-semibold tracking-tight"
class={cn(
"flex h-12 items-center gap-2 border-b font-semibold tracking-tight",
open ? "px-4" : "justify-center"
)}
href="{base}/"
title="Beaver"
>
<span class="size-2.5 rounded-sm bg-primary"></span>
Beaver
<span class="size-2.5 shrink-0 rounded-sm bg-primary"></span>
{#if open}
Beaver
{/if}
</a>
<nav aria-label="Sections" class="flex flex-1 flex-col gap-0.5 p-2">
{#each NAV as item (item.href)}
{@const active = isActive(page.url.pathname, base, item.href)}
<a
aria-current={active ? "page" : undefined}
aria-label={item.label}
class={cn(
"flex h-8 items-center gap-2.5 rounded-md px-2.5 text-sm transition-colors",
"relative flex h-8 items-center gap-2.5 rounded-md text-sm transition-colors",
open ? "px-2.5" : "justify-center",
active
? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
: "text-sidebar-foreground/80 hover:bg-sidebar-accent/60 hover:text-sidebar-foreground"
)}
href="{base}{item.href}"
title={open ? undefined : item.label}
>
<item.icon class="size-4 shrink-0 text-icon" />
<span class="flex-1">{item.label}</span>
{#if open}
<span class="flex-1">{item.label}</span>
{/if}
{#if item.href === "/" && running > 0}
<span
class="tabular rounded-full bg-signal/12 px-1.5 font-medium text-signal text-xs"
>
{running}
</span>
{#if open}
<span
class="tabular rounded-full bg-signal/12 px-1.5 font-medium text-signal text-xs"
>
{running}
</span>
{:else}
<span
class="absolute top-1 right-1 size-1.5 rounded-full bg-signal"
></span>
{/if}
{/if}
</a>
{/each}
</nav>
<div class="flex flex-col gap-2 border-t p-3">
<LiveDot detail={gateway.live.detail} state={gateway.live.state} />
<div class="flex items-center justify-between gap-2">
<span class="truncate text-muted-foreground text-xs">{session.user}</span>
<div class="flex items-center">
<ThemeToggle />
<Button
aria-label="Sign out"
onclick={signOut}
size="icon-sm"
title="Sign out"
variant="ghost"
>
<LogOutIcon class="size-4" />
</Button>
<div
class={cn(
"flex flex-col gap-2 border-t",
open ? "p-3" : "items-center p-2"
)}
>
<LiveDot
detail={gateway.live.detail}
label={open}
state={gateway.live.state}
/>
{#if open}
<div class="flex items-center justify-between gap-2">
<span class="truncate text-muted-foreground text-xs">
{session.user}
</span>
<div class="flex items-center">
<ThemeToggle />
<Button
aria-label="Sign out"
onclick={signOut}
size="icon-sm"
title="Sign out"
variant="ghost"
>
<LogOutIcon class="size-4" />
</Button>
</div>
</div>
</div>
{:else}
<ThemeToggle />
<Button
aria-label="Sign out"
onclick={signOut}
size="icon-sm"
title="Sign out"
variant="ghost"
>
<LogOutIcon class="size-4" />
</Button>
{/if}
<Button
aria-label={open ? "Collapse sidebar" : "Expand sidebar"}
class={open ? "self-end" : ""}
onclick={() => ui.toggleNav()}
size="icon-sm"
title="{open ? 'Collapse' : 'Expand'} sidebar (⌘B)"
variant="ghost"
>
{#if open}
<PanelLeftCloseIcon class="size-4" />
{:else}
<PanelLeftOpenIcon class="size-4" />
{/if}
</Button>
</div>
</aside>