Refresh Badge and StatCard for Dixie dashboard - #35
Conversation
Badge: - Light-mode variants move from white-fill + colored glow to a soft tint + solid hairline border, no glow; text deepens one step and reads roomier. neutral becomes navy-tinted to match the mock. - Variant classes (.gp-badge-*) now own color + semantic weight only; geometry moves into the component's base + size classes so the two no longer fight over padding. - New additive `count` / `countPosition` props render a monospace, tabular count on the leading (flags) or trailing (tags) edge. StatCard: - New `surface` prop: `muted` (default, unchanged filled tile) or `plain` (transparent) so tiles nested inside a Card/SectionCard inherit the surface instead of reading grey-on-white. - Fill control moves fully into the component; .gp-stat-card is now geometry-only, removing the duplicated background definition. Adds Badge and StatCard tests plus playground demos for both. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Preview deployed! 🚀View the playground preview at: https://thegpvc.github.io/gp-ui/pr-35/ Last updated: 2026-07-18T21:00:20.239Z |
Review: Refresh Badge and StatCard for Dixie dashboardOverall this is a clean, well-scoped restyle. Good discipline splitting color/geometry ownership between Design-system conformance
Token-first authoring (per CLAUDE.md)Two new arbitrary-value classes bypass the token system the guide calls out as a review smell:
If these pixel values are needed to match the mock precisely, consider promoting them to Minor a11y noteThe count span applies What looks good
Nothing here blocks merge; the neutral/info collapse is the one I'd want a second look at before it ships, since it affects every badge instance per the PR description. |
|
🧹 Preview deployment has been cleaned up. |
Refreshes Badge and StatCard to match the Dixie dashboard mock. Two independent deltas, folded into one PR.
Badge
The mock's badges use a soft tinted fill + solid hairline border + no glow, they're roomier, and several carry a monospace count.
theme.css): white-fill + halved-opacity border + colored glow → soft*-50tint + solid*-200border, no glow. Text deepens one step (*-800) to read against the tint.neutralbecomes navy-tinted to match the mock;success/infoget the same treatment for family consistency. Dark mode unchanged (the mock is light-only)..gp-badge-*no longer bake in padding/gap/radius — those move to the component's base +sizeclasses, so the two can't fight over spacing (the "sizing prop interaction" the mock flagged). Semantic weight stays on the variant:font-semiboldfor flags (success/warning/error),font-mediumfor info/neutral.count/countPositionprops (additive, no breaking change): render afont-mono tabular-numscount on theleadingedge (flags — "10 flagged") ortrailingedge (tags — "other 525").Deliberate deviation from the handoff: the count is not
aria-hidden. It carries meaning ("10 sessions flagged"), so hiding it from screen readers would drop real information.count={0}renders correctly (covered by a test).StatCard
gp-stat-cardbaked a grey fill that reads muddy grey-on-white when nested inside a white Card/SectionCard (Metrics card, session-detail stat grids).surfaceprop:muted(default — today's filled tile, zero visual change) orplain(transparent, inherits the parent card)..gp-stat-cardis now geometry-only; the fill was previously defined twice (in the CSS class and viacolorClasses[color].bg) and relied on utility-layer ordering. Now a singlesurfaceClasses[color][surface]map owns it.variant="display"is chrome-less and ignoressurface.Tests & playground
Badge.test.tsx(variant classes, count render,count={0}, leading/trailing order) andStatCard.test.tsx(muted default, plain transparent, accent+plain, display-ignores-surface).BadgeDemogets a "With Count" section;StatCardDemogets a "Surface: muted vs plain" side-by-side inside white cards so the muddy-vs-clean difference is the visual contract.Risk
Badgein consuming apps — worth a visual pass on any screen already using badges.surface="muted"is the default, so existing StatCards are unchanged;plainis opt-in.npm run typecheck,npm run build, and the new tests all pass.🤖 Generated with Claude Code