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/skills/omd-sync/SKILL.md
CHANGED
|
@@ -5,34 +5,158 @@ description: "DESIGN.md shim 파일들(CLAUDE.md / AGENTS.md / .cursor/rules/omd
|
|
|
5
5
|
|
|
6
6
|
# omd:sync — Shim Maintenance
|
|
7
7
|
|
|
8
|
-
DESIGN.md가 모든 주요 AI 코딩 에이전트
|
|
8
|
+
DESIGN.md가 모든 주요 AI 코딩 에이전트(Claude Code, Codex, OpenCode, Cursor)에게 보이도록 shim 파일 3종을 관리한다. **CLI 호출 없음** — Read/Write/Edit 툴로 직접 처리.
|
|
9
9
|
|
|
10
|
-
## 관리 대상
|
|
10
|
+
## 관리 대상 (3 파일)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
| ID | 경로 | 모드 |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `claude` | `CLAUDE.md` | block (managed marker만) |
|
|
15
|
+
| `agents` | `AGENTS.md` | block (managed marker만) |
|
|
16
|
+
| `cursor` | `.cursor/rules/omd-design.mdc` | whole (전체 파일이 omd 전용) |
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
block 모드는 `<!-- omd:start v=1 hash=<sha256:12> -->` ~ `<!-- omd:end -->` 마커 안만 관리, 나머지 사용자 콘텐츠 보존. whole 모드는 frontmatter 포함 전체 파일이 관리 단위.
|
|
17
19
|
|
|
18
|
-
##
|
|
20
|
+
## 템플릿 (정확히 이 본문 — 절대 paraphrase 금지)
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
### CLAUDE.md body
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
# Design System (oh-my-design)
|
|
26
|
+
|
|
27
|
+
The authoritative brand & UI spec is **@./DESIGN.md**.
|
|
28
|
+
Read before any UI/styling/microcopy/motion work.
|
|
29
|
+
|
|
30
|
+
Preference log (pending corrections): @./.omd/preferences.md
|
|
31
|
+
|
|
32
|
+
Precedence: DESIGN.md > preferences.md > your defaults.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### AGENTS.md body
|
|
36
|
+
|
|
37
|
+
```markdown
|
|
38
|
+
## Design System (oh-my-design)
|
|
39
|
+
|
|
40
|
+
**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.
|
|
41
|
+
|
|
42
|
+
If present, read `./.omd/preferences.md` — pending corrections not yet folded into DESIGN.md. Apply them; flag conflicts.
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### .cursor/rules/omd-design.mdc (whole, frontmatter 포함)
|
|
46
|
+
|
|
47
|
+
```mdc
|
|
48
|
+
---
|
|
49
|
+
description: Authoritative brand & UI design system. Read DESIGN.md before UI work.
|
|
50
|
+
globs:
|
|
51
|
+
- "**/*.tsx"
|
|
52
|
+
- "**/*.jsx"
|
|
53
|
+
- "**/*.vue"
|
|
54
|
+
- "**/*.svelte"
|
|
55
|
+
- "**/*.css"
|
|
56
|
+
- "**/*.scss"
|
|
57
|
+
- "**/tailwind.config.*"
|
|
58
|
+
- "**/components/**"
|
|
59
|
+
- "**/app/**/page.*"
|
|
60
|
+
alwaysApply: false
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
<!-- omd:start v=1 hash=<HASH> -->
|
|
64
|
+
The authoritative design spec lives at `@DESIGN.md` (repo root). Open and read before generating/modifying UI.
|
|
65
|
+
|
|
66
|
+
Pending preference corrections: `@.omd/preferences.md`.
|
|
67
|
+
|
|
68
|
+
Precedence: DESIGN.md > preferences.md > framework defaults.
|
|
69
|
+
<!-- omd:end -->
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 해시 계산
|
|
73
|
+
|
|
74
|
+
`<HASH>` = sha256 of the body content (마커 제외, body 텍스트만), 12자 hex prefix:
|
|
21
75
|
|
|
22
76
|
```bash
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
77
|
+
node -e "console.log(require('crypto').createHash('sha256').update(process.argv[1]).digest('hex').slice(0,12))" "<body 텍스트>"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
block 모드 마커 형식 정확히:
|
|
81
|
+
```
|
|
82
|
+
<!-- omd:start v=1 hash=ab12cd34ef56 -->
|
|
83
|
+
<body>
|
|
84
|
+
<!-- omd:end -->
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 실행 절차
|
|
88
|
+
|
|
89
|
+
사용자가 어떤 모드를 요청하는지 분기:
|
|
90
|
+
- **인터랙티브 (디폴트)** — drift 발견 시 사용자에게 묻기
|
|
91
|
+
- **--force 의도** ("강제 덮어쓰기") — drift 무시하고 덮어씀
|
|
92
|
+
- **--check 의도** ("상태만 검사") — 파일 상태만 출력, write 안 함
|
|
93
|
+
|
|
94
|
+
각 shim별로:
|
|
95
|
+
|
|
96
|
+
### Step 1 — Read existing
|
|
97
|
+
파일 없으면 → status: `missing`, 새로 write 진행
|
|
98
|
+
파일 있으면 → 내용 파싱
|
|
99
|
+
|
|
100
|
+
### Step 2 — block 모드 파싱
|
|
101
|
+
`<!-- omd:start v=N hash=H -->` 라인 찾기:
|
|
102
|
+
- 없으면 → status: `missing` (block 부재, 사용자 content 외에 새로 추가 필요)
|
|
103
|
+
- 있으면 → marker 사이의 본문 추출. 추출된 본문의 sha256:12를 계산해서 marker의 `hash=H`와 비교
|
|
104
|
+
- 불일치 → status: `drifted` (사용자가 수동 편집함)
|
|
105
|
+
- 일치 + 본문 == 템플릿 → status: `clean`
|
|
106
|
+
- 일치 + 본문 != 템플릿 → status: `out-of-date` (omd 템플릿이 갱신됨)
|
|
107
|
+
|
|
108
|
+
### Step 3 — whole 모드 파싱
|
|
109
|
+
existing 전체 content와 rendered 템플릿 비교:
|
|
110
|
+
- 동일 → `clean`
|
|
111
|
+
- 차이 → `drifted`
|
|
112
|
+
|
|
113
|
+
### Step 4 — drift 처리
|
|
114
|
+
- **인터랙티브**: drift된 shim별로 "${path}는 수동 편집됐어요. 덮어쓸까요? (yes/no/show diff)" 묻기
|
|
115
|
+
- **--force**: drift 무시 덮어씀
|
|
116
|
+
- **--check**: drift 있으면 exit 1 동등 — 사용자에게 "drift detected" 보고 후 종료
|
|
117
|
+
|
|
118
|
+
### Step 5 — Write
|
|
119
|
+
- block 모드: existing 안의 marker block만 새 hash + 새 body로 교체. 마커 외부 사용자 content는 보존
|
|
120
|
+
- whole 모드: 파일 전체를 새 rendered content로 교체. 디렉토리 (`.cursor/rules/`) 없으면 mkdir
|
|
121
|
+
|
|
122
|
+
### Step 6 — sync-lock 갱신
|
|
123
|
+
`.omd/sync.lock.json` 기록 (없으면 만든다):
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"design_md_hash": "<DESIGN.md sha256:12>",
|
|
127
|
+
"targets": {
|
|
128
|
+
"CLAUDE.md": "<hash>",
|
|
129
|
+
"AGENTS.md": "<hash>",
|
|
130
|
+
".cursor/rules/omd-design.mdc": "<hash>"
|
|
131
|
+
},
|
|
132
|
+
"updated_at": "<ISO timestamp>"
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
DESIGN.md 해시:
|
|
137
|
+
```bash
|
|
138
|
+
[ -f DESIGN.md ] && node -e "console.log(require('crypto').createHash('sha256').update(require('fs').readFileSync('DESIGN.md')).digest('hex').slice(0,12))"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 결과 보고
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
CLAUDE.md (block) — updated
|
|
145
|
+
AGENTS.md (block) — unchanged
|
|
146
|
+
.cursor/rules/omd-design.mdc — created
|
|
147
|
+
DESIGN.md hash: ab12cd34ef56
|
|
26
148
|
```
|
|
27
149
|
|
|
28
150
|
## 언제 실행하나
|
|
29
151
|
|
|
30
|
-
-
|
|
31
|
-
- 새
|
|
152
|
+
- DESIGN.md 변경 직후 (shim hash 갱신용)
|
|
153
|
+
- 새 프로젝트 첫 도입 (3종 생성)
|
|
32
154
|
- `.claude` / `.cursor` 디렉토리 추가 후
|
|
33
|
-
-
|
|
155
|
+
- "drift 확인" 요청
|
|
34
156
|
|
|
35
157
|
## 금지
|
|
36
158
|
|
|
37
|
-
-
|
|
38
|
-
-
|
|
159
|
+
- 마커 안 본문에 임의 추가/축약 금지 — 위 템플릿 정확히 사용
|
|
160
|
+
- block 모드 파일에서 마커 외부 사용자 content 절대 삭제 금지
|
|
161
|
+
- `.omd/sync.lock.json` 무시 금지 — 항상 갱신
|
|
162
|
+
- DESIGN.md가 없어도 shim은 만들 수 있음 (DESIGN.md 생성 후에 hash만 채움)
|
package/dist/chunk-6YNSV3VY.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/core/agent-detect.ts
|
|
4
|
-
import { existsSync } from "fs";
|
|
5
|
-
import { join } from "path";
|
|
6
|
-
function detectCallingAgent() {
|
|
7
|
-
const env = process.env;
|
|
8
|
-
if (env.CLAUDECODE === "1" || env.CLAUDE_CODE === "1" || env.CLAUDE_CODE_TASK_ID) {
|
|
9
|
-
return "claude-code";
|
|
10
|
-
}
|
|
11
|
-
if (env.CODEX_SESSION_ID || env.CODEX || env.OPENAI_CODEX) {
|
|
12
|
-
return "codex";
|
|
13
|
-
}
|
|
14
|
-
if (env.OPENCODE || env.OPENCODE_SESSION) {
|
|
15
|
-
return "opencode";
|
|
16
|
-
}
|
|
17
|
-
if (env.CURSOR_SESSION_ID || env.CURSOR_AGENT) {
|
|
18
|
-
return "cursor";
|
|
19
|
-
}
|
|
20
|
-
return "unknown";
|
|
21
|
-
}
|
|
22
|
-
function detectInstalledAgents(projectRoot) {
|
|
23
|
-
return {
|
|
24
|
-
claudeCode: existsSync(join(projectRoot, ".claude")) || existsSync(join(projectRoot, "CLAUDE.md")),
|
|
25
|
-
codex: existsSync(join(projectRoot, ".codex")) || existsSync(join(projectRoot, "AGENTS.md")) || existsSync(join(projectRoot, "AGENTS.override.md")),
|
|
26
|
-
opencode: existsSync(join(projectRoot, ".opencode")) || existsSync(join(projectRoot, "opencode.json")) || existsSync(join(projectRoot, "opencode.jsonc")),
|
|
27
|
-
cursor: existsSync(join(projectRoot, ".cursor")) || existsSync(join(projectRoot, ".cursorrules"))
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export {
|
|
32
|
-
detectCallingAgent,
|
|
33
|
-
detectInstalledAgents
|
|
34
|
-
};
|
|
35
|
-
//# sourceMappingURL=chunk-6YNSV3VY.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/agent-detect.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport type AgentId = 'claude-code' | 'codex' | 'opencode' | 'cursor' | 'unknown';\n\nexport function detectCallingAgent(): AgentId {\n const env = process.env;\n\n if (env.CLAUDECODE === '1' || env.CLAUDE_CODE === '1' || env.CLAUDE_CODE_TASK_ID) {\n return 'claude-code';\n }\n if (env.CODEX_SESSION_ID || env.CODEX || env.OPENAI_CODEX) {\n return 'codex';\n }\n if (env.OPENCODE || env.OPENCODE_SESSION) {\n return 'opencode';\n }\n if (env.CURSOR_SESSION_ID || env.CURSOR_AGENT) {\n return 'cursor';\n }\n\n return 'unknown';\n}\n\nexport interface AgentPresence {\n claudeCode: boolean;\n codex: boolean;\n opencode: boolean;\n cursor: boolean;\n}\n\nexport function detectInstalledAgents(projectRoot: string): AgentPresence {\n return {\n claudeCode:\n existsSync(join(projectRoot, '.claude')) ||\n existsSync(join(projectRoot, 'CLAUDE.md')),\n codex:\n existsSync(join(projectRoot, '.codex')) ||\n existsSync(join(projectRoot, 'AGENTS.md')) ||\n existsSync(join(projectRoot, 'AGENTS.override.md')),\n opencode:\n existsSync(join(projectRoot, '.opencode')) ||\n existsSync(join(projectRoot, 'opencode.json')) ||\n existsSync(join(projectRoot, 'opencode.jsonc')),\n cursor:\n existsSync(join(projectRoot, '.cursor')) ||\n existsSync(join(projectRoot, '.cursorrules')),\n };\n}\n"],"mappings":";;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AAId,SAAS,qBAA8B;AAC5C,QAAM,MAAM,QAAQ;AAEpB,MAAI,IAAI,eAAe,OAAO,IAAI,gBAAgB,OAAO,IAAI,qBAAqB;AAChF,WAAO;AAAA,EACT;AACA,MAAI,IAAI,oBAAoB,IAAI,SAAS,IAAI,cAAc;AACzD,WAAO;AAAA,EACT;AACA,MAAI,IAAI,YAAY,IAAI,kBAAkB;AACxC,WAAO;AAAA,EACT;AACA,MAAI,IAAI,qBAAqB,IAAI,cAAc;AAC7C,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AASO,SAAS,sBAAsB,aAAoC;AACxE,SAAO;AAAA,IACL,YACE,WAAW,KAAK,aAAa,SAAS,CAAC,KACvC,WAAW,KAAK,aAAa,WAAW,CAAC;AAAA,IAC3C,OACE,WAAW,KAAK,aAAa,QAAQ,CAAC,KACtC,WAAW,KAAK,aAAa,WAAW,CAAC,KACzC,WAAW,KAAK,aAAa,oBAAoB,CAAC;AAAA,IACpD,UACE,WAAW,KAAK,aAAa,WAAW,CAAC,KACzC,WAAW,KAAK,aAAa,eAAe,CAAC,KAC7C,WAAW,KAAK,aAAa,gBAAgB,CAAC;AAAA,IAChD,QACE,WAAW,KAAK,aAAa,SAAS,CAAC,KACvC,WAAW,KAAK,aAAa,cAAc,CAAC;AAAA,EAChD;AACF;","names":[]}
|
package/dist/chunk-MHFYGZSO.js
DELETED
|
@@ -1,337 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/utils/color.ts
|
|
4
|
-
function hexToRgb(hex) {
|
|
5
|
-
const h = hex.replace("#", "");
|
|
6
|
-
return [
|
|
7
|
-
parseInt(h.slice(0, 2), 16),
|
|
8
|
-
parseInt(h.slice(2, 4), 16),
|
|
9
|
-
parseInt(h.slice(4, 6), 16)
|
|
10
|
-
];
|
|
11
|
-
}
|
|
12
|
-
function rgbToHex(r, g, b) {
|
|
13
|
-
return "#" + [r, g, b].map((v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0")).join("");
|
|
14
|
-
}
|
|
15
|
-
function hexToHsl(hex) {
|
|
16
|
-
const [r, g, b] = hexToRgb(hex).map((v) => v / 255);
|
|
17
|
-
const max = Math.max(r, g, b);
|
|
18
|
-
const min = Math.min(r, g, b);
|
|
19
|
-
const l = (max + min) / 2;
|
|
20
|
-
let h = 0;
|
|
21
|
-
let s = 0;
|
|
22
|
-
if (max !== min) {
|
|
23
|
-
const d = max - min;
|
|
24
|
-
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
25
|
-
switch (max) {
|
|
26
|
-
case r:
|
|
27
|
-
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
28
|
-
break;
|
|
29
|
-
case g:
|
|
30
|
-
h = ((b - r) / d + 2) / 6;
|
|
31
|
-
break;
|
|
32
|
-
case b:
|
|
33
|
-
h = ((r - g) / d + 4) / 6;
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
|
|
38
|
-
}
|
|
39
|
-
function hslToHex(h, s, l) {
|
|
40
|
-
const sn = s / 100;
|
|
41
|
-
const ln = l / 100;
|
|
42
|
-
const a = sn * Math.min(ln, 1 - ln);
|
|
43
|
-
const f = (n) => {
|
|
44
|
-
const k = (n + h / 30) % 12;
|
|
45
|
-
const color = ln - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
|
46
|
-
return Math.round(255 * color);
|
|
47
|
-
};
|
|
48
|
-
return rgbToHex(f(0), f(8), f(4));
|
|
49
|
-
}
|
|
50
|
-
function hslString(hex) {
|
|
51
|
-
const [h, s, l] = hexToHsl(hex);
|
|
52
|
-
return `${h} ${s}% ${l}%`;
|
|
53
|
-
}
|
|
54
|
-
function generateColorScale(hex) {
|
|
55
|
-
const [h, s] = hexToHsl(hex);
|
|
56
|
-
const lightnesses = {
|
|
57
|
-
50: 97,
|
|
58
|
-
100: 94,
|
|
59
|
-
200: 86,
|
|
60
|
-
300: 77,
|
|
61
|
-
400: 66,
|
|
62
|
-
500: 55,
|
|
63
|
-
600: 47,
|
|
64
|
-
700: 39,
|
|
65
|
-
800: 32,
|
|
66
|
-
900: 24,
|
|
67
|
-
950: 14
|
|
68
|
-
};
|
|
69
|
-
const scale = {};
|
|
70
|
-
for (const [key, l] of Object.entries(lightnesses)) {
|
|
71
|
-
scale[key] = hslToHex(h, s, l);
|
|
72
|
-
}
|
|
73
|
-
return scale;
|
|
74
|
-
}
|
|
75
|
-
function isLight(hex) {
|
|
76
|
-
const [, , l] = hexToHsl(hex);
|
|
77
|
-
return l > 55;
|
|
78
|
-
}
|
|
79
|
-
function contrastForeground(bgHex) {
|
|
80
|
-
return isLight(bgHex) ? "#09090b" : "#fafafa";
|
|
81
|
-
}
|
|
82
|
-
function lighten(hex, amount) {
|
|
83
|
-
const [h, s, l] = hexToHsl(hex);
|
|
84
|
-
return hslToHex(h, s, Math.min(100, l + amount));
|
|
85
|
-
}
|
|
86
|
-
function darken(hex, amount) {
|
|
87
|
-
const [h, s, l] = hexToHsl(hex);
|
|
88
|
-
return hslToHex(h, s, Math.max(0, l - amount));
|
|
89
|
-
}
|
|
90
|
-
function generateChartColors(primaryHex) {
|
|
91
|
-
const [h, s, l] = hexToHsl(primaryHex);
|
|
92
|
-
return [
|
|
93
|
-
primaryHex,
|
|
94
|
-
hslToHex((h + 40) % 360, s, l),
|
|
95
|
-
hslToHex((h + 80) % 360, s, l),
|
|
96
|
-
hslToHex((h + 160) % 360, s, l),
|
|
97
|
-
hslToHex((h + 220) % 360, s, l)
|
|
98
|
-
];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// src/core/customizer.ts
|
|
102
|
-
function applyOverrides(ref, overrides, mode, components) {
|
|
103
|
-
let md = ref.designMd;
|
|
104
|
-
const effectivePrimary = overrides.primaryColor || ref.colors.primary;
|
|
105
|
-
const effectiveFont = overrides.fontFamily || ref.typography.primary;
|
|
106
|
-
const effectiveWeight = overrides.headingWeight || ref.typography.headingWeight;
|
|
107
|
-
const effectiveRadius = overrides.borderRadius || ref.radius.replace(/[-–].*/, "").trim();
|
|
108
|
-
const effectiveBg = ref.colors.background;
|
|
109
|
-
const effectiveFg = ref.colors.foreground;
|
|
110
|
-
md = md.replace(/[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{FE00}-\u{FE0F}\u{1FA00}-\u{1FAFF}\u{200D}\u{20E3}\u{E0020}-\u{E007F}]/gu, "");
|
|
111
|
-
if (mode === "customized") {
|
|
112
|
-
md = md.replace(/^# .+$/m, `# Custom Design System (based on ${ref.name})`);
|
|
113
|
-
if (overrides.primaryColor && overrides.primaryColor !== ref.colors.primary) {
|
|
114
|
-
const re = new RegExp(ref.colors.primary.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
|
|
115
|
-
md = re[Symbol.replace](md, overrides.primaryColor);
|
|
116
|
-
}
|
|
117
|
-
if (overrides.fontFamily && overrides.fontFamily !== ref.typography.primary) {
|
|
118
|
-
md = md.replaceAll(ref.typography.primary, overrides.fontFamily);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
if (components && components.length > 0) {
|
|
122
|
-
md += `
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## Included Components
|
|
127
|
-
|
|
128
|
-
The following components are part of this design system:
|
|
129
|
-
|
|
130
|
-
`;
|
|
131
|
-
md += components.map((c) => `- ${c.charAt(0).toUpperCase() + c.slice(1).replace(/-/g, " ")}`).join("\n");
|
|
132
|
-
md += "\n";
|
|
133
|
-
}
|
|
134
|
-
md += buildIconographySection();
|
|
135
|
-
const shadcnCss = generateShadcnCss(effectivePrimary, effectiveBg, effectiveFg, effectiveRadius, ref, overrides);
|
|
136
|
-
md += buildDocumentPolicies();
|
|
137
|
-
const previewData = buildPreviewData(ref, overrides, effectivePrimary, effectiveBg, effectiveFg, effectiveFont, effectiveWeight, effectiveRadius);
|
|
138
|
-
return { designMd: md, shadcnCss, previewData };
|
|
139
|
-
}
|
|
140
|
-
function generateShadcnCss(primary, background, foreground, radius, ref, overrides) {
|
|
141
|
-
const scale = generateColorScale(primary);
|
|
142
|
-
const accent = ref.colors.accent || hslToHex((hexToHsl(primary)[0] + 30) % 360, 60, 55);
|
|
143
|
-
const border = ref.colors.border || lighten(foreground, 75);
|
|
144
|
-
const muted = lighten(background === "#ffffff" ? "#f5f5f5" : background, 5);
|
|
145
|
-
const destructive = "#ef4444";
|
|
146
|
-
const chart = generateChartColors(primary);
|
|
147
|
-
const radiusRem = radius === "9999px" ? "9999px" : `${parseInt(radius) / 16}rem`;
|
|
148
|
-
const vars = {
|
|
149
|
-
"--background": hslString(background),
|
|
150
|
-
"--foreground": hslString(foreground),
|
|
151
|
-
"--card": hslString(background === "#ffffff" ? "#ffffff" : lighten(background, 3)),
|
|
152
|
-
"--card-foreground": hslString(foreground),
|
|
153
|
-
"--popover": hslString(background === "#ffffff" ? "#ffffff" : lighten(background, 5)),
|
|
154
|
-
"--popover-foreground": hslString(foreground),
|
|
155
|
-
"--primary": hslString(primary),
|
|
156
|
-
"--primary-foreground": hslString(contrastForeground(primary)),
|
|
157
|
-
"--secondary": hslString(scale[100]),
|
|
158
|
-
"--secondary-foreground": hslString(foreground),
|
|
159
|
-
"--muted": hslString(muted),
|
|
160
|
-
"--muted-foreground": hslString(lighten(foreground, 40)),
|
|
161
|
-
"--accent": hslString(accent),
|
|
162
|
-
"--accent-foreground": hslString(contrastForeground(accent)),
|
|
163
|
-
"--destructive": hslString(destructive),
|
|
164
|
-
"--destructive-foreground": hslString(contrastForeground(destructive)),
|
|
165
|
-
"--border": hslString(border),
|
|
166
|
-
"--input": hslString(border),
|
|
167
|
-
"--ring": hslString(primary),
|
|
168
|
-
"--radius": radiusRem,
|
|
169
|
-
"--chart-1": hslString(chart[0]),
|
|
170
|
-
"--chart-2": hslString(chart[1]),
|
|
171
|
-
"--chart-3": hslString(chart[2]),
|
|
172
|
-
"--chart-4": hslString(chart[3]),
|
|
173
|
-
"--chart-5": hslString(chart[4])
|
|
174
|
-
};
|
|
175
|
-
const lines = ["@layer base {", " :root {"];
|
|
176
|
-
for (const [k, v] of Object.entries(vars)) {
|
|
177
|
-
lines.push(` ${k}: ${v};`);
|
|
178
|
-
}
|
|
179
|
-
lines.push(" }");
|
|
180
|
-
if (overrides.darkMode) {
|
|
181
|
-
const darkBg = hslToHex(hexToHsl(primary)[0], 15, 7);
|
|
182
|
-
const darkFg = "#fafafa";
|
|
183
|
-
const darkBorder = hslToHex(hexToHsl(primary)[0], 10, 18);
|
|
184
|
-
const darkMuted = hslToHex(hexToHsl(primary)[0], 10, 15);
|
|
185
|
-
lines.push("", " .dark {");
|
|
186
|
-
const darkVars = {
|
|
187
|
-
"--background": hslString(darkBg),
|
|
188
|
-
"--foreground": hslString(darkFg),
|
|
189
|
-
"--card": hslString(lighten(darkBg, 3)),
|
|
190
|
-
"--card-foreground": hslString(darkFg),
|
|
191
|
-
"--popover": hslString(lighten(darkBg, 5)),
|
|
192
|
-
"--popover-foreground": hslString(darkFg),
|
|
193
|
-
"--primary": hslString(primary),
|
|
194
|
-
"--primary-foreground": hslString(contrastForeground(primary)),
|
|
195
|
-
"--secondary": hslString(hslToHex(hexToHsl(primary)[0], 15, 20)),
|
|
196
|
-
"--secondary-foreground": hslString(darkFg),
|
|
197
|
-
"--muted": hslString(darkMuted),
|
|
198
|
-
"--muted-foreground": hslString(darken(darkFg, 35)),
|
|
199
|
-
"--accent": hslString(accent),
|
|
200
|
-
"--accent-foreground": hslString(contrastForeground(accent)),
|
|
201
|
-
"--destructive": hslString(destructive),
|
|
202
|
-
"--destructive-foreground": hslString(contrastForeground(destructive)),
|
|
203
|
-
"--border": hslString(darkBorder),
|
|
204
|
-
"--input": hslString(lighten(darkBorder, 5)),
|
|
205
|
-
"--ring": hslString(primary),
|
|
206
|
-
"--chart-1": hslString(chart[0]),
|
|
207
|
-
"--chart-2": hslString(chart[1]),
|
|
208
|
-
"--chart-3": hslString(chart[2]),
|
|
209
|
-
"--chart-4": hslString(chart[3]),
|
|
210
|
-
"--chart-5": hslString(chart[4])
|
|
211
|
-
};
|
|
212
|
-
for (const [k, v] of Object.entries(darkVars)) {
|
|
213
|
-
lines.push(` ${k}: ${v};`);
|
|
214
|
-
}
|
|
215
|
-
lines.push(" }");
|
|
216
|
-
}
|
|
217
|
-
lines.push("}");
|
|
218
|
-
return lines.join("\n");
|
|
219
|
-
}
|
|
220
|
-
function buildPreviewData(ref, overrides, primary, background, foreground, font, headingWeight, radius) {
|
|
221
|
-
const scale = generateColorScale(primary);
|
|
222
|
-
const accent = ref.colors.accent || hslToHex((hexToHsl(primary)[0] + 30) % 360, 60, 55);
|
|
223
|
-
const border = ref.colors.border || lighten(foreground, 75);
|
|
224
|
-
const chart = generateChartColors(primary);
|
|
225
|
-
return {
|
|
226
|
-
name: overrides.primaryColor || overrides.fontFamily ? `Custom (based on ${ref.name})` : ref.name,
|
|
227
|
-
basedOn: ref.name,
|
|
228
|
-
primary,
|
|
229
|
-
background,
|
|
230
|
-
foreground,
|
|
231
|
-
font,
|
|
232
|
-
headingWeight,
|
|
233
|
-
radius,
|
|
234
|
-
shadcnCss: "",
|
|
235
|
-
// filled later
|
|
236
|
-
designMd: "",
|
|
237
|
-
// filled later
|
|
238
|
-
colors: {
|
|
239
|
-
primary,
|
|
240
|
-
accent,
|
|
241
|
-
muted: lighten(background === "#ffffff" ? "#f5f5f5" : background, 5),
|
|
242
|
-
destructive: "#ef4444",
|
|
243
|
-
border,
|
|
244
|
-
scale,
|
|
245
|
-
chart
|
|
246
|
-
},
|
|
247
|
-
darkMode: overrides.darkMode
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
function buildIconographySection() {
|
|
251
|
-
return `
|
|
252
|
-
|
|
253
|
-
---
|
|
254
|
-
|
|
255
|
-
## Iconography & SVG Guidelines
|
|
256
|
-
|
|
257
|
-
### Icon Library
|
|
258
|
-
|
|
259
|
-
Use a single, consistent icon library throughout the project. Recommended options:
|
|
260
|
-
|
|
261
|
-
- **Lucide React** (\`lucide-react\`): Default for shadcn/ui projects. 1,400+ icons, tree-shakeable, consistent 24x24 grid.
|
|
262
|
-
- **Radix Icons** (\`@radix-ui/react-icons\`): 300+ icons, 15x15 grid, minimal and geometric.
|
|
263
|
-
- **Heroicons** (\`@heroicons/react\`): 300+ icons by Tailwind team, outline and solid variants.
|
|
264
|
-
|
|
265
|
-
Pick ONE library and use it everywhere. Do not mix icon libraries within the same project.
|
|
266
|
-
|
|
267
|
-
### SVG Usage Rules
|
|
268
|
-
|
|
269
|
-
- All icons must be inline SVG components (not \`<img>\` tags) for color and size control.
|
|
270
|
-
- Icon size follows the type scale: 16px (inline), 20px (buttons), 24px (standalone).
|
|
271
|
-
- Icon color inherits from \`currentColor\` -- never hard-code fill/stroke colors.
|
|
272
|
-
- For custom/brand icons, export as SVG components with \`currentColor\` fills.
|
|
273
|
-
- Stroke width: 1.5px-2px for outline icons. Keep consistent across the project.
|
|
274
|
-
|
|
275
|
-
### Icon Sizing Scale
|
|
276
|
-
|
|
277
|
-
| Context | Size | Usage |
|
|
278
|
-
|---------|------|-------|
|
|
279
|
-
| Inline text | 16px (1rem) | Badges, labels, breadcrumbs |
|
|
280
|
-
| Button icon | 18px (1.125rem) | Icon buttons, CTA icons |
|
|
281
|
-
| Standalone | 24px (1.5rem) | Navigation, card icons |
|
|
282
|
-
| Feature | 32-48px | Hero sections, empty states |
|
|
283
|
-
|
|
284
|
-
### SVG Optimization
|
|
285
|
-
|
|
286
|
-
- Run all custom SVGs through SVGO before committing.
|
|
287
|
-
- Remove unnecessary attributes: \`xmlns\`, \`xml:space\`, editor metadata.
|
|
288
|
-
- Use \`viewBox\` instead of fixed \`width\`/\`height\` for scalability.
|
|
289
|
-
`;
|
|
290
|
-
}
|
|
291
|
-
function buildDocumentPolicies() {
|
|
292
|
-
return `
|
|
293
|
-
|
|
294
|
-
---
|
|
295
|
-
|
|
296
|
-
## Document Policies
|
|
297
|
-
|
|
298
|
-
### No Emojis
|
|
299
|
-
|
|
300
|
-
This design system must not use emojis in any UI element, component, label, status indicator, or documentation.
|
|
301
|
-
Use SVG icons from the chosen icon library instead. Emojis render inconsistently across platforms and break visual coherence.
|
|
302
|
-
|
|
303
|
-
- Status indicators: use colored dots or icon components, not emoji.
|
|
304
|
-
- Section markers: use text prefixes ("DO:" / "DON'T:") or icons, not checkmark/cross emojis.
|
|
305
|
-
- Navigation: use icon components, not emoji.
|
|
306
|
-
|
|
307
|
-
### Format Compliance
|
|
308
|
-
|
|
309
|
-
This document follows the Google Stitch DESIGN.md 9-section format:
|
|
310
|
-
1. Visual Theme & Atmosphere
|
|
311
|
-
2. Color Palette & Roles
|
|
312
|
-
3. Typography Rules
|
|
313
|
-
4. Component Stylings
|
|
314
|
-
5. Layout Principles
|
|
315
|
-
6. Depth & Elevation
|
|
316
|
-
7. Do's and Don'ts
|
|
317
|
-
8. Responsive Behavior
|
|
318
|
-
9. Agent Prompt Guide
|
|
319
|
-
|
|
320
|
-
Extended with:
|
|
321
|
-
- Iconography & SVG Guidelines
|
|
322
|
-
- Document Policies
|
|
323
|
-
|
|
324
|
-
Total target length: 250-400 lines. Keep sections concise and actionable.
|
|
325
|
-
`;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
export {
|
|
329
|
-
hexToHsl,
|
|
330
|
-
hslToHex,
|
|
331
|
-
generateColorScale,
|
|
332
|
-
contrastForeground,
|
|
333
|
-
lighten,
|
|
334
|
-
darken,
|
|
335
|
-
applyOverrides
|
|
336
|
-
};
|
|
337
|
-
//# sourceMappingURL=chunk-MHFYGZSO.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/color.ts","../src/core/customizer.ts"],"sourcesContent":["import type { ColorScale, SemanticColor } from '../core/types.js';\n\n// ── Hex ↔ HSL conversions ────────────────────────────────────────\n\nexport function hexToRgb(hex: string): [number, number, number] {\n const h = hex.replace('#', '');\n return [\n parseInt(h.slice(0, 2), 16),\n parseInt(h.slice(2, 4), 16),\n parseInt(h.slice(4, 6), 16),\n ];\n}\n\nexport function rgbToHex(r: number, g: number, b: number): string {\n return (\n '#' +\n [r, g, b]\n .map((v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, '0'))\n .join('')\n );\n}\n\nexport function hexToHsl(hex: string): [number, number, number] {\n const [r, g, b] = hexToRgb(hex).map((v) => v / 255);\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n let h = 0;\n let s = 0;\n\n if (max !== min) {\n const d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) {\n case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;\n case g: h = ((b - r) / d + 2) / 6; break;\n case b: h = ((r - g) / d + 4) / 6; break;\n }\n }\n\n return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];\n}\n\nexport function hslToHex(h: number, s: number, l: number): string {\n const sn = s / 100;\n const ln = l / 100;\n const a = sn * Math.min(ln, 1 - ln);\n const f = (n: number) => {\n const k = (n + h / 30) % 12;\n const color = ln - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);\n return Math.round(255 * color);\n };\n return rgbToHex(f(0), f(8), f(4));\n}\n\n/** Format HSL for shadcn CSS variables: \"210 40% 98%\" */\nexport function hslString(hex: string): string {\n const [h, s, l] = hexToHsl(hex);\n return `${h} ${s}% ${l}%`;\n}\n\n// ── Palette generation ───────────────────────────────────────────\n\n/** Generate a full 11-stop color scale from a single hex */\nexport function generateColorScale(hex: string): ColorScale {\n const [h, s] = hexToHsl(hex);\n\n const lightnesses: Record<keyof ColorScale, number> = {\n 50: 97, 100: 94, 200: 86, 300: 77,\n 400: 66, 500: 55, 600: 47, 700: 39,\n 800: 32, 900: 24, 950: 14,\n };\n\n const scale = {} as ColorScale;\n for (const [key, l] of Object.entries(lightnesses)) {\n (scale as unknown as Record<string, string>)[key] = hslToHex(h, s, l);\n }\n return scale;\n}\n\n/** Determine if a color is \"light\" (needs dark foreground) */\nexport function isLight(hex: string): boolean {\n const [, , l] = hexToHsl(hex);\n return l > 55;\n}\n\n/** Pick a contrasting foreground for a given background */\nexport function contrastForeground(bgHex: string): string {\n return isLight(bgHex) ? '#09090b' : '#fafafa';\n}\n\n/** Create a semantic color pair (base + auto-contrast foreground) */\nexport function semanticColor(base: string): SemanticColor {\n return { base, foreground: contrastForeground(base) };\n}\n\n/** Lighten a hex color by a percentage (0-100) */\nexport function lighten(hex: string, amount: number): string {\n const [h, s, l] = hexToHsl(hex);\n return hslToHex(h, s, Math.min(100, l + amount));\n}\n\n/** Darken a hex color by a percentage (0-100) */\nexport function darken(hex: string, amount: number): string {\n const [h, s, l] = hexToHsl(hex);\n return hslToHex(h, s, Math.max(0, l - amount));\n}\n\n/** Desaturate a color */\nexport function desaturate(hex: string, amount: number): string {\n const [h, s, l] = hexToHsl(hex);\n return hslToHex(h, Math.max(0, s - amount), l);\n}\n\n/** Generate chart colors from primary by rotating hue */\nexport function generateChartColors(primaryHex: string): [string, string, string, string, string] {\n const [h, s, l] = hexToHsl(primaryHex);\n return [\n primaryHex,\n hslToHex((h + 40) % 360, s, l),\n hslToHex((h + 80) % 360, s, l),\n hslToHex((h + 160) % 360, s, l),\n hslToHex((h + 220) % 360, s, l),\n ];\n}\n","import type { ReferenceEntry } from './reference-parser.js';\nimport type { CustomOverrides } from '../cli/prompts.js';\nimport {\n generateColorScale,\n contrastForeground,\n hslString,\n hexToHsl,\n hslToHex,\n lighten,\n darken,\n generateChartColors,\n} from '../utils/color.js';\n\n/**\n * Apply user overrides to a reference DESIGN.md.\n *\n * Strategy:\n * - \"as-is\": return the original DESIGN.md content with minimal additions\n * - \"customized\": perform text-level replacements for color/font/radius/weight\n * and append a customization summary + shadcn CSS variables block\n *\n * This is intentionally NOT an AI call. It's deterministic string transformation.\n */\nexport function applyOverrides(\n ref: ReferenceEntry,\n overrides: CustomOverrides,\n mode: 'as-is' | 'customized',\n components?: string[],\n): { designMd: string; shadcnCss: string; previewData: PreviewData } {\n let md = ref.designMd;\n\n const effectivePrimary = overrides.primaryColor || ref.colors.primary;\n const effectiveFont = overrides.fontFamily || ref.typography.primary;\n const effectiveWeight = overrides.headingWeight || ref.typography.headingWeight;\n const effectiveRadius = overrides.borderRadius || ref.radius.replace(/[-–].*/, '').trim();\n const effectiveBg = ref.colors.background;\n const effectiveFg = ref.colors.foreground;\n\n // Strip emojis. The unicode range covers ✅ (U+2705) and ❌ (U+274C) too,\n // so any DO:/DON'T: prefix conversion would never match — references use\n // explicit \"**DO**\" / \"**DON'T**\" markdown instead.\n md = md.replace(/[\\u{1F300}-\\u{1F9FF}\\u{2600}-\\u{26FF}\\u{2700}-\\u{27BF}\\u{FE00}-\\u{FE0F}\\u{1FA00}-\\u{1FAFF}\\u{200D}\\u{20E3}\\u{E0020}-\\u{E007F}]/gu, '');\n\n if (mode === 'customized') {\n // Direct replacement — one source of truth for AI agents\n md = md.replace(/^# .+$/m, `# Custom Design System (based on ${ref.name})`);\n\n if (overrides.primaryColor && overrides.primaryColor !== ref.colors.primary) {\n const re = new RegExp(ref.colors.primary.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n md = re[Symbol.replace](md, overrides.primaryColor);\n }\n if (overrides.fontFamily && overrides.fontFamily !== ref.typography.primary) {\n md = md.replaceAll(ref.typography.primary, overrides.fontFamily);\n }\n }\n\n // Append component list\n if (components && components.length > 0) {\n md += `\\n\\n---\\n\\n## Included Components\\n\\nThe following components are part of this design system:\\n\\n`;\n md += components.map(c => `- ${c.charAt(0).toUpperCase() + c.slice(1).replace(/-/g, ' ')}`).join('\\n');\n md += '\\n';\n }\n\n // Append iconography section\n md += buildIconographySection();\n\n // Generate shadcn CSS for preview data only (no longer appended to DESIGN.md)\n const shadcnCss = generateShadcnCss(effectivePrimary, effectiveBg, effectiveFg, effectiveRadius, ref, overrides);\n\n // Append document policies\n md += buildDocumentPolicies();\n\n // Build preview data\n const previewData = buildPreviewData(ref, overrides, effectivePrimary, effectiveBg, effectiveFg, effectiveFont, effectiveWeight, effectiveRadius);\n\n return { designMd: md, shadcnCss, previewData };\n}\n\n// ── Text replacements ────────────────────────────────────────────\n\nfunction replaceColor(md: string, oldHex: string, newHex: string): string {\n // Replace the exact hex (case-insensitive)\n const regex = new RegExp(escapeRegex(oldHex), 'gi');\n return md.replace(regex, newHex);\n}\n\nfunction replaceFont(md: string, oldFont: string, newFont: string): string {\n const regex = new RegExp(escapeRegex(oldFont), 'g');\n return md.replace(regex, newFont);\n}\n\nfunction replaceWeight(md: string, oldWeight: string, newWeight: string): string {\n // Only replace weight in Display/Heading rows and key characteristics\n // Be careful not to replace all numbers\n const regex = new RegExp(`(Display.*?\\\\|\\\\s*)${oldWeight}(\\\\s*\\\\|)`, 'g');\n let result = md.replace(regex, `$1${newWeight}$2`);\n // Also replace \"weight X\" patterns\n result = result.replace(\n new RegExp(`weight ${oldWeight}`, 'g'),\n `weight ${newWeight}`,\n );\n return result;\n}\n\nfunction replaceRadius(md: string, oldRadius: string, newRadius: string): string {\n // Replace \"Xpx\" radius patterns\n const oldBase = oldRadius.replace(/[-–].*/, '').trim();\n if (oldBase === newRadius) return md;\n const regex = new RegExp(`${escapeRegex(oldBase)}`, 'g');\n return md.replace(regex, newRadius);\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n// ── Customization summary section ────────────────────────────────\n\nfunction buildCustomizationSummary(ref: ReferenceEntry, overrides: CustomOverrides): string {\n const changes: string[] = [];\n if (overrides.primaryColor) {\n changes.push(`- **Primary color**: ${ref.colors.primary} → ${overrides.primaryColor}`);\n }\n if (overrides.fontFamily) {\n changes.push(`- **Font**: ${ref.typography.primary} → ${overrides.fontFamily}`);\n }\n if (overrides.headingWeight) {\n changes.push(`- **Heading weight**: ${ref.typography.headingWeight} → ${overrides.headingWeight}`);\n }\n if (overrides.borderRadius) {\n changes.push(`- **Border radius**: ${ref.radius} → ${overrides.borderRadius}`);\n }\n if (overrides.additionalNotes) {\n changes.push(`- **Additional notes**: ${overrides.additionalNotes}`);\n }\n\n if (changes.length === 0) return '';\n\n return `\n\n---\n\n## Customization Applied\n\n> Based on **${ref.name}** design system with the following modifications:\n\n${changes.join('\\n')}\n`;\n}\n\n// ── shadcn CSS generation ────────────────────────────────────────\n\nfunction generateShadcnCss(\n primary: string,\n background: string,\n foreground: string,\n radius: string,\n ref: ReferenceEntry,\n overrides: CustomOverrides,\n): string {\n const scale = generateColorScale(primary);\n const accent = ref.colors.accent || hslToHex((hexToHsl(primary)[0] + 30) % 360, 60, 55);\n const border = ref.colors.border || lighten(foreground, 75);\n const muted = lighten(background === '#ffffff' ? '#f5f5f5' : background, 5);\n const destructive = '#ef4444';\n const chart = generateChartColors(primary);\n\n const radiusRem = radius === '9999px' ? '9999px' : `${parseInt(radius) / 16}rem`;\n\n const vars: Record<string, string> = {\n '--background': hslString(background),\n '--foreground': hslString(foreground),\n '--card': hslString(background === '#ffffff' ? '#ffffff' : lighten(background, 3)),\n '--card-foreground': hslString(foreground),\n '--popover': hslString(background === '#ffffff' ? '#ffffff' : lighten(background, 5)),\n '--popover-foreground': hslString(foreground),\n '--primary': hslString(primary),\n '--primary-foreground': hslString(contrastForeground(primary)),\n '--secondary': hslString(scale[100]),\n '--secondary-foreground': hslString(foreground),\n '--muted': hslString(muted),\n '--muted-foreground': hslString(lighten(foreground, 40)),\n '--accent': hslString(accent),\n '--accent-foreground': hslString(contrastForeground(accent)),\n '--destructive': hslString(destructive),\n '--destructive-foreground': hslString(contrastForeground(destructive)),\n '--border': hslString(border),\n '--input': hslString(border),\n '--ring': hslString(primary),\n '--radius': radiusRem,\n '--chart-1': hslString(chart[0]),\n '--chart-2': hslString(chart[1]),\n '--chart-3': hslString(chart[2]),\n '--chart-4': hslString(chart[3]),\n '--chart-5': hslString(chart[4]),\n };\n\n const lines = ['@layer base {', ' :root {'];\n for (const [k, v] of Object.entries(vars)) {\n lines.push(` ${k}: ${v};`);\n }\n lines.push(' }');\n\n // Dark mode\n if (overrides.darkMode) {\n const darkBg = hslToHex(hexToHsl(primary)[0], 15, 7);\n const darkFg = '#fafafa';\n const darkBorder = hslToHex(hexToHsl(primary)[0], 10, 18);\n const darkMuted = hslToHex(hexToHsl(primary)[0], 10, 15);\n\n lines.push('', ' .dark {');\n const darkVars: Record<string, string> = {\n '--background': hslString(darkBg),\n '--foreground': hslString(darkFg),\n '--card': hslString(lighten(darkBg, 3)),\n '--card-foreground': hslString(darkFg),\n '--popover': hslString(lighten(darkBg, 5)),\n '--popover-foreground': hslString(darkFg),\n '--primary': hslString(primary),\n '--primary-foreground': hslString(contrastForeground(primary)),\n '--secondary': hslString(hslToHex(hexToHsl(primary)[0], 15, 20)),\n '--secondary-foreground': hslString(darkFg),\n '--muted': hslString(darkMuted),\n '--muted-foreground': hslString(darken(darkFg, 35)),\n '--accent': hslString(accent),\n '--accent-foreground': hslString(contrastForeground(accent)),\n '--destructive': hslString(destructive),\n '--destructive-foreground': hslString(contrastForeground(destructive)),\n '--border': hslString(darkBorder),\n '--input': hslString(lighten(darkBorder, 5)),\n '--ring': hslString(primary),\n '--chart-1': hslString(chart[0]),\n '--chart-2': hslString(chart[1]),\n '--chart-3': hslString(chart[2]),\n '--chart-4': hslString(chart[3]),\n '--chart-5': hslString(chart[4]),\n };\n for (const [k, v] of Object.entries(darkVars)) {\n lines.push(` ${k}: ${v};`);\n }\n lines.push(' }');\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n\nfunction buildShadcnSection(css: string): string {\n return `\n\n---\n\n## 10. shadcn/ui Theme\n\nCopy this CSS block into your \\`globals.css\\` to apply this design system to shadcn/ui components.\n\n\\`\\`\\`css\n${css}\n\\`\\`\\`\n`;\n}\n\n// ── Preview Data ─────────────────────────────────────────────────\n\nexport interface PreviewData {\n name: string;\n basedOn: string;\n primary: string;\n background: string;\n foreground: string;\n font: string;\n headingWeight: string;\n radius: string;\n shadcnCss: string;\n designMd: string;\n colors: {\n primary: string;\n accent: string;\n muted: string;\n destructive: string;\n border: string;\n scale: Record<string, string>;\n chart: string[];\n };\n darkMode: boolean;\n}\n\nfunction buildPreviewData(\n ref: ReferenceEntry,\n overrides: CustomOverrides,\n primary: string,\n background: string,\n foreground: string,\n font: string,\n headingWeight: string,\n radius: string,\n): PreviewData {\n const scale = generateColorScale(primary);\n const accent = ref.colors.accent || hslToHex((hexToHsl(primary)[0] + 30) % 360, 60, 55);\n const border = ref.colors.border || lighten(foreground, 75);\n const chart = generateChartColors(primary);\n\n return {\n name: overrides.primaryColor || overrides.fontFamily ? `Custom (based on ${ref.name})` : ref.name,\n basedOn: ref.name,\n primary,\n background,\n foreground,\n font,\n headingWeight,\n radius,\n shadcnCss: '', // filled later\n designMd: '', // filled later\n colors: {\n primary,\n accent,\n muted: lighten(background === '#ffffff' ? '#f5f5f5' : background, 5),\n destructive: '#ef4444',\n border,\n scale: scale as unknown as Record<string, string>,\n chart,\n },\n darkMode: overrides.darkMode,\n };\n}\n\n// ── Iconography section ──────────────────────────────────────────\n\nfunction buildIconographySection(): string {\n return `\n\n---\n\n## Iconography & SVG Guidelines\n\n### Icon Library\n\nUse a single, consistent icon library throughout the project. Recommended options:\n\n- **Lucide React** (\\`lucide-react\\`): Default for shadcn/ui projects. 1,400+ icons, tree-shakeable, consistent 24x24 grid.\n- **Radix Icons** (\\`@radix-ui/react-icons\\`): 300+ icons, 15x15 grid, minimal and geometric.\n- **Heroicons** (\\`@heroicons/react\\`): 300+ icons by Tailwind team, outline and solid variants.\n\nPick ONE library and use it everywhere. Do not mix icon libraries within the same project.\n\n### SVG Usage Rules\n\n- All icons must be inline SVG components (not \\`<img>\\` tags) for color and size control.\n- Icon size follows the type scale: 16px (inline), 20px (buttons), 24px (standalone).\n- Icon color inherits from \\`currentColor\\` -- never hard-code fill/stroke colors.\n- For custom/brand icons, export as SVG components with \\`currentColor\\` fills.\n- Stroke width: 1.5px-2px for outline icons. Keep consistent across the project.\n\n### Icon Sizing Scale\n\n| Context | Size | Usage |\n|---------|------|-------|\n| Inline text | 16px (1rem) | Badges, labels, breadcrumbs |\n| Button icon | 18px (1.125rem) | Icon buttons, CTA icons |\n| Standalone | 24px (1.5rem) | Navigation, card icons |\n| Feature | 32-48px | Hero sections, empty states |\n\n### SVG Optimization\n\n- Run all custom SVGs through SVGO before committing.\n- Remove unnecessary attributes: \\`xmlns\\`, \\`xml:space\\`, editor metadata.\n- Use \\`viewBox\\` instead of fixed \\`width\\`/\\`height\\` for scalability.\n`;\n}\n\n// ── Document policies ────────────────────────────────────────────\n\nfunction buildDocumentPolicies(): string {\n return `\n\n---\n\n## Document Policies\n\n### No Emojis\n\nThis design system must not use emojis in any UI element, component, label, status indicator, or documentation.\nUse SVG icons from the chosen icon library instead. Emojis render inconsistently across platforms and break visual coherence.\n\n- Status indicators: use colored dots or icon components, not emoji.\n- Section markers: use text prefixes (\"DO:\" / \"DON'T:\") or icons, not checkmark/cross emojis.\n- Navigation: use icon components, not emoji.\n\n### Format Compliance\n\nThis document follows the Google Stitch DESIGN.md 9-section format:\n1. Visual Theme & Atmosphere\n2. Color Palette & Roles\n3. Typography Rules\n4. Component Stylings\n5. Layout Principles\n6. Depth & Elevation\n7. Do's and Don'ts\n8. Responsive Behavior\n9. Agent Prompt Guide\n\nExtended with:\n- Iconography & SVG Guidelines\n- Document Policies\n\nTotal target length: 250-400 lines. Keep sections concise and actionable.\n`;\n}\n"],"mappings":"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","names":[]}
|