@decantr/cli 1.5.2 → 1.5.4
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/bin.js +2 -2
- package/dist/{chunk-66RIAQLH.js → chunk-D3W3MYKT.js} +49 -90
- package/dist/{chunk-6RJSFLT4.js → chunk-T7CQSJGV.js} +390 -379
- package/dist/{heal-54MKDDSQ.js → heal-VYEGIUAS.js} +1 -1
- package/dist/index.js +2 -2
- package/dist/{upgrade-25IURU4X.js → upgrade-TXVD2WIN.js} +1 -1
- package/package.json +1 -1
- package/src/bundled/blueprints/default.json +1 -2
- package/src/templates/DECANTR.md.template +8 -9
- package/src/templates/essence-summary.md.template +1 -1
- package/src/templates/project.json.template +1 -2
- package/src/templates/task-add-page.md.template +7 -8
- package/src/templates/task-modify.md.template +8 -9
- package/src/templates/task-scaffold.md.template +1 -2
|
@@ -2,6 +2,214 @@
|
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync } from "fs";
|
|
3
3
|
import { join, dirname } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
|
+
import { computeSpatialTokens } from "@decantr/essence-spec";
|
|
6
|
+
|
|
7
|
+
// src/treatments.ts
|
|
8
|
+
function generateTreatmentCSS(spatialTokens, treatmentOverrides, themeDecorators, themeName) {
|
|
9
|
+
const lines = [];
|
|
10
|
+
lines.push("/* Generated by @decantr/cli \u2014 Visual Treatment System */");
|
|
11
|
+
lines.push("");
|
|
12
|
+
lines.push("/* \u2500\u2500 Layer 1: Base Treatments \u2500\u2500 */");
|
|
13
|
+
lines.push("");
|
|
14
|
+
function emitRule(selector, props) {
|
|
15
|
+
const treatmentName = selector.replace(/^\./, "").replace(/[:[\s].+$/, "");
|
|
16
|
+
const overrides = treatmentOverrides?.[treatmentName];
|
|
17
|
+
const merged = /* @__PURE__ */ new Map();
|
|
18
|
+
for (const [prop, val] of props) {
|
|
19
|
+
merged.set(prop, val);
|
|
20
|
+
}
|
|
21
|
+
if (overrides && selector === `.${treatmentName}`) {
|
|
22
|
+
for (const [prop, val] of Object.entries(overrides)) {
|
|
23
|
+
merged.set(prop, val);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const body = Array.from(merged.entries()).map(([p, v]) => ` ${p}: ${v};`).join("\n");
|
|
27
|
+
lines.push(`${selector} {`);
|
|
28
|
+
lines.push(body);
|
|
29
|
+
lines.push("}");
|
|
30
|
+
lines.push("");
|
|
31
|
+
}
|
|
32
|
+
emitRule(".d-interactive", [
|
|
33
|
+
["display", "inline-flex"],
|
|
34
|
+
["align-items", "center"],
|
|
35
|
+
["gap", "0.5em"],
|
|
36
|
+
["padding", "var(--d-interactive-py) var(--d-interactive-px)"],
|
|
37
|
+
["border", "1px solid var(--d-border)"],
|
|
38
|
+
["border-radius", "var(--d-radius)"],
|
|
39
|
+
["background", "transparent"],
|
|
40
|
+
["color", "var(--d-text)"],
|
|
41
|
+
["font", "inherit"],
|
|
42
|
+
["cursor", "pointer"],
|
|
43
|
+
["text-decoration", "none"],
|
|
44
|
+
["transition", "background 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease"]
|
|
45
|
+
]);
|
|
46
|
+
emitRule(".d-interactive:hover", [
|
|
47
|
+
["border-color", "var(--d-primary-hover)"],
|
|
48
|
+
["background", "var(--d-surface)"]
|
|
49
|
+
]);
|
|
50
|
+
emitRule(".d-interactive:focus-visible", [
|
|
51
|
+
["outline", "2px solid var(--d-primary)"],
|
|
52
|
+
["outline-offset", "2px"]
|
|
53
|
+
]);
|
|
54
|
+
emitRule(".d-interactive:disabled", [
|
|
55
|
+
["opacity", "0.5"],
|
|
56
|
+
["cursor", "not-allowed"],
|
|
57
|
+
["pointer-events", "none"]
|
|
58
|
+
]);
|
|
59
|
+
emitRule('.d-interactive[data-variant="primary"]', [
|
|
60
|
+
["background", "var(--d-primary)"],
|
|
61
|
+
["color", "#fff"],
|
|
62
|
+
["border-color", "var(--d-primary)"]
|
|
63
|
+
]);
|
|
64
|
+
emitRule('.d-interactive[data-variant="primary"]:hover', [
|
|
65
|
+
["background", "var(--d-primary-hover)"],
|
|
66
|
+
["border-color", "var(--d-primary-hover)"]
|
|
67
|
+
]);
|
|
68
|
+
emitRule('.d-interactive[data-variant="ghost"]', [
|
|
69
|
+
["border-color", "transparent"],
|
|
70
|
+
["background", "transparent"]
|
|
71
|
+
]);
|
|
72
|
+
emitRule('.d-interactive[data-variant="ghost"]:hover', [
|
|
73
|
+
["background", "var(--d-surface)"]
|
|
74
|
+
]);
|
|
75
|
+
emitRule('.d-interactive[data-variant="danger"]', [
|
|
76
|
+
["background", "var(--d-error)"],
|
|
77
|
+
["color", "#fff"],
|
|
78
|
+
["border-color", "var(--d-error)"]
|
|
79
|
+
]);
|
|
80
|
+
emitRule(".d-surface", [
|
|
81
|
+
["background", "var(--d-surface)"],
|
|
82
|
+
["border", "1px solid var(--d-border)"],
|
|
83
|
+
["border-radius", "var(--d-radius)"],
|
|
84
|
+
["box-shadow", "var(--d-shadow)"],
|
|
85
|
+
["padding", "var(--d-surface-p)"]
|
|
86
|
+
]);
|
|
87
|
+
emitRule('.d-surface[data-elevation="raised"]', [
|
|
88
|
+
["background", "var(--d-surface-raised)"],
|
|
89
|
+
["box-shadow", "var(--d-shadow-md)"]
|
|
90
|
+
]);
|
|
91
|
+
emitRule('.d-surface[data-elevation="overlay"]', [
|
|
92
|
+
["background", "var(--d-surface-raised)"],
|
|
93
|
+
["box-shadow", "var(--d-shadow-lg)"],
|
|
94
|
+
["z-index", "50"]
|
|
95
|
+
]);
|
|
96
|
+
emitRule(".d-surface[data-interactive]:hover", [
|
|
97
|
+
["border-color", "var(--d-primary-hover, var(--d-border))"],
|
|
98
|
+
["box-shadow", "var(--d-shadow-md)"],
|
|
99
|
+
["transition", "border-color 0.15s ease, box-shadow 0.15s ease"]
|
|
100
|
+
]);
|
|
101
|
+
emitRule(".d-data", [
|
|
102
|
+
["width", "100%"],
|
|
103
|
+
["border-collapse", "collapse"],
|
|
104
|
+
["text-align", "left"],
|
|
105
|
+
["font-size", "0.875rem"]
|
|
106
|
+
]);
|
|
107
|
+
emitRule(".d-data-header", [
|
|
108
|
+
["padding", "var(--d-data-py) var(--d-content-gap)"],
|
|
109
|
+
["font-weight", "500"],
|
|
110
|
+
["color", "var(--d-text-muted)"],
|
|
111
|
+
["border-bottom", "1px solid var(--d-border)"],
|
|
112
|
+
["font-size", "0.75rem"],
|
|
113
|
+
["text-transform", "uppercase"],
|
|
114
|
+
["letter-spacing", "0.05em"]
|
|
115
|
+
]);
|
|
116
|
+
emitRule(".d-data-row", [
|
|
117
|
+
["border-bottom", "1px solid var(--d-border)"],
|
|
118
|
+
["transition", "background 0.1s ease"]
|
|
119
|
+
]);
|
|
120
|
+
emitRule(".d-data-row:hover", [
|
|
121
|
+
["background", "var(--d-surface)"]
|
|
122
|
+
]);
|
|
123
|
+
emitRule(".d-data-cell", [
|
|
124
|
+
["padding", "var(--d-data-py) var(--d-content-gap)"],
|
|
125
|
+
["vertical-align", "middle"]
|
|
126
|
+
]);
|
|
127
|
+
emitRule(".d-control", [
|
|
128
|
+
["background", "var(--d-surface)"],
|
|
129
|
+
["color", "var(--d-text)"],
|
|
130
|
+
["padding", "var(--d-control-py) 0.75rem"],
|
|
131
|
+
["border-radius", "var(--d-radius)"],
|
|
132
|
+
["border", "1px solid var(--d-border)"],
|
|
133
|
+
["width", "100%"],
|
|
134
|
+
["outline", "none"],
|
|
135
|
+
["font", "inherit"],
|
|
136
|
+
["transition", "border-color 0.15s ease, box-shadow 0.15s ease"]
|
|
137
|
+
]);
|
|
138
|
+
emitRule(".d-control:focus", [
|
|
139
|
+
["border-color", "var(--d-primary)"],
|
|
140
|
+
["box-shadow", "0 0 0 3px color-mix(in srgb, var(--d-primary) 25%, transparent)"]
|
|
141
|
+
]);
|
|
142
|
+
emitRule(".d-control::placeholder", [
|
|
143
|
+
["color", "var(--d-text-muted)"]
|
|
144
|
+
]);
|
|
145
|
+
emitRule(".d-control:disabled", [
|
|
146
|
+
["opacity", "0.5"],
|
|
147
|
+
["cursor", "not-allowed"]
|
|
148
|
+
]);
|
|
149
|
+
emitRule(".d-control[aria-invalid]", [
|
|
150
|
+
["border-color", "var(--d-error)"],
|
|
151
|
+
["box-shadow", "0 0 0 3px color-mix(in srgb, var(--d-error) 15%, transparent)"]
|
|
152
|
+
]);
|
|
153
|
+
emitRule(".d-section", [
|
|
154
|
+
["padding", "var(--d-section-py) 0"]
|
|
155
|
+
]);
|
|
156
|
+
lines.push(".d-section + .d-section {");
|
|
157
|
+
lines.push(" border-top: 1px solid var(--d-border);");
|
|
158
|
+
lines.push("}");
|
|
159
|
+
lines.push("");
|
|
160
|
+
emitRule(".d-annotation", [
|
|
161
|
+
["display", "inline-flex"],
|
|
162
|
+
["align-items", "center"],
|
|
163
|
+
["gap", "0.25em"],
|
|
164
|
+
["font-size", "0.75rem"],
|
|
165
|
+
["font-weight", "500"],
|
|
166
|
+
["padding", "0.125rem 0.5rem"],
|
|
167
|
+
["border-radius", "var(--d-radius-full)"],
|
|
168
|
+
["background", "var(--d-surface)"],
|
|
169
|
+
["color", "var(--d-text-muted)"],
|
|
170
|
+
["white-space", "nowrap"]
|
|
171
|
+
]);
|
|
172
|
+
emitRule('.d-annotation[data-status="success"]', [
|
|
173
|
+
["background", "color-mix(in srgb, var(--d-success) 15%, transparent)"],
|
|
174
|
+
["color", "var(--d-success)"]
|
|
175
|
+
]);
|
|
176
|
+
emitRule('.d-annotation[data-status="error"]', [
|
|
177
|
+
["background", "color-mix(in srgb, var(--d-error) 15%, transparent)"],
|
|
178
|
+
["color", "var(--d-error)"]
|
|
179
|
+
]);
|
|
180
|
+
emitRule('.d-annotation[data-status="warning"]', [
|
|
181
|
+
["background", "color-mix(in srgb, var(--d-warning) 15%, transparent)"],
|
|
182
|
+
["color", "var(--d-warning)"]
|
|
183
|
+
]);
|
|
184
|
+
emitRule('.d-annotation[data-status="info"]', [
|
|
185
|
+
["background", "color-mix(in srgb, var(--d-info) 15%, transparent)"],
|
|
186
|
+
["color", "var(--d-info)"]
|
|
187
|
+
]);
|
|
188
|
+
if (themeDecorators && Object.keys(themeDecorators).length > 0) {
|
|
189
|
+
const label = themeName ? ` (${themeName})` : "";
|
|
190
|
+
lines.push(`/* \u2500\u2500 Layer 3: Theme Decorators${label} \u2500\u2500 */`);
|
|
191
|
+
lines.push("");
|
|
192
|
+
for (const [name, description] of Object.entries(themeDecorators)) {
|
|
193
|
+
const rule = generateDecoratorRule(name, description);
|
|
194
|
+
lines.push(rule);
|
|
195
|
+
lines.push("");
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
lines.push("/* \u2500\u2500 Keyframes \u2500\u2500 */");
|
|
199
|
+
lines.push("");
|
|
200
|
+
lines.push("@keyframes decantr-fade-in {");
|
|
201
|
+
lines.push(" from { opacity: 0; transform: translateY(4px); }");
|
|
202
|
+
lines.push(" to { opacity: 1; transform: translateY(0); }");
|
|
203
|
+
lines.push("}");
|
|
204
|
+
lines.push("");
|
|
205
|
+
lines.push("@keyframes decantr-pulse {");
|
|
206
|
+
lines.push(" 0%, 100% { opacity: 1; }");
|
|
207
|
+
lines.push(" 50% { opacity: 0.5; }");
|
|
208
|
+
lines.push("}");
|
|
209
|
+
return lines.join("\n");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/scaffold.ts
|
|
5
213
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
214
|
function composeArchetypes(composeEntries, archetypeResults) {
|
|
7
215
|
if (composeEntries.length === 0) {
|
|
@@ -251,8 +459,9 @@ function generateTopologySection(data, personality) {
|
|
|
251
459
|
return lines.join("\n");
|
|
252
460
|
}
|
|
253
461
|
var CLI_VERSION = "1.0.0";
|
|
254
|
-
function generateTokensCSS(themeData, mode) {
|
|
462
|
+
function generateTokensCSS(themeData, mode, spatialTokens) {
|
|
255
463
|
if (!themeData) {
|
|
464
|
+
const spatialLines2 = spatialTokens ? "\n" + Object.entries(spatialTokens).map(([k, v]) => ` ${k}: ${v};`).join("\n") : "";
|
|
256
465
|
return `/* No theme data available */
|
|
257
466
|
:root {
|
|
258
467
|
--d-primary: #6366f1;
|
|
@@ -263,7 +472,7 @@ function generateTokensCSS(themeData, mode) {
|
|
|
263
472
|
--d-surface-raised: #27272a;
|
|
264
473
|
--d-border: #3f3f46;
|
|
265
474
|
--d-text: #fafafa;
|
|
266
|
-
--d-text-muted: #a1a1aa
|
|
475
|
+
--d-text-muted: #a1a1aa;${spatialLines2}
|
|
267
476
|
}
|
|
268
477
|
`;
|
|
269
478
|
}
|
|
@@ -311,10 +520,26 @@ function generateTokensCSS(themeData, mode) {
|
|
|
311
520
|
};
|
|
312
521
|
}
|
|
313
522
|
const tokens = buildTokens(resolvedMode);
|
|
523
|
+
if (themeData?.typography?.mono) {
|
|
524
|
+
tokens["--d-font-mono"] = themeData.typography.mono;
|
|
525
|
+
}
|
|
526
|
+
if (themeData?.palette?.["accent-glow"]?.[resolvedMode]) {
|
|
527
|
+
tokens["--d-accent-glow"] = themeData.palette["accent-glow"][resolvedMode];
|
|
528
|
+
}
|
|
529
|
+
if (themeData?.motion?.durations?.hover) {
|
|
530
|
+
tokens["--d-duration-hover"] = themeData.motion.durations.hover;
|
|
531
|
+
}
|
|
532
|
+
if (themeData?.motion?.durations?.entrance) {
|
|
533
|
+
tokens["--d-duration-entrance"] = themeData.motion.durations.entrance;
|
|
534
|
+
}
|
|
535
|
+
if (themeData?.motion?.timing) {
|
|
536
|
+
tokens["--d-easing"] = themeData.motion.timing;
|
|
537
|
+
}
|
|
314
538
|
const lines = Object.entries(tokens).map(([key, value]) => ` ${key}: ${value};`).join("\n");
|
|
539
|
+
const spatialLines = spatialTokens ? "\n" + Object.entries(spatialTokens).map(([k, v]) => ` ${k}: ${v};`).join("\n") : "";
|
|
315
540
|
let css = `/* Generated by @decantr/cli */
|
|
316
541
|
:root {
|
|
317
|
-
${lines}
|
|
542
|
+
${lines}${spatialLines}
|
|
318
543
|
}
|
|
319
544
|
`;
|
|
320
545
|
if (mode === "auto") {
|
|
@@ -343,32 +568,6 @@ ${lightLines}
|
|
|
343
568
|
}
|
|
344
569
|
return css;
|
|
345
570
|
}
|
|
346
|
-
function generateDecoratorsCSS(recipeData, themeName) {
|
|
347
|
-
if (!recipeData?.decorators) {
|
|
348
|
-
return `/* No recipe decorators available */`;
|
|
349
|
-
}
|
|
350
|
-
const decorators = recipeData.decorators;
|
|
351
|
-
const css = [
|
|
352
|
-
`/* Generated by @decantr/cli from recipe: ${themeName} */`,
|
|
353
|
-
""
|
|
354
|
-
];
|
|
355
|
-
for (const [name, description] of Object.entries(decorators)) {
|
|
356
|
-
css.push(generateDecoratorRule(name, description));
|
|
357
|
-
css.push("");
|
|
358
|
-
}
|
|
359
|
-
css.push(`/* Animation keyframes */
|
|
360
|
-
@keyframes decantr-fade-in {
|
|
361
|
-
from { opacity: 0; transform: translateY(8px); }
|
|
362
|
-
to { opacity: 1; transform: translateY(0); }
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
@keyframes decantr-pulse {
|
|
366
|
-
0%, 100% { opacity: 1; }
|
|
367
|
-
50% { opacity: 0.5; }
|
|
368
|
-
}
|
|
369
|
-
`);
|
|
370
|
-
return css.join("\n");
|
|
371
|
-
}
|
|
372
571
|
function generateGlobalCSS(personality) {
|
|
373
572
|
const personalityText = personality.join(" ").toLowerCase();
|
|
374
573
|
let fontBody = "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
|
|
@@ -428,34 +627,33 @@ input, button, textarea, select {
|
|
|
428
627
|
}
|
|
429
628
|
`;
|
|
430
629
|
}
|
|
431
|
-
function
|
|
630
|
+
function generateTreatmentsContext(themeData, themeName) {
|
|
432
631
|
const lines = [];
|
|
433
|
-
lines.push(`#
|
|
632
|
+
lines.push(`# Visual Treatments: ${themeName}`);
|
|
633
|
+
lines.push("");
|
|
634
|
+
lines.push("## Base Treatments");
|
|
434
635
|
lines.push("");
|
|
435
|
-
lines.push("
|
|
636
|
+
lines.push("d-interactive, d-surface, d-data, d-control, d-section, d-annotation \u2014 see DECANTR.md for usage.");
|
|
436
637
|
lines.push("");
|
|
437
|
-
if (
|
|
438
|
-
lines.push(
|
|
439
|
-
lines.push("
|
|
440
|
-
|
|
441
|
-
|
|
638
|
+
if (themeData?.decorators && Object.keys(themeData.decorators).length > 0) {
|
|
639
|
+
lines.push(`## Theme Decorators (${themeName}-specific)`);
|
|
640
|
+
lines.push("");
|
|
641
|
+
lines.push("| Class | Use for |");
|
|
642
|
+
lines.push("|-------|---------|");
|
|
643
|
+
for (const [name, description] of Object.entries(themeData.decorators)) {
|
|
644
|
+
const useFor = description.split(".")[0].trim();
|
|
645
|
+
lines.push(`| ${name} | ${useFor} |`);
|
|
442
646
|
}
|
|
443
|
-
|
|
444
|
-
lines.push("No decorators defined.");
|
|
647
|
+
lines.push("");
|
|
445
648
|
}
|
|
649
|
+
lines.push("## Composition");
|
|
446
650
|
lines.push("");
|
|
447
|
-
lines.push("
|
|
448
|
-
lines.push("");
|
|
449
|
-
lines.push("Decorators are plain CSS class names from `src/styles/decorators.css`. Combine with atoms:");
|
|
450
|
-
lines.push("");
|
|
651
|
+
lines.push("Atoms + treatment + theme decorator:");
|
|
451
652
|
lines.push("```tsx");
|
|
452
|
-
lines.push(
|
|
453
|
-
lines.push(" <pre className={css('_p3') + ' " + recipeName + "-code'}>{code}</pre>");
|
|
454
|
-
lines.push("</div>");
|
|
653
|
+
lines.push(`css('_flex _col _gap4') + ' d-surface'`);
|
|
455
654
|
lines.push("```");
|
|
456
655
|
lines.push("");
|
|
457
|
-
lines.push("Atoms use `css()` function.
|
|
458
|
-
lines.push("");
|
|
656
|
+
lines.push("Atoms use `css()` function. Treatments and theme decorators are plain class strings.");
|
|
459
657
|
return lines.join("\n");
|
|
460
658
|
}
|
|
461
659
|
function generateDecoratorRule(name, description) {
|
|
@@ -693,7 +891,7 @@ function buildEssence(options, archetypeData) {
|
|
|
693
891
|
style: options.theme,
|
|
694
892
|
mode: options.mode,
|
|
695
893
|
recipe: options.theme,
|
|
696
|
-
//
|
|
894
|
+
// Legacy v2 field — kept for backward compatibility
|
|
697
895
|
shape: options.shape
|
|
698
896
|
},
|
|
699
897
|
personality: options.personality,
|
|
@@ -706,6 +904,7 @@ function buildEssence(options, archetypeData) {
|
|
|
706
904
|
guard: {
|
|
707
905
|
enforce_style: true,
|
|
708
906
|
enforce_recipe: true,
|
|
907
|
+
// Legacy v2 field — kept for backward compatibility
|
|
709
908
|
mode: options.guard
|
|
710
909
|
},
|
|
711
910
|
density: {
|
|
@@ -719,7 +918,7 @@ function buildEssence(options, archetypeData) {
|
|
|
719
918
|
}
|
|
720
919
|
return essence;
|
|
721
920
|
}
|
|
722
|
-
function buildEssenceV3(options, archetypeData, themeHints
|
|
921
|
+
function buildEssenceV3(options, archetypeData, themeHints) {
|
|
723
922
|
let pages = [
|
|
724
923
|
{ id: "home", layout: ["hero"] }
|
|
725
924
|
];
|
|
@@ -756,9 +955,8 @@ function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
|
|
|
756
955
|
};
|
|
757
956
|
const dna = {
|
|
758
957
|
theme: {
|
|
759
|
-
|
|
958
|
+
id: options.theme,
|
|
760
959
|
mode: options.mode,
|
|
761
|
-
recipe: options.theme,
|
|
762
960
|
shape: options.shape
|
|
763
961
|
},
|
|
764
962
|
spacing: {
|
|
@@ -768,9 +966,9 @@ function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
|
|
|
768
966
|
content_gap: densityLevelMap[options.density] || "_gap4"
|
|
769
967
|
},
|
|
770
968
|
typography: {
|
|
771
|
-
scale: themeHints?.
|
|
772
|
-
heading_weight: themeHints?.
|
|
773
|
-
body_weight: themeHints?.
|
|
969
|
+
scale: themeHints?.typography?.scale || "modular",
|
|
970
|
+
heading_weight: themeHints?.typography?.heading_weight || 600,
|
|
971
|
+
body_weight: themeHints?.typography?.body_weight || 400
|
|
774
972
|
},
|
|
775
973
|
color: {
|
|
776
974
|
palette: "semantic",
|
|
@@ -778,17 +976,17 @@ function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
|
|
|
778
976
|
cvd_preference: options.accessibility?.cvd_preference || "auto"
|
|
779
977
|
},
|
|
780
978
|
radius: {
|
|
781
|
-
philosophy:
|
|
782
|
-
base:
|
|
979
|
+
philosophy: themeHints?.radius?.philosophy || options.shape,
|
|
980
|
+
base: themeHints?.radius?.base || shapeRadiusMap[options.shape] || 8
|
|
783
981
|
},
|
|
784
982
|
elevation: {
|
|
785
983
|
system: "layered",
|
|
786
984
|
max_levels: 3
|
|
787
985
|
},
|
|
788
986
|
motion: {
|
|
789
|
-
preference:
|
|
987
|
+
preference: themeHints?.motion?.preference || "subtle",
|
|
790
988
|
duration_scale: 1,
|
|
791
|
-
reduce_motion: themeHints?.
|
|
989
|
+
reduce_motion: themeHints?.motion?.reduce_motion ?? true
|
|
792
990
|
},
|
|
793
991
|
accessibility: {
|
|
794
992
|
wcag_level: options.accessibility?.wcag_level || "AA",
|
|
@@ -820,219 +1018,84 @@ function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
|
|
|
820
1018
|
}
|
|
821
1019
|
var CSS_APPROACH_CONTENT = `## CSS Implementation
|
|
822
1020
|
|
|
823
|
-
This project uses **@decantr/css** for layout atoms
|
|
824
|
-
|
|
825
|
-
### Setup
|
|
1021
|
+
This project uses **@decantr/css** for layout atoms, **visual treatments** for semantic styling, and **theme decorators** for theme-specific decoration.
|
|
826
1022
|
|
|
827
|
-
|
|
828
|
-
// 1. Import the atoms runtime
|
|
829
|
-
import { css } from '@decantr/css';
|
|
1023
|
+
### Three File Setup
|
|
830
1024
|
|
|
831
|
-
// 2. Import generated CSS files (created by decantr init)
|
|
832
|
-
import './styles/tokens.css'; // Theme tokens (--d-primary, --d-surface, etc.)
|
|
833
|
-
import './styles/decorators.css'; // Recipe decorators
|
|
834
1025
|
\`\`\`
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
\`\`\`jsx
|
|
841
|
-
// Layout atoms
|
|
842
|
-
<div className={css('_flex _col _gap4 _p4')}>
|
|
843
|
-
<h1 className={css('_heading1')}>Title</h1>
|
|
844
|
-
<p className={css('_textsm _fgmuted')}>Description</p>
|
|
845
|
-
</div>
|
|
846
|
-
|
|
847
|
-
// Responsive prefixes (mobile-first)
|
|
848
|
-
<div className={css('_gc1 _sm:gc2 _lg:gc4')}>
|
|
849
|
-
{/* 1 col -> 2 cols at 640px -> 4 cols at 1024px */}
|
|
850
|
-
</div>
|
|
1026
|
+
src/styles/
|
|
1027
|
+
tokens.css # Design tokens: --d-primary, --d-surface, --d-bg, etc.
|
|
1028
|
+
treatments.css # Visual treatments (d-interactive, d-surface, ...) + theme decorators
|
|
1029
|
+
global.css # Resets, base typography, sr-only
|
|
851
1030
|
\`\`\`
|
|
852
1031
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
| \`_grid\` | \`display:grid\` |
|
|
860
|
-
| \`_block\` | \`display:block\` |
|
|
861
|
-
| \`_inline\` | \`display:inline\` |
|
|
862
|
-
| \`_inlineflex\` | \`display:inline-flex\` |
|
|
863
|
-
| \`_none\` | \`display:none\` |
|
|
864
|
-
| \`_contents\` | \`display:contents\` |
|
|
865
|
-
|
|
866
|
-
#### Flexbox
|
|
867
|
-
| Atom | CSS |
|
|
868
|
-
|------|-----|
|
|
869
|
-
| \`_col\` | \`flex-direction:column\` |
|
|
870
|
-
| \`_row\` | \`flex-direction:row\` |
|
|
871
|
-
| \`_colrev\` | \`flex-direction:column-reverse\` |
|
|
872
|
-
| \`_wrap\` | \`flex-wrap:wrap\` |
|
|
873
|
-
| \`_nowrap\` | \`flex-wrap:nowrap\` |
|
|
874
|
-
| \`_flex1\` | \`flex:1\` |
|
|
875
|
-
| \`_flex0\` | \`flex:none\` |
|
|
876
|
-
| \`_flexauto\` | \`flex:auto\` |
|
|
877
|
-
| \`_grow\` | \`flex-grow:1\` |
|
|
878
|
-
| \`_grow0\` | \`flex-grow:0\` |
|
|
879
|
-
| \`_shrink0\` | \`flex-shrink:0\` |
|
|
880
|
-
|
|
881
|
-
#### Alignment
|
|
882
|
-
| Atom | CSS |
|
|
883
|
-
|------|-----|
|
|
884
|
-
| \`_aic\` | \`align-items:center\` |
|
|
885
|
-
| \`_aifs\` | \`align-items:flex-start\` |
|
|
886
|
-
| \`_aife\` | \`align-items:flex-end\` |
|
|
887
|
-
| \`_aist\` | \`align-items:stretch\` |
|
|
888
|
-
| \`_aibl\` | \`align-items:baseline\` |
|
|
889
|
-
| \`_jcc\` | \`justify-content:center\` |
|
|
890
|
-
| \`_jcfs\` | \`justify-content:flex-start\` |
|
|
891
|
-
| \`_jcfe\` | \`justify-content:flex-end\` |
|
|
892
|
-
| \`_jcsb\` | \`justify-content:space-between\` |
|
|
893
|
-
| \`_jcsa\` | \`justify-content:space-around\` |
|
|
894
|
-
| \`_jcse\` | \`justify-content:space-evenly\` |
|
|
895
|
-
| \`_pic\` | \`place-items:center\` |
|
|
896
|
-
| \`_pcc\` | \`place-content:center\` |
|
|
897
|
-
|
|
898
|
-
#### Spacing (scale: 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, ...)
|
|
899
|
-
| Atom | CSS | Notes |
|
|
900
|
-
|------|-----|-------|
|
|
901
|
-
| \`_gap{n}\` | \`gap:{scale}\` | e.g. \`_gap4\` = \`gap:1rem\` |
|
|
902
|
-
| \`_gx{n}\` | \`column-gap:{scale}\` | horizontal gap |
|
|
903
|
-
| \`_gy{n}\` | \`row-gap:{scale}\` | vertical gap |
|
|
904
|
-
| \`_p{n}\` | \`padding:{scale}\` | all sides |
|
|
905
|
-
| \`_pt{n}\`, \`_pr{n}\`, \`_pb{n}\`, \`_pl{n}\` | directional padding | top/right/bottom/left |
|
|
906
|
-
| \`_px{n}\` | \`padding-inline:{scale}\` | horizontal |
|
|
907
|
-
| \`_py{n}\` | \`padding-block:{scale}\` | vertical |
|
|
908
|
-
| \`_m{n}\` | \`margin:{scale}\` | same as padding variants |
|
|
909
|
-
| \`_mx{n}\`, \`_my{n}\` | inline/block margin | horizontal/vertical |
|
|
910
|
-
|
|
911
|
-
#### Sizing
|
|
912
|
-
| Atom | CSS |
|
|
913
|
-
|------|-----|
|
|
914
|
-
| \`_wfull\` / \`_w100\` | \`width:100%\` |
|
|
915
|
-
| \`_hfull\` / \`_h100\` | \`height:100%\` |
|
|
916
|
-
| \`_wscreen\` | \`width:100vw\` |
|
|
917
|
-
| \`_hscreen\` | \`height:100vh\` |
|
|
918
|
-
| \`_wfit\` | \`width:fit-content\` |
|
|
919
|
-
| \`_hfit\` | \`height:fit-content\` |
|
|
920
|
-
| \`_wauto\` | \`width:auto\` |
|
|
921
|
-
| \`_minw0\` | \`min-width:0\` |
|
|
922
|
-
| \`_minh0\` | \`min-height:0\` |
|
|
923
|
-
| \`_w{n}\`, \`_h{n}\` | width/height from spacing scale |
|
|
924
|
-
| \`_minw{n}\`, \`_maxw{n}\` | min/max width from scale |
|
|
1032
|
+
\`\`\`javascript
|
|
1033
|
+
import { css } from '@decantr/css'; // Atoms runtime
|
|
1034
|
+
import './styles/tokens.css'; // Theme tokens
|
|
1035
|
+
import './styles/treatments.css'; // Treatments + theme decorators
|
|
1036
|
+
import './styles/global.css'; // Resets
|
|
1037
|
+
\`\`\`
|
|
925
1038
|
|
|
926
|
-
|
|
927
|
-
| Atom | Size | Line-height |
|
|
928
|
-
|------|------|-------------|
|
|
929
|
-
| \`_textxs\` | 0.75rem | 1rem |
|
|
930
|
-
| \`_textsm\` | 0.875rem | 1.25rem |
|
|
931
|
-
| \`_textbase\` | 1rem | 1.5rem |
|
|
932
|
-
| \`_textlg\` | 1.125rem | 1.75rem |
|
|
933
|
-
| \`_textxl\` | 1.25rem | 1.75rem |
|
|
934
|
-
| \`_text2xl\` | 1.5rem | 2rem |
|
|
935
|
-
| \`_text3xl\` | 1.875rem | 2.25rem |
|
|
936
|
-
| \`_heading1\`-\`_heading6\` | Heading presets (size + weight) |
|
|
1039
|
+
### Visual Treatments
|
|
937
1040
|
|
|
938
|
-
|
|
939
|
-
| Atom | CSS |
|
|
940
|
-
|------|-----|
|
|
941
|
-
| \`_fontbold\` | \`font-weight:700\` |
|
|
942
|
-
| \`_fontsemi\` | \`font-weight:600\` |
|
|
943
|
-
| \`_fontmedium\` | \`font-weight:500\` |
|
|
944
|
-
| \`_fontlight\` | \`font-weight:300\` |
|
|
945
|
-
| \`_italic\` | \`font-style:italic\` |
|
|
946
|
-
| \`_underline\` | \`text-decoration:underline\` |
|
|
947
|
-
| \`_uppercase\` | \`text-transform:uppercase\` |
|
|
948
|
-
| \`_truncate\` | overflow ellipsis + nowrap |
|
|
949
|
-
| \`_textl\`, \`_textc\`, \`_textr\` | text-align left/center/right |
|
|
1041
|
+
Six base treatment classes provide semantic styling. Combine with atoms for layout:
|
|
950
1042
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
| \`
|
|
955
|
-
| \`
|
|
956
|
-
| \`
|
|
957
|
-
|
|
|
958
|
-
| \`
|
|
959
|
-
| \`_bgsuccess\`, \`_bgerror\`, \`_bgwarning\`, \`_bginfo\` | status backgrounds |
|
|
960
|
-
| \`_fgprimary\` | \`color:var(--d-primary)\` |
|
|
961
|
-
| \`_fgtext\` | \`color:var(--d-text)\` |
|
|
962
|
-
| \`_fgmuted\` | \`color:var(--d-text-muted)\` |
|
|
963
|
-
| \`_fgsuccess\`, \`_fgerror\`, \`_fgwarning\`, \`_fginfo\` | status text |
|
|
964
|
-
| \`_bcborder\` | \`border-color:var(--d-border)\` |
|
|
1043
|
+
| Treatment | Class | Variants / States |
|
|
1044
|
+
|-----------|-------|-------------------|
|
|
1045
|
+
| **Interactive Surface** | \`d-interactive\` | \`data-variant="primary\\|ghost\\|danger"\`, hover/focus-visible/disabled states |
|
|
1046
|
+
| **Container Surface** | \`d-surface\` | \`data-variant="raised\\|overlay"\`, optional \`data-interactive\` for hover |
|
|
1047
|
+
| **Data Display** | \`d-data\`, \`d-data-header\`, \`d-data-row\`, \`d-data-cell\` | Row hover highlight |
|
|
1048
|
+
| **Form Control** | \`d-control\` | Focus ring, placeholder, disabled, error via \`aria-invalid\` |
|
|
1049
|
+
| **Section Rhythm** | \`d-section\` | Auto-spacing between adjacent sections, density-aware |
|
|
1050
|
+
| **Inline Annotation** | \`d-annotation\` | \`data-status="success\\|error\\|warning\\|info"\` |
|
|
965
1051
|
|
|
966
|
-
|
|
967
|
-
| Atom | CSS |
|
|
968
|
-
|------|-----|
|
|
969
|
-
| \`_overhidden\` | \`overflow:hidden\` |
|
|
970
|
-
| \`_overauto\` | \`overflow:auto\` |
|
|
971
|
-
| \`_overscroll\` | \`overflow:scroll\` |
|
|
972
|
-
| \`_overxauto\`, \`_overyauto\` | axis-specific overflow |
|
|
973
|
-
| \`_nowraptext\` | \`white-space:nowrap\` |
|
|
974
|
-
| \`_prewrap\` | \`white-space:pre-wrap\` |
|
|
975
|
-
| \`_breakword\` | \`overflow-wrap:break-word\` |
|
|
1052
|
+
### Composition
|
|
976
1053
|
|
|
977
|
-
|
|
978
|
-
| Atom | CSS |
|
|
979
|
-
|------|-----|
|
|
980
|
-
| \`_pointer\` | \`cursor:pointer\` |
|
|
981
|
-
| \`_cursordefault\` | \`cursor:default\` |
|
|
982
|
-
| \`_notallowed\` | \`cursor:not-allowed\` |
|
|
983
|
-
| \`_grab\` | \`cursor:grab\` |
|
|
984
|
-
| \`_selectnone\` | \`user-select:none\` |
|
|
985
|
-
| \`_ptrnone\` | \`pointer-events:none\` |
|
|
1054
|
+
Atoms + treatment + theme decorator:
|
|
986
1055
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
| \`_fixed\` | \`position:fixed\` |
|
|
993
|
-
| \`_sticky\` | \`position:sticky\` |
|
|
994
|
-
| \`_inset0\` | \`inset:0\` |
|
|
995
|
-
| \`_top0\`, \`_right0\`, \`_bottom0\`, \`_left0\` | edge positioning |
|
|
996
|
-
| \`_z10\`-\`_z50\` | z-index scale |
|
|
1056
|
+
\`\`\`tsx
|
|
1057
|
+
<button className={css('_px4 _py2') + ' d-interactive'} data-variant="primary">Deploy</button>
|
|
1058
|
+
<div className={css('_flex _col _gap4') + ' d-surface carbon-glass'}>Card</div>
|
|
1059
|
+
<span className="d-annotation" data-status="success">Active</span>
|
|
1060
|
+
\`\`\`
|
|
997
1061
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
| \`_gr1\`-\`_gr6\` | \`grid-template-rows:repeat(N,...)\` |
|
|
1003
|
-
| \`_span1\`-\`_span12\`, \`_spanfull\` | column span |
|
|
1004
|
-
| \`_rowspan1\`-\`_rowspan6\` | row span |
|
|
1062
|
+
- **Atoms:** \`css('_flex _col _gap4')\` \u2014 processed by @decantr/css runtime
|
|
1063
|
+
- **Treatments:** \`d-interactive\`, \`d-surface\` \u2014 semantic base styles from treatments.css
|
|
1064
|
+
- **Theme decorators:** \`carbon-glass\`, \`carbon-code\` \u2014 theme-specific decoration from treatments.css
|
|
1065
|
+
- **Combined:** \`css('_flex _col') + ' d-surface carbon-card'\`
|
|
1005
1066
|
|
|
1006
|
-
|
|
1007
|
-
| Atom | CSS |
|
|
1008
|
-
|------|-----|
|
|
1009
|
-
| \`_rounded\` | \`border-radius:var(--d-radius)\` |
|
|
1010
|
-
| \`_roundedfull\` | \`border-radius:9999px\` |
|
|
1011
|
-
| \`_roundedsm\`, \`_roundedlg\`, \`_roundedxl\` | radius variants |
|
|
1012
|
-
| \`_shadow\`, \`_shadowmd\`, \`_shadowlg\` | box-shadow presets |
|
|
1013
|
-
| \`_bordernone\` | \`border:none\` |
|
|
1014
|
-
| \`_bw{n}\` | \`border-width:{n}px\` |
|
|
1015
|
-
| \`_op0\`-\`_op100\` | opacity (0, 25, 50, 75, 100) |
|
|
1016
|
-
| \`_trans\` | \`transition:all 0.15s ease\` |
|
|
1017
|
-
| \`_visible\`, \`_invisible\` | visibility |
|
|
1067
|
+
### Atoms Quick Reference
|
|
1018
1068
|
|
|
1019
|
-
|
|
1069
|
+
| Category | Examples | Purpose |
|
|
1070
|
+
|----------|----------|---------|
|
|
1071
|
+
| Layout | \`_flex\`, \`_col\`, \`_row\`, \`_wrap\`, \`_grid\` | Flex/grid containers |
|
|
1072
|
+
| Spacing | \`_gap4\`, \`_p4\`, \`_px4\`, \`_py2\`, \`_m0\` | Gaps, padding, margin |
|
|
1073
|
+
| Sizing | \`_w100\`, \`_h100\`, \`_minw0\`, \`_maxwfull\` | Width, height |
|
|
1074
|
+
| Text | \`_textlg\`, \`_text2xl\`, \`_fontbold\`, \`_textc\` | Typography |
|
|
1075
|
+
| Alignment | \`_aic\`, \`_jcc\`, \`_jcsb\`, \`_pic\` | Flex/grid alignment |
|
|
1076
|
+
| Position | \`_rel\`, \`_abs\`, \`_sticky\`, \`_z10\` | Positioning |
|
|
1077
|
+
| Visual | \`_rounded\`, \`_shadow\`, \`_trans\`, \`_op50\` | Decoration |
|
|
1078
|
+
| Color | \`_bgprimary\`, \`_fgtext\`, \`_fgmuted\`, \`_bcborder\` | Theme colors |
|
|
1079
|
+
| Responsive | \`_md:gc2\`, \`_lg:gc4\`, \`_sm:flex\` | Breakpoint prefixes |
|
|
1020
1080
|
|
|
1021
|
-
|
|
1081
|
+
Scale: 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24. Example: \`_gap4\` = \`gap:1rem\`.
|
|
1022
1082
|
|
|
1023
|
-
|
|
1024
|
-
// Atoms use css() function, decorators are plain class names
|
|
1025
|
-
<div className={css('_flex _col _gap4') + ' carbon-card'}>
|
|
1026
|
-
<div className={css('_p4') + ' carbon-glass'}>
|
|
1027
|
-
<pre className={css('_p3') + ' carbon-code'}>{code}</pre>
|
|
1028
|
-
</div>
|
|
1029
|
-
</div>
|
|
1030
|
-
\`\`\`
|
|
1083
|
+
### Design Tokens
|
|
1031
1084
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
-
|
|
1035
|
-
-
|
|
1085
|
+
| Token | Purpose | Use for |
|
|
1086
|
+
|-------|---------|---------|
|
|
1087
|
+
| \`--d-primary\` | Primary brand color | Buttons, links, focus rings |
|
|
1088
|
+
| \`--d-surface\`, \`--d-surface-raised\` | Surface backgrounds | Cards, panels |
|
|
1089
|
+
| \`--d-bg\` | Page background | Body, main container |
|
|
1090
|
+
| \`--d-border\` | Border color | Dividers, card borders |
|
|
1091
|
+
| \`--d-text\`, \`--d-text-muted\` | Text colors | Body text, secondary text |
|
|
1092
|
+
| \`--d-success\`, \`--d-error\`, \`--d-warning\`, \`--d-info\` | Status colors | Alerts, badges, toasts |
|
|
1093
|
+
| \`--d-shadow\`, \`--d-shadow-lg\` | Elevation shadows | Cards, overlays |
|
|
1094
|
+
| \`--d-radius\`, \`--d-radius-lg\` | Border radii | Buttons, cards |
|
|
1095
|
+
| \`--d-font-mono\` | Monospace font stack | Code, metrics, data |
|
|
1096
|
+
| \`--d-duration-hover\` | Hover transition | Interactive elements |
|
|
1097
|
+
| \`--d-easing\` | Animation easing | All transitions |
|
|
1098
|
+
| \`--d-accent-glow\` | Glow color | Hover effects, focus rings |
|
|
1036
1099
|
|
|
1037
1100
|
### Routing
|
|
1038
1101
|
|
|
@@ -1040,28 +1103,7 @@ Check \`decantr.essence.json\` \u2192 \`meta.platform.routing\` for the routing
|
|
|
1040
1103
|
- \`"hash"\` \u2192 use \`HashRouter\` (e.g., for static hosting, GitHub Pages)
|
|
1041
1104
|
- \`"history"\` \u2192 use \`BrowserRouter\` (e.g., for server-rendered apps)
|
|
1042
1105
|
|
|
1043
|
-
Routes are defined in \`decantr.essence.json\` \u2192 \`blueprint.routes\` and listed in \`.decantr/context/scaffold.md
|
|
1044
|
-
|
|
1045
|
-
### CSS Architecture
|
|
1046
|
-
|
|
1047
|
-
The CSS is organized into two parts:
|
|
1048
|
-
|
|
1049
|
-
1. **Atoms (@decantr/css)** - Layout utilities injected at runtime into \`@layer d.atoms\`
|
|
1050
|
-
2. **Generated CSS files** - Theme tokens and recipe decorators created during scaffold
|
|
1051
|
-
|
|
1052
|
-
\`\`\`
|
|
1053
|
-
src/styles/
|
|
1054
|
-
tokens.css # :root { --d-primary: #...; --d-surface: #...; }
|
|
1055
|
-
decorators.css # .recipe-card { ... }
|
|
1056
|
-
\`\`\`
|
|
1057
|
-
|
|
1058
|
-
### Variable Naming Convention
|
|
1059
|
-
|
|
1060
|
-
| Prefix | Purpose | Example |
|
|
1061
|
-
|--------|---------|---------|
|
|
1062
|
-
| \`--d-\` | Core Decantr tokens | \`--d-primary\`, \`--d-bg\` |
|
|
1063
|
-
| \`--d-gap-{n}\` | Spacing tokens | \`--d-gap-4\`, \`--d-gap-8\` |
|
|
1064
|
-
| \`--d-radius\` | Border radius | \`--d-radius\`, \`--d-radius-lg\` |`;
|
|
1106
|
+
Routes are defined in \`decantr.essence.json\` \u2192 \`blueprint.routes\` and listed in \`.decantr/context/scaffold.md\`.`;
|
|
1065
1107
|
function generateDecantrMdV31(guardMode, cssApproach) {
|
|
1066
1108
|
const template = loadTemplate("DECANTR.md.template");
|
|
1067
1109
|
return renderTemplate(template, {
|
|
@@ -1090,8 +1132,7 @@ function generateProjectJson(detected, options, registrySource) {
|
|
|
1090
1132
|
cachedContent: {
|
|
1091
1133
|
archetypes: [],
|
|
1092
1134
|
patterns: [],
|
|
1093
|
-
themes: []
|
|
1094
|
-
recipes: []
|
|
1135
|
+
themes: []
|
|
1095
1136
|
}
|
|
1096
1137
|
},
|
|
1097
1138
|
initialized: {
|
|
@@ -1124,7 +1165,7 @@ function generateTaskContext(templateName, essence) {
|
|
|
1124
1165
|
TARGET: essence.target,
|
|
1125
1166
|
THEME_STYLE: essence.theme.style,
|
|
1126
1167
|
THEME_MODE: essence.theme.mode,
|
|
1127
|
-
THEME_RECIPE: essence.theme.
|
|
1168
|
+
THEME_RECIPE: essence.theme.style,
|
|
1128
1169
|
DEFAULT_SHELL: defaultShell,
|
|
1129
1170
|
GUARD_MODE: essence.guard.mode,
|
|
1130
1171
|
LAYOUT: layout,
|
|
@@ -1148,9 +1189,9 @@ function generateTaskContextV3(templateName, essence) {
|
|
|
1148
1189
|
const contentGap = essence.dna.spacing?.content_gap || "_gap4";
|
|
1149
1190
|
const vars = {
|
|
1150
1191
|
TARGET: essence.meta.target || "react",
|
|
1151
|
-
THEME_STYLE: essence.dna.theme.style,
|
|
1192
|
+
THEME_STYLE: essence.dna.theme.id || essence.dna.theme.style || "",
|
|
1152
1193
|
THEME_MODE: essence.dna.theme.mode,
|
|
1153
|
-
THEME_RECIPE: essence.dna.theme.
|
|
1194
|
+
THEME_RECIPE: essence.dna.theme.id || essence.dna.theme.style || "",
|
|
1154
1195
|
DEFAULT_SHELL: defaultShell,
|
|
1155
1196
|
GUARD_MODE: essence.meta.guard.mode,
|
|
1156
1197
|
LAYOUT: layout,
|
|
@@ -1187,9 +1228,9 @@ ${rows.join("\n")}`;
|
|
|
1187
1228
|
BLUEPRINT: "",
|
|
1188
1229
|
PERSONALITY: (essence.dna.personality || []).join(", "),
|
|
1189
1230
|
TARGET: essence.meta.target ?? "",
|
|
1190
|
-
THEME_STYLE: essence.dna.theme.style,
|
|
1231
|
+
THEME_STYLE: essence.dna.theme.id ?? essence.dna.theme.style ?? "",
|
|
1191
1232
|
THEME_MODE: essence.dna.theme.mode,
|
|
1192
|
-
THEME_RECIPE: essence.dna.theme.
|
|
1233
|
+
THEME_RECIPE: essence.dna.theme.id ?? essence.dna.theme.style ?? "",
|
|
1193
1234
|
SHAPE: essence.dna.theme.shape ?? "",
|
|
1194
1235
|
PAGES_TABLE: pagesTable,
|
|
1195
1236
|
FEATURES_LIST: featuresList,
|
|
@@ -1224,8 +1265,8 @@ ${cacheEntry}
|
|
|
1224
1265
|
return true;
|
|
1225
1266
|
}
|
|
1226
1267
|
}
|
|
1227
|
-
async function scaffoldProject(projectRoot, options, detected, registry, archetypeData, registrySource = "cache", themeData,
|
|
1228
|
-
const essenceV3 = buildEssenceV3(options, archetypeData, themeData
|
|
1268
|
+
async function scaffoldProject(projectRoot, options, detected, registry, archetypeData, registrySource = "cache", themeData, topologyMarkdown, composedSections, routeMap, patternSpecs, blueprintData) {
|
|
1269
|
+
const essenceV3 = buildEssenceV3(options, archetypeData, themeData);
|
|
1229
1270
|
const essence = buildEssence(options, archetypeData);
|
|
1230
1271
|
const decantrDir = join(projectRoot, ".decantr");
|
|
1231
1272
|
const contextDir = join(decantrDir, "context");
|
|
@@ -1261,7 +1302,7 @@ async function scaffoldProject(projectRoot, options, detected, registry, archety
|
|
|
1261
1302
|
}
|
|
1262
1303
|
writeFileSync(essencePath, JSON.stringify(essenceV3, null, 2) + "\n");
|
|
1263
1304
|
}
|
|
1264
|
-
const refreshResult = await refreshDerivedFiles(projectRoot, essenceV3, registry, themeData,
|
|
1305
|
+
const refreshResult = await refreshDerivedFiles(projectRoot, essenceV3, registry, themeData, { isInitialScaffold: true });
|
|
1265
1306
|
contextFiles.push(...refreshResult.contextFiles);
|
|
1266
1307
|
const gitignoreUpdated = updateGitignore(projectRoot);
|
|
1267
1308
|
return {
|
|
@@ -1276,7 +1317,7 @@ async function scaffoldProject(projectRoot, options, detected, registry, archety
|
|
|
1276
1317
|
function scaffoldMinimal(projectRoot) {
|
|
1277
1318
|
const decantrDir = join(projectRoot, ".decantr");
|
|
1278
1319
|
const customDir = join(decantrDir, "custom");
|
|
1279
|
-
const contentTypes = ["patterns", "
|
|
1320
|
+
const contentTypes = ["patterns", "themes", "blueprints", "archetypes", "shells"];
|
|
1280
1321
|
for (const type of contentTypes) {
|
|
1281
1322
|
mkdirSync(join(customDir, type), { recursive: true });
|
|
1282
1323
|
}
|
|
@@ -1284,9 +1325,8 @@ function scaffoldMinimal(projectRoot) {
|
|
|
1284
1325
|
version: "3.0.0",
|
|
1285
1326
|
dna: {
|
|
1286
1327
|
theme: {
|
|
1287
|
-
|
|
1328
|
+
id: "default",
|
|
1288
1329
|
mode: "dark",
|
|
1289
|
-
recipe: "default",
|
|
1290
1330
|
shape: "rounded"
|
|
1291
1331
|
},
|
|
1292
1332
|
spacing: {
|
|
@@ -1368,8 +1408,7 @@ function scaffoldMinimal(projectRoot) {
|
|
|
1368
1408
|
cachedContent: {
|
|
1369
1409
|
archetypes: [],
|
|
1370
1410
|
patterns: [],
|
|
1371
|
-
themes: []
|
|
1372
|
-
recipes: []
|
|
1411
|
+
themes: []
|
|
1373
1412
|
}
|
|
1374
1413
|
},
|
|
1375
1414
|
initialized: {
|
|
@@ -1463,12 +1502,11 @@ When available, use these tools:
|
|
|
1463
1502
|
gitignoreUpdated
|
|
1464
1503
|
};
|
|
1465
1504
|
}
|
|
1466
|
-
async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThemeData,
|
|
1505
|
+
async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThemeData, options) {
|
|
1467
1506
|
const decantrDir = join(projectRoot, ".decantr");
|
|
1468
1507
|
const contextDir = join(decantrDir, "context");
|
|
1469
1508
|
mkdirSync(contextDir, { recursive: true });
|
|
1470
|
-
const themeName = essence.dna.theme.style;
|
|
1471
|
-
const recipeName = essence.dna.theme.recipe ?? themeName;
|
|
1509
|
+
const themeName = essence.dna.theme.id || essence.dna.theme.style || "default";
|
|
1472
1510
|
const mode = essence.dna.theme.mode;
|
|
1473
1511
|
const guardMode = essence.meta.guard.mode;
|
|
1474
1512
|
const guardConfig = {
|
|
@@ -1478,7 +1516,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1478
1516
|
};
|
|
1479
1517
|
const personality = essence.dna.personality || [];
|
|
1480
1518
|
let themeData = prefetchedThemeData;
|
|
1481
|
-
let recipeData = prefetchedRecipeData;
|
|
1482
1519
|
if (!themeData) try {
|
|
1483
1520
|
const themeResult = await registry.fetchTheme(themeName);
|
|
1484
1521
|
if (themeResult?.data) {
|
|
@@ -1489,51 +1526,20 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1489
1526
|
palette: t.palette,
|
|
1490
1527
|
cvd_support: t.cvd_support,
|
|
1491
1528
|
tokens: t.tokens,
|
|
1492
|
-
|
|
1493
|
-
|
|
1529
|
+
typography: t.typography,
|
|
1530
|
+
motion: t.motion,
|
|
1531
|
+
decorators: t.decorators,
|
|
1532
|
+
treatments: t.treatments,
|
|
1533
|
+
spatial: t.spatial,
|
|
1534
|
+
radius: t.radius,
|
|
1535
|
+
shell: t.shell,
|
|
1536
|
+
effects: t.effects,
|
|
1537
|
+
compositions: t.compositions,
|
|
1538
|
+
pattern_preferences: t.pattern_preferences
|
|
1494
1539
|
};
|
|
1495
1540
|
}
|
|
1496
1541
|
} catch {
|
|
1497
1542
|
}
|
|
1498
|
-
if (!recipeData) try {
|
|
1499
|
-
const recipeResult = await registry.fetchRecipe(recipeName);
|
|
1500
|
-
if (recipeResult?.data) {
|
|
1501
|
-
const raw = recipeResult.data;
|
|
1502
|
-
const r = raw.data ?? raw;
|
|
1503
|
-
recipeData = {
|
|
1504
|
-
decorators: r.decorators,
|
|
1505
|
-
spatial_hints: r.spatial_hints,
|
|
1506
|
-
radius_hints: r.radius_hints
|
|
1507
|
-
};
|
|
1508
|
-
if (!recipeData.decorators && raw.data) {
|
|
1509
|
-
const inner = raw.data;
|
|
1510
|
-
if (inner.decorators) {
|
|
1511
|
-
recipeData.decorators = inner.decorators;
|
|
1512
|
-
recipeData.spatial_hints = inner.spatial_hints;
|
|
1513
|
-
recipeData.radius_hints = inner.radius_hints;
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
} catch {
|
|
1518
|
-
}
|
|
1519
|
-
if (!recipeData?.decorators || Object.keys(recipeData.decorators).length === 0) {
|
|
1520
|
-
try {
|
|
1521
|
-
const apiUrl = registry.apiUrl || "https://api.decantr.ai/v1";
|
|
1522
|
-
const resp = await fetch(`${apiUrl}/recipes/@official/${recipeName}`);
|
|
1523
|
-
if (resp.ok) {
|
|
1524
|
-
const apiData = await resp.json();
|
|
1525
|
-
const inner = apiData.data ?? apiData;
|
|
1526
|
-
if (inner.decorators && Object.keys(inner.decorators).length > 0) {
|
|
1527
|
-
recipeData = {
|
|
1528
|
-
decorators: inner.decorators,
|
|
1529
|
-
spatial_hints: inner.spatial_hints,
|
|
1530
|
-
radius_hints: inner.radius_hints
|
|
1531
|
-
};
|
|
1532
|
-
}
|
|
1533
|
-
}
|
|
1534
|
-
} catch {
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
1543
|
if (!themeData?.seed?.primary) {
|
|
1538
1544
|
try {
|
|
1539
1545
|
const apiUrl = registry.apiUrl || "https://api.decantr.ai/v1";
|
|
@@ -1547,8 +1553,16 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1547
1553
|
palette: inner.palette,
|
|
1548
1554
|
cvd_support: inner.cvd_support,
|
|
1549
1555
|
tokens: inner.tokens,
|
|
1550
|
-
|
|
1551
|
-
|
|
1556
|
+
typography: inner.typography,
|
|
1557
|
+
motion: inner.motion,
|
|
1558
|
+
decorators: inner.decorators,
|
|
1559
|
+
treatments: inner.treatments,
|
|
1560
|
+
spatial: inner.spatial,
|
|
1561
|
+
radius: inner.radius,
|
|
1562
|
+
shell: inner.shell,
|
|
1563
|
+
effects: inner.effects,
|
|
1564
|
+
compositions: inner.compositions,
|
|
1565
|
+
pattern_preferences: inner.pattern_preferences
|
|
1552
1566
|
};
|
|
1553
1567
|
}
|
|
1554
1568
|
}
|
|
@@ -1557,27 +1571,35 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1557
1571
|
}
|
|
1558
1572
|
const stylesDir = join(projectRoot, "src", "styles");
|
|
1559
1573
|
mkdirSync(stylesDir, { recursive: true });
|
|
1574
|
+
const densityLevel = options.density || "comfortable";
|
|
1575
|
+
const spatialTokens = computeSpatialTokens(densityLevel, themeData?.spatial ? {
|
|
1576
|
+
section_padding: themeData.spatial.section_padding ?? void 0,
|
|
1577
|
+
density_bias: typeof themeData.spatial.density_bias === "number" ? themeData.spatial.density_bias : void 0,
|
|
1578
|
+
content_gap_shift: themeData.spatial.content_gap_shift
|
|
1579
|
+
} : void 0);
|
|
1560
1580
|
const tokensPath = join(stylesDir, "tokens.css");
|
|
1561
1581
|
const hasRealThemeData = themeData?.seed?.primary || themeData?.palette?.background;
|
|
1562
1582
|
if (hasRealThemeData || !existsSync(tokensPath)) {
|
|
1563
|
-
writeFileSync(tokensPath, generateTokensCSS(themeData, mode));
|
|
1564
|
-
}
|
|
1565
|
-
const
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1583
|
+
writeFileSync(tokensPath, generateTokensCSS(themeData, mode, spatialTokens));
|
|
1584
|
+
}
|
|
1585
|
+
const treatmentsPath = join(stylesDir, "treatments.css");
|
|
1586
|
+
writeFileSync(treatmentsPath, generateTreatmentCSS(
|
|
1587
|
+
spatialTokens,
|
|
1588
|
+
themeData?.treatments,
|
|
1589
|
+
themeData?.decorators,
|
|
1590
|
+
themeName
|
|
1591
|
+
));
|
|
1570
1592
|
const globalPath = join(stylesDir, "global.css");
|
|
1571
1593
|
if (!existsSync(globalPath)) {
|
|
1572
1594
|
writeFileSync(globalPath, generateGlobalCSS(personality));
|
|
1573
1595
|
}
|
|
1574
|
-
const cssFiles = [tokensPath,
|
|
1575
|
-
const
|
|
1576
|
-
writeFileSync(
|
|
1596
|
+
const cssFiles = [tokensPath, treatmentsPath, globalPath];
|
|
1597
|
+
const treatmentsMdPath = join(contextDir, "treatments.md");
|
|
1598
|
+
writeFileSync(treatmentsMdPath, generateTreatmentsContext(themeData, themeName));
|
|
1577
1599
|
const decantrMdPath = join(projectRoot, "DECANTR.md");
|
|
1578
1600
|
writeFileSync(decantrMdPath, generateDecantrMdV31(guardMode, CSS_APPROACH_CONTENT));
|
|
1579
1601
|
const hasSections = essence.blueprint.sections && essence.blueprint.sections.length > 0;
|
|
1580
|
-
const contextFiles = [
|
|
1602
|
+
const contextFiles = [treatmentsMdPath];
|
|
1581
1603
|
if (!hasSections) {
|
|
1582
1604
|
const summaryPath = join(contextDir, "essence-summary.md");
|
|
1583
1605
|
writeFileSync(summaryPath, generateEssenceSummaryV3(essence));
|
|
@@ -1675,8 +1697,8 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1675
1697
|
const topologyMarkdown = generateTopologySection(topologyData, personality);
|
|
1676
1698
|
const themeTokensCss = existsSync(tokensPath) ? readFileSync(tokensPath, "utf-8") : "";
|
|
1677
1699
|
const decoratorList = [];
|
|
1678
|
-
if (
|
|
1679
|
-
for (const [name, desc] of Object.entries(
|
|
1700
|
+
if (themeData?.decorators) {
|
|
1701
|
+
for (const [name, desc] of Object.entries(themeData.decorators)) {
|
|
1680
1702
|
decoratorList.push({ name, description: desc });
|
|
1681
1703
|
}
|
|
1682
1704
|
} else if (existsSync(decoratorsPath)) {
|
|
@@ -1744,7 +1766,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1744
1766
|
guardConfig,
|
|
1745
1767
|
personality,
|
|
1746
1768
|
themeName,
|
|
1747
|
-
recipeName,
|
|
1748
1769
|
zoneContext,
|
|
1749
1770
|
patternSpecs: sectionPatterns,
|
|
1750
1771
|
constraints: essence.dna.constraints,
|
|
@@ -1759,7 +1780,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1759
1780
|
appName: essence.meta.archetype || "Application",
|
|
1760
1781
|
blueprintId: "",
|
|
1761
1782
|
themeName,
|
|
1762
|
-
recipeName,
|
|
1763
1783
|
personality,
|
|
1764
1784
|
topologyMarkdown,
|
|
1765
1785
|
sections,
|
|
@@ -1834,8 +1854,8 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1834
1854
|
}
|
|
1835
1855
|
const themeTokensCss = existsSync(tokensPath) ? readFileSync(tokensPath, "utf-8") : "";
|
|
1836
1856
|
const decoratorList = [];
|
|
1837
|
-
if (
|
|
1838
|
-
for (const [name, desc] of Object.entries(
|
|
1857
|
+
if (themeData?.decorators) {
|
|
1858
|
+
for (const [name, desc] of Object.entries(themeData.decorators)) {
|
|
1839
1859
|
decoratorList.push({ name, description: desc });
|
|
1840
1860
|
}
|
|
1841
1861
|
} else if (existsSync(decoratorsPath)) {
|
|
@@ -1873,7 +1893,6 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1873
1893
|
guardConfig,
|
|
1874
1894
|
personality,
|
|
1875
1895
|
themeName,
|
|
1876
|
-
recipeName,
|
|
1877
1896
|
zoneContext: `This is the primary section (${shell} shell).`,
|
|
1878
1897
|
patternSpecs,
|
|
1879
1898
|
constraints: essence.dna.constraints,
|
|
@@ -1977,7 +1996,7 @@ function generateSyntheticComponents(patternId, description) {
|
|
|
1977
1996
|
return [...new Set(syntheticComponents)];
|
|
1978
1997
|
}
|
|
1979
1998
|
function generateSectionContext(input) {
|
|
1980
|
-
const { section, decorators, guardConfig, personality, themeName,
|
|
1999
|
+
const { section, decorators, guardConfig, personality, themeName, zoneContext, patternSpecs, themeHints, constraints, shellInfo } = input;
|
|
1981
2000
|
const lines = [];
|
|
1982
2001
|
lines.push(`# Section: ${section.id}`);
|
|
1983
2002
|
lines.push("");
|
|
@@ -2002,23 +2021,21 @@ function generateSectionContext(input) {
|
|
|
2002
2021
|
lines.push("");
|
|
2003
2022
|
lines.push(`**Theme tokens:** see \`src/styles/tokens.css\` \u2014 use \`var(--d-primary)\`, \`var(--d-bg)\`, etc.`);
|
|
2004
2023
|
lines.push("");
|
|
2024
|
+
lines.push("**Visual Treatments:** All 6 base treatments available (see DECANTR.md for usage).");
|
|
2005
2025
|
if (decorators.length > 0) {
|
|
2006
|
-
const names = decorators.map((d) =>
|
|
2007
|
-
lines.push(`**
|
|
2008
|
-
lines.push("Usage: `className={css('_flex _col') + ' carbon-card'}` \u2014 atoms via css(), decorators as plain class strings.");
|
|
2009
|
-
} else {
|
|
2010
|
-
lines.push("**Decorators:** none defined.");
|
|
2026
|
+
const names = decorators.map((d) => d.name).join(", ");
|
|
2027
|
+
lines.push(`**Theme decorators:** ${names}`);
|
|
2011
2028
|
}
|
|
2012
2029
|
lines.push("");
|
|
2013
|
-
if (
|
|
2014
|
-
if (
|
|
2015
|
-
lines.push(`**Preferred:** ${
|
|
2030
|
+
if (themeHints) {
|
|
2031
|
+
if (themeHints.preferred && themeHints.preferred.length > 0) {
|
|
2032
|
+
lines.push(`**Preferred:** ${themeHints.preferred.join(", ")}`);
|
|
2016
2033
|
}
|
|
2017
|
-
if (
|
|
2018
|
-
lines.push(`**Compositions:** ${
|
|
2034
|
+
if (themeHints.compositions) {
|
|
2035
|
+
lines.push(`**Compositions:** ${themeHints.compositions}`);
|
|
2019
2036
|
}
|
|
2020
|
-
if (
|
|
2021
|
-
lines.push(`**Spatial hints:** ${
|
|
2037
|
+
if (themeHints.spatialHints) {
|
|
2038
|
+
lines.push(`**Spatial hints:** ${themeHints.spatialHints}`);
|
|
2022
2039
|
}
|
|
2023
2040
|
lines.push("");
|
|
2024
2041
|
}
|
|
@@ -2103,12 +2120,12 @@ function generateSectionContext(input) {
|
|
|
2103
2120
|
return lines.join("\n");
|
|
2104
2121
|
}
|
|
2105
2122
|
function generateScaffoldContext(input) {
|
|
2106
|
-
const { appName, blueprintId, themeName,
|
|
2123
|
+
const { appName, blueprintId, themeName, personality, topologyMarkdown, sections, routes, constraints, seo, navigation } = input;
|
|
2107
2124
|
const lines = [];
|
|
2108
2125
|
lines.push(`# Scaffold: ${appName}`);
|
|
2109
2126
|
lines.push("");
|
|
2110
2127
|
lines.push(`**Blueprint:** ${blueprintId}`);
|
|
2111
|
-
lines.push(`**Theme:** ${themeName}
|
|
2128
|
+
lines.push(`**Theme:** ${themeName}`);
|
|
2112
2129
|
lines.push(`**Personality:** ${personality.join(", ")}`);
|
|
2113
2130
|
lines.push("**Guard mode:** creative (no enforcement during initial scaffolding)");
|
|
2114
2131
|
lines.push("");
|
|
@@ -2203,7 +2220,7 @@ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as rea
|
|
|
2203
2220
|
import { join as join2 } from "path";
|
|
2204
2221
|
import { RegistryAPIClient } from "@decantr/registry";
|
|
2205
2222
|
var DEFAULT_API_URL = "https://api.decantr.ai/v1";
|
|
2206
|
-
var ALL_CONTENT_TYPES = ["themes", "patterns", "
|
|
2223
|
+
var ALL_CONTENT_TYPES = ["themes", "patterns", "blueprints", "archetypes", "shells"];
|
|
2207
2224
|
function loadFromCache(cacheDir, contentType, id, namespace) {
|
|
2208
2225
|
const nsDir = namespace ? join2(cacheDir, namespace) : cacheDir;
|
|
2209
2226
|
const cachePath = id ? join2(nsDir, contentType, `${id}.json`) : join2(nsDir, contentType, "index.json");
|
|
@@ -2367,12 +2384,6 @@ var RegistryClient = class {
|
|
|
2367
2384
|
async fetchShell(id) {
|
|
2368
2385
|
return this.fetchContentItem("shells", id);
|
|
2369
2386
|
}
|
|
2370
|
-
async fetchRecipes() {
|
|
2371
|
-
return this.fetchContentList("recipes");
|
|
2372
|
-
}
|
|
2373
|
-
async fetchRecipe(id) {
|
|
2374
|
-
return this.fetchContentItem("recipes", id);
|
|
2375
|
-
}
|
|
2376
2387
|
/**
|
|
2377
2388
|
* Check if API is available.
|
|
2378
2389
|
*/
|