feat(theme): merge light/dark CSS and add brand-token tiers#314
Merged
Conversation
Merge light.css and dark.css into a single default.css holding both the light :root block and the .dark override. Organize every theme block (default, cream, bloom) into tiers: BRAND (primary/secondary + foregrounds, shell-gradient — the only re-skin knobs), DERIVED (accent/ring/sidebar-* via color-mix on var(--primary)), SYSTEM (neutral surfaces, accessibility- locked), and STATUS (semantic, fixed). Give cream and bloom dark variants that inherit default's status colors. Decouple the shell gradient from --background via a dedicated --shell-gradient-base token. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
IzumiSy
approved these changes
Jun 15, 2026
IzumiSy
pushed a commit
that referenced
this pull request
Jun 15, 2026
Merge light.css and dark.css into a single default.css holding both the light :root block and the .dark override. Organize every theme block (default, cream, bloom) into tiers: BRAND (primary/secondary + foregrounds, shell-gradient — the only re-skin knobs), DERIVED (accent/ring/sidebar-* via color-mix on var(--primary)), SYSTEM (neutral surfaces, accessibility- locked), and STATUS (semantic, fixed). Give cream and bloom dark variants that inherit default's status colors. Decouple the shell gradient from --background via a dedicated --shell-gradient-base token. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
IzumiSy
added a commit
that referenced
this pull request
Jun 15, 2026
* feat(theme): split theming into mode and palette axes Introduce two independent theming axes: mode (light/dark/system) as the end-user accessibility preference via useMode, and palette/theme (default/cream/bloom) as a developer configuration via useTheme. Mode is persisted; palette is prop-driven. The <html> element carries mode as the .light/.dark class and palette as data-theme. The font axis is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(theme): merge light/dark CSS and add brand-token tiers (#314) Merge light.css and dark.css into a single default.css holding both the light :root block and the .dark override. Organize every theme block (default, cream, bloom) into tiers: BRAND (primary/secondary + foregrounds, shell-gradient — the only re-skin knobs), DERIVED (accent/ring/sidebar-* via color-mix on var(--primary)), SYSTEM (neutral surfaces, accessibility- locked), and STATUS (semantic, fixed). Give cream and bloom dark variants that inherit default's status colors. Decouple the shell gradient from --background via a dedicated --shell-gradient-base token. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: outline rename feedback plan Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> * refactor(theme): rename mode APIs to color mode names Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com>
IzumiSy
added a commit
that referenced
this pull request
Jun 15, 2026
* feat(theme): split theming into mode and palette axes Introduce two independent theming axes: mode (light/dark/system) as the end-user accessibility preference via useMode, and palette/theme (default/cream/bloom) as a developer configuration via useTheme. Mode is persisted; palette is prop-driven. The <html> element carries mode as the .light/.dark class and palette as data-theme. The font axis is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(theme): merge light/dark CSS and add brand-token tiers (#314) Merge light.css and dark.css into a single default.css holding both the light :root block and the .dark override. Organize every theme block (default, cream, bloom) into tiers: BRAND (primary/secondary + foregrounds, shell-gradient — the only re-skin knobs), DERIVED (accent/ring/sidebar-* via color-mix on var(--primary)), SYSTEM (neutral surfaces, accessibility- locked), and STATUS (semantic, fixed). Give cream and bloom dark variants that inherit default's status colors. Decouple the shell gradient from --background via a dedicated --shell-gradient-base token. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: outline rename feedback plan Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> * refactor(theme): rename mode APIs to color mode names Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com>
IzumiSy
added a commit
that referenced
this pull request
Jun 17, 2026
* feat(theme): split theming into mode and palette axes Introduce two independent theming axes: mode (light/dark/system) as the end-user accessibility preference via useMode, and palette/theme (default/cream/bloom) as a developer configuration via useTheme. Mode is persisted; palette is prop-driven. The <html> element carries mode as the .light/.dark class and palette as data-theme. The font axis is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(theme): merge light/dark CSS and add brand-token tiers (#314) Merge light.css and dark.css into a single default.css holding both the light :root block and the .dark override. Organize every theme block (default, cream, bloom) into tiers: BRAND (primary/secondary + foregrounds, shell-gradient — the only re-skin knobs), DERIVED (accent/ring/sidebar-* via color-mix on var(--primary)), SYSTEM (neutral surfaces, accessibility- locked), and STATUS (semantic, fixed). Give cream and bloom dark variants that inherit default's status colors. Decouple the shell gradient from --background via a dedicated --shell-gradient-base token. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: outline rename feedback plan Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> * refactor(theme): rename mode APIs to color mode names Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com>
IzumiSy
added a commit
that referenced
this pull request
Jun 17, 2026
* feat(theme): split theming into mode and palette axes Introduce two independent theming axes: mode (light/dark/system) as the end-user accessibility preference via useMode, and palette/theme (default/cream/bloom) as a developer configuration via useTheme. Mode is persisted; palette is prop-driven. The <html> element carries mode as the .light/.dark class and palette as data-theme. The font axis is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(theme): merge light/dark CSS and add brand-token tiers (#314) Merge light.css and dark.css into a single default.css holding both the light :root block and the .dark override. Organize every theme block (default, cream, bloom) into tiers: BRAND (primary/secondary + foregrounds, shell-gradient — the only re-skin knobs), DERIVED (accent/ring/sidebar-* via color-mix on var(--primary)), SYSTEM (neutral surfaces, accessibility- locked), and STATUS (semantic, fixed). Give cream and bloom dark variants that inherit default's status colors. Decouple the shell gradient from --background via a dedicated --shell-gradient-base token. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: outline rename feedback plan Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> * refactor(theme): rename mode APIs to color mode names Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com>
IzumiSy
added a commit
that referenced
this pull request
Jun 24, 2026
…witcher (#306) * feat(themes): theme foundation — palettes, ThemeProvider refactor, font axis - Add cream/bloom color palettes with CSS custom properties (theme.css) - Shell gradient, font-axis CSS, squircle corners, autofill overrides (globals.css) - Refactor ThemeProvider: Theme/ResolvedTheme/Font types, useFont hook, legacy ID migration, memoized context - Add defaultTheme/defaultFont props to AppShell - Export new types and hooks from package index - Add ThemeProvider unit tests * refactor(theme): simplify ThemeProvider — remove legacy migration, hardcode storage keys, add system reactivity * Format files * feat: add ThemeSwitcher component with color palette and font selection - Add ThemeSwitcher dropdown menu with 5 color themes and 2 font options - Extract useFont hook from theme-context for independent font state access - Replace sidebar-layout's simple light/dark toggle with full ThemeSwitcher - Add themeSwitcher prop to SidebarLayout for customization/hiding - Export ThemeSwitcher and useFont from package index - Add component tests for ThemeSwitcher * Revert vite-app * refactor: remove themeSwitcher prop from SidebarLayout * refactor(core): split theme.css into per-theme files Extract token definitions and structural overrides into individual files under src/assets/themes/ (light, dark, cream, bloom). Each branded theme (cream/bloom) is now fully self-contained with its own gradient, squircle, and transparency rules. theme.css becomes a lightweight hub: @import directives + @theme inline bridge. globals.css retains only theme-agnostic global rules. * refactor(core): pre-generate font assets and append via closeBundle hook - Add scripts/generate-fonts.mjs to produce fonts.generated.css and copy woff2 files to src/assets/fonts/ from fontsource packages - Remove fonts.css; globals.css no longer imports fonts directly (avoids Vite woff2 resolution warnings during build) - Add appendFonts Vite plugin that appends fonts.generated.css to dist/app-shell.css in closeBundle hook (instant, no font generation) - Committed generated assets so CI doesn't need to re-run generation - Add generate:fonts script to package.json * Fix appendFonts plugin to use proper hooks * Fix concatenation target * feat(theme): split theming into mode and palette axes (#313) * feat(theme): split theming into mode and palette axes Introduce two independent theming axes: mode (light/dark/system) as the end-user accessibility preference via useMode, and palette/theme (default/cream/bloom) as a developer configuration via useTheme. Mode is persisted; palette is prop-driven. The <html> element carries mode as the .light/.dark class and palette as data-theme. The font axis is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(theme): merge light/dark CSS and add brand-token tiers (#314) Merge light.css and dark.css into a single default.css holding both the light :root block and the .dark override. Organize every theme block (default, cream, bloom) into tiers: BRAND (primary/secondary + foregrounds, shell-gradient — the only re-skin knobs), DERIVED (accent/ring/sidebar-* via color-mix on var(--primary)), SYSTEM (neutral surfaces, accessibility- locked), and STATUS (semantic, fixed). Give cream and bloom dark variants that inherit default's status colors. Decouple the shell gradient from --background via a dedicated --shell-gradient-base token. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: outline rename feedback plan Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> * refactor(theme): rename mode APIs to color mode names Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> * refactor: move @custom-variant dark to theme.css * refactor: consolidate token tier docs into theme.css * refactor(core): simplify theme system — remove font axis, make palette static - Remove font switching (useFont, FONT_OPTIONS, data-font CSS, FontPreview) - Rename ThemeSwitcher to AppearanceSwitcher (now only handles color mode) - Make theme/palette prop-only (remove setTheme, simplify useTheme to read-only) - Inline DOM updates into handlers instead of separate useEffect - Move resolveMode/getSystemDark to module scope (lint fix) * Remove unnecessary exports * refactor: auto-scan @fontsource-variable packages from dependencies * Revise changeset * refactor(theme): rename Theme→ThemePalette, ColorMode→ColorTheme Clarify the two independent axes of the theming system: - ThemePalette (default/cream/bloom): developer-configured brand palette - ColorTheme (light/dark/system): user-facing color scheme preference Rename internal variables, props, constants, and test IDs to align with the new terminology. Public hook API (useTheme → theme/resolvedTheme/setTheme) remains unchanged for backward compatibility. * refactor(theme): remove type aliases in index.ts exports, fix changeset prop names * feat(themes): add i18n labels to AppearanceSwitcher and remove ThemePalette from public exports * refactor: replace defaultThemePalette prop with static CSS theme imports Remove runtime palette selection via prop in favor of static CSS imports. Each theme (default, cream, bloom) is now imported directly: import "@tailor-platform/app-shell/themes/cream"; Changes: - Remove defaultThemePalette prop from AppShell and ThemeProvider - Remove ThemePalette type, THEME_PALETTE_OPTIONS, data-theme logic - Change theme CSS selectors from [data-theme=x] to :root - Wrap default theme in @layer theme.defaults so custom themes always win - Move structural overrides (gradient, transparent chrome) out of @layer to ensure they override Tailwind utilities - Add subpath pattern export: "./themes/*" -> "./dist/themes/*.css" - Update examples and e2e to use CSS imports instead of prop * chore(core): remove generated font assets * Revert style loading * feat(theme): accent tokens, palette tier organisation, and appearance icons (#323) * feat(theme): explicit accent tiers, palette template, and appearance icons Organise palette CSS into numbered tiers (Brand → Shell → Derived → System → Palette → Semantic → Structural) with `_template.css` as the new-palette checklist. Set explicit `--accent` per palette and mode for reliable sidebar/menu selection. Add `--alert-*` tokens to default palette CSS. Replace AppearanceSwitcher menu swatches with Sun/Moon/Monitor icons. Add Color demo page and styling-theming docs for palette authoring. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(alert): wire variants to semantic --alert-* tokens Use CSS variable tokens for all alert variants including neutral (--alert-neutral-* aliases muted). Lighter dark-mode foregrounds from default.css apply automatically; drop hardcoded Tailwind color classes. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> * Remove unnecessary changeset * refactor(themes): inherit shared aliases from default --------- Co-authored-by: pradeep <6978383+itsprade@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Sean Hasselback <seanhasselback@gmail.com>
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
The CSS layer of the theming work. Merges the light/dark stylesheets into one file per palette and reorganizes every theme block into a brand-token architecture with a clear rule for what a developer changes to re-skin vs. what stays locked for accessibility.
Stack: built on
feat/theme-mode-axis(#313); targets that branch. The component-surface token-ization follows in the next PR.What changed
light.css+dark.css→default.css— one file holds the light:rootblock and the.darkoverride.cream.cssandbloom.csseach gain a dark variant.theme.cssimports the three palette files.--primary/--secondary(+ their foregrounds) and--shell-gradient-*. The only knobs a product overrides to re-skin.--accent,--ring,--sidebar-primary/accent,--chart-1, gradient stops — allcolor-mix(... var(--primary) …, var(--card)). Declared once in the light block; CSS resolvesvar()at use-time, so they re-resolve correctly in dark because dark overrides--primary/--card.--background,--card,--muted,--border,--input…), accessibility-locked.--status-*,--destructive,--chart-2..5, semantic and fixed. Cream/Bloom inherit default's status colors rather than brand-harmonizing them.--background— a dedicated--shell-gradient-basetoken drives the gradient, so--backgroundcan stay a neutral default across all palettes without flattening the gradient.Why this architecture
Re-skinning never breaks contrast: the only solid brand surfaces carrying text are
--primary/--secondary, whose foregrounds are owned alongside them. Everything else is either a derived light/dark tint over a neutral card or a locked neutral/status surface — so any brand swap stays readable in both modes with no per-mode duplication.Files
assets/themes/default.css(new — merged light+dark),cream.css,bloom.css— tiered + derivations.assets/themes/light.css,dark.css— removed.assets/theme.css— import the three palette files.Verification
pnpm --filter @tailor-platform/app-shell buildgreen — CSS bundles with no dangling imports.🤖 Generated with Claude Code