feat(themes): add shadcn create styles to themes and installs

Merged
LO
1d ago
+1270-171

What and why

Closes #113.

A project scaffolded with shadcn create in Nova or Maia got drift components that still looked like Vega. This adds the eight create styles (Vega, Nova, Maia, Lyra, Mira, Luma, Sera, Rhea) to /themes and to installs. The decision is recorded in the issue comment.

Shape tokens

Fields, buttons, popovers, cards and dialogs in registry/default/ui and registry/base/ui now use h-control, h-control-sm, rounded-control, rounded-box, rounded-card, rounded-dialog, shadow-control and shadow-card instead of fixed classes. Each style's values are one entry in lib/style-tokens.ts.

Components that use the tokens depend on a new @drift-ui/shape item (registry:theme). scripts/build-style-registry.ts writes public/r/styles/<style>/shape.json, and next.config.ts serves it for radix-<style> and base-<style>. Every other style, including new-york, gets Vega, whose values are the classes drift uses today, so existing installs don't change.

tests/lib/style-tokens.test.ts fails if a registry item uses a token class without depending on @drift-ui/shape, or if globals.css and the shape item drift from the Vega values.

/themes

  • The sidebar panel is now a floating bar at the bottom. Style, Preset and Radius open as popovers on hover, and click and keyboard still work. Below 1024px the bar collapses to one button that opens the full panel.
  • The docs preview theme popover also gets the Style section.
  • The URL carries ?preset=<7-char code>, a hash of style, preset and radius. The server decodes it, so a shared or reloaded link renders without a layout shift. Pasted custom CSS isn't encoded and stays in localStorage only. /themes is now dynamic because it reads searchParams.
  • The page heading matches Components and Blocks.

Known gaps

  • Tokens don't reproduce Sera's underline-only input, Rhea's filled input or Nova's muted card footer.
  • Dialog padding stays the same across styles.
  • Drift's own button.tsx is shadcn's new-york button, so the Vega preview pads buttons a little differently from real Vega. Installs use the user's own button.

No new dependencies.

Screenshots

Light, Maia with the Ember preset:

Themes page in light mode with the Maia style and Ember preset

Dark, with the Style picker open:

Themes page in dark mode with the Style picker open

Checklist

  • bun run typecheck, bun run lint and bun run test pass
  • Tests cover the change, including keyboard interaction for UI components
  • New components are added to registry.json, lib/catalog.ts, components/docs/preview-registry.tsx and lib/agent-docs/component-usage.ts, each at its alphabetical position (no new components)
  • Checked in light and dark mode