synthesisui 0.16.510 → 0.16.512

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.
@@ -150,7 +150,7 @@ function borderGroup(variants: string, rest: string, cls: string): string {
150
150
  (tail.startsWith("[") && !isArbitraryColor(tail));
151
151
  if (isWidth) return \`\${variants}border\${side}-width\`;
152
152
  if (BORDER_STYLES.has(tail)) return \`\${variants}border-style\`;
153
- if (COLORS.has(tail) || COLOR_KEYWORDS.has(tail) || isArbitraryColor(tail)) {
153
+ if (COLORS.has(tail) || COLOR_KEYWORDS.has(tail) || isPaletteStep(tail) || isArbitraryColor(tail)) {
154
154
  return \`\${variants}border\${side}-color\`;
155
155
  }
156
156
  return \`\${variants}\${cls}\`;
@@ -166,9 +166,32 @@ function isArbitraryColor(v: string): boolean {
166
166
  * Returning the class itself is the safe answer: an unknown class then collides
167
167
  * only with an identical one, so nothing is ever dropped by mistake.
168
168
  */
169
+ /**
170
+ * THE LAST COLON OUTSIDE BRACKETS ends the variants. \`data-[disabled]:[opacity:0.5]\` has a colon INSIDE the
171
+ * arbitrary property, and \`lastIndexOf\` cut there.
172
+ */
173
+ function variantCut(cls: string): number {
174
+ let depth = 0;
175
+ let cut = -1;
176
+ for (let i = 0; i < cls.length; i++) {
177
+ const ch = cls[i];
178
+ if (ch === "[") depth++;
179
+ else if (ch === "]") depth--;
180
+ else if (ch === ":" && depth === 0) cut = i;
181
+ }
182
+ return cut;
183
+ }
184
+
185
+ /** A palette colour with a step - \`sand-900\`, \`moss-600\` - is a colour even when the system does not name it. */
186
+ function isPaletteStep(v: string): boolean {
187
+ return /^[a-z]+(-[a-z]+)*-[0-9]{2,3}$/.test(v);
188
+ }
189
+
190
+ const OUTLINE_STYLES = new Set(["none", "dashed", "dotted", "double", "hidden"]);
191
+
169
192
  function groupOf(cls: string): string {
170
193
  // A variant is part of the identity: \`hover:bg-x\` must not replace \`bg-y\`.
171
- const cut = cls.lastIndexOf(":");
194
+ const cut = variantCut(cls);
172
195
  const variants = cut === -1 ? "" : cls.slice(0, cut + 1);
173
196
  let base = cut === -1 ? cls : cls.slice(cut + 1);
174
197
 
@@ -179,6 +202,10 @@ function groupOf(cls: string): string {
179
202
 
180
203
  if (DISPLAYS.has(base)) return \`\${variants}display\`;
181
204
 
205
+ // \`[transition:…]\` sets exactly the property it names - grouped by it, so the caller's replaces the base's.
206
+ const arbitrary = /^\\[([a-z-]+):/.exec(base);
207
+ if (arbitrary) return \`\${variants}\${arbitrary[1]}\`;
208
+
182
209
  const dash = base.indexOf("-");
183
210
  const head = dash === -1 ? base : base.slice(0, dash);
184
211
  const rest = dash === -1 ? "" : base.slice(dash + 1);
@@ -197,7 +224,7 @@ function groupOf(cls: string): string {
197
224
  // The two families a prefix cannot settle, answered by this system's names.
198
225
  if (head === "text") {
199
226
  if (TEXT_SIZES.has(rest)) return \`\${variants}font-size\`;
200
- if (COLORS.has(rest) || rest.startsWith("[")) return \`\${variants}text-color\`;
227
+ if (COLORS.has(rest) || isPaletteStep(rest) || rest.startsWith("[")) return \`\${variants}text-color\`;
201
228
  return \`\${variants}\${cls}\`;
202
229
  }
203
230
  if (head === "font") {
@@ -206,6 +233,16 @@ function groupOf(cls: string): string {
206
233
  return \`\${variants}\${cls}\`;
207
234
  }
208
235
  if (head === "border") return borderGroup(variants, rest, cls);
236
+ // Every \`transition-*\` sets transition-property, and so does \`[transition:…]\`.
237
+ if (head === "transition") return \`\${variants}transition\`;
238
+ if (head === "outline") {
239
+ if (rest.startsWith("offset")) return \`\${variants}outline-offset\`;
240
+ if (rest === "" || OUTLINE_STYLES.has(rest)) return \`\${variants}outline-style\`;
241
+ if ([...rest].every((ch) => ch >= "0" && ch <= "9")) return \`\${variants}outline-width\`;
242
+ if (COLORS.has(rest) || COLOR_KEYWORDS.has(rest) || isPaletteStep(rest) || isArbitraryColor(rest))
243
+ return \`\${variants}outline-color\`;
244
+ return \`\${variants}\${cls}\`;
245
+ }
209
246
 
210
247
  for (const p of PREFIXES) {
211
248
  if (base === p || base.startsWith(\`\${p}-\`)) return \`\${variants}\${p}\`;
@@ -2,7 +2,7 @@ import { mkdir, stat, writeFile } from "node:fs/promises";
2
2
  import { dirname, join, relative } from "node:path";
3
3
  import { readProjectConfig, resolveRegistry } from "../config.js";
4
4
  import { installedSheetCss, RECIPE_HEADER, recipeRulesFor, } from "../recipe-css.js";
5
- import { fetchDesignSystem, fetchTemplate } from "../registry.js";
5
+ import { fetchDesignSystem, fetchPages, fetchTemplate } from "../registry.js";
6
6
  import { inTheirTongue, projectTongue, tongueFromArtifacts, } from "../their-tongue.js";
7
7
  import { keptLine, recordWritten, editedHere as theirEdits, } from "../written.js";
8
8
  /**
@@ -46,6 +46,28 @@ function withoutTheSheetInstruction(code) {
46
46
  * path classes; the co-located CSS (Next target) carries the responsive media
47
47
  * queries + the CSS-only hamburger, so it re-vests once `tokens.css` is in.
48
48
  */
49
+ /**
50
+ * `template <slug>` SEM NOME - as páginas prontas do sistema (jornada "o CLI na primeira página", E02). Antes, a única
51
+ * resposta era pedir os dois argumentos, e o nome só se descobria tentando. Sem página nenhuma, o caminho que existe é
52
+ * a landing por seções, e a lista diz isso em vez de ficar vazia.
53
+ */
54
+ export async function listPages(slug, registry) {
55
+ const pages = await fetchPages(resolveRegistry(registry), slug);
56
+ if (pages === null) {
57
+ console.log(`The registry did not list the pages of "${slug}". Try \`synthesisui template ${slug} <name>\`.`);
58
+ return;
59
+ }
60
+ if (pages.length === 0) {
61
+ console.log(`"${slug}" has no ready pages.`);
62
+ console.log(`A landing is put together from its sections: synthesisui landing ${slug} "<what the page is for>"`);
63
+ return;
64
+ }
65
+ console.log(`"${slug}" has ${pages.length} ready page${pages.length === 1 ? "" : "s"}:`);
66
+ for (const page of pages)
67
+ console.log(` ${page}`);
68
+ console.log("");
69
+ console.log(` synthesisui template ${slug} ${pages[0]}`);
70
+ }
49
71
  export async function template(slug, name, opts) {
50
72
  const base = resolveRegistry(opts.registry);
51
73
  const root = opts.dir ?? process.cwd();
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ import { request } from "./commands/request.js";
34
34
  import { status } from "./commands/status.js";
35
35
  import { summary } from "./commands/summary.js";
36
36
  import { sync } from "./commands/sync.js";
37
- import { template } from "./commands/template.js";
37
+ import { listPages, template } from "./commands/template.js";
38
38
  import { upgrade } from "./commands/upgrade.js";
39
39
  import { use } from "./commands/use.js";
40
40
  import { appendEvent } from "./doctor/ledger.js";
@@ -62,6 +62,7 @@ Usage - deterministic, FREE:
62
62
  synthesisui blueprint | component the same command, spelled in full
63
63
  synthesisui template <slug> <name> materialize a whole page from a DS template
64
64
  (--as landing-home names the output - multi-page safe)
65
+ synthesisui template <slug> the ready pages that system has
65
66
  synthesisui upgrade <slug> update an installed DS + regenerate your components + migration brief
66
67
  synthesisui colours [slug] write the colours you chose on the site into your CSS, in your names (asks first)
67
68
  synthesisui use <slug> "<intent>" print a ready-to-paste agent prompt to build/modify on-system
@@ -608,11 +609,16 @@ async function main() {
608
609
  }
609
610
  const slug = args[0];
610
611
  const name = args[1];
611
- if (!slug || !name) {
612
+ if (!slug) {
612
613
  console.error("error: provide slug and template name - `synthesisui template <slug> <name>`");
613
614
  process.exitCode = 1;
614
615
  return;
615
616
  }
617
+ /** SEM NOME, A LISTA - o que o sistema tem, em vez de pedir um nome que só se descobre tentando (E02, 12/10). */
618
+ if (!name) {
619
+ await listPages(slug, registry);
620
+ return;
621
+ }
616
622
  let version;
617
623
  if (typeof flags.version === "string") {
618
624
  version = Number.parseInt(flags.version.replace(/^v/i, ""), 10);
package/dist/registry.js CHANGED
@@ -70,6 +70,23 @@ export async function fetchDesignSystem(base, slug, version) {
70
70
  * Fetches a whole page generated from a DS template (`?template=&target=`). The
71
71
  * server codegens it from `document.layouts[<template>]`; the CLI just writes it.
72
72
  */
73
+ /**
74
+ * AS PÁGINAS PRONTAS DE UM SISTEMA - `template <slug>` sem nome (jornada "o CLI na primeira página", E02). `null` quando
75
+ * o registro ainda não sabe responder (anterior a `?pages=1`): ele devolve o documento, que não tem `pages`.
76
+ */
77
+ export async function fetchPages(base, slug) {
78
+ const url = new URL(`${base}/api/registry/ds/${encodeURIComponent(slug)}`);
79
+ url.searchParams.set("pages", "1");
80
+ const res = await request(url.toString());
81
+ if (res.status === 404)
82
+ throw new RegistryError(`No design system "${slug}" that this machine can see. \`synthesisui list\` shows what is public.`);
83
+ if (!res.ok)
84
+ throw new RegistryError(`Registry responded ${res.status} while listing the pages of "${slug}".`);
85
+ const body = (await res.json().catch(() => ({})));
86
+ return Array.isArray(body.pages)
87
+ ? body.pages.filter((p) => typeof p === "string")
88
+ : null;
89
+ }
73
90
  export async function fetchTemplate(base, slug, template, target, version, as_) {
74
91
  const url = new URL(`${base}/api/registry/ds/${encodeURIComponent(slug)}`);
75
92
  url.searchParams.set("template", template);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.510",
3
+ "version": "0.16.512",
4
4
  "description": "Bring SynthesisUI design systems into any project - tokens, typed components, whole pages and an agent-ready CLAUDE.md manifest.",
5
5
  "type": "module",
6
6
  "bin": {