@autono/open-pages 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/dist/{build-TP72kiw7.js → build-Cq6uszaI.js} +3 -3
- package/dist/cli/bin.js +4 -4
- package/dist/{config-L0IbktJ0.js → config-DniCVIl6.js} +34 -7
- package/dist/{dev-I2IyEh5W.js → dev-DyY9SvwF.js} +2 -2
- package/dist/export-DqLDEQkL.js +4 -0
- package/dist/{export-ic28osQP.js → export-pYjzc4Cl.js} +10 -3
- package/dist/{open-pages-plugin-D_DN_zjh.js → open-pages-plugin-CACQ7TVo.js} +40 -6
- package/dist/{preview-BrDuvgAN.js → preview-CLb35jHx.js} +2 -2
- package/dist/vite/index.js +2 -2
- package/package.json +1 -1
- package/skills/apply-comments/SKILL.md +4 -4
- package/skills/create-page/SKILL.md +26 -8
- package/skills/create-theme/SKILL.md +137 -150
- package/skills/current-page/SKILL.md +1 -1
- package/skills/page-authoring/SKILL.md +97 -42
- package/skills/page-authoring/references/interactivity.md +70 -22
- package/skills/page-authoring/references/layout-and-responsive.md +38 -17
- package/skills/page-authoring/references/typography-and-color.md +50 -32
- package/skills/shadcn/SKILL.md +277 -0
- package/skills/shadcn/assets/shadcn-small.png +0 -0
- package/skills/shadcn/assets/shadcn.png +0 -0
- package/skills/shadcn/cli.md +290 -0
- package/skills/shadcn/customization.md +209 -0
- package/skills/shadcn/mcp.md +105 -0
- package/skills/shadcn/registry.md +277 -0
- package/skills/shadcn/rules/base-vs-radix.md +306 -0
- package/skills/shadcn/rules/chat.md +224 -0
- package/skills/shadcn/rules/composition.md +213 -0
- package/skills/shadcn/rules/forms.md +192 -0
- package/skills/shadcn/rules/icons.md +101 -0
- package/skills/shadcn/rules/styling.md +185 -0
- package/src/app/components/asset-view.tsx +11 -11
- package/src/app/components/command/command-menu.tsx +6 -6
- package/src/app/components/command/command.tsx +2 -2
- package/src/app/components/command/home-command-menu.tsx +2 -2
- package/src/app/components/icon-tooltip.tsx +1 -1
- package/src/app/components/language-toggle.tsx +7 -7
- package/src/app/components/sidebar/folder-item.tsx +5 -5
- package/src/app/components/sidebar/icon-picker.tsx +3 -3
- package/src/app/components/sidebar/sidebar-footer.tsx +4 -4
- package/src/app/components/sidebar/sidebar.tsx +6 -6
- package/src/app/components/theme-toggle.tsx +6 -6
- package/src/app/components/themes/theme-detail.tsx +4 -4
- package/src/app/components/themes/themes-gallery.tsx +1 -1
- package/src/app/components/ui/badge.tsx +1 -1
- package/src/app/components/ui/button.tsx +1 -1
- package/src/app/components/ui/card.tsx +1 -1
- package/src/app/components/ui/context-menu.tsx +1 -1
- package/src/app/components/ui/dialog.tsx +2 -2
- package/src/app/components/ui/dropdown-menu.tsx +1 -1
- package/src/app/components/ui/input.tsx +1 -1
- package/src/app/components/ui/label.tsx +1 -1
- package/src/app/components/ui/popover.tsx +1 -1
- package/src/app/components/ui/progress.tsx +1 -1
- package/src/app/components/ui/scroll-area.tsx +1 -1
- package/src/app/components/ui/select.tsx +1 -1
- package/src/app/components/ui/separator.tsx +1 -1
- package/src/app/components/ui/slider.tsx +1 -1
- package/src/app/components/ui/tabs.tsx +1 -1
- package/src/app/components/ui/textarea.tsx +1 -1
- package/src/app/components/ui/toggle-group.tsx +2 -2
- package/src/app/components/ui/toggle.tsx +1 -1
- package/src/app/components/ui/tooltip.tsx +1 -1
- package/src/app/frame/main.tsx +3 -1
- package/src/app/lib/themes.ts +1 -0
- package/src/app/lib/use-restart-server.ts +1 -1
- package/src/app/routes/home-shell.tsx +7 -7
- package/src/app/routes/home.tsx +5 -5
- package/src/app/routes/page.tsx +2 -2
- package/src/app/routes/themes.tsx +1 -1
- package/src/app/virtual.d.ts +3 -0
- package/dist/export-B-kBRWB1.js +0 -4
|
@@ -1,49 +1,106 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-theme
|
|
3
|
-
description: Use this skill when the user wants to create, draft, author, or extract a
|
|
3
|
+
description: Use this skill when the user wants to create, draft, author, or extract a theme in this open-pages repo. Triggers on phrases like "create a theme", "make a theme called X", "extract a theme from <page>", "match our brand", "build a design system from these screenshots", "apply this shadcn preset". Produces a three-file bundle under `themes/` — `<id>.md` (direction, fonts, component notes, token table), `<id>.css` (the shadcn token overrides), and `<id>.demo.tsx` (a demo page composed from `ui/` components that the workspace's Themes panel previews live). Do NOT use for editing real pages — only for authoring the theme bundle.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Create a
|
|
6
|
+
# Create a theme
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
A theme is a **token set**. Every workspace ships the full shadcn/ui set under `ui/`, and every component reads its colors, radius, and fonts from the CSS variables in `styles/globals.css` (`--background`, `--primary`, `--radius`, …). A theme overrides those variables; every component and every token-styled page restyles at once. Nothing is copied into pages.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
2. `themes/<id>.demo.tsx` — a runnable demo page (same module shape as `pages/<id>/index.tsx`: **one default-exported component**) that shows the theme on a single scrolling page. The workspace's Themes panel renders it live, exactly like a real page.
|
|
10
|
+
The bundle is three files sharing one stem under `themes/`:
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
1. `themes/<id>.md` — agent-facing direction: aesthetic, fonts, how to use the components in this theme, and a table of token → value. This is what `create-page` reads when an author picks the theme.
|
|
13
|
+
2. `themes/<id>.css` — **only** `:root { … }` and `.dark { … }` blocks overriding the shadcn tokens (plus an optional Google Fonts `@import url(…)` at the very top). No `@theme` block, no Tailwind import, no selectors beyond those two.
|
|
14
|
+
3. `themes/<id>.demo.tsx` — a runnable page module (same shape as `pages/<id>/index.tsx`, **one default-exported component**) composed from `@/ui/*` components so the tokens are shown on real parts. The Themes panel renders it with `<id>.css` injected automatically; the demo does not set `meta.theme`.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
A page opts in with `meta.theme: '<id>'`; the runtime injects `themes/<id>.css` into that page's preview frame and into its export.
|
|
16
17
|
|
|
17
|
-
You only write
|
|
18
|
+
You only write the three theme files. Never modify pages, `ui/`, `styles/globals.css`, or configuration. The token names and how pages consume them live in the **`page-authoring`** skill (`references/typography-and-color.md`) — read it first. Component props and variants: the **`shadcn`** skill.
|
|
18
19
|
|
|
19
20
|
## Step 1 — Identify the input source
|
|
20
21
|
|
|
21
|
-
A theme can be derived from any combination of
|
|
22
|
+
A theme can be derived from any combination of:
|
|
22
23
|
|
|
23
|
-
- **
|
|
24
|
+
- **A shadcn preset** — a code or URL from https://ui.shadcn.com/create. `npx shadcn@latest preset decode <code>` prints its tokens; or run `npx shadcn@latest apply <code> --only theme,font` in a scratch copy and lift the resulting `:root`/`.dark` values. Never run `apply` against the workspace's `styles/globals.css` directly — that changes the default for every page.
|
|
25
|
+
- **Image references / brand guidelines** — paths or URLs to screenshots, mood boards, logo files, a brand PDF. You will translate them into OKLCH tokens.
|
|
24
26
|
- **Free-text description** — prose describing the desired palette, weight, feel.
|
|
25
|
-
- **An existing page** — `pages/<id>/index.tsx` whose
|
|
27
|
+
- **An existing page** — `pages/<id>/index.tsx` whose look should become reusable.
|
|
26
28
|
|
|
27
|
-
If the user's original message already specifies the inputs unambiguously, skip the question and proceed. Otherwise call `AskUserQuestion` (multi-select) so they can pick one or more sources, and ask follow-ups (paths, page id, prose) only as needed.
|
|
29
|
+
If the user's original message already specifies the inputs unambiguously, skip the question and proceed. Otherwise call `AskUserQuestion` (multi-select) so they can pick one or more sources, and ask follow-ups (paths, preset code, page id, prose) only as needed.
|
|
28
30
|
|
|
29
31
|
## Step 2 — Gather raw inputs
|
|
30
32
|
|
|
31
|
-
- **
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
34
|
-
|
|
35
|
-
- Type sizes and any font loading (`<link>` to Google Fonts, `font-[…]`) → Typography section.
|
|
36
|
-
- Container widths, section padding, breakpoints used → Layout section.
|
|
37
|
-
- Recurring helper components (nav, hero, cards, buttons, footer) → Fixed components section.
|
|
38
|
-
- The aesthetic feel implied → Aesthetic paragraph.
|
|
33
|
+
- **Preset**: take its tokens as the baseline; adjust only what the user asked to change.
|
|
34
|
+
- **Images**: read each path with the `Read` tool (it accepts images). Note dominant colors (write them as hex, then convert to OKLCH), type family feel, corner radius, surface treatment (flat vs. cards vs. borders), light or dark default, and chrome (nav style, footer).
|
|
35
|
+
- **Text**: extract explicit values (hex codes, font names, "rounded", "sharp", "dense") and resolve vague language into concrete decisions before writing.
|
|
36
|
+
- **Existing page**: read `pages/<id>/index.tsx` (and `components/`) and pull any raw palette classes or hex values into token roles (the page's `bg-[#0b0b10]` root → `--background`; its CTA fill → `--primary`; its card border → `--border`), plus fonts and radius.
|
|
39
37
|
|
|
40
|
-
When inputs disagree (
|
|
38
|
+
Every color ends up as `oklch(L C H)` — the same format as `styles/globals.css`. When inputs disagree (images use blue but the description says green), ask the user which to honor.
|
|
41
39
|
|
|
42
40
|
## Step 3 — Pick a theme id
|
|
43
41
|
|
|
44
42
|
Use **kebab-case**, short, descriptive. Examples: `dark-launch`, `clean-saas`, `editorial-warm`, `ops-console`. Check `themes/` to avoid collisions.
|
|
45
43
|
|
|
46
|
-
## Step 4 — Write `themes/<id>.
|
|
44
|
+
## Step 4 — Write `themes/<id>.css`
|
|
45
|
+
|
|
46
|
+
Override the full token list for both modes, even when a value equals the default, so the file is self-describing:
|
|
47
|
+
|
|
48
|
+
```css
|
|
49
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter+Tight:wght@500;700&family=Inter:wght@400;500&display=swap');
|
|
50
|
+
|
|
51
|
+
:root {
|
|
52
|
+
--font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
|
|
53
|
+
--font-heading: 'Inter Tight', var(--font-sans);
|
|
54
|
+
--radius: 0.75rem;
|
|
55
|
+
--background: oklch(1 0 0);
|
|
56
|
+
--foreground: oklch(0.145 0 0);
|
|
57
|
+
--card: oklch(1 0 0);
|
|
58
|
+
--card-foreground: oklch(0.145 0 0);
|
|
59
|
+
--popover: oklch(1 0 0);
|
|
60
|
+
--popover-foreground: oklch(0.145 0 0);
|
|
61
|
+
--primary: oklch(0.55 0.2 265);
|
|
62
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
63
|
+
--secondary: oklch(0.97 0 0);
|
|
64
|
+
--secondary-foreground: oklch(0.205 0 0);
|
|
65
|
+
--muted: oklch(0.97 0 0);
|
|
66
|
+
--muted-foreground: oklch(0.5 0 0);
|
|
67
|
+
--accent: oklch(0.97 0 0);
|
|
68
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
69
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
70
|
+
--border: oklch(0.922 0 0);
|
|
71
|
+
--input: oklch(0.922 0 0);
|
|
72
|
+
--ring: oklch(0.55 0.2 265);
|
|
73
|
+
--chart-1: oklch(0.55 0.2 265);
|
|
74
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
75
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
76
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
77
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
78
|
+
--sidebar: oklch(0.985 0 0);
|
|
79
|
+
--sidebar-foreground: oklch(0.145 0 0);
|
|
80
|
+
--sidebar-primary: oklch(0.55 0.2 265);
|
|
81
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
82
|
+
--sidebar-accent: oklch(0.97 0 0);
|
|
83
|
+
--sidebar-accent-foreground: oklch(0.205 0 0);
|
|
84
|
+
--sidebar-border: oklch(0.922 0 0);
|
|
85
|
+
--sidebar-ring: oklch(0.55 0.2 265);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.dark {
|
|
89
|
+
--background: oklch(0.13 0.01 265);
|
|
90
|
+
--foreground: oklch(0.985 0 0);
|
|
91
|
+
/* … every token again, dark values … */
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Rules:
|
|
96
|
+
|
|
97
|
+
- Exactly the shadcn token names (`--background` … `--sidebar-ring`, `--radius`), plus optionally `--font-sans` / `--font-heading` and the font `@import`. Unknown names do nothing; misspelled names silently fall back to the default.
|
|
98
|
+
- `*-foreground` must contrast with its surface (≥ 4.5:1 for body pairs). Check `--muted-foreground` on `--background` and `--primary-foreground` on `--primary` explicitly.
|
|
99
|
+
- A dark-first theme still defines `:root` for light; a page that wants dark puts `dark` on its root element. If the theme is dark-only, make both blocks the dark values.
|
|
100
|
+
- `--radius` sets every radius (`rounded-sm` … `rounded-2xl` scale from it): `0` sharp, `0.5rem` default-ish, `1rem` soft.
|
|
101
|
+
- Fonts load from Google Fonts via `@import url(…)` at the top of this file, or from a self-hosted file the theme tells `create-page` to place under `assets/` (then `@font-face` goes in the page's `styles.css`, not here).
|
|
102
|
+
|
|
103
|
+
## Step 5 — Write `themes/<id>.md`
|
|
47
104
|
|
|
48
105
|
Produce a file with this exact section order. Section bodies adapt to the theme; the headings stay consistent across all themes.
|
|
49
106
|
|
|
@@ -55,169 +112,99 @@ description: <one-line elevator pitch>
|
|
|
55
112
|
|
|
56
113
|
# <Theme name>
|
|
57
114
|
|
|
58
|
-
##
|
|
115
|
+
## Tokens
|
|
59
116
|
|
|
60
|
-
|
|
|
117
|
+
| Token | Light | Dark | Role in pages |
|
|
61
118
|
| --- | --- | --- | --- |
|
|
62
|
-
| background | `
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
119
|
+
| `--background` / `--foreground` | `oklch(1 0 0)` / `oklch(0.145 0 0)` | … | page root (`bg-background text-foreground`) |
|
|
120
|
+
| `--primary` / `--primary-foreground` | … | … | the one accent: CTAs, active tabs, links |
|
|
121
|
+
| `--card`, `--muted`, `--accent`, `--secondary` | … | … | surfaces |
|
|
122
|
+
| `--border`, `--input`, `--ring` | … | … | rules, fields, focus |
|
|
123
|
+
| `--destructive` | … | … | delete, errors |
|
|
124
|
+
| `--chart-1…5` | … | … | chart series order |
|
|
125
|
+
| `--radius` | `0.75rem` | | rounded-lg cards, pill buttons via `rounded-full` |
|
|
126
|
+
|
|
127
|
+
The full set lives in `themes/<id>.css`; this table is the reference for what each value is *for*.
|
|
68
128
|
|
|
69
129
|
## Typography
|
|
70
130
|
|
|
71
|
-
-
|
|
72
|
-
- Type-scale overrides (only
|
|
73
|
-
- Hero heading: `text-5xl sm:text-7xl font-bold leading-[1.02] tracking-tight`
|
|
74
|
-
- Section heading: `text-3xl font-bold tracking-tight`
|
|
75
|
-
- Body: `text-lg text-white/60`
|
|
76
|
-
- Eyebrow: `text-xs font-semibold uppercase tracking-[0.25em] text-emerald-400`
|
|
131
|
+
- Fonts: `--font-sans` / `--font-heading` set in the CSS (how they load: Google Fonts `@import`, or a self-hosted file under `assets/`).
|
|
132
|
+
- Type-scale overrides (only what differs from `page-authoring` defaults): hero `text-5xl sm:text-7xl font-heading tracking-tight`; body `text-lg`; eyebrow `<Badge variant="secondary">`.
|
|
77
133
|
|
|
78
134
|
## Layout
|
|
79
135
|
|
|
80
|
-
- Container: `mx-auto max-w-6xl px-6`.
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
- Radius: `rounded-full` for buttons, `rounded-2xl` for cards.
|
|
84
|
-
|
|
85
|
-
## Fixed components
|
|
86
|
-
|
|
87
|
-
These are paste-ready React JSX with `className`. Copy them verbatim into a page that uses this theme.
|
|
88
|
-
|
|
89
|
-
### Nav
|
|
90
|
-
|
|
91
|
-
```tsx
|
|
92
|
-
const Nav = ({ brand, links, cta }: { brand: string; links: { label: string; href: string }[]; cta: { label: string; href: string } }) => (
|
|
93
|
-
<header className="mx-auto flex max-w-6xl items-center justify-between px-6 py-6">
|
|
94
|
-
<span className="font-semibold tracking-tight">{brand}</span>
|
|
95
|
-
<nav className="hidden gap-8 text-sm text-white/70 sm:flex">
|
|
96
|
-
{links.map((l) => (
|
|
97
|
-
<a key={l.href} href={l.href} className="hover:text-white">{l.label}</a>
|
|
98
|
-
))}
|
|
99
|
-
</nav>
|
|
100
|
-
<a href={cta.href} className="rounded-full bg-white px-4 py-2 text-sm font-medium text-black hover:bg-white/90">{cta.label}</a>
|
|
101
|
-
</header>
|
|
102
|
-
);
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Hero
|
|
106
|
-
|
|
107
|
-
```tsx
|
|
108
|
-
const Hero = ({ eyebrow, title, lede, children }: { eyebrow: string; title: string; lede: string; children?: React.ReactNode }) => (
|
|
109
|
-
<section className="mx-auto max-w-6xl px-6 pt-20 pb-24 text-center">
|
|
110
|
-
<p className="text-xs font-semibold uppercase tracking-[0.25em] text-emerald-400">{eyebrow}</p>
|
|
111
|
-
<h1 className="mx-auto mt-6 max-w-3xl text-5xl font-bold leading-[1.02] tracking-tight sm:text-7xl">{title}</h1>
|
|
112
|
-
<p className="mx-auto mt-6 max-w-xl text-lg text-white/60">{lede}</p>
|
|
113
|
-
<div className="mt-10 flex flex-col justify-center gap-3 sm:flex-row">{children}</div>
|
|
114
|
-
</section>
|
|
115
|
-
);
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### Section
|
|
119
|
-
|
|
120
|
-
```tsx
|
|
121
|
-
const Section = ({ id, children }: { id?: string; children: React.ReactNode }) => (
|
|
122
|
-
<section id={id} className="border-t border-white/10">
|
|
123
|
-
<div className="mx-auto max-w-6xl px-6 py-20">{children}</div>
|
|
124
|
-
</section>
|
|
125
|
-
);
|
|
126
|
-
```
|
|
136
|
+
- Container: `mx-auto max-w-6xl px-6`; section rhythm `py-20`; separators `border-t border-border`.
|
|
137
|
+
- Default mode: light | dark (`dark` on the page root).
|
|
138
|
+
- Density: airy | standard | dense — how much `gap-*` and padding pages should use.
|
|
127
139
|
|
|
128
|
-
|
|
140
|
+
## Components in this theme
|
|
129
141
|
|
|
130
|
-
|
|
131
|
-
const PrimaryButton = ({ href, children }: { href: string; children: React.ReactNode }) => (
|
|
132
|
-
<a href={href} className="rounded-full bg-emerald-400 px-6 py-3 font-medium text-black hover:bg-emerald-300">{children}</a>
|
|
133
|
-
);
|
|
134
|
-
const SecondaryButton = ({ href, children }: { href: string; children: React.ReactNode }) => (
|
|
135
|
-
<a href={href} className="rounded-full border border-white/20 px-6 py-3 font-medium text-white/80 hover:border-white/40">{children}</a>
|
|
136
|
-
);
|
|
137
|
-
```
|
|
142
|
+
Notes on how to use the `ui/` set so pages feel like this theme — which variants to prefer, what to avoid:
|
|
138
143
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
<div className="mt-2 text-white/60">{children}</div>
|
|
146
|
-
</div>
|
|
147
|
-
);
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### Footer
|
|
151
|
-
|
|
152
|
-
```tsx
|
|
153
|
-
const Footer = ({ left, right }: { left: string; right: string }) => (
|
|
154
|
-
<footer className="border-t border-white/10">
|
|
155
|
-
<div className="mx-auto flex max-w-6xl items-center justify-between px-6 py-8 text-sm text-white/40">
|
|
156
|
-
<span>{left}</span>
|
|
157
|
-
<span>{right}</span>
|
|
158
|
-
</div>
|
|
159
|
-
</footer>
|
|
160
|
-
);
|
|
161
|
-
```
|
|
144
|
+
- Buttons: primary CTA `<Button size="lg">`; secondary `<Button size="lg" variant="outline">`; pill shape via `className="rounded-full"` (or not).
|
|
145
|
+
- Cards: `<Card>` with `border-border`, no shadow | `shadow-sm`.
|
|
146
|
+
- Nav: `<NavigationMenu>` on desktop, `<Sheet>` on mobile; sticky with `bg-background/90 backdrop-blur`.
|
|
147
|
+
- Data: `<Table>` + `<Badge>` for status; charts use `--chart-*` in order.
|
|
148
|
+
- Feedback: `<Alert>`, `sonner` toasts.
|
|
149
|
+
- Avoid: gradients | shadows | more than one accent | … (whatever the theme forbids).
|
|
162
150
|
|
|
163
151
|
## Aesthetic
|
|
164
152
|
|
|
165
|
-
One paragraph. What it feels like, the references it draws on, what to avoid
|
|
153
|
+
One paragraph. What it feels like, the references it draws on, what to avoid. Commit to a single direction.
|
|
166
154
|
|
|
167
155
|
## Example usage
|
|
168
156
|
|
|
169
157
|
```tsx
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
</Hero>
|
|
176
|
-
{/* … */}
|
|
177
|
-
<Footer left="© 2026 Meridian" right="Built with open-pages" />
|
|
158
|
+
export const meta: PageMeta = { title: '…', theme: '<id>', createdAt: '…' };
|
|
159
|
+
|
|
160
|
+
<main className="min-h-screen bg-background text-foreground antialiased">
|
|
161
|
+
<header className="mx-auto flex max-w-6xl items-center justify-between px-6 py-6">…<Button>Get started</Button></header>
|
|
162
|
+
<section className="mx-auto max-w-6xl px-6 py-20">…</section>
|
|
178
163
|
</main>
|
|
179
164
|
```
|
|
180
165
|
````
|
|
181
166
|
|
|
182
|
-
|
|
167
|
+
The markdown never contains color values that are not also in the CSS, and never contains paste-ready components with raw colors — pages compose `ui/` and the tokens do the rest.
|
|
168
|
+
|
|
169
|
+
## Step 6 — Write `themes/<id>.demo.tsx`
|
|
183
170
|
|
|
184
|
-
The demo is a normal page module — same shape as `pages/<id>/index.tsx`,
|
|
171
|
+
The demo is a normal page module — same shape as `pages/<id>/index.tsx`, sitting under `themes/` so the runtime knows it's preview-only.
|
|
185
172
|
|
|
186
173
|
Contract:
|
|
187
174
|
|
|
188
|
-
- `import type { PageMeta } from '@autono/open-pages'
|
|
189
|
-
- **One default-exported component** — a single scrolling page that exercises the
|
|
190
|
-
-
|
|
191
|
-
-
|
|
192
|
-
- Content should be plausible and realistic, not lorem ipsum. Self-contained: no `@/` imports, no page-local assets; if the theme names a Google Font, render the `<link>` tag in the demo too.
|
|
175
|
+
- `import type { PageMeta } from '@autono/open-pages';`, `@/ui/*` imports, React hooks as needed. No `meta.theme` (the runtime injects `<id>.css` for demos).
|
|
176
|
+
- **One default-exported component** — a single scrolling page that exercises the tokens on real components: a header with `<Button>`s, a hero, a `<Card>` grid, a `<Tabs>` or `<Accordion>`, a `<Table>` with `<Badge>` status, an `<Input>` + `<Button>` form row, and a footer. Include one dark section (`<div className="dark bg-background text-foreground">`) if the theme is light-first, or one light section if dark-first, so both blocks of the CSS are visible.
|
|
177
|
+
- Root element: `min-h-screen bg-background text-foreground` (with `dark` if the theme is dark by default). Everything token-styled — the demo is the proof that pages need no raw colors.
|
|
178
|
+
- Realistic content, not lorem ipsum. Must look right at Mobile (390px) as well as Desktop. Self-contained: no page-local assets.
|
|
193
179
|
|
|
194
|
-
## Step
|
|
180
|
+
## Step 7 — Self-review
|
|
195
181
|
|
|
196
|
-
- [ ]
|
|
197
|
-
- [ ]
|
|
198
|
-
- [ ]
|
|
199
|
-
- [ ]
|
|
200
|
-
- [ ]
|
|
201
|
-
- [ ]
|
|
202
|
-
- [ ]
|
|
203
|
-
- [ ] Demo `.tsx` default-exports one component and inlines the same fixed components as the markdown; contrast holds; nothing overflows on mobile.
|
|
182
|
+
- [ ] `themes/<id>.css` overrides every shadcn token in both `:root` and `.dark`, in OKLCH, with only those two selectors (plus an optional font `@import`).
|
|
183
|
+
- [ ] Every `*-foreground` passes contrast on its surface; `--muted-foreground` is readable on `--background`.
|
|
184
|
+
- [ ] Frontmatter in the `.md` has `name` and `description` only (the runtime reads nothing else).
|
|
185
|
+
- [ ] Typography names only fonts the CSS loads (or the system stack).
|
|
186
|
+
- [ ] "Components in this theme" gives variant guidance for buttons, cards, nav, data, feedback.
|
|
187
|
+
- [ ] Demo `.tsx` default-exports one component, imports only `@/ui/*`, uses semantic tokens only, shows both modes, nothing overflows on mobile.
|
|
188
|
+
- [ ] All three files written with the same stem. No page changes, no `ui/` changes, no `styles/globals.css` changes.
|
|
204
189
|
|
|
205
|
-
## Step
|
|
190
|
+
## Step 8 — Hand off
|
|
206
191
|
|
|
207
192
|
Tell the user:
|
|
208
193
|
|
|
209
|
-
- The theme id and the
|
|
194
|
+
- The theme id and the three file paths.
|
|
210
195
|
- That the Themes panel in the workspace (`http://localhost:5173/themes`) previews the demo live, and `/create-page` will list the theme as a picker option on its next run.
|
|
211
|
-
-
|
|
196
|
+
- That any existing page can adopt it by setting `meta.theme: '<id>'` — no other change.
|
|
197
|
+
- A one-line summary of the look (accent, mode, radius, fonts).
|
|
212
198
|
|
|
213
199
|
Do not run the dev server. Do not modify real pages — the demo `.tsx` is the demonstration.
|
|
214
200
|
|
|
215
201
|
## Anti-patterns
|
|
216
202
|
|
|
217
|
-
- ❌
|
|
218
|
-
- ❌
|
|
219
|
-
- ❌
|
|
220
|
-
- ❌
|
|
221
|
-
- ❌
|
|
222
|
-
- ❌
|
|
223
|
-
- ❌
|
|
203
|
+
- ❌ Pasting token values into pages, or theme markdown full of `bg-[#hex]` snippets. Tokens live in the CSS; pages stay semantic.
|
|
204
|
+
- ❌ `@theme inline`, `@import "tailwindcss"`, `@source`, or selectors other than `:root`/`.dark` in `themes/<id>.css`.
|
|
205
|
+
- ❌ Editing `styles/globals.css` or running `npx shadcn apply` against the workspace — that silently rethemes every page.
|
|
206
|
+
- ❌ Producing one or two of the three files. A theme is the **bundle** — `.md`, `.css`, `.demo.tsx`, every time.
|
|
207
|
+
- ❌ A demo with raw colors or hand-rolled buttons — it must prove the tokens carry the look through `ui/`.
|
|
208
|
+
- ❌ Naming font families the CSS never loads.
|
|
209
|
+
- ❌ Inventing values when the user supplied a preset, images, or an existing page. Extract, don't fabricate.
|
|
210
|
+
- ❌ Editing `pages/`, `ui/`, `packages/`, `package.json`, or `open-pages.config.ts`.
|
|
@@ -49,7 +49,7 @@ Path is relative to the project root (the user's `cwd`, the directory that conta
|
|
|
49
49
|
- `view` — `"pages"` when the user is viewing the page, `"assets"` when they are browsing that page's files in the asset manager rather than the page itself.
|
|
50
50
|
- `selection` — `null` if nothing is selected. Otherwise, the JSX element the user picked in the inspector:
|
|
51
51
|
- `line` (1-indexed) and `column` (0-indexed) point to the JSX opening tag in the page source. This is the canonical handle — match against the source line.
|
|
52
|
-
- `tagName` is the rendered HTML tag, lowercased (`"h1"`, `"div"`, `"button"`).
|
|
52
|
+
- `tagName` is the rendered HTML tag, lowercased (`"h1"`, `"div"`, `"button"`). The source line it points at may be a shadcn component rather than that tag — a `"button"` selection usually lands on a `<Button>` line in the page, because `ui/` components spread the inspector tag onto their root. Edit the page line; never follow it into `ui/*.tsx`.
|
|
53
53
|
- `text` is a trimmed text snippet (≤120 chars) of the element's content — a sanity check that you're looking at the right node.
|
|
54
54
|
- Selection auto-clears whenever the user navigates to a different page or clears it in the viewer. HTML pages never produce a selection.
|
|
55
55
|
- `updatedAt` — ISO timestamp of the last navigation or selection change. Use it to detect staleness.
|