You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(design): enforce strict component styles across plugins and examples
Tighten the shared `@internal/design` vocabulary so every surface reads as
one product:
- One nav: a single fixed-height `df-nav` led by `navBrand()` (a
primary-tinted Phosphor icon + the product name), replacing each
surface's bespoke header.
- Exactly three button forms: a text button (`button()`), an icon button
(`iconButton()`, bordered) and a borderless icon button
(`iconButton({ variant: 'ghost' })`). Icon sizes are removed from the
text-button recipe so the forms can't blur together.
- One segmented view switcher (`tabsList()` + `tab()`) with a leading
icon per tab. Inspect's tabs gain icons; git drops its sidebar switcher
for the same top-nav selector.
Bring every plugin (inspect, git, a11y, terminals, code-server) and all
five examples onto the system, adding the UnoCSS toolchain to the
examples. Document the rules in AGENTS.md, including the antfu /
antfu-design skills and the upstream inspector UIs the surfaces descend
from.
Copy file name to clipboardExpand all lines: AGENTS.md
+11-9Lines changed: 11 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -40,15 +40,17 @@ The `pnpm test` script intentionally runs `build` first so `tsnapi` snapshots co
40
40
41
41
### Design system
42
42
43
-
All five built-in plugins share one design system, `@internal/design`, so they look and feel like one product across frameworks (Git is React/Next, terminals is Svelte, code-server is vanilla DOM, inspect is Vue, a11y is Solid). It's a private, source-only package — never built or published; consumers import its TypeScript/CSS directly (resolved through `alias.ts` for bundlers and the package `exports` for config loaders), so editing it needs no rebuild.
44
-
45
-
-**One preset to extend.** Each plugin's `uno.config.ts` is just `presets: [presetDevframe()]` (imported from `@internal/design/preset`). The preset bundles `presetWind4` + `presetIcons` (Phosphor) + the directive/variant-group transformers, the semantic token theme, and the shared `df-*` component shortcuts (which it safelists). Don't re-declare presets, palettes, or shortcuts per plugin.
46
-
-**One token source.** Import `@internal/design/theme.css` once on the page (after the generated UnoCSS stylesheet so its base layer wins). Token *values* (the `--df-*` custom properties, light + dark via the `.dark` class) live only there — never hardcode a palette in a plugin. The brand primary is devframe's sage green; flip the OS preference onto `<html class="dark">` from the SPA entry.
47
-
-**Shared component vocabulary.** Build UI from the `df-*` classes (`df-btn`, `df-badge`, `df-tab`, `df-navtab`, `df-nav`, `df-toolbar`, `df-card`, `df-input`, `df-dot`, `df-tag-*`, …) and the semantic token utilities (`bg-primary`, `text-muted-foreground`, `bg-card`, `border-border`, …). Markup differs per framework; the classes resolve identically, which is what keeps the surfaces consistent.
48
-
-**Component builders.** Prefer the framework-neutral recipes from `@internal/design/components` (`button`, `badge`, `tab`, `navTab`, `nav`, `toolbar`, `card`, `panel`, `input`, `link`, `dot`, `spinner`, `tag`) over hand-written class strings — they return the canonical `df-*` classes and read the same in React (`className=`), Svelte (`class=`), vanilla DOM and Solid. Because these classes are assembled at runtime, the preset safelists the `df-*` vocabulary so UnoCSS always emits it; add new component classes to `DF_SAFELIST` when you extend the set.
49
-
-**Icons** come from the shared Phosphor set (`i-ph-*`, duotone preferred) via `presetIcons` — use them across every plugin instead of per-plugin icon libraries or bespoke SVG.
50
-
-**A plugin keeping its own component CSS** (inspect, a11y) re-bases its color/radius tokens onto the `--df-*` variables rather than hardcoding a palette, so it tracks the shared theme.
51
-
-**Plain `.ts`/vanilla views** must opt `.ts` into UnoCSS extraction (`content.pipeline.include`), since UnoCSS only scans framework files by default.
43
+
All five built-in plugins — and every example under `examples/` — share one design system, `@internal/design`, so they look and feel like one product across frameworks (Git is React/Next, terminals is Svelte, code-server is vanilla DOM, inspect is Vue, a11y is Solid, the examples are Preact/Next/vanilla). It's a private, source-only package — never built or published; consumers import its TypeScript/CSS directly (resolved through `alias.ts` for bundlers and the package `exports` for config loaders), so editing it needs no rebuild.
44
+
45
+
-**Respect the skills.** This design system is built to the `antfu` and `antfu-design` skills (UnoCSS-first, class-based semantic tokens, dual light/dark, anti-slop) — load and follow them when building or changing any UI here. The surfaces deliberately echo the upstream devtools they descend from; reference their UI/UX when in doubt: [`antfu/node-modules-inspector`](https://github.com/antfu/node-modules-inspector), [`antfu/vite-plugin-inspect`](https://github.com/antfu/vite-plugin-inspect), [`eslint/config-inspector`](https://github.com/eslint/config-inspector), and [`vitejs/devtools` → `packages/rolldown`](https://github.com/vitejs/devtools/tree/main/packages/rolldown).
46
+
-**One preset to extend.** Each consumer's `uno.config.ts` is just `presets: [presetDevframe()]` (imported from `@internal/design/preset`). The preset bundles `presetWind4` + `presetIcons` (Phosphor) + the directive/variant-group transformers, the semantic token theme, and the shared `df-*` component shortcuts (which it safelists). Don't re-declare presets, palettes, or shortcuts per consumer.
47
+
-**One token source.** Import `@internal/design/theme.css` once on the page (after the generated UnoCSS stylesheet so its base layer wins). Token *values* (the `--df-*` custom properties, light + dark via the `.dark` class) live only there — never hardcode a palette. The brand primary is devframe's sage green; flip the OS preference onto `<html class="dark">` from the SPA entry.
48
+
-**Shared component vocabulary.** Build UI from the `df-*` classes (`df-btn`, `df-badge`, `df-tab`, `df-navtab`, `df-nav`, `df-nav-brand`, `df-toolbar`, `df-card`, `df-input`, `df-dot`, `df-tag-*`, …) and the semantic token utilities (`bg-primary`, `text-muted-foreground`, `bg-card`, `border-border`, …). Markup differs per framework; the classes resolve identically, which is what keeps the surfaces consistent.
49
+
-**Component builders.** Prefer the framework-neutral recipes from `@internal/design/components` (`button`, `iconButton`, `badge`, `tab`, `tabsList`, `navTab`, `nav`, `navBrand`, `toolbar`, `card`, `panel`, `input`, `link`, `dot`, `spinner`, `tag`) over hand-written class strings — they return the canonical `df-*` classes and read the same in React (`className=`), Svelte/Vue (`class=`), vanilla DOM and Solid. Because these classes are assembled at runtime, the preset safelists the `df-*` vocabulary so UnoCSS always emits it; add new component classes to `DF_SAFELIST` when you extend the set.
50
+
-**One nav, three buttons, one tab selector — strictly.** Every surface opens with the same top bar: `nav()` (a single row, one fixed height) led by `navBrand()` (a primary-tinted `i-ph-*` icon + the product name). Buttons come in exactly three forms and nothing else: a **text button** (`button({ variant, size })`), an **icon button** (`iconButton()` — bordered), and a **borderless icon button** (`iconButton({ variant: 'ghost' })`). Multi-view tools (inspect, git) switch views with the one shared segmented selector — `tabsList()` wrapping `tab()` buttons that carry `data-state="active"` and a leading `i-ph-*` icon per tab. Don't invent bespoke nav bars, button shapes, or tab styles.
51
+
-**Icons** come from the shared Phosphor set (`i-ph-*`, duotone preferred) via `presetIcons` — use them everywhere instead of per-consumer icon libraries or bespoke SVG.
52
+
-**A surface keeping its own component CSS** (inspect, a11y) re-bases its color/radius tokens onto the `--df-*` variables rather than hardcoding a palette, so it tracks the shared theme.
53
+
-**Plain `.ts`/vanilla views** must opt `.ts` into UnoCSS extraction (`content.pipeline.include` for Vite, or `content.filesystem` globs for the `@unocss/postcss` setup Next uses), since UnoCSS only scans framework files by default.
0 commit comments