Skip to content

refactor: colour system cleanup — container recipe + palette semantics - #12574

Open
Healsi wants to merge 12 commits into
mainfrom
ds-color-cleanup
Open

refactor: colour system cleanup — container recipe + palette semantics#12574
Healsi wants to merge 12 commits into
mainfrom
ds-color-cleanup

Conversation

@Healsi

@Healsi Healsi commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

The main purpose of this PR is to make it easier for designers, engineers and agents to know which color to use where. It fixes inconsistencies with the colors and makes them them easier to maintain while being somewhat consistent with MUI.

The problem we're solving

I've found the existing color system confusing to use, and I've noticed that people have a hard time knowing which color to use where, and that a bunch of colors being used out of their intended usage.

This is not ideal because colors ends up being used for other purposes, and it makes the design system hard to use and maintain.

What's done?

Nothing changes visually in this PR. It cleans up the theme color system so that semantic palettes follows the MUI contract and share one consistent recipe for main, text, and surface/container backgrounds, then remaps every usage to match. No logic, data-flow, or behavioral changes. purely styling and variable remapping.

Theme changes

  • Adds a container recipe (container / containerBorder / onContainer) to primary + info / success / warning / error / neutral for tinted surfaces (badges, chips, soft banners, alerts).
  • Restores MUI-standard meaning to .light (now a mid-shade of main, was a pale tint) and .contrastText (now text-on-main, was text-on-tint).
  • Removes redundant slots on semantic palettes: .bordercontainerBorder, background.applicationbackground.default, action.alternative is removed, and palette.spotlight is removed.
  • Repurposes background.default as the app canvas; background.paper is the surface.
  • Makes secondary dormant (all usages migrated to primary). This slot will be repurposed for a secondary color later.

Usage remaps

  • 179 component files remapped mechanically to the new tokens.
  • Defensive fallbacks (container ?? light, onContainer ?? contrastText, containerBorder ?? border) keep the dormant secondary palette rendering correctly.

Important files

  • frontend/src/themes/theme.ts, dark-theme.ts, themeTypes.ts — the source of the change.

Screenshots:

image image image image image

@github-actions

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@Healsi Healsi added the 🤖 all-ai Fully LLM generated (minor human check) label Aug 26, 2026
@gastonfournier gastonfournier moved this from New to In Progress in Issues and PRs Aug 27, 2026
@gergokekesi

Copy link
Copy Markdown
Contributor

@Healsi Sorry I couldn't give it a more thorough look but here's a quick review I did with Claude. Please skim through, it may be rubbish:

Review complete. Checked remap classes for both themes and searched the post-PR tree for leftovers. The mechanical changes are mostly clean, but a visual issue exists in dark mode: text that was colored now appears white (~30 sites affected). This is because onContainer defaults to #EEEEFC, which overrides old color tokens used by alerts and badges.

Must fix / acknowledge:

  1. Dark Mode Color Changes: Every remap from X.dark → X.onContainer turns colored text into white (~30 sites affected). Old dark theme colors (info/success/warning/error) are now lost or overwritten with the new container color. Affected files include: BillingPlan.tsx, ChangeRequestReviewStatus.tsx, InstanceStatusBar.tsx, and many others (e.g., FeatureStaleCell, ReactJSONEditor).
  2. Demo Spotlight Colors: The demo colors changed from old hues to primary palette colors (primary.main/.light). Dark mode's new dark shade is much darker than the old outline color, which affects visual appearance in demos only.
  3. GoalSummaryPanel.tsx: Gradient background replaced with flat fill for dark mode.

Verified clean (value-by-value):

  • All remaps (light→container, border→containerBorder, etc.) are exact and present in both themes.
  • No leftover references to removed slots or semantic colors outside the theme files.
  • Standard Alerts use container overrides; no MUI buttons/chips picked up changed semantics.

Notes:

  • Body Background: Changed from light/dark grey values via CssBaseline. Component-level remaps were applied, but loading/unstyled surfaces shifted slightly.
  • MUI Internals: New semantic .light and contrastText feed default styles if not overridden (e.g., filled Chips). Nothing found yet; a visual sweep is the safety net for this 179-file change.
  • PR Description Stale: It claims defensive fallbacks, but the head commit drops them entirely ("refactor: drop dead container-recipe fallbacks"). Update description.
  • Badge Color Union: Still offers 'secondary'. With secondary now fjord teal, a stray renders teal. Drop this from the union since it is dormant outside themes.

