sh-ui-cli 0.98.0 → 0.109.1
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/data/changelog/versions.json +169 -0
- package/data/registry/react/components/scroll-area/index.module.tsx +71 -0
- package/data/registry/react/components/scroll-area/index.tailwind.tsx +54 -0
- package/data/registry/react/components/scroll-area/index.tsx +67 -0
- package/data/registry/react/components/scroll-area/styles.css +64 -0
- package/data/registry/react/components/scroll-area/styles.module.css +64 -0
- package/data/registry/react/components/sheet/index.module.tsx +93 -0
- package/data/registry/react/components/sheet/index.tailwind.tsx +120 -0
- package/data/registry/react/components/sheet/index.tsx +121 -0
- package/data/registry/react/components/sheet/styles.css +183 -0
- package/data/registry/react/components/sheet/styles.module.css +171 -0
- package/data/registry/react/registry.json +94 -0
- package/data/registry/react/tokens-used.json +86 -1
- package/data/summaries/react.json +3 -1
- package/data/tokens/src/primitives.json +8 -0
- package/data/tokens/src/semantic.json +36 -10
- package/package.json +1 -1
- package/src/add.mjs +39 -14
- package/src/create/cli-args.js +18 -5
- package/src/create/generator.js +116 -4
- package/src/create/index.mjs +3 -0
- package/src/create/plugins/nextIntl.js +3 -0
- package/src/create/theme/decode.js +3 -0
- package/src/create/theme/presets.js +45 -8
- package/src/css-bundle.mjs +60 -0
- package/src/mcp.mjs +47 -3
- package/src/remove.mjs +10 -1
- package/src/theme-extract.mjs +1 -0
- package/templates/nextjs-standalone/_arch/flat/app/globals.css +16 -4
- package/templates/nextjs-standalone/_arch/flat/lib/styles/tokens.css +35 -4
- package/templates/nextjs-standalone/_arch/fsd/src/shared/styles/tokens.css +35 -4
- package/templates/nextjs-standalone/_arch/mes/app/globals.css +16 -4
- package/templates/nextjs-standalone/_arch/mes/src/lib/styles/tokens.css +33 -2
- package/templates/nextjs-standalone/app/globals.css +16 -4
- package/templates/ui-app-template/src/styles/globals.css +16 -4
- package/templates/ui-app-template/src/styles/tokens.css +35 -4
- package/templates/vite-standalone/_arch/flat/src/lib/styles/globals.css +16 -0
- package/templates/vite-standalone/_arch/flat/src/lib/styles/tokens.css +35 -4
- package/templates/vite-standalone/_arch/fsd/src/shared/styles/globals.css +16 -0
- package/templates/vite-standalone/_arch/fsd/src/shared/styles/tokens.css +35 -4
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
const NEUTRAL_LIGHT = {
|
|
10
10
|
'background': '#FFFFFF',
|
|
11
|
-
'background-subtle': '#
|
|
12
|
-
'background-muted': '#
|
|
11
|
+
'background-subtle': '#F5F5F5',
|
|
12
|
+
'background-muted': '#E5E5E5',
|
|
13
13
|
'background-inverse': '#0A0A0A',
|
|
14
14
|
'foreground': '#0A0A0A',
|
|
15
15
|
'foreground-muted': '#525252',
|
|
@@ -20,6 +20,10 @@ const NEUTRAL_LIGHT = {
|
|
|
20
20
|
'primary': '#171717',
|
|
21
21
|
'primary-foreground': '#FAFAFA',
|
|
22
22
|
'primary-hover': '#262626',
|
|
23
|
+
// accent — 디폴트는 primary 와 동일. 사용자가 분리하고 싶을 때만 별 값으로 override.
|
|
24
|
+
'accent': '#171717',
|
|
25
|
+
'accent-foreground': '#FAFAFA',
|
|
26
|
+
'accent-hover': '#262626',
|
|
23
27
|
'danger': '#DC2626',
|
|
24
28
|
'danger-foreground': '#FFFFFF',
|
|
25
29
|
'danger-hover': '#B91C1C',
|
|
@@ -30,10 +34,10 @@ const NEUTRAL_LIGHT = {
|
|
|
30
34
|
'warning-foreground': '#FFFFFF',
|
|
31
35
|
'info': '#2563EB',
|
|
32
36
|
'info-foreground': '#FFFFFF',
|
|
33
|
-
'sidebar-bg': '#
|
|
37
|
+
'sidebar-bg': '#F5F5F5',
|
|
34
38
|
'sidebar-fg': '#0A0A0A',
|
|
35
39
|
'sidebar-border': '#E5E5E5',
|
|
36
|
-
'sidebar-accent': '#
|
|
40
|
+
'sidebar-accent': '#E5E5E5',
|
|
37
41
|
'sidebar-accent-fg': '#0A0A0A',
|
|
38
42
|
};
|
|
39
43
|
|
|
@@ -51,6 +55,10 @@ const NEUTRAL_DARK = {
|
|
|
51
55
|
'primary': '#FAFAFA',
|
|
52
56
|
'primary-foreground': '#171717',
|
|
53
57
|
'primary-hover': '#E5E5E5',
|
|
58
|
+
// accent — 디폴트는 primary 와 동일. 사용자가 분리하고 싶을 때만 별 값으로 override.
|
|
59
|
+
'accent': '#FAFAFA',
|
|
60
|
+
'accent-foreground': '#171717',
|
|
61
|
+
'accent-hover': '#E5E5E5',
|
|
54
62
|
'danger': '#DC2626',
|
|
55
63
|
'danger-foreground': '#FFFFFF',
|
|
56
64
|
'danger-hover': '#EF4444',
|
|
@@ -79,8 +87,8 @@ export const THEME_PRESETS = {
|
|
|
79
87
|
label: '슬레이트 — 차분한 슬레이트 + 인디고 (정보 밀도)',
|
|
80
88
|
light: {
|
|
81
89
|
'background': '#FFFFFF',
|
|
82
|
-
'background-subtle': '#
|
|
83
|
-
'background-muted': '#
|
|
90
|
+
'background-subtle': '#F1F5F9',
|
|
91
|
+
'background-muted': '#E2E8F0',
|
|
84
92
|
'background-inverse': '#0F172A',
|
|
85
93
|
'foreground': '#0F172A',
|
|
86
94
|
'foreground-muted': '#475569',
|
|
@@ -91,6 +99,9 @@ export const THEME_PRESETS = {
|
|
|
91
99
|
'primary': '#4F46E5',
|
|
92
100
|
'primary-foreground': '#FFFFFF',
|
|
93
101
|
'primary-hover': '#4338CA',
|
|
102
|
+
'accent': '#4F46E5',
|
|
103
|
+
'accent-foreground': '#FFFFFF',
|
|
104
|
+
'accent-hover': '#4338CA',
|
|
94
105
|
'danger': '#DC2626',
|
|
95
106
|
'danger-foreground': '#FFFFFF',
|
|
96
107
|
'danger-hover': '#B91C1C',
|
|
@@ -101,10 +112,10 @@ export const THEME_PRESETS = {
|
|
|
101
112
|
'warning-foreground': '#FFFFFF',
|
|
102
113
|
'info': '#2563EB',
|
|
103
114
|
'info-foreground': '#FFFFFF',
|
|
104
|
-
'sidebar-bg': '#
|
|
115
|
+
'sidebar-bg': '#F1F5F9',
|
|
105
116
|
'sidebar-fg': '#0F172A',
|
|
106
117
|
'sidebar-border': '#E2E8F0',
|
|
107
|
-
'sidebar-accent': '#
|
|
118
|
+
'sidebar-accent': '#E2E8F0',
|
|
108
119
|
'sidebar-accent-fg': '#0F172A',
|
|
109
120
|
},
|
|
110
121
|
dark: {
|
|
@@ -121,6 +132,11 @@ export const THEME_PRESETS = {
|
|
|
121
132
|
'primary': '#818CF8',
|
|
122
133
|
'primary-foreground': '#1E1B4B',
|
|
123
134
|
'primary-hover': '#A5B4FC',
|
|
135
|
+
// accent chroma 상향 — primary 보다 한 단계 lighter+saturated 한 indigo-300.
|
|
136
|
+
// 어두운 배경 위에서 highlight (링크/선택 상태) 가독성 ↑ (v0.109.0+).
|
|
137
|
+
'accent': '#A5B4FC',
|
|
138
|
+
'accent-foreground': '#1E1B4B',
|
|
139
|
+
'accent-hover': '#C7D2FE',
|
|
124
140
|
'danger': '#F87171',
|
|
125
141
|
'danger-foreground': '#450A0A',
|
|
126
142
|
'danger-hover': '#FCA5A5',
|
|
@@ -149,12 +165,19 @@ export const THEME_PRESETS = {
|
|
|
149
165
|
'primary': '#E11D48',
|
|
150
166
|
'primary-foreground': '#FFF1F2',
|
|
151
167
|
'primary-hover': '#BE123C',
|
|
168
|
+
'accent': '#E11D48',
|
|
169
|
+
'accent-foreground': '#FFF1F2',
|
|
170
|
+
'accent-hover': '#BE123C',
|
|
152
171
|
},
|
|
153
172
|
dark: {
|
|
154
173
|
...NEUTRAL_DARK,
|
|
155
174
|
'primary': '#FB7185',
|
|
156
175
|
'primary-foreground': '#4C0519',
|
|
157
176
|
'primary-hover': '#FDA4AF',
|
|
177
|
+
// accent chroma 상향 — rose-300 (v0.109.0+).
|
|
178
|
+
'accent': '#FDA4AF',
|
|
179
|
+
'accent-foreground': '#4C0519',
|
|
180
|
+
'accent-hover': '#FECDD3',
|
|
158
181
|
},
|
|
159
182
|
radius: 0.75,
|
|
160
183
|
// 큰 모서리 + 큼직한 컨트롤 — 소비자 앱 / 캐주얼 인상
|
|
@@ -167,12 +190,19 @@ export const THEME_PRESETS = {
|
|
|
167
190
|
'primary': '#059669',
|
|
168
191
|
'primary-foreground': '#ECFDF5',
|
|
169
192
|
'primary-hover': '#047857',
|
|
193
|
+
'accent': '#059669',
|
|
194
|
+
'accent-foreground': '#ECFDF5',
|
|
195
|
+
'accent-hover': '#047857',
|
|
170
196
|
},
|
|
171
197
|
dark: {
|
|
172
198
|
...NEUTRAL_DARK,
|
|
173
199
|
'primary': '#34D399',
|
|
174
200
|
'primary-foreground': '#022C22',
|
|
175
201
|
'primary-hover': '#6EE7B7',
|
|
202
|
+
// accent chroma 상향 — emerald-300 (v0.109.0+).
|
|
203
|
+
'accent': '#6EE7B7',
|
|
204
|
+
'accent-foreground': '#022C22',
|
|
205
|
+
'accent-hover': '#A7F3D0',
|
|
176
206
|
},
|
|
177
207
|
radius: 0.5,
|
|
178
208
|
},
|
|
@@ -183,12 +213,19 @@ export const THEME_PRESETS = {
|
|
|
183
213
|
'primary': '#7C3AED',
|
|
184
214
|
'primary-foreground': '#F5F3FF',
|
|
185
215
|
'primary-hover': '#6D28D9',
|
|
216
|
+
'accent': '#7C3AED',
|
|
217
|
+
'accent-foreground': '#F5F3FF',
|
|
218
|
+
'accent-hover': '#6D28D9',
|
|
186
219
|
},
|
|
187
220
|
dark: {
|
|
188
221
|
...NEUTRAL_DARK,
|
|
189
222
|
'primary': '#A78BFA',
|
|
190
223
|
'primary-foreground': '#1E1B4B',
|
|
191
224
|
'primary-hover': '#C4B5FD',
|
|
225
|
+
// accent chroma 상향 — violet-300 (v0.109.0+).
|
|
226
|
+
'accent': '#C4B5FD',
|
|
227
|
+
'accent-foreground': '#1E1B4B',
|
|
228
|
+
'accent-hover': '#DDD6FE',
|
|
192
229
|
},
|
|
193
230
|
radius: 0.625,
|
|
194
231
|
// 살짝 큰 컨트롤 + 진한 강조 보더 (creative/디자인 도구 인상)
|
package/src/css-bundle.mjs
CHANGED
|
@@ -88,6 +88,66 @@ export function stripStylesImport(tsxText) {
|
|
|
88
88
|
);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* 크로스컴포넌트 상대 import 매칭 정규식 생성 (호출마다 새 RegExp — lastIndex 상태 회피).
|
|
93
|
+
*
|
|
94
|
+
* 매칭: `... from "../<comp>..."` / `... from "../<comp>/index.tsx"` 형태.
|
|
95
|
+
* - group1: `from` 키워드 + 공백 (re-export `export {…} from` 도 포함)
|
|
96
|
+
* - group2: 따옴표
|
|
97
|
+
* - 리터럴 `../` 다음 negative-lookahead `(?!\.)` — `../../` / `../.x` 는 제외
|
|
98
|
+
* (sh-ui 컴포넌트는 항상 형제 디렉터리라 정확히 한 단계 `../`)
|
|
99
|
+
* - group3: 컴포넌트 경로 (따옴표/개행 없음, subpath 포함 가능: `form/types`)
|
|
100
|
+
* 같은 디렉터리(`./styles.css` 등)와 side-effect import(`import "..."`)는 매칭 안 됨.
|
|
101
|
+
*/
|
|
102
|
+
function crossComponentImportRe() {
|
|
103
|
+
return /(\bfrom\s+)(["'])\.\.\/(?!\.)([^"'\n]+)\2/g;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 컴포넌트 소스에 다른 sh-ui 컴포넌트를 가리키는 상대 import 가 있는지.
|
|
108
|
+
* add 시 aliases.components 미설정을 사전 차단하는 게이트로 사용.
|
|
109
|
+
*/
|
|
110
|
+
export function hasCrossComponentImport(content) {
|
|
111
|
+
return crossComponentImportRe().test(content);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* registry 컴포넌트의 크로스컴포넌트 상대 import 를 사용자 config 의
|
|
116
|
+
* `aliases.components` 경유 모듈 스펙으로 재작성.
|
|
117
|
+
*
|
|
118
|
+
* 왜: registry 소스는 가독성을 위해 형제 컴포넌트를 `import … from "../popover"`
|
|
119
|
+
* 처럼 상대경로로 적는다. 이게 그대로 소비자 프로젝트에 emit 되면
|
|
120
|
+
* `moduleResolution: "NodeNext"`/`"Node16"` 환경에서 깨진다 — NodeNext 는
|
|
121
|
+
* 확장자 없는/디렉터리 상대 import 를 허용하지 않고, 과거 일부 버전이 emit 한
|
|
122
|
+
* `"../popover/index.tsx"` 는 명시적 `.tsx` 확장자라 TS5097 로 막힌다. 소비자는
|
|
123
|
+
* `allowImportingTsExtensions`+`noEmit` 같은 침습적 tsconfig 변경을 강요당한다.
|
|
124
|
+
* `@SH_UI_UTILS@` 가 `aliases.utils` 로 치환되는 것과 동일하게, 크로스컴포넌트
|
|
125
|
+
* import 도 add 시점에 `aliases.components` 로 재작성하면 Bundler/NodeNext
|
|
126
|
+
* 양쪽에서 소비자 tsconfig 변경 없이 resolve 된다.
|
|
127
|
+
*
|
|
128
|
+
* 변환 규칙: `../<rest>` → `<componentsAlias>/<rest>` (선행 `../` 제거),
|
|
129
|
+
* 그리고 말미의 `/index`(+`.tsx|.ts|.jsx|.js`)는 제거 — `../popover`,
|
|
130
|
+
* `../popover/index.tsx`, `../form/types` 가 모두 동일하게
|
|
131
|
+
* `<alias>/popover`, `<alias>/form/types` 로 정규화된다.
|
|
132
|
+
*
|
|
133
|
+
* `componentsAlias` 가 falsy 면 그대로 반환 (remove.mjs 의 best-effort 재생 replay
|
|
134
|
+
* 처럼 alias 미설정 컨텍스트에서 throw 하지 않기 위함 — 검증/차단은 add.mjs 책임).
|
|
135
|
+
*
|
|
136
|
+
* @param {string} content 컴포넌트 소스
|
|
137
|
+
* @param {string} componentsAlias 예: `@workspace/ui-core/components`
|
|
138
|
+
* @returns {string} 재작성된 소스
|
|
139
|
+
*/
|
|
140
|
+
export function rewriteCrossComponentImports(content, componentsAlias) {
|
|
141
|
+
if (!componentsAlias) return content;
|
|
142
|
+
return content.replace(
|
|
143
|
+
crossComponentImportRe(),
|
|
144
|
+
(_m, fromKw, quote, spec) => {
|
|
145
|
+
const rest = spec.replace(/\/index(\.[tj]sx?)?$/, "");
|
|
146
|
+
return `${fromKw}${quote}${componentsAlias}/${rest}${quote}`;
|
|
147
|
+
},
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
91
151
|
/**
|
|
92
152
|
* registry 의 file 엔트리가 CSS 변종인지 (bundled 모드에서 별도 처리 대상).
|
|
93
153
|
*/
|
package/src/mcp.mjs
CHANGED
|
@@ -93,6 +93,34 @@ const INIT_DESCRIPTIONS = {
|
|
|
93
93
|
tailwind: "Tailwind v4 utility class — class-variance-authority 기반",
|
|
94
94
|
"css-modules": "CSS Modules — .module.css + styles.X 참조, 빌드 타임 hash 격리",
|
|
95
95
|
},
|
|
96
|
+
// theme 프리셋 — sh_ui_create_project 의 theme 인자에 그대로 전달 가능.
|
|
97
|
+
// 사용자가 "다크 모던" / "따뜻한 종이" 같이 자연어로 의도를 표현하면 아래 keywordHints 로 매핑.
|
|
98
|
+
theme: {
|
|
99
|
+
neutral: "뉴트럴 — 흑백 강조 (sh-ui 기본). 어떤 브랜드에도 무난.",
|
|
100
|
+
slate: "슬레이트 — 차분한 슬레이트 + 인디고 (정보 밀도). 대시보드/관리자 인상.",
|
|
101
|
+
rose: "로즈 — 핑크 강조 + 둥근 모서리 (친근·여유). 소비자 앱·캐주얼.",
|
|
102
|
+
emerald: "에메랄드 — 그린 강조. 자연·금융·헬스 인상.",
|
|
103
|
+
violet: "바이올렛 — 퍼플 강조 + 살짝 라운드 (모던·또렷). 크리에이티브/디자인 도구.",
|
|
104
|
+
},
|
|
105
|
+
// 자연어 의도 → enum/preset 매핑 힌트 (한국어 표현 위주).
|
|
106
|
+
// 사용자가 "다크 모던" / "따뜻한 종이" / "한국 핀테크 스타일" 같이 의도만 던지면 AI 가
|
|
107
|
+
// 이 사전을 보고 platform/base/radius/mode/theme 조합으로 매핑한다.
|
|
108
|
+
keywordHints: {
|
|
109
|
+
"다크 모던 / dark modern / 검정 모던": "base=zinc · mode=dark · radius=sm · theme=neutral",
|
|
110
|
+
"라이트 모던 / 밝은 모던 / clean": "base=zinc · mode=light · radius=sm · theme=neutral",
|
|
111
|
+
"따뜻한 / 따뜻한 종이 / warm paper / 종이": "theme=rose 또는 neutral · radius=md · mode=light-dark",
|
|
112
|
+
"친근한 / 캐주얼 / 부드러운 / 동글동글 / soft": "theme=rose · radius=lg · mode=light-dark",
|
|
113
|
+
"한국 핀테크 / 핀테크 / fintech / 금융": "theme=slate (indigo) 또는 violet · radius=sm · mode=light-dark",
|
|
114
|
+
"기업 관리자 / 관리자 / 어드민 / admin / MES / ERP / 백오피스": "theme=slate · arch=mes · radius=sm",
|
|
115
|
+
"차분한 / 프로페셔널 / 푸른빛 / 정보 밀도": "base=slate 또는 theme=slate · radius=sm",
|
|
116
|
+
"그린 강조 / 자연 / 헬스 / 환경": "theme=emerald · radius=md",
|
|
117
|
+
"퍼플 강조 / 크리에이티브 / 디자인 도구": "theme=violet · radius=lg · borders=두꺼움",
|
|
118
|
+
"쇼핑몰 / 커머스 / 소비자 앱": "theme=rose 또는 emerald · radius=lg · mode=light-dark",
|
|
119
|
+
"데이터 대시보드 / 차트 / 분석 도구": "theme=slate · base=slate · radius=sm · 정보 밀도 ↑",
|
|
120
|
+
"AI / 챗봇 / 생성형": "theme=violet 또는 neutral · radius=md · mode=light-dark",
|
|
121
|
+
"스타트업 / 모던 / 트렌디": "theme=violet 또는 rose · radius=md",
|
|
122
|
+
"교육 / 학습 / 친근": "theme=rose 또는 emerald · radius=lg",
|
|
123
|
+
},
|
|
96
124
|
};
|
|
97
125
|
|
|
98
126
|
/** stdout 으로 출력되는 console.* 호출을 버퍼에 캡처해 텍스트로 반환. */
|
|
@@ -419,8 +447,10 @@ export async function startMcpServer() {
|
|
|
419
447
|
"sh_ui_describe_init",
|
|
420
448
|
{
|
|
421
449
|
description:
|
|
422
|
-
"sh-ui init 의
|
|
423
|
-
"
|
|
450
|
+
"sh-ui init 의 선택지 사전 — platform/base/radius/mode/cssFramework/theme 의 enum + 한글 설명, " +
|
|
451
|
+
"그리고 사용자 자연어 의도 (\"다크 모던\" / \"따뜻한 종이\" / \"한국 핀테크 스타일\" 등) 를 " +
|
|
452
|
+
"enum/preset 조합으로 매핑하는 keywordHints 사전을 함께 반환. " +
|
|
453
|
+
"사용자가 톤을 자연어로 던지면 이 툴을 먼저 호출해 매핑 후 sh_ui_create_project 의 theme/base/radius 인자에 반영. v0.106.0+ 에서 theme + keywordHints 키 추가.",
|
|
424
454
|
inputSchema: {},
|
|
425
455
|
},
|
|
426
456
|
async () => jsonResult(INIT_DESCRIPTIONS),
|
|
@@ -478,6 +508,17 @@ export async function startMcpServer() {
|
|
|
478
508
|
),
|
|
479
509
|
port: z.string().optional()
|
|
480
510
|
.describe("monorepo 첫 앱의 dev 포트. 기본 '3000'. structure=monorepo 일 때만 의미."),
|
|
511
|
+
gitInit: z.boolean().optional()
|
|
512
|
+
.describe(
|
|
513
|
+
"git init 실행 여부. 기본 auto — parent 가 이미 git tree 안이면 자동 스킵 (nested .git 충돌 방지), 밖이면 init. " +
|
|
514
|
+
"true 로 nested 강제, false 로 명시 스킵. v0.102.0+ 신규.",
|
|
515
|
+
),
|
|
516
|
+
locale: z.enum(["default", "ko"]).optional()
|
|
517
|
+
.describe(
|
|
518
|
+
"사용자 지역 디폴트 가정. 'ko' 선택 시 globals.css 에 Pretendard 폰트가 자동 적용 (CDN @import + body font-family). " +
|
|
519
|
+
"한국어 사용자가 init 직후 거의 100% 첫 작업이라 한 옵션으로 자동화. " +
|
|
520
|
+
"locales (복수) 와 다름 — locales 는 i18n 활성화 시 생성할 locale 코드 목록. v0.103.0+ 신규.",
|
|
521
|
+
),
|
|
481
522
|
},
|
|
482
523
|
},
|
|
483
524
|
async (input) => {
|
|
@@ -537,6 +578,8 @@ export async function startMcpServer() {
|
|
|
537
578
|
locales: input.locales,
|
|
538
579
|
appName: input.appName,
|
|
539
580
|
port: input.port,
|
|
581
|
+
gitInit: input.gitInit,
|
|
582
|
+
locale: input.locale,
|
|
540
583
|
yes: true, // 사전 검사를 마쳤으니 generator 의 confirm 프롬프트 우회
|
|
541
584
|
}),
|
|
542
585
|
);
|
|
@@ -802,8 +845,9 @@ export async function startMcpServer() {
|
|
|
802
845
|
success: HEX.optional(), "success-foreground": HEX.optional(),
|
|
803
846
|
warning: HEX.optional(), "warning-foreground": HEX.optional(),
|
|
804
847
|
info: HEX.optional(), "info-foreground": HEX.optional(),
|
|
848
|
+
accent: HEX.optional(), "accent-foreground": HEX.optional(), "accent-hover": HEX.optional(),
|
|
805
849
|
})
|
|
806
|
-
.describe("15개 필수 색 토큰 + 옵셔널
|
|
850
|
+
.describe("15개 필수 색 토큰 + 옵셔널 9개(success/warning/info × -foreground + accent/accent-foreground/accent-hover). 각 값은 #RRGGBB hex");
|
|
807
851
|
|
|
808
852
|
server.registerTool(
|
|
809
853
|
"sh_ui_encode_theme",
|
package/src/remove.mjs
CHANGED
|
@@ -2,7 +2,13 @@ import { readFile, rm, rmdir, readdir, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { dirname, resolve, relative } from "node:path";
|
|
4
4
|
import { getRegistryRoot } from "./paths.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
removeSection,
|
|
7
|
+
isStyleFile,
|
|
8
|
+
stripStylesImport,
|
|
9
|
+
isTsxFile,
|
|
10
|
+
rewriteCrossComponentImports,
|
|
11
|
+
} from "./css-bundle.mjs";
|
|
6
12
|
|
|
7
13
|
/** registry file 엔트리가 현재 cssFramework 와 호환되는지 (add.mjs 와 동일 규칙). */
|
|
8
14
|
function frameworkMatches(entry, cssFramework) {
|
|
@@ -105,6 +111,9 @@ export async function remove({ cwd, names, force = false, dryRun = false }) {
|
|
|
105
111
|
if (config.aliases?.utils) {
|
|
106
112
|
out = out.replaceAll("@SH_UI_UTILS@", config.aliases.utils);
|
|
107
113
|
}
|
|
114
|
+
if (config.aliases?.components) {
|
|
115
|
+
out = rewriteCrossComponentImports(out, config.aliases.components);
|
|
116
|
+
}
|
|
108
117
|
if (bundled && isTsxFile(file)) out = stripStylesImport(out);
|
|
109
118
|
return out;
|
|
110
119
|
};
|
package/src/theme-extract.mjs
CHANGED
|
@@ -31,6 +31,9 @@
|
|
|
31
31
|
--color-primary: var(--primary);
|
|
32
32
|
--color-primary-foreground: var(--primary-foreground);
|
|
33
33
|
--color-primary-hover: var(--primary-hover);
|
|
34
|
+
--color-accent: var(--accent);
|
|
35
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
36
|
+
--color-accent-hover: var(--accent-hover);
|
|
34
37
|
--color-ring: var(--ring);
|
|
35
38
|
--color-danger: var(--danger);
|
|
36
39
|
--color-danger-hover: var(--danger-hover);
|
|
@@ -46,10 +49,19 @@
|
|
|
46
49
|
--color-sidebar-border: var(--sidebar-border);
|
|
47
50
|
--color-sidebar-accent: var(--sidebar-accent);
|
|
48
51
|
--color-sidebar-accent-fg: var(--sidebar-accent-fg);
|
|
49
|
-
--
|
|
50
|
-
--
|
|
51
|
-
--
|
|
52
|
-
--
|
|
52
|
+
--shadow-popover: var(--shadow-popover);
|
|
53
|
+
--shadow-modal: var(--shadow-modal);
|
|
54
|
+
--shadow-toast: var(--shadow-toast);
|
|
55
|
+
--tracking-tighter: var(--tracking-tighter);
|
|
56
|
+
--tracking-tight: var(--tracking-tight);
|
|
57
|
+
--tracking-normal: var(--tracking-normal);
|
|
58
|
+
--tracking-wide: var(--tracking-wide);
|
|
59
|
+
--tracking-wider: var(--tracking-wider);
|
|
60
|
+
--radius-sm: 0.25rem;
|
|
61
|
+
--radius-md: 0.5rem;
|
|
62
|
+
--radius-lg: 0.75rem;
|
|
63
|
+
--radius-xl: 1rem;
|
|
64
|
+
--radius-full: 9999px;
|
|
53
65
|
}
|
|
54
66
|
|
|
55
67
|
@layer base {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/* Generated by @sh-ui/tokens — do not edit directly */
|
|
2
|
+
/* Input: sh-ui.config.json (theme block) */
|
|
3
|
+
/* Regenerate: npx sh-ui-cli tokens upgrade --replace */
|
|
2
4
|
/* base=neutral radius=md mode=light-dark */
|
|
3
5
|
|
|
4
6
|
/* sh-ui:theme-colors-start */
|
|
5
7
|
:root {
|
|
6
8
|
--background: #FFFFFF;
|
|
7
|
-
--background-subtle: #
|
|
8
|
-
--background-muted: #
|
|
9
|
+
--background-subtle: #F5F5F5;
|
|
10
|
+
--background-muted: #E5E5E5;
|
|
9
11
|
--background-inverse: #0A0A0A;
|
|
10
12
|
--foreground: #0A0A0A;
|
|
11
13
|
--foreground-muted: #525252;
|
|
@@ -16,6 +18,9 @@
|
|
|
16
18
|
--primary: #171717;
|
|
17
19
|
--primary-foreground: #FAFAFA;
|
|
18
20
|
--primary-hover: #262626;
|
|
21
|
+
--accent: #171717;
|
|
22
|
+
--accent-foreground: #FAFAFA;
|
|
23
|
+
--accent-hover: #262626;
|
|
19
24
|
--ring: color-mix(in srgb, var(--primary) 50%, transparent);
|
|
20
25
|
--danger: #DC2626;
|
|
21
26
|
--danger-hover: color-mix(in srgb, var(--danger) 90%, black);
|
|
@@ -26,10 +31,10 @@
|
|
|
26
31
|
--warning-foreground: #FFFFFF;
|
|
27
32
|
--info: #2563EB;
|
|
28
33
|
--info-foreground: #FFFFFF;
|
|
29
|
-
--sidebar-bg: #
|
|
34
|
+
--sidebar-bg: #F5F5F5;
|
|
30
35
|
--sidebar-fg: #0A0A0A;
|
|
31
36
|
--sidebar-border: #E5E5E5;
|
|
32
|
-
--sidebar-accent: #
|
|
37
|
+
--sidebar-accent: #E5E5E5;
|
|
33
38
|
--sidebar-accent-fg: #0A0A0A;
|
|
34
39
|
}
|
|
35
40
|
@media (prefers-color-scheme: dark) {
|
|
@@ -47,6 +52,9 @@
|
|
|
47
52
|
--primary: #FAFAFA;
|
|
48
53
|
--primary-foreground: #171717;
|
|
49
54
|
--primary-hover: #E5E5E5;
|
|
55
|
+
--accent: #FAFAFA;
|
|
56
|
+
--accent-foreground: #171717;
|
|
57
|
+
--accent-hover: #E5E5E5;
|
|
50
58
|
--danger: #DC2626;
|
|
51
59
|
--danger-hover: color-mix(in srgb, var(--danger) 90%, black);
|
|
52
60
|
--danger-foreground: #FFFFFF;
|
|
@@ -77,6 +85,9 @@
|
|
|
77
85
|
--primary: #FAFAFA;
|
|
78
86
|
--primary-foreground: #171717;
|
|
79
87
|
--primary-hover: #E5E5E5;
|
|
88
|
+
--accent: #FAFAFA;
|
|
89
|
+
--accent-foreground: #171717;
|
|
90
|
+
--accent-hover: #E5E5E5;
|
|
80
91
|
--danger: #DC2626;
|
|
81
92
|
--danger-hover: color-mix(in srgb, var(--danger) 90%, black);
|
|
82
93
|
--danger-foreground: #FFFFFF;
|
|
@@ -97,6 +108,16 @@
|
|
|
97
108
|
:root {
|
|
98
109
|
/* sh-ui:theme-radius-start */
|
|
99
110
|
--radius: 0.5rem;
|
|
111
|
+
/* sh-ui:theme-radius-scale-start — Tailwind utility rounded-sm/md/lg/xl/full 의 값과 일치.
|
|
112
|
+
* v0.106.0+ — 사용자 base radius (--radius) 와 별개의 절대값 scale.
|
|
113
|
+
* --radius 변경은 컴포넌트 default (input/button 등) 만 영향,
|
|
114
|
+
* rounded-* utility 는 아래 scale 값을 그대로 따른다. */
|
|
115
|
+
--radius-sm: 0.25rem;
|
|
116
|
+
--radius-md: 0.5rem;
|
|
117
|
+
--radius-lg: 0.75rem;
|
|
118
|
+
--radius-xl: 1rem;
|
|
119
|
+
--radius-full: 9999px;
|
|
120
|
+
/* sh-ui:theme-radius-scale-end */
|
|
100
121
|
/* sh-ui:theme-radius-end */
|
|
101
122
|
/* sh-ui:theme-space-start */
|
|
102
123
|
--space-0: 0;
|
|
@@ -133,6 +154,9 @@
|
|
|
133
154
|
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
134
155
|
--shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.18);
|
|
135
156
|
--shadow-menu: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
|
|
157
|
+
--shadow-popover: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
158
|
+
--shadow-modal: 0 16px 48px rgba(0, 0, 0, 0.18);
|
|
159
|
+
--shadow-toast: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
136
160
|
/* sh-ui:theme-shadow-end */
|
|
137
161
|
/* sh-ui:theme-duration-start */
|
|
138
162
|
--duration-fast: 120ms;
|
|
@@ -142,6 +166,13 @@
|
|
|
142
166
|
/* sh-ui:theme-ease-start */
|
|
143
167
|
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
|
|
144
168
|
--ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
|
|
169
|
+
/* sh-ui:theme-tracking-start */
|
|
170
|
+
--tracking-tighter: -0.04em;
|
|
171
|
+
--tracking-tight: -0.02em;
|
|
172
|
+
--tracking-normal: 0;
|
|
173
|
+
--tracking-wide: 0.02em;
|
|
174
|
+
--tracking-wider: 0.04em;
|
|
175
|
+
/* sh-ui:theme-tracking-end */
|
|
145
176
|
/* sh-ui:theme-ease-end */
|
|
146
177
|
/* sh-ui:theme-control-start */
|
|
147
178
|
--control-sm: 2rem;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/* Generated by @sh-ui/tokens — do not edit directly */
|
|
2
|
+
/* Input: sh-ui.config.json (theme block) */
|
|
3
|
+
/* Regenerate: npx sh-ui-cli tokens upgrade --replace */
|
|
2
4
|
/* base=neutral radius=md mode=light-dark */
|
|
3
5
|
|
|
4
6
|
/* sh-ui:theme-colors-start */
|
|
5
7
|
:root {
|
|
6
8
|
--background: #FFFFFF;
|
|
7
|
-
--background-subtle: #
|
|
8
|
-
--background-muted: #
|
|
9
|
+
--background-subtle: #F5F5F5;
|
|
10
|
+
--background-muted: #E5E5E5;
|
|
9
11
|
--background-inverse: #0A0A0A;
|
|
10
12
|
--foreground: #0A0A0A;
|
|
11
13
|
--foreground-muted: #525252;
|
|
@@ -16,6 +18,9 @@
|
|
|
16
18
|
--primary: #171717;
|
|
17
19
|
--primary-foreground: #FAFAFA;
|
|
18
20
|
--primary-hover: #262626;
|
|
21
|
+
--accent: #171717;
|
|
22
|
+
--accent-foreground: #FAFAFA;
|
|
23
|
+
--accent-hover: #262626;
|
|
19
24
|
--ring: color-mix(in srgb, var(--primary) 50%, transparent);
|
|
20
25
|
--danger: #DC2626;
|
|
21
26
|
--danger-hover: color-mix(in srgb, var(--danger) 90%, black);
|
|
@@ -26,10 +31,10 @@
|
|
|
26
31
|
--warning-foreground: #FFFFFF;
|
|
27
32
|
--info: #2563EB;
|
|
28
33
|
--info-foreground: #FFFFFF;
|
|
29
|
-
--sidebar-bg: #
|
|
34
|
+
--sidebar-bg: #F5F5F5;
|
|
30
35
|
--sidebar-fg: #0A0A0A;
|
|
31
36
|
--sidebar-border: #E5E5E5;
|
|
32
|
-
--sidebar-accent: #
|
|
37
|
+
--sidebar-accent: #E5E5E5;
|
|
33
38
|
--sidebar-accent-fg: #0A0A0A;
|
|
34
39
|
}
|
|
35
40
|
@media (prefers-color-scheme: dark) {
|
|
@@ -47,6 +52,9 @@
|
|
|
47
52
|
--primary: #FAFAFA;
|
|
48
53
|
--primary-foreground: #171717;
|
|
49
54
|
--primary-hover: #E5E5E5;
|
|
55
|
+
--accent: #FAFAFA;
|
|
56
|
+
--accent-foreground: #171717;
|
|
57
|
+
--accent-hover: #E5E5E5;
|
|
50
58
|
--danger: #DC2626;
|
|
51
59
|
--danger-hover: color-mix(in srgb, var(--danger) 90%, black);
|
|
52
60
|
--danger-foreground: #FFFFFF;
|
|
@@ -77,6 +85,9 @@
|
|
|
77
85
|
--primary: #FAFAFA;
|
|
78
86
|
--primary-foreground: #171717;
|
|
79
87
|
--primary-hover: #E5E5E5;
|
|
88
|
+
--accent: #FAFAFA;
|
|
89
|
+
--accent-foreground: #171717;
|
|
90
|
+
--accent-hover: #E5E5E5;
|
|
80
91
|
--danger: #DC2626;
|
|
81
92
|
--danger-hover: color-mix(in srgb, var(--danger) 90%, black);
|
|
82
93
|
--danger-foreground: #FFFFFF;
|
|
@@ -97,6 +108,16 @@
|
|
|
97
108
|
:root {
|
|
98
109
|
/* sh-ui:theme-radius-start */
|
|
99
110
|
--radius: 0.5rem;
|
|
111
|
+
/* sh-ui:theme-radius-scale-start — Tailwind utility rounded-sm/md/lg/xl/full 의 값과 일치.
|
|
112
|
+
* v0.106.0+ — 사용자 base radius (--radius) 와 별개의 절대값 scale.
|
|
113
|
+
* --radius 변경은 컴포넌트 default (input/button 등) 만 영향,
|
|
114
|
+
* rounded-* utility 는 아래 scale 값을 그대로 따른다. */
|
|
115
|
+
--radius-sm: 0.25rem;
|
|
116
|
+
--radius-md: 0.5rem;
|
|
117
|
+
--radius-lg: 0.75rem;
|
|
118
|
+
--radius-xl: 1rem;
|
|
119
|
+
--radius-full: 9999px;
|
|
120
|
+
/* sh-ui:theme-radius-scale-end */
|
|
100
121
|
/* sh-ui:theme-radius-end */
|
|
101
122
|
/* sh-ui:theme-space-start */
|
|
102
123
|
--space-0: 0;
|
|
@@ -133,6 +154,9 @@
|
|
|
133
154
|
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
134
155
|
--shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.18);
|
|
135
156
|
--shadow-menu: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
|
|
157
|
+
--shadow-popover: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
158
|
+
--shadow-modal: 0 16px 48px rgba(0, 0, 0, 0.18);
|
|
159
|
+
--shadow-toast: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
136
160
|
/* sh-ui:theme-shadow-end */
|
|
137
161
|
/* sh-ui:theme-duration-start */
|
|
138
162
|
--duration-fast: 120ms;
|
|
@@ -142,6 +166,13 @@
|
|
|
142
166
|
/* sh-ui:theme-ease-start */
|
|
143
167
|
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
|
|
144
168
|
--ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
|
|
169
|
+
/* sh-ui:theme-tracking-start */
|
|
170
|
+
--tracking-tighter: -0.04em;
|
|
171
|
+
--tracking-tight: -0.02em;
|
|
172
|
+
--tracking-normal: 0;
|
|
173
|
+
--tracking-wide: 0.02em;
|
|
174
|
+
--tracking-wider: 0.04em;
|
|
175
|
+
/* sh-ui:theme-tracking-end */
|
|
145
176
|
/* sh-ui:theme-ease-end */
|
|
146
177
|
/* sh-ui:theme-control-start */
|
|
147
178
|
--control-sm: 2rem;
|
|
@@ -31,6 +31,9 @@
|
|
|
31
31
|
--color-primary: var(--primary);
|
|
32
32
|
--color-primary-foreground: var(--primary-foreground);
|
|
33
33
|
--color-primary-hover: var(--primary-hover);
|
|
34
|
+
--color-accent: var(--accent);
|
|
35
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
36
|
+
--color-accent-hover: var(--accent-hover);
|
|
34
37
|
--color-ring: var(--ring);
|
|
35
38
|
--color-danger: var(--danger);
|
|
36
39
|
--color-danger-hover: var(--danger-hover);
|
|
@@ -46,10 +49,19 @@
|
|
|
46
49
|
--color-sidebar-border: var(--sidebar-border);
|
|
47
50
|
--color-sidebar-accent: var(--sidebar-accent);
|
|
48
51
|
--color-sidebar-accent-fg: var(--sidebar-accent-fg);
|
|
49
|
-
--
|
|
50
|
-
--
|
|
51
|
-
--
|
|
52
|
-
--
|
|
52
|
+
--shadow-popover: var(--shadow-popover);
|
|
53
|
+
--shadow-modal: var(--shadow-modal);
|
|
54
|
+
--shadow-toast: var(--shadow-toast);
|
|
55
|
+
--tracking-tighter: var(--tracking-tighter);
|
|
56
|
+
--tracking-tight: var(--tracking-tight);
|
|
57
|
+
--tracking-normal: var(--tracking-normal);
|
|
58
|
+
--tracking-wide: var(--tracking-wide);
|
|
59
|
+
--tracking-wider: var(--tracking-wider);
|
|
60
|
+
--radius-sm: 0.25rem;
|
|
61
|
+
--radius-md: 0.5rem;
|
|
62
|
+
--radius-lg: 0.75rem;
|
|
63
|
+
--radius-xl: 1rem;
|
|
64
|
+
--radius-full: 9999px;
|
|
53
65
|
}
|
|
54
66
|
|
|
55
67
|
@layer base {
|