synthesisui 0.1.14 → 0.1.15
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/claude-md.js +4 -4
- package/dist/commands/add.js +4 -4
- package/dist/commands/advise.js +2 -2
- package/dist/commands/generate.js +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/page.js +20 -10
- package/dist/config.js +1 -1
- package/dist/guide.js +39 -37
- package/dist/index.js +7 -7
- package/dist/repo-context.js +3 -3
- package/dist/types.js +1 -1
- package/package.json +1 -1
package/dist/claude-md.js
CHANGED
|
@@ -21,7 +21,7 @@ async function readInstalled(projectRoot) {
|
|
|
21
21
|
locks.push({ slug: lock.slug, name: lock.name, version: lock.version });
|
|
22
22
|
}
|
|
23
23
|
catch {
|
|
24
|
-
// folder without a valid .lock
|
|
24
|
+
// folder without a valid .lock - ignore
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
return locks;
|
|
@@ -31,7 +31,7 @@ function renderRegion(installed) {
|
|
|
31
31
|
return `${START}\n${END}`;
|
|
32
32
|
}
|
|
33
33
|
const lines = installed
|
|
34
|
-
.map((ds) => `- **${ds.name}** (\`${ds.slug}\`, v${ds.version})
|
|
34
|
+
.map((ds) => `- **${ds.name}** (\`${ds.slug}\`, v${ds.version}) - guide: \`_synthesisui/ds/${ds.slug}/v${ds.version}/GUIDE.md\``)
|
|
35
35
|
.join("\n");
|
|
36
36
|
const body = `## Design Systems (via SynthesisUI)
|
|
37
37
|
|
|
@@ -39,12 +39,12 @@ This project uses design system(s) brought in by the \`synthesisui\` CLI. **When
|
|
|
39
39
|
components, read the system's GUIDE.md and follow it:** use only semantic tokens
|
|
40
40
|
(\`var(--ds-color-semantic-*)\`, \`--ds-spacing-*\`, etc.), scope the UI with \`data-ds="<slug>"\`,
|
|
41
41
|
and reuse the \`.ds-*\` classes. Do not use raw values outside the system's scale. **To review a
|
|
42
|
-
component, create an isolated sample page (e.g. \`app/synthesisui-samples/<component>/\`)
|
|
42
|
+
component, create an isolated sample page (e.g. \`app/synthesisui-samples/<component>/\`) - do not
|
|
43
43
|
apply it to real production pages unless asked.**
|
|
44
44
|
|
|
45
45
|
${lines}
|
|
46
46
|
|
|
47
|
-
_Block managed by the CLI
|
|
47
|
+
_Block managed by the CLI - do not edit by hand; run \`synthesisui add <slug>\` to update._`;
|
|
48
48
|
return `${START}\n${body}\n${END}`;
|
|
49
49
|
}
|
|
50
50
|
/**
|
package/dist/commands/add.js
CHANGED
|
@@ -41,7 +41,7 @@ export async function add(slug, opts) {
|
|
|
41
41
|
// so the consumer's @import path never changes across updates
|
|
42
42
|
const cssArtifacts = Object.keys(payload.artifacts).filter((f) => f.endsWith(".css"));
|
|
43
43
|
for (const filename of cssArtifacts) {
|
|
44
|
-
await writeFile(join(slugDir, filename), `/* Active version (v${payload.version}). Managed by synthesisui
|
|
44
|
+
await writeFile(join(slugDir, filename), `/* Active version (v${payload.version}). Managed by synthesisui - do not edit. */\n` +
|
|
45
45
|
`@import "./v${payload.version}/${filename}";\n`, "utf8");
|
|
46
46
|
}
|
|
47
47
|
// 5. root pointer
|
|
@@ -57,8 +57,8 @@ export async function add(slug, opts) {
|
|
|
57
57
|
// highest authority; the GUIDE tells the agent to read it first)
|
|
58
58
|
const rules = payload.rules ?? [];
|
|
59
59
|
if (rules.length > 0) {
|
|
60
|
-
const body = `# ${payload.name}
|
|
61
|
-
"> Accumulated rules for this design system. **Max authority
|
|
60
|
+
const body = `# ${payload.name} - Rules\n\n` +
|
|
61
|
+
"> Accumulated rules for this design system. **Max authority - follow these first.**\n" +
|
|
62
62
|
`> Managed by synthesisui (edit in the studio). ${rules.length} rule(s).\n\n${rules
|
|
63
63
|
.map((r) => `- ${r}`)
|
|
64
64
|
.join("\n")}\n`;
|
|
@@ -72,7 +72,7 @@ export async function add(slug, opts) {
|
|
|
72
72
|
console.log(`✓ ${payload.name} v${v} installed → _synthesisui/ds/${payload.slug}/`);
|
|
73
73
|
}
|
|
74
74
|
else if (prev.version === v) {
|
|
75
|
-
console.log(`✓ ${payload.name} v${v} already installed${opts.version == null ? " (latest)" : ""}
|
|
75
|
+
console.log(`✓ ${payload.name} v${v} already installed${opts.version == null ? " (latest)" : ""} - refreshed`);
|
|
76
76
|
}
|
|
77
77
|
else if (v > prev.version) {
|
|
78
78
|
console.log(`↑ ${payload.name} v${prev.version} → v${v} (kept v${prev.version}/ for rollback)`);
|
package/dist/commands/advise.js
CHANGED
|
@@ -4,7 +4,7 @@ import { buildRepoContext } from "../repo-context.js";
|
|
|
4
4
|
/**
|
|
5
5
|
* Asks the hosted advisor for engagement-pattern proposals, grounded in THIS
|
|
6
6
|
* project (the CLI gathers a compact repo summary) + the value proposition you
|
|
7
|
-
* pass. The advisor proposes only
|
|
7
|
+
* pass. The advisor proposes only - it changes nothing in your project.
|
|
8
8
|
*/
|
|
9
9
|
export async function advise(valueProp, opts) {
|
|
10
10
|
const base = resolveRegistry(opts.registry);
|
|
@@ -26,6 +26,6 @@ export async function advise(valueProp, opts) {
|
|
|
26
26
|
}
|
|
27
27
|
console.log("");
|
|
28
28
|
});
|
|
29
|
-
console.log(`(${res.usage.inputTokens} in / ${res.usage.outputTokens} out tokens
|
|
29
|
+
console.log(`(${res.usage.inputTokens} in / ${res.usage.outputTokens} out tokens - ` +
|
|
30
30
|
`proposals only; nothing in your project was changed)`);
|
|
31
31
|
}
|
|
@@ -49,5 +49,5 @@ export async function generate(description, opts) {
|
|
|
49
49
|
console.log("Use it:");
|
|
50
50
|
console.log(` • @import "_synthesisui/ds/${slug}/generated/${res.name}.css" in your CSS`);
|
|
51
51
|
console.log(` • <div data-ds="${slug}"><div class="ds-${res.name}">…</div></div>`);
|
|
52
|
-
console.log(` (${res.usage.inputTokens} in / ${res.usage.outputTokens} out tokens
|
|
52
|
+
console.log(` (${res.usage.inputTokens} in / ${res.usage.outputTokens} out tokens - recipe is additive; nothing else changed)`);
|
|
53
53
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_CONFIG, writeProjectConfig } from "../config.js";
|
|
2
2
|
/**
|
|
3
|
-
* Writes `_synthesisui/config.json`
|
|
3
|
+
* Writes `_synthesisui/config.json` - where `synthesisui page` materializes
|
|
4
4
|
* pages and which framework to target. Committable; safe to re-run.
|
|
5
5
|
*/
|
|
6
6
|
export async function init(opts) {
|
package/dist/commands/login.js
CHANGED
|
@@ -20,7 +20,7 @@ function openBrowser(url) {
|
|
|
20
20
|
child.unref();
|
|
21
21
|
}
|
|
22
22
|
catch {
|
|
23
|
-
// no browser available
|
|
23
|
+
// no browser available - the user opens it manually
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
/** Device authorization (RFC 8628): opens the browser, waits for approval. */
|
package/dist/commands/page.js
CHANGED
|
@@ -4,9 +4,10 @@ import { readProjectConfig, resolveRegistry } from "../config.js";
|
|
|
4
4
|
import { fetchPage } from "../registry.js";
|
|
5
5
|
/**
|
|
6
6
|
* Materializes a whole page from a DS template into the project (hybrid
|
|
7
|
-
* codegen-first): the server codegens
|
|
8
|
-
* the agent refines
|
|
9
|
-
*
|
|
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.
|
|
10
11
|
*/
|
|
11
12
|
export async function page(slug, template, opts) {
|
|
12
13
|
const base = resolveRegistry(opts.registry);
|
|
@@ -17,16 +18,25 @@ export async function page(slug, template, opts) {
|
|
|
17
18
|
: config.target;
|
|
18
19
|
console.log(`→ generating "${template}" from "${slug}" (${target}) …`);
|
|
19
20
|
const generated = await fetchPage(base, slug, template, target, opts.version);
|
|
20
|
-
// --out
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
+
}
|
|
26
36
|
console.log("");
|
|
27
37
|
console.log("Next steps:");
|
|
28
38
|
console.log(` • ensure the DS is installed: synthesisui add ${slug} (provides tokens.css)`);
|
|
29
39
|
console.log(` • @import "_synthesisui/ds/${slug}/tokens.css" in your global CSS`);
|
|
30
40
|
console.log(" • refine the file: wire real data, split into components, swap placeholders");
|
|
31
|
-
console.log(` • keep the data-ds="${slug}" wrapper and the ds-* classes (stays on-system)`);
|
|
41
|
+
console.log(` • keep the data-ds="${slug}" wrapper and the ds-* / layout classes (stays on-system)`);
|
|
32
42
|
}
|
package/dist/config.js
CHANGED
|
@@ -11,7 +11,7 @@ export function resolveRegistry(flag) {
|
|
|
11
11
|
const base = flag || process.env.SYNTHESISUI_REGISTRY_URL || DEFAULT_REGISTRY;
|
|
12
12
|
return base.replace(/\/+$/, ""); // no trailing slash
|
|
13
13
|
}
|
|
14
|
-
/** Where the device-flow token lives
|
|
14
|
+
/** Where the device-flow token lives - per machine, in the home dir. */
|
|
15
15
|
export const credentialsPath = join(homedir(), ".synthesisui", "credentials.json");
|
|
16
16
|
/**
|
|
17
17
|
* Reads the saved token, if any. Optional for now (open gate); the device-flow
|
package/dist/guide.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const kebab = (v) => v.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
2
2
|
const list = (items) => items.length ? items.map((i) => `\`${i}\``).join(", ") : "_(none)_";
|
|
3
3
|
const dataAttrs = (variants) => Object.entries(variants).map(([axis, opts]) => `data-${kebab(axis)}="${Object.keys(opts).join("|")}"`);
|
|
4
|
-
// Famílias genéricas do CSS
|
|
4
|
+
// Famílias genéricas do CSS - fallbacks, não webfonts a carregar.
|
|
5
5
|
const GENERIC_FAMILIES = new Set([
|
|
6
6
|
"sans-serif",
|
|
7
7
|
"serif",
|
|
@@ -35,7 +35,7 @@ function customFontFamilies(families) {
|
|
|
35
35
|
function componentEntry(cname, recipe) {
|
|
36
36
|
const cls = `.ds-${kebab(cname)}`;
|
|
37
37
|
const axes = dataAttrs(recipe.variants).map((a) => `\`${a}\``);
|
|
38
|
-
const variantsText = axes.length ? `
|
|
38
|
+
const variantsText = axes.length ? ` - variants: ${axes.join(", ")}` : "";
|
|
39
39
|
const states = Object.keys(recipe.states ?? {});
|
|
40
40
|
const statesText = states.length ? `\n states: ${list(states)}` : "";
|
|
41
41
|
const partEntries = Object.entries(recipe.parts ?? {});
|
|
@@ -51,7 +51,7 @@ function componentEntry(cname, recipe) {
|
|
|
51
51
|
return `- **${cname}** (\`${cls}\`)${variantsText}\n ${recipe.description}${partsText}${statesText}`;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* Builds GUIDE.md
|
|
54
|
+
* Builds GUIDE.md - instructions *for the agent* on how to build components
|
|
55
55
|
* that follow the design system. This is the piece that makes "I create the
|
|
56
56
|
* components with claude-code" work: the tokens alone are not enough, the agent
|
|
57
57
|
* needs the rules and the real vocabulary (semantic token names and recipes).
|
|
@@ -71,17 +71,17 @@ export function buildGuide(payload) {
|
|
|
71
71
|
? `
|
|
72
72
|
## Fonts
|
|
73
73
|
|
|
74
|
-
This system's type relies on ${list(fontFamilies)}
|
|
74
|
+
This system's type relies on ${list(fontFamilies)} - **the DS ships token names, not the
|
|
75
75
|
fonts themselves.** If you don't load them they fall back to a generic family and the system loses
|
|
76
76
|
its typographic identity. Load them once (any one approach):
|
|
77
77
|
|
|
78
|
-
- **Google Fonts**
|
|
78
|
+
- **Google Fonts** - drop in your \`<head>\` (or root layout):
|
|
79
79
|
\`\`\`html
|
|
80
80
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
81
81
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
82
82
|
<link rel="stylesheet" href="${fontsHref}" />
|
|
83
83
|
\`\`\`
|
|
84
|
-
- **Next.js** (\`next/font/google\`), **Fontsource**, or self-hosted \`@font-face\` work too
|
|
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
87
|
---
|
|
@@ -94,7 +94,7 @@ its typographic identity. Load them once (any one approach):
|
|
|
94
94
|
const hasTailwind = "theme.css" in payload.artifacts;
|
|
95
95
|
const hasParts = Object.values(components).some((r) => r.parts && Object.keys(r.parts).length > 0);
|
|
96
96
|
const componentLines = Object.entries(components).map(([cname, recipe]) => componentEntry(cname, recipe));
|
|
97
|
-
// Engagement blocks (gamification library)
|
|
97
|
+
// Engagement blocks (gamification library) - category apart from core components.
|
|
98
98
|
const blockEntries = Object.entries(doc.blocks ?? {});
|
|
99
99
|
const blockLines = blockEntries.map(([bname, recipe]) => componentEntry(bname, recipe));
|
|
100
100
|
const artifactList = Object.keys(payload.artifacts)
|
|
@@ -109,13 +109,15 @@ This system ships whole-page templates: ${layoutNames.map((n) => `\`${n}\``).joi
|
|
|
109
109
|
|
|
110
110
|
Materialize one as a real file:
|
|
111
111
|
\`\`\`bash
|
|
112
|
-
synthesisui page ${slug} ${layoutNames[0]} # Next .tsx (default)
|
|
113
|
-
synthesisui page ${slug} ${layoutNames[0]} --target general #
|
|
112
|
+
synthesisui page ${slug} ${layoutNames[0]} # Next .tsx + .css (default)
|
|
113
|
+
synthesisui page ${slug} ${layoutNames[0]} --target general # single self-contained HTML
|
|
114
114
|
\`\`\`
|
|
115
|
-
It writes a **deterministic scaffold
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
It writes a **deterministic scaffold**: the page uses this DS's \`.ds-*\` recipe classes + layout
|
|
116
|
+
path-classes, paired with a co-located scoped CSS (Next target) that carries the **responsive** media
|
|
117
|
+
queries and the **CSS-only hamburger** - so the page is mobile-ready out of the box. **Refine it in
|
|
118
|
+
place** - wire real data, split into components, swap the chart/icon/media placeholders - but keep the
|
|
119
|
+
\`data-ds="${slug}"\` wrapper and the \`.ds-*\` / layout classes so it stays on-system. Run
|
|
120
|
+
\`synthesisui init\` once to set the target (next/general) and the output folder.
|
|
119
121
|
|
|
120
122
|
---
|
|
121
123
|
`
|
|
@@ -123,7 +125,7 @@ to set the target (next/general) and the output folder.
|
|
|
123
125
|
const hasRules = (payload.rules?.length ?? 0) > 0;
|
|
124
126
|
const rulesNote = hasRules
|
|
125
127
|
? `
|
|
126
|
-
## Rules
|
|
128
|
+
## Rules - highest authority
|
|
127
129
|
|
|
128
130
|
**Read \`_synthesisui/ds/${slug}/rules.md\` FIRST and obey it above everything else in this guide.**
|
|
129
131
|
It carries this system's accumulated, project-specific rules; on any conflict they win over the
|
|
@@ -134,7 +136,7 @@ generic guidance below.
|
|
|
134
136
|
: "";
|
|
135
137
|
return `# Design System: ${name}
|
|
136
138
|
|
|
137
|
-
> Generated by \`synthesisui add ${slug}\` (v${version}). **Do not edit by hand**
|
|
139
|
+
> Generated by \`synthesisui add ${slug}\` (v${version}). **Do not edit by hand** -
|
|
138
140
|
> run \`synthesisui add ${slug}\` again to update.
|
|
139
141
|
|
|
140
142
|
${meta.tagline}
|
|
@@ -161,7 +163,7 @@ ${rulesNote}
|
|
|
161
163
|
\`\`\`
|
|
162
164
|
All \`--ds-*\` custom properties and \`.ds-*\` classes only apply inside that scope.
|
|
163
165
|
Applying \`data-ds="${slug}"\` at the app root (e.g. \`<body>\` or the root layout)
|
|
164
|
-
is the simplest choice
|
|
166
|
+
is the simplest choice - the whole app then wears the system.
|
|
165
167
|
${hasAlt
|
|
166
168
|
? `
|
|
167
169
|
3. Light/dark: an ancestor with \`data-scheme="${altScheme}"\` switches the neutral roles to the opposite mode.
|
|
@@ -189,16 +191,16 @@ backed by the design system: \`bg-*\`/\`text-*\`/\`border-*\` (semantic colors),
|
|
|
189
191
|
? `, \`bg-series-*\`/\`text-series-*\`/\`fill-series-*\` (data-viz series)`
|
|
190
192
|
: ""}.
|
|
191
193
|
|
|
192
|
-
**Prefer these utilities for layout and new composition**
|
|
194
|
+
**Prefer these utilities for layout and new composition** - they are this project's idiom and read
|
|
193
195
|
far better than inline \`style\`. Reach for inline \`var(--ds-*)\` only when no utility fits.
|
|
194
196
|
|
|
195
197
|
\`\`\`tsx
|
|
196
|
-
// ✅ preferred
|
|
198
|
+
// ✅ preferred - Tailwind utilities backed by the DS
|
|
197
199
|
<main className="bg-canvas text-foreground p-2xl flex flex-col gap-md">
|
|
198
200
|
<button className="ds-button" data-intent="primary">Save</button>
|
|
199
201
|
</main>
|
|
200
202
|
|
|
201
|
-
// ❌ avoid
|
|
203
|
+
// ❌ avoid - inline styles with raw var() when a utility exists
|
|
202
204
|
<main style={{ background: "var(--ds-color-semantic-canvas)", padding: "var(--ds-spacing-2xl)" }}>
|
|
203
205
|
\`\`\`
|
|
204
206
|
|
|
@@ -206,16 +208,16 @@ far better than inline \`style\`. Reach for inline \`var(--ds-*)\` only when no
|
|
|
206
208
|
`
|
|
207
209
|
: ""}
|
|
208
210
|
This is **v${version}**. The stable entrypoints at \`_synthesisui/ds/${slug}/\` (the
|
|
209
|
-
\`tokens.css\`/\`theme.css\` re-exports, plus \`.lock\`) always point at the active version
|
|
210
|
-
those, not the versioned ones. The pinned files for this version
|
|
211
|
-
\`design-system.json\` (canonical source of truth), \`GUIDE.md\` (this file)
|
|
211
|
+
\`tokens.css\`/\`theme.css\` re-exports, plus \`.lock\`) always point at the active version - import
|
|
212
|
+
those, not the versioned ones. The pinned files for this version - ${artifactList},
|
|
213
|
+
\`design-system.json\` (canonical source of truth), \`GUIDE.md\` (this file) - live in
|
|
212
214
|
\`_synthesisui/ds/${slug}/v${version}/\`.
|
|
213
215
|
|
|
214
216
|
---
|
|
215
217
|
${pagesSection}
|
|
216
218
|
## Building with the system
|
|
217
219
|
|
|
218
|
-
**This system is for building real product UI**
|
|
220
|
+
**This system is for building real product UI** - pages, layouts, dashboards, whole flows.
|
|
219
221
|
Compose the \`.ds-*\` recipes (and their parts) together with the DS-backed utilities to assemble
|
|
220
222
|
actual screens. There is **no "samples only" rule**: build the real app. An
|
|
221
223
|
\`app/synthesisui-samples/<component>/\` page is a fine *optional* scratch space to eyeball a single
|
|
@@ -223,15 +225,15 @@ component, but it is never required.
|
|
|
223
225
|
|
|
224
226
|
### Layout & composition
|
|
225
227
|
The system defines the scale; these are sensible defaults for spending it:
|
|
226
|
-
- **Page gutter / container padding:** a large spacing step
|
|
228
|
+
- **Page gutter / container padding:** a large spacing step - ${list(Object.keys(foundations.spacing).filter((k) => /xl/.test(k)))}.
|
|
227
229
|
- **Section gaps:** \`lg\` (or the nearest large step). **Card/panel padding:** \`md\`.
|
|
228
230
|
- **Field / tight gaps:** \`2xs\`/\`3xs\`.
|
|
229
|
-
- The system imposes no content max-width
|
|
231
|
+
- The system imposes no content max-width - cap long-form/text columns yourself for readability.
|
|
230
232
|
${hasParts
|
|
231
233
|
? `
|
|
232
234
|
### Multi-part components
|
|
233
235
|
Components that have **parts** compile to \`.ds-<name>-<part>\` classes you nest yourself; the exact
|
|
234
|
-
part classes and their \`data-*\` are listed per component below. Example
|
|
236
|
+
part classes and their \`data-*\` are listed per component below. Example - a table:
|
|
235
237
|
\`\`\`tsx
|
|
236
238
|
<table className="ds-table">
|
|
237
239
|
<thead className="ds-table-head">
|
|
@@ -251,27 +253,27 @@ part classes and their \`data-*\` are listed per component below. Example — a
|
|
|
251
253
|
`
|
|
252
254
|
: ""}
|
|
253
255
|
### Overlays & portals
|
|
254
|
-
Dialogs, menus and toasts are often rendered through a portal at the end of \`<body>\`
|
|
256
|
+
Dialogs, menus and toasts are often rendered through a portal at the end of \`<body>\` - **outside**
|
|
255
257
|
your \`data-ds\` scope. Since \`.ds-*\`/\`--ds-*\` only resolve inside the scope, wrap any portalled UI
|
|
256
258
|
in its own \`<div data-ds="${slug}"${hasAlt ? ` data-scheme="…"` : ""}>\`, or apply \`data-ds\` at the
|
|
257
259
|
app root so everything (portals included) inherits it. Behavior (open/close, focus trap, positioning,
|
|
258
|
-
keyboard) is yours to wire
|
|
260
|
+
keyboard) is yours to wire - the system ships the **looks**, not the JavaScript.
|
|
259
261
|
|
|
260
|
-
### Interactive recipes
|
|
262
|
+
### Interactive recipes - the behavior contract
|
|
261
263
|
Several recipes are **static surfaces**: they ship the styling for every state, but never any
|
|
262
264
|
JavaScript. You own the interaction and drive each state by toggling the documented \`data-*\`
|
|
263
265
|
attributes (listed per component below). The recipe restyles itself; you wire the logic.
|
|
264
266
|
- **Open / close** (menu, select, modal, tooltip, popover): render the surface, then handle show/hide,
|
|
265
267
|
outside-click, focus trap, positioning and \`Esc\` yourself (or with a headless lib).
|
|
266
268
|
- **Selection / active** (tabs, sidebar, pagination): set \`data-active="true"\` on the chosen item from
|
|
267
|
-
your own state/router
|
|
269
|
+
your own state/router - the recipe lifts it onto a surface.
|
|
268
270
|
- **On / off** (switch): toggle \`data-state="on"\` on the track **and** its thumb together.
|
|
269
|
-
- **Command bar / ⌘K** (if your system ships one): the recipe is only the styled input row
|
|
271
|
+
- **Command bar / ⌘K** (if your system ships one): the recipe is only the styled input row - wire the
|
|
270
272
|
shortcut, the palette list and filtering yourself.
|
|
271
273
|
- **Select** (native vs custom): \`.ds-select\` strips native chrome (\`appearance:none\`). On a real
|
|
272
274
|
\`<select>\`, wrap it and overlay your own chevron; on a custom trigger, nest \`.ds-select-chevron\`.
|
|
273
275
|
|
|
274
|
-
Pair these with the right ARIA (\`aria-expanded\`, \`role="dialog"\`, \`aria-current\`, …)
|
|
276
|
+
Pair these with the right ARIA (\`aria-expanded\`, \`role="dialog"\`, \`aria-current\`, …) - the system
|
|
275
277
|
styles it, you make it work.
|
|
276
278
|
|
|
277
279
|
---
|
|
@@ -282,11 +284,11 @@ ${hasTailwind
|
|
|
282
284
|
- **Styling mechanism:** prefer Tailwind utilities backed by the DS (\`bg-primary\`, \`p-md\`,
|
|
283
285
|
\`font-display\`, \`font-medium\`, …) for layout and new composition, and reuse the \`.ds-*\` recipes
|
|
284
286
|
for components the DS already covers. Use inline \`style\` with \`var(--ds-*)\` only as a last resort.
|
|
285
|
-
The token names below are the source vocabulary
|
|
287
|
+
The token names below are the source vocabulary - every utility derives from them.`
|
|
286
288
|
: ""}
|
|
287
289
|
- **Always use semantic tokens**, never raw values nor primitives directly.
|
|
288
290
|
Color: \`var(--ds-color-semantic-<role>)\`${hasTailwind ? " (utility: `bg-<role>`/`text-<role>`)" : ""}. The roles are: ${list(semanticRoles)}.
|
|
289
|
-
- Primitives (\`--ds-color-<palette>-<step>\`) exist but should **not** be referenced directly
|
|
291
|
+
- Primitives (\`--ds-color-<palette>-<step>\`) exist but should **not** be referenced directly -
|
|
290
292
|
they feed the semantic roles.${seriesKeys.length > 0
|
|
291
293
|
? `\n- Data-viz → \`var(--ds-color-series-<n>)\`${hasTailwind ? " (utility: `bg-series-<n>`/`text-series-<n>`/`fill-series-<n>`)" : ""}: categorical chart/series colors, ${seriesKeys.length} of them (${list(seriesKeys)}). Use them in order for multi-series charts; they re-paint with the system.`
|
|
292
294
|
: ""}
|
|
@@ -299,7 +301,7 @@ ${hasTailwind
|
|
|
299
301
|
- Motion: durations \`--ds-motion-durations-<key>\` (${list(Object.keys(motion.durations))}) and
|
|
300
302
|
easings \`--ds-motion-easings-<key>\` (${list(Object.keys(motion.easings))}). Use them on
|
|
301
303
|
\`transition\`/\`animation\` (e.g. \`transition: color var(--ds-motion-durations-fast) var(--ds-motion-easings-standard)\`)
|
|
302
|
-
so timing stays on-brand. The DS ships timing tokens, **not** a runtime
|
|
304
|
+
so timing stays on-brand. The DS ships timing tokens, **not** a runtime - for entrance/reveal/stagger
|
|
303
305
|
pair them with a motion lib (e.g. \`motion\`/Framer) or CSS \`@keyframes\`.
|
|
304
306
|
- When **creating a new component** the DS does not cover yet: compose it from these semantic
|
|
305
307
|
tokens to inherit the system's identity; do not invent colors/measures outside the scale.
|
|
@@ -319,10 +321,10 @@ ${blockEntries.length
|
|
|
319
321
|
|
|
320
322
|
## Engagement blocks (optional)
|
|
321
323
|
|
|
322
|
-
A small gamification library the AI advisor (\`synthesisui advise\`) can propose
|
|
324
|
+
A small gamification library the AI advisor (\`synthesisui advise\`) can propose - same
|
|
323
325
|
\`.ds-<name>\` recipe shape as the components above, token-only so they wear the system. Use them
|
|
324
326
|
**only where they fit the product** (progress, retention, recognition); they're a library to compose
|
|
325
|
-
from, not a default
|
|
327
|
+
from, not a default - and lean against over-gamifying a serious B2B product. Each is a \`.ds-<name>\`
|
|
326
328
|
class inside the \`[data-ds="${slug}"]\` scope; multi-part ones expose \`.ds-<name>-<part>\`.
|
|
327
329
|
|
|
328
330
|
${blockLines.join("\n\n")}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { list } from "./commands/list.js";
|
|
|
7
7
|
import { login } from "./commands/login.js";
|
|
8
8
|
import { page } from "./commands/page.js";
|
|
9
9
|
import { RegistryError } from "./registry.js";
|
|
10
|
-
const HELP = `synthesisui
|
|
10
|
+
const HELP = `synthesisui - bring SynthesisUI design systems into your project
|
|
11
11
|
|
|
12
12
|
Usage:
|
|
13
13
|
synthesisui login [options] connect the CLI to your account (device-flow)
|
|
@@ -81,7 +81,7 @@ async function main() {
|
|
|
81
81
|
case "add": {
|
|
82
82
|
const slug = args[0];
|
|
83
83
|
if (!slug) {
|
|
84
|
-
console.error("error: provide the slug
|
|
84
|
+
console.error("error: provide the slug - `synthesisui add <slug>`");
|
|
85
85
|
process.exitCode = 1;
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
@@ -89,7 +89,7 @@ async function main() {
|
|
|
89
89
|
if (typeof flags.version === "string") {
|
|
90
90
|
version = Number.parseInt(flags.version.replace(/^v/i, ""), 10);
|
|
91
91
|
if (!Number.isInteger(version) || version < 1) {
|
|
92
|
-
console.error(`error: invalid --version "${flags.version}"
|
|
92
|
+
console.error(`error: invalid --version "${flags.version}" - use an integer ≥ 1`);
|
|
93
93
|
process.exitCode = 1;
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
@@ -109,7 +109,7 @@ async function main() {
|
|
|
109
109
|
const slug = args[0];
|
|
110
110
|
const template = args[1];
|
|
111
111
|
if (!slug || !template) {
|
|
112
|
-
console.error("error: provide slug and template
|
|
112
|
+
console.error("error: provide slug and template - `synthesisui page <slug> <template>`");
|
|
113
113
|
process.exitCode = 1;
|
|
114
114
|
return;
|
|
115
115
|
}
|
|
@@ -117,7 +117,7 @@ async function main() {
|
|
|
117
117
|
if (typeof flags.version === "string") {
|
|
118
118
|
version = Number.parseInt(flags.version.replace(/^v/i, ""), 10);
|
|
119
119
|
if (!Number.isInteger(version) || version < 1) {
|
|
120
|
-
console.error(`error: invalid --version "${flags.version}"
|
|
120
|
+
console.error(`error: invalid --version "${flags.version}" - use an integer ≥ 1`);
|
|
121
121
|
process.exitCode = 1;
|
|
122
122
|
return;
|
|
123
123
|
}
|
|
@@ -130,7 +130,7 @@ async function main() {
|
|
|
130
130
|
case "advise": {
|
|
131
131
|
const valueProp = args.join(" ").trim();
|
|
132
132
|
if (!valueProp) {
|
|
133
|
-
console.error('error: describe your product
|
|
133
|
+
console.error('error: describe your product - `synthesisui advise "<value proposition>"`');
|
|
134
134
|
process.exitCode = 1;
|
|
135
135
|
return;
|
|
136
136
|
}
|
|
@@ -140,7 +140,7 @@ async function main() {
|
|
|
140
140
|
case "generate": {
|
|
141
141
|
const description = args.join(" ").trim();
|
|
142
142
|
if (!description) {
|
|
143
|
-
console.error('error: describe the component
|
|
143
|
+
console.error('error: describe the component - `synthesisui generate "<description>"`');
|
|
144
144
|
process.exitCode = 1;
|
|
145
145
|
return;
|
|
146
146
|
}
|
package/dist/repo-context.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
/**
|
|
4
|
-
* Monta um resumo COMPACTO e aterrado do projeto pro advisor
|
|
4
|
+
* Monta um resumo COMPACTO e aterrado do projeto pro advisor - barato em tokens
|
|
5
5
|
* e suficiente pra propostas específicas: stack (package.json), forma do repo
|
|
6
6
|
* (árvore nível 1), DS SynthesisUI instalado(s) e o começo do README. Sem dump
|
|
7
7
|
* de código (custo/ruído): o advisor propõe padrões, não lê implementação.
|
|
@@ -52,7 +52,7 @@ async function installedDesignSystems(root) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
catch {
|
|
55
|
-
// nenhum DS instalado
|
|
55
|
+
// nenhum DS instalado - tudo bem
|
|
56
56
|
}
|
|
57
57
|
return out;
|
|
58
58
|
}
|
|
@@ -72,7 +72,7 @@ export async function buildRepoContext(root) {
|
|
|
72
72
|
const pkg = await readJson(join(root, "package.json"));
|
|
73
73
|
const parts = [];
|
|
74
74
|
if (pkg) {
|
|
75
|
-
parts.push(`Projeto: ${pkg.name ?? "(sem nome)"}${pkg.description ? `
|
|
75
|
+
parts.push(`Projeto: ${pkg.name ?? "(sem nome)"}${pkg.description ? ` - ${pkg.description}` : ""}`);
|
|
76
76
|
const deps = [
|
|
77
77
|
...Object.keys(pkg.dependencies ?? {}),
|
|
78
78
|
...Object.keys(pkg.devDependencies ?? {}),
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Minimal mirror of the registry contract
|
|
2
|
+
* Minimal mirror of the registry contract - the CLI is standalone and does NOT
|
|
3
3
|
* import `@synthesisui-hub/ds-contracts` (it only consumes the endpoint JSON).
|
|
4
4
|
* We type only what the CLI reads to generate GUIDE.md and the .lock.
|
|
5
5
|
*/
|