Skip to content

feat(gamut)!: move components onto color roles - #54

Draft
dreamwasp wants to merge 13 commits into
cass-gmt-1825-color-brandsfrom
cass-gmt-1825-color-components
Draft

dreamwasp wants to merge 13 commits into
cass-gmt-1825-color-brandsfrom
cass-gmt-1825-color-components

Conversation

@dreamwasp

@dreamwasp dreamwasp commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Moves every gamut component onto the color system's roles, following design's component map (gamut-sandbox PR #34, Migration → Components, head ef1272a). Stacked on #52. Draft, for showing the team what the components look like on the new colors.

Screenshots: today's core next to this branch on skillsoft and originalCodecademy, light and dark, 37 stories: https://claude.ai/artifact/QJ836yQVQ6ghKHwawDqE5m (private; ask for access).

How it was made

  • Ran the color-roles preset from feat(gamut-codemods): add a color-roles preset #53 on packages/gamut/src: 60 files, 273 lines. A second run changes nothing.
  • Resolved the ~170 places it leaves for a person (splits, retired names, pending names, old palette colors, runtime-built names) using design's component map.

Buttons (Button/shared/variants.ts)

  • variant values don't change. primary, secondary and danger map to action-primary, action-neutral and action-danger, each with its own hover and pressed step; interface merges into primary (TextButton's interface label is text-default).
  • Labels on fills are text-inverse; every variant gets one action-primary focus ring; disabled fill labels are a knockout.
  • StrokeButton and TextButton hover and press with state-hover / state-pressed veils instead of a gray fill and a full inversion.
  • CTAButton follows primary FillButton; its offset shadow is action-neutral until there's a shadow role.

