Files
annu-kute-ced/src/routes/[[locale=locale]]/+layout.svelte
T

176 lines
3.4 KiB
Svelte
Raw Normal View History

<script lang="ts">
import '$lib/styles/oki-tokens.css';
import '$lib/styles/base.css';
import { onNavigate } from '$app/navigation';
import Footer from '$lib/components/Footer.svelte';
import Nav from '$lib/components/Nav.svelte';
import Sidebar from '$lib/components/Sidebar.svelte';
import ScrollProgressBar from '$lib/components/motion/ScrollProgressBar.svelte';
import { prefersReducedMotion } from '$lib/motion/tokens';
import type { LayoutProps } from './$types';
let { data, children }: LayoutProps = $props();
let menuOpen = $state(false);
onNavigate((navigation) => {
if (prefersReducedMotion()) return;
if (!('startViewTransition' in document)) return;
return new Promise((resolve) => {
document.startViewTransition(async () => {
resolve();
await navigation.complete;
});
});
});
</script>
<svelte:head>
<meta name="generator" content="SvelteKit" />
</svelte:head>
<a href="#main-content" class="skip-link">{data.t.nav.skipToContent}</a>
<ScrollProgressBar label={data.t.a11y.progressLabel} />
<Nav
locale={data.locale}
t={data.t}
{menuOpen}
onToggleMenu={() => (menuOpen = !menuOpen)}
/>
<div class="shell">
<aside class="sidebar">
<Sidebar locale={data.locale} t={data.t} />
</aside>
{#if menuOpen}
<div class="drawer-backdrop" onclick={() => (menuOpen = false)} aria-hidden="true"></div>
{/if}
<aside
id="mobile-menu"
class="drawer"
class:open={menuOpen}
aria-label={data.t.nav.mainLabel}
inert={!menuOpen}
>
<Sidebar locale={data.locale} t={data.t} onNavigate={() => (menuOpen = false)} />
</aside>
<div class="content">
<main id="main-content" class="main-content">
{@render children()}
</main>
<Footer locale={data.locale} t={data.t} />
</div>
</div>
<style>
.shell {
display: grid;
grid-template-columns: var(--sidebar-w) 1fr;
flex: 1;
min-height: 0;
}
.sidebar {
border-right: 1px solid var(--line);
background: var(--surface);
overflow-y: auto;
position: sticky;
top: calc(var(--header-h) + 6px);
height: calc(100dvh - var(--header-h) - 6px);
}
.content {
min-width: 0;
display: flex;
flex-direction: column;
}
.main-content {
flex: 1;
padding: var(--space-3);
display: flex;
flex-direction: column;
gap: var(--space-4);
}
.drawer {
display: none;
}
@media (max-width: 900px) {
.shell {
grid-template-columns: 1fr;
}
.sidebar {
display: none;
}
.drawer {
display: block;
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: min(300px, 85vw);
z-index: 280;
background: var(--surface);
border-right: 1px solid var(--line);
overflow-y: auto;
transform: translateX(-100%);
transition: transform var(--dur-mesure) var(--ease-ka);
}
.drawer.open {
transform: translateX(0);
}
.drawer-backdrop {
position: fixed;
inset: 0;
z-index: 270;
background: rgba(13, 13, 13, 0.6);
}
}
@media (prefers-reduced-motion: reduce) {
.drawer {
transition: none;
}
}
@view-transition {
navigation: auto;
}
@keyframes vt-fade-in {
from {
opacity: 0;
}
}
@keyframes vt-fade-out {
to {
opacity: 0;
}
}
::view-transition-old(root) {
animation: vt-fade-out var(--dur-mesure) var(--ease-ka) both;
}
::view-transition-new(root) {
animation: vt-fade-in var(--dur-mesure) var(--ease-ka) both;
}
@media (prefers-reduced-motion: reduce) {
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
}
}
</style>