sh-ui-cli 0.98.1 → 0.110.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.
Files changed (40) hide show
  1. package/data/changelog/versions.json +169 -0
  2. package/data/registry/react/components/scroll-area/index.module.tsx +71 -0
  3. package/data/registry/react/components/scroll-area/index.tailwind.tsx +54 -0
  4. package/data/registry/react/components/scroll-area/index.tsx +67 -0
  5. package/data/registry/react/components/scroll-area/styles.css +64 -0
  6. package/data/registry/react/components/scroll-area/styles.module.css +64 -0
  7. package/data/registry/react/components/sheet/index.module.tsx +93 -0
  8. package/data/registry/react/components/sheet/index.tailwind.tsx +120 -0
  9. package/data/registry/react/components/sheet/index.tsx +121 -0
  10. package/data/registry/react/components/sheet/styles.css +183 -0
  11. package/data/registry/react/components/sheet/styles.module.css +171 -0
  12. package/data/registry/react/registry.json +94 -0
  13. package/data/registry/react/tokens-used.json +86 -1
  14. package/data/summaries/react.json +3 -1
  15. package/data/tokens/src/primitives.json +8 -0
  16. package/data/tokens/src/semantic.json +36 -10
  17. package/package.json +1 -1
  18. package/src/create/cli-args.js +20 -5
  19. package/src/create/describeTemplate.js +9 -7
  20. package/src/create/generator.js +168 -21
  21. package/src/create/index.mjs +9 -0
  22. package/src/create/plugins/nextIntl.js +3 -0
  23. package/src/create/templateManifest.js +1 -1
  24. package/src/create/theme/decode.js +3 -0
  25. package/src/create/theme/presets.js +45 -8
  26. package/src/mcp.mjs +68 -6
  27. package/src/theme-extract.mjs +1 -0
  28. package/templates/monorepo/npmrc +5 -0
  29. package/templates/nextjs-standalone/_arch/flat/app/globals.css +16 -4
  30. package/templates/nextjs-standalone/_arch/flat/lib/styles/tokens.css +35 -4
  31. package/templates/nextjs-standalone/_arch/fsd/src/shared/styles/tokens.css +35 -4
  32. package/templates/nextjs-standalone/_arch/mes/app/globals.css +16 -4
  33. package/templates/nextjs-standalone/_arch/mes/src/lib/styles/tokens.css +33 -2
  34. package/templates/nextjs-standalone/app/globals.css +16 -4
  35. package/templates/ui-app-template/src/styles/globals.css +16 -4
  36. package/templates/ui-app-template/src/styles/tokens.css +35 -4
  37. package/templates/vite-standalone/_arch/flat/src/lib/styles/globals.css +16 -0
  38. package/templates/vite-standalone/_arch/flat/src/lib/styles/tokens.css +35 -4
  39. package/templates/vite-standalone/_arch/fsd/src/shared/styles/globals.css +16 -0
  40. 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': '#FAFAFA',
12
- 'background-muted': '#F5F5F5',
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': '#FAFAFA',
37
+ 'sidebar-bg': '#F5F5F5',
34
38
  'sidebar-fg': '#0A0A0A',
35
39
  'sidebar-border': '#E5E5E5',
36
- 'sidebar-accent': '#F5F5F5',
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': '#F8FAFC',
83
- 'background-muted': '#F1F5F9',
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': '#F8FAFC',
115
+ 'sidebar-bg': '#F1F5F9',
105
116
  'sidebar-fg': '#0F172A',
106
117
  'sidebar-border': '#E2E8F0',
