# Kalenderansicht · Spec #386

Monatliches Kalenderraster auf `/documents` als Alternative zur Listenansicht. Jeder Tag mit Dokumenten zeigt kompakte Eintragszeilen; Hover öffnet eine Vorschaukarte; Klick navigiert zu `/documents/{id}`. Aktive Personen- und Tag-Filter bleiben bei der Monatsnavigation erhalten.

Familienarchiv · 2026-05-03 · Leonie Voss, UX Lead · Issue #386

## 1 · Anatomy

Acht benannte Zonen der Kalenderansicht.

Familienarchiv Dokumente ① Ansichts-Toggle
Dokumente durchsuchen …
② SearchFilterBar (Timeline ausgeblendet)
‹
Oktober 1912
③ Monats-Navigation
›
Mo
Di
Mi
Do
Fr
Sa
So
30
1
Brief — Herbsternte
⑤ Dokumentzeile
2
3
4
5
Postkarte Hamburg
6
④ Tageszelle · ⑥ Überlauf "+N weitere" · ⑦ Hover-Karte (Overlay) · ⑧ Leere Zelle
① Toggle — Rechts in der SearchFilterBar. List | Kalender. Aktive Ansicht: navy-Hintergrund.
② Timeline — Timeline-Widget (#385) wird in Kalender-Mode ausgeblendet. Eine aktive Auswahl wird im State behalten und bei Rückwechsel wiederhergestellt.
③ Monats-Nav — ‹ / › für Prev/Next. Klick auf Monatstitel öffnet Year/Month-Picker. Feld zeigt „Monat Jahr" (deutsch).
④ Tageszelle — Tagesnummer oben rechts. Unter 4 Dokumente: alle als Zeilen. Ab 4: erste 3 + „+N weitere"-Link.
⑤ Dokumentzeile — Einzeilig: Kurzform des Titels. Linker Mint-Balken als Farb-Akzent. Klick → `/documents/{id}`.
⑦ Hover-Karte — Erscheint beim Hovern über eine Dokumentzeile. Zeigt Titel, Datum, Absender → Empfänger, optionalen Thumbnail-Stub. Verschwindet on-mouseout.

## 2 · Design-Tokens

Light theme

cal-surface | #FFFFFF — Kalender-Hintergrund
cal-header-bg | #F5F4EF — DOW-Kopfzeile, Monat-Nav
cal-line | #F0EEE8 — Zellrahmen intern
cal-outer-line | #D8D6CF — Widget-Außenrahmen
doc-entry-bg | #EFF8F7 — Dokumentzeile Hintergrund
doc-entry-accent | #A1DCD8 — Linker Balken der Dokumentzeile (brand-mint)
doc-entry-text | #012851 — Titel in Dokumentzeile (navy)
inactive-day-bg | #FAFAF8 — Zellen des Vor-/Nachmonats
inactive-day-num | #D0CEC8 — Tagesnummer Vor-/Nachmonat

Dark theme

cal-surface | #0A1218
cal-header-bg | #060C12
cal-line | #1A2830
doc-entry-bg | #0A2030
doc-entry-accent | #1E5060 — gedämpftes Teal
doc-entry-text | #A1DCD8 — Mint statt Navy
inactive-day | #070E14

## 3 · Vollständiger Kalender — Oktober 1912 · Light

7 Dokumente verteilt auf den Monat. Zeigt alle Zell-Varianten: leer, 1 Dokument, mehrere Dokumente, und Überlauf.

Desktop · 1440px · ~55% SkalierungLight mode
familienarchiv.local/documents
Dokumente durchsuchen …
Sortierung ▾
▾ Filter
Mo
Di
Mi
Do
Fr
Sa
So
30
1
Brief — Herbsternte
2
3
4
5
Postkarte aus Hamburg
6
7
8
Nachrichten v. Gut Grüße aus Posen
9
10
11
12
Brief — Erbschaftssachen
13
14
15
Antwort a. Elfriedes Brief
16
17
18
19
Reisebericht aus Berlin
Reisebericht aus Berlin
19. Oktober 1912
Von Hans Raddatz
An Elfriede Raddatz
Zum Dokument →
20
21
22
23
Weihnachtspläne 1912
24
25
26
27
28
Grüße z. Namenstag
29
30
31
1
2
3

## 4 · Tageszellen-Varianten

Alle möglichen Zustände einer Tageszelle im Detail.

Variant ALeere Zelle
14
Nur Tagesnummer. Kein Cursor-Pointer. Kein Hover-Effekt.
Variant B1 Dokument
1
Brief über die Herbsternte
Titel wird auf eine Zeile begrenzt. Klick → `/documents/{id}`.
Variant C3 Dokumente
8
Nachrichten v. Gut
Grüße aus Posen
Brief a. Elfriede
Bis zu 3 Einträge vollständig sichtbar.
Variant D5 Dokumente — Überlauf
15
Antwort a. Elfriedes Brief
Feldpost Nr. 12
Kurzbrief Sonntag
+2 weitere
Ab 4 Docs: erste 3 anzeigen, Rest als „+N weitere". Klick auf Link → Tages-Ansicht oder Modal (OQ-4, Entscheidung: Modal).
Variant EVor-/Nachmonat
30
Gedimmte Tagesnummer. Kein Dokument-Eintrag (Dokumente des Vormonats erscheinen nicht im aktuellen Raster). Kein klickbarer Inhalt.

## 5 · Dark Mode — Kalender Oktober 1912

DarkKalender · aktiver Monat
Dokumente durchsuchen …
▾ Filter
Mo
Di
Mi
Do
Fr
Sa
So
30
1
Brief — Herbsternte
2
3
4
5
Postkarte Hamburg
6
7
8
Nachrichten v. GutGrüße aus Posen
9
10
11
12
Brief — Erbschaft
13
14
15
Antwort a. Elfriede
16
17
18
19
Reisebericht Berlin
20
Dark mode: Dokumentzeilen Mint-Text auf sehr dunklem Hintergrund. Balken-Akzent gedämpftes Teal. Monatstitel Mint.

## 6 · Filter-Integration

Aktive Personen- und Tag-Filter aus der SearchFilterBar bleiben bei Kalender-Navigation erhalten.

Filter aktivNur Briefe von Karl Raddatz
Dokumente durchsuchen …
KR
Karl Raddatz ×
Mo
Di
Mi
Do
Fr
Sa
So
30
1
Brief — Herbsternte
2
3
4
5
6
7
8
Nachrichten v. Gut
9
10
11
12
13
14
15
Antwort a. Elfriedes Brief
16
17
18
19
20
Person-Filter „Karl Raddatz" ist aktiv. Monat-Nav zeigt „3 von 7 Dokumente sichtbar (Filter aktiv)". Tage ohne Karl-Dokumente sind leer, auch wenn der Originalmonat dort Briefe anderer Personen hat.

## 7 · Verhaltensregeln

Szenario | Verhalten
--- | ---
Ansichts-Toggle | Klick auf Kalender-Icon → URL wechselt zu `?view=calendar`. Listenansicht und Timeline werden per `display:none` ausgeblendet. State (Filter, Auswahl) bleibt erhalten.
Startmonat (OQ-3) | Entscheidung: Monat des aktuellsten Dokuments. Wenn Timeline-Filter aktiv ist, zeigt Kalender den ersten Monat des Filterbereichs. Ohne Filter: Monat des neuesten Dokuments im Archiv.
Monats-Navigation Prev/Next | Button ‹ / › lädt Dokumente des Nachbarmonats via `GET /api/documents?year=1912&month=11`. Vorherige und nachfolgende Monate werden prefetched (SvelteKit prefetch).
Year/Month-Picker | Klick auf Monatstitel öffnet ein kompaktes Dropdown mit Jahres-Liste (scrollen) und Monatsgitter (12 Felder). Bestätigung mit Enter oder Klick auf Monat.
Dokumentzeilen-Hover | Hover-Karte erscheint nach 400 ms Verzögerung neben der Zelle (kein sofortiges Aufpoppen). Karte verschwindet wenn Maus die Zelle verlässt. Kein Hover auf Touch-Geräten.
Klick auf Dokumentzeile | Navigation zu `/documents/{id}`.
Überlauf-Link „+N weitere" (OQ-4) | Entscheidung: Modal mit vollständiger Liste der Dokumente des Tages. Kein In-Cell-Scroll. Modal zeigt Datum als Titel + alle Dokumente als DocumentRow.
Kein documentDate | Dokument erscheint nicht im Kalender. Timeline-Widget und Listenansicht zeigen es weiterhin.
Monat ohne Dokumente | Leeres Raster (alle Zellen ohne Einträge). Monat-Nav zeigt „0 Dokumente in diesem Monat".
Aktive Filter + Kalender | AND-Semantik. Nur Dokumente, die alle aktiven Filter (Person, Tag, Zeitachse) erfüllen, erscheinen im Kalender.
Mobile (<640 px) | Kalenderansicht wechselt zu Wochen-View (1 Woche sichtbar, horizontal scrollbar). Toggle zwischen List/Kalender bleibt verfügbar.
Keyboard-Navigation | Tab auf Monatsnavigation: ‹ / › per Enter/Space. Pfeiltasten bewegen Fokus von Zelle zu Zelle. Enter auf Dokumentzeile: Navigation zu Dokument.
ARIA | `role="grid"` auf Kalender-Container. `role="gridcell"` auf jede Tageszelle. `aria-label="15. Oktober 1912, 3 Dokumente"` auf belegte Zellen. `aria-label="Vorheriger Monat"` auf ‹-Button.

## 8 · Offene Fragen — Entscheidungen

OQ-3: Welcher Monat wird zuerst angezeigt? Monat des aktuellsten Dokuments (nach `documentDate`). Begründung: Neue Uploads werden zuerst erschlossen. Wenn ein Zeitachsen-Filter aktiv ist, zeigt der Kalender den ersten Monat des Filterbereichs.
OQ-4: Zell-Überlauf bei 4+ Dokumenten. Erste 3 sichtbar + „+N weitere"-Link → öffnet Modal. Kein In-Cell-Scroll (schlechte Touch-Zugänglichkeit). Das Modal zeigt den Tagestitel als Heading + eine vollständige DocumentRow-Liste.
Backend-Anforderung. Neuer Endpoint `GET /api/documents?year=1912&month=10` ohne Paginierung — gibt alle Dokumente des Monats zurück (max. ~100, keine Offset-Pages). Alternativ: bestehender Endpoint mit `dateFrom=1912-10-01&dateTo=1912-10-31`. Der View-Toggle-State wird als URL-Parameter `?view=calendar` gespeichert und von SvelteKit per `url.searchParams` gelesen.

## 9 · Implementation Reference

Element | Tailwind-Klassen | Pixelwert | Anmerkung
--- | --- | --- | ---
Ansichts-Toggle Container | `flex border border-line rounded-sm overflow-hidden` | — | Sitzt ganz rechts in der SearchFilterBar-Zeile
Toggle-Button (inaktiv) | `p-1.5 bg-muted flex items-center justify-center` | 6px padding | Icon: 16px × 16px SVG
Toggle-Button (aktiv) | `p-1.5 bg-primary flex items-center justify-center` | 6px padding | Icon fill: `#A1DCD8`
Monat-Nav Container | `bg-surface border border-line rounded-t-sm flex items-center justify-between px-4 py-2.5` | padding 16px / 10px | Oberer Radius; Kalender-Grid hat unteren Radius
Prev/Next Button | `w-8 h-8 flex items-center justify-center border border-line rounded-sm bg-muted text-ink-2 hover:bg-line transition-colors` | 32px / 32px | Touch target ≥ 44px durch unsichtbares Padding auf Wrapper
Monatstitel | `text-sm font-bold text-primary cursor-pointer hover:underline` | 14px / 700 | Klick → Year/Month-Picker Dropdown
Monat-Subtext | `text-[10px] text-ink-3 text-center mt-0.5` | 10px | Orange + fett wenn Filter aktiv: `text-orange-600 font-bold`
DOW-Kopfzeile | `grid grid-cols-7 bg-muted border-b border-line` | — | —
DOW-Zelle | `py-1.5 text-center text-[9px] font-bold uppercase tracking-widest text-ink-3` | 9px / 700 | Kein Klick-Handler
Kalender-Grid | `bg-surface border border-line border-t-0 rounded-b-sm` + `role="grid"` | — | Border-top entfernt wegen Monat-Nav-Header
Wochen-Reihe | `grid grid-cols-7` | — | —
Tageszelle (aktiver Monat) | `border-r border-b border-line min-h-[80px] p-1.5 relative` | min 80px hoch | `role="gridcell"` + `aria-label`
Tageszelle (Vor/Nachmonat) | `border-r border-b border-line min-h-[80px] p-1.5 bg-muted/40` | — | Kein Dokument-Inhalt
Tagesnummer (aktiv) | `text-right text-[11px] font-bold text-ink mb-1 leading-none` | 11px / 700 | —
Tagesnummer (inaktiv) | `text-right text-[11px] font-bold text-ink-3/40 mb-1 leading-none` | 11px | Stark gedimmt
Dokumentzeile | `block text-[10px] text-primary truncate px-1.5 py-0.5 bg-[#EFF8F7] border-l-2 border-mint rounded-[2px] mb-0.5 cursor-pointer hover:bg-mint/20 transition-colors` | 10px | `role="link"` + `aria-label` mit Volltitel
Überlauf-Link | `text-[9px] text-ink-3 italic px-1.5 py-0.5 hover:underline cursor-pointer` | 9px | Öffnet Modal via `onclick`
Hover-Karte | `absolute z-50 bg-surface border border-line rounded-sm shadow-lg p-3 min-w-[180px] pointer-events-none` | — | Positioniert per JS (verhindert Viewport-Overflow). `pointer-events-none` damit sie Hover nicht blockiert.
Hover-Karte Titel | `text-[11px] font-bold text-ink mb-1 leading-snug` | 11px / 700 | Mehrzeilig erlaubt
Hover-Karte Datum | `text-[9px] text-ink-3 mb-2` | 9px | Format: „19. Oktober 1912"
Hover-Karte Von/An | `text-[9px] text-ink-2` mit `font-bold uppercase tracking-wide` auf Label | 9px | —
Komponenten-Namen | `CalendarView.svelte`, `CalendarMonthGrid.svelte`, `CalendarDayCell.svelte`, `CalendarDocEntry.svelte`, `CalendarHoverCard.svelte`, `MonthPicker.svelte` | — | Alle unter `src/lib/components/calendar/`
Benötigter URL-Parameter | `?view=calendar&year=1912&month=10` | — | SvelteKit `url.searchParams` in `+page.server.ts`