Feature - Establish house-style color system and migrate collections to it - #752
Draft
markmead wants to merge 30 commits into
Draft
Feature - Establish house-style color system and migrate collections to it#752markmead wants to merge 30 commits into
markmead wants to merge 30 commits into
Conversation
…o a single collection flag Dark mode support moves from a per-component opt-in (duplicated dark: true across every entry in a collection) to a single collection-level flag in content.config.ts, defaulting to false until a collection has been through a full house-style audit. ComponentPost.astro now renders a dark card for every component purely off that flag; the per-component field is retired in favor of an optional darkContributors override for the rare hand-authored dark variant (announcements, toasts, steps keep their WinnyChang credit). Adds two targeted dark-mode rules (src/lib/dark-mode/config.js) so solid action/destructive buttons map to indigo-500/red-500 in dark mode instead of the generic shade map's washed-out indigo-300/red-300, and fixes the browser tool's createDefaultConfig() to actually seed from those rules instead of hardcoding an empty array. badges is migrated as the pilot collection: its four generic variants used arbitrary purple, now standardized to the indigo action color; its themed variant already matched the intended success/warning/error recipe. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…the house style The Rules panel now auto-loads 3 house-style rules (from the previous commit's createDefaultConfig fix) with no explanation of where they came from. Adds a short line above the rule list so it's not a silent surprise. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tracks status, the settled house-style color table, and the remaining phases for the collection-by-collection dark mode migration, so the effort can be picked back up without re-deriving the decisions already made (house style values, which collections are exempt, why). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ark-mode-reset # Conflicts: # src/layouts/ComponentPost.astro
…ants Fixes the grouped/bordered variant's border-gray-300 to border-gray-200, matching the convention used by other grouped interactive elements (button-groups, pagination). Switches to the collection-level dark flag and regenerates all five dark variants through the shared engine.
…riants Fixes focus:ring-blue-500 (a stray shade found nowhere else in the codebase) to focus:ring-gray-900 per the house style's non-action-control focus ring rule. Switches to the collection-level dark flag and regenerates all five dark variants through the shared engine.
…follow-up charts pairs Tailwind classes with hand-picked Chart.js hex colors in inline <script> blocks that the shared dark-mode engine can't touch, so the normal delete-and-regenerate Phase 3 step would silently break dark mode there. Skipping it in the alphabetical rollout order until it gets its own pass.
No light-mode class drift found. Regenerating dark variants dropped the control's own dark:bg-gray-900/dark:ring-offset-gray-900 because @tailwindcss/forms bakes a white background and white ring-offset into its own base CSS for [type=checkbox], never exposed as a light-mode class for the engine to transform — restored both by hand to avoid a white checkbox on a dark page. Documents the same gap for other forms-plugin collections still to come.
…iants No light-mode class drift found. Regeneration only tightened dark:text-white to dark:text-gray-50, the engine's standard shade-map inversion for text-gray-900 headings.
Fixes the divider line's bg-gray-300 (and gradient to-gray-300) to bg-gray-200/to-gray-200, matching the house style table's border-gray-200 row which names dividers explicitly under the default (not emphasized) border weight.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
hyperui | 375a44a | Commit Preview URL Branch Preview URL |
Sep 04 2026, 10:53 AM |
…cript' into feature/house-style-dark-mode-reset
…cript' into feature/house-style-dark-mode-reset
CLAUDE.md now mentions the scoping flags in the main dark-variant-generation note. HOUSE_STYLE_PLAN.md's Phase 3 instructions and rollout log were still describing the old unscoped, discard-the-extras workaround now that the generator itself is fixed.
…s-script) That doc line is owned by feature/generate-dark-variants-script's own CLAUDE.md addition, not this branch's — moving the flag documentation there instead so each branch's docs match what it actually introduces.
…cript' into feature/house-style-dark-mode-reset
… divider dark:bg-black had almost no contrast against the preview iframe's own bg-gray-900 wrapper, making the card nearly disappear. Uses dark:bg-gray-800 for the card (visibly lighter than the page) and dark:bg-gray-900 for the recessed "Home" segment inside it, preserving the same relative relationship as light mode (bg-gray-100 inside bg-white) just inverted. Documents the same gotcha in HOUSE_STYLE_PLAN.md for any future bg-white-card component.
…se-style-dark-mode-reset
Phase 2: both wrapper elements (split-button trigger, flyout menu panel) used border-gray-300/divide-gray-300, neither of which is a form input — changed to border-gray-200 to match the button-groups/card precedent. Also fixed the "Delete" menu item's text-red-700 to text-red-600 per the house style table's plain-destructive-text row. Phase 3: regenerated dark variants, then applied two known gotchas by hand — the bg-white card fix (dark:bg-black -> dark:bg-gray-800) and, new this collection, a hover/card-shade collision it exposed: with the card now dark:bg-gray-800, the engine's dark:hover:bg-gray-800 on items inside it collides and the hover highlight disappears, so bumped it one step lighter to dark:hover:bg-gray-700. Also hand-added the dark:bg-gray-900 body background (#754) that the generator script doesn't know to add to freshly-generated files. Flips dropdown's collection-level dark flag and documents both gotchas in HOUSE_STYLE_PLAN.md for the next collection.
scripts/generate-dark-variants.js previously left every freshly-generated -dark.html's <body> without the dark:bg-gray-900 background from #754 (that fix predates the script, and <body> never carries a bg-* class in light mode for the shade-map engine to invert in the first place), so it had to be added by hand for every migrated collection. Adds ensureBodyDarkBackground(), a small post-processing step run on the generator's output that adds dark:bg-gray-900 to <body>'s existing class attribute, or adds the attribute if <body> has none. Verified against both cases with throwaway fixtures. Only affects the Node CLI path (transformHtmlString) — the browser tool's DOM-aware path only ever returns body.innerHTML for iframe embedding, so it was never exposed to this gap.
…iants Fixed a stray focus:border-indigo-500 (Action color) on the search input's focus state - non-action controls use the gray-900 focus color. Regenerated dark variants and restored the dark:bg-gray-900/dark:ring-offset-gray-900 pairing on the search input by hand, since @tailwindcss/forms bakes a white background/ring-offset into plain text inputs (not just checkboxes/radios) that the light file never states as a class, so the engine can't invert it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ariants Light-mode classes already conformed to house style. Regenerated dark variants and fixed a hover-state collision the shared SHADE_MAP produces for any bg-gray-50/hover:bg-gray-100 pair: both 50 and 100 invert to the same dark shade (800), so the "Browse files" chip lost its hover feedback entirely in dark mode. Bumped the hover shade one step lighter by hand (dark:hover:bg-gray-700) so it visibly lifts on hover instead of staying flat, same principle as the earlier dropdown hover/card-shade fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fixed the filter panels' border/divide color: -300 was borrowed from the inputs/interactive-outlines role, but a floating flyout panel and a self-contained accordion card both belong under the default -200 border, matching the dropdown and details-list precedent. Left the standalone <summary> toggle's own border and the checkboxes' plugin-default checked color alone (established precedent for both). Regenerated dark variants, then fixed the recurring bg-white-card gotcha (dark:bg-gray-800 instead of the engine's dark:bg-black) and the @tailwindcss/forms gotcha on both the checkbox and number inputs (restored dark:bg-gray-900/dark:ring-offset-gray-900, plus dark:text-gray-50 on the number inputs) by hand. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Light-mode classes already conformed to house style. Regenerated dark variants and hit the @tailwindcss/forms gotcha on all four input variants - restored dark:bg-gray-900/dark:text-gray-50/ dark:ring-offset-gray-900 by hand. The floating-label variant's border-masking span surfaced a narrower case of the bg-white-card gotcha: it's a small patch meant to blend into the page behind it, not an elevated surface, so it needs dark:bg-gray-900 (matching the page) rather than dark:bg-gray-800 (standing out from it) or the engine's generic dark:bg-black. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Light-mode classes already conformed to house style. Regenerating dark variants fixed the pastel dark:bg-indigo-300 fill bug (the exact problem Phase 1's solid-fill rule was built for) on the pulse/ping/bounce dots and the progress-bar fill - they now correctly render dark:bg-indigo-500, a solid visible fill instead of a washed-out one. Spinner stroke colors are unaffected (that rule is bg-only) and read fine as-is. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fixed the "Done" button's bg-blue-600 -> bg-indigo-600 (Action color drift) and added the Confirm input's missing focus ring in the "Input with close" variant to match its sibling. Settled the focus-ring scope question left open after empty-states: modals already carries the a11y-sweep's focus:ring-indigo-600 recipe on every interactive control, confirming it's a pre-existing accessibility convention orthogonal to this color migration - preserve it where present, fix only its colors, don't add or remove it wholesale. Regenerated dark variants and fixed three new issues that only show up with a real elevated card: - backdrop:bg-black/50 was inverting to backdrop:bg-white/50 in dark mode (a dimming scrim shouldn't invert at all) - removed the bad override. - ring-offset color needs to match the nearest enclosing surface, not always the page - buttons/input inside the now-gray-800 dialog card get dark:ring-offset-gray-800, not the page's gray-900. - The "recessed sub-region inside a card" principle from breadcrumbs applies to buttons too - the Cancel button's bg-gray-100 mapped to the same shade as its own card, making it invisible at rest; bumped one step darker (dark:bg-gray-900) to preserve the light-mode relationship. Also fixed the Close button's hover/card-shade collision the same way as earlier collections. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The dark-mode engine's generic white<->black colorMap swap fires on any utility, so text-white labels on a solid bg-indigo-600 Action fill were rewritten to dark:text-black on regeneration, undoing Phase 1's fill-shade override that exists specifically to keep the label legible. Found after the fact on empty-states (3 buttons/badges) and modals (the Done button across 4 variants) - removes the erroneous dark:text-black, leaving plain text-white to carry through unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHz6MHjQz4Nbas6NyT9xSN
No light-mode class drift found. Regenerating dark variants hit the text-white -> dark:text-black flip on the current-page indicator (fixed per the empty-states/modals gotcha) plus a new variant of it: the indicator's border-indigo-600 exists only to match its own bg-indigo-600 fill, but border and bg shade-map independently, producing a mismatched dark:border-indigo-300 around the dark:bg-indigo-500 fill - fixed to dark:border-indigo-500 to keep the seamless solid box. Also restored the @tailwindcss/forms dark chrome on the number-input variant per the inputs/filters precedent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHz6MHjQz4Nbas6NyT9xSN
…l review Relying on each migration session to notice and hand-fix the text-white -> dark:text-black flip had already failed twice (missed on both empty-states's and modals's own migrations, only caught afterward). Adds a rule to DEFAULT_CONFIG.rules (src/lib/dark-mode/config.js) so the engine's white<->black colorMap swap never fires on the text utility - text-white/text-black now pass through regeneration unchanged in both the Node script and the browser tool, since both read the same config. Verified by regenerating empty-states from scratch: output is byte-for-byte identical to the hand-fixed file. Also ran the existing dark-mode-generator Playwright suite before and after this change - 6 pre-existing failures in that file (a stale rules- count assertion and two rule-inspector cases) reproduce identically with the change reverted, confirming they predate this fix and aren't a regression from it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHz6MHjQz4Nbas6NyT9xSN
The previous commit added a rule making the engine's white<->black colorMap swap skip the text utility entirely, verified only against the 11 known cases (all in application, all white text on a colored Action/Destructive fill that stays colored in dark mode). That verification was too narrow: neobrutalism pairs text-black with neutral surfaces (bg-white, bg-blue-100, etc, 32+ occurrences) that themselves invert via the existing bg-white -> dark:bg-black rule, so the text has to invert with them or it goes invisible on its own card once that collection is migrated. A global "never invert text white/black" rule fixes one shape of this problem and silently breaks the other - the real distinction is whether the paired surface itself inverts, which the engine has no sibling-class awareness to determine per class. Reverting to hand-fixing each occurrence at Phase 3 review, as before. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHz6MHjQz4Nbas6NyT9xSN
…te properly The previous revert left the text-white/dark:text-black flip as a manual check again, since a blanket "never invert text white/black" rule was unsafe (neobrutalism pairs text-black with neutral surfaces that must invert with it). But the engine already had what it needed: element class attributes are split into tokens before per-class transformation, that token list just never got threaded any further. Adds requireClasses to the Rule schema - an extra match gate alongside utilities/shade/colors that only fires when the same element also carries one of the listed light-mode classes - and threads a siblingClasses param through applyRules/transformClass/transformClassAttribute so it has something to check. Re-adds the fill-text rule scoped correctly this time: text-white only stays put when the element also has bg-indigo-600 or bg-red-600, so neobrutalism's text-black/text-white (paired with bg-white/bg-black, never a Phase-1 fill color) is untouched and keeps inverting normally through the plain colorMap swap. Verified both directions before shipping: regenerated empty-states, pagination, and one modals file, diffed byte-for-byte against the hand-fixed committed versions (the only differences were other, unrelated, already-documented manual gotchas, with text-color handling identical); separately ran the transform against neobrutalism/badges (both bg-white->text-black and bg-black->text-white pairings on the same file) and tabs' hover state, confirming they still invert correctly. Re-ran the dark-mode-generator Playwright suite - identical pass/fail counts to the reverted baseline, no new regressions. Also audited every already-migrated collection (badges through pagination) for this bug shape before trusting the "done" list: every text-white occurrence is the same already-fixed bg-indigo-600 pairing, and text-black doesn't appear anywhere in application. Nothing needed rework. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHz6MHjQz4Nbas6NyT9xSN
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on top of #751 — this PR's base is
feature/generate-dark-variants-script, notmain, so the diff below is only the incremental house-style work. Once #751 merges, GitHub will retarget this PR tomainautomatically.HOUSE_STYLE_PLAN.md) covering surfaces, text, borders, action/destructive/status colors, and focus rings — fixing real drift across the 311 light components (e.g. ~91bg-indigo-600vs 66bg-blue-600action buttons, 146 straytext-gray-400body-copy instances failing WCAG AA)src/lib/dark-mode/config.js): solid-fill indigo/red buttons get an explicitdarkShadeoverride instead of the generic600→300shade map, which was producing pasteldark:bg-indigo-300fills for what should be solid action buttonscontent.config.ts'sdarknow defaults tofalse, and a collection only flips totrueonce every component in it has been migrated. The old per-componentdark: true | { contributors }union is retired in favor of an optionaldarkContributors: string[]for the rare hand-authored-dark-only caseComponentPost.astro/ComponentCard.astro/SearchWrapper.astroupdated to match — renders a paired "(Dark)" card per component when the collection flag is set, replacing the "X/Y Dark Mode (Request)" badge with a plain "Dark Mode" labelapplicationcollections through the full pipeline (standardize light-mode classes to house style, then regenerate dark variants via the generator script from Feature - Add dark variant generator script and collection-level dark mode opt-out #751, verify, flip the collection flag):badges,breadcrumbs,button-groups,checkboxes,details-list,dividers,dropdownchartsis deliberately skipped for now and flagged inHOUSE_STYLE_PLAN.mdfor a dedicated follow-up — its dark variants pair Tailwind classes with hand-picked hex colors inside inline Chart.js<script>blocks that the shared engine can't touchscripts/generate-dark-variants.jsto add the standalonedark:bg-gray-900background (from Bugfix - Give dark example HTML files an explicit dark background #754) to every freshly-generated file's<body>itself, instead of needing it patched by hand after every regeneration —<body>never carries abg-*class in light mode for the shade-map engine to invert, so this is a fixed convention applied as a small post-processing step, independent of the color-transform engineProgress and per-collection gotchas are tracked in
HOUSE_STYLE_PLAN.mdas the effort continues —empty-statesis next alphabetically (accordionswas seemingly skipped by the original ordering and still needs a pass at some point too).Test plan
pnpm lintpnpm astro check<body>background handling against both<body class="...">and bare<body>fixturespnpm test(Playwright) once the full collection set is migrated