From 854b51c56034977ee06c6d88637361f91203b2af Mon Sep 17 00:00:00 2001 From: Mark M <50486078+markmead@users.noreply.github.com> Date: Fri, 21 Aug 2026 08:55:32 +0100 Subject: [PATCH 01/25] Feature - Establish house-style color system and simplify dark mode to 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 --- .../examples/application/badges/1-dark.html | 4 +- public/examples/application/badges/1.html | 4 +- .../examples/application/badges/2-dark.html | 4 +- public/examples/application/badges/2.html | 4 +- .../examples/application/badges/3-dark.html | 8 ++-- public/examples/application/badges/3.html | 8 ++-- .../examples/application/badges/4-dark.html | 4 +- public/examples/application/badges/4.html | 4 +- .../examples/application/badges/5-dark.html | 12 +++--- src/components/ComponentCard.astro | 4 +- src/components/SearchWrapper.astro | 4 +- src/content.config.ts | 11 +---- src/content/collection/application/badges.mdx | 6 +-- src/content/collection/application/steps.mdx | 10 ++--- src/content/collection/application/toasts.mdx | 12 +++--- .../collection/marketing/announcements.mdx | 12 +++--- src/layouts/ComponentPost.astro | 29 ++----------- src/lib/dark-mode/config.js | 41 ++++++++++++++++++- 18 files changed, 93 insertions(+), 88 deletions(-) diff --git a/public/examples/application/badges/1-dark.html b/public/examples/application/badges/1-dark.html index 86e6d95dd..695b55816 100644 --- a/public/examples/application/badges/1-dark.html +++ b/public/examples/application/badges/1-dark.html @@ -8,13 +8,13 @@ Live Live diff --git a/public/examples/application/badges/1.html b/public/examples/application/badges/1.html index 12a628269..822788411 100644 --- a/public/examples/application/badges/1.html +++ b/public/examples/application/badges/1.html @@ -8,13 +8,13 @@ Live Live diff --git a/public/examples/application/badges/2-dark.html b/public/examples/application/badges/2-dark.html index 07e4df39c..574ecbd67 100644 --- a/public/examples/application/badges/2-dark.html +++ b/public/examples/application/badges/2-dark.html @@ -8,7 +8,7 @@

Euro

