Files
familienarchiv/frontend/src/routes/+layout.svelte
Marcel 12b8324245
Some checks failed
CI / E2E Tests (pull_request) Failing after 1h51m28s
CI / Unit & Component Tests (pull_request) Failing after 1m30s
CI / Backend Unit Tests (pull_request) Failing after 2m23s
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
chore: merge main into feat/issue-166 — resolve blue header conflicts
- +layout.svelte: adopt main's blue header structure (accent stripe, no
  border-b, bg-header instead of bg-brand-navy)
- layout.css light mode: drop --c-nav-active (removed by main); set
  --c-header: #012851 (confirmed correct now that header is brand-navy)
- layout.css dark mode: drop --c-nav-active; keep navy PDF tokens and
  --c-header: #012851 from our branch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 12:24:20 +02:00

74 lines
2.1 KiB
Svelte

<script lang="ts">
import './layout.css';
import { page } from '$app/state';
import { onMount } from 'svelte';
import LanguageSwitcher from '$lib/components/LanguageSwitcher.svelte';
import ThemeToggle from '$lib/components/ThemeToggle.svelte';
import NotificationBell from '$lib/components/NotificationBell.svelte';
import AppNav from './AppNav.svelte';
import UserMenu from './UserMenu.svelte';
let { children, data } = $props();
const isAdmin = $derived(
data?.user?.groups?.some((g: { permissions: string[] }) => g.permissions.includes('ADMIN'))
);
// Set after client-side hydration completes. Used by E2E tests to know the
// page is interactive (event handlers registered) before they interact with it.
let hydrated = $state(false);
onMount(() => {
hydrated = true;
});
const isAuthPage = $derived(
['/login', '/forgot-password', '/reset-password'].some((p) => page.url.pathname.startsWith(p))
);
const userInitials = $derived.by(() => {
const first = data?.user?.firstName?.[0];
const last = data?.user?.lastName?.[0];
if (first && last) return (first + last).toUpperCase();
return null;
});
</script>
<div class="min-h-screen bg-canvas" data-hydrated={hydrated || undefined}>
{#if !isAuthPage}
<header class="sticky top-0 z-50 bg-header">
<div class="h-1 bg-accent"></div>
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex h-16 justify-between">
<!-- Logo & Nav -->
<AppNav isAdmin={isAdmin} />
<!-- Right Side -->
<div class="flex items-center gap-3">
<!-- Language selector (desktop only — mobile lives in nav drawer) -->
<div
class="hidden items-center gap-1 pr-3 lg:flex [&_button]:px-1.5 [&_button]:py-1 [&_button]:text-xs"
>
<LanguageSwitcher inverted />
</div>
<!-- Theme toggle -->
<ThemeToggle />
<!-- Notification bell (authenticated users only) -->
{#if data?.user}
<NotificationBell />
{/if}
<!-- User menu -->
<UserMenu userInitials={userInitials} />
</div>
</div>
</div>
</header>
{/if}
<main class={isAuthPage ? '' : 'py-6'}>
{@render children()}
</main>
</div>