docs(apps): design-system component + theme showcase (VitePress-primary, HTML⇄React) - #22
Merged
Merged
Conversation
…ents}@0.1.2 CSS Pin the design-system devDeps to 0.1.2 (theme/components/components-react) and load the tokens + component CSS globally in the custom theme so the upcoming <ComponentDemo>/<TokenGallery> live previews render fully themed. Safe against the VitePress chrome by construction (a dedicated non-regression test will assert it): @civitai/theme ships only --civitai-* custom properties (no --vp-* overlap, styles no elements); @civitai/components is scoped to [data-civitai-ui] and wrapped in @layer civitai.components (layered CSS loses to the unlayered chrome). Build stays green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ve demo Shoelace-style demo component: renders the framework-agnostic `data-civitai-ui` HTML LIVE as the primary themed preview, above a code panel toggling HTML⇄React source (both shiki-highlighted with copy buttons via VitePress fenced-block slots). Single source of truth: the live preview is derived from the SAME text shown in the HTML panel (the #html slot's rendered <code>), so the preview can never drift from the shown HTML. The preview container's data-theme is driven by VitePress dark mode (useData().isDark) so every --civitai-* token re-resolves to match the site theme. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nents
Adds apps/showcase.md: a <ComponentDemo> live-themed gallery covering every
@civitai/components component (Button variants/sizes/loading, Badge variants +
0.1.2 data-color intents, Alert intents, the 3 labeled inputs incl. invalid
state, Card +/-border, Stack/Group, Loader) with an HTML-React source toggle,
plus nav + a shared 'Design system' sidebar (showcase + tokens).
Also fixes a latent <ComponentDemo> bug: Vue 3.3+ infers type: Boolean from the
react?: boolean annotation, so an absent Boolean prop casts to false — a bare
<ComponentDemo> hid the React panel. Explicit { react: true } default restores
the intended behaviour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds apps/tokens.md and a <TokenGallery> that reads the tokens LIVE from the published @civitai/theme JS export (tokens/darkTokens/tokenVars) plus a getComputedStyle probe per theme — color swatches (hex+name), typography specimens, radius, a full light/dark token table, the component size scales (reference), and the DTCG tokens.json surfaced in a collapsible panel. Every row is derived from Object.keys(tokenVars) so it cannot drift from the package. Container follows useData().isDark. Registered in the theme + already in nav. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds two committed, runnable gates plus a faithful-render CSS fix: - scripts/test-showcase-e2e.mjs (playwright-core + system/nix Chromium): 21 checks — live-render-themed previews in BOTH light and dark (filled Button bg rgb(34,139,230)->rgb(25,113,194), Badge pill, Card surface, Loader circle, Alert tint, inputs; toggling the appearance switch re-resolves the tokens in place), <ComponentDemo> panel-swap + preview render, snippet accuracy (shown HTML === live preview for all 9 demos), and site-chrome non-regression (no DS leak into nav/sidebar; chrome font = --vp-font-family-base while previews use --civitai-font; --vp-c-brand-1 unshadowed). Captures light+dark screenshots. Skips gracefully (exit 0) when no Chromium is present. - scripts/test-tokens-drift.mjs: asserts <TokenGallery> renders EXACTLY the tokens @civitai/theme exports (missing/stale/misnamed all fail). - design-system.css: revert-layer fix so preview form controls render faithfully despite VitePress's UNLAYERED button/input reset beating the LAYERED component CSS — scoped to .cds-preview, chrome untouched (asserted by the chrome test). React-snippet typecheck accuracy is covered by the existing test:snippets:appblocks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ZacxDev
marked this pull request as ready for review
July 22, 2026 20:58
Clears the CodeQL high 'DOM text reinterpreted as HTML' finding in the snippet- accuracy check. DOMParser.parseFromString is inert (no execution) and yields the same parsed tree for the [data-civitai-ui] comparison. E2E still 21/21. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CodeQL flags BOTH innerHTML and DOMParser.parseFromString when fed DOM text (js/xss-through-dom). Compare the shown snippet's data-civitai-ui markers via a regex string match instead of reinterpreting the code text as HTML — same assertion, no sink. E2E still 21/21 (snippet-accuracy passes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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.
Design-system component + theme showcase (VitePress-primary, HTML⇄React)
Adds a live component showcase + token gallery for Civitai's
dual-consumption design system (
@civitai/theme/@civitai/components/@civitai/components-react) into the developer-docs site — VitePressmarkdown-primary, with a Shoelace-style HTML⇄React source toggle. Every live
preview is painted by the published packages a real consumer installs, so
the docs render exactly what a user gets.
Status: READY. Full build + test matrix is green (one pre-existing,
unrelated snapshot drift noted below).
Why VitePress-primary (not a standalone Storybook)
The design-system docs already live here (
apps/guide/theming, the generatedapps/reference/components). A showcase belongs next to them: same nav, search,shiki code blocks, and the existing
test:snippets:appblockssnippet-typecheckdrift-guard already typechecks React examples against the pinned
@civitai/components-reactdeclarations. One site, one deploy(developer.civitai.com).
What's built
@civitai/{theme,components,components-react}to0.1.2(exact); loaded the tokens + component CSS globally in the custom theme.
<ComponentDemo>: a live, themed HTML preview with an HTML⇄Reactsource toggle. The preview is derived from the same text shown in the HTML
panel, so it can't drift from the shown source.
apps/showcase.md: a<ComponentDemo>gallery for all 10components — Button (variants × sizes + loading/disabled), Badge (variants +
the new
0.1.2data-colorintents + sizes), Alert (all four intents +title + dismiss), TextInput / Textarea / NumberInput (incl. the invalid
state), Card (±border, padding), Stack & Group (gaps), Loader (sizes +
standalone
role="status"). Added nav + a shared Design system sidebar.apps/tokens.md+<TokenGallery>: reads the tokens live fromthe published
@civitai/themeJS export (tokens/darkTokens/tokenVars) plus agetComputedStyleprobe per theme — color swatches(hex + name + resolved), typography specimens, radius, a full light/dark
token table, the component size scales (clearly labelled as component-level,
not theme tokens), and the DTCG
tokens.jsonin a collapsible panel. Everyrow derives from
Object.keys(tokenVars), so it can't drift from the package.Containers follow
useData().isDark.Also fixed two latent issues surfaced while wiring the previews:
<ComponentDemo>hid the React panel on every bare<ComponentDemo>— Vue3.3+ infers
type: Booleanfromreact?: boolean, and an absent Booleanprop casts to
false(notundefined). Added an explicit{ react: true }default.
<button>/<input>rendered unthemed (transparent) becauseVitePress ships an unlayered form-control reset, and every
@civitai/componentsrule lives in@layer civitai.components— so theunlayered chrome reset won. Fixed with a
.cds-preview-scopedall: revert-layerthat rolls the cascade back past the reset to thedesign-system layer. Scoped to previews only; the chrome is provably
untouched (see the chrome test).
Test coverage — verbatim results
npm run build— exit 0, no dead links:npm run test:snippets:appblocks(existing gate; typechecks all Reactsnippets, incl. the 9 new
showcase.mdtsxblocks +tokens.mdts, againstpinned
@civitai/components-react@0.1.2):npm run test:tokens:drift(new — TokenGallery shows EXACTLY the theme'sexported tokens; missing/stale/misnamed all fail):
npm run test:showcase:e2e(new —playwright-core+ system/nix Chromium,against the built + served site; skips gracefully when no Chromium):
Coverage map to the plan: live-render-themed (light + dark, one anchor per
family, toggle re-resolves) ✓ · snippet accuracy — React typecheck via
test:snippets:appblocks+ HTML↔preview parity in the E2E ✓ · token-gallerydrift ✓ ·
<ComponentDemo>behaviour (toggle + preview render) ✓ ·site-chrome non-regression ✓ · existing gates kept green ✓.
Screenshots (light + dark, showcase + token gallery) are captured on-host by the
E2E run to
.showcase-shots/and were visually confirmed; thergb(...)assertions above are the objective, reproducible evidence of correct theming in
both modes.
Chrome-unaffected — confirmed
Asserted by the dedicated non-regression checks (all PASS above): no
[data-civitai-ui]element leaks into the nav/sidebar; the chrome font resolvesfrom
--vp-font-family-base(Inter, …) while previews use--civitai-font(
-apple-system, …); and--vp-c-brand-1(#0ea5e9) is not shadowed by--civitai-color-primary. By construction,@civitai/themeships only--civitai-*custom properties (no--vp-*overlap) and@civitai/componentsis scoped to
[data-civitai-ui]under@layer civitai.components(layered CSSloses to the unlayered chrome — the same mechanism the preview
revert-layerfix works with, scoped to
.cds-preview).Pre-existing, out-of-scope:
check:snapshotsnpm run check:snapshotsreports 1 drifted —appblocks-snapshots/MARKUP.mdvs the live upstream
civitai-app-starters. This is pre-existing andunrelated to this PR:
MARKUP.mdwas last modified in #18 and is byte-identicalat the branch base and HEAD. Upstream has since re-pinned the CDN URLs to
@0.1.1and added Badge
data-colordocs; the committed snapshot is unpinned and predatesdata-color. Reconciling it needs a maintainer decision on the CDN pin (the repodeliberately unpinned per #19/#20), so it's intentionally left untouched here.
🤖 Generated with Claude Code