mitgliederverwaltung/docs/badge-wcag-phase1-analysis.md

6.5 KiB
Raw Blame History

Phase 1 — Badge WCAG Analysis & Migration

1) Repo-Analyse (Stand vor Änderungen)

Badge-Verwendungen (alle Fundstellen)

Datei Kontext Markup
lib/mv_web/live/member_field_live/index_component.ex Tabelle (show_in_overview) <span class="badge badge-success"> / <span class="badge badge-ghost">
lib/mv_web/live/components/member_filter_component.ex Filter-Chips (Anzahl) <span class="badge badge-primary badge-sm"> (2×)
lib/mv_web/live/role_live/index.html.heex Tabelle (System Role, Permission Set, Custom) badge-warning, permission_set_badge_class(), badge-ghost (User Count)
lib/mv_web/helpers/membership_fee_helpers.ex Helper status_color/1 → "badge-success" | "badge-error" | "badge-ghost"
lib/mv_web/live/member_live/show.ex Mitgliedsdetail (Beiträge) <span class={["badge", status_color(status)]}>, badge-ghost (No cycles)
lib/mv_web/live/membership_fee_settings_live.ex Settings (Fee Types) badge-outline, badge-ghost (member count)
lib/mv_web/live/membership_fee_type_live/index.ex Index (Fee Types) badge-outline, badge-ghost (member count)
lib/mv_web/live/role_live/index.ex (Helper-Import) permission_set_badge_class/1
lib/mv_web/live/member_live/show/membership_fees_component.ex Mitgliedsbeiträge badge-outline, ["badge", status_color]
lib/mv_web/live/custom_field_live/index_component.ex Tabelle (show_in_overview) badge-success, badge-ghost
lib/mv_web/member_live/index/membership_fee_status.ex Helper format_cycle_status_badge/1 → map mit color, icon, label
lib/mv_web/live/global_settings_live.ex Form (label-text-alt) badge badge-ghost "(set)" (2×)
lib/mv_web/live/member_live/index.html.heex Tabelle (Status) format_cycle_status_badge + <span class={["badge", badge.color]}>, badge-ghost (No cycle), badge-outline badge-primary (Filter-Chip)
lib/mv_web/live/role_live/helpers.ex Helper permission_set_badge_class/1 → "badge badge-* badge-sm"
lib/mv_web/live/group_live/show.ex Card badge badge-outline badge
lib/mv_web/live/role_live/show.ex Detail permission_set_badge_class, badge-warning (System), badge-ghost (No)

DaisyUI/Tailwind Config

  • Tailwind: assets/tailwind.config.js — erweitert nur theme.extend.colors.brand; kein DaisyUI hier.
  • DaisyUI: wird in assets/css/app.css per @plugin "../vendor/daisyui" mit themes: false geladen.
  • Themes: Zwei Custom-Themes in app.css:
    • @plugin "../vendor/daisyui-theme" mit name: "dark" (default: false)
    • @plugin "../vendor/daisyui-theme" mit name: "light" (default: true)
  • Theme-Umschaltung: lib/mv_web/components/layouts/root.html.heex — Inline-Script setzt document.documentElement.setAttribute("data-theme", "light"|"dark") aus localStorage["phx:theme"] oder prefers-color-scheme. Sidebar enthält Theme-Toggle (<.theme_toggle />).

Core Components

  • Modul: lib/mv_web/components/core_components.ex (MvWeb.CoreComponents).
  • Vorhanden: flash, button, dropdown_menu, form_section, input, header, table, icon, link, etc.
  • Badge: Bisher keine zentrale <.badge>-Komponente.

DaisyUI Badge (Vendor)

  • Default: --badge-bg: var(--badge-color, var(--color-base-100)), --badge-fg: var(--color-base-content).
  • badge-outline: --badge-bg: "#0000" (transparent) → Kontrastproblem auf base-200/base-300.
  • badge-ghost: background-color: var(--color-base-200), color: var(--color-base-content) → auf base-200-Flächen kaum sichtbar.
  • badge-soft: color-mix 8% Variante mit base-100 → sichtbar; Text ist Variantenfarbe (Kontrast prüfen).

2) Core Component <.badge> API (geplant)

  • attr :variant:neutral | :primary | :info | :success | :warning | :error
  • attr :style:soft | :solid | :outline (Default: :soft)
  • attr :size:sm | :md (Default: :md)
  • slot :inner_block — Badge-Text
  • attr :sr_label — optional, für Icon-only (Screen Reader)
  • slot :icon — optional

Regeln:

  • :soft und :solid nutzen sichtbaren Hintergrund (kein transparenter Ghost als Default).
  • :outline setzt immer einen Hintergrund (z. B. bg-base-100), damit der Rand auf grauen Flächen sichtbar bleibt.
  • Ghost nur als explizites Opt-in; dann mit bg-base-100 für Sichtbarkeit.

3) Theme-Overrides (WCAG)

  • In app.css sind bereits Custom-Themes für light und dark mit eigenen Tokens.
  • Badge-Kontrast (WCAG 2.2 AA 4.5:1): Zusätzliche Overrides in app.css:
    • Light theme: Dunkle --badge-fg für alle Varianten (primary, success, error, warning, info, neutral); für badge-soft dunklere Textfarbe (color) auf getöntem Hintergrund; für badge-outline einheitlich dunkle Schrift auf base-100.
    • Dark theme: Leicht abgedunkelte Badge-Hintergründe für Solid-Badges, damit die hellen *-content-Farben 4.5:1 erreichen; für badge-soft hellere, gut lesbare Variantentöne; für badge-outline heller Text (--badge-fg) auf base-100.

4) Migration (erledigt)

  • Alle <span class="badge ..."> durch <.badge variant="..." style="...">...</.badge> ersetzt.
  • Klickbare Chips (z. B. Group Show „Remove“) bleiben als <.badge> mit Button im inner_block (Badge ist nur Container).
  • Neue Helper: MembershipFeeHelpers.status_variant/1 (→ :success | :error | :warning; suspended = :warning wie Edit-Button), RoleLive.Helpers.permission_set_badge_variant/1 (→ :neutral | :info | :success | :error).
  • Angepasst: MembershipFeeStatus.format_cycle_status_badge/1 liefert zusätzlich :variant für <.badge>.
  • Migrierte Stellen: member_field_live, member_filter_component, role_live (index + show), member_live (show, index, membership_fees_component), membership_fee_settings_live, membership_fee_type_live, custom_field_live, global_settings_live, group_live/show.

5) Weitere Anpassungen (nach Phase 1)

  • Filter Join-Buttons (WCAG): In app.css Kontrast-Overrides für .member-filter-dropdown .join .btn (inaktiv: base-100/base-200 + dunkle/helle Schrift; aktiv: success/error mit 4.5:1).
  • Badge „Pausiert“ (suspended): status_variant(:suspended):warning (gelb), damit Badge dieselbe Farbe wie der Edit-Button (btn-warning) hat.
  • Filter-Dropdown schließen: phx-click-away vom inneren Panel auf den äußeren Wrapper (member-filter-dropdown) verschoben; Klick auf den Filter-Button schließt das Dropdown (konsistent mit Spalten/Ausblenden).