Skip to content

0.30.0 - Sidebar active gradient tokens: --sidebar-active-start and --sidebar-active-end - #4

Merged
jalexw merged 1 commit into
mainfrom
claude/sidebar-active-gradient-tokens-eo72u4
Sep 27, 2026
Merged

jalexw merged 1 commit into
mainfrom
claude/sidebar-active-gradient-tokens-eo72u4

Conversation

@jalexw

@jalexw jalexw commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Summary

schemavaults/ui#126 uses a two-colour gradient to mark the DashboardLayout sidebar item for the current page. It reads the colours as var(--sidebar-active-start, var(--schemavaults-brand-blue)) and var(--sidebar-active-end, var(--schemavaults-brand-red)). This PR defines those two tokens so deployments can re-theme the gradient like any other token. It also bumps the package to 0.30.0. No existing token is changed or repurposed.

id label default (light & dark)
sidebar-active-start Sidebar active gradient start var(--schemavaults-brand-blue)
sidebar-active-end Sidebar active gradient end var(--schemavaults-brand-red)

Both are in the sidebar group with the css-color format, placed right after sidebar-ring.

Defaults that follow another token

The defaults are references to other tokens, not literal colours, so re-theming brand-blue or brand-red also re-colours the gradient unless these two are set separately:

--sidebar-active-start: var(--sv-theme-light-sidebar-active-start, var(--schemavaults-brand-blue));

The manifest now represents such a default explicitly instead of hiding it in a string:

  • ModeThemeToken.defaultFrom (optional): names the token the default follows. A new helper, colorFrom(), builds defaults from that token's CSS variable, so the two can't drift apart.
  • Sync test: checks that a defaultFrom token's default is exactly var(<source variable>), that its source has the same scopes, and that no other token's default hides a var() reference.
  • resolveThemeTokens: resolves a defaultFrom default to the source token's effective value, including the source's override. A settings page therefore shows #0ea5e9 after brand-blue is re-themed, not var(...). For tokens without defaultFrom, nothing changes.

No fallback to literal values was needed.

Other changes

  • globals.css: declares both tokens in :root and .dark.
  • Overrides: createThemeOverrideStyle, renderThemeOverrideCss and themeOverridesFromEnvironment pick the tokens up from the manifest (THEME_LIGHT_SIDEBAR_ACTIVE_START, THEME_DARK_SIDEBAR_ACTIVE_END, …).
  • Tailwind: new sidebarColors exposes sidebar-active-start and sidebar-active-end through colorWithAlphaChannel, so from-sidebar-active-start to-sidebar-active-end and bg-sidebar-active-start/20 work. The keys are flat rather than nested under sidebar, so they can't collide with an app's own sidebar colour.
  • README: documents the tokens, their env var names, the brand-following defaults, and that they are accent colours (use saturated, mid-lightness values when overriding them).

Verification

  • bun run test: 135 pass (117 before). The new src/sidebar_colors.test.ts covers the manifest entries, env var names, override CSS output, defaults following the brand tokens (per mode, and giving way to the token's own override), and the Tailwind classes including gradient stops and opacity modifiers. With globals.css, the Tailwind wiring and the resolver change reverted, 10 of the new tests fail.
  • tsc --noEmit and bun run build are clean; bun pm pack --dry-run includes dist/sidebar_colors.*.
  • Compiled globals.css through the factory's Tailwind config and loaded it in headless Chromium:
    • Defaults resolve to #60a5fa / #dc2626 in both modes.
    • A light brand-blue override changes the gradient in light mode only.
    • A dark brand-red override applies with .dark on <body>.
    • An explicit --sv-theme-light-sidebar-active-start wins over a brand override.
  • Contrast check on the default pair, mixed 60/40 with --foreground as the UI does: ≥ 5.59:1 against the plain sidebar background in both modes (sRGB mix; 6.19:1 in oklab). On its own, brand blue is 2.4:1 on the light sidebar, which is why the README calls these accent colours, not text colours.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Edc98fMEUtdYir2GjG9fa4


Generated by Claude Code

…-sidebar-active-end

Two overridable colour tokens for the gradient that marks the active
navigation sidebar item (@schemavaults/ui DashboardLayout). They sit in the
"sidebar" group right after sidebar-ring and default to the brand colours,
so re-theming brand-blue / brand-red re-colours the gradient unless these
are set separately:

  --sidebar-active-start: var(--sv-theme-light-sidebar-active-start, var(--schemavaults-brand-blue));
  --sidebar-active-end:   var(--sv-theme-light-sidebar-active-end,   var(--schemavaults-brand-red));

- theme_tokens: ModeThemeToken gains an optional `defaultFrom`, naming the
  token a default follows; the manifest sync test checks that such a
  default is exactly `var(<source variable>)` and that no other default
  hides a `var()` reference.
- resolveThemeTokens resolves a `defaultFrom` default to the source
  token's effective value, its override included, so a settings page
  shows a real colour rather than `var(...)`.
- Tailwind: `sidebar-active-start` / `sidebar-active-end` colours through
  colorWithAlphaChannel (from-/via-/to-, bg-…/20, …).
- README: tokens, env var names, brand-following defaults, and guidance
  that they are accent colours, not text colours.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Edc98fMEUtdYir2GjG9fa4
@jalexw
jalexw merged commit c2a1cd1 into main Sep 27, 2026
@jalexw jalexw self-assigned this Sep 27, 2026
@jalexw
jalexw deleted the claude/sidebar-active-gradient-tokens-eo72u4 branch September 27, 2026 03:20
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.

2 participants