107
- 'sidebar-accent': '#F1F5F9',
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/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 의 4개 축(platform/base/radius/mode) 선택지와 한글 설명 반환. " +
423
- "사용자의 자연어 의도(\"다크 모던\", \"따뜻한 느낌\")를 enum 값으로 매핑할 먼저 호출.",
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),
@@ -458,7 +488,14 @@ export async function startMcpServer() {
458
488
  cwd: z.string().optional()
459
489
  .describe("부모 디렉토리. 기본 process.cwd()"),
460
490
  force: z.boolean().optional()
461
- .describe("기존 디렉토리 덮어쓰기. 기본 false (안전)"),
491
+ .describe("기존 디렉토리 덮어쓰기 — 디렉토리 전체를 삭제 후 새로 스캐폴드. 기본 false (안전)."),
492
+ inPlace: z.boolean().optional()
493
+ .describe(
494
+ "기존 디렉토리에 비파괴 머지 — 디렉토리를 삭제하지 않고, 이미 있는 파일은 보존한 채 " +
495
+ "없는 파일만 채워 넣는다. 커스터마이즈된 monorepo 루트(CLAUDE.md·.gitignore 등)·.git 을 " +
496
+ "지키면서 apps/·packages/ 를 재생성할 때 사용. force 와 상호배타 — force 는 전체 삭제, " +
497
+ "inPlace 는 보존. 재생성하려는 파일은 미리 지워두면 그 자리만 새로 채워진다. v0.110.0+ 신규.",
498
+ ),
462
499
  i18n: z.enum(I18N_LIBRARIES).optional()
463
500
  .describe(
464
501
  "i18n 라이브러리 — platform=vite 일 때만 의미. 'react-i18next' 로 설정 시 i18next + react-i18next + browser-languagedetector + http-backend 셋업 + " +
@@ -478,6 +515,17 @@ export async function startMcpServer() {
478
515
  ),
479
516
  port: z.string().optional()
480
517
  .describe("monorepo 첫 앱의 dev 포트. 기본 '3000'. structure=monorepo 일 때만 의미."),
518
+ gitInit: z.boolean().optional()
519
+ .describe(
520
+ "git init 실행 여부. 기본 auto — parent 가 이미 git tree 안이면 자동 스킵 (nested .git 충돌 방지), 밖이면 init. " +
521
+ "true 로 nested 강제, false 로 명시 스킵. v0.102.0+ 신규.",
522
+ ),
523
+ locale: z.enum(["default", "ko"]).optional()
524
+ .describe(
525
+ "사용자 지역 디폴트 가정. 'ko' 선택 시 globals.css 에 Pretendard 폰트가 자동 적용 (CDN @import + body font-family). " +
526
+ "한국어 사용자가 init 직후 거의 100% 첫 작업이라 한 옵션으로 자동화. " +
527
+ "locales (복수) 와 다름 — locales 는 i18n 활성화 시 생성할 locale 코드 목록. v0.103.0+ 신규.",
528
+ ),
481
529
  },
482
530
  },
483
531
  async (input) => {
@@ -508,15 +556,25 @@ export async function startMcpServer() {
508
556
  }],
509
557
  };
510
558
  }
559
+ if (input.force && input.inPlace) {
560
+ return {
561
+ isError: true,
562
+ content: [{
563
+ type: "text",
564
+ text: "force 와 inPlace 는 동시에 쓸 수 없습니다 — force 는 디렉토리 전체 삭제, inPlace 는 보존 머지.",
565
+ }],
566
+ };
567
+ }
511
568
  const targetParent = resolveCwd(input);
512
569
  const targetDir = resolve(targetParent, input.name);
513
- if (existsSync(targetDir) && !input.force) {
570
+ // inPlace 기존 디렉토리를 전제로 하므로 '이미 존재' 가 에러가 아니다.
571
+ if (existsSync(targetDir) && !input.force && !input.inPlace) {
514
572
  return {
515
573
  isError: true,
516
574
  content: [
517
575
  {
518
576
  type: "text",
519
- text: `'${targetDir}' 가 이미 존재합니다. 덮어쓰려면 force: true.`,
577
+ text: `'${targetDir}' 가 이미 존재합니다. 덮어쓰려면 force: true, 보존 머지하려면 inPlace: true.`,
520
578
  },
521
579
  ],
522
580
  };
@@ -537,6 +595,9 @@ export async function startMcpServer() {
537
595
  locales: input.locales,
538
596
  appName: input.appName,
539
597
  port: input.port,
598
+ gitInit: input.gitInit,
599
+ locale: input.locale,
600
+ inPlace: input.inPlace,
540
601
  yes: true, // 사전 검사를 마쳤으니 generator 의 confirm 프롬프트 우회
541
602
  }),
542
603
  );
@@ -802,8 +863,9 @@ export async function startMcpServer() {
802
863
  success: HEX.optional(), "success-foreground": HEX.optional(),
803
864
  warning: HEX.optional(), "warning-foreground": HEX.optional(),
804
865
  info: HEX.optional(), "info-foreground": HEX.optional(),
866
+ accent: HEX.optional(), "accent-foreground": HEX.optional(), "accent-hover": HEX.optional(),
805
867
  })
806
- .describe("15개 필수 색 토큰 + 옵셔널 6개(success/warning/info × -foreground). 각 값은 #RRGGBB hex");
868
+ .describe("15개 필수 색 토큰 + 옵셔널 9개(success/warning/info × -foreground + accent/accent-foreground/accent-hover). 각 값은 #RRGGBB hex");
807
869
 