diff --git a/public/examples/application/button-groups/1.html b/public/examples/application/button-groups/1.html index 9e145431c..94ae3daa2 100644 --- a/public/examples/application/button-groups/1.html +++ b/public/examples/application/button-groups/1.html @@ -9,19 +9,19 @@
diff --git a/public/examples/application/button-groups/2-dark.html b/public/examples/application/button-groups/2-dark.html index e8932ab0d..4cec77099 100644 --- a/public/examples/application/button-groups/2-dark.html +++ b/public/examples/application/button-groups/2-dark.html @@ -9,7 +9,7 @@
diff --git a/public/examples/application/dropdown/2-dark.html b/public/examples/application/dropdown/2-dark.html index 94f1844a7..ef9cb9475 100644 --- a/public/examples/application/dropdown/2-dark.html +++ b/public/examples/application/dropdown/2-dark.html @@ -9,18 +9,18 @@
diff --git a/public/examples/application/dropdown/2.html b/public/examples/application/dropdown/2.html index 09b41861d..9bfc1b866 100644 --- a/public/examples/application/dropdown/2.html +++ b/public/examples/application/dropdown/2.html @@ -9,7 +9,7 @@
diff --git a/public/examples/application/dropdown/3-dark.html b/public/examples/application/dropdown/3-dark.html index 538918434..e2296dbac 100644 --- a/public/examples/application/dropdown/3-dark.html +++ b/public/examples/application/dropdown/3-dark.html @@ -9,18 +9,18 @@
diff --git a/public/examples/application/dropdown/3.html b/public/examples/application/dropdown/3.html index a523298a8..2014c962f 100644 --- a/public/examples/application/dropdown/3.html +++ b/public/examples/application/dropdown/3.html @@ -9,7 +9,7 @@
diff --git a/src/content/collection/application/dropdown.mdx b/src/content/collection/application/dropdown.mdx index 0ad9d3c40..aca0d39ab 100644 --- a/src/content/collection/application/dropdown.mdx +++ b/src/content/collection/application/dropdown.mdx @@ -4,13 +4,14 @@ description: Responsive dropdown menu components for navigation, filters, settin category: application slug: dropdown pattern: https://js.hyperui.dev/patterns/dropdown/ +dark: true terms: - menu - navigation components: - - { title: 'Base', dark: true } - - { title: 'Divided', dark: true } - - { title: 'Grouped', dark: true } + - { title: 'Base' } + - { title: 'Divided' } + - { title: 'Grouped' } --- import BaseHero from '../../../components/BaseHero.astro' From 4920dfaef807d9e68cb9d3dc71607c0430a3beb2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 31 Aug 2026 15:26:21 +0000 Subject: [PATCH 14/25] Update - Generator script now adds the standalone dark background itself MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/generate-dark-variants.js previously left every freshly-generated -dark.html's without the dark:bg-gray-900 background from #754 (that fix predates the script, and 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 's existing class attribute, or adds the attribute if 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. --- HOUSE_STYLE_PLAN.md | 20 ++++++++++++++------ scripts/generate-dark-variants.js | 30 +++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/HOUSE_STYLE_PLAN.md b/HOUSE_STYLE_PLAN.md index 8dec0734c..fcef2d44a 100644 --- a/HOUSE_STYLE_PLAN.md +++ b/HOUSE_STYLE_PLAN.md @@ -129,13 +129,21 @@ direction (a hover state should lift off the card, not recess into it). Check for this same collision on any future component with hoverable items inside its own `bg-white` card. -Also: `scripts/generate-dark-variants.js` doesn't add the `dark:bg-*` +**Fixed:** `scripts/generate-dark-variants.js` didn't add the `dark:bg-*` background from #754 to a freshly-generated file's `` — that fix -predates the script's authoring and nothing wires them together. Every -regenerated file still needs it added by hand (matching the `dark:bg-gray-900` -convention used everywhere else) until the generator itself is updated to -do this automatically — worth fixing in the script rather than by hand -forever, but out of scope for a single collection's migration. +predates the script's authoring and nothing wired them together, so every +regenerated file needed it added by hand. The script now does this itself: +`ensureBodyDarkBackground()` post-processes each generated file's `` +tag directly (adding `dark:bg-gray-900` to its existing `class`, or adding +the attribute if `` has none), independent of the class-shade +engine — `` never carries a `bg-*` class in light mode, so there was +never anything for the engine to invert in the first place; this is a +fixed convention, not a color-shade mapping. Only touches the Node CLI +path (`transformHtmlString`); the browser tool's DOM-aware path +(`transformHtmlDom`) only ever returns `body.innerHTML` for iframe +embedding and never touches the `` tag itself, so it was never +affected by this gap. No more by-hand patching needed for future +collections. Next action: pick the next `application` collection (alphabetical after `dropdown`, skipping `charts` — `empty-states` is next) and run it through diff --git a/scripts/generate-dark-variants.js b/scripts/generate-dark-variants.js index a6bf53bcc..b1c3be21e 100644 --- a/scripts/generate-dark-variants.js +++ b/scripts/generate-dark-variants.js @@ -14,6 +14,32 @@ const examplesRootPath = path.join(repositoryRootPath, 'public/examples') const componentCategories = ['application', 'marketing', 'neobrutalism', 'templates'] +// Standalone dark files aren't embedded in ComponentPreview.astro's iframe (which supplies its +// own bg-gray-900) when opened directly, so needs an explicit dark background — see #753. +// never carries a bg-* class in light mode (nothing for the shade-map engine to invert), +// so this is a fixed convention applied here rather than a rule in the color-transform engine. +const bodyDarkBackgroundClass = 'dark:bg-gray-900' + +function ensureBodyDarkBackground(htmlContent) { + return htmlContent.replace(/]*)>/, (fullMatch, attributesString) => { + const classAttributeMatch = attributesString.match(/class="([^"]*)"/) + + if (!classAttributeMatch) { + return `` + } + + const [classAttribute, classValue] = classAttributeMatch + + if (classValue.includes('dark:bg-')) { + return fullMatch + } + + const updatedClassAttribute = `class="${classValue} ${bodyDarkBackgroundClass}"` + + return `` + }) +} + const cliCategoryFilter = process.argv .find((argValue) => argValue.startsWith('--category=')) ?.split('=')[1] @@ -127,7 +153,9 @@ function generateDarkVariants() { for (const missingVariant of missingDarkVariants) { const lightHtmlContent = fs.readFileSync(missingVariant.lightFilePath, 'utf8') - const darkHtmlContent = transformHtmlString(lightHtmlContent, DEFAULT_CONFIG) + const darkHtmlContent = ensureBodyDarkBackground( + transformHtmlString(lightHtmlContent, DEFAULT_CONFIG), + ) fs.writeFileSync(missingVariant.darkFilePath, darkHtmlContent, 'utf8') From bd88250d464fb2ec940c0abfce23313f85aed339 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 08:06:25 +0000 Subject: [PATCH 15/25] Feature - Migrate empty-states to house style and regenerate dark variants 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 --- HOUSE_STYLE_PLAN.md | 71 +++++++++++++++---- .../application/empty-states/1-dark.html | 8 +-- .../application/empty-states/2-dark.html | 6 +- .../application/empty-states/3-dark.html | 8 +-- .../application/empty-states/4-dark.html | 10 +-- .../application/empty-states/5-dark.html | 12 ++-- .../examples/application/empty-states/5.html | 2 +- .../collection/application/empty-states.mdx | 11 +-- 8 files changed, 86 insertions(+), 42 deletions(-) diff --git a/HOUSE_STYLE_PLAN.md b/HOUSE_STYLE_PLAN.md index fcef2d44a..13cbbe8cc 100644 --- a/HOUSE_STYLE_PLAN.md +++ b/HOUSE_STYLE_PLAN.md @@ -16,11 +16,12 @@ plus: - `details-list` migrated through Phase 2 → Phase 3 (see below) - `dividers` migrated through Phase 2 → Phase 3 (see below) - `dropdown` migrated through Phase 2 → Phase 3 (see below) +- `empty-states` migrated through Phase 2 → Phase 3 (see below) Done: Phase 1, the schema/layout rewiring, and `badges`, `breadcrumbs`, -`button-groups`, `checkboxes`, `details-list`, `dividers`, and `dropdown` -as fully-migrated collections (see sections below for exactly what that -entailed). +`button-groups`, `checkboxes`, `details-list`, `dividers`, `dropdown`, and +`empty-states` as fully-migrated collections (see sections below for +exactly what that entailed). `breadcrumbs` needed one Phase 2 fix: its grouped/bordered variant used `border-gray-300` for the group wrapper, but grouped interactive elements @@ -129,6 +130,42 @@ direction (a hover state should lift off the card, not recess into it). Check for this same collision on any future component with hoverable items inside its own `bg-white` card. +`empty-states` needed one Phase 2 fix: its "No results found" search +`` used `focus:border-indigo-500` (the Action color, borrowed onto a +non-action control) — changed to `focus:border-gray-900` per the house +style table's non-action-control focus-ring row, keeping the existing +border-based focus mechanism rather than switching it to a ring. Its +solid `bg-indigo-600` buttons and `border-gray-300` outline +buttons/dropzone/input already conformed — `border-gray-300` is correct +here (not the grouped-control `border-gray-200` case) because these are +standalone "interactive outlines"/inputs, the exact case the table +reserves `-300` for. Its large decorative `text-gray-400` icons +(`aria-hidden="true"`, purely illustrative, not body copy) were left +alone — sitewide convention, identical in the not-yet-migrated +`marketing/empty-content` sibling collection, and outside what the +Text-role table governs. Also confirmed the missing `focus:ring-2 +focus:ring-indigo-600` on its Action buttons — present in the house +style table's Action recipe, but not actually implemented on *any* +`bg-indigo-600` button anywhere in the codebase today (verified via +grep), and the dedicated a11y-fixes commit (`47a41de`) touched these +exact files but deliberately didn't add it — so treated as a separate, +not-yet-started convention rather than Phase 2 drift, and left untouched. + +`empty-states` also hit the `@tailwindcss/forms` gotcha from `checkboxes` +above, extended to a plain text input (verified in +`@tailwindcss/forms`'s own source: `[type='text']` etc. get the same +baked-in `background-color: #fff` and, on `:focus`, +`--tw-ring-offset-color: #fff`, not just `[type=checkbox]`/`[type=radio]`) +— the previous hand-tuned dark file had `dark:bg-gray-900 dark:text-white` +on the search input with no light-mode counterpart, which the regenerate +step silently dropped. Restored by hand as `dark:bg-gray-900 +dark:text-gray-50 dark:ring-offset-gray-900` (text shade tightened to +match the engine's current `text-gray-50` convention, ring-offset added +to match the `checkboxes` pairing). Verified in the dev server (light + +dark, standalone iframe and the full collection page) that the input's +dark background/text/focus all render correctly instead of showing a +stray white box. + **Fixed:** `scripts/generate-dark-variants.js` didn't add the `dark:bg-*` background from #754 to a freshly-generated file's `` — that fix predates the script's authoring and nothing wired them together, so every @@ -146,16 +183,26 @@ affected by this gap. No more by-hand patching needed for future collections. Next action: pick the next `application` collection (alphabetical after -`dropdown`, skipping `charts` — `empty-states` is next) and run it through -Phase 2 → Phase 3 the same way the collections above were done, +`empty-states`, skipping `charts` — `file-uploaders` is next) and run it +through Phase 2 → Phase 3 the same way the collections above were done, remembering the forms-plugin gotcha above for any remaining form-control -collections and the hover/card-shade collision above for any component -with hoverable items inside its own `bg-white` card. No open design -questions remain for the normal pipeline — the house style table below and -the collection-exemption list are settled. Note: `accordions` sorts -alphabetically before `badges` (the original pilot) and was never picked -up by this effort — it isn't on the exemption list, so it's presumably -just an oversight in the ordering and still needs a pass at some point. +collections (now confirmed to also cover plain text ``s, not just +checkboxes/radios) and the hover/card-shade collision above for any +component with hoverable items inside its own `bg-white` card. No open +design questions remain for the normal pipeline — the house style table +below and the collection-exemption list are settled. Note: `accordions` +sorts alphabetically before `badges` (the original pilot) and was never +picked up by this effort — it isn't on the exemption list, so it's +presumably just an oversight in the ordering and still needs a pass at +some point. + +Also flagged, not yet resolved: the house style table's Action recipe +includes `focus:ring-2 focus:ring-indigo-600` on solid buttons, but no +`bg-indigo-600` button anywhere in the codebase actually has it today, and +the dedicated a11y-fixes pass deliberately skipped adding it. Worth a +decision in its own session (add it everywhere as part of Phase 2, or +drop it from the table as aspirational/out-of-scope) rather than having +each collection guess — `empty-states` left it alone pending that call. **Collection exemptions are final:** only `grids` and `media` skip dark mode (`dark: false`), because they have no real themeable surface — `grids` is diff --git a/public/examples/application/empty-states/1-dark.html b/public/examples/application/empty-states/1-dark.html index 023628bfb..e4263423e 100644 --- a/public/examples/application/empty-states/1-dark.html +++ b/public/examples/application/empty-states/1-dark.html @@ -24,7 +24,7 @@ /> -

