Skip to content

[bug] All 11 DataTab status badges are light-theme Tailwind pairs on a dark-only app, and disagree with the app's own success/error colours #368

Closed

Description

@serge-ivo

Every badge in DataTab is a light-theme design, on an app that has no light theme

tabs/DataTab.tsx:42-56:

const STATUS_CLASS: Record<string, string> = {
	new:         "bg-blue-100 text-blue-700",
	contacted:   "bg-amber-100 text-amber-700",
	won:         "bg-green-100 text-green-700",
	dead:        "bg-gray-200 text-gray-600",
	none:        "bg-green-100 text-green-700",
	unreachable: "bg-amber-100 text-amber-700",
	running:     "bg-blue-100 text-blue-700",
	completed:   "bg-green-100 text-green-700",
	failed:      "bg-red-100 text-red-700",
	interrupted: "bg-amber-100 text-amber-700",
};
function Badge({ value }) {
	const cls = STATUS_CLASS[value] || "bg-gray-100 text-gray-600";
	…
}

Eleven entries, every one a *-100 background with *-700 text — the standard Tailwind light
mode
pairing. The console's only palette is dark (--color-paper: #0a0a0a, index.css:15), so
these render as bright pastel blocks on near-black. Not unreadable — dark-on-light is legible — but
they are the only elements in the app that look like they came from a different product, and they sit
in a data table where several appear at once.

dead and the fallback are the worst: bg-gray-200 text-gray-600 and bg-gray-100 text-gray-600 are
mid-grey on light-grey, a pairing designed to recede on a white page. On black it neither recedes nor
reads.

It also disagrees with the rest of the console about what "success" looks like

The app's success colour is --color-green: #22c55e, used as text-green throughout — the runner
status dot, the deploy line, every confirmation message. DataTab's won/completed/none badges use
green-700 on green-100 instead. So two surfaces in the same product show two different greens for
the same idea, and neither is the token.

Same for failed (red-700 vs the app's text-red), running (blue-700 vs --color-blue), and
contacted/interrupted/unreachable (amber-*, which is not a token at all — there is no amber in
@theme).

Fix

Rebuild the map on the app's own tokens, as tinted-background + solid-foreground pairs:

  • won · completed · none → green
  • failed → red
  • contacted · interrupted · unreachable → yellow (the existing --color-yellow, standing in for
    the warning intent)
  • new · running → blue
  • dead and the fallback → muted

The tint currently has to be an opacity hack (bg-green/10) because the design system's -soft
background pairings are not declared in this repo's @theme. That is #367's to fix properly; this
issue should use whatever exists at the time rather than wait for it.

Worth doing as its own change even though #366 introduces a shared Badge: this is a
colour-correctness bug that ships today, and it is ten lines. The shared component can adopt the
corrected map afterwards.

Found while measuring the console against DESIGN-SYSTEM.md (#367).

Activity

  1. serge-ivo commented on Aug 7, 2026

    @serge-ivo
    ContributorAuthor

    Context update — the fix direction is now settled. The owner decided on 2026-08-07 that PAGS does not follow the other stores' design system (#367, workspace commit serge-ivo/stores@358b029).

    That does not soften this ticket — it sharpens it. The console being dark-only is exactly why bg-blue-100 text-blue-700 is a bug rather than a light-mode style, and having our own system is a reason to name tokens, not to keep Tailwind literals.

    So: replace all 11 with PAGS's own semantic status tokens, dark-only values, agreeing with what the rest of the console already uses for success/warning/error. Do not introduce a twelfth colour vocabulary. The one rule taken verbatim from the shared spec is never hardcode red/green/yellow hex.

    The sweep still matters: bg-*-100 text-*-700 is a mechanically detectable signature, and a file with 11 of them is unlikely to be the only one.

  2. serge-ivo commented on Aug 7, 2026

    @serge-ivo
    ContributorAuthor

    Fixed in 60fe544. CI green.

    What the badges use now

    Not new dark values picked by eye — the console already had a status vocabulary, in BoardTab.statusClass: a tinted background under a solid foreground of the same @theme token, at /15. DataTab now agrees with it instead of inventing a twelfth.

    The map is routed through an intent rather than a colour, which is the part worth keeping:

    Intent Class Statuses
    success bg-green/15 text-green won · completed · none
    danger bg-red/15 text-red failed
    warning bg-yellow/15 text-yellow contacted · interrupted · unreachable
    info bg-blue/15 text-blue new · running
    neutral bg-muted/15 text-muted dead, and the fallback

    --color-green is the app's success colour everywhere else (runner dot, deploy line, every confirmation), so the two surfaces now show one green for one idea. --color-muted at 15% is what BoardTab already used for rejected/cancelled — dead reads as receded on black, which is what the light-grey pairing was trying and failing to do.

    It lives in store/console/src/lib/statusBadge.ts, pure, with statusBadge.test.ts (6 tests). BoardTab delegates to it and keeps only its three board-only hues (needs_human, interview, blocked) — those must read as distinct from queued/running/failed sitting beside them, and @theme has no token for them. No pixel changes on the board.

    The tint stays an opacity modifier, as the ticket anticipated — @theme declares a soft background for the accent and for nothing else. #367 §1 now records that.

    The badges were the symptom, not the extent

    Sweeping the same file for the same class found the component was authored for a light theme throughout, not just in its badges:

    Before After
    Column-picker dropdown bg-white bg-panel
    Sticky table headers (×4) bg-white bg-panel
    Kanban cards bg-white bg-panel
    Record-detail modal bg-white bg-panel
    Row hover (×2) hover:bg-black/5 hover:bg-panel
    Run error count text-red-600 text-red
    22 borders bare border / border-b + border-line

    The borders are worth naming: Tailwind v4 changed the default border colour from gray-200 to currentColor, so a bare border in this app renders as near-white --color-ink lines. Every table rule and control outline in DataTab was drawing at full brightness.

    Sweep count for the light-theme signature

    Searching (bg|text|border)-<hue>-(50|100|200|300) across the trees I own:

    • store/console/src: 13 occurrences. 11 in DataTab.tsx (this bug), 2 in pages/Login.tsx — bg-gray-50 + border-gray-200 on the Google sign-in button, which is brand-mandated (Google's guidelines specify a white button) and is a white button on every site that has one. Left alone, allowlisted explicitly.
    • store/admin/src: 0.
    • agents/coder/web has 4 more (bg-orange-50 ×3, text-neutral-200) but is another agent's tree — not touched, flagged here.

    So DataTab was all of the console's genuine light-theme drift. The signature is now gated at zero by a test (see #367).

    One trap worth recording

    Tailwind v4's source scan reads comments and strings, not just JSX. The first version of the fix quoted the broken utility names while explaining them, and those exact rules reappeared in the built stylesheet — the bug's CSS surviving its own postmortem. The comments describe the shape instead ("a 100-level background under 700-level text"), and the built CSS is verified free of them.

    Verified: biome check --error-on-warnings store clean, tsc --noEmit clean, vite build clean, 493 store unit tests pass, CI green on 60fe544.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfrontendFrontend / UI work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions