feat(web): top-bar centered nav + Library tab page (replace sidebar)
test-web / test (push) Successful in 32s
test-web / test (push) Successful in 32s
Operator 2026-06-01: "navigation layout and library sections are
what I'd like to have implemented as it seems better than our
current navbar solution. I think I'd like to have these nav options
moved into the top bar centered."
Top-bar restructure:
- Centered nav (replaces the 192dp left sidebar): Home / Library /
Discover, with icons + labels. Labels collapse below sm breakpoint
so the bar stays icon-only on small viewports.
- Right side (search input + user dropdown) unchanged.
- Hamburger button + MobileNavDrawer + the mobileNav store all
removed - the centered nav lives at all viewport sizes.
Library page restructure (mirrors Android LibraryScreen):
- New routes/library/+layout.svelte renders a tab bar across the
five Library sub-pages: Artists / Albums / Liked / History /
Playlists. Active tab gets an accent underline + onSurface text.
- routes/library/+page.server.ts redirects bare /library to
/library/artists (Android default tab).
- /playlists (list) moved to /library/playlists; old URL gets a 308
redirect (routes/playlists/+page.server.ts) so existing bookmarks
land on the new location. /playlists/[id] (detail) is unchanged -
matches the server API URL shape.
Deleted: Shell's sidebar markup, MobileNavDrawer.{svelte,test.ts},
the mobileNav store, the old routes/playlists/+page.svelte. Shell
test rewritten to assert the new 3-item centered nav; playlists
test moved next to its new +page.svelte and its test-utils import
path updated.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
|
||||
let { children } = $props<{ children: import('svelte').Snippet }>();
|
||||
|
||||
// Tab bar for the Library section. Mirrors Android's LibraryScreen
|
||||
// (artists / albums / liked / history / playlists) — Playlists lives
|
||||
// here so the operator can find their personal collection in one
|
||||
// place rather than tracking a separate top-level route.
|
||||
const tabs = [
|
||||
{ href: '/library/artists', label: 'Artists' },
|
||||
{ href: '/library/albums', label: 'Albums' },
|
||||
{ href: '/library/liked', label: 'Liked' },
|
||||
{ href: '/library/history', label: 'History' },
|
||||
{ href: '/library/playlists', label: 'Playlists' }
|
||||
];
|
||||
|
||||
function isActiveTab(href: string): boolean {
|
||||
return page.url.pathname === href || page.url.pathname.startsWith(href + '/');
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="space-y-4">
|
||||
<nav aria-label="Library sections" class="border-b border-border">
|
||||
<ul class="flex gap-1 overflow-x-auto">
|
||||
{#each tabs as tab}
|
||||
{@const active = isActiveTab(tab.href)}
|
||||
<li>
|
||||
<a
|
||||
href={tab.href}
|
||||
class="block px-3 md:px-4 py-3 text-sm whitespace-nowrap border-b-2
|
||||
{active
|
||||
? 'border-accent text-text-primary'
|
||||
: 'border-transparent text-text-secondary hover:text-text-primary'}"
|
||||
aria-current={active ? 'page' : undefined}
|
||||
>
|
||||
{tab.label}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{@render children?.()}
|
||||
</div>
|
||||
Reference in New Issue
Block a user