No items found

+

No items found

Get started by creating your first item. It only takes a few seconds. @@ -32,14 +32,14 @@

No items found

- Learn how or - view examples + Learn how or + view examples

diff --git a/public/examples/application/empty-states/2-dark.html b/public/examples/application/empty-states/2-dark.html index a4fca3267..ad1cdea65 100644 --- a/public/examples/application/empty-states/2-dark.html +++ b/public/examples/application/empty-states/2-dark.html @@ -24,7 +24,7 @@ /> -

No data to display

+

No data to display

Get started by creating your first item. It only takes a few seconds. @@ -32,13 +32,13 @@

No data to dis
diff --git a/public/examples/application/empty-states/3-dark.html b/public/examples/application/empty-states/3-dark.html index 6f900323b..36b212532 100644 --- a/public/examples/application/empty-states/3-dark.html +++ b/public/examples/application/empty-states/3-dark.html @@ -24,7 +24,7 @@ /> -

Upload your files

+

Upload your files

Drag and drop files here or click to browse your computer. @@ -32,11 +32,9 @@

Upload your fi diff --git a/public/examples/application/empty-states/4-dark.html b/public/examples/application/empty-states/4-dark.html index 965c0c089..d8f1d4958 100644 --- a/public/examples/application/empty-states/4-dark.html +++ b/public/examples/application/empty-states/4-dark.html @@ -24,7 +24,7 @@ /> -

Get started in seconds

+

Get started in seconds

Complete these quick steps to set up your workspace. @@ -33,7 +33,7 @@

Get started in
  1. 1 @@ -43,7 +43,7 @@

    Get started in
  2. 2 @@ -53,7 +53,7 @@

    Get started in
  3. 3 @@ -63,7 +63,7 @@

    Get started in

diff --git a/public/examples/application/empty-states/5-dark.html b/public/examples/application/empty-states/5-dark.html index 6117d9c58..e27e96dee 100644 --- a/public/examples/application/empty-states/5-dark.html +++ b/public/examples/application/empty-states/5-dark.html @@ -24,7 +24,7 @@ /> -

No results found

+

No results found

Try adjusting your search or filters to find what you're looking for. @@ -34,21 +34,19 @@

No results fou

- Contact support - if you need help + Contact support if + you need help

diff --git a/public/examples/application/empty-states/5.html b/public/examples/application/empty-states/5.html index 7658172b4..3179c83cf 100644 --- a/public/examples/application/empty-states/5.html +++ b/public/examples/application/empty-states/5.html @@ -34,7 +34,7 @@

No results found

@@ -54,7 +54,7 @@