oh-my-design-cli 0.1.3 → 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 -21
- 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/bin/oh-my-design.js
CHANGED
|
@@ -1,717 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
listReferences,
|
|
4
|
-
loadReference
|
|
5
|
-
} from "../chunk-N2JG6N4Q.js";
|
|
6
|
-
import {
|
|
7
|
-
applyOverrides,
|
|
8
|
-
contrastForeground,
|
|
9
|
-
darken,
|
|
10
|
-
generateColorScale,
|
|
11
|
-
hexToHsl,
|
|
12
|
-
hslToHex,
|
|
13
|
-
lighten
|
|
14
|
-
} from "../chunk-MHFYGZSO.js";
|
|
15
2
|
|
|
16
3
|
// bin/oh-my-design.ts
|
|
17
4
|
import { Command } from "commander";
|
|
18
5
|
import { readFileSync, existsSync } from "fs";
|
|
19
6
|
import { dirname, join } from "path";
|
|
20
7
|
import { fileURLToPath } from "url";
|
|
21
|
-
|
|
22
|
-
// src/cli/index.ts
|
|
23
|
-
import * as p2 from "@clack/prompts";
|
|
24
|
-
import { writeFileSync } from "fs";
|
|
25
|
-
import { resolve } from "path";
|
|
26
|
-
|
|
27
|
-
// src/cli/prompts.ts
|
|
28
|
-
import * as p from "@clack/prompts";
|
|
29
|
-
import pc from "picocolors";
|
|
30
|
-
async function runPrompts() {
|
|
31
|
-
p.intro(`${pc.bold("oh-my-design")} \u2014 Generate your DESIGN.md from real design systems`);
|
|
32
|
-
const refs = listReferences();
|
|
33
|
-
const categories = [...new Set(refs.map((r) => r.category))];
|
|
34
|
-
const category = await p.select({
|
|
35
|
-
message: "Pick a category:",
|
|
36
|
-
options: categories.map((cat) => {
|
|
37
|
-
const count = refs.filter((r) => r.category === cat).length;
|
|
38
|
-
return { value: cat, label: `${cat}`, hint: `${count} references` };
|
|
39
|
-
})
|
|
40
|
-
});
|
|
41
|
-
if (p.isCancel(category)) {
|
|
42
|
-
p.cancel("Cancelled.");
|
|
43
|
-
process.exit(0);
|
|
44
|
-
}
|
|
45
|
-
const categoryRefs = refs.filter((r) => r.category === category);
|
|
46
|
-
const refId = await p.select({
|
|
47
|
-
message: `Select a design system reference:`,
|
|
48
|
-
options: categoryRefs.map((r) => ({
|
|
49
|
-
value: r.id,
|
|
50
|
-
label: `${r.name}`,
|
|
51
|
-
hint: `${r.primaryColor}`
|
|
52
|
-
}))
|
|
53
|
-
});
|
|
54
|
-
if (p.isCancel(refId)) {
|
|
55
|
-
p.cancel("Cancelled.");
|
|
56
|
-
process.exit(0);
|
|
57
|
-
}
|
|
58
|
-
const reference = loadReference(refId);
|
|
59
|
-
p.log.info(`${pc.bold(reference.name)} loaded`);
|
|
60
|
-
p.log.info(` Primary: ${pc.bold(reference.colors.primary)} ${reference.colors.primaryName}`);
|
|
61
|
-
p.log.info(` Font: ${reference.typography.primary}`);
|
|
62
|
-
p.log.info(` Radius: ${reference.radius}`);
|
|
63
|
-
if (reference.mood) {
|
|
64
|
-
p.log.info(` Mood: ${reference.mood.slice(0, 120)}...`);
|
|
65
|
-
}
|
|
66
|
-
const mode = await p.select({
|
|
67
|
-
message: "How do you want to use this design system?",
|
|
68
|
-
options: [
|
|
69
|
-
{ value: "as-is", label: "Use as-is", hint: "Copy the reference DESIGN.md directly" },
|
|
70
|
-
{ value: "customized", label: "Customize", hint: "Modify colors, fonts, radius, etc." }
|
|
71
|
-
]
|
|
72
|
-
});
|
|
73
|
-
if (p.isCancel(mode)) {
|
|
74
|
-
p.cancel("Cancelled.");
|
|
75
|
-
process.exit(0);
|
|
76
|
-
}
|
|
77
|
-
if (mode === "as-is") {
|
|
78
|
-
const darkMode = await p.confirm({
|
|
79
|
-
message: "Include dark mode notes?",
|
|
80
|
-
initialValue: false
|
|
81
|
-
});
|
|
82
|
-
if (p.isCancel(darkMode)) {
|
|
83
|
-
p.cancel("Cancelled.");
|
|
84
|
-
process.exit(0);
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
reference,
|
|
88
|
-
overrides: { darkMode },
|
|
89
|
-
outputMode: "as-is"
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
const overrides = await p.group(
|
|
93
|
-
{
|
|
94
|
-
primaryColor: () => p.text({
|
|
95
|
-
message: `Primary color (current: ${reference.colors.primary}):`,
|
|
96
|
-
placeholder: "Press enter to keep, or type a hex like #6366f1",
|
|
97
|
-
validate: (val) => {
|
|
98
|
-
if (val && !/^#[0-9a-fA-F]{6}$/.test(val)) return "Invalid hex color";
|
|
99
|
-
}
|
|
100
|
-
}),
|
|
101
|
-
fontFamily: () => p.select({
|
|
102
|
-
message: `Primary font (current: ${reference.typography.primary}):`,
|
|
103
|
-
options: [
|
|
104
|
-
{ value: "", label: `Keep "${reference.typography.primary}"`, hint: "No change" },
|
|
105
|
-
{ value: "Inter", label: "Inter", hint: "Clean, geometric sans-serif" },
|
|
106
|
-
{ value: "system-ui", label: "System UI", hint: "Native OS fonts" },
|
|
107
|
-
{ value: "JetBrains Mono", label: "JetBrains Mono", hint: "Monospace, technical" },
|
|
108
|
-
{ value: "Geist", label: "Geist", hint: "Vercel's modern sans" }
|
|
109
|
-
]
|
|
110
|
-
}),
|
|
111
|
-
headingWeight: () => p.select({
|
|
112
|
-
message: `Heading weight (current: ${reference.typography.headingWeight}):`,
|
|
113
|
-
options: [
|
|
114
|
-
{ value: "", label: `Keep ${reference.typography.headingWeight}`, hint: "No change" },
|
|
115
|
-
{ value: "300", label: "300 \u2014 Light", hint: "Whisper authority (Stripe style)" },
|
|
116
|
-
{ value: "400", label: "400 \u2014 Regular" },
|
|
117
|
-
{ value: "500", label: "500 \u2014 Medium", hint: "Balanced emphasis" },
|
|
118
|
-
{ value: "600", label: "600 \u2014 Semibold", hint: "Strong headings" },
|
|
119
|
-
{ value: "700", label: "700 \u2014 Bold", hint: "Maximum impact" }
|
|
120
|
-
]
|
|
121
|
-
}),
|
|
122
|
-
borderRadius: () => p.select({
|
|
123
|
-
message: `Border radius (current: ${reference.radius}):`,
|
|
124
|
-
options: [
|
|
125
|
-
{ value: "", label: `Keep "${reference.radius}"`, hint: "No change" },
|
|
126
|
-
{ value: "2px", label: "Sharp (2px)", hint: "Technical, precise" },
|
|
127
|
-
{ value: "4px", label: "Tight (4px)", hint: "Conservative" },
|
|
128
|
-
{ value: "6px", label: "Moderate (6px)", hint: "Balanced" },
|
|
129
|
-
{ value: "8px", label: "Comfortable (8px)", hint: "Friendly" },
|
|
130
|
-
{ value: "12px", label: "Rounded (12px)", hint: "Soft, approachable" },
|
|
131
|
-
{ value: "9999px", label: "Pill", hint: "Fully rounded" }
|
|
132
|
-
]
|
|
133
|
-
}),
|
|
134
|
-
darkMode: () => p.confirm({
|
|
135
|
-
message: "Generate dark mode variant?",
|
|
136
|
-
initialValue: false
|
|
137
|
-
}),
|
|
138
|
-
additionalNotes: () => p.text({
|
|
139
|
-
message: "Any additional customization notes? (optional)",
|
|
140
|
-
placeholder: 'e.g. "Use more warm tones" or press enter to skip'
|
|
141
|
-
})
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
onCancel: () => {
|
|
145
|
-
p.cancel("Cancelled.");
|
|
146
|
-
process.exit(0);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
);
|
|
150
|
-
return {
|
|
151
|
-
reference,
|
|
152
|
-
overrides: {
|
|
153
|
-
primaryColor: overrides.primaryColor || void 0,
|
|
154
|
-
fontFamily: overrides.fontFamily || void 0,
|
|
155
|
-
headingWeight: overrides.headingWeight || void 0,
|
|
156
|
-
borderRadius: overrides.borderRadius || void 0,
|
|
157
|
-
darkMode: overrides.darkMode,
|
|
158
|
-
additionalNotes: overrides.additionalNotes || void 0
|
|
159
|
-
},
|
|
160
|
-
outputMode: "customized"
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// src/core/preview-generator.ts
|
|
165
|
-
function generatePreviewHtml(data) {
|
|
166
|
-
const {
|
|
167
|
-
name,
|
|
168
|
-
basedOn,
|
|
169
|
-
primary,
|
|
170
|
-
background,
|
|
171
|
-
foreground,
|
|
172
|
-
font,
|
|
173
|
-
headingWeight,
|
|
174
|
-
radius,
|
|
175
|
-
colors,
|
|
176
|
-
darkMode,
|
|
177
|
-
shadcnCss
|
|
178
|
-
} = data;
|
|
179
|
-
const isLightBg = isLight(background);
|
|
180
|
-
const scale = generateColorScale(primary);
|
|
181
|
-
const radiusPx = radius === "9999px" ? "24px" : radius;
|
|
182
|
-
const borderColor = colors.border;
|
|
183
|
-
const accent = colors.accent;
|
|
184
|
-
const muted = colors.muted;
|
|
185
|
-
const chart = colors.chart;
|
|
186
|
-
const darkBg = hslToHex(hexToHsl(primary)[0], 15, 7);
|
|
187
|
-
const darkFg = "#fafafa";
|
|
188
|
-
const darkBorder = hslToHex(hexToHsl(primary)[0], 10, 18);
|
|
189
|
-
return `<!DOCTYPE html>
|
|
190
|
-
<html lang="en">
|
|
191
|
-
<head>
|
|
192
|
-
<meta charset="UTF-8">
|
|
193
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
194
|
-
<title>${esc(name)} \u2014 Design System Preview</title>
|
|
195
|
-
<style>
|
|
196
|
-
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
197
|
-
|
|
198
|
-
:root {
|
|
199
|
-
--bg: ${background};
|
|
200
|
-
--fg: ${foreground};
|
|
201
|
-
--primary: ${primary};
|
|
202
|
-
--primary-fg: ${contrastForeground(primary)};
|
|
203
|
-
--accent: ${accent};
|
|
204
|
-
--muted: ${muted};
|
|
205
|
-
--muted-fg: ${lighten(foreground, 40)};
|
|
206
|
-
--border: ${borderColor};
|
|
207
|
-
--destructive: #ef4444;
|
|
208
|
-
--card: ${isLightBg ? "#ffffff" : lighten(background, 3)};
|
|
209
|
-
--radius: ${radiusPx};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.dark {
|
|
213
|
-
--bg: ${darkBg};
|
|
214
|
-
--fg: ${darkFg};
|
|
215
|
-
--card: ${lighten(darkBg, 3)};
|
|
216
|
-
--muted: ${hslToHex(hexToHsl(primary)[0], 10, 15)};
|
|
217
|
-
--muted-fg: ${darken(darkFg, 35)};
|
|
218
|
-
--border: ${darkBorder};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
body {
|
|
222
|
-
font-family: "${font}", "Inter", system-ui, sans-serif;
|
|
223
|
-
background: var(--bg);
|
|
224
|
-
color: var(--fg);
|
|
225
|
-
line-height: 1.5;
|
|
226
|
-
transition: background 0.25s, color 0.25s;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.shell { max-width: 1100px; margin: 0 auto; padding: 40px 24px 80px; }
|
|
230
|
-
|
|
231
|
-
/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
232
|
-
.header {
|
|
233
|
-
display: flex; justify-content: space-between; align-items: center;
|
|
234
|
-
padding-bottom: 24px; margin-bottom: 40px;
|
|
235
|
-
border-bottom: 1px solid var(--border);
|
|
236
|
-
}
|
|
237
|
-
.header h1 {
|
|
238
|
-
font-size: 2rem; font-weight: ${headingWeight};
|
|
239
|
-
letter-spacing: -0.02em;
|
|
240
|
-
}
|
|
241
|
-
.header .sub {
|
|
242
|
-
font-size: 0.875rem; color: var(--muted-fg); margin-top: 4px;
|
|
243
|
-
}
|
|
244
|
-
.controls { display: flex; gap: 8px; }
|
|
245
|
-
.ctrl-btn {
|
|
246
|
-
padding: 8px 16px; border-radius: var(--radius);
|
|
247
|
-
font-size: 0.8125rem; font-family: inherit; cursor: pointer;
|
|
248
|
-
transition: all 0.15s; border: 1px solid var(--border);
|
|
249
|
-
background: var(--card); color: var(--fg);
|
|
250
|
-
}
|
|
251
|
-
.ctrl-btn:hover { opacity: 0.85; }
|
|
252
|
-
.ctrl-btn.primary { background: var(--primary); color: var(--primary-fg); border-color: transparent; }
|
|
253
|
-
|
|
254
|
-
/* \u2500\u2500 Sections \u2500\u2500\u2500\u2500\u2500 */
|
|
255
|
-
.section { margin-bottom: 48px; }
|
|
256
|
-
.section-title {
|
|
257
|
-
font-size: 1.375rem; font-weight: ${headingWeight};
|
|
258
|
-
letter-spacing: -0.01em; margin-bottom: 16px;
|
|
259
|
-
}
|
|
260
|
-
.section-sub { font-size: 0.8125rem; color: var(--muted-fg); margin-bottom: 16px; }
|
|
261
|
-
|
|
262
|
-
/* \u2500\u2500 Color Scale \u2500\u2500 */
|
|
263
|
-
.scale-row {
|
|
264
|
-
display: flex; border-radius: var(--radius); overflow: hidden;
|
|
265
|
-
border: 1px solid var(--border); margin-bottom: 24px;
|
|
266
|
-
}
|
|
267
|
-
.scale-stop {
|
|
268
|
-
flex: 1; padding: 28px 4px 8px; text-align: center;
|
|
269
|
-
font-size: 10px; font-family: monospace; cursor: pointer;
|
|
270
|
-
transition: transform 0.1s; position: relative;
|
|
271
|
-
}
|
|
272
|
-
.scale-stop:hover { z-index: 1; transform: scaleY(1.12); }
|
|
273
|
-
.scale-stop .lbl { display: block; opacity: 0.7; margin-bottom: 2px; }
|
|
274
|
-
.scale-stop .hex {
|
|
275
|
-
background: rgba(0,0,0,0.2); color: #fff;
|
|
276
|
-
padding: 1px 4px; border-radius: 3px; font-size: 9px;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/* \u2500\u2500 Color Chips \u2500\u2500 */
|
|
280
|
-
.chip-grid {
|
|
281
|
-
display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px;
|
|
282
|
-
}
|
|
283
|
-
.chip {
|
|
284
|
-
border-radius: var(--radius); overflow: hidden;
|
|
285
|
-
border: 1px solid var(--border); cursor: pointer;
|
|
286
|
-
transition: transform 0.15s, box-shadow 0.15s;
|
|
287
|
-
}
|
|
288
|
-
.chip:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
|
289
|
-
.chip .sw { height: 64px; display: flex; align-items: end; padding: 6px; }
|
|
290
|
-
.chip .sw span {
|
|
291
|
-
font-size: 10px; font-family: monospace;
|
|
292
|
-
background: rgba(0,0,0,0.25); color: #fff;
|
|
293
|
-
padding: 1px 5px; border-radius: 3px;
|
|
294
|
-
}
|
|
295
|
-
.chip .inf { padding: 8px; background: var(--card); }
|
|
296
|
-
.chip .inf .n { font-size: 0.75rem; font-weight: 500; }
|
|
297
|
-
.chip .inf .v { font-size: 10px; color: var(--muted-fg); font-family: monospace; }
|
|
298
|
-
|
|
299
|
-
/* \u2500\u2500 Typography \u2500\u2500 */
|
|
300
|
-
.type-rows { display: flex; flex-direction: column; gap: 8px; }
|
|
301
|
-
.type-row {
|
|
302
|
-
display: flex; align-items: baseline; gap: 16px;
|
|
303
|
-
padding: 12px 16px; border-radius: var(--radius);
|
|
304
|
-
background: var(--card); border: 1px solid var(--border);
|
|
305
|
-
}
|
|
306
|
-
.type-row .lbl {
|
|
307
|
-
min-width: 48px; font-size: 0.75rem; color: var(--muted-fg);
|
|
308
|
-
font-family: monospace; flex-shrink: 0;
|
|
309
|
-
}
|
|
310
|
-
.type-row .sample { flex: 1; }
|
|
311
|
-
|
|
312
|
-
/* \u2500\u2500 Components \u2500\u2500 */
|
|
313
|
-
.comp-card {
|
|
314
|
-
padding: 24px; border-radius: var(--radius);
|
|
315
|
-
background: var(--card); border: 1px solid var(--border);
|
|
316
|
-
margin-bottom: 16px;
|
|
317
|
-
}
|
|
318
|
-
.comp-card h3 { font-size: 1rem; font-weight: 600; margin-bottom: 16px; }
|
|
319
|
-
.comp-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 12px; }
|
|
320
|
-
|
|
321
|
-
.btn {
|
|
322
|
-
display: inline-flex; align-items: center; justify-content: center;
|
|
323
|
-
font-family: inherit; font-weight: 500; cursor: pointer;
|
|
324
|
-
transition: all 0.15s; border: none; font-size: 0.8125rem;
|
|
325
|
-
padding: 8px 16px; height: 36px; border-radius: var(--radius);
|
|
326
|
-
}
|
|
327
|
-
.btn-primary { background: var(--primary); color: var(--primary-fg); }
|
|
328
|
-
.btn-secondary { background: var(--muted); color: var(--fg); }
|
|
329
|
-
.btn-outline { background: transparent; color: var(--fg); border: 1px solid var(--border); }
|
|
330
|
-
.btn-ghost { background: transparent; color: var(--fg); }
|
|
331
|
-
.btn-destructive { background: var(--destructive); color: #fff; }
|
|
332
|
-
.btn:hover { opacity: 0.9; }
|
|
333
|
-
|
|
334
|
-
.badge {
|
|
335
|
-
display: inline-flex; font-size: 0.6875rem; font-weight: 500;
|
|
336
|
-
padding: 2px 10px; border-radius: 9999px;
|
|
337
|
-
}
|
|
338
|
-
.badge-primary { background: var(--primary); color: var(--primary-fg); }
|
|
339
|
-
.badge-secondary { background: var(--muted); color: var(--fg); }
|
|
340
|
-
.badge-outline { background: transparent; color: var(--fg); border: 1px solid var(--border); }
|
|
341
|
-
|
|
342
|
-
.input-demo {
|
|
343
|
-
width: 100%; max-width: 320px; font-family: inherit;
|
|
344
|
-
background: var(--bg); color: var(--fg);
|
|
345
|
-
border: 1px solid var(--border); border-radius: var(--radius);
|
|
346
|
-
padding: 8px 12px; font-size: 0.8125rem; outline: none;
|
|
347
|
-
transition: border-color 0.15s;
|
|
348
|
-
}
|
|
349
|
-
.input-demo:focus {
|
|
350
|
-
border-color: var(--primary);
|
|
351
|
-
box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 20%, transparent);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
.demo-table {
|
|
355
|
-
width: 100%; border-collapse: collapse; font-size: 0.8125rem;
|
|
356
|
-
}
|
|
357
|
-
.demo-table th, .demo-table td {
|
|
358
|
-
padding: 10px 12px; text-align: left;
|
|
359
|
-
border-bottom: 1px solid var(--border);
|
|
360
|
-
}
|
|
361
|
-
.demo-table th {
|
|
362
|
-
font-weight: 500; color: var(--muted-fg);
|
|
363
|
-
font-size: 0.75rem; text-transform: uppercase;
|
|
364
|
-
letter-spacing: 0.05em;
|
|
365
|
-
}
|
|
366
|
-
.demo-table tr:hover td { background: var(--muted); }
|
|
367
|
-
|
|
368
|
-
.demo-card {
|
|
369
|
-
padding: 20px; border-radius: var(--radius);
|
|
370
|
-
background: var(--card); border: 1px solid var(--border);
|
|
371
|
-
max-width: 340px; box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
|
372
|
-
}
|
|
373
|
-
.demo-card h4 { font-weight: 600; margin-bottom: 6px; }
|
|
374
|
-
.demo-card p { font-size: 0.8125rem; color: var(--muted-fg); margin-bottom: 14px; }
|
|
375
|
-
|
|
376
|
-
.demo-dialog {
|
|
377
|
-
padding: 24px; border-radius: var(--radius);
|
|
378
|
-
background: var(--card); box-shadow: 0 20px 40px rgba(0,0,0,0.15);
|
|
379
|
-
max-width: 400px; border: 1px solid var(--border);
|
|
380
|
-
}
|
|
381
|
-
.demo-dialog h4 { font-weight: 600; margin-bottom: 8px; }
|
|
382
|
-
.demo-dialog p { font-size: 0.8125rem; color: var(--muted-fg); margin-bottom: 16px; }
|
|
383
|
-
.demo-dialog .acts { display: flex; justify-content: flex-end; gap: 8px; }
|
|
384
|
-
|
|
385
|
-
.tabs {
|
|
386
|
-
display: flex; background: var(--muted); border-radius: var(--radius); padding: 4px; gap: 2px;
|
|
387
|
-
}
|
|
388
|
-
.tab {
|
|
389
|
-
padding: 6px 14px; border-radius: calc(var(--radius) - 2px);
|
|
390
|
-
font-size: 0.8125rem; font-family: inherit; font-weight: 500;
|
|
391
|
-
border: none; cursor: pointer; background: transparent;
|
|
392
|
-
color: var(--muted-fg); transition: all 0.15s;
|
|
393
|
-
}
|
|
394
|
-
.tab.active {
|
|
395
|
-
background: var(--bg); color: var(--fg);
|
|
396
|
-
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
|
397
|
-
}
|
|
398
|
-
.tab:hover:not(.active) { color: var(--fg); }
|
|
399
|
-
|
|
400
|
-
/* \u2500\u2500 CSS Block \u2500\u2500\u2500\u2500 */
|
|
401
|
-
.css-block {
|
|
402
|
-
position: relative; background: var(--card);
|
|
403
|
-
border: 1px solid var(--border); border-radius: var(--radius);
|
|
404
|
-
overflow: hidden;
|
|
405
|
-
}
|
|
406
|
-
.css-block pre {
|
|
407
|
-
padding: 20px; overflow-x: auto; font-family: monospace;
|
|
408
|
-
font-size: 11px; line-height: 1.6; color: var(--fg);
|
|
409
|
-
}
|
|
410
|
-
.css-block .copy-css { position: absolute; top: 8px; right: 8px; }
|
|
411
|
-
|
|
412
|
-
/* \u2500\u2500 Spacing \u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
413
|
-
.spacing-vis {
|
|
414
|
-
display: flex; align-items: end; gap: 8px; padding: 24px;
|
|
415
|
-
background: var(--card); border: 1px solid var(--border);
|
|
416
|
-
border-radius: var(--radius);
|
|
417
|
-
}
|
|
418
|
-
.sp-bar { display: flex; flex-direction: column; align-items: center; gap: 4px; }
|
|
419
|
-
.sp-bar .bar { background: var(--primary); border-radius: 2px; width: 28px; }
|
|
420
|
-
.sp-bar .val { font-size: 10px; font-family: monospace; color: var(--muted-fg); }
|
|
421
|
-
|
|
422
|
-
/* \u2500\u2500 Radius \u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
423
|
-
.radius-grid { display: flex; gap: 16px; flex-wrap: wrap; }
|
|
424
|
-
.radius-demo {
|
|
425
|
-
width: 72px; height: 72px; background: var(--primary);
|
|
426
|
-
display: flex; align-items: center; justify-content: center;
|
|
427
|
-
color: var(--primary-fg); font-size: 0.6875rem; font-family: monospace;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/* \u2500\u2500 Toast \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
431
|
-
.toast-popup {
|
|
432
|
-
position: fixed; bottom: 24px; right: 24px;
|
|
433
|
-
padding: 10px 20px; background: var(--fg); color: var(--bg);
|
|
434
|
-
border-radius: var(--radius); font-size: 0.8125rem;
|
|
435
|
-
box-shadow: 0 8px 20px rgba(0,0,0,0.15);
|
|
436
|
-
transform: translateY(100px); opacity: 0;
|
|
437
|
-
transition: all 0.3s; z-index: 100;
|
|
438
|
-
}
|
|
439
|
-
.toast-popup.show { transform: translateY(0); opacity: 1; }
|
|
440
|
-
|
|
441
|
-
@media (max-width: 768px) {
|
|
442
|
-
.shell { padding: 16px 12px 48px; }
|
|
443
|
-
.header { flex-direction: column; gap: 12px; align-items: flex-start; }
|
|
444
|
-
.chip-grid { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); }
|
|
445
|
-
}
|
|
446
|
-
</style>
|
|
447
|
-
</head>
|
|
448
|
-
<body>
|
|
449
|
-
<div class="shell">
|
|
450
|
-
|
|
451
|
-
<div class="header">
|
|
452
|
-
<div>
|
|
453
|
-
<h1>${esc(name)}</h1>
|
|
454
|
-
<div class="sub">Based on ${esc(basedOn)} · Generated by oh-my-design</div>
|
|
455
|
-
</div>
|
|
456
|
-
<div class="controls">
|
|
457
|
-
${darkMode ? '<button class="ctrl-btn" onclick="toggleTheme()" id="theme-btn">\u{1F319} Dark</button>' : ""}
|
|
458
|
-
<button class="ctrl-btn primary" onclick="copyCss()">Copy CSS</button>
|
|
459
|
-
</div>
|
|
460
|
-
</div>
|
|
461
|
-
|
|
462
|
-
<!-- Primary Scale -->
|
|
463
|
-
<div class="section">
|
|
464
|
-
<h2 class="section-title">Primary Color Scale</h2>
|
|
465
|
-
<div class="section-sub">Click to copy hex value</div>
|
|
466
|
-
<div class="scale-row">
|
|
467
|
-
${Object.entries(scale).map(([stop, hex]) => ` <div class="scale-stop" style="background:${hex};color:${isLight(hex) ? "#000" : "#fff"}" onclick="copy('${hex}')">
|
|
468
|
-
<span class="lbl">${stop}</span><span class="hex">${hex}</span>
|
|
469
|
-
</div>`).join("\n")}
|
|
470
|
-
</div>
|
|
471
|
-
</div>
|
|
472
|
-
|
|
473
|
-
<!-- Semantic Colors -->
|
|
474
|
-
<div class="section">
|
|
475
|
-
<h2 class="section-title">Semantic Colors</h2>
|
|
476
|
-
<div class="chip-grid">
|
|
477
|
-
${[
|
|
478
|
-
{ n: "Primary", bg: primary, v: "--primary" },
|
|
479
|
-
{ n: "Accent", bg: accent, v: "--accent" },
|
|
480
|
-
{ n: "Muted", bg: muted, v: "--muted" },
|
|
481
|
-
{ n: "Destructive", bg: "#ef4444", v: "--destructive" },
|
|
482
|
-
{ n: "Background", bg: background, v: "--background" },
|
|
483
|
-
{ n: "Foreground", bg: foreground, v: "--foreground" },
|
|
484
|
-
{ n: "Border", bg: borderColor, v: "--border" },
|
|
485
|
-
{ n: "Card", bg: isLightBg ? "#ffffff" : lighten(background, 3), v: "--card" }
|
|
486
|
-
].map((c) => ` <div class="chip" onclick="copy('${c.bg}')">
|
|
487
|
-
<div class="sw" style="background:${c.bg}"><span>${c.bg}</span></div>
|
|
488
|
-
<div class="inf"><div class="n">${c.n}</div><div class="v">${c.v}</div></div>
|
|
489
|
-
</div>`).join("\n")}
|
|
490
|
-
</div>
|
|
491
|
-
</div>
|
|
492
|
-
|
|
493
|
-
<!-- Chart Colors -->
|
|
494
|
-
<div class="section">
|
|
495
|
-
<h2 class="section-title">Chart Colors</h2>
|
|
496
|
-
<div style="display:flex;gap:8px;">
|
|
497
|
-
${chart.map((c, i) => ` <div style="width:48px;height:48px;border-radius:var(--radius);background:${c};cursor:pointer;" onclick="copy('${c}')" title="Chart ${i + 1}: ${c}"></div>`).join("\n")}
|
|
498
|
-
</div>
|
|
499
|
-
</div>
|
|
500
|
-
|
|
501
|
-
<!-- Typography -->
|
|
502
|
-
<div class="section">
|
|
503
|
-
<h2 class="section-title">Typography</h2>
|
|
504
|
-
<div class="type-rows">
|
|
505
|
-
<div class="type-row">
|
|
506
|
-
<span class="lbl">H1</span>
|
|
507
|
-
<span class="sample" style="font-size:2.25rem;font-weight:${headingWeight};letter-spacing:-0.02em;line-height:1.2">Page Title Heading</span>
|
|
508
|
-
</div>
|
|
509
|
-
<div class="type-row">
|
|
510
|
-
<span class="lbl">H2</span>
|
|
511
|
-
<span class="sample" style="font-size:1.875rem;font-weight:${headingWeight};letter-spacing:-0.01em;line-height:1.25">Section Heading</span>
|
|
512
|
-
</div>
|
|
513
|
-
<div class="type-row">
|
|
514
|
-
<span class="lbl">H3</span>
|
|
515
|
-
<span class="sample" style="font-size:1.5rem;font-weight:${headingWeight};line-height:1.3">Subsection</span>
|
|
516
|
-
</div>
|
|
517
|
-
<div class="type-row">
|
|
518
|
-
<span class="lbl">body</span>
|
|
519
|
-
<span class="sample" style="font-size:1rem;">The quick brown fox jumps over the lazy dog. \uB2E4\uB78C\uC950 \uD5CC \uCCC7\uBC14\uD034\uC5D0 \uD0C0\uACE0\uD30C.</span>
|
|
520
|
-
</div>
|
|
521
|
-
<div class="type-row">
|
|
522
|
-
<span class="lbl">sm</span>
|
|
523
|
-
<span class="sample" style="font-size:0.875rem;color:var(--muted-fg)">Secondary text, labels, and metadata</span>
|
|
524
|
-
</div>
|
|
525
|
-
<div class="type-row">
|
|
526
|
-
<span class="lbl">mono</span>
|
|
527
|
-
<span class="sample" style="font-family:monospace;font-size:0.875rem">const theme = generateDesignSystem();</span>
|
|
528
|
-
</div>
|
|
529
|
-
</div>
|
|
530
|
-
</div>
|
|
531
|
-
|
|
532
|
-
<!-- Radius -->
|
|
533
|
-
<div class="section">
|
|
534
|
-
<h2 class="section-title">Border Radius</h2>
|
|
535
|
-
<div class="radius-grid">
|
|
536
|
-
<div style="text-align:center"><div class="radius-demo" style="border-radius:0">0</div><div style="font-size:10px;margin-top:4px;color:var(--muted-fg)">none</div></div>
|
|
537
|
-
<div style="text-align:center"><div class="radius-demo" style="border-radius:${radiusPx}">${radiusPx}</div><div style="font-size:10px;margin-top:4px;color:var(--muted-fg)">base</div></div>
|
|
538
|
-
<div style="text-align:center"><div class="radius-demo" style="border-radius:${parseInt(radiusPx) * 2}px">${parseInt(radiusPx) * 2}px</div><div style="font-size:10px;margin-top:4px;color:var(--muted-fg)">lg</div></div>
|
|
539
|
-
<div style="text-align:center"><div class="radius-demo" style="border-radius:9999px">pill</div><div style="font-size:10px;margin-top:4px;color:var(--muted-fg)">full</div></div>
|
|
540
|
-
</div>
|
|
541
|
-
</div>
|
|
542
|
-
|
|
543
|
-
<!-- Components -->
|
|
544
|
-
<div class="section">
|
|
545
|
-
<h2 class="section-title">Components</h2>
|
|
546
|
-
|
|
547
|
-
<!-- Buttons -->
|
|
548
|
-
<div class="comp-card">
|
|
549
|
-
<h3>Buttons</h3>
|
|
550
|
-
<div class="comp-row">
|
|
551
|
-
<button class="btn btn-primary">Primary</button>
|
|
552
|
-
<button class="btn btn-secondary">Secondary</button>
|
|
553
|
-
<button class="btn btn-outline">Outline</button>
|
|
554
|
-
<button class="btn btn-ghost">Ghost</button>
|
|
555
|
-
<button class="btn btn-destructive">Delete</button>
|
|
556
|
-
</div>
|
|
557
|
-
</div>
|
|
558
|
-
|
|
559
|
-
<!-- Badges -->
|
|
560
|
-
<div class="comp-card">
|
|
561
|
-
<h3>Badges</h3>
|
|
562
|
-
<div class="comp-row">
|
|
563
|
-
<span class="badge badge-primary">Active</span>
|
|
564
|
-
<span class="badge badge-secondary">Draft</span>
|
|
565
|
-
<span class="badge badge-outline">Archived</span>
|
|
566
|
-
</div>
|
|
567
|
-
</div>
|
|
568
|
-
|
|
569
|
-
<!-- Input -->
|
|
570
|
-
<div class="comp-card">
|
|
571
|
-
<h3>Input</h3>
|
|
572
|
-
<div style="display:flex;flex-direction:column;gap:12px;max-width:400px;">
|
|
573
|
-
<div>
|
|
574
|
-
<label style="font-size:0.8125rem;font-weight:500;display:block;margin-bottom:4px;">Email</label>
|
|
575
|
-
<input class="input-demo" type="email" placeholder="you@example.com">
|
|
576
|
-
</div>
|
|
577
|
-
<div>
|
|
578
|
-
<label style="font-size:0.8125rem;font-weight:500;display:block;margin-bottom:4px;">Password</label>
|
|
579
|
-
<input class="input-demo" type="password" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022">
|
|
580
|
-
</div>
|
|
581
|
-
</div>
|
|
582
|
-
</div>
|
|
583
|
-
|
|
584
|
-
<!-- Card -->
|
|
585
|
-
<div class="comp-card">
|
|
586
|
-
<h3>Card</h3>
|
|
587
|
-
<div class="comp-row" style="align-items:stretch;">
|
|
588
|
-
<div class="demo-card">
|
|
589
|
-
<h4>Project Overview</h4>
|
|
590
|
-
<p>A summary card showing key metrics and status for your project.</p>
|
|
591
|
-
<button class="btn btn-primary" style="height:32px;font-size:0.75rem;">View Details</button>
|
|
592
|
-
</div>
|
|
593
|
-
</div>
|
|
594
|
-
</div>
|
|
595
|
-
|
|
596
|
-
<!-- Table -->
|
|
597
|
-
<div class="comp-card">
|
|
598
|
-
<h3>Table</h3>
|
|
599
|
-
<div style="overflow-x:auto;">
|
|
600
|
-
<table class="demo-table">
|
|
601
|
-
<thead><tr><th>Name</th><th>Status</th><th>Role</th><th>Email</th></tr></thead>
|
|
602
|
-
<tbody>
|
|
603
|
-
<tr><td>Kim Minjae</td><td><span class="badge badge-primary" style="font-size:10px;">Active</span></td><td>Developer</td><td>minjae@example.com</td></tr>
|
|
604
|
-
<tr><td>Lee Soyeon</td><td><span class="badge badge-secondary" style="font-size:10px;">Pending</span></td><td>Designer</td><td>soyeon@example.com</td></tr>
|
|
605
|
-
<tr><td>Park Jiwoo</td><td><span class="badge badge-outline" style="font-size:10px;">Inactive</span></td><td>PM</td><td>jiwoo@example.com</td></tr>
|
|
606
|
-
</tbody>
|
|
607
|
-
</table>
|
|
608
|
-
</div>
|
|
609
|
-
</div>
|
|
610
|
-
|
|
611
|
-
<!-- Dialog -->
|
|
612
|
-
<div class="comp-card">
|
|
613
|
-
<h3>Dialog</h3>
|
|
614
|
-
<div class="demo-dialog">
|
|
615
|
-
<h4>Delete item?</h4>
|
|
616
|
-
<p>This action cannot be undone.</p>
|
|
617
|
-
<div class="acts">
|
|
618
|
-
<button class="btn btn-outline" style="height:32px;">Cancel</button>
|
|
619
|
-
<button class="btn btn-destructive" style="height:32px;">Delete</button>
|
|
620
|
-
</div>
|
|
621
|
-
</div>
|
|
622
|
-
</div>
|
|
623
|
-
|
|
624
|
-
<!-- Tabs -->
|
|
625
|
-
<div class="comp-card">
|
|
626
|
-
<h3>Tabs</h3>
|
|
627
|
-
<div class="tabs">
|
|
628
|
-
<button class="tab active">Overview</button>
|
|
629
|
-
<button class="tab">Analytics</button>
|
|
630
|
-
<button class="tab">Settings</button>
|
|
631
|
-
</div>
|
|
632
|
-
</div>
|
|
633
|
-
</div>
|
|
634
|
-
|
|
635
|
-
<!-- shadcn CSS -->
|
|
636
|
-
<div class="section">
|
|
637
|
-
<h2 class="section-title">shadcn/ui CSS Variables</h2>
|
|
638
|
-
<div class="section-sub">Ready to paste into globals.css</div>
|
|
639
|
-
<div class="css-block">
|
|
640
|
-
<button class="ctrl-btn copy-css" onclick="copyCss()" style="position:absolute;top:8px;right:8px;">Copy</button>
|
|
641
|
-
<pre id="css-output">${escHtml(shadcnCss)}</pre>
|
|
642
|
-
</div>
|
|
643
|
-
</div>
|
|
644
|
-
|
|
645
|
-
</div>
|
|
646
|
-
|
|
647
|
-
<div class="toast-popup" id="toast">Copied!</div>
|
|
648
|
-
|
|
649
|
-
<script>
|
|
650
|
-
let isDark = false;
|
|
651
|
-
function toggleTheme() {
|
|
652
|
-
isDark = !isDark;
|
|
653
|
-
document.body.classList.toggle('dark', isDark);
|
|
654
|
-
const btn = document.getElementById('theme-btn');
|
|
655
|
-
if (btn) btn.textContent = isDark ? '\u2600\uFE0F Light' : '\u{1F319} Dark';
|
|
656
|
-
}
|
|
657
|
-
function showToast(msg) {
|
|
658
|
-
const el = document.getElementById('toast');
|
|
659
|
-
el.textContent = msg;
|
|
660
|
-
el.classList.add('show');
|
|
661
|
-
setTimeout(() => el.classList.remove('show'), 1800);
|
|
662
|
-
}
|
|
663
|
-
function copy(val) {
|
|
664
|
-
navigator.clipboard.writeText(val).then(() => showToast('Copied: ' + val));
|
|
665
|
-
}
|
|
666
|
-
function copyCss() {
|
|
667
|
-
const css = document.getElementById('css-output').textContent;
|
|
668
|
-
navigator.clipboard.writeText(css).then(() => showToast('CSS variables copied!'));
|
|
669
|
-
}
|
|
670
|
-
document.querySelectorAll('.tab').forEach(t => {
|
|
671
|
-
t.addEventListener('click', () => {
|
|
672
|
-
t.parentElement.querySelectorAll('.tab').forEach(x => x.classList.remove('active'));
|
|
673
|
-
t.classList.add('active');
|
|
674
|
-
});
|
|
675
|
-
});
|
|
676
|
-
</script>
|
|
677
|
-
</body>
|
|
678
|
-
</html>`;
|
|
679
|
-
}
|
|
680
|
-
function isLight(hex) {
|
|
681
|
-
const h = hex.replace("#", "");
|
|
682
|
-
const r = parseInt(h.slice(0, 2), 16);
|
|
683
|
-
const g = parseInt(h.slice(2, 4), 16);
|
|
684
|
-
const b = parseInt(h.slice(4, 6), 16);
|
|
685
|
-
return (r * 299 + g * 587 + b * 114) / 1e3 > 140;
|
|
686
|
-
}
|
|
687
|
-
function esc(s) {
|
|
688
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
689
|
-
}
|
|
690
|
-
function escHtml(s) {
|
|
691
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
// src/cli/index.ts
|
|
695
|
-
async function run() {
|
|
696
|
-
const { reference, overrides, outputMode } = await runPrompts();
|
|
697
|
-
const s = p2.spinner();
|
|
698
|
-
s.start(`Building design system based on ${reference.name}...`);
|
|
699
|
-
const { designMd, shadcnCss, previewData } = applyOverrides(reference, overrides, outputMode);
|
|
700
|
-
previewData.shadcnCss = shadcnCss;
|
|
701
|
-
previewData.designMd = designMd;
|
|
702
|
-
const html = generatePreviewHtml(previewData);
|
|
703
|
-
const outputDir = process.cwd();
|
|
704
|
-
const mdPath = resolve(outputDir, "DESIGN.md");
|
|
705
|
-
const htmlPath = resolve(outputDir, "DESIGN.preview.html");
|
|
706
|
-
writeFileSync(mdPath, designMd, "utf-8");
|
|
707
|
-
writeFileSync(htmlPath, html, "utf-8");
|
|
708
|
-
s.stop("Done!");
|
|
709
|
-
p2.log.success(`DESIGN.md \u2192 ${mdPath}`);
|
|
710
|
-
p2.log.success(`Preview HTML \u2192 ${htmlPath}`);
|
|
711
|
-
p2.outro("Open DESIGN.preview.html in your browser to explore your design system.");
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
// bin/oh-my-design.ts
|
|
715
8
|
function readPackageVersion() {
|
|
716
9
|
let cur = dirname(fileURLToPath(import.meta.url));
|
|
717
10
|
for (let i = 0; i < 8; i++) {
|
|
@@ -730,61 +23,10 @@ function readPackageVersion() {
|
|
|
730
23
|
return "0.0.0";
|
|
731
24
|
}
|
|
732
25
|
var program = new Command();
|
|
733
|
-
program.name("oh-my-design").description("
|
|
734
|
-
program.command("
|
|
735
|
-
if (opts.config) {
|
|
736
|
-
const { writeFileSync: writeFileSync2 } = await import("fs");
|
|
737
|
-
const { resolve: resolve2 } = await import("path");
|
|
738
|
-
let b64 = opts.config.replace(/-/g, "+").replace(/_/g, "/");
|
|
739
|
-
while (b64.length % 4) b64 += "=";
|
|
740
|
-
const decoded = Buffer.from(b64, "base64").toString("utf-8");
|
|
741
|
-
const parts = decoded.split("|");
|
|
742
|
-
const refId = parts[0] || "vercel";
|
|
743
|
-
const overrides = {
|
|
744
|
-
primaryColor: parts[1] || void 0,
|
|
745
|
-
fontFamily: parts[2] || void 0,
|
|
746
|
-
headingWeight: parts[3] || void 0,
|
|
747
|
-
borderRadius: parts[4] || void 0,
|
|
748
|
-
darkMode: parts[5] === "1"
|
|
749
|
-
};
|
|
750
|
-
const components = parts[6] ? parts[6].split(",").filter(Boolean) : [];
|
|
751
|
-
const stylePrefs = {};
|
|
752
|
-
if (parts[7]) {
|
|
753
|
-
for (const pair of parts[7].split(";")) {
|
|
754
|
-
const [k, v] = pair.split("=");
|
|
755
|
-
if (k && v) stylePrefs[k] = v;
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
const { loadReference: loadReference2 } = await import("../reference-parser-TM3CJPNE.js");
|
|
759
|
-
const { applyOverrides: applyOverrides2 } = await import("../customizer-CM76752R.js");
|
|
760
|
-
const ref = loadReference2(refId);
|
|
761
|
-
const mode = overrides.primaryColor || overrides.fontFamily ? "customized" : "as-is";
|
|
762
|
-
const { designMd, shadcnCss, previewData } = applyOverrides2(ref, {
|
|
763
|
-
primaryColor: overrides.primaryColor,
|
|
764
|
-
fontFamily: overrides.fontFamily,
|
|
765
|
-
headingWeight: overrides.headingWeight,
|
|
766
|
-
borderRadius: overrides.borderRadius,
|
|
767
|
-
darkMode: overrides.darkMode
|
|
768
|
-
}, mode, components);
|
|
769
|
-
previewData.shadcnCss = shadcnCss;
|
|
770
|
-
previewData.designMd = designMd;
|
|
771
|
-
const outputDir = process.cwd();
|
|
772
|
-
const mdPath = resolve2(outputDir, "DESIGN.md");
|
|
773
|
-
writeFileSync2(mdPath, designMd, "utf-8");
|
|
774
|
-
console.log(`\x1B[32m\u2713\x1B[0m DESIGN.md generated at ${mdPath}`);
|
|
775
|
-
console.log(` Based on: ${ref.name}`);
|
|
776
|
-
if (overrides.primaryColor) console.log(` Primary: ${overrides.primaryColor}`);
|
|
777
|
-
if (overrides.fontFamily) console.log(` Font: ${overrides.fontFamily}`);
|
|
778
|
-
if (overrides.headingWeight) console.log(` Weight: ${overrides.headingWeight}`);
|
|
779
|
-
if (overrides.borderRadius) console.log(` Radius: ${overrides.borderRadius}`);
|
|
780
|
-
if (overrides.darkMode) console.log(` Dark mode: included`);
|
|
781
|
-
} else {
|
|
782
|
-
await run();
|
|
783
|
-
}
|
|
784
|
-
});
|
|
785
|
-
program.command("install-skills").description("Install omd:* skill files into agent directories (.claude/, .codex/, .opencode/)").option("--dir <path>", "Project root (defaults to cwd)").option("--agent <name...>", "Restrict to specific agents (claude-code | codex | opencode)").option("--force", "Overwrite existing files even without the omd marker").action(
|
|
26
|
+
program.name("oh-my-design").description("Bootstrap oh-my-design skills + agents into your project. After install, talk to your agent in natural language \u2014 no other CLI commands.").version(readPackageVersion()).showSuggestionAfterError(true).showHelpAfterError(true);
|
|
27
|
+
program.command("install-skills").description("Install omd skill files + canonical agents into agent directories (.claude/, .codex/, .opencode/)").option("--dir <path>", "Project root (defaults to cwd)").option("--agent <name...>", "Restrict to specific agents (claude-code | codex | opencode)").option("--force", "Overwrite existing files even without the omd marker").action(
|
|
786
28
|
async (opts) => {
|
|
787
|
-
const { runInstallSkills } = await import("../install-skills-
|
|
29
|
+
const { runInstallSkills } = await import("../install-skills-SVIYKXOE.js");
|
|
788
30
|
const validAgents = ["claude-code", "codex", "opencode"];
|
|
789
31
|
const agents = opts.agent ? opts.agent.filter(
|
|
790
32
|
(a) => validAgents.includes(a)
|
|
@@ -797,62 +39,5 @@ program.command("install-skills").description("Install omd:* skill files into ag
|
|
|
797
39
|
if (code !== 0) process.exit(code);
|
|
798
40
|
}
|
|
799
41
|
);
|
|
800
|
-
var referenceCmd = program.command("reference").description("Inspect bundled design references");
|
|
801
|
-
referenceCmd.command("list").description("List all bundled reference ids").action(async () => {
|
|
802
|
-
const { runReferenceList } = await import("../reference-YMNAOXJQ.js");
|
|
803
|
-
process.exit(runReferenceList());
|
|
804
|
-
});
|
|
805
|
-
referenceCmd.command("show <id>").description("Print the full reference DESIGN.md to stdout").action(async (id) => {
|
|
806
|
-
const { runReferenceShow } = await import("../reference-YMNAOXJQ.js");
|
|
807
|
-
process.exit(runReferenceShow(id));
|
|
808
|
-
});
|
|
809
|
-
var initCmd = program.command("init").description("Bootstrap DESIGN.md from a reference + project description");
|
|
810
|
-
initCmd.command("recommend <description...>").description("Recommend references matching a project description").option("--top <n>", "Number of recommendations", "5").option("--json", "Emit machine-readable JSON").action(
|
|
811
|
-
async (descParts, opts) => {
|
|
812
|
-
const { runInitRecommend } = await import("../init-UMM4XIV5.js");
|
|
813
|
-
const code = runInitRecommend({
|
|
814
|
-
description: descParts.join(" "),
|
|
815
|
-
topK: opts.top ? Number(opts.top) : 5,
|
|
816
|
-
json: opts.json
|
|
817
|
-
});
|
|
818
|
-
if (code !== 0) process.exit(code);
|
|
819
|
-
}
|
|
820
|
-
);
|
|
821
|
-
initCmd.command("prepare").description("Stage init context: rename existing DESIGN.md, compute delta_set, write .omd/init-context.json").requiredOption("--ref <id>", "Reference id (e.g. vercel, linear.app)").requiredOption("--description <text>", "Project description").option("--dir <path>", "Project root (defaults to cwd)").option("--reason <text>", "Reason for deprecation header", "user-initiated omd init").option("--json", "Emit machine-readable JSON").action(async (opts) => {
|
|
822
|
-
const { runInitPrepare } = await import("../init-UMM4XIV5.js");
|
|
823
|
-
const code = runInitPrepare(opts);
|
|
824
|
-
if (code !== 0) process.exit(code);
|
|
825
|
-
});
|
|
826
|
-
program.command("learn").description("List preferences and flip status (applied/rejected)").option("--dir <path>", "Project root (defaults to cwd)").option("--all", "Include all statuses (default: pending only)").option("--status <s>", "Filter by status: pending|applied|rejected|superseded").option("--scope <s>", "Filter by scope").option("--mark-applied <id>", "Mark entry as applied").option("--mark-rejected <id>", "Mark entry as rejected (requires --reason)").option("--reason <text>", "Reason for rejection").option("--hash <value>", "DESIGN.md hash to stamp on applied entry (defaults to current file)").action(async (opts) => {
|
|
827
|
-
const { runLearn } = await import("../learn-33LHKEJA.js");
|
|
828
|
-
const code = await runLearn(opts);
|
|
829
|
-
if (code !== 0) process.exit(code);
|
|
830
|
-
});
|
|
831
|
-
program.command("remember <note...>").description("Append a design preference/correction to .omd/preferences.md").option("--dir <path>", "Project root (defaults to cwd)").option("--scope <scope>", "Explicit scope (e.g. color, components.button)").option("--agent <name>", "Source agent (e.g. claude-code, codex)").option("--context <text>", "Source file/line context").action(
|
|
832
|
-
async (noteParts, opts) => {
|
|
833
|
-
const { runRemember } = await import("../remember-UAFA5B2O.js");
|
|
834
|
-
const code = await runRemember(noteParts.join(" "), opts);
|
|
835
|
-
if (code !== 0) process.exit(code);
|
|
836
|
-
}
|
|
837
|
-
);
|
|
838
|
-
program.command("sync").description("Sync DESIGN.md shim files (CLAUDE.md, AGENTS.md, .cursor/rules/omd-design.mdc)").option("--dir <path>", "Project root (defaults to cwd)").option("--force", "Overwrite drift without prompting").option("--check", "Exit non-zero if any shim has drift; do not write").action(async (opts) => {
|
|
839
|
-
const { runSync } = await import("../sync-FDYRKNFE.js");
|
|
840
|
-
const code = await runSync(opts);
|
|
841
|
-
if (code !== 0) process.exit(code);
|
|
842
|
-
});
|
|
843
|
-
program.command("preview").description("Open the preview HTML in the default browser").action(async () => {
|
|
844
|
-
const { existsSync: existsSync2 } = await import("fs");
|
|
845
|
-
const { resolve: resolve2 } = await import("path");
|
|
846
|
-
const previewPath = resolve2(process.cwd(), "DESIGN.preview.html");
|
|
847
|
-
if (!existsSync2(previewPath)) {
|
|
848
|
-
console.error("No DESIGN.preview.html found. Run `oh-my-design generate` first.");
|
|
849
|
-
process.exit(1);
|
|
850
|
-
}
|
|
851
|
-
const { exec } = await import("child_process");
|
|
852
|
-
const platform = process.platform;
|
|
853
|
-
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
|
|
854
|
-
exec(`${cmd} "${previewPath}"`);
|
|
855
|
-
console.log(`Opening ${previewPath}...`);
|
|
856
|
-
});
|
|
857
42
|
program.parse();
|
|
858
43
|
//# sourceMappingURL=oh-my-design.js.map
|