Make sidebar collapsible with hamburger toggle
Sidebar is now hidden by default, opened via a small hamburger button in the top-left corner. Clicking a nav link or the overlay closes it. Keeps focus on the search bar. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,19 +3,56 @@
|
|||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
|
let sidebarOpen = $state(false);
|
||||||
|
|
||||||
function isActive(path) {
|
function isActive(path) {
|
||||||
const current = $page.url.pathname;
|
const current = $page.url.pathname;
|
||||||
if (path === '/') return current === '/';
|
if (path === '/') return current === '/';
|
||||||
return current.startsWith(path);
|
return current.startsWith(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closeSidebar() {
|
||||||
|
sidebarOpen = false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex h-screen overflow-hidden">
|
<div class="relative h-screen overflow-hidden">
|
||||||
|
<!-- Hamburger toggle -->
|
||||||
|
<button
|
||||||
|
onclick={() => sidebarOpen = !sidebarOpen}
|
||||||
|
class="fixed top-3 left-3 z-50 w-8 h-8 flex items-center justify-center rounded
|
||||||
|
bg-surface-raised/80 backdrop-blur border border-surface-border
|
||||||
|
hover:bg-surface-hover hover:border-surface-border-hover
|
||||||
|
text-text-secondary hover:text-text-primary transition-all duration-150"
|
||||||
|
aria-label="Toggle menu"
|
||||||
|
>
|
||||||
|
{#if sidebarOpen}
|
||||||
|
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
{:else}
|
||||||
|
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5M3.75 17.25h16.5" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Overlay -->
|
||||||
|
{#if sidebarOpen}
|
||||||
|
<button
|
||||||
|
class="fixed inset-0 z-30 bg-black/50 backdrop-blur-sm"
|
||||||
|
onclick={closeSidebar}
|
||||||
|
aria-label="Close menu"
|
||||||
|
></button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<aside class="w-56 flex-shrink-0 bg-surface border-r border-surface-border flex flex-col">
|
<aside class="fixed top-0 left-0 z-40 h-full w-56 bg-surface border-r border-surface-border flex flex-col
|
||||||
|
transform transition-transform duration-200 ease-out
|
||||||
|
{sidebarOpen ? 'translate-x-0' : '-translate-x-full'}">
|
||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<div class="px-4 py-4 border-b border-surface-border">
|
<div class="px-4 py-4 border-b border-surface-border">
|
||||||
<a href="/" class="flex items-center gap-2.5 group">
|
<a href="/" onclick={closeSidebar} class="flex items-center gap-2.5 group">
|
||||||
<div class="w-6 h-6 rounded bg-accent flex items-center justify-center">
|
<div class="w-6 h-6 rounded bg-accent flex items-center justify-center">
|
||||||
<svg class="w-3.5 h-3.5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
<svg class="w-3.5 h-3.5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
|
||||||
@@ -28,14 +65,14 @@
|
|||||||
<!-- Nav -->
|
<!-- Nav -->
|
||||||
<nav class="flex-1 px-2 py-3 space-y-0.5 overflow-y-auto">
|
<nav class="flex-1 px-2 py-3 space-y-0.5 overflow-y-auto">
|
||||||
<span class="block px-2 py-1.5 text-2xs font-medium text-text-tertiary uppercase tracking-wider">Search</span>
|
<span class="block px-2 py-1.5 text-2xs font-medium text-text-tertiary uppercase tracking-wider">Search</span>
|
||||||
<a href="/" class="flex items-center gap-2.5 px-2 py-1.5 rounded text-sm transition-colors duration-100
|
<a href="/" onclick={closeSidebar} class="flex items-center gap-2.5 px-2 py-1.5 rounded text-sm transition-colors duration-100
|
||||||
{isActive('/') && !isActive('/results') && !isActive('/admin') ? 'bg-surface-hover text-text-primary' : 'text-text-secondary hover:text-text-primary hover:bg-surface-hover'}">
|
{isActive('/') && !isActive('/results') && !isActive('/admin') ? 'bg-surface-hover text-text-primary' : 'text-text-secondary hover:text-text-primary hover:bg-surface-hover'}">
|
||||||
<svg class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
<svg class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
|
||||||
</svg>
|
</svg>
|
||||||
Search
|
Search
|
||||||
</a>
|
</a>
|
||||||
<a href="/results?q=" class="flex items-center gap-2.5 px-2 py-1.5 rounded text-sm transition-colors duration-100
|
<a href="/results?q=" onclick={closeSidebar} class="flex items-center gap-2.5 px-2 py-1.5 rounded text-sm transition-colors duration-100
|
||||||
{isActive('/results') ? 'bg-surface-hover text-text-primary' : 'text-text-secondary hover:text-text-primary hover:bg-surface-hover'}">
|
{isActive('/results') ? 'bg-surface-hover text-text-primary' : 'text-text-secondary hover:text-text-primary hover:bg-surface-hover'}">
|
||||||
<svg class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
<svg class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||||
@@ -44,14 +81,14 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<span class="block px-2 pt-4 pb-1.5 text-2xs font-medium text-text-tertiary uppercase tracking-wider">Manage</span>
|
<span class="block px-2 pt-4 pb-1.5 text-2xs font-medium text-text-tertiary uppercase tracking-wider">Manage</span>
|
||||||
<a href="/admin" class="flex items-center gap-2.5 px-2 py-1.5 rounded text-sm transition-colors duration-100
|
<a href="/admin" onclick={closeSidebar} class="flex items-center gap-2.5 px-2 py-1.5 rounded text-sm transition-colors duration-100
|
||||||
{isActive('/admin') && !isActive('/admin/categories') ? 'bg-surface-hover text-text-primary' : 'text-text-secondary hover:text-text-primary hover:bg-surface-hover'}">
|
{isActive('/admin') && !isActive('/admin/categories') ? 'bg-surface-hover text-text-primary' : 'text-text-secondary hover:text-text-primary hover:bg-surface-hover'}">
|
||||||
<svg class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
<svg class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 21v-7.5a.75.75 0 01.75-.75h3a.75.75 0 01.75.75V21m-4.5 0H2.36m11.14 0H18m0 0h3.64m-1.39 0V9.349m-16.5 11.65V9.35m0 0a3.001 3.001 0 003.75-.615A2.993 2.993 0 009.75 9.75c.896 0 1.7-.393 2.25-1.016a2.993 2.993 0 002.25 1.016c.896 0 1.7-.393 2.25-1.016A3.001 3.001 0 0021 9.349m-18 0a2.997 2.997 0 00.177-.728C3.364 7.364 4 6 4.5 4.5h15c.5 1.5 1.136 2.864 1.323 3.621a2.997 2.997 0 00.177.728" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 21v-7.5a.75.75 0 01.75-.75h3a.75.75 0 01.75.75V21m-4.5 0H2.36m11.14 0H18m0 0h3.64m-1.39 0V9.349m-16.5 11.65V9.35m0 0a3.001 3.001 0 003.75-.615A2.993 2.993 0 009.75 9.75c.896 0 1.7-.393 2.25-1.016a2.993 2.993 0 002.25 1.016c.896 0 1.7-.393 2.25-1.016A3.001 3.001 0 0021 9.349m-18 0a2.997 2.997 0 00.177-.728C3.364 7.364 4 6 4.5 4.5h15c.5 1.5 1.136 2.864 1.323 3.621a2.997 2.997 0 00.177.728" />
|
||||||
</svg>
|
</svg>
|
||||||
Stores
|
Stores
|
||||||
</a>
|
</a>
|
||||||
<a href="/admin/categories" class="flex items-center gap-2.5 px-2 py-1.5 rounded text-sm transition-colors duration-100
|
<a href="/admin/categories" onclick={closeSidebar} class="flex items-center gap-2.5 px-2 py-1.5 rounded text-sm transition-colors duration-100
|
||||||
{isActive('/admin/categories') ? 'bg-surface-hover text-text-primary' : 'text-text-secondary hover:text-text-primary hover:bg-surface-hover'}">
|
{isActive('/admin/categories') ? 'bg-surface-hover text-text-primary' : 'text-text-secondary hover:text-text-primary hover:bg-surface-hover'}">
|
||||||
<svg class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
<svg class="w-4 h-4 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z" />
|
||||||
@@ -62,8 +99,8 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- Main content -->
|
<!-- Main content (full width) -->
|
||||||
<main class="flex-1 overflow-y-auto bg-surface">
|
<main class="h-full overflow-y-auto bg-surface">
|
||||||
{@render children()}
|
{@render children()}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user