ccef9be2d3
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.
89 lines
2.5 KiB
Svelte
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>
|