Mila petrol theme tokens, contrast-safe variants and the new button API #602

Closed
opened 2026-10-17 02:46:10 +02:00 by simon · 0 comments
Owner

Motivation

The theme still uses the Phoenix generator's orange as primary (and priv/static/images/logo.svg is the Phoenix logo, not Mila's). In dark mode primary has two hues (orange buttons, purple badges) and the secondary is louder than the primary. Contrast is patched per component (~150 lines of overrides, a parallel .text-*-aa palette), and solid alerts stay below AA. <.button> defaults to primary, which renders Cancel buttons as primary, and its variant mixes style and color, so call sites inject btn-primary through class. DESIGN_GUIDELINES §1.6 and §5.2 define the target.

Visible improvement

Mila's own petrol instead of the generator orange; a calm, readable dark mode where the main action is clearly the main action; no more primary Cancel buttons.

Scope (ordered steps, just ci-dev green after each)

  1. Tokens: in both @plugin "daisyui-theme" blocks set primary to Mila petrol (guide #007980, white content), add --color-primary-ink (light = primary, dark guide #46c6cd), accent slate blue (#346180, plus a lighter dark variant chosen and measured here), secondary muted slate in both themes, status colors contrast-safe. Orange remains only as warning.
  2. Ink rule group: one commented rule group derives btn-soft/btn-ghost/btn-outline + btn-primary, badge-soft/badge-outline + badge-primary, link-primary, text-primary, toggle-primary and the focus ring from primary-ink. Checkbox exception: checked checkbox-primary keeps dark petrol + white check in both themes, with a 1px primary-ink border in dark (WCAG 1.4.11).
  3. Remove patches: move remaining [data-theme] token overrides into the plugin blocks; delete per-component badge/link overrides and the .text-*-aa utilities; replace their uses with tokens. For each remaining recolor patch (e.g. the .label opacity override), decide: remove it through tokens, or keep it as a documented exception with its reason in DESIGN_GUIDELINES §1.5.
  4. Text levels: measure /85 and /70 against base-100 and base-200 in both themes (≥ 4.5:1; raise /70 if needed); migrate all other text opacities; align <.header>'s subtitle (today /70) with DESIGN_GUIDELINES §3.
  5. Button API: <.button> gets separate color and style axes (DESIGN_GUIDELINES §5.2), no implicit primary, class for layout only. Decide here: required color vs. neutral default, and the final attribute names (shared with <.badge>); the name style shadows the global HTML style attribute, so decide whether to keep it or rename the axis on both components.
  6. Migrate call sites: every <.button> and raw btn usage in views, incl. the primary Cancel buttons, the hidden primary “Regenerate cycles”, and the 7 btn-primary injections. Apply the label scheme of DESIGN_GUIDELINES §5.7 on the touched buttons.
  7. Segmented control: <.segmented> replacing the three hand-built variants (filter builder, fees tab). Decide the ARIA model (radio group or pressed buttons) and the selected-state color.
  8. Remove priv/static/images/logo.svg if still unused.
  9. Showcase: sections for buttons (all color × style × size), badges, links, switches, checkboxes and text levels in both themes.

Out of scope

  • Branding settings, theme picker, runtime color injection (later feature; only the token rules apply).
  • Email layout colors (branding feature).
  • Callouts and sections (U5).

Acceptance criteria

  • DESIGN_GUIDELINES §1.6 (tokens, one hue per role, ink token, checkbox exception), §3.1 (two text levels), §5.2, §5.4, §5.5, §5.7 are met.
  • A contrast table for every color/-content pair and every derived variant in both themes, all ≥ 4.5:1 (text) / ≥ 3:1 (non-text), is attached to the PR.
  • Before/after screenshots: member overview header (light and dark), fee type form footer, fees tab toolbar, a page with badges.
  • No <.button> without an explicit color renders as primary; no view passes btn-* through class.
  • Keyboard check: focus ring visible on every button style in both themes.
  • Showcase sections added.
  • just ci-dev green after every step.

Dependencies

  • U2 (current daisyUI version).
  • Blocks U4–U10 (all build on the tokens and the button API).

Anchors (verified against main @ d9093a1f, re-check before filing)

  • Theme blocks: assets/css/app.css:24-92; dark overrides that make secondary louder: assets/css/app.css:576-584 (see also :569-585)
  • Badge/link overrides and -aa utilities: assets/css/app.css:125-255, :600-617
  • Button default: lib/mv_web/components/core_components.ex:143
  • Primary Cancel buttons: lib/mv_web/live/membership_fee_type_live/form.ex:146, lib/mv_web/live/import_live/components.ex:242
  • Hidden primary with injected classes: lib/mv_web/live/member_live/show/membership_fees_component.ex:156
  • Segmented variants: lib/mv_web/components/add_filter_builder_component.ex (filter modes), lib/mv_web/live/member_live/show/membership_fees_component.ex (cycle status)

Caution

  • The guide values come from rendered mockups; soft badges and the nav accent in dark mode were too pale there. Measure, do not trust the guide values.
  • A future club brand needs two values per theme (surface + ink) plus a computed content color: keep the derivation in one place so a brand only changes token values.
## Motivation The theme still uses the Phoenix generator's orange as primary (and `priv/static/images/logo.svg` is the Phoenix logo, not Mila's). In dark mode primary has two hues (orange buttons, purple badges) and the secondary is louder than the primary. Contrast is patched per component (~150 lines of overrides, a parallel `.text-*-aa` palette), and solid alerts stay below AA. `<.button>` defaults to `primary`, which renders Cancel buttons as primary, and its `variant` mixes style and color, so call sites inject `btn-primary` through `class`. DESIGN_GUIDELINES §1.6 and §5.2 define the target. ## Visible improvement Mila's own petrol instead of the generator orange; a calm, readable dark mode where the main action is clearly the main action; no more primary Cancel buttons. ## Scope (ordered steps, `just ci-dev` green after each) 1. **Tokens:** in both `@plugin "daisyui-theme"` blocks set primary to Mila petrol (guide `#007980`, white content), add `--color-primary-ink` (light = primary, dark guide `#46c6cd`), accent slate blue (`#346180`, plus a lighter dark variant chosen and measured here), secondary muted slate in both themes, status colors contrast-safe. Orange remains only as `warning`. 2. **Ink rule group:** one commented rule group derives `btn-soft`/`btn-ghost`/`btn-outline` + `btn-primary`, `badge-soft`/`badge-outline` + `badge-primary`, `link-primary`, `text-primary`, `toggle-primary` and the focus ring from `primary-ink`. Checkbox exception: checked `checkbox-primary` keeps dark petrol + white check in both themes, with a 1px `primary-ink` border in dark (WCAG 1.4.11). 3. **Remove patches:** move remaining `[data-theme]` token overrides into the plugin blocks; delete per-component badge/link overrides and the `.text-*-aa` utilities; replace their uses with tokens. For each remaining recolor patch (e.g. the `.label` opacity override), decide: remove it through tokens, or keep it as a documented exception with its reason in DESIGN_GUIDELINES §1.5. 4. **Text levels:** measure `/85` and `/70` against `base-100` and `base-200` in both themes (≥ 4.5:1; raise `/70` if needed); migrate all other text opacities; align `<.header>`'s subtitle (today `/70`) with DESIGN_GUIDELINES §3. 5. **Button API:** `<.button>` gets separate color and style axes (DESIGN_GUIDELINES §5.2), no implicit primary, `class` for layout only. Decide here: required color vs. `neutral` default, and the final attribute names (shared with `<.badge>`); the name `style` shadows the global HTML `style` attribute, so decide whether to keep it or rename the axis on both components. 6. **Migrate call sites:** every `<.button>` and raw `btn` usage in views, incl. the primary Cancel buttons, the hidden primary “Regenerate cycles”, and the 7 `btn-primary` injections. Apply the label scheme of DESIGN_GUIDELINES §5.7 on the touched buttons. 7. **Segmented control:** `<.segmented>` replacing the three hand-built variants (filter builder, fees tab). Decide the ARIA model (radio group or pressed buttons) and the selected-state color. 8. Remove `priv/static/images/logo.svg` if still unused. 9. Showcase: sections for buttons (all color × style × size), badges, links, switches, checkboxes and text levels in both themes. ## Out of scope - Branding settings, theme picker, runtime color injection (later feature; only the token rules apply). - Email layout colors (branding feature). - Callouts and sections (U5). ## Acceptance criteria - DESIGN_GUIDELINES §1.6 (tokens, one hue per role, ink token, checkbox exception), §3.1 (two text levels), §5.2, §5.4, §5.5, §5.7 are met. - A contrast table for every color/`-content` pair and every derived variant in both themes, all ≥ 4.5:1 (text) / ≥ 3:1 (non-text), is attached to the PR. - Before/after screenshots: member overview header (light and dark), fee type form footer, fees tab toolbar, a page with badges. - No `<.button>` without an explicit color renders as primary; no view passes `btn-*` through `class`. - Keyboard check: focus ring visible on every button style in both themes. - Showcase sections added. - `just ci-dev` green after every step. ## Dependencies - U2 (current daisyUI version). - Blocks U4–U10 (all build on the tokens and the button API). ## Anchors (verified against `main` @ `d9093a1f`, re-check before filing) - Theme blocks: `assets/css/app.css:24-92`; dark overrides that make secondary louder: `assets/css/app.css:576-584` (see also `:569-585`) - Badge/link overrides and `-aa` utilities: `assets/css/app.css:125-255`, `:600-617` - Button default: `lib/mv_web/components/core_components.ex:143` - Primary Cancel buttons: `lib/mv_web/live/membership_fee_type_live/form.ex:146`, `lib/mv_web/live/import_live/components.ex:242` - Hidden primary with injected classes: `lib/mv_web/live/member_live/show/membership_fees_component.ex:156` - Segmented variants: `lib/mv_web/components/add_filter_builder_component.ex` (filter modes), `lib/mv_web/live/member_live/show/membership_fees_component.ex` (cycle status) ## Caution - The guide values come from rendered mockups; soft badges and the nav accent in dark mode were too pale there. Measure, do not trust the guide values. - A future club brand needs two values per theme (surface + ink) plus a computed content color: keep the derivation in one place so a brand only changes token values.
simon closed this issue 2026-10-19 21:49:09 +02:00
Sign in to join this conversation.
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
local-it/mitgliederverwaltung#602
No description provided.