Components, by design's map

  • Alert, Toast, Popover, Menu, Tip, Modals, Flyout, Overlay — floating surfaces are surface-raised with a border-default edge; the scrim is backdrop. Tooltips are no longer black.
  • Form, GridForm, ConnectedForm, Toggle — fields on surface-raised, hover darkens the outline (border-strong) so blue only means focus; a checked Radio is action-primary; Toggle disabled is action-disabled instead of 50% opacity.
  • Card — yellow and hyper become a featured card on the brand gradient (Alert's gradient layer moved to utils/gradientLayer.ts so both use it); navy is a dark-mode scope; every card gets a border-subtle hairline.
  • Badge, Tag — filled badges are text-default / text-subtle behind text-inverse; accent is surface-brand with a border-default edge.
  • Tabs, Disclosure, Pagination, Anchor — block Tabs follow the page's mode instead of forcing dark; Disclosure focus is a ring, not a fill.
  • ProgressBar, DataList, List, BarChart, Markdown, Video, Loading, Typography and the rest — mapped by the closest documented rule; see "Choices" below.

Choices where design has no exact mapping (each has a /* */ comment at the spot)

  • background-current stays in List, Drawer, DataList empty rows, Card's offset shadow, RadialProgress and Text fade. Design describes a surface-current alias that every surface sets; that rename belongs in gamut-styles, as a follow-up.
  • Badge accent gets the flat surface-brand, not the gradient: the gradient is sized in cqw, and a content-sized badge can't be its own container.
  • DatePicker (no map): weekday headers text-subtle, today action-primary, selected day a dark chip with text-inverse, range state-selected, disabled action-disabled.
  • SelectDropdown multi-value chip follows the selection Tag (text-subtle / text-inverse). Design's slot says surface-sunken but its note says "follows the selection Tag", so this needs design to pick.
  • Retired primary-inverse (Text highlight) → action-primary, flagged for design.
  • Video controls are always dark, so they use the mode-independent white and black.
  • BarChart defaults take the plain renames; moving them onto viz-* is a follow-up.

Added 2026-10-29

  • Old themes: feat(gamut-styles)!: rebuild admin, platform, percipio and lxStudio as brands #58 rebuilds admin, platform, percipio and lxStudio as brands and is merged in here, so every theme in the toolbar defines every role. Merge feat(gamut-styles)!: rebuild admin, platform, percipio and lxStudio as brands #58 first. Old coreTheme still has no roles; Original Codecademy is its rebuild.
  • styleguide: its stories and docs are on roles (52 files). The type check has no color errors left; the 23 remaining errors exist on the base branch too (argTypes alias, InfoTip, BarChart, Tabs types).
  • Card: an interactive card gets design's hover. The border goes to border-strong, and a state-hover veil sits under the content, on the same trigger as the existing lift. 4 new tests.
  • Storybook defaults to Skillsoft and drops the old Core option.
  • Tag (design feedback, 2026-10-29): navigation and suggestion tags have no fill of their own, so they sit on the surface they're on. Disabled tags drop the action-disabled fill, take action-disabled ink, and keep their edge. The selection chip at rest stays a dark chip, per design's map. Adds Tag's first tests.
  • Merged in feat(gamut-styles)!: brands, overrides and Original Codecademy on the color system #52's design fixes: Alert's status inks and mode-following CTA, and navy and beige unpinned. Screenshots retaken with all seven themes.
  • Judgement calls in the styleguide, for design:
    • background-selected as a resting panel → surface-sunken
    • text-disabled as muted helper text → text-subtle
    • background-contrast as a label on a fill → text-inverse
    • danger as red text → text-error
    • Tabs yellow → flat surface-brand
    • The PreviewTip avatar loses its yellow accent

Known gaps

  • No shadow role yet, so elevation still renders undefined.
  • BarChart onto viz-* is a follow-up.

PR Checklist

  • Related to designs: gamut-sandbox PR #34, Migration → Components
  • Related to JIRA ticket: GMT-1825
  • Version plan added/updated (.changeset/color-roles-components.md)
  • I have run this code to verify it works
  • This PR includes unit tests for the code change
  • This PR includes testing instructions for the code change

Testing Instructions

  1. npx jest -c packages/gamut/jest.config.ts → 1208 of 1208 pass. On feat(gamut-styles)!: brands, overrides and Original Codecademy on the color system #52, 48 BarChart and Modal tests fail because they expect old names.
  2. npx jest -c packages/gamut-styles/jest.config.ts → 280 of 280; yarn workspace @skillsoft/gamut-styles validate:tokens → every check passes for both brands.
  3. Type-check gamut's library: 0 errors (145 after the codemod alone).
  4. Storybook: pick Skillsoft or Original Codecademy in the theme toolbar, both modes. Check Actions → Buttons → Button Examples, Molecules → Alert, Atoms → FormInputs, Containers → Card, Overlays → Dialog. Compare with the screenshots page.
  5. Switch to Core: components lose their colors. That's expected on this branch (see Known gaps).

🤖 Generated with Claude Code

dreamwasp and others added 4 commits October 28, 2026 14:13
- Ran the color-roles codemod on gamut, then resolved every leftover
  (splits, retired and pending names, old palette colors, runtime names)
  from design's component map in colorSystem/migration.ts.
- Buttons follow design's button map: action families per variant,
  interface merges into primary, text-inverse labels, one action-primary
  focus ring, state veils for StrokeButton and TextButton, disabled
  knockout, CTAButton's offset shadow on action-neutral.
- Card variants become surfaces, with the brand gradient for yellow and
  hyper; Alert's gradient layer moves to utils/gradientLayer for both.
- Stories that painted old palette colors use roles or mode scopes.
- BREAKING: old themes don't define the roles, so components lose their
  colors on core, admin, platform, percipio and lxStudio until they're
  rebuilt as brands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mponents

Picks up #50's tokensCss injection in GamutProvider and the merge of main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mponents

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s brands

Each old theme becomes a brand of the generated color system, so every
theme defines every role and components on roles work under all of them.

- Hues come from what the old theme rendered in each job, including what
  it inherited from core. Page backgrounds, text and yellow are pinned.
  Percipio and lxStudio keep core's yellow accent and dark mode.
- Fonts, weights, elevation and lxStudio's radii are unchanged.
  createBrandTheme takes `borderRadii` and `initialMode`; platform starts
  in dark mode and adds its editor-* colors with their old values.
- The two-color gradient pairs primary with accent-alt for every brand
  with a yellow accent, as design asked for Original Codecademy.
- validate-tokens treats a polished rounding tie as agreement with the
  content-mode table and reports it (percipio primary-600).
- The styling contract test only reads the blocks of the brand it tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dreamwasp and others added 9 commits October 29, 2026 10:52
Design's card map (Interactive) puts a `state-hover` veil over the card's
own fill and darkens the edge to `border-strong` on hover. The veil is a
layer behind the content, so it tints the fill and a brand gradient but
not the text, and it keys off the same wrapper hover as the elevation
lift. The theme's elevation hover stays until elevation tokens exist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ran the color-roles codemod over packages/styleguide and resolved every
split, retirement and old palette color it flagged, following design's
migration map and the choices gamut's components already made. Stories
and docs that list color names now show roles, MDX examples included.
The Storybook provider sets the page surface from the selected theme's
`background-current` instead of a white/navy palette pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…olor-components

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ption

Every theme in the toolbar is now a brand of the generated color system.
Old core has no roles, so components on roles render without color under
it; Original Codecademy is its rebuild. The core theme docs page shows
Original Codecademy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
packages/.storybook is the config Storybook runs; the theme default change only belongs there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gacy-brands

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Design feedback on the comparison page (2026-10-29): pinned navy-800
carries much more chroma than the generated surfaces beside it. As for
Original Codecademy (#52), lxStudio uses the generated step at navy's hue.
Admin and platform inherit Original Codecademy's pins, so they follow;
platform's blue-0 and the near-white pages are nearly achromatic and stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…olor-components

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Design feedback on the comparison page (2026-10-29): selection and
navigation tags shouldn't have a fill.

- Navigation and suggestion tags rest on a transparent fill instead of
  surface-raised, so they don't show as a white box on beige or paper
  pages. Hover and press stay veils.
- A disabled tag drops the action-disabled fill. With nothing under it,
  the knockout label becomes the action-disabled ink; a disabled
  selection chip keeps an inset border-default edge so it doesn't resize.
- The selection chip at rest stays a text-subtle chip, per design's map.
- Adds Tag's first unit tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@dreamwasp dreamwasp left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix from design feedback on the components comparison page (2026-10-29).

*/
navigation: {
bg: 'background-current',
bg: 'transparent',

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design feedback (2026-10-29): selection and navigation tags shouldn't have a fill. Navigation and suggestion tags were surface-raised, which shows as a white box on beige or paper pages. They're transparent now, so they sit on whatever surface they're on; hover and press stay state-hover / state-pressed veils. The selection chip at rest stays text-subtle behind text-inverse, per design's map.

* a knockout label to sit on. The label takes the disabled ink instead,
* and the chip keeps an edge, inset so disabling it doesn't resize it.
*/
selectionDisabled: {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disabled tags lose the action-disabled fill too. A knockout label (surface-raised) needs a fill under it, so the label becomes the action-disabled ink instead. This is contrast-exempt as an inactive control. The chip keeps a border-default edge as an inset shadow, so disabling it doesn't change its size. Navigation, suggestion and the dismiss button get the same treatment below.

This branch has not been deployed

No deployments
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