Platform backbone (plan 2026-10-13-plattform-rueckgrat), all tasks reviewed: - webhooks with delivery table, retries and stable delivery id - calendar handlers; a finished task removes its Outlook event - tasks, automations, inspections, varroa, treatments, feedings, harvests, colonies, wintering, stock and bottling record domain events in the same transaction; legacy post-commit calls removed - row locks through one helper (lockRowForUpdate, lockRowsForShare, lockRowsForUpdate) - job framework with JobRun, cli exit codes, cleanup, task templates, daily evaluation, hourly app-backup and the rekey job - system API and page "Verwaltung > System" with retry - @nestjs/schedule removed, guard tests against in-process schedulers Field capture T3 (plan 2026-10-13-t3-erfassung-am-stand), all tasks reviewed: - inspection photo offline without metadata - bulk capture for treatments, feedings and varroa (backend + frontend) - offline stand mode with service worker, offline pages and packs - offline session, cold start and logout on shared devices Docs: ARCHITECTURE.md assumptions and sections updated, TASKS.md. Gates: backend lint, typecheck, 1770 unit, 420 e2e, build, no schema drift; frontend lint, typecheck, 913 tests, build. Not rolled out. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
1167 lines
86 KiB
Markdown
1167 lines
86 KiB
Markdown
# T5 Optik mit eigener Handschrift — Design
|
||
|
||
Stand: 2026-10-14 · Betrifft: ApiCore-Frontend (plus ein kleiner Zusatz am Backend-Endpunkt `GET /autopilot/today`) · Teilprojekt T5 aus `docs/superpowers/specs/2026-10-12-plattform-rueckgrat-und-fahrplan-design.md` §10
|
||
|
||
## 1. Ziel
|
||
|
||
ApiCore soll man draußen am Stand lesen können: in der Mittagssonne, mit Handschuhen, mit einer Hand. Und man soll es auf den ersten Blick als Imker-App erkennen, nicht als Verwaltungsvorlage.
|
||
|
||
- Jeder Text und jedes Bedienelement erfüllt WCAG 2.2 AA. Die wichtigen Stellen liegen deutlich darüber, damit noch genug Kontrast übrig bleibt, wenn die Sonne auf dem Display spiegelt.
|
||
- Es gibt hell, dunkel und einen Kontrastmodus „Sonne“. Der Wechsel geht mit einem Tipp und flackert nicht.
|
||
- Ein Motiv trägt die Handschrift: **die Wabenzelle**. Sie zeigt den Zustand der Völker (Waben-Standkarte, Kartenmarker), sitzt am Zeiger des Bienenjahr-Rads, rahmt die Bereichs-Icons und bildet das Markenzeichen. Verläufe, Glas-Effekte und Zierbewegung fallen weg.
|
||
- Der Baukasten wird durchgesetzt. Jede Auswahlgruppe, jede Checkbox, jede Tab-Leiste und jedes Plus/Minus-Feld kommt aus genau einem Baustein, mit einem gemeinsamen Fokusstil.
|
||
|
||
Technisch heißt das:
|
||
|
||
- Farben stehen nur noch als Tokens in `globals.css`. Es gibt vier geprüfte Sätze: hell, dunkel, Sonne hell, Sonne dunkel. Ein Wächter-Test misst jedes Paar aus Abschnitt 4.4. Ein Token, das einem Satz fehlt, lässt den Test scheitern.
|
||
- Neue Grafiken sind handgeschriebenes SVG, wie heute das Varroa-Diagramm. Keine neue Laufzeit-Bibliothek. `next-themes` fliegt raus.
|
||
- Wo T4-Daten (Saison, nächste Schritte, Varroa-Bänder) schon da sind, zeigen Rad und Lebenslinie sie an. Fehlen sie, greift ein Kalender-Rückfall. Die Oberfläche funktioniert vor T4 und bricht nach T4 nicht.
|
||
|
||
**Voraussetzungen:**
|
||
- T3-Plan `docs/superpowers/plans/2026-10-13-t3-erfassung-am-stand.md`: Tasks 7 (Navigation, `nav-config.ts`, Sheets), 8 (`NumberStepper`, `RatingScale` mit Richtung und Tönen, Kontrast-Wächter), 11 (Varroa-Trend) und 14 (Stand-Seite mit Ampel, `colonyStatusLight`, `StatusLightBadge`) sind gemergt. T5 baut darauf auf und nichts davon neu.
|
||
- Für T5b: T4-Plan `docs/superpowers/plans/2026-10-13-t4-logik-ketten.md`, Lieferung T4a mit den Tasks 13, 15, 17, 18 und 19, ist gemergt. T4b (Tasks 25, 26, 31) ist optional; ohne T4b gilt die Saison nach Kalender.
|
||
|
||
### Bindende Vorgaben (Inhaber, aus Fahrplan, T3 und T4)
|
||
|
||
- ADHS-freundlich: wenig kognitive Last, ein Hauptknopf je Ansicht, kurze deutsche Sätze, Zustand nie nur über Farbe (immer Icon plus Wort).
|
||
- Sicherheit hat Priorität 1, Konsistenz ist oberstes Gesetz: ein Muster, gemeinsame Bausteine, keine Kopien.
|
||
- Touch-Ziele mindestens 44 px, Sheet-Zeilen 56 px. WCAG 2.2 AA.
|
||
- Dark Mode wird angeschlossen, sonst fliegen die Tokens raus (Fahrplan §10). Diese Spec schließt ihn an.
|
||
- Vor jedem Next.js-Code die passende Anleitung unter `ApiCore-Frontend/node_modules/next/dist/docs/` lesen (`AGENTS.md`). Für T5 sind das vor allem `01-app/02-guides/preventing-flash-before-hydration.md`, `progressive-web-apps.md` und `01-app/03-api-reference/03-file-conventions/01-metadata/manifest.md` sowie `app-icons.md`.
|
||
|
||
### Entscheidungen
|
||
|
||
| Frage | Entscheidung |
|
||
|---|---|
|
||
| Wie wird der Hauptknopf lesbar? | **Honig als Fläche, dunkle Tinte als Text** (9,4:1). Das ersetzt Weiß auf Honigverlauf (2,3:1). Für Text, Links, Icons und den Fokusring auf hellen Flächen gibt es ein eigenes Token `--primary-ink` (dunkler Bernstein, 6,5:1). `text-primary` ist verboten, weil heller Honig als Schrift nicht lesbar ist. Abweichung zur Wahl: Offene Frage 1. |
|
||
| Wie unterscheidet sich ein gewählter Zustand? | Honigfläche **plus** 2 px Rahmen in Tinte **plus** Haken-Icon. Die Fläche allein hätte gegen die Karte nur 1,9:1. Rahmen und Haken tragen den Zustand, auch für Farbenblinde und in der Sonne. |
|
||
| Ampel-Abzeichen im Dunkelmodus | Heute steht dort dunkle Schrift auf dunkler Tönung (1,4:1). Darum bekommt jede Zustandsfarbe drei Tokens: Fläche (`--condition-x`), Text auf der Fläche (`-foreground`) und Text oder Icon auf normalen Flächen und Tönungen (`-ink`). |
|
||
| Kontrastmodus | **„Sonne“** als eigener Tokensatz (`html[data-contrast="sun"]`): reinweiße Fläche, fast schwarze Tinte, Rahmen in Tinte, keine Tönungen, Schatten oder Unschärfe, 3-px-Fokus, Nebentext 16 px. Sonne funktioniert hell und dunkel. Schaltbar im Profil und mit einem Tipp im Benutzermenü; `prefers-contrast: more` schaltet Sonne vor, solange der Nutzer nichts gewählt hat. |
|
||
| Wie wird umgeschaltet, ohne zu flackern? | Ein kleines Inline-Skript im `<head>` setzt vor dem ersten Bild `class="dark"`, `data-contrast` und `data-motion` auf `<html>` (Muster aus der Next-Anleitung „Preventing Flash“). Die Werte liegen je Gerät in `localStorage`, wie heute die Bewegungsstufe. `next-themes` wird entfernt. Ein Mechanismus für alle drei Einstellungen. |
|
||
| Standard-Farbschema | **Hell**, nicht „Wie Gerät“. Viele Handys stehen dauerhaft auf dunkel; draußen bei Tag ist eine helle Oberfläche besser lesbar. Wahl: Offene Frage 3. |
|
||
| Grundschrift | Fließtext, Formular-Beschriftungen, Auswahl-Knöpfe, Listentitel und Hauptknöpfe haben 16 px. Nebentext 14 px. `text-xs` wird 13 px und ist nur für Achsen, Legenden und Fußzeilen erlaubt. In Sonne 16 bzw. 14 px. |
|
||
| Kompakte Größen | Kompakt darf nur ein Gerät mit feinem Zeiger (`@media (pointer: fine)`) sein, nicht jeder Bildschirm ab `sm`. Heute bekommt ein Tablet am Stand 32-px-Knöpfe und 36-px-Felder. |
|
||
| Fokusstil | **Einer für alles:** 2 px durchgehender Ring in `--ring` mit 2 px Abstand (Sonne: 3 px). Er sitzt als Basisregel auf `:focus-visible`. Komponenten löschen ihn nicht mehr (`outline-none`, `ring-ring/50` werden entfernt). Der Abstand sorgt dafür, dass der Ring gegen den Hintergrund gemessen wird, nicht gegen den Knopf. |
|
||
| Ein Motiv | Die Wabenzelle (Sechseck mit spitzer Oberseite) ist das einzige grafische Motiv. Verläufe (`--gradient-honey/-sage/-sky`) werden entfernt, ebenso der Glas-Effekt in Sonne. Das Wabenmuster `HoneycombPattern` bleibt nur auf Login und Herkunftsseite. |
|
||
| Waben-Standkarte: Datenquelle | Der bestehende Endpunkt `GET /apiaries/:id/colony-overview` (T3, mit T4-Feldern) je Stand über `useQueries`. Cache und Offline-Paket-Rückfall der Stand-Seite gelten damit mit. Kein neuer Sammel-Endpunkt. |
|
||
| Randstärke der Zelle | Wie im Fahrplan zeigt die Randstärke die Tage seit der letzten Durchsicht, aber in **drei Stufen** statt stufenlos: dünn = frisch, mittel = bald fällig, dick und gestrichelt = fällig oder nie durchgesehen. Stufenlose Strichstärken sind draußen nicht unterscheidbar. Die genaue Zahl steht im Namen der Zelle und in der Liste. |
|
||
| Lebenslinie und Rad: Daten | Nur vorhandene Endpunkte (Volk, Durchsichten, Varroa, Behandlungen, Fütterungen, Schwarmkontrollen, Historie, Königin; ab T4 `next-steps` und Varroa-Bewertung). Einzige Backend-Änderung: `GET /autopilot/today` bekommt **additiv** den Saisonkalender und `segmentSince` je Stand (9.1). |
|
||
| Diagramm-Bibliothek | Keine. Handgeschriebenes SVG wie `colony-varroa.tsx`. Beim Bau den `dataviz`-Skill laden (wie T3/T4). |
|
||
| Bewegung | Keine neue Animation. Rad, Lebenslinie und Waben erscheinen sofort. Bewegung gibt es nur, wo sie heute einen Zustand zeigt (Abhaken, nächster Schritt). |
|
||
| Icons | Lucide wie bisher. Eine Tabelle `AREAS` (Abschnitt 11) ist die einzige Quelle für Icon und Farbton je Bereich. Navigation, Kopfzeilen, „+ Neu“ und T4-Vorschläge lesen daraus. |
|
||
| App-Icons | Ein Master-SVG, daraus erzeugte PNGs (192/512 „any“, 192/512 „maskable“, 512 „monochrome“, 180 Apple, Favicon). Die erzeugten Dateien liegen im Repo; das Skript nutzt `sharp` als neue devDependency. |
|
||
|
||
## 2. Umfang
|
||
|
||
### 2.1 Im Umfang (§10 T5 → Lösung)
|
||
|
||
| Punkt aus §10 T5 | Lösung | Abschnitt |
|
||
|---|---|---|
|
||
| Waben-Standkarte: Stand = Wabe, Volk = Zelle, Füllung über `condition-*` plus Icon, Randstärke = Tage seit Durchsicht | `ApiaryComb` auf der Stand-Seite und der Bienenstände-Liste | 6 |
|
||
| Mini-Waben ersetzen die Leaflet-Marker | `L.divIcon` mit SVG-Rosette, Listen-Rückfall | 7 |
|
||
| Lebenslinie: senkrechte Zeitleiste, Stärkekurve, Band für Milben pro Tag, Königin als Punkt in Zeichenfarbe | `ColonyLifeline` auf der Volksseite | 8 |
|
||
| Bienenjahr-Rad auf dem Dashboard, ersetzt die Zählkacheln | `YearWheel` mit Saison, Fenstern, Zeiger, Aufgabenpunkten | 9 |
|
||
| Text auf Hauptknopf ≥ 4,5:1, Rahmen ≥ 3:1, Grundschrift 16 px | neue Tokens, `-ink`-Tokens, Schriftregeln | 4 |
|
||
| Optional ein Kontrastmodus | „Sonne“ | 4.3, 5 |
|
||
| Dark Mode anschließen oder Tokens raus | angeschlossen, Tokens repariert | 4, 5 |
|
||
| Manifest in Markenfarben mit PNG und maskable Icons | neues Markenzeichen, Icon-Satz, Shortcuts | 12 |
|
||
| Je ein Baustein für Auswahlgruppe, Checkbox, Tabs, Plus/Minus | `ChoiceGroup`, `Checkbox`/`CheckboxField`, `Tabs`, `NumberStepper` | 10 |
|
||
| Feste Icon- und Farbzuordnung pro Bereich | `AREAS`, `AreaIcon` | 11 |
|
||
| Fokusstil für alle eigenen Bedienelemente | globale Fokusregel | 4.6, 10.6 |
|
||
| §11 T5-Befunde: Weiß auf Honig 2,3:1, Eingaberahmen 1,56:1, Dark Mode unerreichbar, Auswahlgruppen von Hand, Checkboxen in 4, Tabs in 3 Varianten | alle behoben | 4.4, 5, 10 |
|
||
|
||
### 2.2 Befunde aus dem Code, die T5 zusätzlich behebt
|
||
|
||
Gemessen mit derselben OKLCH-Rechnung wie `src/lib/forms/rating-contrast.spec.ts`.
|
||
|
||
| Befund | Wert heute | Lösung | Abschnitt |
|
||
|---|---|---|---|
|
||
| Links und Icons in `text-primary` auf dem Seitenhintergrund | 3,66:1 | `--primary-ink`, Codemod für 32 Stellen | 4.2 |
|
||
| Fokusring `ring-ring/50` auf der Karte | 1,94:1 (dunkel 2,59) | durchgehender Ring mit Abstand | 4.6 |
|
||
| Ampel-Abzeichen (Text auf 15-%-Tönung) im Dunkelmodus | 1,36–1,43:1 | `-ink`-Tokens | 4.2 |
|
||
| Warn-Badge im Dunkelmodus | 1,49:1 | `--warning-ink` | 4.2 |
|
||
| Aktiver Navigationseintrag (`bg-primary text-primary-foreground`) | 4,04:1 | Honig plus Tinte, 9,38:1 | 4.2 |
|
||
| Weiße Icons auf Honigverlauf (Seitenkopf, Karten, Markenzeichen) | 2,39:1 | `AreaIcon`, `BrandMark` | 11, 12 |
|
||
| Warn-Icons `text-warning` auf der Karte | 2,90:1 | `text-warning-ink`, 6,09:1 | 4.2 |
|
||
| Diagrammfarbe `chart-3` | 2,90:1 | 3,93:1 | 4.2 |
|
||
| Ampelfläche „mittel“ als gewählte Skalenstufe | 2,65:1 | 3,03:1, dazu Rahmen und Haken | 4.2, 10.2 |
|
||
| Ab `sm` (640 px) Knöpfe 32 px und Felder 36 px, auch auf Tablets mit Touch | – | Kompaktmaß nur bei `pointer: fine` | 4.5 |
|
||
| `Toaster` nutzt `useTheme` aus `next-themes` ohne Provider und folgt damit dem System, die App aber nicht | – | eigener Appearance-Hook | 5 |
|
||
| `data-motion` wird erst in `useEffect` gesetzt | erster Seitenübergang läuft ungebremst | Inline-Skript setzt es vor dem ersten Bild | 5 |
|
||
| `TabSwitcher` und `ActiveHistoryTabs` haben `role="tablist"` ohne Tabpanel und ohne Pfeiltasten | – | ein `Tabs`-Baustein auf Base UI | 10.4 |
|
||
| Farbverläufe je Seite von Hand gewählt (Königinnen Salbei, Kalender Himmel, Inventar mal Salbei, mal Himmel) | – | Farbe aus `AREAS` | 11 |
|
||
| Abweichende Icons: Ernte-Detail `Boxes` statt `Scissors`, Schleuderung neu `Droplet` statt `FlaskConical`, Lager zusätzlich `Package` (= Abfüllung) | – | eine Quelle `AREAS` | 11 |
|
||
| Manifest: `theme_color #0a0a0a`, `background_color #ffffff`, nur `icon.svg`; das Icon zeigt drei gelbe Balken statt des Markenzeichens | – | neuer Icon-Satz | 12 |
|
||
| Leaflet-Popups sind immer weiß, auch im Dunkelmodus | – | Popup-Stil aus Tokens | 7 |
|
||
| `ui/*` hat eigene `dark:`-Klassen, die das Token-System umgehen | – | entfernt, Tokens tragen den Modus | 4.1 |
|
||
|
||
### 2.3 Nicht im Umfang
|
||
|
||
- Neue Fachlogik. Ampelregeln, Saison, Fälligkeit und Varroa-Bänder kommen aus T3 und T4.
|
||
- Echte Aufstellung der Völker am Stand (Position in der Reihe). Die Zellen stehen nach Volkscode, siehe Offene Frage 2.
|
||
- Neue Diagramme in der Statistik. Die Statistik bekommt nur die neuen Tokens und den Tabs-Baustein.
|
||
- Etiketten-Designer und PDF-Ausgaben. Sie bekommen nur Tokens und Bausteine, wo sie Bedienelemente der App nutzen; Druck bleibt immer hell.
|
||
- Native App, Umgebungslicht-Sensor (zu wenig Browserunterstützung), Haptik.
|
||
- Ein E2E-Framework (Playwright) im Frontend. Die Sichtprüfung läuft per Screenshot-Matrix (13.4).
|
||
|
||
### 2.4 Abgrenzung zu T3 und T4
|
||
|
||
| Baustein | Liefert | T5 ändert |
|
||
|---|---|---|
|
||
| T3 Task 8 `RatingScale`, `RATING_TONE_CLASS`, `rating-contrast.spec.ts` | Töne je Stufe, Kontrast-Wächter für Ampelflächen | Wächter geht in `src/styles/contrast.spec.ts` auf (alle Paare, vier Sätze). Gewählte Stufe bekommt Rahmen und Haken wie jede Auswahl. |
|
||
| T3 Task 8 `NumberStepper` | Plus/Minus-Feld | API bleibt. Weitere Zählfelder stellen darauf um (10.5). |
|
||
| T3 Task 14 `colonyStatusLight`, `StatusLightBadge`, `ApiaryColoniesCard` | Ampel je Volk, Zeilenliste | Die Ampel füllt die Zellen. Die Zeilenliste bleibt als Rückfall unter der Wabe. |
|
||
| T3 Task 7 `nav-config.ts`, `quick-actions.ts`, Sheets | eine Navigationsquelle | Icons kommen aus `AREAS`. |
|
||
| T3 Task 11 Varroa-Trend (SVG) | Muster für handgeschriebene Diagramme | Vorlage für Lebenslinie und Rad. |
|
||
| T4 Task 15 `ColonyOverviewRow.inspectionDueOn`, `ColonyNextSteps`, `AutopilotToday` | Fälligkeit, nächste Schritte, Saison je Stand | Randstufen der Zelle, Zukunftszone der Lebenslinie, Rad. `AutopilotToday` bekommt zwei Felder (9.1). |
|
||
| T4 Task 18 `SeasonChip`, `SEGMENT_LABELS`, Heute-Karten | Saison-Chips auf dem Dashboard | Die Saison je Stand zieht in die Rad-Karte. Die Chip-Zeile entfällt dort, um Doppelanzeige zu vermeiden. `SeasonChip` bleibt auf der Stand-Seite. |
|
||
| T4 Task 17 `INTENT_ICONS` | Icon je Absicht | Werte aus `AREAS` (Durchsicht, Varroa, Fütterung …). |
|
||
| T4 Task 19 Varroa-Bänder, `rating` je Messung | Ampel je Messung | Lebenslinie färbt mit `rating.light` und markiert `band.redAbove`. |
|
||
| T4 Task 31 `PHASE_SOURCE_LABELS` | „gemeldet“, „geschätzt“, „Kalender“ | Rad zeigt die Quelle damit. |
|
||
|
||
## 3. Gestaltungsgrundsätze für diese App
|
||
|
||
1. **Sonne zuerst.** Draußen spiegelt das Display, und Spiegelung frisst Kontrast. Darum liegen Fließtext und Hauptknopf über 7:1, nicht knapp über 4,5:1. Flächen sind hell und ruhig, Text ist dunkel. Unterschiede zeigen sich über Helligkeit, Form und Strichstärke, nicht über Sättigung.
|
||
2. **Handschuhe.** Jedes Ziel mindestens 44 × 44 px, Zeilen in Sheets 56 px. Kein Ziel, das nur durch Hover oder einen langen Druck erreichbar ist. Benachbarte Ziele haben mindestens 4 px Abstand.
|
||
3. **Ein Blick, eine Sache.** Jede Ansicht hat einen Hauptknopf in Honig. Alles andere ist umrandet oder Text. Eine Grafik beantwortet genau eine Frage:
|
||
- Waben: Welches Volk braucht mich?
|
||
- Lebenslinie: Wie hat sich das Volk entwickelt?
|
||
- Rad: Wo stehen wir im Bienenjahr, was kommt?
|
||
4. **Nie nur Farbe.** Jeder Zustand hat ein Icon und ein Wort, jede Grafik einen Text und eine Tabelle. Die Zellen tragen den Volkscode und ein Zustands-Icon. Gestrichelte Ränder und Schraffuren unterscheiden auch ohne Farbsehen.
|
||
5. **Vertraute Bedienung, eigene Handschrift im Detail.** Knöpfe, Felder, Tabs und Sheets verhalten sich wie überall im Web. Die Handschrift sitzt in Material (Wachs und Honig), Tinte und dem einen Motiv Wabenzelle, nicht in erfundenen Bedienelementen.
|
||
6. **Ruhe.** Keine Verläufe, kein Glas, keine Zierbewegung, keine Großbuchstaben-Laufschrift. Schatten sind leise und entfallen in Sonne. Die Farbtöne der Bereiche erscheinen nur als Icon-Kachel, nicht als Fläche.
|
||
|
||
**Verboten** (der Wächter-Test prüft, was sich prüfen lässt):
|
||
- Weiß auf Honig
|
||
- `text-primary` als Schriftfarbe
|
||
- `ring-ring/50` und `outline-none` ohne Ersatz
|
||
- Farbverlauf als Hintergrund
|
||
- Text unter 13 px
|
||
- Zustand nur über Farbe
|
||
- eigene `role="radio|checkbox|tab"`-Bauten außerhalb des Baukastens
|
||
|
||
## 4. Tokens
|
||
|
||
### 4.1 Grundregeln
|
||
|
||
- Jede Farbe hat eine Rolle. **Fläche** (`--primary`, `--condition-good`, …) trägt ihren **Text auf der Fläche** (`--primary-foreground`, `--condition-good-foreground`). Für Text und Icons auf normalen Flächen gibt es **Tinte** (`--primary-ink`, `--warning-ink`, `--condition-good-ink`).
|
||
- Vier Sätze in dieser Reihenfolge in `globals.css`:
|
||
1. `:root` (hell)
|
||
2. `.dark` (dunkel)
|
||
3. `:root[data-contrast="sun"]` (Sonne hell)
|
||
4. `.dark[data-contrast="sun"]` (Sonne dunkel)
|
||
|
||
Die Sonne-Sätze überschreiben nur die Tokens aus 4.3.
|
||
- `@custom-variant dark (&:where(.dark, .dark *));` statt heute `(&:is(.dark *))`, damit die Klasse direkt auf `<html>` greift. Dazu kommen die Varianten `sun`, `pointer-fine` und `pointer-coarse`.
|
||
- `ui/*` und `components/*` enthalten keine `dark:`-Klassen mehr. Ein Modus ist nur ein anderer Tokensatz. Einzige Ausnahme: Leaflet-Kacheln (7.4).
|
||
- Entfernt: `--gradient-honey`, `--gradient-sage`, `--gradient-sky`. Die Komponente `PageHeader`/`EntityCard` verliert den Prop `gradient`.
|
||
- `@media print` setzt immer den hellen Satz.
|
||
- `@media (forced-colors: active)`:
|
||
- Zellen, Ränder, Ringe und Rad-Segmente bekommen `CanvasText`-Striche.
|
||
- Zustände bleiben über Icon, Muster und Strichstärke erkennbar.
|
||
- SVG-Flächen nutzen `forced-color-adjust: auto`.
|
||
|
||
### 4.2 Werte hell und dunkel
|
||
|
||
OKLCH ist die Quelle, Hex dient nur zur Orientierung. Alle Werte liegen im sRGB-Farbraum (vom Skript geprüft).
|
||
|
||
| Token | Hell | Dunkel | Verwendung |
|
||
|---|---|---|---|
|
||
| `--background` | `oklch(0.968 0.014 85)` #f9f4ea | `oklch(0.19 0.016 55)` #1a120d | Seite („Wachs“) |
|
||
| `--foreground` | `oklch(0.21 0.03 55)` #23140a | `oklch(0.95 0.018 80)` #f5ede1 | Text („Tinte“) |
|
||
| `--card`, `--popover`, `--sidebar` | `oklch(0.995 0.004 90)` #fefdfa | `oklch(0.235 0.018 55)` #251c16 | Karten, Sheets |
|
||
| `--muted` | `oklch(0.925 0.018 82)` #ece5d9 | `oklch(0.28 0.018 55)` #302720 | ruhige Flächen, Rad-Segmente |
|
||
| `--muted-foreground` | `oklch(0.44 0.03 60)` #5f4f42 | `oklch(0.76 0.025 75)` #bbafa0 | Nebentext |
|
||
| `--primary` | `oklch(0.80 0.145 78)` #f0b13f | `oklch(0.80 0.14 78)` #efb146 | Honig: Hauptknopf, Auswahl, aktiver Eintrag |
|
||
| `--primary-foreground` | `oklch(0.21 0.035 55)` #251408 | `oklch(0.19 0.03 55)` #1e1006 | Text auf Honig |
|
||
| `--primary-ink` **neu** | `oklch(0.47 0.115 55)` #8a4603 | `oklch(0.82 0.13 80)` #f0ba59 | Links, Akzent-Icons, aktiver Tab-Strich |
|
||
| `--ring` | = `--primary-ink` | = `--primary-ink` | Fokusring |
|
||
| `--secondary` / `-foreground` | `oklch(0.44 0.07 145)` / `oklch(0.98 0.015 100)` | `oklch(0.66 0.08 145)` / `oklch(0.16 0.02 145)` | Salbei, Zweitknopf |
|
||
| `--accent` / `-foreground` | `oklch(0.935 0.03 78)` / `oklch(0.25 0.045 50)` | `oklch(0.31 0.03 60)` / `oklch(0.95 0.018 80)` | Hover, Menüs |
|
||
| `--destructive` | `oklch(0.50 0.17 28)` #af2b25 | `oklch(0.70 0.15 28)` #ed7668 | Text, Icon, Rahmen |
|
||
| `--destructive-foreground` **neu** | `oklch(0.985 0.005 30)` | `oklch(0.17 0.03 30)` | Text auf voller Fläche (Bestätigen-Dialog) |
|
||
| `--border` | `oklch(0.86 0.022 78)` #d9d0c1 | `oklch(0.34 0.02 60)` #40362e | nur Trennlinien und Kartenkanten (Deko) |
|
||
| `--input` | `oklch(0.60 0.035 65)` #8f7c6b | `oklch(0.56 0.025 70)` #7e7265 | Rahmen jedes Bedienelements |
|
||
| `--warning` / `-foreground` | `oklch(0.79 0.15 80)` / `oklch(0.23 0.04 60)` | `oklch(0.80 0.14 80)` / `oklch(0.20 0.03 60)` | Warnfläche |
|
||
| `--warning-ink` **neu** | `oklch(0.50 0.11 65)` #8d5406 | `oklch(0.82 0.13 82)` #eebb58 | Warn-Icon und -Text |
|
||
| `--success` / `-foreground` | `oklch(0.46 0.08 145)` / `oklch(0.98 0.015 100)` | `oklch(0.70 0.09 145)` / `oklch(0.16 0.02 145)` | Erfolg |
|
||
| `--condition-excellent` / `-foreground` / `-ink` | `0.62 0.13 150` / `0.15 0.04 150` / `0.40 0.09 150` | `0.68 0.12 150` / `0.17 0.04 150` / `0.80 0.11 150` | Ampel „sehr gut“ |
|
||
| `--condition-good` / … | `0.645 0.13 125` / `0.17 0.04 125` / `0.41 0.09 125` | `0.72 0.12 125` / `0.18 0.04 125` / `0.83 0.11 125` | Ampel „gut“, Zelle grün |
|
||
| `--condition-average` / … | `0.665 0.125 88` / `0.19 0.04 90` / `0.44 0.09 85` | `0.77 0.13 90` / `0.20 0.04 90` / `0.86 0.11 90` | Ampel „Achtung“, Zelle gelb |
|
||
| `--condition-weak` / … | `0.665 0.14 58` / `0.18 0.04 55` / `0.46 0.12 52` | `0.74 0.13 60` / `0.19 0.04 55` / `0.82 0.11 60` | Ampel „schwach“ |
|
||
| `--condition-critical` / … | `0.62 0.17 30` / `0.15 0.04 30` / `0.47 0.16 28` | `0.68 0.16 28` / `0.16 0.04 30` / `0.78 0.11 28` | Ampel „kritisch“, Zelle rot |
|
||
| `--chart-1` … `--chart-5` | `0.56 0.13 55`, `0.46 0.08 145`, `0.60 0.12 85`, `0.50 0.17 28`, `0.52 0.08 250` | `0.78 0.13 70`, `0.70 0.09 145`, `0.82 0.12 90`, `0.70 0.15 28`, `0.72 0.08 250` | Diagramme; Rad-Fenster: Tracht = 3, Varroa = 4, Einwinterung = 5 |
|
||
| `--area-betrieb` **neu** | `oklch(0.46 0.08 150)` | `oklch(0.74 0.09 150)` | Bereichston (Abschnitt 11) |
|
||
| `--area-erfassung` **neu** | `oklch(0.50 0.12 60)` | `oklch(0.80 0.12 70)` | |
|
||
| `--area-arbeit` **neu** | `oklch(0.48 0.08 250)` | `oklch(0.76 0.07 250)` | |
|
||
| `--area-ernte` **neu** | `oklch(0.52 0.11 75)` | `oklch(0.80 0.10 80)` | |
|
||
| `--area-neutral` **neu** | `oklch(0.45 0.02 60)` | `oklch(0.76 0.02 70)` | |
|
||
| `--queen-white/-yellow/-red/-green/-blue` **neu** | `0.97 0.005 90`, `0.86 0.17 95`, `0.58 0.20 27`, `0.58 0.15 145`, `0.52 0.15 255` | gleich, außer rot `0.62 0.20 27`, grün `0.66 0.15 145`, blau `0.62 0.15 255` | Zeichenfarbe der Königin, immer mit 2-px-Ring in `--foreground` |
|
||
| `--radius` | `0.75rem` | gleich | unverändert |
|
||
| `--shadow-soft`, `--shadow-elevated` | unverändert | unverändert | in Sonne `none` |
|
||
|
||
Bestehende Klassen werden so umgestellt (Codemod, Abschnitt 10.8):
|
||
- `text-primary` → `text-primary-ink`
|
||
- `text-warning` → `text-warning-ink`
|
||
- `text-condition-x-foreground` in Abzeichen → `text-condition-x-ink` (`COLONY_CONDITION_TONE_CLASS`, `StatusLightBadge`)
|
||
- `border-primary` bei Auswahlzuständen → `border-foreground`
|
||
|
||
### 4.3 Kontrastmodus „Sonne“
|
||
|
||
Ziel: draußen bei voller Sonne alles mit maximaler Helligkeitsdifferenz lesbar, ohne dass sich Bedienung oder Anordnung ändern.
|
||
|
||
| Token | Sonne hell | Sonne dunkel |
|
||
|---|---|---|
|
||
| `--background`, `--card`, `--popover`, `--sidebar` | `oklch(1 0 0)` #ffffff | `oklch(0.10 0.005 55)` #040302 |
|
||
| `--foreground`, `--primary-foreground`, `--ring` | `oklch(0.13 0.02 55)` #0d0602 | `--foreground`/`--ring` `oklch(0.99 0.005 85)` |
|
||
| `--muted` | `oklch(0.95 0.01 80)` | `oklch(0.20 0.01 55)` |
|
||
| `--muted-foreground` | `oklch(0.32 0.03 60)` | `oklch(0.88 0.02 80)` |
|
||
| `--border` | `oklch(0.40 0.03 60)` | `oklch(0.70 0.02 70)` |
|
||
| `--input` | `oklch(0.20 0.03 55)` | `oklch(0.92 0.01 80)` |
|
||
| `--primary-ink` | `oklch(0.38 0.10 52)` | wie dunkel |
|
||
|
||
Dazu kommen Regeln unter `[data-contrast="sun"]`:
|
||
- **Schrift:** `--text-sm: 1rem`, `--text-xs: 0.875rem`. Tailwind 4 liest die Größen aus diesen Variablen, deshalb wirkt das ohne Klassenänderung.
|
||
- **Fokus:** `--focus-width: 3px`.
|
||
- **Rahmen:** Rahmen von Bedienelementen 2 px (`--control-border-width: 2px`).
|
||
- **Flächen:** keine Schatten (`--shadow-*: none`). Kopfzeile undurchsichtig (`backdrop-filter: none`, `bg-card`). Tönungen `bg-*/15` werden zu `bg-card` mit 2-px-Rahmen in der jeweiligen Tinte (Hilfsklasse `.tint` statt `/15`).
|
||
- **Grafik:** Wabenränder 3/5/7 px statt 2/4/6 px. Keine Honig-Tönung unter der Stärkekurve.
|
||
|
||
### 4.4 Gemessene Kontraste (Ist → Soll)
|
||
|
||
Grenzen: Text 4,5:1, Bedienrahmen, Fokus und Grafik 3:1. Für Fließtext und Hauptknopf ist das Ziel 7:1. Die Werte unten sind die Sollwerte, die der Wächter-Test prüft.
|
||
|
||
| Paar | Ist hell | Soll hell | Ist dunkel | Soll dunkel | Sonne hell | Sonne dunkel | Grenze |
|
||
|---|---|---|---|---|---|---|---|
|
||
| Text auf Hauptknopf | 2,31 (Verlaufsanfang) / 4,04 | **9,38** | 1,72 (Verlaufsende) | **9,77** | 10,61 | 9,77 | 7 |
|
||
| Grundtext / Seite | 15,25 | 16,23 | 15,21 | 15,98 | 20,15 | 20,01 | 7 |
|
||
| Grundtext / Karte | 17,15 | 17,56 | 13,46 | 14,45 | 20,15 | 20,01 | 7 |
|
||
| Nebentext / Seite | 5,77 | 7,13 | 6,78 | 8,60 | 12,77 | 14,33 | 4,5 |
|
||
| Nebentext / `--muted` | 4,88 | 6,27 | 5,29 | 6,81 | 11,03 | 12,62 | 4,5 |
|
||
| Link (`--primary-ink`) / Seite | 3,66 | **6,48** | 7,05 | 10,48 | 10,37 | 11,66 | 4,5 |
|
||
| Eingaberahmen / Karte | **1,56** | **3,92** | 1,66 | 3,58 | 18,19 | 16,25 | 3 |
|
||
| Eingaberahmen / Seite | – | 3,62 | – | 3,96 | 18,19 | 16,25 | 3 |
|
||
| Fokusring / Karte (mit Abstand) | 1,94 | 7,01 | 2,59 | 9,47 | 20,15 | 20,01 | 3 |
|
||
| Fokusring / Seite | – | 6,48 | – | 10,48 | 20,15 | 20,01 | 3 |
|
||
| Warn-Icon/-Text / Karte | 2,90 | 6,09 | 6,84 | 9,49 | 6,18 | 11,68 | 4,5 |
|
||
| Warn-Text / Warn-Tönung | 14,14 | 5,53 | 1,49 | 6,92 | 5,60 | 9,37 | 4,5 |
|
||
| Fehlertext / Karte | 6,41 | 6,45 | 4,10 | 5,87 | 6,54 | 7,23 | 4,5 |
|
||
| Fehlertext / Fehler-Tönung | 5,48 | 5,50 | 3,66 | 5,06 | 5,57 | 6,58 | 4,5 |
|
||
| Salbei-Knopf | 7,11 | 7,11 | 5,56 | 6,43 | 7,11 | 6,43 | 4,5 |
|
||
| Ampel-Abzeichen (Tinte / Tönung), schlechteste Stufe | 12,61 | 6,06 | **1,36** | 6,45 | 6,14 | 8,49 | 4,5 |
|
||
| Text auf Ampelfläche, schlechteste Stufe | 4,71 | 5,02 | 4,66 | 6,32 | 5,02 | 6,32 | 4,5 |
|
||
| Ampelfläche / Karte (Zelle, gewählte Stufe), schlechteste | 2,65 | 3,03 | 4,10 | 5,41 | 3,07 | 6,66 | 3 |
|
||
| Diagramm `chart-1…5` / Karte, schlechteste | 2,90 (`chart-3`) | 3,93 | 4,10 | 5,87 | 3,99 | 7,23 | 3 |
|
||
| Bereichston / Karte, schlechtester | – | 5,54 | – | 7,52 | 5,54 | 7,52 | 3 |
|
||
| Königinnenfarbe mit Tinten-Ring / Karte | – | 17,56 (Ring) | – | 14,45 (Ring) | 20,15 | 20,01 | 3 |
|
||
|
||
Abzeichen im hellen Modus fallen bewusst von 12–16:1 auf 6–7,4:1. Statt fast schwarzer Schrift zeigen sie nun den Farbton als Tinte, damit „Kritisch“ und „Gut“ auch ohne Icon verschieden aussehen. Sie bleiben deutlich über 4,5:1.
|
||
|
||
Die Honigfläche hat gegen die Karte nur 1,87:1. Das ist zulässig: Ein Knopf wird über seinen Text erkannt, und gewählte Zustände tragen Rahmen und Haken (Entscheidungen). Im Rad bekommt das aktuelle Segment einen 2-px-Rahmen in Tinte (9.3).
|
||
|
||
### 4.5 Schrift und Größen
|
||
|
||
| Rolle | Größe | Klasse | Familie |
|
||
|---|---|---|---|
|
||
| Fließtext, Formular-Beschriftung, Auswahl-Knöpfe, Listentitel, Knopftext, Eingabe | 16 px | `text-base` | Inter |
|
||
| Nebentext (Datum, Hinweis, Begründung) | 14 px (Sonne 16) | `text-sm` | Inter |
|
||
| Achsen, Legenden, Fußzeilen | 13 px (Sonne 14) | `text-xs` (`--text-xs: 0.8125rem`) | Inter |
|
||
| Überschriften h1–h4 | 20 / 24 / 30 px | wie heute | Space Grotesk, nie in Knöpfen oder Labels |
|
||
| Codes, Losnummern | wie Umgebung | `font-mono` | IBM Plex Mono |
|
||
|
||
- Diese Bausteine stellen Inhaltstext von `text-sm` auf `text-base` um:
|
||
- `Field`-Label
|
||
- `ChoiceGroup`-Option
|
||
- `CheckboxField`-Label
|
||
- Button-Größe `touch` (heute `text-[0.95rem]`)
|
||
- `Input`/`Textarea` (`md:text-sm` entfällt; 16 px verhindert auch das Zoomen in iOS)
|
||
- Zeilentitel in Listen, `DetailHeader`-Untertitel
|
||
- `EmptyState`-Beschreibung
|
||
- Größen: `size="default"` bei Button und `Input` hat 44 px Höhe. 32 bzw. 36 px gibt es nur mit `pointer-fine:` statt `sm:`. `size="touch"` bleibt 44 px. In `ui/button.tsx`, `ui/input.tsx`, `ui/select.tsx`, `ui/textarea.tsx` und `ui/tabs.tsx` wird `sm:h-*` zu `pointer-fine:h-*`.
|
||
- Ziele: Icon-Knöpfe ohne Text (`icon`, `icon-sm`) bekommen bei `pointer-coarse` eine Trefferfläche von 44 px über ein `::after`-Element, ohne optisch zu wachsen.
|
||
|
||
### 4.6 Fokusstil
|
||
|
||
In `@layer base`:
|
||
|
||
```css
|
||
:root { --focus-width: 2px; --focus-offset: 2px; }
|
||
:where(:focus-visible) { outline: var(--focus-width) solid var(--ring); outline-offset: var(--focus-offset); }
|
||
```
|
||
|
||
- Alle `outline-none`, `focus-visible:ring-3 focus-visible:ring-ring/50` und `has-[:focus-visible]:outline-*` in `ui/*`, `components/*` und `app/*` entfallen (18 Stellen `ring-ring/50` in 17 Dateien, 22 `outline-none`).
|
||
- Wo der Fokus auf einem inneren Element liegt (Label-Zeile mit verstecktem Input, Wabenzelle), zeigt der Baustein den Ring am äußeren Element über `:has(:focus-visible)`. Bei der Wabenzelle ist das ein zweiter Sechseckpfad (6.6).
|
||
- Fehlerzustand (`aria-invalid`): Rahmen in `--destructive`, 2 px, dazu der Fehlertext am Feld. Der Fokusring bleibt in `--ring`.
|
||
- Fokus wird nicht verdeckt (WCAG 2.4.11): Das bestehende `scroll-padding` bleibt.
|
||
|
||
## 5. Darstellung umschalten
|
||
|
||
### 5.1 Einstellungen
|
||
|
||
| Einstellung | Werte | Standard | Attribut auf `<html>` | Speicher (je Gerät) |
|
||
|---|---|---|---|---|
|
||
| Farbschema | „Hell“, „Dunkel“, „Wie Gerät“ | Hell (Offene Frage 3) | `class="dark"` oder nichts | `localStorage` `apicore.theme` |
|
||
| Kontrast | „Normal“, „Sonne“ | Normal; ohne gespeicherten Wert Sonne bei `prefers-contrast: more` | `data-contrast="sun"` | `apicore.contrast` |
|
||
| Bewegung | „Voll“, „Dezent“, „Aus“ | Voll (wie heute) | `data-motion` | `apicore.motion` (heute schon) |
|
||
|
||
Alles wird je Gerät gespeichert, nicht am Konto. Draußen am Handy will man Sonne, am Schreibtisch nicht. Das folgt dem bestehenden Muster der Bewegungsstufe.
|
||
|
||
### 5.2 Ablauf
|
||
|
||
1. **Vor dem ersten Bild:** `src/components/appearance-script.tsx` rendert im `<head>` von `app/layout.tsx` ein Inline-Skript nach dem Muster `InlineScript` der Next-Anleitung „Preventing Flash“.
|
||
- Es liest die drei Schlüssel in `try/catch` und setzt Klasse und Attribute.
|
||
- Es setzt den Inhalt von `<meta name="theme-color">` auf die Seitenfarbe des aktiven Satzes.
|
||
- `<html>` bekommt `suppressHydrationWarning`.
|
||
- Das Skript kommt aus derselben Konstante wie der Hook (`APPEARANCE_KEYS`), damit Schlüssel und Werte nie auseinanderlaufen.
|
||
- CSP: `script-src 'self' 'unsafe-inline'` (`proxy.ts`) erlaubt das schon. Wird die CSP später verschärft, kommt der SHA-256-Hash des Skripts in die Liste. Das Skript enthält keine Nutzerdaten.
|
||
2. **Zur Laufzeit:** `useAppearance()` (`src/lib/appearance/appearance.ts`) liefert die Werte und Setter.
|
||
- Ein Setter schreibt `localStorage` und das Attribut.
|
||
- Er hört auf `matchMedia('(prefers-color-scheme: dark)')`, solange „Wie Gerät“ gewählt ist, und auf `prefers-contrast`, solange nichts gewählt ist.
|
||
- Er hört auf das `storage`-Ereignis, damit ein zweiter Tab mitzieht.
|
||
- `motion-preference.ts` behält seine API; `applyMotionLevel` wird vom Skript übernommen, der `useEffect` in `providers.tsx` entfällt.
|
||
3. **Toaster:** `components/ui/sonner.tsx` liest `useAppearance().resolvedTheme` statt `next-themes`. `next-themes` wird aus `package.json` entfernt.
|
||
4. **Metadaten:** `viewport.themeColor` in `app/layout.tsx`:
|
||
- `[{ media: '(prefers-color-scheme: light)', color: '#f9f4ea' }, { media: '(prefers-color-scheme: dark)', color: '#1a120d' }]`
|
||
- Das Skript überschreibt den Wert bei manueller Wahl.
|
||
|
||
### 5.3 Bedienung
|
||
|
||
- **Profil → Karte „Darstellung“** (ersetzt die Karte „Bewegung & Effekte“, `appearance-section.tsx` statt `motion-section.tsx`). Drei `ChoiceGroup`-Felder (Aussehen „Karten“ mit Beschreibung, 10.2):
|
||
- **Farbschema:** „Hell – am besten bei Tageslicht“, „Dunkel – für abends“, „Wie Gerät“.
|
||
- **Kontrast:** „Normal“, „Sonne – maximaler Kontrast, größere Schrift, für draußen“.
|
||
- **Bewegung:** Texte wie heute.
|
||
- Darunter steht: „Gilt nur für dieses Gerät.“ Die Änderung wirkt sofort und ohne Übergang.
|
||
- **Schnellschalter:** Im Benutzermenü (Avatar) steht oben ein Eintrag „Sonnenmodus“ als `DropdownMenuCheckboxItem` (`role="menuitemcheckbox"`, 44 px), mit Sonnen-Icon und Haken. Vom Stand aus sind das zwei Tipps, ohne Seitenwechsel. Nach dem Umschalten erscheint der Toast „Sonnenmodus an“ bzw. „aus“.
|
||
- **Abmelden** löscht diese Einstellungen nicht. Sie sind Gerätevorlieben, keine Daten.
|
||
|
||
### 5.4 Seiten außerhalb der App
|
||
|
||
- Login und `/herkunft/[lot]` folgen denselben Tokens und Einstellungen. Ein Kunde ohne gespeicherten Wert sieht „Hell“.
|
||
- Druck (`@media print`) und PDF-Vorschau bleiben hell.
|
||
|
||
## 6. Waben-Standkarte
|
||
|
||
**Frage, die sie beantwortet:** Welches Volk an diesem Stand braucht mich, und wann war ich zuletzt dran?
|
||
|
||
### 6.1 Daten
|
||
|
||
- Je Stand `ColonyOverview` aus `GET /apiaries/:id/colony-overview`, Query-Key `["apiaries", apiaryId, "colony-overview"]` (wie T3 Task 14). Offline greift `withPackFallback` (T3 Task 15).
|
||
- Je Zeile: `code`, `status`, Bedingungen, `lastInspectionDate`, `openWarnings`, `openCritical`. Ab T4 zusätzlich `inspectionDueOn`, `segment`, `nextStepTitle`.
|
||
- Zustand der Zelle = `colonyStatusLight(row, { today, inspectionsVisible })`, unverändert aus T3/T4.
|
||
- Auf der Bienenstände-Liste lädt `useQueries` die Übersicht aller aktiven Stände, höchstens 20. Bei mehr Ständen zeigen die übrigen Karten nur die Zusammenfassung, ohne Wabe; das ist im Betrieb nicht zu erwarten.
|
||
|
||
### 6.2 Aufbau
|
||
|
||
Stand-Seite, Karte „Völker“ (Handy, 328 px Inhaltsbreite):
|
||
|
||
```
|
||
┌ Völker (7) ─────────────────────────────────────────┐
|
||
│ 5 Gut · 1 Achtung · 1 Kritisch · 2 Durchsichten fällig│
|
||
│ │
|
||
│ ⬡B1 ⬡B2 ⬡B3 ⬡B4 ⬡ = Zelle 64 px │
|
||
│ ⬡B5 ⬡B6 ⬡B7 versetzte Reihe │
|
||
│ │
|
||
│ ⬡ Gut ⬡ Achtung ⬡ Kritisch · Rand: dünn = frisch, │
|
||
│ dick = Durchsicht fällig │
|
||
│ ──────────────────────────────────────────────────── │
|
||
│ Braucht Blick │
|
||
│ B3 ▲ Achtung Futter schwach · 16 Tage ohne Durchs.│
|
||
│ B6 ✕ Kritisch Weisellos │
|
||
│ [ Alle 7 Völker als Liste ▾ ] │
|
||
└──────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
- Zusammenfassung oben: ein Satz mit Icons, nach Ampel gezählt, dazu fällige Durchsichten (ab T4 aus `inspectionDueOn`, vorher Stufe 3 der Randregel).
|
||
- Wabe: die Zellen.
|
||
- Legende: immer sichtbar, eine Zeile, 13 px. Sie erklärt die drei Füllungen mit Wort und Icon und den Rand.
|
||
- „Braucht Blick“: nur Völker mit Gelb oder Rot, mit Gründen. Das ist die Arbeitsliste. Bei null Völkern steht dort „Alle Völker sind in Ordnung.“
|
||
- „Alle 7 Völker als Liste“: ein Knopf mit `aria-expanded`, der die T3-Zeilenliste aufklappt. Das ist der Tabellen-Rückfall für alle, die die Wabe nicht lesen können oder wollen. Ab T4 zeigt die Liste auch „Durchsicht fällig in 2 Tagen“ und den nächsten Schritt (T4 Task 18).
|
||
- Der Hauptknopf der Seite bleibt „Runde starten“ (T3).
|
||
|
||
Bienenstände-Liste (`/apiaries`, Tab „Aktiv“): Jeder aktive Stand ist eine Karte.
|
||
|
||
```
|
||
┌ ⬡ Nordhang ──────────────── Schwarmzeit · alle 7 Tage ┐ ← AreaIcon, Name (Link), SeasonChip (T4)
|
||
│ 7 Völker · 1 Achtung · 1 Kritisch │
|
||
│ ⬡ ⬡ ⬡ ⬡ │ Zellen 56 px, verlinken zum Volk
|
||
│ ⬡ ⬡ ⬡ │
|
||
└───────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
- Die Liste behält ihren Hauptknopf „+ Neuer Bienenstand“. Die Karten haben keine eigenen Knöpfe. Der Name führt zum Stand, die Zellen führen zu den Völkern.
|
||
- Der Tab „Historie“ bleibt eine `EntityCard`-Liste ohne Wabe.
|
||
- Die Legende steht einmal oben über allen Karten.
|
||
|
||
### 6.3 Zelle
|
||
|
||
- **Form:** Sechseck mit spitzer Oberseite. Breite (Abstand der senkrechten Seiten) 64 px bei `pointer-coarse`, 56 px bei `pointer-fine`, auf der Liste 56 bzw. 48 px. Höhe = Breite × 2/√3. Der Innenkreis (= Breite) ist immer mindestens 48 px, also mindestens 44 px Trefferfläche.
|
||
- **Anordnung:**
|
||
- Reihen mit `n` Zellen. `n = floor((Breite_Container − (b + 4)/2) / (b + 4))`, mindestens 3, höchstens 10.
|
||
- Jede zweite Reihe ist um `(b + 4)/2` nach rechts versetzt und um ein Viertel der Höhe nach oben verzahnt. Abstand 4 px.
|
||
- `n` misst ein `ResizeObserver` (`useContainerWidth`).
|
||
- Reihenfolge nach Volkscode, natürlich sortiert, wie Liste und Runde (Offene Frage 2).
|
||
- **Füllung** nach Ampel: Grün `--condition-good`, Gelb `--condition-average`, Rot `--condition-critical`. Text und Icon in `--condition-*-foreground`. Alle drei Flächen haben mindestens 3:1 gegen die Karte (4.4).
|
||
- **Inhalt:**
|
||
- oben das Zustands-Icon (16 px; `CheckCircle2`, `AlertTriangle`, `XCircle` wie `StatusLightBadge`)
|
||
- darunter der Volkscode (16 px halbfett; bis 6 Zeichen, länger mit Auslassung, voller Code im Namen)
|
||
- Bei mehr als einem Grund steht ein kleiner Zähler „2“ unten rechts in der Zelle (13 px).
|
||
- **Rand = Tage seit der letzten Durchsicht**, in Tinte (`--foreground`), innen gezeichnet, damit die Zelle gleich groß bleibt:
|
||
|
||
| Stufe | Bedeutung | ab T4 (mit `inspectionDueOn`) | vor T4 (`INSPECTION_STALE_DAYS = 14`) | Strich | Sonne |
|
||
|---|---|---|---|---|---|
|
||
| 1 frisch | alles gut | Fälligkeit mehr als 3 Tage entfernt, oder Winterruhe (`inspectionDueOn = null`) | höchstens 10 Tage her | 2 px durchgehend | 3 px |
|
||
| 2 bald fällig | bald hin | fällig heute bis in 3 Tagen | 11–14 Tage her | 4 px durchgehend | 5 px |
|
||
| 3 fällig | jetzt hin | Fälligkeit überschritten oder nie durchgesehen | mehr als 14 Tage oder nie | 6 px gestrichelt (6 4), kleines Uhr-Icon oben rechts | 7 px |
|
||
|
||
- Ohne `inspections:read` (`inspectionsVisible = false`) gibt es einen 1-px-Rand in `--input` und keine Aussage zur Durchsicht.
|
||
- Die 3-Tage-Grenze ist dieselbe wie „SOON“ in der T4-Rangfolge.
|
||
- Die Funktion `rimStepOf(row, today, inspectionsVisible)` liegt in `src/lib/honeycomb/cell-state.ts`.
|
||
- **Zustand „Winterruhe“:** Ab T4 heißt die Rand-Erklärung im Namen „Winterruhe – keine Durchsicht nötig“.
|
||
|
||
### 6.4 Bedienung
|
||
|
||
- Jede Zelle ist ein Link zur Volksseite. Tippen öffnet das Volk; es gibt kein Menü und keinen langen Druck.
|
||
- Hover (nur `pointer-fine`) hebt die Zelle mit einem 2-px-Rahmen in `--primary-ink` hervor, ohne Bewegung und ohne Größenänderung.
|
||
- Kein Ziehen, kein Zoomen. Bei vielen Völkern wächst die Wabe in die Höhe.
|
||
|
||
### 6.5 Barrierefreiheit
|
||
|
||
- Semantik: `<ul aria-label="Völker am Stand {Name}">` mit `<li><a>` je Zelle. Die Sechseck-Form ist ein `aria-hidden`-SVG im Link; Text und Icon liegen als HTML darüber.
|
||
- Name jeder Zelle (`aria-label`, beginnt mit dem sichtbaren Code, damit Sprachsteuerung funktioniert): „B3 – Achtung: Futter schwach. Letzte Durchsicht vor 16 Tagen.“, ab T4 „… Durchsicht seit 2 Tagen fällig.“
|
||
- Tab-Reihenfolge = Codereihenfolge, Zeile für Zeile.
|
||
- Zusammenfassung und Legende sind normaler Text. Die aufklappbare Liste ist die Tabellen-Alternative.
|
||
- Forced Colors: Fläche `Canvas`, Rand `CanvasText`. Die Stufen bleiben über Strichstärke und Strichelung erkennbar, der Zustand über das Icon.
|
||
|
||
### 6.6 Fokus in der Zelle
|
||
|
||
Der Link selbst hat `outline: none` als einzige erlaubte Ausnahme. Stattdessen zeichnet ein zweiter Sechseckpfad 3 px außerhalb der Zelle den Ring in `--ring` (`.comb-cell:focus-visible .comb-focus { stroke: var(--ring) }`, Breite `var(--focus-width)`). Der Wächter-Test führt diese Datei in der Ausnahmeliste.
|
||
|
||
### 6.7 Leistung
|
||
|
||
- Ein `<symbol id="comb-hex">` je Seite, jede Zelle nutzt `<use href>`. Keine neue Abhängigkeit.
|
||
- Budget: `ApiaryComb` mit allen Teilen höchstens 5 kB gzip. 100 Zellen rendern in unter 30 ms Scripting auf einem Mittelklasse-Handy (Messung mit dem React Profiler bei 4-facher CPU-Drosselung).
|
||
- Die Layout-Rechnung `combLayout(count, columns)` ist eine reine Funktion, mit `useMemo`.
|
||
|
||
### 6.8 Bewegung
|
||
|
||
Keine Animation. Ändert sich der Zustand nach einem Sync, wechselt die Füllung sofort.
|
||
|
||
## 7. Mini-Waben auf der Karte
|
||
|
||
**Frage:** Wo steht welcher Stand, und braucht dort etwas meinen Blick?
|
||
|
||
### 7.1 Marker
|
||
|
||
- `L.divIcon({ html: miniCombSvg(summary), className: "stand-marker", iconSize: [48, 52], iconAnchor: [24, 26], popupAnchor: [0, -24] })` ersetzt `L.icon` mit den PNG-Markern. Die Dateien in `public/leaflet/` werden gelöscht.
|
||
- `miniCombSvg(summary)` (`src/lib/honeycomb/mini-comb-svg.ts`, reine Funktion, liefert einen SVG-String):
|
||
- Hintergrund-Sechseck (Radius 24) in `--card` mit 2 px Rand in `--foreground`. So hebt sich der Marker von jeder Kachel ab.
|
||
- Darauf eine Rosette aus 7 Zellen (Radius 7): eine Mitte, sechs ringsum.
|
||
- Bis zu 7 Völker sind je eine Zelle, sortiert nach Ampel, das schlechteste in die Mitte. Freie Plätze sind Wachs-Umrisse (`--muted`, Rand `--input`).
|
||
- Bei mehr als 7 Völkern zeigen die Zellen die 7 schlechtesten. Darunter steht ein Zählchip „12“ (13 px fett, `--card` mit Tinten-Rand).
|
||
- Farben über `var(--condition-*)`. Weil das `divIcon` im DOM liegt, ziehen Theme und Sonne ohne Neuaufbau mit.
|
||
- Unter dem Marker steht der Standname als Chip (13 px, `--card`, Tinten-Rand), ab Zoomstufe 9. Darunter wird er ausgeblendet, damit sich nichts überlappt.
|
||
- Vor dem Laden der Übersicht zeigt der Marker eine einzelne Wachs-Zelle ohne Zahl.
|
||
|
||
### 7.2 Bedienung
|
||
|
||
- Tippen oder Enter öffnet das Popup:
|
||
- Standname
|
||
- Zusammenfassung wie in 6.2
|
||
- Knopf „Stand öffnen“ (44 px, `size="touch"`, Umriss)
|
||
- Keine Bedienung einzelner Zellen auf der Karte. Sie wären für Handschuhe zu klein.
|
||
- Popup im Token-Stil: `.leaflet-popup-content-wrapper`, `.leaflet-popup-tip` mit `--popover`/`--popover-foreground` und Tinten-Rand. Den Schließknopf `.leaflet-popup-close-button` vergrößert ein Pseudo-Element auf 44 px.
|
||
|
||
### 7.3 Barrierefreiheit und Rückfall
|
||
|
||
- `L.marker(..., { keyboard: true, title })`. Nach `add` setzt der Code `aria-label` am Marker-Element: „Stand Nordhang: 7 Völker, 1 kritisch, 1 Achtung“.
|
||
- Unter der Karte steht die Liste „Stände auf der Karte“ (`<ul>`): Name als Link, Zusammenfassung, „2 Durchsichten fällig“. Sie ist die Alternative zur Karte und hilft auch, wenn die Kacheln offline nicht laden.
|
||
- Ohne Netz: Hinweis „Die Karte braucht Internet. Die Stände stehen unten als Liste.“ (`role="status"`).
|
||
|
||
### 7.4 Dunkel und Sonne
|
||
|
||
- Dunkel: Die Kachel-Ebene bekommt `filter: brightness(0.8) contrast(1.1)` (`.dark .leaflet-tile-pane`). Keine Farbumkehr, weil invertierte Karten Wasser und Wald falsch färben.
|
||
- Sonne: Kacheln unverändert, Marker-Rand 3 px.
|
||
|
||
### 7.5 Leistung
|
||
|
||
Ein SVG-String je Stand, gemerkt nach den Ampel-Zählern. Keine neue Abhängigkeit. Leaflet bleibt per `dynamic(..., { ssr: false })` nachgeladen.
|
||
|
||
## 8. Lebenslinie des Volks
|
||
|
||
**Frage:** Wie hat sich dieses Volk entwickelt, und was kommt als Nächstes?
|
||
|
||
### 8.1 Daten
|
||
|
||
`buildLifeline(input, today)` in `src/lib/colonies/lifeline.ts` ist eine reine Funktion. Sie liefert ein `LifelineModel` mit Zeitachse, Spuren und Ereignissen. `useColonyLifeline(colonyId)` sammelt die Queries; sie nutzen dieselben Keys wie die Karten der Volksseite, also keine Doppel-Requests.
|
||
|
||
| Spur | Quelle | Key | ab T4 |
|
||
|---|---|---|---|
|
||
| Lebensbeginn | `Colony.createdAt`, `ColonyHistory.lineageAsResult` | `["colonies", id]`, `["colonies", id, "history"]` | – |
|
||
| Stärke (besetzte Waben) | `Inspection.colonyStrength`, `date` | `["colonies", id, "inspections"]` | Obergrenze 40 (T4 4.14) |
|
||
| Milben pro Tag | `VarroaMeasurement` mit `method = NATURAL_MITE_FALL` und `calculatedValue`, Dauer aus `durationMinutes` | `["colonies", id, "varroa"]` (Key wie `colony-varroa.tsx`) | `rating.light`, `rating.band.redAbove` (T4 Task 19) |
|
||
| Ampel ohne T4 | `varroaLight(rate, threshold)` (T3) | `["varroa", "threshold"]` | entfällt |
|
||
| Behandlungen | `Treatment.date`, `endDate`, `product` | `["colonies", id, "treatments"]` | – |
|
||
| Königin | `ColonyHistory.queenHistory` (Beginn, Ende), je Königin `markingColor`, `code`, `hatchYear` | `["queens", queenId]` (höchstens 5) | – |
|
||
| Ereignisse | Fütterungen, Schwarmkontrollen, Umsetzen (`apiaryHistory`), Ableger/Vereinigung (`lineage*`), Königinwechsel | vorhandene Keys | – |
|
||
| Zukunft | offene Aufgaben des Volks mit Termin in den nächsten 21 Tagen, höchstens 3 | `["tasks", …]` | `GET /colonies/:id/next-steps` → `steps[].dueOn`, `title` (höchstens 3) |
|
||
|
||
- **Einheitswechsel der Stärke:** `colonyStrength` zählt erst seit T3 besetzte Waben, vorher war es eine Skala.
|
||
- Die Konstante `STRENGTH_IN_FRAMES_SINCE` (`lifeline.ts`) ist das Rollout-Datum von T3 Task 9. Es wird beim Bau aus dem Deploy-Protokoll eingetragen.
|
||
- Ältere Werte erscheinen nicht in der Kurve, nur in der Tabelle mit der Einheit „Skala (alt)“.
|
||
- So vermischt die Kurve keine Einheiten.
|
||
- **Rechte:** Fehlt ein Leserecht (403), fällt die Spur weg, ohne Fehlermeldung. Das gilt für `inspections:read` (Stärke), `varroa:read` (Milben), `treatments:read` (Behandlungen) und `queens:read` (Königin). Die Kopfzeile nennt nur vorhandene Spuren.
|
||
|
||
### 8.2 Aufbau
|
||
|
||
Senkrechte Zeitleiste, oben die Gegenwart, darüber eine schmale Zukunftszone. Handy, 328 px:
|
||
|
||
```
|
||
Lebenslinie Stärke 0 ─5─10─15─20 Milben/Tag ┆10
|
||
┌──────┬────┬────┬────────────────────────────┬──────────────┐
|
||
│ │ │ ⬡ │ Durchsicht mit Schwarmk. · 15.05. (Zukunft, gestrichelt)
|
||
│ heute│━━━━│━━━━│━━━━━━━━━━━━━━━━━━━━━━━━━━━━│━━━━━━━━━━━━━━│
|
||
│ Mai │ ┃ │ ● │ ●9 │ ▇▇▇ 2,1 │
|
||
│ │ ┃ │ │ ╱ │ │
|
||
│ │ ┃ │ 🍴 │ ●6 │ │
|
||
│ Apr │ ┃ │ │ ╱ │ ▇▇▇▇▇▇ 8,4 ▲ │
|
||
│ │ ◉ │ 👑 │ ●4 Königin Q-12 (blau) │ │
|
||
│ Mär │ │ │ │░░░ Behandlung│
|
||
└──────┴────┴────┴────────────────────────────┴──────────────┘
|
||
Monat Königin Ereignisse Stärke (besetzte Waben) Milben pro Tag
|
||
● Q-12 · Schlupf 2025 · blau · seit 20.04.2026
|
||
[ Ganzes Leben zeigen ] [ Als Tabelle ▾ ]
|
||
```
|
||
|
||
Spalten (Handy / Desktop):
|
||
|
||
| Spalte | Breite | Inhalt |
|
||
|---|---|---|
|
||
| Monat | 44 px | Monatsnamen (13 px), Jahreswechsel fett |
|
||
| Königin | 16 px | Schiene 4 px in Zeichenfarbe mit 1 px Tinten-Rand für die Amtszeit. Zu Beginn ein Punkt (Radius 6, 2 px Ring in `--foreground`). Ohne Farbe: graue gestrichelte Schiene. |
|
||
| Ereignisse | 24 px | Icons 16 px aus `AREAS` in einer Kreiskachel 20 px. Am selben Tag nur ein Icon mit Zähler. |
|
||
| Stärke | Rest (≥ 160 px) | Achse 0 bis `max(20, aufgerundet auf 5)` Waben, Raster bei 5er-Schritten gepunktet. Linie in `--foreground`, 2 px. Punkte (Radius 4) je Durchsicht. Fläche unter der Linie `--primary` 18 % (Sonne ohne Fläche). Lücke über 45 Tage: Linie unterbrochen, gestrichelte Verbindung, im Text „keine Durchsicht“. |
|
||
| Milben | 64 px (Desktop 96) | Stufenband: je Messung ein Balken über ihre echte Liegezeit (1–7 Tage, mindestens 4 px hoch), Breite ∝ Milben/Tag bis zum Doppelten der Schwelle (darüber ▶). Farbe nach Ampel (`--condition-good/-average/-critical`), dazu Wert als Text bei Gelb, Rot und der letzten Messung. Schwelle: vor T4 eine gestrichelte senkrechte Linie mit Wert im Kopf; ab T4 je Balken ein Strich bei `band.redAbove`, weil die Grenze mit der Jahreszeit wechselt. Behandlungen: schraffierter Hintergrund (`--chart-4` 30 %, 45°-Streifen) von `date` bis `endDate`, Icon `Syringe` in der Ereignisspalte. |
|
||
|
||
- **Zeitmaß:** 1,6 px je Tag (etwa 48 px je Monat).
|
||
- **Standardausschnitt:** die letzten 12 Monate (höchstens seit Lebensbeginn) plus 21 Tage Zukunft.
|
||
- „Ganzes Leben zeigen“ schaltet auf die gesamte Lebenszeit. Der Knopftext wechselt zu „Letzte 12 Monate“ (`aria-pressed`).
|
||
- **Heute:** waagerechte Linie in `--foreground`, 2 px, über alle Spalten, beschriftet „heute“.
|
||
- **Zukunft** (über heute):
|
||
- Höchstens drei Schritte als hohle Sechsecke in der Ereignisspalte, mit Titel und Datum in einer Zeile in der Stärke-Spalte.
|
||
- Die Zukunftszone ist gestrichelt umrandet.
|
||
- Ab T4 sind das `next-steps`, vorher offene Aufgaben.
|
||
- Der Hinweis `withdrawalUntil` (T4) erscheint als Satz unter der Grafik: „Wartezeit bis 20.08.“
|
||
- **Wertbeschriftung:** Die Stärke-Kurve beschriftet nur den letzten Wert, den höchsten und den niedrigsten Wert im Ausschnitt sowie Punkte, die mindestens 24 px Abstand haben. So überlappen keine Zahlen.
|
||
|
||
### 8.3 Platzierung und Bedienung
|
||
|
||
- **Volksseite:** eigene Karte „Lebenslinie“ direkt unter der T4-Karte „Als Nächstes“, auf dem Desktop in der rechten Spalte oben. Der Hauptknopf der Seite bleibt „Durchsicht erfassen“.
|
||
- **Bedienung:** nur zwei Knöpfe, „Ganzes Leben zeigen“ und „Als Tabelle“ (`aria-expanded`). Punkte und Balken sind nicht antippbar; sie wären zu klein für Handschuhe. Details stehen in der Tabelle und in den bestehenden Karten (Durchsichten, Varroa, Behandlungen).
|
||
- **Leer:** Ohne Durchsicht und Messung steht dort „Noch keine Durchsicht. Die Lebenslinie wächst mit jeder Durchsicht.“ und der Knopf „Durchsicht erfassen“ als Umriss. Königin und Ereignisse erscheinen trotzdem, falls vorhanden.
|
||
- **Laden:** ein Skelett-Block in voller Höhe des Ausschnitts, kein Spinner.
|
||
- **Fehler:** `QueryState`-Muster mit „Erneut versuchen“.
|
||
|
||
### 8.4 Barrierefreiheit
|
||
|
||
- `<figure>` mit `<svg role="img" aria-labelledby="{titleId} {descId}">`.
|
||
- `<title>`: „Lebenslinie {Code}“.
|
||
- `<desc>` (aus dem Modell erzeugt, höchstens 4 Sätze):
|
||
1. „Volk B3 seit 12.03.2025.“
|
||
2. „Stärke zuletzt 9 Waben am 02.10., höchstens 14 Waben im Juli.“
|
||
3. „Milben zuletzt 2,1 pro Tag am 28.09. – Gut.“
|
||
4. „Königin Q-12, Schlupf 2025, blau, seit 20.04.2026. 2 Behandlungen in diesem Ausschnitt.“
|
||
- „Als Tabelle“ klappt eine `<table>` auf: Spalten Datum | Ereignis | Wert. Je Durchsicht „Durchsicht · 9 besetzte Waben · 5 Brutwaben“, je Messung „Varroa · 8,4 Milben/Tag · Achtung“, je Behandlung „Behandlung Oxuvar · 01.09.–14.09.“, dazu Königin, Fütterung, Umsetzen und Ableger. Die Tabelle stammt aus demselben `LifelineModel` wie die Grafik und hat dieselbe Zeitspanne.
|
||
- Zeichenfarbe der Königin immer zusätzlich als Wort („blau“).
|
||
- Forced Colors: Linie und Balken in `CanvasText`, Ampel über Text und Schraffur.
|
||
|
||
### 8.5 Leistung und Bewegung
|
||
|
||
- Ein SVG, höchstens 600 Knoten für drei Jahre Daten (etwa 150 Durchsichten).
|
||
- `buildLifeline` und das Rendern bleiben unter 50 ms Scripting bei 4-facher CPU-Drosselung.
|
||
- Komponente höchstens 8 kB gzip, keine Abhängigkeit.
|
||
- Keine Animation, kein Aufbau-Effekt.
|
||
|
||
## 9. Bienenjahr-Rad auf dem Dashboard
|
||
|
||
**Frage:** Wo stehen wir im Bienenjahr, und welches Arbeitsfenster kommt?
|
||
|
||
### 9.1 Daten
|
||
|
||
- **Saisonabschnitte und Kalender:**
|
||
- Vor T4 aus `src/lib/season/season-defaults.ts`. Das sind exakt die T4-Standardwerte (`PHENOLOGY.calendarFallback`: Salweide 03-20, Kirsche 04-15, Apfel 04-28, Holunder 05-30, Linde 06-20, Trachtende 08-01, Herbst 09-15, Winter 11-15; `swarmSeason` Kirsche bis Linde; `SEASON_AUTOPILOT.winterVarroaWindow` 11-15 bis 12-20).
|
||
- Ab T4 kommen sie aus dem Server, damit Änderungen in „Verwaltung > Automatisierung“ auch im Rad ankommen.
|
||
- **Additive Erweiterung von `GET /autopilot/today`** (T5-Task am Backend, Recht `colonies:read` wie bisher, keine Geheimnisse):
|
||
|
||
```ts
|
||
interface AutopilotToday {
|
||
// … unverändert aus T4 Task 15 …
|
||
seasons: { apiaryId: string; apiaryName: string; segment: SeasonSegmentKey; phase: PhenologyPhaseKey | null;
|
||
phaseSource: PhaseSourceKey | null;
|
||
segmentSince: string; // neu, aus SeasonState
|
||
reportedOn: string | null; // neu
|
||
note: SeasonNote }[]; // neu: 'NO_COORDINATES' | 'WEATHER_GAPS' | 'WEATHER_STALE' | null
|
||
seasonCalendar: { // neu, aus readRule(PHENOLOGY) und readRule(SEASON_AUTOPILOT)
|
||
calendarFallback: Record<PhenologyPhaseKey, string>; // 'MM-DD'
|
||
swarmSeason: { from: PhenologyPhaseKey; until: PhenologyPhaseKey };
|
||
winterVarroaWindow: { from: string; to: string };
|
||
};
|
||
}
|
||
```
|
||
|
||
- Gebaut in `NextStepsService.today` aus `SeasonService.statesFor` (hat `segmentSince` schon) und `readRule`.
|
||
- Fehlen die Felder (älteres Backend), nutzt das Frontend `season-defaults.ts`.
|
||
- **Bezugsstand:**
|
||
- Das Rad zeigt den Abschnitt, in dem die meisten aktiven Stände sind.
|
||
- Bei Gleichstand gilt der weiter fortgeschrittene Abschnitt. Lieber eine Durchsicht zu früh als einen Schwarm verpasst (T4 7.3).
|
||
- Abweichende Stände nennt die dritte Zeile im Zentrum: „Südhang: noch Frühjahr“. Bei mehr als einem Stand steht dort „2 Stände weichen ab – siehe Tabelle“.
|
||
- **Aufgaben:** offene Aufgaben mit Termin aus der bestehenden Dashboard-Query `["tasks", "dashboard"]`.
|
||
- Je Kalenderwoche ein Punkt.
|
||
- Überfällige Aufgaben bilden einen eigenen Punkt kurz vor dem Zeiger.
|
||
- Vorschläge (T4) zählt das Rad nicht. Sie haben ihre eigene Liste.
|
||
- **Modell:** `buildYearWheel(input, today)` in `src/lib/season/year-wheel.ts` (reine Funktion):
|
||
|
||
```ts
|
||
interface YearWheelModel {
|
||
year: number; today: string;
|
||
segments: { key: SeasonSegmentKey; from: string; to: string; source: 'REPORT' | 'GTS' | 'CALENDAR'; current: boolean; estimated: boolean }[];
|
||
windows: { key: 'TRACHT' | 'VARROA_SUMMER' | 'EINWINTERUNG' | 'VARROA_WINTER'; from: string; to: string }[];
|
||
taskWeeks: { weekStart: string; count: number }[]; overdueCount: number;
|
||
reference: { apiaryId: string; apiaryName: string } | null;
|
||
deviations: { apiaryName: string; segment: SeasonSegmentKey }[];
|
||
}
|
||
```
|
||
|
||
- Fenster:
|
||
- Tracht = Salweide bis Trachtende
|
||
- Varroa Sommer = Trachtende bis Herbst
|
||
- Einwinterung = Herbst bis Winter
|
||
- Varroa Winter = `winterVarroaWindow`
|
||
|
||
Die Fenster liegen nacheinander und überlappen nicht.
|
||
- Der aktuelle Abschnitt beginnt bei `segmentSince` (gemeldet, geschätzt oder Kalender).
|
||
- Vergangene und künftige Grenzen sind Kalenderwerte mit `estimated = true` und werden gestrichelt gezeichnet.
|
||
- Ist ein Kalenderdatum schon vorbei, der Abschnitt aber noch nicht erreicht (späte Blüte), beginnt der nächste Abschnitt im Rad „ab morgen, noch offen“.
|
||
- Die Winterruhe über den Jahreswechsel wird als zwei Bögen gezeichnet.
|
||
|
||
### 9.2 Aufbau
|
||
|
||
Feste Größe 320 × 320 px. Unter 328 px Containerbreite skaliert das Rad mit, Text bleibt dabei mindestens 13 px.
|
||
|
||
```
|
||
J
|
||
D · ┃ · F Monatsinitialen r=150 (13 px)
|
||
N ╭────┃────╮ M Außenring r=124, 26 px: Saisonabschnitte
|
||
╭─╯ ╭──┃──╮ ╰─╮ aktuell: Honig + Tinten-Rand, sonst --muted
|
||
O │ ╭─╯ ╰─╮ │ A Innenring r=96, 10 px: Tracht / Varroa ▨ / Einwinterung
|
||
│ │ HERBST │ │ Aufgabenpunkte r=78
|
||
S │ │ seit 15.09.·Kalender │ M Zentrum r<62: drei Zeilen Text
|
||
│ │ Einwinterung bis ~15.11.│
|
||
╰─╮ ╰─────╯ ╭─╯ Zeiger: von r=66 bis r=140, 3 px Tinte,
|
||
A ╰─────⬡───╯ J am Ende eine Wabenzelle (Honig, Tinten-Rand)
|
||
J J
|
||
▬ Tracht ▨ Varroa-Behandlung ▬ Einwinterung ● Aufgabe ◉ überfällig
|
||
Jetzt: Herbst seit 15.09. (Kalender) · Danach: Winterruhe ab ca. 15.11.
|
||
[ Als Tabelle ▾ ] Zum Kalender →
|
||
```
|
||
|
||
- **Winkel:** Januar oben, im Uhrzeigersinn. `winkel(datum) = 360° × (Tag im Jahr − 1) / Tage im Jahr − 90°`; Schaltjahre werden berücksichtigt.
|
||
- **Außenring:**
|
||
- Segmente mit 2 px Lücke in `--card`, Kontur 1,5 px in `--input`.
|
||
- Das aktuelle Segment hat eine Honigfläche und 2 px Rahmen in `--foreground`.
|
||
- Geschätzte Grenzen sind gestrichelt.
|
||
- Keine Beschriftung im Ring: Bei 26 Tagen Frühjahr wäre der Bogen zu kurz für lesbare Schrift. Namen stehen im Zentrum, in der Zeile darunter und in der Tabelle.
|
||
- **Innenring:**
|
||
- Tracht in `--chart-3` (voll)
|
||
- Varroa in `--chart-4` mit 45°-Schraffur (zwei Fenster)
|
||
- Einwinterung in `--chart-5` (voll)
|
||
|
||
Muster plus Legende, damit die Fenster auch ohne Farbsehen unterscheidbar sind.
|
||
- **Aufgabenpunkte:**
|
||
- Radius 3 px (1 Aufgabe), 4,5 px (2–3) bzw. 6 px (4 und mehr), in `--foreground`.
|
||
- Überfällige: ein Punkt in `--condition-critical` mit 2 px Tinten-Ring, 4° vor dem Zeiger.
|
||
- **Zentrum:**
|
||
1. Abschnitt (22 px, Space Grotesk halbfett)
|
||
2. „seit {Datum} · {Quelle}“ (14 px; Quelle aus `PHASE_SOURCE_LABELS`: „gemeldet am 18.04.“, „geschätzt“, „Kalender“; bei `note` zusätzlich „Wetterdaten lückenhaft“ bzw. „ohne Koordinaten“)
|
||
3. das laufende Arbeitsfenster mit Ende, oder die Abweichung eines Stands
|
||
- **Zeiger:** Linie in `--foreground` mit der Wabenzelle als Kappe. Er steht auf heute und bewegt sich nie animiert.
|
||
- **Darunter:** die Legende (eine Zeile, 13 px) und der Satz „Jetzt … · Danach …“.
|
||
- **Karte:** Überschrift „Bienenjahr“ (h2). Rechts steht der Textlink „Zum Kalender“ (44 px Trefferfläche) als einzige Aktion; „Als Tabelle“ ist eine Aufklapp-Steuerung.
|
||
|
||
### 9.3 Dashboard nach T5
|
||
|
||
Reihenfolge von oben nach unten:
|
||
|
||
1. **Kopf:** Gruß als `h1` in Tinte auf dem Seitenhintergrund und die Datumszeile, ohne Honigbanner und ohne Weiß auf Honig. Die Honigfarbe gehört allein dem Hauptknopf.
|
||
2. **„Als Nächstes“** (T4 aus `/autopilot/today`, offline aus Aufgaben): einziger Honigknopf der Seite.
|
||
3. **„Außerdem heute“.**
|
||
4. **T4-Karte „Durchsicht fällig“** je Stand.
|
||
5. **„Im Blick behalten“** (Meldungen).
|
||
6. **„Bienenjahr“** (Rad). Es ersetzt die Kacheln „Überblick“ (Zähler für Stände, Völker, Königinnen, Aufgaben, Honigchargen, Bestand). Die Zähler entfallen ersatzlos:
|
||
- Die Bereiche sind über die Navigation erreichbar.
|
||
- „unter Minimum“ steht schon als Meldung `LOW_STOCK` in „Im Blick behalten“.
|
||
- Die T4-Chips „Saison je Stand“ ziehen in das Zentrum und die Tabelle des Rads.
|
||
|
||
### 9.4 Barrierefreiheit
|
||
|
||
- `<svg role="img">` mit `<title>` „Bienenjahr {Jahr}“ und `<desc>`: „Heute, 14.10.: Herbst seit 15.09. nach Kalender. Einwinterung läuft bis etwa 15.11. Danach Varroa-Winterbehandlung 15.11. bis 20.12. Offene Aufgaben mit Termin: 3 in den nächsten 4 Wochen, 1 überfällig.“
|
||
- „Als Tabelle“ öffnet zwei Tabellen:
|
||
- Abschnitt | von | bis | Quelle (je Stand eine Spalte, wenn Stände abweichen)
|
||
- Fenster | von | bis
|
||
|
||
Dazu kommt die Zeile „Aufgaben je Woche“ für die nächsten 4 Wochen.
|
||
- Keine interaktiven Teile im SVG. Die Punkte wären zu klein (eine Woche entspricht etwa 15 px Bogen).
|
||
|
||
### 9.5 Leistung und Bewegung
|
||
|
||
- Etwa 150 SVG-Knoten, Rechnung in `useMemo`, höchstens 6 kB gzip, keine Abhängigkeit.
|
||
- Keine Animation, auch nicht bei „Voll“. Der Zeiger springt nicht und dreht sich nicht.
|
||
|
||
## 10. Baukasten durchsetzen
|
||
|
||
### 10.1 Bausteine
|
||
|
||
| Baustein | Datei | ersetzt | Stellen heute |
|
||
|---|---|---|---|
|
||
| Auswahlgruppe `ChoiceGroup` | `components/form/choice-group.tsx` (bleibt) | Ausgang des Winters (`winter-check-dialog.tsx`, Knöpfe mit `aria-pressed`), Linien-Ausrichtung im Etiketten-Designer (zwei Knöpfe), Bewegungsstufe im Profil (native Radio-Karten) | 3; die übrigen der 7 aus der Analyse vom 12.10. hat Paket 0 schon umgestellt |
|
||
| Checkbox `Checkbox` + `CheckboxField` | `components/ui/checkbox.tsx` (umgebaut), `components/form/checkbox-field.tsx` (neu) | `ToggleChip` (4 Dateien), native `type="checkbox"` (9 Stellen: Ernte-Dialog, Webhook anlegen/bearbeiten ×3, Aufgabenvorlage, Etiketten-Designer ×2, Aufgabenliste, `harvest-select-field`), Base-UI-Checkbox (3 Dateien), `honey-check` (Heute-Liste) | 4 Varianten, 17 Stellen |
|
||
| Tabs `Tabs` | `components/ui/tabs.tsx` (umgebaut) | `TabSwitcher` (2 Seiten), `ActiveHistoryTabs` (9 Seiten, wird Vorlage auf `Tabs`), Statistik (`ui/tabs`) | 3 Varianten, 12 Stellen |
|
||
| Plus/Minus `NumberStepper` | `components/form/number-stepper.tsx` (bleibt) | ganzzahlige Zählfelder am Stand (10.5) | 6 Felder |
|
||
| Fokus | `globals.css` | 4 Fokus-Varianten in Komponenten | 44 Stellen |
|
||
| Bereichs-Icon `AreaIcon` | `components/area-icon.tsx` (neu) | weiße Icons auf Verlauf in `PageHeader`, `DetailHeader`, `EntityCard` | 3 Komponenten, 10 `gradient`-Props |
|
||
| Markenzeichen `BrandMark` | `components/brand-mark.tsx` (neu) | `Hexagon` auf Verlauf in Sidebar, Kopfzeile, Login, Herkunft | 4 |
|
||
|
||
Der Wächter-Test `src/styles/baukasten-guard.spec.ts` prüft die Regeln aus 10.7.
|
||
|
||
### 10.2 Auswahlgruppe
|
||
|
||
- **Nicht gewählt:** Fläche `--card`, Rahmen 1 px `--input` (3,9:1), Text 16 px.
|
||
- **Gewählt (Antwort):** Fläche `--primary`, Text `--primary-foreground` halbfett, Rahmen 2 px `--foreground`, Haken-Icon (16 px) vor dem Label.
|
||
- **Gewählt, „Nicht geprüft“ (`null`):** Fläche `--muted`, Rahmen 2 px gestrichelt `--foreground`, Strich-Icon. Damit bleibt der T3-Gedanke „Nicht geprüft ist gedämpft“, ist aber erkennbar gewählt.
|
||
- **Skalen** (`RatingScale`): Die Ton-Fläche (`selectedClassName`) bleibt. Rahmen und Haken kommen dazu; der Haken steht vor der Zahl („✓ 4“).
|
||
- **Neues Prop `appearance`:**
|
||
- `"buttons"` (Standard, wie heute Raster)
|
||
- `"cards"`: Option mit Label (16 px) und Beschreibung (14 px), volle Breite, mindestens 56 px hoch; für Darstellung, Bewegung und Ausgang des Winters
|
||
- **Neues Feld `ChoiceOption.icon?`:** Lucide-Icon vor dem Label, z. B. beim Ausgang des Winters.
|
||
- **Tastatur** bleibt wie heute: ein Tab-Halt, Pfeiltasten, Home und End.
|
||
- **Toolbar-Umschalter** im Etiketten-Designer (fett, kursiv) sind keine Auswahlgruppe. Sie bekommen `aria-pressed` und `aria-label` am bestehenden `Button` (Prop `pressed`). Ausnahme im Wächter.
|
||
- **Kalender:** Die Tageswahl im Monatsraster bleibt ein Raster aus Tag-Knöpfen mit `aria-pressed` (Ausnahme im Wächter). Sie bekommt nur den globalen Fokus und die neue Auswahl-Optik.
|
||
|
||
### 10.3 Checkbox
|
||
|
||
- `ui/checkbox.tsx` (Base UI `Checkbox`):
|
||
- Kästchen 20 px, Rahmen 2 px `--input`, Radius 6 px.
|
||
- Gewählt: Fläche `--primary`, Rahmen `--foreground`, Haken 14 px in `--primary-foreground`, Strichstärke 3.
|
||
- `indeterminate`: Strich-Icon.
|
||
- Deaktiviert: 50 % Deckkraft, Hinweistext am Feld statt nur Grau.
|
||
- `CheckboxField` mit `label`, `description?`, `checked`, `onCheckedChange`, `disabled?`, `appearance`:
|
||
- `"row"` (Standard): ganze Zeile klickbar, mindestens 44 px (in Sheets 56 px über `size="sheet"`), Text 16 px
|
||
- `"tile"`: umrandete Kachel wie `ToggleChip`; gewählt mit Honig-Tönung und 2-px-Tinten-Rand; Sonne: `--card` mit Tinten-Rand
|
||
- `"task"`: die Abhak-Zelle der Heute-Liste; die `honey-check`-Animation bleibt als einzige „Moment“-Bewegung, jetzt auf dem Base-UI-Primitiv statt eines eigenen `role="checkbox"`
|
||
- `ToggleChip` wird nach der Umstellung gelöscht.
|
||
|
||
### 10.4 Tabs
|
||
|
||
- `ui/tabs.tsx` mit einer Variante `segment` (Standard):
|
||
- Leiste in `--muted`, Innenabstand 4 px.
|
||
- Reiter 44 px (`pointer-fine`: 36 px), Text 16 px.
|
||
- Aktiv: Fläche `--card`, Text `--foreground` halbfett, unten ein 3-px-Strich in `--primary-ink`. Der Zustand zeigt sich also über Fläche, Gewicht und Strich, nicht nur über Farbe.
|
||
- Base UI liefert `role="tab"`/`tabpanel`, `aria-controls` und Pfeiltasten.
|
||
- Die Variante `line` entfällt; die Statistik nutzt `segment`.
|
||
- `ActiveHistoryTabs` wird eine Vorlage auf `Tabs` (Props `value`, `onValueChange`, `activeCount`, `historyCount`, `children` je Panel). Die 9 Listen legen ihre Liste in das Panel. `TabSwitcher` wird gelöscht; die beiden Einstellungsseiten nutzen `Tabs` direkt.
|
||
|
||
### 10.5 Plus/Minus
|
||
|
||
- Regel: Ein ganzzahliger Zählwert, der typischerweise unter 100 liegt und am Stand erfasst wird, nutzt `NumberStepper`. Messwerte mit Komma (kg, Liter, %) und Einstellungswerte am Schreibtisch nutzen `Input inputMode="decimal"` bzw. `"numeric"`.
|
||
- Umstellung, beim Bau je Feld bestätigen:
|
||
- Besetzte Wabengassen in der Einwinterung (`winter-seams`)
|
||
- Milbenzahl in `varroa-edit-dialog` (wie im T3-Neuformular)
|
||
- Weiselzellen in Schwarmkontrolle neu und bearbeiten
|
||
- Entnahme und gezählter Bestand in `stock-card`
|
||
- Startposition im Etikettendruck
|
||
- Bleibt Eingabefeld:
|
||
- Wartezeit in Tagen (Einstellwert)
|
||
- Schlupfjahr (Jahreszahl)
|
||
- Mengen in Rohstoffen und Herstellung (Gramm)
|
||
- MFA-Codes
|
||
- Spalten und Zeilen im Etiketten-Designer
|
||
- Werte in Aufgabenvorlagen und Regeln
|
||
|
||
### 10.6 Fokus für eigene Bedienelemente
|
||
|
||
Alle eigenen Bedienelemente nehmen den globalen Fokus aus 4.6:
|
||
- `ChoiceGroup`, `CheckboxField`, `NumberStepper`
|
||
- Tage im Kalender
|
||
- `honey-check`
|
||
- Wabenzelle (eigener Pfad, 6.6)
|
||
- Leaflet-Marker
|
||
- Links in Zeilen (`ApiaryColoniesCard`, `TodayRow`)
|
||
|
||
### 10.7 Wächter-Regeln (`baukasten-guard.spec.ts`)
|
||
|
||
Der Test durchsucht `src/**/*.tsx` ohne `*.spec.tsx`. Ausnahmen stehen als Liste mit Begründung im Test.
|
||
|
||
| Regel | Ausnahmen |
|
||
|---|---|
|
||
| kein `role="radio"`, `role="radiogroup"`, `type="radio"` außerhalb von `choice-group.tsx` | – |
|
||
| kein `role="checkbox"`, `type="checkbox"` außerhalb von `ui/checkbox.tsx` | – |
|
||
| kein `role="tablist"`, `role="tab"` außerhalb von `ui/tabs.tsx` | – |
|
||
| `aria-pressed` nur in `ui/button.tsx` (Prop `pressed`) und `calendar/page.tsx` | Kalender-Tage |
|
||
| kein `ring-ring/50`, kein `outline-none` | `honeycomb-cell.tsx` (6.6) |
|
||
| kein `text-primary` ohne `-foreground`/`-ink` | – |
|
||
| kein `gradient-` und kein `text-white` | `herkunft/[lot]/page.tsx` nur für das Foto-Overlay, falls nötig |
|
||
| kein `dark:` | `apiary-map.tsx` (Kachel-Filter, nur in CSS) |
|
||
| keine Schriftgröße unter 13 px (`text-[10px]`, `text-[11px]`, `text-[12px]`) | – |
|
||
| `PageHeader`, `DetailHeader`, `EntityCard` ohne Prop `gradient` | – (Typfehler) |
|
||
|
||
### 10.8 Migrationsreihenfolge (Seiten brechen nie)
|
||
|
||
Jeder Schritt ist ein eigener, grüner Commit des Orchestrators. Lint, Typecheck, `vitest run` und `next build` laufen nach jedem Schritt.
|
||
|
||
1. **Tokens additiv:**
|
||
- Neue Tokens und Varianten in `globals.css` ergänzen (`-ink`, `area-*`, `queen-*`, `--destructive-foreground`, Sonne-Sätze, `pointer-*`, `sun`). Bestehende Werte bleiben noch.
|
||
- `contrast.spec.ts` prüft schon die neuen Paare.
|
||
2. **Darstellung:**
|
||
- Appearance-Modul und Inline-Skript.
|
||
- Profil-Karte „Darstellung“ und Schnellschalter.
|
||
- `next-themes` raus, Toaster umgestellt.
|
||
- Dunkel ist ab hier erreichbar, aber noch mit alten Werten. Darum bleibt der Schalter „Dunkel“ bis Schritt 4 hinter einem Entwicklungs-Flag (`NEXT_PUBLIC_APPEARANCE_DARK=1`).
|
||
3. **Codemod Farben** (ein Skript `scripts/codemod-t5-colors.mjs`, Ergebnis per Diff geprüft):
|
||
- `text-primary` → `text-primary-ink`, `text-warning` → `text-warning-ink`
|
||
- Abzeichen-Klassen auf `-ink`
|
||
- `border-primary` bei Auswahl → `border-foreground`
|
||
- Die Honig-Fläche bleibt `bg-primary`.
|
||
4. **Tokenwerte umstellen:**
|
||
- Werte aus 4.2 einsetzen, Verläufe entfernen.
|
||
- `ui/button` Standard ohne Verlauf, `dark:`-Klassen aus `ui/*` entfernen.
|
||
- Der Wächter `contrast.spec.ts` wird ab hier hart (alle vier Sätze).
|
||
- Das Entwicklungs-Flag aus Schritt 2 entfällt.
|
||
5. **Fokus und Größen:**
|
||
- Globale Fokusregel.
|
||
- Entfernen der Komponenten-Fokusklassen (Codemod), `sm:h-*` → `pointer-fine:h-*`, Schriftgrößen aus 4.5.
|
||
6. **`AREAS` und `AreaIcon`:**
|
||
- `nav-config.ts`, `quick-actions.ts`, `PageHeader`, `DetailHeader`, `EntityCard` (Prop `area` statt `gradient`), `BrandMark`, Icon-Abweichungen aus 2.2.
|
||
- Ist T4 Task 17 gemergt: `INTENT_ICONS` aus `AREAS`.
|
||
7. **Auswahlgruppe:** neue Optik, `appearance="cards"`, die drei Umstellungen.
|
||
8. **Checkbox:** `Checkbox` umbauen, `CheckboxField` neu; dann je Datei umstellen (Formulare zuerst, dann Einstellungen, zuletzt `honey-check`). `ToggleChip` löschen.
|
||
9. **Tabs:** `ui/tabs` umbauen, `ActiveHistoryTabs` als Vorlage, die 9 Listen und 2 Einstellungsseiten umstellen. `TabSwitcher` löschen.
|
||
10. **Plus/Minus:** Felder aus 10.5.
|
||
11. **Wächter:** `baukasten-guard.spec.ts` wird hart.
|
||
12. **Manifest und Icons** (12), Service-Worker-Version.
|
||
13. **T5b** (Abschnitte 6–9):
|
||
- Wabe auf der Stand-Seite, dann Bienenstände-Liste
|
||
- Marker
|
||
- Lebenslinie
|
||
- Backend-Zusatz `/autopilot/today`, dann Rad und Dashboard-Umbau
|
||
|
||
Schritte 1–5 berühren viele Dateien mechanisch. Sie laufen in einem kurzen Fenster, in dem keine anderen Frontend-Tasks offen sind (15).
|
||
|
||
## 11. Icon und Farbe je Bereich
|
||
|
||
Quelle ist `src/lib/areas.ts`:
|
||
|
||
```ts
|
||
export type AreaTone = 'betrieb' | 'erfassung' | 'arbeit' | 'ernte' | 'neutral';
|
||
export interface Area { key: AreaKey; label: string; icon: LucideIcon; tone: AreaTone; href?: string }
|
||
export const AREAS: Readonly<Record<AreaKey, Area>>;
|
||
```
|
||
|
||
- `AreaIcon({ area, size })` zeichnet das Icon in einer Wabenzelle (Sechseck, 40 px; in Listen 32 px).
|
||
- Die Zelle ist mit dem Bereichston in 14 % getönt und hat 1 px Rand im Ton; das Icon steht im Ton. Sonne: Fläche `--card`, Rand 2 px.
|
||
- Die Navigation bleibt neutral (Icons in `--muted-foreground`, aktiv Honig). Bunte Navigationslisten wären Unruhe.
|
||
- Der Ton erscheint nur in:
|
||
- `AreaIcon` (Seitenkopf, Detailkopf, Karten)
|
||
- im „+ Neu“-Sheet
|
||
- bei den Ereignis-Icons der Lebenslinie
|
||
- bei den Absichts-Icons der T4-Vorschläge
|
||
|
||
**Regel:** Ein Bereichston ist nie eine Zustandsfarbe. Rot, Grün und Gelb der Ampel sowie `--destructive` und `--warning` sind für Zustände reserviert.
|
||
|
||
| Bereich | Schlüssel | Icon (lucide) | Ton | Hinweis |
|
||
|---|---|---|---|---|
|
||
| Start | `dashboard` | `LayoutDashboard` | neutral | |
|
||
| Suche | `search` | `Search` | neutral | |
|
||
| Bienenstände | `apiaries` | `MapPin` | betrieb | auch Kartenansicht |
|
||
| Völker | `colonies` | `Layers` | betrieb | Beute = gestapelte Zargen; das Sechseck ist der Marke vorbehalten |
|
||
| Königinnen | `queens` | `Crown` | betrieb | bisher Salbei-Verlauf von Hand |
|
||
| Überwinterung | `winter` | `Snowflake` | betrieb | |
|
||
| Pflanzenentwicklung (T4b) | `phenology` | `Flower2` | betrieb | |
|
||
| Durchsicht | `inspections` | `ClipboardCheck` | erfassung | |
|
||
| Varroa | `varroa` | `Bug` | erfassung | |
|
||
| Schwarmkontrolle | `swarm-control` | `Sprout` | erfassung | bleibt, weil schon gelernt (T3) |
|
||
| Behandlung | `treatments` | `Syringe` | erfassung | |
|
||
| Fütterung | `feedings` | `Utensils` | erfassung | bleibt, weil schon gelernt (T3) |
|
||
| Aufgaben | `tasks` | `ListTodo` | arbeit | |
|
||
| Kalender | `calendar` | `CalendarDays` | arbeit | bisher Himmel-Verlauf von Hand |
|
||
| Vorschläge (T4) | `suggestions` | `Lightbulb` | arbeit | wie T4 Task 17 |
|
||
| Meldungen | `notifications` | `Bell` | arbeit | |
|
||
| Ernten | `harvests` | `Scissors` | ernte | Detailseite bisher `Boxes` |
|
||
| Schleuderungen | `extractions` | `FlaskConical` | ernte | Neu-Seite bisher `Droplet` |
|
||
| Honigchargen | `honey-batches` | `Droplet` | ernte | |
|
||
| Abfüllungen | `bottling` | `Package` | ernte | |
|
||
| Produkte | `products` | `ShoppingBag` | ernte | |
|
||
| Rohstoffe | `raw-materials` | `Boxes` | ernte | |
|
||
| Herstellungschargen | `production-batches` | `Factory` | ernte | |
|
||
| Lager | `storage` | `Warehouse` | ernte | bisher zusätzlich `Package` |
|
||
| Inventar | `equipment` | `Wrench` | ernte | bisher Salbei oder Himmel |
|
||
| Statistik | `statistics` | `BarChart3` | neutral | |
|
||
| Benutzer & Rollen | `users-roles` | `Users` | neutral | |
|
||
| Automatisierung | `automation` | `Zap` | neutral | |
|
||
| Etikettenvorlagen | `label-templates` | `Tag` | neutral | bisher Himmel |
|
||
| Backup | `backup` | `Database` | neutral | |
|
||
| Audit-Log | `audit-log` | `History` | neutral | bisher Salbei |
|
||
| Profil | `profile` | `UserRound` | neutral | bisher Salbei |
|
||
|
||
- Eine Seite, die einen anderen Bereich nur erwähnt (z. B. die Schleuderung in der Honigcharge), darf dessen Icon tragen. Ein Icon bedeutet immer seinen Bereich.
|
||
- Die öffentliche Herkunftsseite behält ihre eigenen Icons.
|
||
|
||
## 12. Manifest und Icons
|
||
|
||
### 12.1 Markenzeichen
|
||
|
||
- **Form:** eine verdeckelte Wabenzelle.
|
||
- Sechseck mit spitzer Oberseite in Honig (#f0b13f) mit 6 % Rand in Tinte.
|
||
- Darin ein kleineres Sechseck in hellem Wachs (`oklch(0.88 0.11 85)` #f9d280) als Deckel, leicht nach oben versetzt.
|
||
- Es ist bei 16 px als Honig-Sechseck lesbar.
|
||
- **Master:** `public/brand/apicore-mark.svg`.
|
||
- **App-Icon:** Hintergrund in dunkler Tinte `oklch(0.24 0.035 55)` #2c1b0f, Zelle mittig. Honig auf Tinte hat 8,7:1. Das ist eine Weiterentwicklung des bisherigen Schwarz-Gelb, kein Bruch.
|
||
- **`BrandMark`-Komponente:** dieselbe Zelle als SVG (24/32 px) neben dem Schriftzug „ApiCore“ (Space Grotesk). Sie ersetzt `Hexagon` auf Verlauf in Sidebar, Kopfzeile, Login und Herkunftsseite.
|
||
|
||
### 12.2 Dateien
|
||
|
||
| Datei | Größe | `purpose` | Inhalt |
|
||
|---|---|---|---|
|
||
| `public/icon.svg` | skalierbar | any | Zelle auf Tinte, Ecken 22 % gerundet (ersetzt die Balken) |
|
||
| `public/icons/icon-192.png`, `icon-512.png` | 192, 512 | any | wie `icon.svg` |
|
||
| `public/icons/maskable-192.png`, `maskable-512.png` | 192, 512 | maskable | Tinte randlos, Zelle innerhalb der sicheren Zone (Kreis mit 40 % Radius, also Zelle höchstens 66 % der Kante) |
|
||
| `public/icons/monochrome-512.png` | 512 | monochrome | Zellen-Silhouette, weiß auf transparent (Android-Themen-Icons) |
|
||
| `public/icons/shortcut-inspection-96.png`, `shortcut-varroa-96.png`, `shortcut-today-96.png` | 96 | – | Bereichs-Icon in Tinte auf Wachs |
|
||
| `src/app/apple-icon.png` | 180 | – | Zelle auf Tinte, ohne eigene Rundung (iOS maskiert). Ersetzt `apple-icon.tsx` (Satori-Balken). |
|
||
| `src/app/favicon.ico` | 16, 32, 48 | – | Zelle ohne Hintergrund |
|
||
|
||
- Erzeugt werden die Dateien mit `scripts/generate-icons.mjs` aus dem Master-SVG (`sharp` als devDependency; heute nur transitiv über Next vorhanden). Das Skript ist idempotent. Die Ausgabe wird committet, damit das Docker-Image nicht vom Skript abhängt.
|
||
|
||
### 12.3 `app/manifest.ts`
|
||
|
||
```ts
|
||
{
|
||
id: "/", name: "ApiCore – Imkereiverwaltung", short_name: "ApiCore",
|
||
description: "Digitale Imkereiverwaltung für Wabenhain", lang: "de", dir: "ltr",
|
||
start_url: "/", scope: "/", display: "standalone",
|
||
background_color: "#f9f4ea", // = --background hell
|
||
theme_color: "#f9f4ea", // Statusleiste; dunkel über viewport.themeColor (5.2)
|
||
categories: ["productivity", "business"],
|
||
icons: [ /* any 192/512, maskable 192/512, monochrome 512, icon.svg any */ ],
|
||
shortcuts: [
|
||
{ name: "Durchsicht erfassen", short_name: "Durchsicht", url: "/inspections/new", icons: [{ src: "/icons/shortcut-inspection-96.png", sizes: "96x96" }] },
|
||
{ name: "Varroa messen", short_name: "Varroa", url: "/varroa/new", icons: [ … ] },
|
||
{ name: "Heute", url: "/dashboard", icons: [ … ] },
|
||
],
|
||
}
|
||
```
|
||
|
||
- Die Shortcuts sind Routen der Service-Worker-Shell (T3 Task 15). Sie öffnen also auch offline.
|
||
- Ein langer Druck auf das App-Icon führt direkt zur Durchsicht.
|
||
- `proxy.ts`: Der `matcher` nimmt `/icons/` und `apple-icon.png` aus, wie heute `icon.svg`.
|
||
- `public/sw.js`:
|
||
- `SHELL_ROUTES` bleiben.
|
||
- Die neuen Icons kommen in den Shell-Cache.
|
||
- Die Cache-Version steigt (`apicore-shell-v5`), damit installierte Apps das neue Icon und die neuen Tokens bekommen.
|
||
|
||
## 13. Tests
|
||
|
||
TDD wie in T3/T4: erst der fehlschlagende Test, dann der Code. Vitest + RTL im Frontend, Jest/Supertest für den Backend-Zusatz.
|
||
|
||
### 13.1 Wächter
|
||
|
||
- **`src/styles/contrast.spec.ts`** (ersetzt `src/lib/forms/rating-contrast.spec.ts`; gleiche OKLCH-Rechnung, ergänzt um Alpha-Mischung für Tönungen):
|
||
- Liest die vier Sätze aus `globals.css`. Die Sonne-Sätze werden auf ihren Grundsatz gelegt.
|
||
- Prüft jede Zeile aus 4.4 mit ihrer Grenze. Dazu kommen alle Ampelflächen (Text auf Fläche ≥ 4,5, Fläche auf Karte ≥ 3, Tinte auf Tönung ≥ 4,5), alle `chart-*` und `area-*` (≥ 3) und alle `queen-*` mit Tinten-Ring.
|
||
- `it('every token in @theme inline exists in light and dark')`: der Wächter für „Dark angeschlossen“.
|
||
- `it('all tokens are inside the sRGB gamut')`.
|
||
- **`src/styles/baukasten-guard.spec.ts`:** Regeln aus 10.7.
|
||
- **`src/lib/season/season-defaults.spec.ts`:** `it('defaults equal the T4 PHENOLOGY and SEASON_AUTOPILOT defaults')`. Der Test liest die Backend-Datei mit den Config-Standards (`ApiCore-Backend/src/automation/rule-config/*`, genauer Pfad aus T4 Task 1) per `readFileSync` und vergleicht die `MM-DD`-Werte. Ändert jemand nur eine Seite, schlägt der Test fehl.
|
||
- **`src/app/manifest.spec.ts`:**
|
||
- Icons für 192/512 „any“ und „maskable“ sind vorhanden.
|
||
- Jede Datei existiert unter `public/` mit der angegebenen Größe (PNG-Kopf lesen).
|
||
- `background_color` und `theme_color` entsprechen dem hellen `--background`.
|
||
- Die Shortcut-URLs stehen in `SHELL_ROUTES`.
|
||
|
||
### 13.2 Unit
|
||
|
||
- `appearance.spec.ts`:
|
||
- Standard „Hell“
|
||
- „Wie Gerät“ folgt `matchMedia` und reagiert auf Wechsel
|
||
- `prefers-contrast: more` ohne gespeicherten Wert → Sonne
|
||
- Blockierter Speicher fällt auf den Standard zurück
|
||
- `storage`-Ereignis zieht mit
|
||
- Das Inline-Skript nutzt dieselben Schlüssel (String enthält `APPEARANCE_KEYS`) und setzt `theme-color`
|
||
- `areas.spec.ts`:
|
||
- Jeder `NAV_GROUPS`-Eintrag und jede `QUICK_ACTION` hat einen `AREAS`-Schlüssel und dasselbe Icon
|
||
- Kein Ton ist eine Zustandsfarbe
|
||
- `honeycomb/layout.spec.ts`:
|
||
- Spaltenzahl aus der Breite (3 bis 10)
|
||
- Versatz jeder zweiten Reihe
|
||
- Verzahnung um ein Viertel der Höhe
|
||
- Reihenfolge nach Code natürlich sortiert (V-2 vor V-10)
|
||
- `honeycomb/cell-state.spec.ts` (Tabelle):
|
||
- Randstufen vor T4 (10/11/14/15 Tage, nie)
|
||
- Randstufen ab T4 (fällig in 4 Tagen → 1, in 3 → 2, gestern → 3, `null` → 1 mit „Winterruhe“)
|
||
- ohne `inspections:read` → neutral
|
||
- Name der Zelle beginnt mit dem Code und nennt Ampel, Gründe und Tage
|
||
- `mini-comb-svg.spec.ts`:
|
||
- schlechtestes Volk in der Mitte
|
||
- freie Plätze als Umriss
|
||
- mehr als 7 → Zählchip
|
||
- nur `var(--…)`-Farben, kein Hex
|
||
- `lifeline.spec.ts`:
|
||
- Werte vor `STRENGTH_IN_FRAMES_SINCE` nicht in der Kurve, aber in der Tabelle
|
||
- Lücke über 45 Tage bricht die Linie
|
||
- Varroa-Balken über die echte Liegezeit
|
||
- `rating.light` (T4) hat Vorrang vor `varroaLight` (T3)
|
||
- Königinnen-Amtszeiten aus `queenHistory`, Farbe aus `markingColor`
|
||
- unbekannte Farbe → gestrichelt
|
||
- Behandlungsspannen
|
||
- Zukunft: T4-Schritte, sonst Aufgaben, höchstens 3
|
||
- fehlende Spur bei 403
|
||
- `<desc>`-Text
|
||
- `year-wheel.spec.ts`:
|
||
- Winkel für 01.01., 01.07. und 31.12. im Schaltjahr
|
||
- Winterruhe als zwei Bögen
|
||
- aktueller Abschnitt ab `segmentSince` (Kirsche am 05.04. gemeldet → Schwarmzeit ab 05.04.)
|
||
- späte Blüte → nächster Abschnitt „ab morgen, noch offen“
|
||
- Fenster lückenlos und überlappungsfrei
|
||
- Bezugsstand nach Mehrheit, bei Gleichstand fortgeschrittener
|
||
- Abweichungen
|
||
- Aufgaben je Woche, überfällige gesammelt
|
||
- ohne `seasonCalendar` → `season-defaults`
|
||
|
||
### 13.3 Komponenten (RTL)
|
||
|
||
- `ChoiceGroup`:
|
||
- gewählte Option hat `aria-checked="true"`, das Haken-Icon und den Tinten-Rahmen
|
||
- „Nicht geprüft“ gewählt hat das Strich-Icon
|
||
- `appearance="cards"` zeigt die Beschreibung
|
||
- Pfeiltasten wie bisher
|
||
- `CheckboxField`:
|
||
- ganze Zeile schaltet
|
||
- Name aus dem Label
|
||
- Zeile mindestens 44 px (Klasse `min-h-11`), im Sheet `min-h-14`
|
||
- `tile` und `task` haben `role="checkbox"` vom Primitiv
|
||
- `Tabs`: Pfeiltasten wechseln, Panel ist `tabpanel` mit `aria-labelledby`, `ActiveHistoryTabs` zeigt Zähler.
|
||
- `AppearanceSection`: Wahl setzt Klasse und Attribute auf `document.documentElement` und speichert. Schnellschalter im Benutzermenü ist ein `menuitemcheckbox`.
|
||
- `ApiaryComb`:
|
||
- Liste mit benannten Links in Codereihenfolge
|
||
- Legende sichtbar
|
||
- „Braucht Blick“ nur mit Gelb und Rot
|
||
- „Alle Völker als Liste“ klappt die T3-Liste auf (`aria-expanded`)
|
||
- leerer Stand
|
||
- offline aus dem Paket
|
||
- `ApiaryMap`: Marker mit `aria-label`, Popup mit „Stand öffnen“, Liste unter der Karte, Offline-Hinweis. Leaflet wird gemockt.
|
||
- `ColonyLifeline`:
|
||
- `figure` mit Titel und Beschreibung
|
||
- Tabelle aufklappbar mit denselben Einträgen
|
||
- „Ganzes Leben zeigen“ ändert den Ausschnitt
|
||
- Leerzustand mit Knopf
|
||
- fehlende Varroa-Rechte → keine Milbenspalte
|
||
- `YearWheel`:
|
||
- Zentrum zeigt Abschnitt, Quelle und Fenster
|
||
- Tabelle aufklappbar
|
||
- „Zum Kalender“
|
||
- Dashboard ohne Zählkacheln und ohne Weiß auf Honig
|
||
- Backend `test/next-steps.e2e-spec.ts`: `it('GET /autopilot/today carries seasonCalendar and segmentSince per apiary')`, `it('seasonCalendar follows a changed PHENOLOGY config')`.
|
||
|
||
### 13.4 Sichtprüfung
|
||
|
||
- **Screenshot-Matrix:**
|
||
- Werkzeug: Chrome DevTools (MCP `chrome-devtools`: `emulate`, `resize_page`, `take_screenshot`) gegen `npm run build && npm run start` mit Demo-Daten.
|
||
- Seiten:
|
||
- Start, Stand (Wabe), Bienenstände, Karte, Volk (Lebenslinie)
|
||
- Durchsicht neu, Varroa neu, Profil > Darstellung
|
||
- Login, Herkunft
|
||
- Modi: hell, dunkel, Sonne hell, Sonne dunkel.
|
||
- Breiten: 390 px (Touch), 820 px (Tablet, Touch-Emulation, prüft `pointer-coarse`), 1366 px.
|
||
- Dazu `forced-colors: active` und `prefers-reduced-motion: reduce` je einmal auf Start, Stand und Volk.
|
||
- Die Bilder liegen als Anhang am PR, nicht im Repo.
|
||
- **Automatisch:**
|
||
- Lighthouse Barrierefreiheit mindestens 95 auf Start, Stand, Volk, Durchsicht neu und Profil, in hell und Sonne.
|
||
- Danach einmal den Impeccable-Detektor über die geänderten Dateien laufen lassen (`impeccable detect --json`); 0 Befunde.
|
||
- **Draußen-Test** mit dem Inhaber: Handy, Mittagssonne, Arbeitshandschuhe, eine Hand, je einmal Normal und Sonne. Bestanden, wenn jede Aufgabe ohne Hilfe und ohne Fehlgriff gelingt:
|
||
1. den Hauptknopf auf Start finden und tippen
|
||
2. auf 50 cm Abstand sagen, welches Volk an einem Stand Kritisch ist und welches lange nicht durchgesehen wurde
|
||
3. Brutwaben mit dem Stepper von 0 auf 6 bringen
|
||
4. den Sonnenmodus einschalten
|
||
5. im Rad sagen, welcher Abschnitt gerade ist
|
||
|
||
Ergebnis und Zeit je Aufgabe stehen im PR. Ein Fehlschlag führt zu Token- oder Größenänderung, nicht zu neuer Bedienung.
|
||
|
||
## 14. Aufwand
|
||
|
||
| Baustein | PT |
|
||
|---|---|
|
||
| Tokens: vier Sätze, `-ink`-Tokens, Bereichs- und Königinnenfarben, Codemod Farben, `dark:` aus `ui/*`, Kontrast-Wächter | 1,0 |
|
||
| Darstellung: Appearance-Modul, Inline-Skript, Profil-Karte, Schnellschalter, `next-themes` raus, Toaster, `theme-color` | 0,5 |
|
||
| Fokus und Größen: globaler Fokus, Codemod, `pointer-fine` statt `sm`, Schrift 16 px | 0,5 |
|
||
| Baukasten: Auswahlgruppe (0,25), Checkbox mit 17 Stellen (0,5), Tabs mit 12 Stellen (0,5), Plus/Minus (0,25), `AREAS`/`AreaIcon`/`BrandMark` (0,5), Wächter (0,25) | 2,25 |
|
||
| Manifest, Icons, Skript, Service-Worker-Version | 0,5 |
|
||
| **T5a „Sonnentauglich und Baukasten“** | **4,75** |
|
||
| Waben-Standkarte: Layout, Zelle, Stand-Seite, Bienenstände-Liste | 1,25 |
|
||
| Mini-Waben-Marker, Popup-Stil, Listen-Rückfall | 0,5 |
|
||
| Lebenslinie: Modell, SVG, Tabelle | 1,5 |
|
||
| Bienenjahr-Rad: Backend-Zusatz (0,25), Modell, SVG, Tabelle, Dashboard-Umbau | 1,5 |
|
||
| Sichtprüfung (Matrix, Draußen-Test), Doku | 0,5 |
|
||
| **T5b „Handschrift“** | **5,25** |
|
||
| **Summe** | **10,0** |
|
||
|
||
Der Fahrplan nannte etwa 5 PT. Mehr wird es durch vier Punkte, die §10 nicht einpreist:
|
||
|
||
1. Der Dunkelmodus ist heute nicht nur unerreichbar, sondern unlesbar (Abzeichen 1,4:1). Er braucht einen vollständigen zweiten Satz, und mit Sonne werden es vier geprüfte Sätze.
|
||
2. Checkboxen und Tabs liegen an 29 Stellen, nicht an einer Handvoll.
|
||
3. Der Fokus ist an 44 Stellen von Hand gebaut.
|
||
4. Tablets bekommen heute Desktop-Größen.
|
||
|
||
**Vorschlag: zwei Lieferungen.**
|
||
- **T5a (≈ 4,75 PT)** bringt den größten Nutzen draußen und hängt nur an T3. Sie kann vor oder parallel zum T4-Backend laufen.
|
||
- **T5b (≈ 5,25 PT)** braucht T4a für die vollen Daten, läuft aber auch ohne (Kalender-Rückfall). Falls gekürzt werden muss, lassen sich die Mini-Waben-Marker (0,5 PT) auf später verschieben, ohne dass etwas anderes fehlt.
|
||
|
||
## 15. Rollout
|
||
|
||
1. **Reihenfolge:**
|
||
- T3-Frontend Tasks 7, 8, 11 und 14 sind gemergt.
|
||
- Dann T5a Schritte 1–5 (10.8) in einem Fenster ohne offene Frontend-Tasks. Am besten vor den T4-Frontend-Tasks 17–22, damit T4 schon auf dem neuen Baukasten baut (`CheckboxField`, `AreaIcon`, neue Tokens).
|
||
- T5a Schritte 6–12 laufen parallel zum T4-Backend.
|
||
- T5b nach T4a-Frontend (Tasks 17, 18, 19), weil T5b dieselben Dateien berührt (`dashboard/page.tsx`, `apiary-colonies-card.tsx`, Volksseite).
|
||
2. **Keine Migration, keine Cluster-Änderung.** T5a ist ein reines Frontend-Image. T5b bringt zusätzlich den Backend-Zusatz an `/autopilot/today` (additiv, alte Frontends ignorieren die Felder). Deploy wie gewohnt, jeder Cluster-Schritt nur mit Freigabe des Inhabers (Rückgrat-Runbook).
|
||
3. **Service Worker:**
|
||
- Die Shell-Version steigt (`apicore-shell-v5`). Installierte Apps holen beim nächsten Start Tokens und Icons.
|
||
- Das Icon auf dem Homescreen aktualisiert Android von selbst (kann Stunden dauern). iOS erst nach Entfernen und neu Hinzufügen; das steht im Changelog.
|
||
4. **Nutzerhinweis:** Einmalig erscheint auf Start der Hinweis „Neu: Sonnenmodus für draußen – im Benutzermenü.“ mit „Ausprobieren“ und „Schließen“ (gemerkt je Gerät). Danach nicht mehr.
|
||
5. **Erste Woche:**
|
||
- Draußen-Test (13.4) mit dem Inhaber.
|
||
- Tokenwerte dürfen danach nur zusammen mit `contrast.spec.ts` geändert werden; der Test hält die Grenzen.
|
||
6. **Doku:**
|
||
- ARCHITECTURE bekommt neue Annahmen unter der dann nächsten freien Nummer (T3 und T4 vergeben 22–27 und folgende):
|
||
- „Darstellung je Gerät“: hell, dunkel, Sonne; Inline-Skript; keine Kontodaten
|
||
- „Ein Baukasten“: Bausteine aus 10.1, Wächter, Ausnahmen
|
||
- ARCHITECTURE §2: `AREAS` als einzige Quelle für Icon und Ton, Wabenzelle als einziges Motiv.
|
||
- TASKS.md: Abschnitt T5 mit Haken; Abschnitt R „Redesign“ verweist auf T5.
|
||
- Empfohlen: `ApiCore-Frontend/DESIGN.md` per `/impeccable document` aus dem fertigen Stand erzeugen, damit spätere Seiten den Baukasten finden.
|
||
|
||
## 16. Offene Fragen an den Inhaber
|
||
|
||
1. **Farbe des Hauptknopfs.** Heute steht weiße Schrift auf einem Honigverlauf (2,3:1, draußen kaum lesbar).
|
||
- A: Heller Honig (#f0b13f) mit dunkler Tinten-Schrift, 9,4:1. Wirkt wie ein Honigetikett. Links und Icons bekommen ein eigenes dunkles Bernstein.
|
||
- B: Dunkler Bernstein (#9b4900) mit weißer Schrift, 6,1:1. Ein Token für Fläche und Text, dafür eher rostbraun als honigfarben.
|
||
- C: Wie heute (verletzt AA, nicht empfohlen).
|
||
- **Empfehlung: A.** Höchster Kontrast, bleibt in der Sonne lesbar, und die Honigfarbe wird zum Erkennungszeichen des einen Hauptknopfs.
|
||
|
||
2. **Reihenfolge der Zellen in der Waben-Standkarte.**
|
||
- A: Nach Volkscode, wie Liste und Standrunde.
|
||
- B: Wie die Beuten wirklich am Stand stehen. Dafür gibt es ein neues Feld `Colony.standSlot` mit Migration, Backup-Eintrag und einer Ansicht „Anordnen“ (+1 PT).
|
||
- C: Schlechtestes Volk zuerst.
|
||
- **Empfehlung: A jetzt.** Wer seine Völker nach Platz nummeriert, hat damit schon die echte Reihenfolge. B lohnt erst, wenn die Codes nicht zur Aufstellung passen. C würde die Zellen bei jeder Durchsicht umsortieren und das räumliche Gedächtnis stören.
|
||
|
||
3. **Standard-Farbschema auf einem neuen Gerät.**
|
||
- A: Hell, Dunkel nur auf Wunsch.
|
||
- B: Wie das Gerät. Ein Handy im Dunkelmodus zeigt die App dann auch draußen dunkel.
|
||
- **Empfehlung: A.** Draußen bei Tag ist hell besser lesbar. Wer abends dunkel will, stellt einmal „Dunkel“ oder „Wie Gerät“ ein, und das Gerät merkt es sich.
|