808
870
  server.registerTool(
809
871
  "sh_ui_encode_theme",
@@ -55,6 +55,7 @@ const TOKEN_KEYS_OPTIONAL = [
55
55
  "info", "info-foreground",
56
56
  "danger-hover",
57
57
  "ring",
58
+ "accent", "accent-foreground", "accent-hover",
58
59
  ];
59
60
 
60
61
  const HEX_RE = /^#[0-9A-Fa-f]{6}$/;
@@ -0,0 +1,5 @@
1
+ # pnpm 으로 워크스페이스 패키지의 peer dep 자동 설치 (host 가 아니라 패키지 자체).
2
+ auto-install-peers=true
3
+
4
+ # `pnpm install` 시 lock 의 strict-version 검사 활성. CI 와 로컬 일관성.
5
+ strict-peer-dependencies=false
@@ -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
- --radius-sm: calc(var(--radius) - 2px);
50
- --radius-md: var(--radius);
51
- --radius-lg: calc(var(--radius) + 2px);
52
- --radius-xl: calc(var(--radius) + 4px);
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: #FAFAFA;
8
- --background-muted: #F5F5F5;
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: #FAFAFA;
34
+ --sidebar-bg: #F5F5F5;
30
35
  --sidebar-fg: #0A0A0A;
31
36
  --sidebar-border: #E5E5E5;
32
- --sidebar-accent: #F5F5F5;
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: #FAFAFA;
8
- --background-muted: #F5F5F5;
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: #FAFAFA;
34
+ --sidebar-bg: #F5F5F5;
30
35
  --sidebar-fg: #0A0A0A;
31
36
  --sidebar-border: #E5E5E5;
32
- --sidebar-accent: #F5F5F5;
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
- --radius-sm: calc(var(--radius) - 2px);
50
- --radius-md: var(--radius);
51
- --radius-lg: calc(var(--radius) + 2px);
52
- --radius-xl: calc(var(--radius) + 4px);
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: #FAFAFA;
8
- --background-muted: #F5F5F5;
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);
@@ -36,6 +41,9 @@
36
41
  --primary: #FAFAFA;
37
42
  --primary-foreground: #171717;
38
43
  --primary-hover: #E5E5E5;
44
+ --accent: #FAFAFA;
45
+ --accent-foreground: #171717;
46
+ --accent-hover: #E5E5E5;
39
47
  --danger: #DC2626;
40
48
  --danger-hover: color-mix(in srgb, var(--danger) 90%, black);
41
49
  --danger-foreground: #FFFFFF;
@@ -55,6 +63,9 @@
55
63
  --primary: #FAFAFA;
56
64
  --primary-foreground: #171717;
57
65
  --primary-hover: #E5E5E5;
66
+ --accent: #FAFAFA;
67
+ --accent-foreground: #171717;
68
+ --accent-hover: #E5E5E5;
58
69
  --danger: #DC2626;
59
70
  --danger-hover: color-mix(in srgb, var(--danger) 90%, black);
60
71
  --danger-foreground: #FFFFFF;
@@ -64,6 +75,16 @@
64
75
  :root {
65
76
  /* sh-ui:theme-radius-start */
66
77
  --radius: 0.5rem;
78
+ /* sh-ui:theme-radius-scale-start — Tailwind utility rounded-sm/md/lg/xl/full 의 값과 일치.
79
+ * v0.106.0+ — 사용자 base radius (--radius) 와 별개의 절대값 scale.
80
+ * --radius 변경은 컴포넌트 default (input/button 등) 만 영향,
81
+ * rounded-* utility 는 아래 scale 값을 그대로 따른다. */
82
+ --radius-sm: 0.25rem;
83
+ --radius-md: 0.5rem;
84
+ --radius-lg: 0.75rem;
85
+ --radius-xl: 1rem;
86
+ --radius-full: 9999px;
87
+ /* sh-ui:theme-radius-scale-end */
67
88
  /* sh-ui:theme-radius-end */
68
89
  /* sh-ui:theme-space-start */
69
90
  --space-0: 0;
@@ -100,6 +121,9 @@
100
121
  --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);
101
122
  --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.18);
102
123
  --shadow-menu: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
124
+ --shadow-popover: 0 8px 24px rgba(0, 0, 0, 0.15);
125
+ --shadow-modal: 0 16px 48px rgba(0, 0, 0, 0.18);
126
+ --shadow-toast: 0 4px 12px rgba(0, 0, 0, 0.12);
103
127
  /* sh-ui:theme-shadow-end */
104
128
  /* sh-ui:theme-duration-start */
105
129
  --duration-fast: 120ms;
@@ -109,6 +133,13 @@
109
133
  /* sh-ui:theme-ease-start */
110
134
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
111
135
  --ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
136
+ /* sh-ui:theme-tracking-start */
137
+ --tracking-tighter: -0.04em;
138
+ --tracking-tight: -0.02em;
139
+ --tracking-normal: 0;
140
+ --tracking-wide: 0.02em;
141
+ --tracking-wider: 0.04em;
142
+ /* sh-ui:theme-tracking-end */
112
143
  /* sh-ui:theme-ease-end */
113
144
  /* sh-ui:theme-control-start */
114
145
  --control-sm: 2rem;