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:
@@ -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>
|
||||
Reference in New Issue
Block a user