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.
@@ -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
- console.log("Next steps:");
115
- console.log(" In your global CSS, import the system (use a path relative to that CSS file -");
116
- console.log(" from `app/globals.css` in a Next App Router project that means a leading `../`):");
117
- console.log(` @import "_synthesisui/ds/${payload.slug}/tokens.css";`);
118
- if (hasTheme) {
119
- console.log(` @import "_synthesisui/ds/${payload.slug}/theme.css"; /* Tailwind v4 utilities - required */`);
120
- console.log(' (import `theme.css` after `tokens.css`, both after `@import "tailwindcss";`)');
121
- }
122
- console.log(` • scope your UI with data-ds="${payload.slug}"`);
123
- console.log(` • details and rules in _synthesisui/ds/${payload.slug}/v${v}/GUIDE.md`);
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("Use it:");
56
- console.log(` • once per app: synthesisui add ${slug} (tokens.css${config.styles === "tailwind" ? " + theme.css" : ""}), import it globally,`);
57
- console.log(` and put data-ds="${slug}" on a root element (e.g. <body data-ds="${slug}">)`);
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
- console.log(` • import { ${pascalName} } from "./${config.componentsDir}/${res.name}" and render <${pascalName} />`);
65
- console.log(` • or ask your agent: "use the ${pascalName} component from ${config.componentsDir}/${res.name} (SynthesisUI ${slug})"`);
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(` • @import "_synthesisui/ds/${slug}/components/${res.name}.css" and use <div class="ds-${res.name}">…</div>`);
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Traz design systems do SynthesisUI para qualquer projeto (materializa em _local/ds/).",
5
5
  "type": "module",
6
6
  "bin": {