mara: "make clickable badges a proper pill not a roundrect" (#4276). .ui-badge's base border-radius: 1em is a genuine pill at its own compact display-only height, but .ui-badge-interactive's min-height: 2.75em (the WCAG 2.5.5 touch-target floor) makes an interactive badge tall enough that the fixed 1em radius no longer reaches half the box's height -- the corners round without the sides ever meeting the same curve, i.e. a rounded rectangle. border-radius: 999px is the standard stadium-shape trick (the browser clamps it to exactly half the box's height whenever it exceeds it), same value .hive-pill/.hive-pill-sm already use. Shared component -- fixes every interactive Badge caller (swarm-ui's WantedMenu/AgentCard/model-effort pickers, the per-agent page's StatusChips/MetaNav/HeaderPill) in one place. Verified with a real headless-chromium screenshot of the /components Badge section before/after: the interactive "model sonnet"/"pause" badges were visibly rectangular with rounded corners before this, matching the non-interactive display badges' pill shape after.
133 lines
5.8 KiB
CSS
133 lines
5.8 KiB
CSS
/* <Badge> — pill-shaped status/control chip. Same touch-target floor as
|
|
the rest of the shared control set (2.75em ≈ 44px, WCAG 2.5.5) when
|
|
interactive; a plain display badge (no `onClick`) stays compact since
|
|
it's not a tap target at all. Colours are the shared base16-derived
|
|
vars (../theme.css) — `--bg-elev` is the same slot dropdowns/popovers
|
|
use, so an open Badge and the Dropdown it triggers read as one surface. */
|
|
.ui-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.35em;
|
|
padding: 0.15em 0.6em;
|
|
border-radius: 1em;
|
|
font: inherit;
|
|
font-size: 0.85em;
|
|
line-height: 1.4;
|
|
background: color-mix(in srgb, var(--purple-dim) 65%, transparent);
|
|
-webkit-backdrop-filter: blur(6px) saturate(140%);
|
|
backdrop-filter: blur(6px) saturate(140%);
|
|
color: var(--fg);
|
|
border: none;
|
|
white-space: nowrap;
|
|
}
|
|
/* Frosted-glass fill (mara: "make badges look glassy... in dark mode
|
|
the added transparency improves readability, bg behind is dark") —
|
|
same recipe as the header chrome/terminal glass (`chrome.css`,
|
|
`terminal.css`): translucent `color-mix` + `backdrop-filter`. Only
|
|
for the default filled badges — `variant="quiet"` (below) already
|
|
has no fill at all, nothing to frost.
|
|
Dark (mocha) only, deliberately: her own reasoning was conditioned
|
|
on a dark surface behind the badge. A light (latte) page has bright,
|
|
often busy content behind a badge — the same transparency would
|
|
wash out the value text instead of improving it, the opposite of
|
|
what this is for — so light mode keeps the plain solid fill. Same
|
|
three-way structure `colors.css` uses for every light/dark switch:
|
|
this default rule *is* the dark look (mocha is the default palette),
|
|
the `@media`/`:root[data-theme]` blocks below revert it for light,
|
|
restore it for an explicit dark override. */
|
|
@media (prefers-color-scheme: light) {
|
|
.ui-badge {
|
|
background: var(--purple-dim);
|
|
-webkit-backdrop-filter: none;
|
|
backdrop-filter: none;
|
|
}
|
|
}
|
|
/* `:not(.ui-badge-quiet)` here, unlike the base rule/`@media` block
|
|
above — argus's review: both of these add `:root`+`[data-theme]` to
|
|
the selector, so specificity is 0-3-0 vs plain `.ui-badge-quiet`'s
|
|
0-1-0. Without the exclusion these would beat quiet's `background:
|
|
none` (below) whenever a user has an *explicit* theme override set
|
|
(SettingsMenu's dropdown, not just the OS default), reintroducing
|
|
the settings/links "should not have the badge bg" bug on those
|
|
triggers. Verified against a real repro before landing, not just
|
|
the specificity arithmetic. */
|
|
:root[data-theme="light"] .ui-badge:not(.ui-badge-quiet) {
|
|
background: var(--purple-dim);
|
|
-webkit-backdrop-filter: none;
|
|
backdrop-filter: none;
|
|
}
|
|
:root[data-theme="dark"] .ui-badge:not(.ui-badge-quiet) {
|
|
background: color-mix(in srgb, var(--purple-dim) 65%, transparent);
|
|
-webkit-backdrop-filter: blur(6px) saturate(140%);
|
|
backdrop-filter: blur(6px) saturate(140%);
|
|
}
|
|
/* The base `.ui-badge` rule's `border-radius: 1em` is a genuine pill at
|
|
its own compact display-only height, but `min-height: 2.75em` below
|
|
(the WCAG 2.5.5 touch-target floor) makes an *interactive* badge tall
|
|
enough that a fixed 1em radius no longer reaches half the box's
|
|
height — the corners round without the sides ever meeting the same
|
|
curve, i.e. a rounded rectangle, not a pill (mara: "make clickable
|
|
badges a proper pill not a roundrect"). `999px` is the standard
|
|
stadium-shape trick — a radius the browser clamps to exactly half the
|
|
box's height whenever it exceeds it, so it reads as a true pill at
|
|
any height instead of one tuned for a specific one. Same value
|
|
`.hive-pill`/`.hive-pill-sm` (`shared/src/pill.css`) already use. */
|
|
.ui-badge-interactive {
|
|
cursor: pointer;
|
|
min-height: 2.75em;
|
|
padding-inline: 0.8em;
|
|
border-radius: 999px;
|
|
}
|
|
.ui-badge-interactive:hover {
|
|
background: var(--border);
|
|
}
|
|
.ui-badge-interactive:disabled {
|
|
opacity: 0.6;
|
|
cursor: default;
|
|
}
|
|
/* `variant="quiet"` — icon-only header triggers (settings/links), not
|
|
status chips: no permanent fill, so it reads as chrome next to the
|
|
rest of the header rather than another data pill. The `:hover` and
|
|
`[aria-expanded='true']` rules above still apply — quiet only drops
|
|
the idle background, which is what mara's report was actually about. */
|
|
.ui-badge-quiet {
|
|
background: none;
|
|
}
|
|
.ui-badge-interactive[aria-expanded="true"] {
|
|
background: var(--bg-elev);
|
|
outline: 1px solid var(--purple);
|
|
}
|
|
.ui-badge-label {
|
|
color: var(
|
|
--muted-on-dim
|
|
); /* --muted alone is too low-contrast on this fill, see theme.css */
|
|
}
|
|
.ui-badge-value {
|
|
color: var(--fg);
|
|
/* Fixes badge with emoji having different size. */
|
|
line-height: 1;
|
|
}
|
|
/* Blended with `--fg`, not the raw accent — a stylix-fed scheme can pick
|
|
any hue/lightness for `--green`/`--amber`/etc., and nothing guarantees
|
|
an arbitrary accent clears 4.5:1 against `--purple-dim` the way the two
|
|
bundled palettes were hand-tuned to (see colors.css's comment above
|
|
`--latte-base08..0F`). `--fg` is the one color the base16 contract
|
|
already guarantees is legible on every surface in the theme, so mixing
|
|
toward it gives every accent a contrast floor without trying to
|
|
compute/fix an operator's own theme (mara, on the low-contrast-badges
|
|
report: "we cant fix a broken theme ... we need to follow base16
|
|
conventions or css mix new colors" — this is that; stock mocha/latte
|
|
keep their existing look, since both accents already sit close to
|
|
`--fg` in contrast terms). */
|
|
.ui-badge-positive .ui-badge-value {
|
|
color: color-mix(in srgb, var(--green) 60%, var(--fg));
|
|
}
|
|
.ui-badge-warning .ui-badge-value {
|
|
color: color-mix(in srgb, var(--amber) 60%, var(--fg));
|
|
}
|
|
.ui-badge-negative .ui-badge-value {
|
|
color: color-mix(in srgb, var(--red) 60%, var(--fg));
|
|
}
|
|
.ui-badge-accent .ui-badge-value {
|
|
color: color-mix(in srgb, var(--purple) 60%, var(--fg));
|
|
}
|