oh-my-design-cli 0.1.2 → 1.0.0
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/.claude/hooks/post-edit-watch.cjs +99 -0
- package/.claude/hooks/session-end-foldin.cjs +96 -0
- package/.claude/hooks/session-state-loader.cjs +64 -0
- package/.claude/hooks/skill-activation.cjs +73 -0
- package/.claude/settings.json +55 -0
- package/.claude/skills/skill-rules.json +87 -0
- package/AGENTS.md +111 -0
- package/README.md +75 -202
- package/agents/AGENT.md +53 -0
- package/agents/omd-3d-blender.md +269 -0
- package/agents/omd-a11y-auditor.md +97 -0
- package/agents/omd-asset-curator.md +260 -0
- package/agents/omd-critic.md +181 -0
- package/agents/omd-master.md +548 -0
- package/agents/omd-microcopy.md +63 -0
- package/agents/omd-persona-tester.md +118 -0
- package/agents/omd-ui-junior.md +129 -0
- package/agents/omd-ux-engineer.md +265 -0
- package/agents/omd-ux-researcher.md +62 -0
- package/agents/omd-ux-writer.md +181 -0
- package/data/opt-out-corpus.json +141 -0
- package/data/reference-fingerprints.json +1495 -0
- package/dist/bin/oh-my-design.js +3 -818
- package/dist/bin/oh-my-design.js.map +1 -1
- package/dist/install-skills-SVIYKXOE.js +442 -0
- package/dist/install-skills-SVIYKXOE.js.map +1 -0
- package/package.json +23 -23
- package/scripts/context.cjs +91 -0
- package/scripts/postinstall.cjs +54 -0
- package/skills/omd-apply/SKILL.md +64 -53
- package/skills/omd-harness/SKILL.md +271 -0
- package/skills/omd-learn/SKILL.md +55 -35
- package/skills/omd-remember/SKILL.md +93 -15
- package/skills/omd-sync/SKILL.md +140 -16
- package/dist/chunk-6YNSV3VY.js +0 -35
- package/dist/chunk-6YNSV3VY.js.map +0 -1
- package/dist/chunk-MHFYGZSO.js +0 -337
- package/dist/chunk-MHFYGZSO.js.map +0 -1
- package/dist/chunk-N2JG6N4Q.js +0 -264
- package/dist/chunk-N2JG6N4Q.js.map +0 -1
- package/dist/chunk-OOQQEUGX.js +0 -46
- package/dist/chunk-OOQQEUGX.js.map +0 -1
- package/dist/chunk-OR5DHENY.js +0 -250
- package/dist/chunk-OR5DHENY.js.map +0 -1
- package/dist/customizer-CM76752R.js +0 -8
- package/dist/customizer-CM76752R.js.map +0 -1
- package/dist/index.d.ts +0 -559
- package/dist/index.js +0 -3113
- package/dist/index.js.map +0 -1
- package/dist/init-UMM4XIV5.js +0 -675
- package/dist/init-UMM4XIV5.js.map +0 -1
- package/dist/install-skills-CM6VXFZJ.js +0 -152
- package/dist/install-skills-CM6VXFZJ.js.map +0 -1
- package/dist/learn-33LHKEJA.js +0 -140
- package/dist/learn-33LHKEJA.js.map +0 -1
- package/dist/reference-YMNAOXJQ.js +0 -47
- package/dist/reference-YMNAOXJQ.js.map +0 -1
- package/dist/reference-parser-TM3CJPNE.js +0 -10
- package/dist/reference-parser-TM3CJPNE.js.map +0 -1
- package/dist/remember-UAFA5B2O.js +0 -78
- package/dist/remember-UAFA5B2O.js.map +0 -1
- package/dist/sync-FDYRKNFE.js +0 -417
- package/dist/sync-FDYRKNFE.js.map +0 -1
- package/dist/templates/templates/design-md.hbs +0 -44
- package/dist/templates/templates/partials/agent-prompt-guide.hbs +0 -28
- package/dist/templates/templates/partials/color-palette.hbs +0 -49
- package/dist/templates/templates/partials/component-stylings.hbs +0 -28
- package/dist/templates/templates/partials/depth-elevation.hbs +0 -31
- package/dist/templates/templates/partials/dos-donts.hbs +0 -13
- package/dist/templates/templates/partials/layout.hbs +0 -30
- package/dist/templates/templates/partials/responsive.hbs +0 -25
- package/dist/templates/templates/partials/shadcn-tokens.hbs +0 -64
- package/dist/templates/templates/partials/typography.hbs +0 -43
- package/dist/templates/templates/partials/visual-theme.hbs +0 -26
package/dist/sync-FDYRKNFE.js
DELETED
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
hasDrift,
|
|
4
|
-
hashContent,
|
|
5
|
-
parseBlock,
|
|
6
|
-
writeBlock
|
|
7
|
-
} from "./chunk-OOQQEUGX.js";
|
|
8
|
-
|
|
9
|
-
// src/cli/sync.ts
|
|
10
|
-
import * as p from "@clack/prompts";
|
|
11
|
-
import pc from "picocolors";
|
|
12
|
-
import { existsSync as existsSync3 } from "fs";
|
|
13
|
-
import { join as join3, relative } from "path";
|
|
14
|
-
|
|
15
|
-
// src/core/shims.ts
|
|
16
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
17
|
-
import { dirname as dirname2, join as join2 } from "path";
|
|
18
|
-
|
|
19
|
-
// src/core/sync-lock.ts
|
|
20
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
21
|
-
import { dirname, join } from "path";
|
|
22
|
-
import { z } from "zod";
|
|
23
|
-
var SYNC_LOCK_VERSION = 1;
|
|
24
|
-
var SYNC_LOCK_PATH = ".omd/sync.lock.json";
|
|
25
|
-
var TargetSchema = z.object({
|
|
26
|
-
managed_hash: z.string(),
|
|
27
|
-
last_synced: z.string()
|
|
28
|
-
});
|
|
29
|
-
var SyncLockSchema = z.object({
|
|
30
|
-
version: z.number().int().positive(),
|
|
31
|
-
design_md_hash: z.string(),
|
|
32
|
-
targets: z.record(z.string(), TargetSchema)
|
|
33
|
-
});
|
|
34
|
-
function lockPath(projectRoot) {
|
|
35
|
-
return join(projectRoot, SYNC_LOCK_PATH);
|
|
36
|
-
}
|
|
37
|
-
function readLock(projectRoot) {
|
|
38
|
-
const path = lockPath(projectRoot);
|
|
39
|
-
if (!existsSync(path)) return null;
|
|
40
|
-
const raw = readFileSync(path, "utf8");
|
|
41
|
-
const parsed = JSON.parse(raw);
|
|
42
|
-
return SyncLockSchema.parse(parsed);
|
|
43
|
-
}
|
|
44
|
-
function writeLock(projectRoot, lock) {
|
|
45
|
-
const validated = SyncLockSchema.parse(lock);
|
|
46
|
-
const path = lockPath(projectRoot);
|
|
47
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
48
|
-
writeFileSync(path, JSON.stringify(validated, null, 2) + "\n", "utf8");
|
|
49
|
-
}
|
|
50
|
-
function createLock(designMdHash) {
|
|
51
|
-
return {
|
|
52
|
-
version: SYNC_LOCK_VERSION,
|
|
53
|
-
design_md_hash: designMdHash,
|
|
54
|
-
targets: {}
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function updateTarget(projectRoot, target, managedHash) {
|
|
58
|
-
const existing = readLock(projectRoot) ?? createLock("");
|
|
59
|
-
const next = {
|
|
60
|
-
...existing,
|
|
61
|
-
targets: {
|
|
62
|
-
...existing.targets,
|
|
63
|
-
[target]: {
|
|
64
|
-
managed_hash: managedHash,
|
|
65
|
-
last_synced: (/* @__PURE__ */ new Date()).toISOString()
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
writeLock(projectRoot, next);
|
|
70
|
-
return next;
|
|
71
|
-
}
|
|
72
|
-
function updateDesignMdHash(projectRoot, designMdHash) {
|
|
73
|
-
const existing = readLock(projectRoot) ?? createLock(designMdHash);
|
|
74
|
-
const next = { ...existing, design_md_hash: designMdHash };
|
|
75
|
-
writeLock(projectRoot, next);
|
|
76
|
-
return next;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// src/core/shims.ts
|
|
80
|
-
var MANAGED_BLOCK_VERSION = 1;
|
|
81
|
-
var CLAUDE_BODY = `# Design System (oh-my-design)
|
|
82
|
-
|
|
83
|
-
The authoritative brand & UI spec is **@./DESIGN.md**.
|
|
84
|
-
Read before any UI/styling/microcopy/motion work.
|
|
85
|
-
|
|
86
|
-
Preference log (pending corrections): @./.omd/preferences.md
|
|
87
|
-
|
|
88
|
-
Precedence: DESIGN.md > preferences.md > your defaults.`;
|
|
89
|
-
var AGENTS_BODY = `## Design System (oh-my-design)
|
|
90
|
-
|
|
91
|
-
**Before any UI, styling, copy, or motion change, open and read \`./DESIGN.md\` in full.** It is the authoritative brand/design spec. Treat its tokens, voice, and component rules as binding unless the user overrides in chat.
|
|
92
|
-
|
|
93
|
-
If present, read \`./.omd/preferences.md\` \u2014 pending corrections not yet folded into DESIGN.md. Apply them; flag conflicts.`;
|
|
94
|
-
var CURSOR_FRONTMATTER = `---
|
|
95
|
-
description: Authoritative brand & UI design system. Read DESIGN.md before UI work.
|
|
96
|
-
globs:
|
|
97
|
-
- "**/*.tsx"
|
|
98
|
-
- "**/*.jsx"
|
|
99
|
-
- "**/*.vue"
|
|
100
|
-
- "**/*.svelte"
|
|
101
|
-
- "**/*.css"
|
|
102
|
-
- "**/*.scss"
|
|
103
|
-
- "**/tailwind.config.*"
|
|
104
|
-
- "**/components/**"
|
|
105
|
-
- "**/app/**/page.*"
|
|
106
|
-
alwaysApply: false
|
|
107
|
-
---`;
|
|
108
|
-
var CURSOR_BODY = `The authoritative design spec lives at \`@DESIGN.md\` (repo root). Open and read before generating/modifying UI.
|
|
109
|
-
|
|
110
|
-
Pending preference corrections: \`@.omd/preferences.md\`.
|
|
111
|
-
|
|
112
|
-
Precedence: DESIGN.md > preferences.md > framework defaults.`;
|
|
113
|
-
var CLAUDE_SHIM = {
|
|
114
|
-
id: "claude",
|
|
115
|
-
relPath: "CLAUDE.md",
|
|
116
|
-
mode: "block",
|
|
117
|
-
render: () => CLAUDE_BODY
|
|
118
|
-
};
|
|
119
|
-
var AGENTS_SHIM = {
|
|
120
|
-
id: "agents",
|
|
121
|
-
relPath: "AGENTS.md",
|
|
122
|
-
mode: "block",
|
|
123
|
-
render: () => AGENTS_BODY
|
|
124
|
-
};
|
|
125
|
-
var CURSOR_SHIM = {
|
|
126
|
-
id: "cursor",
|
|
127
|
-
relPath: ".cursor/rules/omd-design.mdc",
|
|
128
|
-
mode: "whole",
|
|
129
|
-
render: () => {
|
|
130
|
-
const hash = hashContent(CURSOR_BODY);
|
|
131
|
-
return `${CURSOR_FRONTMATTER}
|
|
132
|
-
|
|
133
|
-
<!-- omd:start v=${MANAGED_BLOCK_VERSION} hash=${hash} -->
|
|
134
|
-
${CURSOR_BODY}
|
|
135
|
-
<!-- omd:end -->
|
|
136
|
-
`;
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
var ALL_SHIMS = [
|
|
140
|
-
CLAUDE_SHIM,
|
|
141
|
-
AGENTS_SHIM,
|
|
142
|
-
CURSOR_SHIM
|
|
143
|
-
];
|
|
144
|
-
function resolvePath(projectRoot, relPath) {
|
|
145
|
-
return join2(projectRoot, relPath);
|
|
146
|
-
}
|
|
147
|
-
function readFileOrEmpty(path) {
|
|
148
|
-
return existsSync2(path) ? readFileSync2(path, "utf8") : "";
|
|
149
|
-
}
|
|
150
|
-
function ensureDir(path) {
|
|
151
|
-
mkdirSync2(dirname2(path), { recursive: true });
|
|
152
|
-
}
|
|
153
|
-
function inspectShim(projectRoot, shim) {
|
|
154
|
-
const abs = resolvePath(projectRoot, shim.relPath);
|
|
155
|
-
const existing = readFileOrEmpty(abs);
|
|
156
|
-
const fileExists = existing !== "";
|
|
157
|
-
if (shim.mode === "whole") {
|
|
158
|
-
const rendered = shim.render();
|
|
159
|
-
if (!fileExists) {
|
|
160
|
-
return { id: shim.id, path: abs, status: "missing", rendered };
|
|
161
|
-
}
|
|
162
|
-
if (existing === rendered) {
|
|
163
|
-
return { id: shim.id, path: abs, status: "clean", existing, rendered };
|
|
164
|
-
}
|
|
165
|
-
return { id: shim.id, path: abs, status: "drifted", existing, rendered };
|
|
166
|
-
}
|
|
167
|
-
const managed = shim.render();
|
|
168
|
-
const block = parseBlock(existing);
|
|
169
|
-
if (!block) {
|
|
170
|
-
return {
|
|
171
|
-
id: shim.id,
|
|
172
|
-
path: abs,
|
|
173
|
-
status: "missing",
|
|
174
|
-
existing: fileExists ? existing : void 0,
|
|
175
|
-
rendered: managed
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
if (hasDrift(block)) {
|
|
179
|
-
return {
|
|
180
|
-
id: shim.id,
|
|
181
|
-
path: abs,
|
|
182
|
-
status: "drifted",
|
|
183
|
-
existing: block.content,
|
|
184
|
-
rendered: managed
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
if (block.content === managed) {
|
|
188
|
-
return {
|
|
189
|
-
id: shim.id,
|
|
190
|
-
path: abs,
|
|
191
|
-
status: "clean",
|
|
192
|
-
existing: block.content,
|
|
193
|
-
rendered: managed
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
return {
|
|
197
|
-
id: shim.id,
|
|
198
|
-
path: abs,
|
|
199
|
-
status: "out-of-date",
|
|
200
|
-
existing: block.content,
|
|
201
|
-
rendered: managed
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
function writeShim(projectRoot, shim, opts = {}) {
|
|
205
|
-
const onDrift = opts.onDrift ?? "error";
|
|
206
|
-
const abs = resolvePath(projectRoot, shim.relPath);
|
|
207
|
-
const existing = readFileOrEmpty(abs);
|
|
208
|
-
const fileExists = existing !== "";
|
|
209
|
-
if (shim.mode === "whole") {
|
|
210
|
-
const rendered = shim.render();
|
|
211
|
-
const newHash = hashContent(rendered);
|
|
212
|
-
if (fileExists && existing !== rendered) {
|
|
213
|
-
const existingHash = hashContent(existing);
|
|
214
|
-
if (onDrift === "error") {
|
|
215
|
-
throw new Error(
|
|
216
|
-
`drift detected in ${shim.relPath} (existing hash ${existingHash} != rendered ${newHash}); rerun with onDrift=overwrite to force`
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
if (onDrift === "skip") {
|
|
220
|
-
updateTarget(projectRoot, shim.relPath, existingHash);
|
|
221
|
-
return {
|
|
222
|
-
id: shim.id,
|
|
223
|
-
path: abs,
|
|
224
|
-
hash: existingHash,
|
|
225
|
-
status: "skipped-drift"
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (fileExists && existing === rendered) {
|
|
230
|
-
updateTarget(projectRoot, shim.relPath, newHash);
|
|
231
|
-
return { id: shim.id, path: abs, hash: newHash, status: "unchanged" };
|
|
232
|
-
}
|
|
233
|
-
ensureDir(abs);
|
|
234
|
-
writeFileSync2(abs, rendered, "utf8");
|
|
235
|
-
updateTarget(projectRoot, shim.relPath, newHash);
|
|
236
|
-
return {
|
|
237
|
-
id: shim.id,
|
|
238
|
-
path: abs,
|
|
239
|
-
hash: newHash,
|
|
240
|
-
status: fileExists ? "updated" : "created"
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
const managed = shim.render();
|
|
244
|
-
const existingBlock = parseBlock(existing);
|
|
245
|
-
if (existingBlock && hasDrift(existingBlock)) {
|
|
246
|
-
if (onDrift === "error") {
|
|
247
|
-
throw new Error(
|
|
248
|
-
`managed block in ${shim.relPath} was hand-edited; rerun with onDrift=overwrite to force`
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
if (onDrift === "skip") {
|
|
252
|
-
updateTarget(projectRoot, shim.relPath, existingBlock.hash);
|
|
253
|
-
return {
|
|
254
|
-
id: shim.id,
|
|
255
|
-
path: abs,
|
|
256
|
-
hash: existingBlock.hash,
|
|
257
|
-
status: "skipped-drift"
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
if (existingBlock && existingBlock.content === managed && !hasDrift(existingBlock)) {
|
|
262
|
-
updateTarget(projectRoot, shim.relPath, existingBlock.hash);
|
|
263
|
-
return {
|
|
264
|
-
id: shim.id,
|
|
265
|
-
path: abs,
|
|
266
|
-
hash: existingBlock.hash,
|
|
267
|
-
status: "unchanged"
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
const { updated, hash } = writeBlock(existing, managed, MANAGED_BLOCK_VERSION);
|
|
271
|
-
ensureDir(abs);
|
|
272
|
-
writeFileSync2(abs, updated, "utf8");
|
|
273
|
-
updateTarget(projectRoot, shim.relPath, hash);
|
|
274
|
-
return {
|
|
275
|
-
id: shim.id,
|
|
276
|
-
path: abs,
|
|
277
|
-
hash,
|
|
278
|
-
status: existingBlock ? "updated" : "created"
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
function refreshDesignMdHash(projectRoot) {
|
|
282
|
-
const designMdPath = join2(projectRoot, "DESIGN.md");
|
|
283
|
-
if (!existsSync2(designMdPath)) return null;
|
|
284
|
-
const hash = hashContent(readFileSync2(designMdPath, "utf8"));
|
|
285
|
-
updateDesignMdHash(projectRoot, hash);
|
|
286
|
-
return hash;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// src/cli/sync.ts
|
|
290
|
-
var DESIGN_MD_NAME = "DESIGN.md";
|
|
291
|
-
var DEPRECATED_MD_NAME = "DESIGN_DEPRECATED.md";
|
|
292
|
-
var INIT_CONTEXT_PATH = ".omd/init-context.json";
|
|
293
|
-
var STATUS_LABEL = {
|
|
294
|
-
missing: pc.yellow("missing"),
|
|
295
|
-
clean: pc.green("clean"),
|
|
296
|
-
drifted: pc.red("drifted"),
|
|
297
|
-
"out-of-date": pc.cyan("out-of-date")
|
|
298
|
-
};
|
|
299
|
-
var WRITE_LABEL = {
|
|
300
|
-
created: pc.green("created"),
|
|
301
|
-
updated: pc.cyan("updated"),
|
|
302
|
-
unchanged: pc.dim("unchanged"),
|
|
303
|
-
"skipped-drift": pc.yellow("skipped")
|
|
304
|
-
};
|
|
305
|
-
function printDiff(label, current, proposed) {
|
|
306
|
-
p.log.message(pc.bold("\u2500\u2500\u2500 current (" + label + ") \u2500\u2500\u2500"));
|
|
307
|
-
p.log.message(current || pc.dim("(empty)"));
|
|
308
|
-
p.log.message(pc.bold("\u2500\u2500\u2500 proposed \u2500\u2500\u2500"));
|
|
309
|
-
p.log.message(proposed);
|
|
310
|
-
}
|
|
311
|
-
async function promptDrift(shim, inspection) {
|
|
312
|
-
while (true) {
|
|
313
|
-
const choice = await p.select({
|
|
314
|
-
message: `${pc.bold(shim.relPath)} has drift \u2014 choose:`,
|
|
315
|
-
options: [
|
|
316
|
-
{ value: "overwrite", label: "Overwrite with rendered content" },
|
|
317
|
-
{ value: "skip", label: "Skip (keep user edits)" },
|
|
318
|
-
{ value: "show", label: "Show diff" },
|
|
319
|
-
{ value: "quit", label: "Quit sync" }
|
|
320
|
-
]
|
|
321
|
-
});
|
|
322
|
-
if (p.isCancel(choice)) return "quit";
|
|
323
|
-
if (choice !== "show") return choice;
|
|
324
|
-
printDiff(
|
|
325
|
-
shim.relPath,
|
|
326
|
-
inspection.existing ?? "",
|
|
327
|
-
inspection.rendered
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
async function runSync(opts = {}) {
|
|
332
|
-
const projectRoot = opts.dir ?? process.cwd();
|
|
333
|
-
const relRoot = relative(process.cwd(), projectRoot) || ".";
|
|
334
|
-
p.intro(pc.bold("omd sync") + pc.dim(` (${relRoot})`));
|
|
335
|
-
const inspections = ALL_SHIMS.map((shim) => ({
|
|
336
|
-
shim,
|
|
337
|
-
result: inspectShim(projectRoot, shim)
|
|
338
|
-
}));
|
|
339
|
-
p.log.message(pc.bold("Status:"));
|
|
340
|
-
for (const { result } of inspections) {
|
|
341
|
-
const rel = relative(projectRoot, result.path);
|
|
342
|
-
p.log.message(` ${STATUS_LABEL[result.status]} ${rel}`);
|
|
343
|
-
}
|
|
344
|
-
const designMdMissing = !existsSync3(join3(projectRoot, DESIGN_MD_NAME));
|
|
345
|
-
const initContextExists = existsSync3(join3(projectRoot, INIT_CONTEXT_PATH));
|
|
346
|
-
const deprecatedExists = existsSync3(join3(projectRoot, DEPRECATED_MD_NAME));
|
|
347
|
-
const midInitFlow = designMdMissing && (initContextExists || deprecatedExists);
|
|
348
|
-
if (opts.check) {
|
|
349
|
-
const unsynced = inspections.filter(
|
|
350
|
-
(i) => i.result.status !== "clean"
|
|
351
|
-
);
|
|
352
|
-
if (unsynced.length > 0) {
|
|
353
|
-
p.outro(
|
|
354
|
-
pc.red(
|
|
355
|
-
`${unsynced.length} not in sync \u2014 rerun without --check to resolve.`
|
|
356
|
-
)
|
|
357
|
-
);
|
|
358
|
-
return 1;
|
|
359
|
-
}
|
|
360
|
-
if (designMdMissing) {
|
|
361
|
-
p.log.warn(
|
|
362
|
-
midInitFlow ? "DESIGN.md is missing but init-context is staged \u2014 your agent still needs to run the `omd:init` skill to write DESIGN.md." : 'DESIGN.md is missing \u2014 run `npx oh-my-design-cli init recommend "<description>"` to bootstrap, or have your agent run the `omd:init` skill.'
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
p.outro(pc.green("Shims clean."));
|
|
366
|
-
return 0;
|
|
367
|
-
}
|
|
368
|
-
const results = [];
|
|
369
|
-
for (const { shim, result } of inspections) {
|
|
370
|
-
if (result.status === "clean") {
|
|
371
|
-
results.push({
|
|
372
|
-
id: shim.id,
|
|
373
|
-
path: result.path,
|
|
374
|
-
hash: "",
|
|
375
|
-
status: "unchanged"
|
|
376
|
-
});
|
|
377
|
-
continue;
|
|
378
|
-
}
|
|
379
|
-
if (result.status === "drifted" && !opts.force) {
|
|
380
|
-
const choice = await promptDrift(shim, result);
|
|
381
|
-
if (choice === "quit") {
|
|
382
|
-
p.outro(pc.yellow("Aborted by user."));
|
|
383
|
-
return 1;
|
|
384
|
-
}
|
|
385
|
-
if (choice === "skip") {
|
|
386
|
-
results.push(
|
|
387
|
-
writeShim(projectRoot, shim, { onDrift: "skip" })
|
|
388
|
-
);
|
|
389
|
-
continue;
|
|
390
|
-
}
|
|
391
|
-
results.push(
|
|
392
|
-
writeShim(projectRoot, shim, { onDrift: "overwrite" })
|
|
393
|
-
);
|
|
394
|
-
continue;
|
|
395
|
-
}
|
|
396
|
-
const onDrift = opts.force ? "overwrite" : "error";
|
|
397
|
-
results.push(writeShim(projectRoot, shim, { onDrift }));
|
|
398
|
-
}
|
|
399
|
-
refreshDesignMdHash(projectRoot);
|
|
400
|
-
p.log.message(pc.bold("\nResults:"));
|
|
401
|
-
for (const r of results) {
|
|
402
|
-
const rel = relative(projectRoot, r.path);
|
|
403
|
-
p.log.message(` ${WRITE_LABEL[r.status]} ${rel}`);
|
|
404
|
-
}
|
|
405
|
-
const drifted = results.filter((r) => r.status === "skipped-drift").length;
|
|
406
|
-
const changed = results.filter(
|
|
407
|
-
(r) => r.status === "created" || r.status === "updated"
|
|
408
|
-
).length;
|
|
409
|
-
p.outro(
|
|
410
|
-
drifted > 0 ? pc.yellow(`${changed} written, ${drifted} skipped (drift).`) : pc.green(`${changed} written.`)
|
|
411
|
-
);
|
|
412
|
-
return 0;
|
|
413
|
-
}
|
|
414
|
-
export {
|
|
415
|
-
runSync
|
|
416
|
-
};
|
|
417
|
-
//# sourceMappingURL=sync-FDYRKNFE.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/sync.ts","../src/core/shims.ts","../src/core/sync-lock.ts"],"sourcesContent":["import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { existsSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport {\n ALL_SHIMS,\n inspectShim,\n writeShim,\n refreshDesignMdHash,\n type Shim,\n type InspectResult,\n type WriteShimResult,\n} from '../core/shims.js';\n\nconst DESIGN_MD_NAME = 'DESIGN.md';\nconst DEPRECATED_MD_NAME = 'DESIGN_DEPRECATED.md';\nconst INIT_CONTEXT_PATH = '.omd/init-context.json';\n\nexport interface SyncOptions {\n dir?: string;\n force?: boolean;\n check?: boolean;\n}\n\nconst STATUS_LABEL: Record<InspectResult['status'], string> = {\n missing: pc.yellow('missing'),\n clean: pc.green('clean'),\n drifted: pc.red('drifted'),\n 'out-of-date': pc.cyan('out-of-date'),\n};\n\nconst WRITE_LABEL: Record<WriteShimResult['status'], string> = {\n created: pc.green('created'),\n updated: pc.cyan('updated'),\n unchanged: pc.dim('unchanged'),\n 'skipped-drift': pc.yellow('skipped'),\n};\n\nfunction printDiff(label: string, current: string, proposed: string): void {\n p.log.message(pc.bold('─── current (' + label + ') ───'));\n p.log.message(current || pc.dim('(empty)'));\n p.log.message(pc.bold('─── proposed ───'));\n p.log.message(proposed);\n}\n\ntype DriftChoice = 'overwrite' | 'skip' | 'show' | 'quit';\n\nasync function promptDrift(shim: Shim, inspection: InspectResult): Promise<DriftChoice> {\n while (true) {\n const choice = await p.select<DriftChoice>({\n message: `${pc.bold(shim.relPath)} has drift — choose:`,\n options: [\n { value: 'overwrite', label: 'Overwrite with rendered content' },\n { value: 'skip', label: 'Skip (keep user edits)' },\n { value: 'show', label: 'Show diff' },\n { value: 'quit', label: 'Quit sync' },\n ],\n });\n\n if (p.isCancel(choice)) return 'quit';\n if (choice !== 'show') return choice;\n\n printDiff(\n shim.relPath,\n inspection.existing ?? '',\n inspection.rendered\n );\n }\n}\n\nexport async function runSync(opts: SyncOptions = {}): Promise<number> {\n const projectRoot = opts.dir ?? process.cwd();\n const relRoot = relative(process.cwd(), projectRoot) || '.';\n\n p.intro(pc.bold('omd sync') + pc.dim(` (${relRoot})`));\n\n const inspections = ALL_SHIMS.map((shim) => ({\n shim,\n result: inspectShim(projectRoot, shim),\n }));\n\n p.log.message(pc.bold('Status:'));\n for (const { result } of inspections) {\n const rel = relative(projectRoot, result.path);\n p.log.message(` ${STATUS_LABEL[result.status]} ${rel}`);\n }\n\n // Mid-flow detection: shims may be clean while DESIGN.md is mid-init\n // (after `omd init prepare` renamed the old one but before the agent\n // wrote the new one). Surface this as a soft warning so users don't\n // mistake \"All clean\" for \"fully done\".\n const designMdMissing = !existsSync(join(projectRoot, DESIGN_MD_NAME));\n const initContextExists = existsSync(join(projectRoot, INIT_CONTEXT_PATH));\n const deprecatedExists = existsSync(join(projectRoot, DEPRECATED_MD_NAME));\n const midInitFlow =\n designMdMissing && (initContextExists || deprecatedExists);\n\n if (opts.check) {\n const unsynced = inspections.filter(\n (i) => i.result.status !== 'clean'\n );\n if (unsynced.length > 0) {\n p.outro(\n pc.red(\n `${unsynced.length} not in sync — rerun without --check to resolve.`\n )\n );\n return 1;\n }\n if (designMdMissing) {\n p.log.warn(\n midInitFlow\n ? 'DESIGN.md is missing but init-context is staged — your agent still needs to run the `omd:init` skill to write DESIGN.md.'\n : 'DESIGN.md is missing — run `npx oh-my-design-cli init recommend \"<description>\"` to bootstrap, or have your agent run the `omd:init` skill.'\n );\n }\n p.outro(pc.green('Shims clean.'));\n return 0;\n }\n\n const results: WriteShimResult[] = [];\n\n for (const { shim, result } of inspections) {\n if (result.status === 'clean') {\n results.push({\n id: shim.id,\n path: result.path,\n hash: '',\n status: 'unchanged',\n });\n continue;\n }\n\n if (result.status === 'drifted' && !opts.force) {\n const choice = await promptDrift(shim, result);\n if (choice === 'quit') {\n p.outro(pc.yellow('Aborted by user.'));\n return 1;\n }\n if (choice === 'skip') {\n results.push(\n writeShim(projectRoot, shim, { onDrift: 'skip' })\n );\n continue;\n }\n // overwrite\n results.push(\n writeShim(projectRoot, shim, { onDrift: 'overwrite' })\n );\n continue;\n }\n\n // missing / out-of-date / (drifted with --force)\n const onDrift = opts.force ? 'overwrite' : 'error';\n results.push(writeShim(projectRoot, shim, { onDrift }));\n }\n\n refreshDesignMdHash(projectRoot);\n\n p.log.message(pc.bold('\\nResults:'));\n for (const r of results) {\n const rel = relative(projectRoot, r.path);\n p.log.message(` ${WRITE_LABEL[r.status]} ${rel}`);\n }\n\n const drifted = results.filter((r) => r.status === 'skipped-drift').length;\n const changed = results.filter(\n (r) => r.status === 'created' || r.status === 'updated'\n ).length;\n\n p.outro(\n drifted > 0\n ? pc.yellow(`${changed} written, ${drifted} skipped (drift).`)\n : pc.green(`${changed} written.`)\n );\n\n return 0;\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport {\n parseBlock,\n writeBlock,\n hashContent,\n hasDrift,\n} from './sync-marker.js';\nimport { updateTarget, updateDesignMdHash } from './sync-lock.js';\n\nexport const MANAGED_BLOCK_VERSION = 1;\n\nexport type ShimId = 'claude' | 'agents' | 'cursor';\n\nexport type ShimMode = 'block' | 'whole';\n\nexport interface Shim {\n id: ShimId;\n relPath: string;\n mode: ShimMode;\n render(): string;\n}\n\nconst CLAUDE_BODY = `# Design System (oh-my-design)\n\nThe authoritative brand & UI spec is **@./DESIGN.md**.\nRead before any UI/styling/microcopy/motion work.\n\nPreference log (pending corrections): @./.omd/preferences.md\n\nPrecedence: DESIGN.md > preferences.md > your defaults.`;\n\nconst AGENTS_BODY = `## Design System (oh-my-design)\n\n**Before any UI, styling, copy, or motion change, open and read \\`./DESIGN.md\\` in full.** It is the authoritative brand/design spec. Treat its tokens, voice, and component rules as binding unless the user overrides in chat.\n\nIf present, read \\`./.omd/preferences.md\\` — pending corrections not yet folded into DESIGN.md. Apply them; flag conflicts.`;\n\nconst CURSOR_FRONTMATTER = `---\ndescription: Authoritative brand & UI design system. Read DESIGN.md before UI work.\nglobs:\n - \"**/*.tsx\"\n - \"**/*.jsx\"\n - \"**/*.vue\"\n - \"**/*.svelte\"\n - \"**/*.css\"\n - \"**/*.scss\"\n - \"**/tailwind.config.*\"\n - \"**/components/**\"\n - \"**/app/**/page.*\"\nalwaysApply: false\n---`;\n\nconst CURSOR_BODY = `The authoritative design spec lives at \\`@DESIGN.md\\` (repo root). Open and read before generating/modifying UI.\n\nPending preference corrections: \\`@.omd/preferences.md\\`.\n\nPrecedence: DESIGN.md > preferences.md > framework defaults.`;\n\nexport const CLAUDE_SHIM: Shim = {\n id: 'claude',\n relPath: 'CLAUDE.md',\n mode: 'block',\n render: () => CLAUDE_BODY,\n};\n\nexport const AGENTS_SHIM: Shim = {\n id: 'agents',\n relPath: 'AGENTS.md',\n mode: 'block',\n render: () => AGENTS_BODY,\n};\n\nexport const CURSOR_SHIM: Shim = {\n id: 'cursor',\n relPath: '.cursor/rules/omd-design.mdc',\n mode: 'whole',\n render: () => {\n const hash = hashContent(CURSOR_BODY);\n return `${CURSOR_FRONTMATTER}\\n\\n<!-- omd:start v=${MANAGED_BLOCK_VERSION} hash=${hash} -->\\n${CURSOR_BODY}\\n<!-- omd:end -->\\n`;\n },\n};\n\nexport const ALL_SHIMS: readonly Shim[] = [\n CLAUDE_SHIM,\n AGENTS_SHIM,\n CURSOR_SHIM,\n] as const;\n\nexport type DriftAction = 'overwrite' | 'skip' | 'error';\n\nexport interface WriteShimResult {\n id: ShimId;\n path: string;\n hash: string;\n status: 'created' | 'updated' | 'unchanged' | 'skipped-drift';\n}\n\nexport interface WriteShimsOptions {\n onDrift?: DriftAction;\n}\n\nfunction resolvePath(projectRoot: string, relPath: string): string {\n return join(projectRoot, relPath);\n}\n\nfunction readFileOrEmpty(path: string): string {\n return existsSync(path) ? readFileSync(path, 'utf8') : '';\n}\n\nfunction ensureDir(path: string): void {\n mkdirSync(dirname(path), { recursive: true });\n}\n\nexport type InspectStatus =\n | 'missing'\n | 'clean'\n | 'drifted'\n | 'out-of-date';\n\nexport interface InspectResult {\n id: ShimId;\n path: string;\n status: InspectStatus;\n existing?: string;\n rendered: string;\n}\n\nexport function inspectShim(projectRoot: string, shim: Shim): InspectResult {\n const abs = resolvePath(projectRoot, shim.relPath);\n const existing = readFileOrEmpty(abs);\n const fileExists = existing !== '';\n\n if (shim.mode === 'whole') {\n const rendered = shim.render();\n if (!fileExists) {\n return { id: shim.id, path: abs, status: 'missing', rendered };\n }\n if (existing === rendered) {\n return { id: shim.id, path: abs, status: 'clean', existing, rendered };\n }\n return { id: shim.id, path: abs, status: 'drifted', existing, rendered };\n }\n\n const managed = shim.render();\n const block = parseBlock(existing);\n\n if (!block) {\n return {\n id: shim.id,\n path: abs,\n status: 'missing',\n existing: fileExists ? existing : undefined,\n rendered: managed,\n };\n }\n\n if (hasDrift(block)) {\n return {\n id: shim.id,\n path: abs,\n status: 'drifted',\n existing: block.content,\n rendered: managed,\n };\n }\n\n if (block.content === managed) {\n return {\n id: shim.id,\n path: abs,\n status: 'clean',\n existing: block.content,\n rendered: managed,\n };\n }\n\n return {\n id: shim.id,\n path: abs,\n status: 'out-of-date',\n existing: block.content,\n rendered: managed,\n };\n}\n\nexport function inspectAllShims(projectRoot: string): InspectResult[] {\n return ALL_SHIMS.map((s) => inspectShim(projectRoot, s));\n}\n\nexport function writeShim(\n projectRoot: string,\n shim: Shim,\n opts: WriteShimsOptions = {}\n): WriteShimResult {\n const onDrift = opts.onDrift ?? 'error';\n const abs = resolvePath(projectRoot, shim.relPath);\n const existing = readFileOrEmpty(abs);\n const fileExists = existing !== '';\n\n if (shim.mode === 'whole') {\n const rendered = shim.render();\n const newHash = hashContent(rendered);\n\n if (fileExists && existing !== rendered) {\n const existingHash = hashContent(existing);\n if (onDrift === 'error') {\n throw new Error(\n `drift detected in ${shim.relPath} (existing hash ${existingHash} != rendered ${newHash}); rerun with onDrift=overwrite to force`\n );\n }\n if (onDrift === 'skip') {\n updateTarget(projectRoot, shim.relPath, existingHash);\n return {\n id: shim.id,\n path: abs,\n hash: existingHash,\n status: 'skipped-drift',\n };\n }\n }\n\n if (fileExists && existing === rendered) {\n updateTarget(projectRoot, shim.relPath, newHash);\n return { id: shim.id, path: abs, hash: newHash, status: 'unchanged' };\n }\n\n ensureDir(abs);\n writeFileSync(abs, rendered, 'utf8');\n updateTarget(projectRoot, shim.relPath, newHash);\n return {\n id: shim.id,\n path: abs,\n hash: newHash,\n status: fileExists ? 'updated' : 'created',\n };\n }\n\n const managed = shim.render();\n const existingBlock = parseBlock(existing);\n\n if (existingBlock && hasDrift(existingBlock)) {\n if (onDrift === 'error') {\n throw new Error(\n `managed block in ${shim.relPath} was hand-edited; rerun with onDrift=overwrite to force`\n );\n }\n if (onDrift === 'skip') {\n updateTarget(projectRoot, shim.relPath, existingBlock.hash);\n return {\n id: shim.id,\n path: abs,\n hash: existingBlock.hash,\n status: 'skipped-drift',\n };\n }\n }\n\n if (existingBlock && existingBlock.content === managed && !hasDrift(existingBlock)) {\n updateTarget(projectRoot, shim.relPath, existingBlock.hash);\n return {\n id: shim.id,\n path: abs,\n hash: existingBlock.hash,\n status: 'unchanged',\n };\n }\n\n const { updated, hash } = writeBlock(existing, managed, MANAGED_BLOCK_VERSION);\n ensureDir(abs);\n writeFileSync(abs, updated, 'utf8');\n updateTarget(projectRoot, shim.relPath, hash);\n return {\n id: shim.id,\n path: abs,\n hash,\n status: existingBlock ? 'updated' : 'created',\n };\n}\n\nexport function writeAllShims(\n projectRoot: string,\n opts: WriteShimsOptions = {}\n): WriteShimResult[] {\n const results = ALL_SHIMS.map((shim) => writeShim(projectRoot, shim, opts));\n refreshDesignMdHash(projectRoot);\n return results;\n}\n\nexport function refreshDesignMdHash(projectRoot: string): string | null {\n const designMdPath = join(projectRoot, 'DESIGN.md');\n if (!existsSync(designMdPath)) return null;\n const hash = hashContent(readFileSync(designMdPath, 'utf8'));\n updateDesignMdHash(projectRoot, hash);\n return hash;\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { z } from 'zod';\n\nexport const SYNC_LOCK_VERSION = 1;\nexport const SYNC_LOCK_PATH = '.omd/sync.lock.json';\n\nconst TargetSchema = z.object({\n managed_hash: z.string(),\n last_synced: z.string(),\n});\n\nconst SyncLockSchema = z.object({\n version: z.number().int().positive(),\n design_md_hash: z.string(),\n targets: z.record(z.string(), TargetSchema),\n});\n\nexport type SyncTarget = z.infer<typeof TargetSchema>;\nexport type SyncLock = z.infer<typeof SyncLockSchema>;\n\nfunction lockPath(projectRoot: string): string {\n return join(projectRoot, SYNC_LOCK_PATH);\n}\n\nexport function readLock(projectRoot: string): SyncLock | null {\n const path = lockPath(projectRoot);\n if (!existsSync(path)) return null;\n const raw = readFileSync(path, 'utf8');\n const parsed = JSON.parse(raw);\n return SyncLockSchema.parse(parsed);\n}\n\nexport function writeLock(projectRoot: string, lock: SyncLock): void {\n const validated = SyncLockSchema.parse(lock);\n const path = lockPath(projectRoot);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, JSON.stringify(validated, null, 2) + '\\n', 'utf8');\n}\n\nexport function createLock(designMdHash: string): SyncLock {\n return {\n version: SYNC_LOCK_VERSION,\n design_md_hash: designMdHash,\n targets: {},\n };\n}\n\nexport function updateTarget(\n projectRoot: string,\n target: string,\n managedHash: string\n): SyncLock {\n const existing = readLock(projectRoot) ?? createLock('');\n const next: SyncLock = {\n ...existing,\n targets: {\n ...existing.targets,\n [target]: {\n managed_hash: managedHash,\n last_synced: new Date().toISOString(),\n },\n },\n };\n writeLock(projectRoot, next);\n return next;\n}\n\nexport function updateDesignMdHash(\n projectRoot: string,\n designMdHash: string\n): SyncLock {\n const existing = readLock(projectRoot) ?? createLock(designMdHash);\n const next: SyncLock = { ...existing, design_md_hash: designMdHash };\n writeLock(projectRoot, next);\n return next;\n}\n"],"mappings":"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","names":["existsSync","join","readFileSync","writeFileSync","mkdirSync","existsSync","dirname","join","join","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","join","existsSync","readFileSync","existsSync","join"]}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# {{name}}
|
|
2
|
-
|
|
3
|
-
> Generated by [oh-my-design](https://github.com/oh-my-design/oh-my-design) v{{version}} on {{generatedAt}}
|
|
4
|
-
{{#if presetName}}> Preset: **{{presetName}}**{{/if}}
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
{{> visual-theme }}
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
{{> color-palette }}
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
{{> typography }}
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
{{> component-stylings }}
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
{{> layout }}
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
{{> depth-elevation }}
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
{{> dos-donts }}
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
{{> responsive }}
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
{{> agent-prompt-guide }}
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
{{> shadcn-tokens }}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
## 9. Agent Prompt Guide
|
|
2
|
-
|
|
3
|
-
Use these references when prompting AI coding agents to build UI matching this design system.
|
|
4
|
-
|
|
5
|
-
### Quick Color Reference
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
Primary: {{colors.primary.base}}
|
|
9
|
-
Background: {{colors.background}}
|
|
10
|
-
Foreground: {{colors.foreground}}
|
|
11
|
-
Card: {{colors.card.base}}
|
|
12
|
-
Border: {{colors.border}}
|
|
13
|
-
Destructive: {{colors.destructive.base}}
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
### Quick Style Reference
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
Font: {{typography.fontFamily.sans}}
|
|
20
|
-
Radius: {{radius.md}}
|
|
21
|
-
Shadow: {{shadows.md}}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Example Prompts
|
|
25
|
-
|
|
26
|
-
- "Build a dashboard page using this DESIGN.md. Use the primary color for CTAs and the card surface for content sections."
|
|
27
|
-
- "Create a form with inputs, labels, and a submit button. Follow the spacing scale and component padding from the design system."
|
|
28
|
-
- "Add a data table component with sortable columns. Use the border color for row dividers and the muted color for alternating rows."
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
## 2. Color Palette & Roles
|
|
2
|
-
|
|
3
|
-
### Primary Scale
|
|
4
|
-
|
|
5
|
-
| Stop | Hex | Usage |
|
|
6
|
-
|------|-----|-------|
|
|
7
|
-
| 50 | `{{lookup colors.primary.scale "50"}}` | Subtle backgrounds, hover tints |
|
|
8
|
-
| 100 | `{{lookup colors.primary.scale "100"}}` | Light backgrounds, selected states |
|
|
9
|
-
| 200 | `{{lookup colors.primary.scale "200"}}` | Borders on primary elements |
|
|
10
|
-
| 300 | `{{lookup colors.primary.scale "300"}}` | Icons, secondary interactions |
|
|
11
|
-
| 400 | `{{lookup colors.primary.scale "400"}}` | Hover state for primary buttons |
|
|
12
|
-
| 500 | `{{lookup colors.primary.scale "500"}}` | **Primary brand color** — buttons, links, focus rings |
|
|
13
|
-
| 600 | `{{lookup colors.primary.scale "600"}}` | Active/pressed state |
|
|
14
|
-
| 700 | `{{lookup colors.primary.scale "700"}}` | High-emphasis text on light backgrounds |
|
|
15
|
-
| 800 | `{{lookup colors.primary.scale "800"}}` | Heading text alternative |
|
|
16
|
-
| 900 | `{{lookup colors.primary.scale "900"}}` | Heavy emphasis |
|
|
17
|
-
| 950 | `{{lookup colors.primary.scale "950"}}` | Near-black for dark surfaces |
|
|
18
|
-
|
|
19
|
-
### Semantic Colors
|
|
20
|
-
|
|
21
|
-
| Role | Base | Foreground | Usage |
|
|
22
|
-
|------|------|------------|-------|
|
|
23
|
-
| **Primary** | `{{colors.primary.base}}` | `{{colors.primary.foreground}}` | CTAs, active states, links |
|
|
24
|
-
| **Secondary** | `{{colors.secondary.base}}` | `{{colors.secondary.foreground}}` | Secondary buttons, subtle backgrounds |
|
|
25
|
-
| **Accent** | `{{colors.accent.base}}` | `{{colors.accent.foreground}}` | Highlights, badges, notifications |
|
|
26
|
-
| **Muted** | `{{colors.muted.base}}` | `{{colors.muted.foreground}}` | Disabled states, placeholder text, subtle dividers |
|
|
27
|
-
| **Destructive** | `{{colors.destructive.base}}` | `{{colors.destructive.foreground}}` | Errors, delete actions, warnings |
|
|
28
|
-
|
|
29
|
-
### Surface Colors
|
|
30
|
-
|
|
31
|
-
| Surface | Value | Usage |
|
|
32
|
-
|---------|-------|-------|
|
|
33
|
-
| Background | `{{colors.background}}` | Page background |
|
|
34
|
-
| Foreground | `{{colors.foreground}}` | Default text color |
|
|
35
|
-
| Card | `{{colors.card.base}}` | Card and contained surface backgrounds |
|
|
36
|
-
| Popover | `{{colors.popover.base}}` | Dropdowns, tooltips, dialogs |
|
|
37
|
-
| Border | `{{colors.border}}` | Default border color |
|
|
38
|
-
| Input | `{{colors.input}}` | Form input borders |
|
|
39
|
-
| Ring | `{{colors.ring}}` | Focus ring color |
|
|
40
|
-
|
|
41
|
-
### Chart Colors
|
|
42
|
-
|
|
43
|
-
| Token | Hex |
|
|
44
|
-
|-------|-----|
|
|
45
|
-
| Chart 1 | `{{chartColor colors.chart 0}}` |
|
|
46
|
-
| Chart 2 | `{{chartColor colors.chart 1}}` |
|
|
47
|
-
| Chart 3 | `{{chartColor colors.chart 2}}` |
|
|
48
|
-
| Chart 4 | `{{chartColor colors.chart 3}}` |
|
|
49
|
-
| Chart 5 | `{{chartColor colors.chart 4}}` |
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
## 4. Component Stylings
|
|
2
|
-
|
|
3
|
-
{{#each componentList}}
|
|
4
|
-
### {{this.title}}
|
|
5
|
-
|
|
6
|
-
{{this.description}}
|
|
7
|
-
|
|
8
|
-
**Variants:**
|
|
9
|
-
{{#each this.variants}}
|
|
10
|
-
- **{{@key}}**: background `{{this.background}}`, text `{{this.foreground}}`{{#if this.border}}, border `{{this.border}}`{{/if}}
|
|
11
|
-
{{/each}}
|
|
12
|
-
|
|
13
|
-
**States:**
|
|
14
|
-
{{#if this.states.hover}}- Hover: {{this.states.hover}}{{/if}}
|
|
15
|
-
{{#if this.states.active}}- Active: {{this.states.active}}{{/if}}
|
|
16
|
-
{{#if this.states.focus}}- Focus: {{this.states.focus}}{{/if}}
|
|
17
|
-
{{#if this.states.disabled}}- Disabled: {{this.states.disabled}}{{/if}}
|
|
18
|
-
|
|
19
|
-
{{#if this.sizes}}
|
|
20
|
-
**Sizes:**
|
|
21
|
-
| Size | Height | Padding | Font Size |
|
|
22
|
-
|------|--------|---------|-----------|
|
|
23
|
-
{{#each this.sizes}}
|
|
24
|
-
| {{@key}} | {{this.height}} | {{this.padding}} | {{this.fontSize}} |
|
|
25
|
-
{{/each}}
|
|
26
|
-
{{/if}}
|
|
27
|
-
|
|
28
|
-
{{/each}}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
## 6. Depth & Elevation
|
|
2
|
-
|
|
3
|
-
{{#if (eq preferences.depth "flat")}}
|
|
4
|
-
This system uses a **flat design** approach. Depth is communicated through borders and background color shifts, not shadows.
|
|
5
|
-
{{/if}}
|
|
6
|
-
{{#if (eq preferences.depth "subtle")}}
|
|
7
|
-
This system uses **subtle ambient shadows** to create gentle separation between surface levels without drawing attention to the shadows themselves.
|
|
8
|
-
{{/if}}
|
|
9
|
-
{{#if (eq preferences.depth "layered")}}
|
|
10
|
-
This system uses **multi-layer shadows** to establish a clear spatial hierarchy. Each elevation level is visually distinct.
|
|
11
|
-
{{/if}}
|
|
12
|
-
{{#if (eq preferences.depth "dramatic")}}
|
|
13
|
-
This system uses **dramatic shadows** with high opacity to create bold separation between surfaces. Depth is a primary design tool.
|
|
14
|
-
{{/if}}
|
|
15
|
-
|
|
16
|
-
### Shadow Scale
|
|
17
|
-
|
|
18
|
-
| Level | Value | Usage |
|
|
19
|
-
|-------|-------|-------|
|
|
20
|
-
| None | `{{shadows.none}}` | Inline elements, flat content |
|
|
21
|
-
| Small | `{{shadows.sm}}` | Buttons, input fields |
|
|
22
|
-
| Medium | `{{shadows.md}}` | Cards, raised sections |
|
|
23
|
-
| Large | `{{shadows.lg}}` | Dropdowns, popovers |
|
|
24
|
-
| Extra Large | `{{shadows.xl}}` | Dialogs, modals, toasts |
|
|
25
|
-
|
|
26
|
-
### Surface Hierarchy
|
|
27
|
-
|
|
28
|
-
1. **Base** — Page background (`{{colors.background}}`)
|
|
29
|
-
2. **Raised** — Cards, sections (`{{colors.card.base}}` + shadow-sm)
|
|
30
|
-
3. **Overlay** — Popovers, dropdowns (`{{colors.popover.base}}` + shadow-lg)
|
|
31
|
-
4. **Modal** — Dialogs, command palettes (shadow-xl + backdrop)
|