Skip to content

feat(themes): copy-a-theme flow on /themes + astryx theme add CLI#3241

Merged
rubyycheung merged 11 commits into
mainfrom
docsite/theme-page-content
Jun 29, 2026
Merged

feat(themes): copy-a-theme flow on /themes + astryx theme add CLI#3241
rubyycheung merged 11 commits into
mainfrom
docsite/theme-page-content

Conversation

@rubyycheung

Copy link
Copy Markdown
Contributor

Summary

Reframes the /themes page 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).

/themes page (apps/docsite)

  • New copy: "Astryx comes with a default theme built in. To make it your own, copy any theme you see here into a theme file you own."
  • Two actions: Use this theme (primary) opens a popover with the copy command; Try in Playground (secondary). Mirrors the existing PackageActions install-popover pattern.
  • Preview light/dark toggle moved beside the page title.
  • Command is rendered with the XDS CodeBlock component (was a bespoke pill before).

astryx theme add CLI (@astryxdesign/cli)

  • New 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 to src/themes/<slug>/.
  • New astryx theme list shows available themes.
  • Theme sources are bundled into the CLI under templates/themes/ via scripts/generate-cli-themes.mjs (wired into the root build), so it works without the theme package installed — same model as page templates.
  • Adds ERR_UNKNOWN_THEME, exposes themeAdd/listThemes via @astryxdesign/cli/api, and adds the new commands to the API/CLI parity test.
  • Path-safety, overwrite protection (-f), and --json envelopes match the existing template command.

Test plan

  • /themes: select different themes; verify "Use this theme" popover shows npx astryx theme add <slug> and copy works; "Try in Playground" opens the playground with the theme.
  • Verify desktop sidebar + mobile layouts, and light/dark toggle beside the title.
  • CLI: npx astryx theme list
  • CLI: npx astryx theme add matcha scaffolds src/themes/matcha/{matchaTheme.ts,icons.tsx}
  • CLI: explicit path, -f overwrite, unknown slug, and path-traversal rejection
  • CLI: --json envelopes for theme add / theme list
  • node scripts/generate-cli-themes.mjs regenerates the bundle cleanly

Notes / follow-ups

  • The astryx theme add command bundles theme source at build time; the bundle is committed so the published package contains it.
  • /docs/theme still presents themes as npm install-able packages — a consistency pass there is a follow-up, out of scope for this change.

Made with Cursor

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>
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview, Comment Jun 29, 2026 8:02pm

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Jun 29, 2026
rubyycheung and others added 5 commits June 29, 2026 12:54
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>
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

No new or modified components detected.

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.6KB 0B

Accessibility Audit

Status: No accessibility violations detected.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

github-actions Bot added a commit that referenced this pull request Jun 29, 2026
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 nynexman4464 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
@rubyycheung

Copy link
Copy Markdown
Contributor Author

Thanks for testing this end-to-end, @nynexman4464! Fixed all the issues you hit (commits 5e0fd2f + cbddb8f):

  • Wrong ./src/... import paththeme add and theme build no longer fabricate a cwd-rooted path. They now emit bare ./<name> specifiers with a note that the import is relative to your own file, so it's correct whether or not your file lives under src/.
  • gothicTheme.css vs gothic.js naming mismatchtheme build now derives every default output (.css/.js/.d.ts) from the theme name, so building gothicTheme.ts gives gothic.css + gothic.js + gothic.d.ts. (An explicit --out still wins, so the published theme packages that pass -o dist/theme.css are unchanged.)
  • Unknown prop "variant" on component "card" — false positive; card does support themeable variant values (Gothic adds color variants). Added variant to card's known props, so it now generates the type augmentations instead of warning.

The "had to figure out theme build wanted the full file path" point is fair too — theme add's output now tells you exactly where the files landed. Verified end-to-end with npx astryx theme add gothictheme build.

Co-authored-by: Cursor <cursoragent@cursor.com>

@nynexman4464 nynexman4464 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
@rubyycheung

Copy link
Copy Markdown
Contributor Author

Good call — I overcorrected. Stripping it to bare ./gothicTheme dropped the themes/gothic/ part people actually need (commit 54aa575).

Now it only drops a leading src/ (since most consumers import from a file under src/) and keeps the rest of the path:

import { gothicTheme } from './themes/gothic/gothicTheme';
import './themes/gothic/gothic.css';

Same for theme build. The note clarifies the path is relative to a file in src/ so anyone importing from elsewhere knows to adjust. Glad the naming consistency looks good now.

Co-authored-by: Cursor <cursoragent@cursor.com>
github-actions Bot added a commit that referenced this pull request Jun 29, 2026
@rubyycheung rubyycheung merged commit 627808d into main Jun 29, 2026
23 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants