Shuffle/docs/design-system.md
cschlaefke 936ca7bd4b feat(theme): add Material 3 light/dark theme base and design tokens
Refs #31

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 20:19:19 +01:00

3 KiB

Design-System (Theme-Basis, F6 / Issue #31)

Stand: Basis. Konkrete Komponenten (Formularfelder, Banner, Spiel-Kachel usw.) folgen in U1. Code: app/lib/core/theme/ (app_theme.dart, app_spacing.dart), Tests: app/test/core/theme/.

Theme

  • Material 3, AppTheme.light() und AppTheme.dark(); ShuffleApp nutzt ThemeMode.system.
  • Farben: ColorScheme.fromSeed mit Seed #4F46E5 (Indigo). Einzige Abweichung: outline ist etwas dunkler (hell #6B6A7A) bzw. heller (dunkel #9A99AB), damit Feldrahmen mindestens 3:1 erreichen.
  • Keine Farbwerte in Widgets: immer Theme.of(context).colorScheme und textTheme verwenden.

Kontraste (WCAG 2.1 AA)

Geprüft im Test app_theme_test.dart für Hell und Dunkel. Text mindestens 4.5:1, Bedienelemente (Rahmen, Fokusring, Fehlerrahmen) mindestens 3:1.

Paar Hell Dunkel
onSurface / surface 16.3 14.4
onSurfaceVariant / surface 8.9 10.9
onSurfaceVariant / Feldfüllung 7.2 7.3
onPrimary / primary (Buttons) 6.5 7.7
Fehlertext (error) / Feldfüllung 5.0 7.3
SnackBar-Text / SnackBar-Fläche 11.5 10.1
SnackBar-Aktion / SnackBar-Fläche 7.7 5.0
Feldrahmen (outline) / Feldfüllung 4.1 4.4
Fokusring (primary) / Feldfüllung 5.0 7.2

Regeln: Informationen nie nur über Farbe vermitteln (Fehler = Text + Rahmen + Icon). Neue Farbpaare müssen in den Test aufgenommen werden. Deaktivierte Elemente sind von der Kontrastpflicht ausgenommen.

Touch-Ziele und Fokus

  • Mindestgröße 48 x 48 dp für alle Buttons und Icon-Buttons (minimumSize), MaterialTapTargetSize.padded, VisualDensity.standard. Nicht auf compact verkleinern.
  • Tastaturfokus (Web/Desktop): Buttons und Textfelder zeigen einen 3 dp breiten Rahmen in primary.
  • Icons ohne Text brauchen tooltip bzw. Semantics(label: ...); Bilder ein Label oder excludeSemantics.
  • Text muss bis 200 % Skalierung ohne Abschneiden funktionieren (kein fixes Höhen-Layout für Text).

Typografie

Material-2021-Skala (textTheme), Farbe onSurface. Überschriften headline*/title*, Fließtext bodyLarge/Medium, Hinweise bodySmall (onSurfaceVariant). Schriftgrößen nie hart codieren.

Abstände, Radien, Breakpoints (app_spacing.dart)

Token Wert (dp)
AppSpacing xxs / xs / sm / md / lg / xl / xxl / xxxl 2 / 4 / 8 / 12 / 16 / 24 / 32 / 48
AppRadius sm / md / lg / xl 8 / 12 / 16 / 28
Breakpoints (AppWidthClass) kompakt < 600, mittel 600-1023, groß >= 1024
AppBreakpoints.maxContentWidth 560 (Formulare/Text auf breiten Bildschirmen begrenzen)

AppSpacing.pagePadding(width) liefert den Seitenrand je Breitenklasse (16 / 24 / 32). Web darf nicht wie eine gestreckte Handy-App wirken: Inhalt zentrieren und auf maxContentWidth begrenzen.

Komponenten-Themes in der Basis

FilledButton, ElevatedButton, OutlinedButton, TextButton, IconButton, Checkbox, InputDecoration (gefüllt, Rahmen 1 dp, Fokus 3 dp, Fehler 2 dp), Card, AppBar, Divider, SnackBar (schwebend, mit Schließen-Icon).