Files
minstrel/web/src/lib/components/Shell.svelte
T
bvandeusen ccef9be2d3 feat(web): add PlayerBar slot to Shell
Grid grows to 3 rows (auto / 1fr / auto); PlayerBar spans both columns
in the last row, rendering only when player.current is defined so the
row collapses before first play.
2026-04-24 21:42:10 -04:00

89 lines
2.5 KiB
Svelte

<script lang="ts">
import { page } from '$app/state';
import { goto } from '$app/navigation';
import { user, logout } from '$lib/auth/store.svelte';
import { player } from '$lib/player/store.svelte';
import PlayerBar from './PlayerBar.svelte';
let { children } = $props<{ children: import('svelte').Snippet }>();
let menuOpen = $state(false);
async function handleLogout() {
menuOpen = false;
await logout();
goto('/login', { replaceState: true });
}
function isActive(href: string): boolean {
if (href === '/') return page.url.pathname === '/';
return page.url.pathname.startsWith(href);
}
const navItems = [
{ href: '/', label: 'Library' },
{ href: '/search', label: 'Search' },
{ href: '/playlists', label: 'Playlists' }
];
</script>
<svelte:window onclick={() => (menuOpen = false)} onkeydown={(e) => e.key === 'Escape' && (menuOpen = false)} />
<div class="grid h-screen grid-cols-[auto_1fr] grid-rows-[auto_1fr_auto] bg-background text-text-primary">
<header class="col-span-2 flex items-center justify-between border-b border-border bg-surface px-4 py-3">
<div class="font-semibold">Minstrel</div>
<div class="relative">
<button
type="button"
class="rounded px-3 py-1 hover:bg-surface-hover"
onclick={(e) => { e.stopPropagation(); menuOpen = !menuOpen; }}
>
{user.value?.username ?? ''}
</button>
{#if menuOpen}
<div
class="absolute right-0 mt-1 w-32 rounded border border-border bg-surface shadow"
onclick={(e) => e.stopPropagation()}
onkeydown={(e) => e.stopPropagation()}
role="menu"
tabindex="-1"
>
<button
type="button"
class="block w-full px-3 py-2 text-left hover:bg-surface-hover"
onclick={handleLogout}
>
Log out
</button>
</div>
{/if}
</div>
</header>
<nav class="hidden w-48 border-r border-border bg-surface md:block">
<ul class="p-2">
{#each navItems as item}
<li>
<a
href={item.href}
class="block rounded px-3 py-2 hover:bg-surface-hover"
aria-current={isActive(item.href) ? 'page' : undefined}
>
{item.label}
</a>
</li>
{/each}
</ul>
</nav>
<main class="overflow-y-auto p-4 md:col-start-2">
{@render children?.()}
</main>
{#if player.current}
<div class="col-span-2">
<PlayerBar />
</div>
{/if}
</div>