Files
MindSift/Doku/ui-patterns.md
T
sandrodachandClaude Opus 5.5 6d6a35d28d
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m32s
fix(ui): tab counters 4px lower and further right
Corner counters on tabs (header, task lists, lists, workspace) sat on
the tab's top border and close to the text; now -top-0.5 -right-2 with
pr-3 on the label. The mobile bottom bar keeps its icon placement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:46:26 +01:00

5.8 KiB
Raw Blame History

UI-Muster

Wiederkehrende Bedienelemente, die überall gleich aussehen und sich gleich verhalten. Wer eines davon neu braucht, nimmt die vorhandene Komponente und baut keine eigene Variante.

Komponente: UserAutocomplete.tsx

Eingesetzt beim Teilen (UnifiedShareModal), beim Hinzufügen zu Gruppen (GroupsView) und beim Zuweisen von Aufgaben (TaskDetailModal).

  • Keine Liste vorab: Solange das Feld leer ist, erscheint nichts, auch nicht beim Reinklicken. Kein Dropdown mit allen Personen.
  • Erst beim Tippen erscheinen Treffer direkt unter dem Feld, höchstens 3 (MAX_RESULTS). Gesucht wird in Anzeigename, @Benutzername und E-Mail.
  • Der erste Treffer ist vorausgewählt: Tippen + Enter übernimmt ihn. Pfeiltasten wechseln, Escape schließt.
  • Bereits gewählte oder freigegebene Personen werden über excludeUserIds ausgeblendet.
  • Einzelauswahl (Teilen, Gruppen): selectedUser setzen; das Feld zeigt dann die gewählte Person mit ×.
  • Mehrfachauswahl (Aufgaben zuweisen): selectedUser={null} lassen und in onSelectUser zur Liste hinzufügen. Die Gewählten stehen als Chips (Avatar, Name, ×) über dem Feld, das Feld bleibt für die nächste Suche frei.

Profilbilder als Stapel

Komponente: AvatarStack.tsx (nutzt UserAvatar)

  • Kleine runde Profilbilder, leicht überlappend, höchstens 3. Weitere Personen erscheinen als monochromer Kreis „+n“.
  • Ohne Profilbild zeigt UserAvatar die Initialen.
  • ringClass bekommt die Farbe der Fläche dahinter (meist ring-[var(--bg-panel)] oder ring-[var(--bg-app)]), damit die Kreise sauber getrennt sind.
  • Größen: xxs (16 px) in Tabs, Kanban-Karten und Listeneinträgen, xs (20 px) in Aufgabenzeilen und Kopfzeilen.
  • Kein Hover-Effekt im Stapel selbst. Einzige Ausnahme ist die Anwesenheit in Notizen (PresenceAvatars.tsx): Dort zeigt Hover oder Tastaturfokus die Liste „Gerade online“.
Ort Wer wird gezeigt
Notiz-Kopfzeile wer die Notiz gerade geöffnet hat (Profilbilder aus /users/directory)
Tabs der Aufgabenlisten und Listen alle mit Zugriff außer mir (members)
Aufgabenzeile und Kanban-Karte zugewiesene Personen (nur in geteilten Listen)
Eintrag einer geteilten Liste wer ihn hinzugefügt hat (createdBy); ältere Einträge ohne Autor zeigen nichts

Schalter

Komponente: ToggleSwitch.tsx

  • Ein/Aus-Einstellungen sind immer Schalter, keine Checkbox-Haken (Einrichtung, Admin-Bereich).
  • Text links (Titel, darunter eine kurze Erklärung in text-muted), Schalter rechts.

Kleine Dialoge (Anlegen, Umbenennen)

Komponente: FormSheet.tsx, Tastatur-Abstand über useKeyboardInset.ts

  • Handy: Bottom-Sheet über die volle Breite, das direkt über der Bildschirmtastatur sitzt (der Abstand kommt aus visualViewport), Griff oben, Felder und Buttons mindestens 44 px hoch, Eingaben in 16 px (sonst zoomt iOS), Abbrechen/Erstellen nebeneinander über die ganze Breite.
  • Desktop: zentriertes Fenster, oder mit anchor neben der Klickposition (z. B. „Neuer Ordner“ im Explorer).
  • Escape und Klick auf den Hintergrund schließen. Genutzt für neue Aufgabenliste, neue Einkaufsliste und neuen Ordner; das Emoji-Sheet nutzt denselben Tastatur-Abstand.

Zähler

Komponente: CountBadge.tsx, CSS-Klassen count-badge* in index.css. Es gibt keine anderen Zähler-Stile mehr.

  • Form: runder Kreis, mindestens 16 px, ab 100 als „99+“ (der Screenreader liest die echte Zahl). Bei 0 ausgeblendet, außer mit showZero (z. B. Mitgliederzahl, mobiles Menü).
  • Farbe (variant):
    • accent: Hier wartet etwas auf dich. Navigationsleiste: Triage (Inbox), Aufgaben (offene Aufgaben), Listen (offene Einträge aller eigenen und geteilten Listen). Workspace hat keinen Zähler.
    • muted (Standard): reine Anzahl. Tabs der Aufgabenlisten und Listen, Organisationen, mobiles Menü.
    • Beide kommen aus den Theme-Variablen (--accent-primary/--text-on-accent bzw. --text-muted/--bg-panel) und passen sich damit jedem Theme an.
  • Position (position):
    • corner: Benachrichtigungs-Badge oben rechts am nächsten relative Elternelement, mit Ring in der Seitenfarbe. In der Navigation und an den Tabs sitzt er auf dem Text: der Text steht in einem relative inline-flex-Span (mit pr-3, solange ein Zähler da ist), der Kreis bekommt -top-0.5 -right-2, damit er die obere Tab-Linie nicht anschneidet und nicht am Text klebt. In der mobilen Leiste sitzt er am Icon (-top-1.5 -right-2.5).
    • inline: im Textfluss.
  • Zahlen im mobilen Menü (MobileActionContext, badge: number) werden automatisch als CountBadge gezeigt; Text-Badges wie „2 aktiv“ bleiben Textmarken.
  • Wichtig für neue Klassen: Tailwind entfernt Klassen aus @layer components, die nicht wörtlich im Code stehen. Klassennamen deshalb nie zusammensetzen (count-badge-${variant}), sondern ausschreiben.

Ladebildschirm & Statusleiste

  • manifest.json: name „MindSift“ (kurz, der Slogan steht in description), background_color und theme_color #2563eb – Android baut daraus den Splash-Screen.
  • index.html enthält in #root einen reinen HTML-Platzhalter (vollflächig Blau, Logo in der Mitte, kein Text). React ersetzt ihn beim ersten Rendern, dazwischen blitzt nichts Weißes auf.
  • meta theme-color startet blau und wird von theme.ts nach dem Start und bei jedem Theme-Wechsel auf --bg-app des aktiven Themes gesetzt, damit die Statusleiste zum Header passt.