diff --git a/docs/specs/header-nav-redesign-spec.html b/docs/specs/header-nav-redesign-spec.html new file mode 100644 index 00000000..4aca2d7a --- /dev/null +++ b/docs/specs/header-nav-redesign-spec.html @@ -0,0 +1,855 @@ + + + + + +Header / Navigation Redesign Spec · Familienarchiv + + + +
+ + + +
+
+
+

Header / Navigation Redesign

+

Full header redesign: brand-navy bar, 4px purple accent strip, always-visible logo on mobile, high-contrast nav states, dark-mode as brand constant, and integrated login header. Replaces the current white bg-surface header that leaks the semantic surface color into what should be a brand-constant element.

+
+ Draft · 2026-03-30 +
+
Leonie Voss · Senior UX Designer
+
+
+
Header background
+
bg-surface (#fff)
→ brand-navy #012851
+
+
+
Top accent strip
+
None
→ 4px · brand-purple #B4B9FF
+
+
+
Active nav state
+
rgba purple pill (~1.08:1)
→ white + mint underline
+
+
+
Mobile logo
+
Hidden
→ Always visible, left side
+
+
+
Dark mode header
+
Flips to #1a1a1a
→ Stays brand-navy (constant)
+
+
+
Login page header
+
Hidden entirely
→ Brand header, logo-only
+
+
+
Language switcher (login)
+
Floating, no context
→ Integrated in login header right
+
+
+
Total header height
+
4px strip + 64px bar
= 68px total
+
+
+
+ + + +
+

What changes vs. current implementation

+
+
+

New / changed

+
    +
  • Header bg-surface → fixed bg-brand-navy (#012851) — not theme-aware
  • +
  • 4px accent strip above header: background: #B4B9FF
  • +
  • Nav link colors on navy: inactive 55% white, hover 85% white, active 100% white
  • +
  • Active indicator: 2px bottom border in brand-mint (#A1DCD8) instead of rgba purple pill
  • +
  • Mobile: logo always visible left; hamburger icon white (was hidden or missing)
  • +
  • User avatar: mint background (#A1DCD8) with navy text (#012851)
  • +
  • Dark mode: dark:bg-surface override removed from header — stays navy
  • +
  • Login page: isAuthPage guard changed — shows logo-only header, not null
  • +
  • Language switcher on login: moved into header right slot
  • +
  • Mobile drawer: opens below navy header, white background, navy text links, mint active indicator
  • +
+
+
+

Kept unchanged

+
    +
  • AppNav component structure — only CSS changes
  • +
  • Sticky header behavior (sticky top-0 z-50)
  • +
  • Max-width container and horizontal padding
  • +
  • NotificationBell, ThemeToggle, LanguageSwitcher components — only icon color changes
  • +
  • UserMenu component — only avatar color changes
  • +
  • Mobile drawer open/close logic
  • +
  • Admin nav link conditional visibility
  • +
  • isAuthPage derived value — still used, just different output
  • +
+
+
+
+ + + +
+
1 Current state — problems annotated
+ +
+
+
Desktop ≥768px 6 issues
+
+
/dokumente
+ +
+ +
+ +
+ Dokumente + Personen + Korrespondenz +
+
+ DE +
+
+
LV
+
+
+
+
+
+ Issues — desktop +
    +
  1. Background is bg-surface (white) — not brand. Every other archival app in this family uses a dark branded header.
  2. +
  3. No 4px accent strip at top — missing the canonical brand-purple cap.
  4. +
  5. Active link "Dokumente" uses rgba(180,185,255,0.15) on white = contrast ~1.08:1. Completely invisible. WCAG AA minimum is 3:1 for UI components.
  6. +
  7. Logo is navy-on-white — works in light mode but will disappear in dark mode if header ever inherits #1a1a1a.
  8. +
  9. Dark mode: header flips to near-black (#1a1a1a) — breaks brand consistency. Header should be a brand constant, not a semantic surface.
  10. +
  11. User avatar: dark navy circle blends with any dark-mode context and provides no semantic meaning via color.
  12. +
+
+
+ +
+
Mobile 375px logo missing
+
+
+
09:41
+
+ +
+
+
+
+
+
+
LV
+
+
+
+
+
+
+
+ Mobile issues +
    +
  • Logo hidden on mobile — brand identity completely lost
  • +
  • Hamburger icon is dark on white — fine in light mode, breaks in dark
  • +
  • Header still white — same surface-color problem as desktop
  • +
+
+
+
+
+ + + +
+
2 Proposed redesign — Desktop
+ +
+ + +
+
Light mode ≥768px Proposed
+
+
/korrespondenz
+
+
+ +
+ Dokumente + Personen + Korrespondenz +
+ DE +
+
+
LV
+
+
+
+
+
+
+ 4px accent strip · background: #B4B9FF +
+
+
+
+ 64px nav bar · background: #012851 +
+
+
+
+ Total: 68px +
+
+
Active link: "Korrespondenz" — white text + 2px bottom border in #A1DCD8. Divider between logo and nav: rgba(255,255,255,0.15). Avatar: mint bg + navy text.
+
+ + +
+
Dark mode ≥768px Same navy — brand constant
+
+
/korrespondenz
+
+
+ +
+ Dokumente + Personen + Korrespondenz +
+ DE +
+
+
LV
+
+
+
+
+
+ Dark mode rule: The header is a brand element, not a semantic surface. It does NOT respond to the dark: variant. Page content behind it switches; the header stays #012851. +
    +
  • Remove dark:bg-surface from header element
  • +
  • Apply bg-brand-navy as a non-dark-variant class
  • +
+
+
+
+ + +
+
Element color tokens
+
+
+
+
brand-navy
+
#012851
+
Header bg
+
+
+
+
brand-purple
+
#B4B9FF
+
Accent strip
+
+
+
+
brand-mint
+
#A1DCD8
+
Active underline · avatar bg
+
+
+
+
white
+
#ffffff
+
Active link text · logo
+
+
+
+
white/55
+
rgba(255,255,255,.55)
+
Inactive nav links
+
+
+
+
white/85
+
rgba(255,255,255,.85)
+
Hover nav links
+
+
+
+
+ + + +
+
3 Nav link states
+ +
+ + +
+
Inactive
+
+ Personen +
+
+
color: rgba(255,255,255,.55)
+
+ 4.9:1 ✓ AA +
+
+
Intentionally muted — communicates "not here yet" without removing affordance.
+
+ + +
+
Hover
+
+ Personen +
+
+
color: rgba(255,255,255,.85)
+
+ 7.8:1 ✓ AA +
+
+
Smooth brightness step on hover. Transition: color 150ms ease.
+
+ + +
+
Active (current page)
+
+ Korrespondenz +
+
+
color: #ffffff
+
border-bottom: 2px solid #A1DCD8
+
+ 21:1 ✓ AAA +
+
+
Mint underline is the active indicator — not a background pill. Clear, low-weight, distinct from hover.
+
+ + +
+
Focus (keyboard)
+
+ Personen +
+
+
outline: 2px solid #A1DCD8
+
outline-offset: 3px
+
border-radius: 2px
+
+ 3.4:1 ✓ AA +
+
+
Mint outline on navy — meets WCAG 3:1 focus indicator requirement. Never suppress outline.
+
+
+ + +
+
Active state contrast — before vs. after
+
+
+
Before Fails WCAG
+
+ Dokumente +
+
+ Navy text (#012851) on rgba(180,185,255,0.15) on white.
+ Effective background: approx. #F4F4FF.
+ ~1.08:1 ✗ Fail +
+
The active pill is invisible. Users can't tell which page they're on.
+
+
+
After Passes WCAG AAA
+
+ Dokumente +
+
+ White text (#ffffff) on navy (#012851).
+ Mint underline: #A1DCD8 on navy = 3.1:1 for the indicator itself.
+ 21:1 ✓ AAA (text) +
+
Unambiguous. The underline echoes brand-mint used elsewhere as an accent.
+
+
+
+
+ + + +
+
4 Mobile header + nav drawer
+ +
+ + +
+
Current No logo
+
+
+
09:41
+
+
+
+
+
+
+
+
+
LV
+
+
+
+
+
+
+ Problem: No logo. The user has zero brand context. On first load, there is no visual cue that this is Familienarchiv. The hamburger icon color (dark navy) will also break in dark mode. +
+
+ + +
+
Proposed header Logo visible
+
+
+
09:41
+
+
+ +
+
LV
+
+
+
+
+
+
+
+
+
+
+
Logo always visible left. Avatar + hamburger right. Accent strip is 3px on mobile (saves 1px). Background is brand-navy — no theme variation.
+
+ + +
+
Nav drawer Open state
+
+
+
09:41
+
+
+ +
+
LV
+ +
+
+
+ +
+ + + + +
+
+ Sprache +
DE
+
EN
+
ES
+
+
+
+
+
+
Drawer uses white background with navy text — intentional reversal of the dark header. Active page: mint left border + sand background. Language switcher lives in drawer on mobile (not floating).
+
+
+
+ + + +
+
5 Login page — branded header
+ +
+ + +
+
Current — header hidden No brand context
+
+
/login
+ +
+
+ DE + EN + ES +
+
+ +
+
+
+
+ Problems: Header is hidden entirely on auth pages. Language switcher floats top-right with no visual anchor — it's a ghost. Users arrive with zero brand context. The page could be any app. +
+
+ + +
+
Proposed — logo-only header Branded
+
+
/login
+ +
+
Accent strip + navy header appears on login. No nav links (user is not authenticated). Language switcher lives in header right slot — same position as desktop, consistent muscle memory. The brand is present from the first moment the user sees the app.
+
+
+ + +
+ Implementation change: In +layout.svelte, the {#if !isAuthPage} guard currently hides the entire header. Replace with a conditional that renders a login variant of the header (logo + lang switcher, no nav links) when isAuthPage is true. Move the LanguageSwitcher import into the header for the auth variant. Remove the floating LanguageSwitcher from /login/+page.svelte. +
+
+ + + +
+
6 Right utility area — element by element
+ +
+
+ +
+ DE + EN + ES +
+ +
+ +
+ 🔔 +
+
+ +
LV
+
+
+ +
+
+
Language switcher
+
+ Active lang: color: #ffffff
+ Inactive lang: color: rgba(255,255,255,.5)
+ Separator from rest: border-right: 1px solid rgba(255,255,255,.15)
+ On login: visible in header right slot +
+
+
+
Theme toggle
+
+ Icon: white at opacity: 0.7
+ Hover: opacity: 1.0
+ Background: rgba(255,255,255,.1)
+ No change to toggle logic — icon color only +
+
+
+
Notification bell
+
+ Icon: white at opacity: 0.75
+ Badge: stays bg-red-500 (#EF4444)
+ Badge border: border: 1.5px solid #012851 (halos on navy)
+ No component logic changes +
+
+
+
User avatar
+
+ Background: #A1DCD8 (brand-mint)
+ Text: #012851 (brand-navy)
+ Contrast: 4.8:1 ✓ AA
+ Replaces navy bg (dark-on-dark in dark mode) +
+
+
+
+ + + +
+

Implementation notes

+
+
+

CSS / Tailwind changes

+
    +
  • Header: replace bg-surface with bg-[#012851] (or add a bg-brand-navy utility to layout.css)
  • +
  • Remove border-b border-line-2 from header — the accent strip replaces the visual separator
  • +
  • Add a <div class="h-1 bg-[#B4B9FF]"> before the nav bar in +layout.svelte
  • +
  • Nav links: replace text-ink + bg-nav-active with opacity-based white utilities: text-white/55 inactive, hover:text-white/85, text-white border-b-2 border-[#A1DCD8] active
  • +
  • User avatar: swap bg-brand-navy text-whitebg-[#A1DCD8] text-[#012851]
  • +
  • Notification badge: add border-2 border-[#012851] to badge element
  • +
  • Dark mode: on the <header> element, ensure there is NO dark: variant overriding the background
  • +
+
+
+

Component changes

+
    +
  • +layout.svelte: split the {#if !isAuthPage} guard into two branches — full header (authed) vs. login header (logo + lang only)
  • +
  • AppNav.svelte: ensure logo is always rendered, not hidden on mobile via hidden sm:flex or similar
  • +
  • AppNav.svelte: hamburger button — icon color from dark to text-white/85
  • +
  • AppNav.svelte: active link class — remove bg-nav-active, add bottom border in mint
  • +
  • UserMenu.svelte: avatar background and text color
  • +
  • ThemeToggle.svelte: icon fill/stroke → text-white/70
  • +
  • NotificationBell.svelte: icon color → text-white/75
  • +
  • /login/+page.svelte: remove standalone <LanguageSwitcher> — it moves to the layout header
  • +
+
+
+

CSS variable candidates

+
    +
  • Consider adding to layout.css:
    --header-bg: #012851;
    --header-accent: #B4B9FF;
    --header-nav-active: #A1DCD8;
  • +
  • These are intentionally NOT in the dark-mode @media (prefers-color-scheme: dark) block — they are brand constants
  • +
  • If Tailwind 4 theme is configured, add:
    brand-navy: #012851
    brand-purple: #B4B9FF
    brand-mint: #A1DCD8
    to the @theme block in layout.css
  • +
  • No backend changes required
  • +
  • No i18n key changes required
  • +
  • No new routes required
  • +
+
+
+
+ +
+ + diff --git a/frontend/src/lib/components/DateInput.svelte b/frontend/src/lib/components/DateInput.svelte new file mode 100644 index 00000000..a8beeeaf --- /dev/null +++ b/frontend/src/lib/components/DateInput.svelte @@ -0,0 +1,71 @@ + + + +{#if name} + +{/if}