feat(themes): copy-a-theme flow on /themes + astryx theme add CLI#3241
Conversation
Reframe the /themes page so people copy any theme into their own project instead of installing it: Astryx ships a default theme built into core, and every theme in the gallery is a starting point you own. The primary "Use this theme" action opens a popover with a CLI command; "Try in Playground" is secondary, and the preview mode toggle moves beside the page title. Add a real `astryx theme add <slug> [path]` command (plus `theme list`) that scaffolds a theme's source into the consumer's project, backed by theme sources bundled into the CLI via scripts/generate-cli-themes.mjs (wired into the root build). Adds ERR_UNKNOWN_THEME, exposes themeAdd via the programmatic API, and covers the new commands in the API/CLI parity test. Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Remove the ThemeInstallBlock (npm install + import snippet) that landed on /themes in #3093. It conflicts with this branch's direction: themes aren't installed as packages, they're copied into your own project via "Use this theme". Restore the single showcaseBlock style (the contentBlock /showcaseClip split only existed to share width with the install block). Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
PR Analysis Report📚 Storybook PreviewView Storybook for this PR 🧪 Sandbox PreviewView Sandbox for this PR No new or modified components detected. Bundle Size Summary
Accessibility AuditStatus: No accessibility violations detected. Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
Add `theme add` and `theme list` to the RESPONSE_TYPES/EXAMPLES manifest maps (the drift-guard test requires every JSON-supported command to declare its response types), and remove an unused destructured variable in the `theme add` human output that failed lint. Co-authored-by: Cursor <cursoragent@cursor.com>
nynexman4464
left a comment
There was a problem hiding this comment.
I like this approach. The "Use this theme" button makes things fairly clear. I tested npx astryx theme add gothic with my TODO app.
It copied the theme to src/themes/gothic/gothicTheme.ts and suggested I import with import { gothicTheme } from './src/themes/gothic/gothicTheme';. This is slightly wrong, my app "main.tsx" is already in /src so the correct import path is import { gothicTheme } from './themes/gothic/gothicTheme';. That's easily fixed.
I also got a warning that I should build the theme with npx astryx theme build <file>. IT took me a bit to figure out it wanted src/themes/gothic/gothicTheme.ts (not just gothic or themes/gothic. There were some warnings on build:
⚠ Unknown prop "variant" on component "card". This component has no variant props.
Also the import instructions were slightly wrong. It said
Install in your app:
import { gothicTheme } from './src/themes/gothic/gothic';
import './src/themes/gothic/gothic.css';
<Theme theme={gothicTheme}>
<App />
</Theme>Again the ./src path is wrong (easily fixed) but more annoying the css file was compiled as gothicTheme.css but I think the module was compiled as just gothic.js. Slightly confusing - I can file a separate bug for build if that makes sense. It would be good if they were both the same naming scheme.
Addresses PR review feedback on `astryx theme add` / `theme build`: - Derive the default CSS output name from the theme name (like the JS module) so .css/.js/.d.ts share one scheme; building gothicTheme.ts produced gothicTheme.css but gothic.js — now both are gothic.*. An explicit --out still wins (theme packages pass -o dist/theme.css). - Stop fabricating a cwd-rooted import path (./src/...) in the install / scaffold instructions; show bare ./<name> specifiers with a note to point them at where the files landed, since the import is relative to the consumer's own file (wrong when it already lives under src/). - Reference the actual emitted CSS basename (honors --out) instead of assuming <name>.css. - Add `variant` to card's known props so themes adding card color variants (e.g. Gothic) no longer trigger a false "Unknown prop" warning. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Thanks for testing this end-to-end, @nynexman4464! Fixed all the issues you hit (commits
The "had to figure out |
Co-authored-by: Cursor <cursoragent@cursor.com>
nynexman4464
left a comment
There was a problem hiding this comment.
Seems alright. I think the import just being ./gothicTheme is slightly more confusing, since its missing the themes/gothic/ bit which is required.
Build worked fine, similar feedback on the paths. It emitted
Install in your app (these files are in src/themes/gothic/ — adjust the paths to
import them relative to your own file):
import { gothicTheme } from './gothic';
import './gothic.css';
<Theme theme={gothicTheme}>
<App />
</Theme>
I think most people will at least have to add /themes/gothic/<file> so I sort of think that part should stay.
import { gothicTheme } from './themes/gothic/gothic';
import './themes/gothic/gothic.css';
Naming consistency seems fixed now though so that's good.
Per PR review: stripping the path down to a bare `./gothicTheme` lost the `themes/gothic/` segment people actually need. Now drop only a leading `src/` (most consumers import from a file under src/) and keep the rest, so `theme add`/`theme build` emit `./themes/gothic/gothicTheme`. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Good call — I overcorrected. Stripping it to bare Now it only drops a leading Same for |
Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Reframes the
/themespage around copying a theme into your own project instead of installing it, and adds a real CLI command to do the copy.Why: Feedback showed people thought they could install the gallery themes, but the design team only maintains Neutral and doesn't want to support the rest as packages. Astryx already ships a default theme built into core, so every theme in the gallery is better framed as a starting point you copy and own (like templates).
/themespage (apps/docsite)PackageActionsinstall-popover pattern.CodeBlockcomponent (was a bespoke pill before).astryx theme addCLI (@astryxdesign/cli)astryx theme add <slug> [path]scaffolds a theme's source (<slug>Theme.ts+icons.tsx) into the consumer's project as editable files they own. Defaults tosrc/themes/<slug>/.astryx theme listshows available themes.templates/themes/viascripts/generate-cli-themes.mjs(wired into the rootbuild), so it works without the theme package installed — same model as page templates.ERR_UNKNOWN_THEME, exposesthemeAdd/listThemesvia@astryxdesign/cli/api, and adds the new commands to the API/CLI parity test.-f), and--jsonenvelopes match the existingtemplatecommand.Test plan
/themes: select different themes; verify "Use this theme" popover showsnpx astryx theme add <slug>and copy works; "Try in Playground" opens the playground with the theme.npx astryx theme listnpx astryx theme add matchascaffoldssrc/themes/matcha/{matchaTheme.ts,icons.tsx}-foverwrite, unknown slug, and path-traversal rejection--jsonenvelopes fortheme add/theme listnode scripts/generate-cli-themes.mjsregenerates the bundle cleanlyNotes / follow-ups
astryx theme addcommand bundles theme source at build time; the bundle is committed so the published package contains it./docs/themestill presents themes asnpm install-able packages — a consistency pass there is a follow-up, out of scope for this change.Made with Cursor