@Healsi

Healsi commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Thanks! 
 I have double checked a few of your findings.


1. This is how dark mode behaved before the refactor. I think it’s flagged because it breaks the MUI pattern and the general pattern of the color system, but it’s consistent with how it was used before the refactor. This needs to be addressed later when we adjust the dark mode colors.

  1. This dont make sense to me. I checked the values before replacing them and they are almost identical. Visually I can’t spot any difference. Screenshots below.
image
  1. This is no problem. We’re not using gradients except in legacy designs.

Healsi and others added 12 commits September 4, 2026 11:06
Replace secondary.light/border usages with primary.container/containerBorder
across components and align theme definitions as part of the color cleanup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…trastText semantics

Give success/warning/error/info a container/containerBorder/onContainer recipe
(= the old light/border/contrastText tint values) and migrate every consumer onto
it, mirroring the primary-container migration. With those slots freed, repoint
.light to one ramp step lighter than main and .contrastText to a true contrast
against main (grey[50]), restoring their proper MUI meaning. Visual no-op: new
slots equal the old values in both light and dark themes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Badge container migration flipped <Badge color='primary'> from bright
primary.light to pale primary.container. The Connect SDK stepper's active step
was the only pre-existing primary badge, so it lost its saturated CTA look.
Give it a dedicated StyledActiveBadge (primary.main + white), mirroring the
existing StyledCompletedBadge, and split the render into explicit
completed/active/inactive states.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Give neutral the same container/containerBorder/onContainer recipe as the alert
palettes (= the old light/border/contrastText values) and migrate every consumer
onto it. Repoint .light to one step lighter than main (grey[600]) and
.contrastText to grey[50], restoring their proper MUI meaning. Visual no-op: new
slots equal the old values in both light and dark themes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The interactive demo guide's spotlight used a standalone hardcoded color set.
Point its highlight border/outline and beacon pulse at primary.main/light/main
and drop the now-unused spotlight palette from both themes and themeTypes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
background.default duplicated background.paper (identical value in both themes).
Point every consumer at paper so default is reserved for its MUI role (the page
background behind paper surfaces). Visual no-op. Also reorder the background keys
and mark alternative as deprecated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove per-token comments that just repeat what the name or MUI convention
already conveys (contrastText "contrast against main", "container fill",
"one step lighter than main", etc.). Keep only the non-obvious notes: the
container-recipe provenance, secondary being dormant, dark used as text,
web = sales, and the application/alternative usage notes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pplication

background.default duplicated paper (white); the real page canvas lived in a
custom background.application key. Point default at the canvas value
(grey[300] / #1A1924) per MUI convention (default = page background, paper =
surface) and migrate every application usage to default. Visual no-op for
content surfaces; the <body>/canvas is now the canvas color instead of white.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
info/success/warning/error/neutral used .dark as a text color, which conflicts
with MUI's meaning of dark (a darker shade of main). Point those text usages at
.onContainer (identical value, semantically "text on the container surface") and
drop the stale "used for text" comments. Widen StyledReviewTitle's color prop to
optional since onContainer is optionally typed. Visual no-op.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l panel

action.alternative was a solid brand purple (not an interactive-state color) used
in exactly one place: the dark-theme gradient of GoalSummaryPanel. Point that at
background.alternative (solid, since both stops were the same) and remove the key
from both themes plus its CustomTypeAction augmentation, leaving action as a clean
MUI-contract palette.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Turn the dormant secondary palette into the "fjord" teal, following the
same recipe as primary and the semantic palettes (main + light/dark +
tinted container). Migrate the two primary-button hover styles that only
borrowed secondary.light as a pale-purple tint over to primary.container,
and point the child-dependency badge at the primary palette.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Now that every palette a dynamic color key can resolve to defines the
full container recipe, the `?? light` / `?? contrastText` / `?? border`
fallbacks in Badge, EventTimelineEventCircle, IntroUserGrid and
IntroShowcase are dead code. Collapse them to the direct token and remove
the now-unused optional `border` field from the palette type. Banner's
cross-palette default fallback is left intact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🤖 all-ai Fully LLM generated (minor human check)

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants