feat(chrome): shared account menu and global app header

Move account actions (Settings, Downloads, Display preferences, Sign
out) out of the library-only header into a shared AccountMenu anchored in
a global AppHeader, available on every authenticated non-immersive
screen. Add a layoutShell helper deciding where chrome shows, expose
serverName/serverUrl auth stores, and a display view-mode preference. The
settings page also gains the UR-053 WiFi-only toggle.

TRACES: UR-054 | DR-075, DR-076, DR-077
This commit is contained in:
2026-07-23 20:03:12 +02:00
parent f25deba824
commit cf9472f04f
9 changed files with 643 additions and 19 deletions
+77
View File
@@ -0,0 +1,77 @@
<!--
Shared application header. Lifted out of the library layout so the account
menu (and desktop nav) are available on every authenticated, non-immersive
screen, not only under /library. Routes that need in-header search (the
library layout) pass it in via the `search` snippet; other routes omit it.
TRACES: UR-054 | DR-076
-->
<script lang="ts">
import type { Snippet } from "svelte";
import { page } from "$app/stores";
import AccountMenu from "$lib/components/account/AccountMenu.svelte";
let { search }: { search?: Snippet } = $props();
const pathname = $derived($page.url.pathname);
</script>
<header class="sticky top-0 z-50 bg-[var(--color-background)]/95 backdrop-blur border-b border-gray-800 flex-shrink-0">
<div class="px-4 py-3 flex items-center gap-4">
<!-- Logo -->
<a href="/library" class="text-xl font-bold text-[var(--color-jellyfin)]">
JellyTau
</a>
<!-- Desktop Navigation -->
<nav class="hidden md:flex items-center gap-1">
<a
href="/"
class="px-3 py-2 rounded-lg text-sm transition-colors hover:bg-[var(--color-surface)] {pathname === '/' ? 'text-[var(--color-jellyfin)] bg-[var(--color-surface)]' : 'text-gray-400'}"
>
Home
</a>
<a
href="/library"
class="px-3 py-2 rounded-lg text-sm transition-colors hover:bg-[var(--color-surface)] {pathname.startsWith('/library') ? 'text-[var(--color-jellyfin)] bg-[var(--color-surface)]' : 'text-gray-400'}"
>
Library
</a>
<a
href="/downloads"
class="px-3 py-2 rounded-lg text-sm transition-colors hover:bg-[var(--color-surface)] {pathname === '/downloads' ? 'text-[var(--color-jellyfin)] bg-[var(--color-surface)]' : 'text-gray-400'}"
>
Downloads
</a>
<a
href="/settings"
class="px-3 py-2 rounded-lg text-sm transition-colors hover:bg-[var(--color-surface)] {pathname === '/settings' ? 'text-[var(--color-jellyfin)] bg-[var(--color-surface)]' : 'text-gray-400'}"
>
Settings
</a>
</nav>
<!-- Optional in-header search (library layout supplies it). -->
{#if search}
<div class="flex-1 max-w-md hidden md:block space-y-2">
{@render search()}
</div>
{/if}
<!-- Account menu, anchored to the user's identity. -->
<div class="ml-auto flex items-center gap-3">
<!-- Desktop: Downloads quick icon (kept per UX spec §1.2). -->
<a
href="/downloads"
class="hidden md:block text-gray-400 hover:text-white transition-colors"
title="Downloads"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
</a>
<AccountMenu />
</div>
</div>
</header>