@decantr/cli 1.5.0 → 1.5.3
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-6K6ZPDT4.js → chunk-B5OX2EXL.js} +565 -359
- package/dist/{chunk-SUNMRG3P.js → chunk-QZVA3PFR.js} +1381 -255
- package/dist/heal-54MKDDSQ.js +155 -0
- package/dist/index.js +2 -2
- package/dist/{upgrade-I2RUTNAT.js → upgrade-LTLUPBZQ.js} +1 -1
- package/package.json +6 -6
- package/LICENSE +0 -21
- package/dist/heal-ZG5VJZ5J.js +0 -60
|
@@ -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, recipeDecorators, recipeName) {
|
|
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 (recipeDecorators && Object.keys(recipeDecorators).length > 0) {
|
|
189
|
+
const label = recipeName ? ` (${recipeName})` : "";
|
|
190
|
+
lines.push(`/* \u2500\u2500 Layer 3: Recipe Decorators${label} \u2500\u2500 */`);
|
|
191
|
+
lines.push("");
|
|
192
|
+
for (const [name, description] of Object.entries(recipeDecorators)) {
|
|
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
|
}
|
|
@@ -298,11 +507,11 @@ function generateTokensCSS(themeData, mode) {
|
|
|
298
507
|
"--d-radius-lg": "0.75rem",
|
|
299
508
|
"--d-radius-xl": "1rem",
|
|
300
509
|
"--d-radius-full": "9999px",
|
|
301
|
-
// Shadows
|
|
302
|
-
"--d-shadow-sm": "0 1px 2px rgba(0,0,0,0.05)",
|
|
303
|
-
"--d-shadow": "0 1px 3px rgba(0,0,0,0.1)",
|
|
304
|
-
"--d-shadow-md": "0 4px 6px rgba(0,0,0,0.1)",
|
|
305
|
-
"--d-shadow-lg": "0 10px 15px rgba(0,0,0,0.1)",
|
|
510
|
+
// Shadows — dark mode needs higher opacity to be visible on dark backgrounds
|
|
511
|
+
"--d-shadow-sm": tokenMode === "light" ? "0 1px 2px rgba(0,0,0,0.05)" : "0 1px 2px rgba(0,0,0,0.2)",
|
|
512
|
+
"--d-shadow": tokenMode === "light" ? "0 1px 3px rgba(0,0,0,0.1)" : "0 1px 3px rgba(0,0,0,0.25)",
|
|
513
|
+
"--d-shadow-md": tokenMode === "light" ? "0 4px 6px rgba(0,0,0,0.1)" : "0 4px 6px rgba(0,0,0,0.3)",
|
|
514
|
+
"--d-shadow-lg": tokenMode === "light" ? "0 10px 15px rgba(0,0,0,0.1)" : "0 10px 15px rgba(0,0,0,0.4)",
|
|
306
515
|
// Status colors
|
|
307
516
|
"--d-success": themeData.tokens?.base?.success || "#22c55e",
|
|
308
517
|
"--d-error": themeData.tokens?.base?.danger || "#ef4444",
|
|
@@ -312,14 +521,27 @@ function generateTokensCSS(themeData, mode) {
|
|
|
312
521
|
}
|
|
313
522
|
const tokens = buildTokens(resolvedMode);
|
|
314
523
|
const lines = Object.entries(tokens).map(([key, value]) => ` ${key}: ${value};`).join("\n");
|
|
524
|
+
const spatialLines = spatialTokens ? "\n" + Object.entries(spatialTokens).map(([k, v]) => ` ${k}: ${v};`).join("\n") : "";
|
|
315
525
|
let css = `/* Generated by @decantr/cli */
|
|
316
526
|
:root {
|
|
317
|
-
${lines}
|
|
527
|
+
${lines}${spatialLines}
|
|
318
528
|
}
|
|
319
529
|
`;
|
|
320
530
|
if (mode === "auto") {
|
|
321
531
|
const lightTokens = buildTokens("light");
|
|
322
|
-
const paletteKeys = [
|
|
532
|
+
const paletteKeys = [
|
|
533
|
+
"--d-bg",
|
|
534
|
+
"--d-surface",
|
|
535
|
+
"--d-surface-raised",
|
|
536
|
+
"--d-border",
|
|
537
|
+
"--d-text",
|
|
538
|
+
"--d-text-muted",
|
|
539
|
+
"--d-primary-hover",
|
|
540
|
+
"--d-shadow-sm",
|
|
541
|
+
"--d-shadow",
|
|
542
|
+
"--d-shadow-md",
|
|
543
|
+
"--d-shadow-lg"
|
|
544
|
+
];
|
|
323
545
|
const lightLines = Object.entries(lightTokens).filter(([key]) => paletteKeys.includes(key)).map(([key, value]) => ` ${key}: ${value};`).join("\n");
|
|
324
546
|
css += `
|
|
325
547
|
@media (prefers-color-scheme: light) {
|
|
@@ -331,65 +553,103 @@ ${lightLines}
|
|
|
331
553
|
}
|
|
332
554
|
return css;
|
|
333
555
|
}
|
|
334
|
-
function
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
@keyframes decantr-fade-in {
|
|
349
|
-
from { opacity: 0; transform: translateY(8px); }
|
|
350
|
-
to { opacity: 1; transform: translateY(0); }
|
|
556
|
+
function generateGlobalCSS(personality) {
|
|
557
|
+
const personalityText = personality.join(" ").toLowerCase();
|
|
558
|
+
let fontBody = "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
|
|
559
|
+
if (personalityText.includes("inter")) {
|
|
560
|
+
fontBody = `'Inter', ${fontBody}`;
|
|
561
|
+
} else if (personalityText.includes("geist")) {
|
|
562
|
+
fontBody = `'Geist', ${fontBody}`;
|
|
563
|
+
}
|
|
564
|
+
return `/* Generated by @decantr/cli \u2014 global reset + body styles */
|
|
565
|
+
|
|
566
|
+
*, *::before, *::after {
|
|
567
|
+
box-sizing: border-box;
|
|
568
|
+
margin: 0;
|
|
569
|
+
padding: 0;
|
|
351
570
|
}
|
|
352
571
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
572
|
+
html {
|
|
573
|
+
color-scheme: dark;
|
|
574
|
+
-webkit-font-smoothing: antialiased;
|
|
575
|
+
-moz-osx-font-smoothing: grayscale;
|
|
576
|
+
text-rendering: optimizeLegibility;
|
|
356
577
|
}
|
|
357
|
-
|
|
358
|
-
|
|
578
|
+
|
|
579
|
+
body {
|
|
580
|
+
font-family: ${fontBody};
|
|
581
|
+
background: var(--d-bg);
|
|
582
|
+
color: var(--d-text);
|
|
583
|
+
line-height: 1.6;
|
|
584
|
+
min-height: 100dvh;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
img, picture, video, canvas, svg {
|
|
588
|
+
display: block;
|
|
589
|
+
max-width: 100%;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
input, button, textarea, select {
|
|
593
|
+
font: inherit;
|
|
594
|
+
color: inherit;
|
|
359
595
|
}
|
|
360
|
-
|
|
596
|
+
|
|
597
|
+
:focus-visible {
|
|
598
|
+
outline: 2px solid var(--d-primary);
|
|
599
|
+
outline-offset: 2px;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.sr-only {
|
|
603
|
+
position: absolute;
|
|
604
|
+
width: 1px;
|
|
605
|
+
height: 1px;
|
|
606
|
+
padding: 0;
|
|
607
|
+
margin: -1px;
|
|
608
|
+
overflow: hidden;
|
|
609
|
+
clip: rect(0, 0, 0, 0);
|
|
610
|
+
white-space: nowrap;
|
|
611
|
+
border-width: 0;
|
|
612
|
+
}
|
|
613
|
+
`;
|
|
614
|
+
}
|
|
615
|
+
function generateTreatmentsContext(recipeData, recipeName) {
|
|
361
616
|
const lines = [];
|
|
362
|
-
lines.push(`#
|
|
617
|
+
lines.push(`# Visual Treatments: ${recipeName}`);
|
|
618
|
+
lines.push("");
|
|
619
|
+
lines.push("## Base Treatments");
|
|
363
620
|
lines.push("");
|
|
364
|
-
lines.push("
|
|
621
|
+
lines.push("d-interactive, d-surface, d-data, d-control, d-section, d-annotation \u2014 see DECANTR.md for usage.");
|
|
365
622
|
lines.push("");
|
|
366
623
|
if (recipeData?.decorators && Object.keys(recipeData.decorators).length > 0) {
|
|
367
|
-
lines.push(
|
|
368
|
-
lines.push("
|
|
624
|
+
lines.push(`## Recipe Decorators (${recipeName}-specific)`);
|
|
625
|
+
lines.push("");
|
|
626
|
+
lines.push("| Class | Use for |");
|
|
627
|
+
lines.push("|-------|---------|");
|
|
369
628
|
for (const [name, description] of Object.entries(recipeData.decorators)) {
|
|
370
|
-
|
|
629
|
+
const useFor = description.split(".")[0].trim();
|
|
630
|
+
lines.push(`| ${name} | ${useFor} |`);
|
|
371
631
|
}
|
|
372
|
-
|
|
373
|
-
lines.push("No decorators defined.");
|
|
632
|
+
lines.push("");
|
|
374
633
|
}
|
|
634
|
+
lines.push("## Composition");
|
|
375
635
|
lines.push("");
|
|
376
|
-
lines.push("
|
|
377
|
-
lines.push("");
|
|
378
|
-
lines.push("Decorators are plain CSS class names from `src/styles/decorators.css`. Combine with atoms:");
|
|
379
|
-
lines.push("");
|
|
636
|
+
lines.push("Atoms + treatment + recipe decorator:");
|
|
380
637
|
lines.push("```tsx");
|
|
381
|
-
lines.push(
|
|
382
|
-
lines.push(" <pre className={css('_p3') + ' " + recipeName + "-code'}>{code}</pre>");
|
|
383
|
-
lines.push("</div>");
|
|
638
|
+
lines.push(`css('_flex _col _gap4') + ' d-surface'`);
|
|
384
639
|
lines.push("```");
|
|
385
640
|
lines.push("");
|
|
386
|
-
lines.push("Atoms use `css()` function.
|
|
387
|
-
lines.push("");
|
|
641
|
+
lines.push("Atoms use `css()` function. Treatments and recipe decorators are plain class strings.");
|
|
388
642
|
return lines.join("\n");
|
|
389
643
|
}
|
|
390
644
|
function generateDecoratorRule(name, description) {
|
|
391
645
|
const rules = [];
|
|
392
646
|
const descLower = description.toLowerCase();
|
|
647
|
+
const nameLower = name.toLowerCase();
|
|
648
|
+
const isCard = descLower.includes("card") || descLower.includes("panel") || nameLower.includes("card") || nameLower.includes("panel");
|
|
649
|
+
const isInput = descLower.includes("input") || descLower.includes("field") || descLower.includes("textarea") || nameLower.includes("input") || nameLower.includes("textarea");
|
|
650
|
+
const isGlass = descLower.includes("glassmorphic") || descLower.includes("glass") || nameLower.includes("glass");
|
|
651
|
+
const isInteractive = isCard || isInput || isGlass;
|
|
652
|
+
const isNonInteractive = descLower.includes("divider") || descLower.includes("skeleton") || descLower.includes("keyframe") || descLower.includes("canvas") || nameLower.includes("divider") || nameLower.includes("skeleton") || nameLower.includes("canvas");
|
|
393
653
|
if (descLower.includes("monospace") || descLower.includes("mono font")) {
|
|
394
654
|
rules.push("font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace");
|
|
395
655
|
}
|
|
@@ -402,6 +662,16 @@ function generateDecoratorRule(name, description) {
|
|
|
402
662
|
} else if (descLower.includes("primary-tinted") || descLower.includes("primary background")) {
|
|
403
663
|
rules.push("background: color-mix(in srgb, var(--d-primary) 15%, var(--d-surface))");
|
|
404
664
|
}
|
|
665
|
+
if (isInput) {
|
|
666
|
+
if (!rules.some((r) => r.startsWith("background"))) {
|
|
667
|
+
rules.push("background: var(--d-surface)");
|
|
668
|
+
}
|
|
669
|
+
rules.push("color: var(--d-text)");
|
|
670
|
+
rules.push("padding: 0.5rem 0.75rem");
|
|
671
|
+
rules.push("border-radius: var(--d-radius)");
|
|
672
|
+
rules.push("width: 100%");
|
|
673
|
+
rules.push("outline: none");
|
|
674
|
+
}
|
|
405
675
|
const leftBorderMatch = descLower.match(/(\d+)px\s+left\s+border/);
|
|
406
676
|
if (leftBorderMatch) {
|
|
407
677
|
rules.push(`border-left: ${leftBorderMatch[1]}px solid var(--d-primary)`);
|
|
@@ -415,23 +685,40 @@ function generateDecoratorRule(name, description) {
|
|
|
415
685
|
const radiusMatch = descLower.match(/(\d+)px radius/);
|
|
416
686
|
if (radiusMatch) {
|
|
417
687
|
rules.push(`border-radius: ${radiusMatch[1]}px`);
|
|
418
|
-
} else if (descLower.includes("radius") || descLower.includes("rounded")) {
|
|
688
|
+
} else if ((descLower.includes("radius") || descLower.includes("rounded")) && !isInput) {
|
|
419
689
|
rules.push("border-radius: var(--d-radius)");
|
|
420
690
|
}
|
|
421
|
-
if (descLower.includes("hover shadow") || descLower.includes("shadow transition")) {
|
|
422
|
-
rules.push("transition: box-shadow 0.15s ease");
|
|
423
|
-
}
|
|
424
691
|
if (descLower.includes("elevation") || descLower.includes("shadow")) {
|
|
425
692
|
rules.push("box-shadow: var(--d-shadow)");
|
|
426
693
|
}
|
|
694
|
+
if (isInteractive && !isNonInteractive) {
|
|
695
|
+
rules.push("transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease");
|
|
696
|
+
}
|
|
427
697
|
if (descLower.includes("entrance animation") || descLower.includes("fade")) {
|
|
428
698
|
rules.push("animation: decantr-fade-in 0.2s ease-out");
|
|
429
699
|
}
|
|
430
700
|
if (descLower.includes("pulse animation") || descLower.includes("skeleton")) {
|
|
431
701
|
rules.push("animation: decantr-pulse 1.5s ease-in-out infinite");
|
|
432
702
|
}
|
|
433
|
-
|
|
703
|
+
const blurMatch = descLower.match(/blur\((\d+)px\)/);
|
|
704
|
+
if (blurMatch) {
|
|
705
|
+
rules.push(`backdrop-filter: blur(${blurMatch[1]}px)`);
|
|
706
|
+
rules.push(`-webkit-backdrop-filter: blur(${blurMatch[1]}px)`);
|
|
707
|
+
} else if (isGlass) {
|
|
708
|
+
rules.push("backdrop-filter: blur(12px)");
|
|
709
|
+
rules.push("-webkit-backdrop-filter: blur(12px)");
|
|
710
|
+
} else if (descLower.includes("blur")) {
|
|
434
711
|
rules.push("backdrop-filter: blur(8px)");
|
|
712
|
+
rules.push("-webkit-backdrop-filter: blur(8px)");
|
|
713
|
+
}
|
|
714
|
+
if (descLower.includes("semi-transparent") || descLower.includes("glassmorphic")) {
|
|
715
|
+
const bgIdx = rules.findIndex((r) => r.startsWith("background:"));
|
|
716
|
+
const rgbaBg = "background: rgba(31, 31, 35, 0.8)";
|
|
717
|
+
if (bgIdx !== -1) {
|
|
718
|
+
rules[bgIdx] = rgbaBg;
|
|
719
|
+
} else {
|
|
720
|
+
rules.push(rgbaBg);
|
|
721
|
+
}
|
|
435
722
|
}
|
|
436
723
|
if (descLower.includes("right-aligned")) {
|
|
437
724
|
rules.push("margin-left: auto");
|
|
@@ -455,9 +742,33 @@ function generateDecoratorRule(name, description) {
|
|
|
455
742
|
if (rules.length === 0) {
|
|
456
743
|
return `/* .${name}: ${description} */`;
|
|
457
744
|
}
|
|
458
|
-
|
|
745
|
+
let css = `.${name} {
|
|
459
746
|
${rules.join(";\n ")};
|
|
460
747
|
}`;
|
|
748
|
+
if (isInteractive && !isNonInteractive) {
|
|
749
|
+
const stateRules = [];
|
|
750
|
+
if (isCard || isGlass) {
|
|
751
|
+
stateRules.push(`.${name}:hover {
|
|
752
|
+
border-color: var(--d-primary-hover, var(--d-border));
|
|
753
|
+
box-shadow: var(--d-shadow-md);
|
|
754
|
+
}`);
|
|
755
|
+
}
|
|
756
|
+
if (isInput) {
|
|
757
|
+
stateRules.push(`.${name}:focus {
|
|
758
|
+
border-color: var(--d-primary);
|
|
759
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--d-primary) 25%, transparent);
|
|
760
|
+
}`);
|
|
761
|
+
stateRules.push(`.${name}::placeholder {
|
|
762
|
+
color: var(--d-text-muted);
|
|
763
|
+
}`);
|
|
764
|
+
stateRules.push(`.${name}:disabled {
|
|
765
|
+
opacity: 0.5;
|
|
766
|
+
cursor: not-allowed;
|
|
767
|
+
}`);
|
|
768
|
+
}
|
|
769
|
+
css += "\n\n" + stateRules.join("\n\n");
|
|
770
|
+
}
|
|
771
|
+
return css;
|
|
461
772
|
}
|
|
462
773
|
function serializeLayoutItem(item) {
|
|
463
774
|
if (typeof item === "string") {
|
|
@@ -692,219 +1003,80 @@ function buildEssenceV3(options, archetypeData, themeHints, recipeHints) {
|
|
|
692
1003
|
}
|
|
693
1004
|
var CSS_APPROACH_CONTENT = `## CSS Implementation
|
|
694
1005
|
|
|
695
|
-
This project uses **@decantr/css** for layout atoms
|
|
1006
|
+
This project uses **@decantr/css** for layout atoms, **visual treatments** for semantic styling, and **recipe decorators** for theme-specific decoration.
|
|
696
1007
|
|
|
697
|
-
### Setup
|
|
698
|
-
|
|
699
|
-
\`\`\`javascript
|
|
700
|
-
// 1. Import the atoms runtime
|
|
701
|
-
import { css } from '@decantr/css';
|
|
1008
|
+
### Three File Setup
|
|
702
1009
|
|
|
703
|
-
// 2. Import generated CSS files (created by decantr init)
|
|
704
|
-
import './styles/tokens.css'; // Theme tokens (--d-primary, --d-surface, etc.)
|
|
705
|
-
import './styles/decorators.css'; // Recipe decorators
|
|
706
1010
|
\`\`\`
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
\`\`\`jsx
|
|
713
|
-
// Layout atoms
|
|
714
|
-
<div className={css('_flex _col _gap4 _p4')}>
|
|
715
|
-
<h1 className={css('_heading1')}>Title</h1>
|
|
716
|
-
<p className={css('_textsm _fgmuted')}>Description</p>
|
|
717
|
-
</div>
|
|
718
|
-
|
|
719
|
-
// Responsive prefixes (mobile-first)
|
|
720
|
-
<div className={css('_gc1 _sm:gc2 _lg:gc4')}>
|
|
721
|
-
{/* 1 col -> 2 cols at 640px -> 4 cols at 1024px */}
|
|
722
|
-
</div>
|
|
1011
|
+
src/styles/
|
|
1012
|
+
tokens.css # Design tokens: --d-primary, --d-surface, --d-bg, etc.
|
|
1013
|
+
treatments.css # Visual treatments (d-interactive, d-surface, ...) + recipe decorators
|
|
1014
|
+
global.css # Resets, base typography, sr-only
|
|
723
1015
|
\`\`\`
|
|
724
1016
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
| \`_grid\` | \`display:grid\` |
|
|
732
|
-
| \`_block\` | \`display:block\` |
|
|
733
|
-
| \`_inline\` | \`display:inline\` |
|
|
734
|
-
| \`_inlineflex\` | \`display:inline-flex\` |
|
|
735
|
-
| \`_none\` | \`display:none\` |
|
|
736
|
-
| \`_contents\` | \`display:contents\` |
|
|
737
|
-
|
|
738
|
-
#### Flexbox
|
|
739
|
-
| Atom | CSS |
|
|
740
|
-
|------|-----|
|
|
741
|
-
| \`_col\` | \`flex-direction:column\` |
|
|
742
|
-
| \`_row\` | \`flex-direction:row\` |
|
|
743
|
-
| \`_colrev\` | \`flex-direction:column-reverse\` |
|
|
744
|
-
| \`_wrap\` | \`flex-wrap:wrap\` |
|
|
745
|
-
| \`_nowrap\` | \`flex-wrap:nowrap\` |
|
|
746
|
-
| \`_flex1\` | \`flex:1\` |
|
|
747
|
-
| \`_flex0\` | \`flex:none\` |
|
|
748
|
-
| \`_flexauto\` | \`flex:auto\` |
|
|
749
|
-
| \`_grow\` | \`flex-grow:1\` |
|
|
750
|
-
| \`_grow0\` | \`flex-grow:0\` |
|
|
751
|
-
| \`_shrink0\` | \`flex-shrink:0\` |
|
|
752
|
-
|
|
753
|
-
#### Alignment
|
|
754
|
-
| Atom | CSS |
|
|
755
|
-
|------|-----|
|
|
756
|
-
| \`_aic\` | \`align-items:center\` |
|
|
757
|
-
| \`_aifs\` | \`align-items:flex-start\` |
|
|
758
|
-
| \`_aife\` | \`align-items:flex-end\` |
|
|
759
|
-
| \`_aist\` | \`align-items:stretch\` |
|
|
760
|
-
| \`_aibl\` | \`align-items:baseline\` |
|
|
761
|
-
| \`_jcc\` | \`justify-content:center\` |
|
|
762
|
-
| \`_jcfs\` | \`justify-content:flex-start\` |
|
|
763
|
-
| \`_jcfe\` | \`justify-content:flex-end\` |
|
|
764
|
-
| \`_jcsb\` | \`justify-content:space-between\` |
|
|
765
|
-
| \`_jcsa\` | \`justify-content:space-around\` |
|
|
766
|
-
| \`_jcse\` | \`justify-content:space-evenly\` |
|
|
767
|
-
| \`_pic\` | \`place-items:center\` |
|
|
768
|
-
| \`_pcc\` | \`place-content:center\` |
|
|
769
|
-
|
|
770
|
-
#### Spacing (scale: 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, ...)
|
|
771
|
-
| Atom | CSS | Notes |
|
|
772
|
-
|------|-----|-------|
|
|
773
|
-
| \`_gap{n}\` | \`gap:{scale}\` | e.g. \`_gap4\` = \`gap:1rem\` |
|
|
774
|
-
| \`_gx{n}\` | \`column-gap:{scale}\` | horizontal gap |
|
|
775
|
-
| \`_gy{n}\` | \`row-gap:{scale}\` | vertical gap |
|
|
776
|
-
| \`_p{n}\` | \`padding:{scale}\` | all sides |
|
|
777
|
-
| \`_pt{n}\`, \`_pr{n}\`, \`_pb{n}\`, \`_pl{n}\` | directional padding | top/right/bottom/left |
|
|
778
|
-
| \`_px{n}\` | \`padding-inline:{scale}\` | horizontal |
|
|
779
|
-
| \`_py{n}\` | \`padding-block:{scale}\` | vertical |
|
|
780
|
-
| \`_m{n}\` | \`margin:{scale}\` | same as padding variants |
|
|
781
|
-
| \`_mx{n}\`, \`_my{n}\` | inline/block margin | horizontal/vertical |
|
|
1017
|
+
\`\`\`javascript
|
|
1018
|
+
import { css } from '@decantr/css'; // Atoms runtime
|
|
1019
|
+
import './styles/tokens.css'; // Theme tokens
|
|
1020
|
+
import './styles/treatments.css'; // Treatments + recipe decorators
|
|
1021
|
+
import './styles/global.css'; // Resets
|
|
1022
|
+
\`\`\`
|
|
782
1023
|
|
|
783
|
-
|
|
784
|
-
| Atom | CSS |
|
|
785
|
-
|------|-----|
|
|
786
|
-
| \`_wfull\` / \`_w100\` | \`width:100%\` |
|
|
787
|
-
| \`_hfull\` / \`_h100\` | \`height:100%\` |
|
|
788
|
-
| \`_wscreen\` | \`width:100vw\` |
|
|
789
|
-
| \`_hscreen\` | \`height:100vh\` |
|
|
790
|
-
| \`_wfit\` | \`width:fit-content\` |
|
|
791
|
-
| \`_hfit\` | \`height:fit-content\` |
|
|
792
|
-
| \`_wauto\` | \`width:auto\` |
|
|
793
|
-
| \`_minw0\` | \`min-width:0\` |
|
|
794
|
-
| \`_minh0\` | \`min-height:0\` |
|
|
795
|
-
| \`_w{n}\`, \`_h{n}\` | width/height from spacing scale |
|
|
796
|
-
| \`_minw{n}\`, \`_maxw{n}\` | min/max width from scale |
|
|
1024
|
+
### Visual Treatments
|
|
797
1025
|
|
|
798
|
-
|
|
799
|
-
| Atom | Size | Line-height |
|
|
800
|
-
|------|------|-------------|
|
|
801
|
-
| \`_textxs\` | 0.75rem | 1rem |
|
|
802
|
-
| \`_textsm\` | 0.875rem | 1.25rem |
|
|
803
|
-
| \`_textbase\` | 1rem | 1.5rem |
|
|
804
|
-
| \`_textlg\` | 1.125rem | 1.75rem |
|
|
805
|
-
| \`_textxl\` | 1.25rem | 1.75rem |
|
|
806
|
-
| \`_text2xl\` | 1.5rem | 2rem |
|
|
807
|
-
| \`_text3xl\` | 1.875rem | 2.25rem |
|
|
808
|
-
| \`_heading1\`-\`_heading6\` | Heading presets (size + weight) |
|
|
1026
|
+
Six base treatment classes provide semantic styling. Combine with atoms for layout:
|
|
809
1027
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
| \`
|
|
814
|
-
| \`
|
|
815
|
-
| \`
|
|
816
|
-
|
|
|
817
|
-
| \`
|
|
818
|
-
| \`_underline\` | \`text-decoration:underline\` |
|
|
819
|
-
| \`_uppercase\` | \`text-transform:uppercase\` |
|
|
820
|
-
| \`_truncate\` | overflow ellipsis + nowrap |
|
|
821
|
-
| \`_textl\`, \`_textc\`, \`_textr\` | text-align left/center/right |
|
|
1028
|
+
| Treatment | Class | Variants / States |
|
|
1029
|
+
|-----------|-------|-------------------|
|
|
1030
|
+
| **Interactive Surface** | \`d-interactive\` | \`data-variant="primary\\|ghost\\|danger"\`, hover/focus-visible/disabled states |
|
|
1031
|
+
| **Container Surface** | \`d-surface\` | \`data-variant="raised\\|overlay"\`, optional \`data-interactive\` for hover |
|
|
1032
|
+
| **Data Display** | \`d-data\`, \`d-data-header\`, \`d-data-row\`, \`d-data-cell\` | Row hover highlight |
|
|
1033
|
+
| **Form Control** | \`d-control\` | Focus ring, placeholder, disabled, error via \`aria-invalid\` |
|
|
1034
|
+
| **Section Rhythm** | \`d-section\` | Auto-spacing between adjacent sections, density-aware |
|
|
1035
|
+
| **Inline Annotation** | \`d-annotation\` | \`data-status="success\\|error\\|warning\\|info"\` |
|
|
822
1036
|
|
|
823
|
-
|
|
824
|
-
| Atom | CSS |
|
|
825
|
-
|------|-----|
|
|
826
|
-
| \`_bgprimary\` | \`background:var(--d-primary)\` |
|
|
827
|
-
| \`_bgsurface\` | \`background:var(--d-surface)\` |
|
|
828
|
-
| \`_bgsurface0\`-\`_bgsurface2\` | surface elevation layers |
|
|
829
|
-
| \`_bgmuted\` | \`background:var(--d-muted)\` |
|
|
830
|
-
| \`_bgbg\` | \`background:var(--d-bg)\` |
|
|
831
|
-
| \`_bgsuccess\`, \`_bgerror\`, \`_bgwarning\`, \`_bginfo\` | status backgrounds |
|
|
832
|
-
| \`_fgprimary\` | \`color:var(--d-primary)\` |
|
|
833
|
-
| \`_fgtext\` | \`color:var(--d-text)\` |
|
|
834
|
-
| \`_fgmuted\` | \`color:var(--d-text-muted)\` |
|
|
835
|
-
| \`_fgsuccess\`, \`_fgerror\`, \`_fgwarning\`, \`_fginfo\` | status text |
|
|
836
|
-
| \`_bcborder\` | \`border-color:var(--d-border)\` |
|
|
1037
|
+
### Composition
|
|
837
1038
|
|
|
838
|
-
|
|
839
|
-
| Atom | CSS |
|
|
840
|
-
|------|-----|
|
|
841
|
-
| \`_overhidden\` | \`overflow:hidden\` |
|
|
842
|
-
| \`_overauto\` | \`overflow:auto\` |
|
|
843
|
-
| \`_overscroll\` | \`overflow:scroll\` |
|
|
844
|
-
| \`_overxauto\`, \`_overyauto\` | axis-specific overflow |
|
|
845
|
-
| \`_nowraptext\` | \`white-space:nowrap\` |
|
|
846
|
-
| \`_prewrap\` | \`white-space:pre-wrap\` |
|
|
847
|
-
| \`_breakword\` | \`overflow-wrap:break-word\` |
|
|
1039
|
+
Atoms + treatment + recipe decorator:
|
|
848
1040
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
| \`_notallowed\` | \`cursor:not-allowed\` |
|
|
855
|
-
| \`_grab\` | \`cursor:grab\` |
|
|
856
|
-
| \`_selectnone\` | \`user-select:none\` |
|
|
857
|
-
| \`_ptrnone\` | \`pointer-events:none\` |
|
|
1041
|
+
\`\`\`tsx
|
|
1042
|
+
<button className={css('_px4 _py2') + ' d-interactive'} data-variant="primary">Deploy</button>
|
|
1043
|
+
<div className={css('_flex _col _gap4') + ' d-surface carbon-glass'}>Card</div>
|
|
1044
|
+
<span className="d-annotation" data-status="success">Active</span>
|
|
1045
|
+
\`\`\`
|
|
858
1046
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
| \`_abs\` | \`position:absolute\` |
|
|
864
|
-
| \`_fixed\` | \`position:fixed\` |
|
|
865
|
-
| \`_sticky\` | \`position:sticky\` |
|
|
866
|
-
| \`_inset0\` | \`inset:0\` |
|
|
867
|
-
| \`_top0\`, \`_right0\`, \`_bottom0\`, \`_left0\` | edge positioning |
|
|
868
|
-
| \`_z10\`-\`_z50\` | z-index scale |
|
|
1047
|
+
- **Atoms:** \`css('_flex _col _gap4')\` \u2014 processed by @decantr/css runtime
|
|
1048
|
+
- **Treatments:** \`d-interactive\`, \`d-surface\` \u2014 semantic base styles from treatments.css
|
|
1049
|
+
- **Recipe decorators:** \`carbon-glass\`, \`carbon-code\` \u2014 theme-specific decoration from treatments.css
|
|
1050
|
+
- **Combined:** \`css('_flex _col') + ' d-surface carbon-card'\`
|
|
869
1051
|
|
|
870
|
-
|
|
871
|
-
| Atom | CSS |
|
|
872
|
-
|------|-----|
|
|
873
|
-
| \`_gc1\`-\`_gc12\` | \`grid-template-columns:repeat(N,...)\` |
|
|
874
|
-
| \`_gr1\`-\`_gr6\` | \`grid-template-rows:repeat(N,...)\` |
|
|
875
|
-
| \`_span1\`-\`_span12\`, \`_spanfull\` | column span |
|
|
876
|
-
| \`_rowspan1\`-\`_rowspan6\` | row span |
|
|
1052
|
+
### Atoms Quick Reference
|
|
877
1053
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
| \`
|
|
882
|
-
| \`
|
|
883
|
-
| \`
|
|
884
|
-
| \`
|
|
885
|
-
| \`
|
|
886
|
-
| \`
|
|
887
|
-
|
|
|
888
|
-
|
|
|
889
|
-
| \`_visible\`, \`_invisible\` | visibility |
|
|
1054
|
+
| Category | Examples | Purpose |
|
|
1055
|
+
|----------|----------|---------|
|
|
1056
|
+
| Layout | \`_flex\`, \`_col\`, \`_row\`, \`_wrap\`, \`_grid\` | Flex/grid containers |
|
|
1057
|
+
| Spacing | \`_gap4\`, \`_p4\`, \`_px4\`, \`_py2\`, \`_m0\` | Gaps, padding, margin |
|
|
1058
|
+
| Sizing | \`_w100\`, \`_h100\`, \`_minw0\`, \`_maxwfull\` | Width, height |
|
|
1059
|
+
| Text | \`_textlg\`, \`_text2xl\`, \`_fontbold\`, \`_textc\` | Typography |
|
|
1060
|
+
| Alignment | \`_aic\`, \`_jcc\`, \`_jcsb\`, \`_pic\` | Flex/grid alignment |
|
|
1061
|
+
| Position | \`_rel\`, \`_abs\`, \`_sticky\`, \`_z10\` | Positioning |
|
|
1062
|
+
| Visual | \`_rounded\`, \`_shadow\`, \`_trans\`, \`_op50\` | Decoration |
|
|
1063
|
+
| Color | \`_bgprimary\`, \`_fgtext\`, \`_fgmuted\`, \`_bcborder\` | Theme colors |
|
|
1064
|
+
| Responsive | \`_md:gc2\`, \`_lg:gc4\`, \`_sm:flex\` | Breakpoint prefixes |
|
|
890
1065
|
|
|
891
|
-
|
|
1066
|
+
Scale: 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24. Example: \`_gap4\` = \`gap:1rem\`.
|
|
892
1067
|
|
|
893
|
-
|
|
1068
|
+
### Design Tokens
|
|
894
1069
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
- Atoms: \`css('_flex _col _gap4')\` \u2014 processed by @decantr/css runtime
|
|
906
|
-
- Decorators: \`'carbon-card'\`, \`'carbon-glass'\` \u2014 plain CSS classes from decorators.css
|
|
907
|
-
- Combined: \`css('_flex _col') + ' carbon-card'\`
|
|
1070
|
+
| Token | Purpose |
|
|
1071
|
+
|-------|---------|
|
|
1072
|
+
| \`--d-primary\` | Primary brand color |
|
|
1073
|
+
| \`--d-surface\`, \`--d-surface-raised\` | Surface backgrounds |
|
|
1074
|
+
| \`--d-bg\` | Page background |
|
|
1075
|
+
| \`--d-border\` | Border color |
|
|
1076
|
+
| \`--d-text\`, \`--d-text-muted\` | Text colors |
|
|
1077
|
+
| \`--d-success\`, \`--d-error\`, \`--d-warning\`, \`--d-info\` | Status colors |
|
|
1078
|
+
| \`--d-shadow\`, \`--d-shadow-lg\` | Elevation shadows |
|
|
1079
|
+
| \`--d-radius\`, \`--d-radius-lg\` | Border radii |
|
|
908
1080
|
|
|
909
1081
|
### Routing
|
|
910
1082
|
|
|
@@ -912,28 +1084,7 @@ Check \`decantr.essence.json\` \u2192 \`meta.platform.routing\` for the routing
|
|
|
912
1084
|
- \`"hash"\` \u2192 use \`HashRouter\` (e.g., for static hosting, GitHub Pages)
|
|
913
1085
|
- \`"history"\` \u2192 use \`BrowserRouter\` (e.g., for server-rendered apps)
|
|
914
1086
|
|
|
915
|
-
Routes are defined in \`decantr.essence.json\` \u2192 \`blueprint.routes\` and listed in \`.decantr/context/scaffold.md
|
|
916
|
-
|
|
917
|
-
### CSS Architecture
|
|
918
|
-
|
|
919
|
-
The CSS is organized into two parts:
|
|
920
|
-
|
|
921
|
-
1. **Atoms (@decantr/css)** - Layout utilities injected at runtime into \`@layer d.atoms\`
|
|
922
|
-
2. **Generated CSS files** - Theme tokens and recipe decorators created during scaffold
|
|
923
|
-
|
|
924
|
-
\`\`\`
|
|
925
|
-
src/styles/
|
|
926
|
-
tokens.css # :root { --d-primary: #...; --d-surface: #...; }
|
|
927
|
-
decorators.css # .recipe-card { ... }
|
|
928
|
-
\`\`\`
|
|
929
|
-
|
|
930
|
-
### Variable Naming Convention
|
|
931
|
-
|
|
932
|
-
| Prefix | Purpose | Example |
|
|
933
|
-
|--------|---------|---------|
|
|
934
|
-
| \`--d-\` | Core Decantr tokens | \`--d-primary\`, \`--d-bg\` |
|
|
935
|
-
| \`--d-gap-{n}\` | Spacing tokens | \`--d-gap-4\`, \`--d-gap-8\` |
|
|
936
|
-
| \`--d-radius\` | Border radius | \`--d-radius\`, \`--d-radius-lg\` |`;
|
|
1087
|
+
Routes are defined in \`decantr.essence.json\` \u2192 \`blueprint.routes\` and listed in \`.decantr/context/scaffold.md\`.`;
|
|
937
1088
|
function generateDecantrMdV31(guardMode, cssApproach) {
|
|
938
1089
|
const template = loadTemplate("DECANTR.md.template");
|
|
939
1090
|
return renderTemplate(template, {
|
|
@@ -1006,33 +1157,29 @@ function generateTaskContext(templateName, essence) {
|
|
|
1006
1157
|
};
|
|
1007
1158
|
return renderTemplate(template, vars);
|
|
1008
1159
|
}
|
|
1009
|
-
function
|
|
1010
|
-
const template = loadTemplate(
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
|
|
1160
|
+
function generateTaskContextV3(templateName, essence) {
|
|
1161
|
+
const template = loadTemplate(templateName);
|
|
1162
|
+
const pages = essence.blueprint.sections && essence.blueprint.sections.length > 0 ? essence.blueprint.sections.flatMap((s) => s.pages) : essence.blueprint.pages || [];
|
|
1163
|
+
const defaultShell = essence.blueprint.sections?.[0]?.shell || essence.blueprint.shell || "sidebar-main";
|
|
1164
|
+
const layout = pages[0]?.layout?.map(serializeLayoutItem).join(", ") || "none";
|
|
1165
|
+
const scaffoldStructure = pages.map((p) => {
|
|
1166
|
+
const patterns = p.layout.length > 0 ? `
|
|
1167
|
+
- Patterns: ${p.layout.map(serializeLayoutItem).join(", ")}` : "";
|
|
1168
|
+
return `- **${p.id}** (${defaultShell})${patterns}`;
|
|
1169
|
+
}).join("\n");
|
|
1170
|
+
const densityLevel = essence.dna.spacing?.density || "comfortable";
|
|
1171
|
+
const contentGap = essence.dna.spacing?.content_gap || "_gap4";
|
|
1017
1172
|
const vars = {
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
GUARD_MODE: essence.guard.mode,
|
|
1029
|
-
ENFORCE_STYLE: String(essence.guard.enforce_style),
|
|
1030
|
-
ENFORCE_RECIPE: String(essence.guard.enforce_recipe),
|
|
1031
|
-
DNA_ENFORCEMENT: dnaEnforcement,
|
|
1032
|
-
BLUEPRINT_ENFORCEMENT: blueprintEnforcement,
|
|
1033
|
-
DENSITY: essence.density.level,
|
|
1034
|
-
CONTENT_GAP: essence.density.content_gap,
|
|
1035
|
-
LAST_UPDATED: (/* @__PURE__ */ new Date()).toISOString()
|
|
1173
|
+
TARGET: essence.meta.target || "react",
|
|
1174
|
+
THEME_STYLE: essence.dna.theme.style,
|
|
1175
|
+
THEME_MODE: essence.dna.theme.mode,
|
|
1176
|
+
THEME_RECIPE: essence.dna.theme.recipe || essence.dna.theme.style,
|
|
1177
|
+
DEFAULT_SHELL: defaultShell,
|
|
1178
|
+
GUARD_MODE: essence.meta.guard.mode,
|
|
1179
|
+
LAYOUT: layout,
|
|
1180
|
+
DENSITY: densityLevel,
|
|
1181
|
+
CONTENT_GAP: contentGap,
|
|
1182
|
+
SCAFFOLD_STRUCTURE: scaffoldStructure
|
|
1036
1183
|
};
|
|
1037
1184
|
return renderTemplate(template, vars);
|
|
1038
1185
|
}
|
|
@@ -1116,15 +1263,6 @@ async function scaffoldProject(projectRoot, options, detected, registry, archety
|
|
|
1116
1263
|
const scaffoldPath = join(contextDir, "task-scaffold.md");
|
|
1117
1264
|
writeFileSync(scaffoldPath, generateTaskContext("task-scaffold.md.template", essence));
|
|
1118
1265
|
contextFiles.push(scaffoldPath);
|
|
1119
|
-
const addPagePath = join(contextDir, "task-add-page.md");
|
|
1120
|
-
writeFileSync(addPagePath, generateTaskContext("task-add-page.md.template", essence));
|
|
1121
|
-
contextFiles.push(addPagePath);
|
|
1122
|
-
const modifyPath = join(contextDir, "task-modify.md");
|
|
1123
|
-
writeFileSync(modifyPath, generateTaskContext("task-modify.md.template", essence));
|
|
1124
|
-
contextFiles.push(modifyPath);
|
|
1125
|
-
const summaryPath = join(contextDir, "essence-summary.md");
|
|
1126
|
-
writeFileSync(summaryPath, generateEssenceSummary(essence));
|
|
1127
|
-
contextFiles.push(summaryPath);
|
|
1128
1266
|
if (composedSections) {
|
|
1129
1267
|
essenceV3.version = "3.1.0";
|
|
1130
1268
|
essenceV3.blueprint = {
|
|
@@ -1133,7 +1271,7 @@ async function scaffoldProject(projectRoot, options, detected, registry, archety
|
|
|
1133
1271
|
routes: routeMap || {}
|
|
1134
1272
|
};
|
|
1135
1273
|
if (blueprintData?.personality?.length) {
|
|
1136
|
-
essenceV3.dna.personality = blueprintData.personality;
|
|
1274
|
+
essenceV3.dna.personality = typeof blueprintData.personality === "string" ? [blueprintData.personality] : blueprintData.personality;
|
|
1137
1275
|
}
|
|
1138
1276
|
if (blueprintData?.design_constraints) {
|
|
1139
1277
|
essenceV3.dna.constraints = blueprintData.design_constraints;
|
|
@@ -1146,7 +1284,7 @@ async function scaffoldProject(projectRoot, options, detected, registry, archety
|
|
|
1146
1284
|
}
|
|
1147
1285
|
writeFileSync(essencePath, JSON.stringify(essenceV3, null, 2) + "\n");
|
|
1148
1286
|
}
|
|
1149
|
-
const refreshResult = await refreshDerivedFiles(projectRoot, essenceV3, registry, themeData, recipeData);
|
|
1287
|
+
const refreshResult = await refreshDerivedFiles(projectRoot, essenceV3, registry, themeData, recipeData, { isInitialScaffold: true });
|
|
1150
1288
|
contextFiles.push(...refreshResult.contextFiles);
|
|
1151
1289
|
const gitignoreUpdated = updateGitignore(projectRoot);
|
|
1152
1290
|
return {
|
|
@@ -1348,7 +1486,7 @@ When available, use these tools:
|
|
|
1348
1486
|
gitignoreUpdated
|
|
1349
1487
|
};
|
|
1350
1488
|
}
|
|
1351
|
-
async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThemeData, prefetchedRecipeData) {
|
|
1489
|
+
async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThemeData, prefetchedRecipeData, options) {
|
|
1352
1490
|
const decantrDir = join(projectRoot, ".decantr");
|
|
1353
1491
|
const contextDir = join(decantrDir, "context");
|
|
1354
1492
|
mkdirSync(contextDir, { recursive: true });
|
|
@@ -1388,7 +1526,8 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1388
1526
|
recipeData = {
|
|
1389
1527
|
decorators: r.decorators,
|
|
1390
1528
|
spatial_hints: r.spatial_hints,
|
|
1391
|
-
radius_hints: r.radius_hints
|
|
1529
|
+
radius_hints: r.radius_hints,
|
|
1530
|
+
treatment_overrides: r.treatment_overrides
|
|
1392
1531
|
};
|
|
1393
1532
|
if (!recipeData.decorators && raw.data) {
|
|
1394
1533
|
const inner = raw.data;
|
|
@@ -1412,7 +1551,8 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1412
1551
|
recipeData = {
|
|
1413
1552
|
decorators: inner.decorators,
|
|
1414
1553
|
spatial_hints: inner.spatial_hints,
|
|
1415
|
-
radius_hints: inner.radius_hints
|
|
1554
|
+
radius_hints: inner.radius_hints,
|
|
1555
|
+
treatment_overrides: inner.treatment_overrides
|
|
1416
1556
|
};
|
|
1417
1557
|
}
|
|
1418
1558
|
}
|
|
@@ -1442,24 +1582,48 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1442
1582
|
}
|
|
1443
1583
|
const stylesDir = join(projectRoot, "src", "styles");
|
|
1444
1584
|
mkdirSync(stylesDir, { recursive: true });
|
|
1585
|
+
const densityLevel = options.density || "comfortable";
|
|
1586
|
+
const spatialTokens = computeSpatialTokens(densityLevel, recipeData?.spatial_hints ? {
|
|
1587
|
+
section_padding: recipeData.spatial_hints.section_padding ?? void 0,
|
|
1588
|
+
density_bias: typeof recipeData.spatial_hints.density_bias === "number" ? recipeData.spatial_hints.density_bias : void 0,
|
|
1589
|
+
content_gap_shift: recipeData.spatial_hints.content_gap_shift
|
|
1590
|
+
} : void 0);
|
|
1445
1591
|
const tokensPath = join(stylesDir, "tokens.css");
|
|
1446
1592
|
const hasRealThemeData = themeData?.seed?.primary || themeData?.palette?.background;
|
|
1447
1593
|
if (hasRealThemeData || !existsSync(tokensPath)) {
|
|
1448
|
-
writeFileSync(tokensPath, generateTokensCSS(themeData, mode));
|
|
1449
|
-
}
|
|
1450
|
-
const
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1594
|
+
writeFileSync(tokensPath, generateTokensCSS(themeData, mode, spatialTokens));
|
|
1595
|
+
}
|
|
1596
|
+
const treatmentsPath = join(stylesDir, "treatments.css");
|
|
1597
|
+
writeFileSync(treatmentsPath, generateTreatmentCSS(
|
|
1598
|
+
spatialTokens,
|
|
1599
|
+
recipeData?.treatment_overrides,
|
|
1600
|
+
recipeData?.decorators,
|
|
1601
|
+
themeName
|
|
1602
|
+
));
|
|
1603
|
+
const globalPath = join(stylesDir, "global.css");
|
|
1604
|
+
if (!existsSync(globalPath)) {
|
|
1605
|
+
writeFileSync(globalPath, generateGlobalCSS(personality));
|
|
1606
|
+
}
|
|
1607
|
+
const cssFiles = [tokensPath, treatmentsPath, globalPath];
|
|
1608
|
+
const treatmentsMdPath = join(contextDir, "treatments.md");
|
|
1609
|
+
writeFileSync(treatmentsMdPath, generateTreatmentsContext(recipeData, recipeName));
|
|
1458
1610
|
const decantrMdPath = join(projectRoot, "DECANTR.md");
|
|
1459
1611
|
writeFileSync(decantrMdPath, generateDecantrMdV31(guardMode, CSS_APPROACH_CONTENT));
|
|
1460
|
-
const
|
|
1461
|
-
|
|
1462
|
-
|
|
1612
|
+
const hasSections = essence.blueprint.sections && essence.blueprint.sections.length > 0;
|
|
1613
|
+
const contextFiles = [treatmentsMdPath];
|
|
1614
|
+
if (!hasSections) {
|
|
1615
|
+
const summaryPath = join(contextDir, "essence-summary.md");
|
|
1616
|
+
writeFileSync(summaryPath, generateEssenceSummaryV3(essence));
|
|
1617
|
+
contextFiles.push(summaryPath);
|
|
1618
|
+
}
|
|
1619
|
+
if (!options?.isInitialScaffold) {
|
|
1620
|
+
const addPagePath = join(contextDir, "task-add-page.md");
|
|
1621
|
+
writeFileSync(addPagePath, generateTaskContextV3("task-add-page.md.template", essence));
|
|
1622
|
+
contextFiles.push(addPagePath);
|
|
1623
|
+
const modifyPath = join(contextDir, "task-modify.md");
|
|
1624
|
+
writeFileSync(modifyPath, generateTaskContextV3("task-modify.md.template", essence));
|
|
1625
|
+
contextFiles.push(modifyPath);
|
|
1626
|
+
}
|
|
1463
1627
|
const blueprint = essence.blueprint;
|
|
1464
1628
|
const sections = blueprint.sections && blueprint.sections.length > 0 ? blueprint.sections : [];
|
|
1465
1629
|
if (sections.length > 0) {
|
|
@@ -1492,21 +1656,28 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1492
1656
|
slots = synthetic;
|
|
1493
1657
|
}
|
|
1494
1658
|
}
|
|
1495
|
-
|
|
1659
|
+
const spec = {
|
|
1496
1660
|
description: inner.description || "",
|
|
1497
1661
|
components: inner.components || [],
|
|
1498
1662
|
slots
|
|
1499
1663
|
};
|
|
1664
|
+
if (!spec.components || spec.components.length === 0) {
|
|
1665
|
+
const syntheticComps = generateSyntheticComponents(name, spec.description);
|
|
1666
|
+
if (syntheticComps.length > 0) spec.components = syntheticComps;
|
|
1667
|
+
}
|
|
1668
|
+
patternSpecs[name] = spec;
|
|
1500
1669
|
} else {
|
|
1501
1670
|
const synthetic = generateSyntheticSlots(name, "");
|
|
1502
|
-
|
|
1503
|
-
|
|
1671
|
+
const syntheticComps = generateSyntheticComponents(name, "");
|
|
1672
|
+
if (Object.keys(synthetic).length > 0 || syntheticComps.length > 0) {
|
|
1673
|
+
patternSpecs[name] = { description: "", components: syntheticComps, slots: synthetic };
|
|
1504
1674
|
}
|
|
1505
1675
|
}
|
|
1506
1676
|
} catch {
|
|
1507
1677
|
const synthetic = generateSyntheticSlots(name, "");
|
|
1508
|
-
|
|
1509
|
-
|
|
1678
|
+
const syntheticComps = generateSyntheticComponents(name, "");
|
|
1679
|
+
if (Object.keys(synthetic).length > 0 || syntheticComps.length > 0) {
|
|
1680
|
+
patternSpecs[name] = { description: "", components: syntheticComps, slots: synthetic };
|
|
1510
1681
|
}
|
|
1511
1682
|
}
|
|
1512
1683
|
}
|
|
@@ -1666,21 +1837,28 @@ async function refreshDerivedFiles(projectRoot, essence, registry, prefetchedThe
|
|
|
1666
1837
|
slots = synthetic;
|
|
1667
1838
|
}
|
|
1668
1839
|
}
|
|
1669
|
-
|
|
1840
|
+
const spec = {
|
|
1670
1841
|
description: inner.description || "",
|
|
1671
1842
|
components: inner.components || [],
|
|
1672
1843
|
slots
|
|
1673
1844
|
};
|
|
1845
|
+
if (!spec.components || spec.components.length === 0) {
|
|
1846
|
+
const syntheticComps = generateSyntheticComponents(name, spec.description);
|
|
1847
|
+
if (syntheticComps.length > 0) spec.components = syntheticComps;
|
|
1848
|
+
}
|
|
1849
|
+
patternSpecs[name] = spec;
|
|
1674
1850
|
} else {
|
|
1675
1851
|
const synthetic = generateSyntheticSlots(name, "");
|
|
1676
|
-
|
|
1677
|
-
|
|
1852
|
+
const syntheticComps = generateSyntheticComponents(name, "");
|
|
1853
|
+
if (Object.keys(synthetic).length > 0 || syntheticComps.length > 0) {
|
|
1854
|
+
patternSpecs[name] = { description: "", components: syntheticComps, slots: synthetic };
|
|
1678
1855
|
}
|
|
1679
1856
|
}
|
|
1680
1857
|
} catch {
|
|
1681
1858
|
const synthetic = generateSyntheticSlots(name, "");
|
|
1682
|
-
|
|
1683
|
-
|
|
1859
|
+
const syntheticComps = generateSyntheticComponents(name, "");
|
|
1860
|
+
if (Object.keys(synthetic).length > 0 || syntheticComps.length > 0) {
|
|
1861
|
+
patternSpecs[name] = { description: "", components: syntheticComps, slots: synthetic };
|
|
1684
1862
|
}
|
|
1685
1863
|
}
|
|
1686
1864
|
}
|
|
@@ -1810,6 +1988,27 @@ function generateSyntheticSlots(patternId, description) {
|
|
|
1810
1988
|
}
|
|
1811
1989
|
return syntheticSlots;
|
|
1812
1990
|
}
|
|
1991
|
+
function generateSyntheticComponents(patternId, description) {
|
|
1992
|
+
const desc = description.toLowerCase();
|
|
1993
|
+
const syntheticComponents = [];
|
|
1994
|
+
if (patternId.includes("hero")) syntheticComponents.push("Button", "Icon", "Image");
|
|
1995
|
+
if (patternId.includes("feature")) syntheticComponents.push("Card", "Icon", "Text");
|
|
1996
|
+
if (patternId.includes("pricing")) syntheticComponents.push("Card", "Button", "Badge");
|
|
1997
|
+
if (patternId.includes("testimonial")) syntheticComponents.push("Card", "Avatar", "Text");
|
|
1998
|
+
if (patternId.includes("cta")) syntheticComponents.push("Button", "Text");
|
|
1999
|
+
if (patternId.includes("form") || patternId.includes("contact")) syntheticComponents.push("Input", "Textarea", "Button", "Label");
|
|
2000
|
+
if (patternId.includes("team")) syntheticComponents.push("Card", "Avatar", "Text");
|
|
2001
|
+
if (patternId.includes("settings") || patternId.includes("security")) syntheticComponents.push("Card", "Toggle", "Input", "Button");
|
|
2002
|
+
if (patternId.includes("message") || patternId.includes("chat")) syntheticComponents.push("Avatar", "Text", "CodeBlock");
|
|
2003
|
+
if (patternId.includes("input") && desc.includes("chat")) syntheticComponents.push("Textarea", "Button", "Icon");
|
|
2004
|
+
if (patternId.includes("header") && desc.includes("chat")) syntheticComponents.push("Button", "Icon", "Text");
|
|
2005
|
+
if (patternId.includes("content") || patternId.includes("legal")) syntheticComponents.push("Heading", "Text", "List");
|
|
2006
|
+
if (patternId.includes("how-it-works") || patternId.includes("steps")) syntheticComponents.push("Card", "Icon", "Text", "Badge");
|
|
2007
|
+
if (patternId.includes("values")) syntheticComponents.push("Card", "Icon", "Text");
|
|
2008
|
+
if (patternId.includes("story") || patternId.includes("about")) syntheticComponents.push("Text", "Image");
|
|
2009
|
+
if (patternId.includes("empty") || patternId.includes("new")) syntheticComponents.push("Icon", "Text", "Button");
|
|
2010
|
+
return [...new Set(syntheticComponents)];
|
|
2011
|
+
}
|
|
1813
2012
|
function generateSectionContext(input) {
|
|
1814
2013
|
const { section, decorators, guardConfig, personality, themeName, recipeName, zoneContext, patternSpecs, recipeHints, constraints, shellInfo } = input;
|
|
1815
2014
|
const lines = [];
|
|
@@ -1836,11 +2035,10 @@ function generateSectionContext(input) {
|
|
|
1836
2035
|
lines.push("");
|
|
1837
2036
|
lines.push(`**Theme tokens:** see \`src/styles/tokens.css\` \u2014 use \`var(--d-primary)\`, \`var(--d-bg)\`, etc.`);
|
|
1838
2037
|
lines.push("");
|
|
2038
|
+
lines.push("**Visual Treatments:** All 6 base treatments available (see DECANTR.md for usage).");
|
|
1839
2039
|
if (decorators.length > 0) {
|
|
1840
2040
|
const names = decorators.map((d) => d.name).join(", ");
|
|
1841
|
-
lines.push(`**
|
|
1842
|
-
} else {
|
|
1843
|
-
lines.push("**Decorators:** none defined.");
|
|
2041
|
+
lines.push(`**Recipe decorators:** ${names}`);
|
|
1844
2042
|
}
|
|
1845
2043
|
lines.push("");
|
|
1846
2044
|
if (recipeHints) {
|
|
@@ -1871,11 +2069,7 @@ function generateSectionContext(input) {
|
|
|
1871
2069
|
lines.push("");
|
|
1872
2070
|
}
|
|
1873
2071
|
if (personality.length > 0) {
|
|
1874
|
-
lines.push("
|
|
1875
|
-
lines.push("");
|
|
1876
|
-
lines.push(personality.join(", "));
|
|
1877
|
-
lines.push("");
|
|
1878
|
-
lines.push("---");
|
|
2072
|
+
lines.push("**Personality:** See scaffold.md for personality and visual direction.");
|
|
1879
2073
|
lines.push("");
|
|
1880
2074
|
}
|
|
1881
2075
|
if (constraints && Object.keys(constraints).length > 0) {
|
|
@@ -1888,6 +2082,34 @@ function generateSectionContext(input) {
|
|
|
1888
2082
|
lines.push("---");
|
|
1889
2083
|
lines.push("");
|
|
1890
2084
|
}
|
|
2085
|
+
const uniquePatterns = /* @__PURE__ */ new Map();
|
|
2086
|
+
for (const page of section.pages) {
|
|
2087
|
+
const patternNames = page.layout.flatMap(extractPatternNames);
|
|
2088
|
+
for (const name of patternNames) {
|
|
2089
|
+
if (patternSpecs[name] && !uniquePatterns.has(name)) {
|
|
2090
|
+
uniquePatterns.set(name, patternSpecs[name]);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
if (uniquePatterns.size > 0) {
|
|
2095
|
+
lines.push("## Pattern Reference");
|
|
2096
|
+
lines.push("");
|
|
2097
|
+
for (const [patternName, spec] of uniquePatterns) {
|
|
2098
|
+
lines.push(`### ${patternName}`);
|
|
2099
|
+
lines.push("");
|
|
2100
|
+
lines.push(spec.description);
|
|
2101
|
+
lines.push("");
|
|
2102
|
+
lines.push(`**Components:** ${spec.components.join(", ")}`);
|
|
2103
|
+
lines.push("");
|
|
2104
|
+
lines.push("**Layout slots:**");
|
|
2105
|
+
for (const [slot, desc] of Object.entries(spec.slots)) {
|
|
2106
|
+
lines.push(`- \`${slot}\`: ${desc}`);
|
|
2107
|
+
}
|
|
2108
|
+
lines.push("");
|
|
2109
|
+
}
|
|
2110
|
+
lines.push("---");
|
|
2111
|
+
lines.push("");
|
|
2112
|
+
}
|
|
1891
2113
|
lines.push("## Pages");
|
|
1892
2114
|
lines.push("");
|
|
1893
2115
|
for (const page of section.pages) {
|
|
@@ -1908,22 +2130,6 @@ function generateSectionContext(input) {
|
|
|
1908
2130
|
}
|
|
1909
2131
|
lines.push("");
|
|
1910
2132
|
}
|
|
1911
|
-
const patternNames = page.layout.flatMap(extractPatternNames);
|
|
1912
|
-
for (const patternName of patternNames) {
|
|
1913
|
-
const spec = patternSpecs[patternName];
|
|
1914
|
-
if (!spec) continue;
|
|
1915
|
-
lines.push(`#### Pattern: ${patternName}`);
|
|
1916
|
-
lines.push("");
|
|
1917
|
-
lines.push(spec.description);
|
|
1918
|
-
lines.push("");
|
|
1919
|
-
lines.push(`**Components:** ${spec.components.join(", ")}`);
|
|
1920
|
-
lines.push("");
|
|
1921
|
-
lines.push("**Layout slots:**");
|
|
1922
|
-
for (const [slot, desc] of Object.entries(spec.slots)) {
|
|
1923
|
-
lines.push(`- \`${slot}\`: ${desc}`);
|
|
1924
|
-
}
|
|
1925
|
-
lines.push("");
|
|
1926
|
-
}
|
|
1927
2133
|
}
|
|
1928
2134
|
return lines.join("\n");
|
|
1929
2135
|
}
|