Skip to content

feat(ui): three buttons, and a label you can read on each - #83

Merged
youhide merged 1 commit into
mainfrom
c2-three-buttons
Aug 21, 2026
Merged

feat(ui): three buttons, and a label you can read on each#83
youhide merged 1 commit into
mainfrom
c2-three-buttons

Conversation

@youhide

@youhide youhide commented Aug 21, 2026

Copy link
Copy Markdown
Owner

C2, and it found a live accessibility failure.

Four primary buttons, disagreeing about everything

Values in use
Text colour Color::WHITE (3 places) vs palette.background (2)
Radius 6.0 (3) vs 3.0 (2)
Hover 0.85, 0.9, or palette.border
Disabled dimmed fill at 0.35, at 0.25, or border + muted

The text colour was not merely inconsistent

Measured against WCAG 2.1:

dark light
Color::WHITE on accent 3.21:1 5.53:1
Color::WHITE on danger 3.35:1 5.36:1
palette.background on accent 5.52:1 ✅ 4.89:1 ✅
palette.background on danger 5.30:1 ✅ 4.74:1 ✅

Button labels need 4.5:1. So on the default theme, the primary button of every confirmation dialog, the Commit button, and both welcome buttons were below AA.

Why nothing caught it

This is exactly the blind spot the plan named. The palette's contrast is thoroughly asserted — body text, secondary text, the semantic colours used as text, the graph lanes, even under simulated deuteranopia and protanopia. Nothing checked a label on a filled button, because no palette slot describes that pairing.

Painting a destructive button with the accent also passed every test in the crate. It now fails one.

Two of the offending whites were painted from inside the button's content, over the style's own text_color — no change to the style could have corrected those. So the guard that keeps rules out of view files now also refuses Color::WHITE and Color::BLACK there. After the scrim in #81, both hardcoded colours have caused the same class of bug, and neither has a legitimate use left outside the highlighter's contrast bisection.

Design notes

Disabled is an opaque pair, not the fill at an alpha. What an alpha lands on depends on whatever is behind the button, so its contrast cannot be stated — let alone asserted, which is the point.

quiet gains an outline. The welcome screen's secondary button already had one; the dialogs' Cancel did not. UI_SPEC.md wants Cancel unemphasised — an outline does not undo that, it only makes the target visible before the pointer is over it.

Left alone: the rebase plan's segmented verb control and the tab's close button. Neither is one of the three roles, and both would be worse for pretending to be.

Sabotage — two, both confirmed

Sabotage What broke
the label goes back to Color::WHITE a_button_label_is_readable_on_the_button"dark/primary in Active is 3.21:1, under the 4.5:1 a label needs"
danger is filled with accent a_destructive_button_never_wears_the_ordinary_one_s_colour

The first reproduces the exact number computed by hand before any code changed, which is what makes it a measurement rather than an opinion.

Screenshots

Three retaken — graph, staging and light-theme. The toolbar buttons are outlined now, and the Commit button's label changed colour. command-palette is unchanged: it has no buttons.

Gate

cargo fmt --all -- --check, cargo clippy --workspace --all-targets --all-features --locked -- -D warnings, cargo test --workspace --all-features --locked — 900 tests, all green.

Four designs for "the primary button" existed at once, and they disagreed about
every part of it. The text was `Color::WHITE` in three places and
`palette.background` in two; the radius was 6 in three and 3 in two; hover was
0.85, 0.9, or the border colour depending where you looked.

The text colour was not merely inconsistent. White on the dark theme's accent
measures 3.21:1 and on its danger 3.35:1, under the 4.5:1 a button label needs,
while `palette.background` clears it in both themes — 5.52 and 5.30 on dark,
4.89 and 4.74 on light. So the primary button of every confirmation dialog, the
Commit button and both welcome buttons were below AA on the default theme.

That is the blind spot this item was for. The palette's contrast is thoroughly
asserted — body text, secondary text, the semantic colours used *as* text, the
graph lanes, even under simulated colour blindness — but nothing checked a label
*on* a filled button, because no palette slot describes that pairing. Painting a
destructive button with the accent passed every test in the crate too, and now
does not.

Two of the offending whites were painted from inside the button's content, over
the style's own `text_color`, where no change to the style could have corrected
them. The guard that keeps rules out of view files now also refuses
`Color::WHITE` and `Color::BLACK` there: after the scrim, both hardcoded colours
have caused the same class of bug, and neither has a legitimate use left outside
the highlighter's contrast bisection.

Disabled is an opaque pair rather than the fill at an alpha. What an alpha lands
on depends on whatever is behind the button, so its contrast cannot be stated,
let alone asserted — and asserting it is the point.

`quiet` gains an outline, which the welcome screen's secondary button already
had and the dialogs' Cancel did not. `UI_SPEC.md` wants Cancel unemphasised; an
outline does not undo that, it only makes the target visible before the pointer
is over it.

Left alone: the rebase plan's segmented verb control and the tab's close button,
which are not one of the three roles and would be worse for pretending to be.
@youhide
youhide merged commit b362363 into main Aug 21, 2026
7 checks passed
@youhide
youhide deleted the c2-three-buttons branch August 21, 2026 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant