synthesisui 0.1.21 → 0.1.23
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/dist/commands/init.js +2 -2
- package/dist/commands/template.js +42 -0
- package/dist/guide.js +29 -3
- package/dist/index.js +17 -11
- package/dist/registry.js +3 -3
- package/package.json +1 -1
package/dist/commands/init.js
CHANGED
|
@@ -2,7 +2,7 @@ import { DEFAULT_CONFIG, writeProjectConfig } from "../config.js";
|
|
|
2
2
|
import { add } from "./add.js";
|
|
3
3
|
/**
|
|
4
4
|
* Bootstraps a project for SynthesisUI: writes `_synthesisui/config.json`
|
|
5
|
-
* (where `
|
|
5
|
+
* (where `template` materializes pages, where components live, which framework to
|
|
6
6
|
* target) and - with `--ds <slug>` - immediately brings that system in, so the
|
|
7
7
|
* project lands with tokens, philosophy, rules and a CLAUDE.md in one step.
|
|
8
8
|
* Committable; safe to re-run.
|
|
@@ -30,5 +30,5 @@ export async function init(opts) {
|
|
|
30
30
|
console.log("");
|
|
31
31
|
console.log("Next steps:");
|
|
32
32
|
console.log(" • synthesisui add <slug> bring a design system in");
|
|
33
|
-
console.log(" • synthesisui
|
|
33
|
+
console.log(" • synthesisui template <slug> <name> materialize a full page");
|
|
34
34
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { readProjectConfig, resolveRegistry } from "../config.js";
|
|
4
|
+
import { fetchTemplate } from "../registry.js";
|
|
5
|
+
/**
|
|
6
|
+
* Materializes a whole page from a DS template into the project (hybrid
|
|
7
|
+
* codegen-first): the server codegens deterministic files, we write them, and
|
|
8
|
+
* the agent refines them in place. The page uses the DS's `.ds-*` classes +
|
|
9
|
+
* path classes; the co-located CSS (Next target) carries the responsive media
|
|
10
|
+
* queries + the CSS-only hamburger, so it re-vests once `tokens.css` is in.
|
|
11
|
+
*/
|
|
12
|
+
export async function template(slug, name, opts) {
|
|
13
|
+
const base = resolveRegistry(opts.registry);
|
|
14
|
+
const root = opts.dir ?? process.cwd();
|
|
15
|
+
const config = await readProjectConfig(root);
|
|
16
|
+
const target = opts.target === "general" || opts.target === "next"
|
|
17
|
+
? opts.target
|
|
18
|
+
: config.target;
|
|
19
|
+
console.log(`→ generating "${name}" from "${slug}" (${target}) …`);
|
|
20
|
+
const generated = await fetchTemplate(base, slug, name, target, opts.version);
|
|
21
|
+
// --out targets the page (1st file); sibling files (e.g. the CSS) land in the
|
|
22
|
+
// same directory. Without --out, everything goes under <pagesDir>.
|
|
23
|
+
const [pageFile, ...siblings] = generated.files;
|
|
24
|
+
const pageRel = opts.out ?? join(config.pagesDir, pageFile.filename);
|
|
25
|
+
const pageDir = dirname(join(root, pageRel));
|
|
26
|
+
await mkdir(pageDir, { recursive: true });
|
|
27
|
+
await writeFile(join(root, pageRel), pageFile.code, "utf8");
|
|
28
|
+
console.log(`✓ wrote ${pageRel} (${slug} v${generated.version})`);
|
|
29
|
+
for (const f of siblings) {
|
|
30
|
+
const rel = opts.out
|
|
31
|
+
? join(dirname(pageRel), f.filename)
|
|
32
|
+
: join(config.pagesDir, f.filename);
|
|
33
|
+
await writeFile(join(root, rel), f.code, "utf8");
|
|
34
|
+
console.log(`✓ wrote ${rel}`);
|
|
35
|
+
}
|
|
36
|
+
console.log("");
|
|
37
|
+
console.log("Next steps:");
|
|
38
|
+
console.log(` • ensure the DS is installed: synthesisui add ${slug} (provides tokens.css)`);
|
|
39
|
+
console.log(` • @import "_synthesisui/ds/${slug}/tokens.css" in your global CSS`);
|
|
40
|
+
console.log(" • refine the file: wire real data, split into components, swap placeholders");
|
|
41
|
+
console.log(` • keep the data-ds="${slug}" wrapper and the ds-* / layout classes (stays on-system)`);
|
|
42
|
+
}
|
package/dist/guide.js
CHANGED
|
@@ -84,6 +84,32 @@ its typographic identity. Load them once (any one approach):
|
|
|
84
84
|
- **Next.js** (\`next/font/google\`), **Fontsource**, or self-hosted \`@font-face\` work too - just
|
|
85
85
|
register the families above. If a family isn't on Google Fonts, self-host it.
|
|
86
86
|
|
|
87
|
+
---
|
|
88
|
+
`
|
|
89
|
+
: "";
|
|
90
|
+
// Libraries the system references but doesn't bundle - the agent should
|
|
91
|
+
// install them when it actually renders icons/charts (INS-19).
|
|
92
|
+
const iconLibraries = doc.icons?.libraries ?? [];
|
|
93
|
+
const hasCharts = !!doc.charts && Object.keys(doc.charts).length > 0;
|
|
94
|
+
const depLines = [
|
|
95
|
+
iconLibraries.includes("lucide")
|
|
96
|
+
? "- **Icons** - components reference Lucide icon names. Run `npm i lucide-react` " +
|
|
97
|
+
"(or swap in your own icon set) to render them."
|
|
98
|
+
: "",
|
|
99
|
+
hasCharts
|
|
100
|
+
? "- **Charts** - charts are themed through your series tokens, but you bring the " +
|
|
101
|
+
"renderer. Run `npm i recharts` (the gallery uses Recharts)."
|
|
102
|
+
: "",
|
|
103
|
+
].filter(Boolean);
|
|
104
|
+
const depsSection = depLines.length
|
|
105
|
+
? `
|
|
106
|
+
## Dependencies
|
|
107
|
+
|
|
108
|
+
Beyond loading the fonts above, the system references libraries it doesn't bundle - install them
|
|
109
|
+
when you actually render that UI:
|
|
110
|
+
|
|
111
|
+
${depLines.join("\n")}
|
|
112
|
+
|
|
87
113
|
---
|
|
88
114
|
`
|
|
89
115
|
: "";
|
|
@@ -109,8 +135,8 @@ This system ships whole-page templates: ${layoutNames.map((n) => `\`${n}\``).joi
|
|
|
109
135
|
|
|
110
136
|
Materialize one as a real file:
|
|
111
137
|
\`\`\`bash
|
|
112
|
-
synthesisui
|
|
113
|
-
synthesisui
|
|
138
|
+
synthesisui template ${slug} ${layoutNames[0]} # Next .tsx + .css (default)
|
|
139
|
+
synthesisui template ${slug} ${layoutNames[0]} --target general # single self-contained HTML
|
|
114
140
|
\`\`\`
|
|
115
141
|
It writes a **deterministic scaffold**: the page uses this DS's \`.ds-*\` recipe classes + layout
|
|
116
142
|
path-classes, paired with a co-located scoped CSS (Next target) that carries the **responsive** media
|
|
@@ -186,7 +212,7 @@ ${hasAlt
|
|
|
186
212
|
root.toggleAttribute("data-scheme"); // present = ${altScheme}, absent = ${meta.scheme}
|
|
187
213
|
\`\`\`
|
|
188
214
|
`
|
|
189
|
-
: ""}${fontsSection}${hasTailwind
|
|
215
|
+
: ""}${fontsSection}${depsSection}${hasTailwind
|
|
190
216
|
? `
|
|
191
217
|
## Styling with Tailwind v4 (preferred in this project)
|
|
192
218
|
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { generate } from "./commands/generate.js";
|
|
|
5
5
|
import { init } from "./commands/init.js";
|
|
6
6
|
import { list } from "./commands/list.js";
|
|
7
7
|
import { login } from "./commands/login.js";
|
|
8
|
-
import {
|
|
8
|
+
import { template } from "./commands/template.js";
|
|
9
9
|
import { use } from "./commands/use.js";
|
|
10
10
|
import { RegistryError } from "./registry.js";
|
|
11
11
|
const HELP = `synthesisui - bring SynthesisUI design systems into your project
|
|
@@ -15,7 +15,7 @@ Usage:
|
|
|
15
15
|
synthesisui init [options] write _synthesisui/config.json (target, dirs); --ds to bring one in
|
|
16
16
|
synthesisui list [options] list the published design systems
|
|
17
17
|
synthesisui add <slug> [options] materialize a DS into _synthesisui/ds/<slug>/
|
|
18
|
-
synthesisui
|
|
18
|
+
synthesisui template <slug> <name> materialize a whole page from a DS template
|
|
19
19
|
synthesisui use <slug> "<intent>" print a ready-to-paste agent prompt to build/modify on-system
|
|
20
20
|
synthesisui advise "<value prop>" engagement-pattern proposals for this project (login required)
|
|
21
21
|
synthesisui generate "<desc>" generate a token-only component recipe for your DS (login required)
|
|
@@ -26,10 +26,10 @@ Options:
|
|
|
26
26
|
--version <n> install a specific version (default: latest)
|
|
27
27
|
--ds <slug> init: bring this DS in right away · generate: target DS (default: installed)
|
|
28
28
|
--name <name> preferred component name for generate
|
|
29
|
-
--target <t>
|
|
29
|
+
--target <t> template/init target: next | general (default: next)
|
|
30
30
|
--pages-dir <dir> init: folder for generated pages (default: app)
|
|
31
31
|
--components-dir <dir> init: folder where components live (default: components)
|
|
32
|
-
--out <path> output path for the generated
|
|
32
|
+
--out <path> output path for the generated template (default: <pagesDir>/<file>)
|
|
33
33
|
-h, --help this help
|
|
34
34
|
|
|
35
35
|
Examples:
|
|
@@ -39,8 +39,8 @@ Examples:
|
|
|
39
39
|
synthesisui list
|
|
40
40
|
synthesisui add halogen
|
|
41
41
|
synthesisui add halogen --version 3
|
|
42
|
-
synthesisui
|
|
43
|
-
synthesisui
|
|
42
|
+
synthesisui template halogen dashboard-sidebar
|
|
43
|
+
synthesisui template halogen landing --out app/page.tsx
|
|
44
44
|
synthesisui use halogen "a pricing section with three tiers and a highlighted plan"
|
|
45
45
|
synthesisui use halogen "make the card shadow softer in components/StatCard.tsx"
|
|
46
46
|
synthesisui advise "habit-building app for tracking personal finances"
|
|
@@ -125,11 +125,17 @@ async function main() {
|
|
|
125
125
|
await init({ dir, registry, target, pagesDir, componentsDir, ds });
|
|
126
126
|
break;
|
|
127
127
|
}
|
|
128
|
-
|
|
128
|
+
// `page` is the legacy alias (renamed to `template`); it still works so
|
|
129
|
+
// GUIDE.md files materialized before the rename don't break.
|
|
130
|
+
case "page":
|
|
131
|
+
case "template": {
|
|
132
|
+
if (command === "page") {
|
|
133
|
+
console.error("note: `synthesisui page` was renamed to `synthesisui template` - the old name still works for now.");
|
|
134
|
+
}
|
|
129
135
|
const slug = args[0];
|
|
130
|
-
const
|
|
131
|
-
if (!slug || !
|
|
132
|
-
console.error("error: provide slug and template - `synthesisui
|
|
136
|
+
const name = args[1];
|
|
137
|
+
if (!slug || !name) {
|
|
138
|
+
console.error("error: provide slug and template name - `synthesisui template <slug> <name>`");
|
|
133
139
|
process.exitCode = 1;
|
|
134
140
|
return;
|
|
135
141
|
}
|
|
@@ -144,7 +150,7 @@ async function main() {
|
|
|
144
150
|
}
|
|
145
151
|
const target = typeof flags.target === "string" ? flags.target : undefined;
|
|
146
152
|
const out = typeof flags.out === "string" ? flags.out : undefined;
|
|
147
|
-
await
|
|
153
|
+
await template(slug, name, { registry, dir, out, target, version });
|
|
148
154
|
break;
|
|
149
155
|
}
|
|
150
156
|
case "use": {
|
package/dist/registry.js
CHANGED
|
@@ -43,12 +43,12 @@ export async function fetchDesignSystem(base, slug, version) {
|
|
|
43
43
|
return (await res.json());
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* Fetches a whole page generated from a DS template (`?
|
|
46
|
+
* Fetches a whole page generated from a DS template (`?template=&target=`). The
|
|
47
47
|
* server codegens it from `document.layouts[<template>]`; the CLI just writes it.
|
|
48
48
|
*/
|
|
49
|
-
export async function
|
|
49
|
+
export async function fetchTemplate(base, slug, template, target, version) {
|
|
50
50
|
const url = new URL(`${base}/api/registry/ds/${encodeURIComponent(slug)}`);
|
|
51
|
-
url.searchParams.set("
|
|
51
|
+
url.searchParams.set("template", template);
|
|
52
52
|
url.searchParams.set("target", target);
|
|
53
53
|
if (version != null)
|
|
54
54
|
url.searchParams.set("version", String(version));
|