synthesisui 0.2.0 → 0.2.1
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/add.js +23 -11
- package/dist/commands/component.js +44 -6
- package/dist/output.js +22 -0
- package/package.json +1 -1
package/dist/commands/add.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join } from "node:path";
|
|
|
3
3
|
import { syncClaudeMd } from "../claude-md.js";
|
|
4
4
|
import { resolveRegistry } from "../config.js";
|
|
5
5
|
import { buildGuide } from "../guide.js";
|
|
6
|
+
import { body as line, section, snippet } from "../output.js";
|
|
6
7
|
import { fetchDesignSystem } from "../registry.js";
|
|
7
8
|
async function readRootLock(path) {
|
|
8
9
|
try {
|
|
@@ -109,16 +110,27 @@ export async function add(slug, opts) {
|
|
|
109
110
|
console.log(` philosophy.md → ${sections.length} section(s) (read after rules)`);
|
|
110
111
|
}
|
|
111
112
|
console.log(` CLAUDE.md ${claudeMd.created ? "created" : "updated"} (${claudeMd.count} system(s) installed)`);
|
|
112
|
-
console.log("");
|
|
113
113
|
const hasTheme = cssArtifacts.includes("theme.css");
|
|
114
|
-
|
|
115
|
-
console.log("
|
|
116
|
-
console.log("
|
|
117
|
-
console.log(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
114
|
+
// ── DX: concrete paths + copy-pasteable snippets, with breathing room ──
|
|
115
|
+
console.log(section("One-time setup (once per app)"));
|
|
116
|
+
console.log(line("1. Import the system in your GLOBAL stylesheet, e.g. app/globals.css"));
|
|
117
|
+
console.log(line(" (the path is relative to that file - hence the leading ../):"));
|
|
118
|
+
console.log("");
|
|
119
|
+
console.log(snippet(hasTheme
|
|
120
|
+
? [
|
|
121
|
+
`@import "tailwindcss";`,
|
|
122
|
+
`@import "../_synthesisui/ds/${payload.slug}/tokens.css";`,
|
|
123
|
+
`@import "../_synthesisui/ds/${payload.slug}/theme.css"; /* Tailwind utilities on your tokens */`,
|
|
124
|
+
]
|
|
125
|
+
: [`@import "../_synthesisui/ds/${payload.slug}/tokens.css";`]));
|
|
126
|
+
console.log("");
|
|
127
|
+
console.log(line(`2. Scope your app: add data-ds="${payload.slug}" to a ROOT element, e.g. app/layout.tsx:`));
|
|
128
|
+
console.log("");
|
|
129
|
+
console.log(snippet([`<body data-ds="${payload.slug}">{children}</body>`]));
|
|
130
|
+
console.log(section("Next"));
|
|
131
|
+
console.log(line(`synthesisui component ${payload.slug} button bring a component in as YOUR code`));
|
|
132
|
+
console.log(line(`synthesisui template ${payload.slug} landing materialize a whole page`));
|
|
133
|
+
console.log("");
|
|
134
|
+
console.log(line(`Guide for you and your agent: _synthesisui/ds/${payload.slug}/v${v}/GUIDE.md`));
|
|
135
|
+
console.log("");
|
|
124
136
|
}
|
|
@@ -2,6 +2,7 @@ import { mkdir, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { generateComponentFiles } from "../component-codegen.js";
|
|
4
4
|
import { readProjectConfig, resolveRegistry } from "../config.js";
|
|
5
|
+
import { body, section, snippet } from "../output.js";
|
|
5
6
|
import { fetchComponent, RegistryError } from "../registry.js";
|
|
6
7
|
/** Slugs/names are kebab-case by contract; reject anything else before it ever
|
|
7
8
|
* reaches a filesystem path (defense-in-depth against `../` traversal). */
|
|
@@ -51,20 +52,57 @@ export async function component(slug, name, opts) {
|
|
|
51
52
|
const names = files.map((f) => f.filename).join(", ");
|
|
52
53
|
console.log(`✓ ${config.componentsDir}/${res.name}/ → ${names} (styles: ${config.styles})`);
|
|
53
54
|
}
|
|
55
|
+
// ── DX: concrete paths + copy-pasteable snippets, with breathing room ──
|
|
56
|
+
const tailwind = config.styles === "tailwind";
|
|
57
|
+
const imports = tailwind
|
|
58
|
+
? [
|
|
59
|
+
`@import "tailwindcss";`,
|
|
60
|
+
`@import "../_synthesisui/ds/${slug}/tokens.css";`,
|
|
61
|
+
`@import "../_synthesisui/ds/${slug}/theme.css";`,
|
|
62
|
+
]
|
|
63
|
+
: [`@import "../_synthesisui/ds/${slug}/tokens.css";`];
|
|
64
|
+
console.log(section(`One-time setup (once per app, for "${slug}")`));
|
|
65
|
+
console.log(body(`1. Import the design system in your GLOBAL stylesheet, e.g. app/globals.css`));
|
|
66
|
+
console.log(body(` (the path is relative to that file - hence the leading ../):`));
|
|
54
67
|
console.log("");
|
|
55
|
-
console.log(
|
|
56
|
-
console.log(
|
|
57
|
-
console.log(`
|
|
68
|
+
console.log(snippet(imports));
|
|
69
|
+
console.log("");
|
|
70
|
+
console.log(body(`2. Scope your app: add data-ds="${slug}" to a ROOT element, e.g. app/layout.tsx:`));
|
|
71
|
+
console.log("");
|
|
72
|
+
console.log(snippet([`<body data-ds="${slug}">{children}</body>`]));
|
|
73
|
+
console.log("");
|
|
74
|
+
console.log(body(`(If you haven't installed the system yet, run: synthesisui add ${slug})`));
|
|
75
|
+
console.log(section("Use it"));
|
|
58
76
|
if (!opts.artifactsOnly && config.target === "next") {
|
|
59
77
|
const pascalName = res.name
|
|
60
78
|
.split(/[^a-zA-Z0-9]+/)
|
|
61
79
|
.filter(Boolean)
|
|
62
80
|
.map((p) => p[0].toUpperCase() + p.slice(1))
|
|
63
81
|
.join("");
|
|
64
|
-
|
|
65
|
-
|
|
82
|
+
// Show a real variant in the example when the recipe has one.
|
|
83
|
+
const firstAxis = Object.entries(res.recipe.variants ?? {}).find(([, options]) => Object.values(options).some((block) => Object.keys(block).length > 0));
|
|
84
|
+
const exampleProp = firstAxis
|
|
85
|
+
? ` ${firstAxis[0]}="${Object.keys(firstAxis[1])[0]}"`
|
|
86
|
+
: "";
|
|
87
|
+
console.log(snippet([
|
|
88
|
+
`import { ${pascalName} } from "@/${config.componentsDir}/${res.name}";`,
|
|
89
|
+
"",
|
|
90
|
+
`<${pascalName}${exampleProp} />`,
|
|
91
|
+
]));
|
|
92
|
+
console.log("");
|
|
93
|
+
console.log(body(`(adjust "@/" to your project's import alias if it differs)`));
|
|
94
|
+
console.log("");
|
|
95
|
+
console.log(body("Or ask your agent:"));
|
|
96
|
+
console.log(snippet([
|
|
97
|
+
`"Use the ${pascalName} component from ${config.componentsDir}/${res.name} (SynthesisUI ${slug})."`,
|
|
98
|
+
]));
|
|
66
99
|
}
|
|
67
100
|
else {
|
|
68
|
-
console.log(
|
|
101
|
+
console.log(snippet([
|
|
102
|
+
`@import "../_synthesisui/ds/${slug}/components/${res.name}.css";`,
|
|
103
|
+
"",
|
|
104
|
+
`<div class="ds-${res.name}">…</div>`,
|
|
105
|
+
]));
|
|
69
106
|
}
|
|
107
|
+
console.log("");
|
|
70
108
|
}
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal output helpers - the CLI's DX surface. Principles:
|
|
3
|
+
* - breathing room: blank lines around sections, never a wall of bullets;
|
|
4
|
+
* - concrete over abstract: real paths and copy-pasteable snippets, not
|
|
5
|
+
* "import it globally";
|
|
6
|
+
* - one idea per section, titled with a scannable ruled heading.
|
|
7
|
+
*/
|
|
8
|
+
const WIDTH = 66;
|
|
9
|
+
/** `── Title ───────────…` ruled section heading (with breathing room). */
|
|
10
|
+
export function section(title) {
|
|
11
|
+
const head = `── ${title} `;
|
|
12
|
+
const rest = Math.max(4, WIDTH - head.length);
|
|
13
|
+
return `\n${head}${"─".repeat(rest)}\n`;
|
|
14
|
+
}
|
|
15
|
+
/** Indented, copy-pasteable code block (empty lines stay truly empty). */
|
|
16
|
+
export function snippet(lines) {
|
|
17
|
+
return lines.map((line) => (line ? ` ${line}` : "")).join("\n");
|
|
18
|
+
}
|
|
19
|
+
/** Indented body text line. */
|
|
20
|
+
export function body(line) {
|
|
21
|
+
return ` ${line}`;
|
|
22
|
+
}
|