@kood/claude-code 0.1.6 → 0.1.7
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/dist/index.js +21 -243
- package/package.json +1 -1
- package/templates/hono/CLAUDE.md +10 -6
- package/templates/hono/docs/deployment/index.md +5 -0
- package/templates/hono/docs/library/hono/index.md +6 -0
- package/templates/hono/docs/library/prisma/index.md +3 -0
- package/templates/npx/CLAUDE.md +8 -2
- package/templates/tanstack-start/CLAUDE.md +103 -255
- package/templates/tanstack-start/docs/deployment/cloudflare.md +37 -424
- package/templates/tanstack-start/docs/deployment/index.md +57 -286
- package/templates/tanstack-start/docs/deployment/nitro.md +36 -318
- package/templates/tanstack-start/docs/deployment/railway.md +40 -409
- package/templates/tanstack-start/docs/deployment/vercel.md +43 -465
- package/templates/tanstack-start/docs/design/accessibility.md +56 -326
- package/templates/tanstack-start/docs/design/color.md +37 -179
- package/templates/tanstack-start/docs/design/components.md +77 -311
- package/templates/tanstack-start/docs/design/index.md +24 -87
- package/templates/tanstack-start/docs/design/safe-area.md +51 -250
- package/templates/tanstack-start/docs/design/spacing.md +57 -276
- package/templates/tanstack-start/docs/design/tailwind-setup.md +45 -359
- package/templates/tanstack-start/docs/design/typography.md +40 -284
- package/templates/tanstack-start/docs/library/better-auth/2fa.md +27 -115
- package/templates/tanstack-start/docs/library/better-auth/advanced.md +22 -105
- package/templates/tanstack-start/docs/library/better-auth/index.md +17 -66
- package/templates/tanstack-start/docs/library/better-auth/plugins.md +11 -88
- package/templates/tanstack-start/docs/library/better-auth/session.md +12 -92
- package/templates/tanstack-start/docs/library/better-auth/setup.md +9 -91
- package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +30 -358
- package/templates/tanstack-start/docs/library/prisma/config.md +27 -327
- package/templates/tanstack-start/docs/library/prisma/crud.md +46 -174
- package/templates/tanstack-start/docs/library/prisma/index.md +23 -113
- package/templates/tanstack-start/docs/library/prisma/relations.md +31 -153
- package/templates/tanstack-start/docs/library/prisma/schema.md +40 -217
- package/templates/tanstack-start/docs/library/prisma/setup.md +12 -112
- package/templates/tanstack-start/docs/library/prisma/transactions.md +20 -110
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +12 -99
- package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +28 -107
- package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +44 -146
- package/templates/tanstack-start/docs/library/tanstack-query/setup.md +11 -70
- package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +33 -127
- package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +49 -149
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +19 -112
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +33 -80
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +28 -106
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +21 -118
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +34 -246
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +6 -39
- package/templates/tanstack-start/docs/library/zod/basic-types.md +33 -145
- package/templates/tanstack-start/docs/library/zod/complex-types.md +32 -156
- package/templates/tanstack-start/docs/library/zod/index.md +22 -150
- package/templates/tanstack-start/docs/library/zod/transforms.md +20 -129
- package/templates/tanstack-start/docs/library/zod/validation.md +39 -155
- package/templates/hono/docs/commands/git.md +0 -145
- package/templates/hono/docs/mcp/context7.md +0 -106
- package/templates/hono/docs/mcp/index.md +0 -176
- package/templates/hono/docs/mcp/sequential-thinking.md +0 -101
- package/templates/hono/docs/mcp/serena.md +0 -269
- package/templates/hono/docs/mcp/sgrep.md +0 -105
- package/templates/hono/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/hono/docs/skills/gemini-review/references/checklists.md +0 -136
- package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +0 -303
- package/templates/npx/docs/commands/git.md +0 -145
- package/templates/npx/docs/mcp/index.md +0 -60
- package/templates/npx/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/npx/docs/skills/gemini-review/references/checklists.md +0 -134
- package/templates/npx/docs/skills/gemini-review/references/prompt-templates.md +0 -301
- package/templates/tanstack-start/docs/commands/git.md +0 -145
- package/templates/tanstack-start/docs/mcp/context7.md +0 -204
- package/templates/tanstack-start/docs/mcp/index.md +0 -177
- package/templates/tanstack-start/docs/mcp/sequential-thinking.md +0 -180
- package/templates/tanstack-start/docs/mcp/serena.md +0 -269
- package/templates/tanstack-start/docs/mcp/sgrep.md +0 -174
- package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +0 -144
- package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +0 -292
|
@@ -1,262 +1,105 @@
|
|
|
1
1
|
# Tailwind CSS 설정
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Tailwind CSS v4
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## 기본 설정
|
|
8
|
-
|
|
9
|
-
### 설치
|
|
5
|
+
## 설치
|
|
10
6
|
|
|
11
7
|
```bash
|
|
12
8
|
yarn add tailwindcss postcss autoprefixer
|
|
13
9
|
```
|
|
14
10
|
|
|
15
|
-
### CSS 파일 설정
|
|
16
|
-
|
|
17
11
|
```css
|
|
18
12
|
/* src/styles/app.css */
|
|
19
13
|
@import "tailwindcss";
|
|
20
14
|
```
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
```js
|
|
25
|
-
// postcss.config.js
|
|
26
|
-
export default {
|
|
27
|
-
plugins: {
|
|
28
|
-
tailwindcss: {},
|
|
29
|
-
autoprefixer: {},
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## 디자인 토큰 정의
|
|
35
|
-
|
|
36
|
-
### @theme 디렉티브
|
|
37
|
-
|
|
38
|
-
Tailwind CSS v4에서는 `@theme` 디렉티브로 디자인 토큰을 정의합니다.
|
|
16
|
+
## 디자인 토큰 (@theme)
|
|
39
17
|
|
|
40
18
|
```css
|
|
41
|
-
/* src/styles/app.css */
|
|
42
19
|
@import "tailwindcss";
|
|
43
20
|
|
|
44
21
|
@theme {
|
|
45
|
-
/*
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
--color-primary-50: oklch(0.97 0.01 250);
|
|
51
|
-
--color-primary-100: oklch(0.93 0.03 250);
|
|
52
|
-
--color-primary-200: oklch(0.88 0.06 250);
|
|
53
|
-
--color-primary-300: oklch(0.78 0.1 250);
|
|
54
|
-
--color-primary-400: oklch(0.68 0.15 250);
|
|
55
|
-
--color-primary-500: oklch(0.55 0.2 250); /* 기본 */
|
|
56
|
-
--color-primary-600: oklch(0.48 0.22 250); /* hover */
|
|
57
|
-
--color-primary-700: oklch(0.42 0.2 250); /* active */
|
|
58
|
-
--color-primary-800: oklch(0.35 0.17 250);
|
|
59
|
-
--color-primary-900: oklch(0.28 0.12 250);
|
|
60
|
-
|
|
61
|
-
/* 의미론적 색상 */
|
|
22
|
+
/* 색상 */
|
|
23
|
+
--color-primary-500: oklch(0.55 0.2 250);
|
|
24
|
+
--color-primary-600: oklch(0.48 0.22 250);
|
|
25
|
+
--color-primary-700: oklch(0.42 0.2 250);
|
|
26
|
+
|
|
62
27
|
--color-success: oklch(0.55 0.15 145);
|
|
63
|
-
--color-success-light: oklch(0.92 0.05 145);
|
|
64
28
|
--color-error: oklch(0.55 0.2 25);
|
|
65
|
-
--color-error-light: oklch(0.92 0.05 25);
|
|
66
29
|
--color-warning: oklch(0.75 0.15 85);
|
|
67
|
-
--color-warning-light: oklch(0.95 0.05 85);
|
|
68
|
-
--color-info: oklch(0.55 0.2 250);
|
|
69
|
-
--color-info-light: oklch(0.92 0.05 250);
|
|
70
|
-
|
|
71
|
-
/* ========================================
|
|
72
|
-
* 타이포그래피
|
|
73
|
-
* ======================================== */
|
|
74
|
-
|
|
75
|
-
/* 폰트 패밀리 */
|
|
76
|
-
--font-sans: "Pretendard", "Inter", system-ui, -apple-system, sans-serif;
|
|
77
|
-
--font-mono: "JetBrains Mono", "Fira Code", Consolas, monospace;
|
|
78
30
|
|
|
79
|
-
/* 폰트
|
|
80
|
-
--font-
|
|
81
|
-
|
|
82
|
-
/* ========================================
|
|
83
|
-
* 간격 (선택적 커스텀)
|
|
84
|
-
* ======================================== */
|
|
85
|
-
|
|
86
|
-
--spacing-section: 4rem;
|
|
87
|
-
--spacing-page: 6rem;
|
|
88
|
-
|
|
89
|
-
/* ========================================
|
|
90
|
-
* 테두리 반경
|
|
91
|
-
* ======================================== */
|
|
31
|
+
/* 폰트 */
|
|
32
|
+
--font-sans: "Pretendard", "Inter", system-ui, sans-serif;
|
|
33
|
+
--font-mono: "JetBrains Mono", monospace;
|
|
92
34
|
|
|
35
|
+
/* 반경 */
|
|
93
36
|
--radius-button: 0.5rem;
|
|
94
37
|
--radius-card: 0.75rem;
|
|
95
38
|
--radius-modal: 1rem;
|
|
96
39
|
|
|
97
|
-
/*
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
--shadow-card: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
102
|
-
--shadow-dropdown: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
103
|
-
--shadow-modal: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
104
|
-
|
|
105
|
-
/* ========================================
|
|
106
|
-
* 애니메이션
|
|
107
|
-
* ======================================== */
|
|
108
|
-
|
|
109
|
-
--transition-fast: 150ms ease;
|
|
110
|
-
--transition-normal: 200ms ease;
|
|
111
|
-
--transition-slow: 300ms ease;
|
|
40
|
+
/* 그림자 */
|
|
41
|
+
--shadow-card: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
42
|
+
--shadow-modal: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
|
112
43
|
}
|
|
113
44
|
```
|
|
114
45
|
|
|
115
|
-
##
|
|
116
|
-
|
|
117
|
-
### 색상 토큰 사용
|
|
118
|
-
|
|
119
|
-
```tsx
|
|
120
|
-
// 브랜드 색상
|
|
121
|
-
<button className="bg-primary-600 hover:bg-primary-700 text-white">
|
|
122
|
-
주요 버튼
|
|
123
|
-
</button>
|
|
124
|
-
|
|
125
|
-
// 의미론적 색상
|
|
126
|
-
<div className="bg-success-light border border-success text-success">
|
|
127
|
-
성공 메시지
|
|
128
|
-
</div>
|
|
129
|
-
|
|
130
|
-
<div className="bg-error-light border border-error text-error">
|
|
131
|
-
오류 메시지
|
|
132
|
-
</div>
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### 폰트 토큰 사용
|
|
46
|
+
## 사용법
|
|
136
47
|
|
|
137
48
|
```tsx
|
|
138
|
-
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
// 코드
|
|
142
|
-
<code className="font-mono">JetBrains Mono 적용</code>
|
|
49
|
+
<button className="bg-primary-600 hover:bg-primary-700">버튼</button>
|
|
50
|
+
<div className="text-success">성공</div>
|
|
51
|
+
<div className="rounded-[--radius-card]">카드</div>
|
|
143
52
|
```
|
|
144
53
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
```tsx
|
|
148
|
-
// 섹션 간격
|
|
149
|
-
<section className="py-[--spacing-section]">
|
|
150
|
-
|
|
151
|
-
// 카드 반경
|
|
152
|
-
<div className="rounded-[--radius-card]">
|
|
153
|
-
|
|
154
|
-
// 모달 반경
|
|
155
|
-
<div className="rounded-[--radius-modal]">
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
## 다크 모드 설정
|
|
159
|
-
|
|
160
|
-
### 다크 모드 토큰
|
|
54
|
+
## 다크 모드
|
|
161
55
|
|
|
162
56
|
```css
|
|
163
57
|
@theme {
|
|
164
|
-
/* 라이트 모드 배경 */
|
|
165
58
|
--color-surface: white;
|
|
166
|
-
--color-surface-secondary: oklch(0.98 0 0);
|
|
167
|
-
|
|
168
|
-
/* 라이트 모드 텍스트 */
|
|
169
59
|
--color-text-primary: oklch(0.15 0 0);
|
|
170
|
-
--color-text-secondary: oklch(0.4 0 0);
|
|
171
|
-
--color-text-muted: oklch(0.6 0 0);
|
|
172
|
-
|
|
173
|
-
/* 라이트 모드 테두리 */
|
|
174
|
-
--color-border: oklch(0.9 0 0);
|
|
175
|
-
--color-border-strong: oklch(0.8 0 0);
|
|
176
60
|
}
|
|
177
61
|
|
|
178
|
-
/* 다크 모드 오버라이드 */
|
|
179
62
|
@media (prefers-color-scheme: dark) {
|
|
180
63
|
:root {
|
|
181
64
|
--color-surface: oklch(0.15 0 0);
|
|
182
|
-
--color-surface-secondary: oklch(0.2 0 0);
|
|
183
|
-
|
|
184
65
|
--color-text-primary: oklch(0.95 0 0);
|
|
185
|
-
--color-text-secondary: oklch(0.7 0 0);
|
|
186
|
-
--color-text-muted: oklch(0.5 0 0);
|
|
187
|
-
|
|
188
|
-
--color-border: oklch(0.3 0 0);
|
|
189
|
-
--color-border-strong: oklch(0.4 0 0);
|
|
190
66
|
}
|
|
191
67
|
}
|
|
192
68
|
```
|
|
193
69
|
|
|
194
|
-
### 다크 모드 클래스 사용
|
|
195
|
-
|
|
196
70
|
```tsx
|
|
197
|
-
// Tailwind
|
|
71
|
+
// Tailwind dark: 접두사
|
|
198
72
|
<div className="bg-white dark:bg-gray-900">
|
|
199
73
|
<h1 className="text-gray-900 dark:text-white">제목</h1>
|
|
200
|
-
<p className="text-gray-600 dark:text-gray-300">본문</p>
|
|
201
74
|
</div>
|
|
202
75
|
|
|
203
|
-
//
|
|
76
|
+
// CSS 변수 (자동 대응)
|
|
204
77
|
<div className="bg-[--color-surface] text-[--color-text-primary]">
|
|
205
|
-
자동으로 다크 모드 대응
|
|
206
|
-
</div>
|
|
207
78
|
```
|
|
208
79
|
|
|
209
|
-
|
|
80
|
+
## CVA (class-variance-authority)
|
|
210
81
|
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
import { useEffect, useState } from 'react'
|
|
214
|
-
|
|
215
|
-
export const ThemeToggle = () => {
|
|
216
|
-
const [theme, setTheme] = useState<'light' | 'dark'>('light')
|
|
217
|
-
|
|
218
|
-
useEffect(() => {
|
|
219
|
-
// 시스템 설정 확인
|
|
220
|
-
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
221
|
-
setTheme('dark')
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// localStorage 확인
|
|
225
|
-
const saved = localStorage.getItem('theme')
|
|
226
|
-
if (saved) setTheme(saved as 'light' | 'dark')
|
|
227
|
-
}, [])
|
|
228
|
-
|
|
229
|
-
useEffect(() => {
|
|
230
|
-
document.documentElement.classList.toggle('dark', theme === 'dark')
|
|
231
|
-
localStorage.setItem('theme', theme)
|
|
232
|
-
}, [theme])
|
|
233
|
-
|
|
234
|
-
return (
|
|
235
|
-
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
|
|
236
|
-
{theme === 'light' ? '🌙' : '☀️'}
|
|
237
|
-
</button>
|
|
238
|
-
)
|
|
239
|
-
}
|
|
82
|
+
```bash
|
|
83
|
+
yarn add class-variance-authority clsx tailwind-merge
|
|
240
84
|
```
|
|
241
85
|
|
|
242
|
-
## 컴포넌트 스타일 패턴
|
|
243
|
-
|
|
244
|
-
### 버튼 컴포넌트
|
|
245
|
-
|
|
246
86
|
```tsx
|
|
87
|
+
// src/lib/utils.ts
|
|
88
|
+
import { clsx, type ClassValue } from 'clsx'
|
|
89
|
+
import { twMerge } from 'tailwind-merge'
|
|
90
|
+
export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs))
|
|
91
|
+
|
|
247
92
|
// src/components/ui/button.tsx
|
|
248
93
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
249
94
|
|
|
250
95
|
const buttonVariants = cva(
|
|
251
|
-
|
|
252
|
-
'inline-flex items-center justify-center font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed',
|
|
96
|
+
'inline-flex items-center justify-center font-medium transition-colors focus:ring-2 disabled:opacity-50',
|
|
253
97
|
{
|
|
254
98
|
variants: {
|
|
255
99
|
variant: {
|
|
256
|
-
primary: 'bg-primary-600 text-white hover:bg-primary-700
|
|
257
|
-
secondary: 'border border-gray-300
|
|
258
|
-
|
|
259
|
-
destructive: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',
|
|
100
|
+
primary: 'bg-primary-600 text-white hover:bg-primary-700',
|
|
101
|
+
secondary: 'border border-gray-300 hover:bg-gray-50',
|
|
102
|
+
destructive: 'bg-red-600 text-white hover:bg-red-700',
|
|
260
103
|
},
|
|
261
104
|
size: {
|
|
262
105
|
sm: 'px-3 py-1.5 text-sm rounded-md',
|
|
@@ -264,207 +107,50 @@ const buttonVariants = cva(
|
|
|
264
107
|
lg: 'px-6 py-3 text-lg rounded-lg',
|
|
265
108
|
},
|
|
266
109
|
},
|
|
267
|
-
defaultVariants: {
|
|
268
|
-
variant: 'primary',
|
|
269
|
-
size: 'md',
|
|
270
|
-
},
|
|
110
|
+
defaultVariants: { variant: 'primary', size: 'md' },
|
|
271
111
|
}
|
|
272
112
|
)
|
|
273
113
|
|
|
274
|
-
interface ButtonProps
|
|
275
|
-
|
|
276
|
-
VariantProps<typeof buttonVariants> {}
|
|
277
|
-
|
|
278
|
-
export const Button = ({ variant, size, className, ...props }: ButtonProps) => {
|
|
279
|
-
return (
|
|
280
|
-
<button
|
|
281
|
-
className={buttonVariants({ variant, size, className })}
|
|
282
|
-
{...props}
|
|
283
|
-
/>
|
|
284
|
-
)
|
|
285
|
-
}
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
### 입력 필드 컴포넌트
|
|
114
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
115
|
+
VariantProps<typeof buttonVariants> {}
|
|
289
116
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
import { forwardRef } from 'react'
|
|
293
|
-
|
|
294
|
-
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
295
|
-
label?: string
|
|
296
|
-
error?: string
|
|
297
|
-
hint?: string
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
301
|
-
({ label, error, hint, className, id, ...props }, ref) => {
|
|
302
|
-
const inputId = id || label?.toLowerCase().replace(/\s/g, '-')
|
|
303
|
-
|
|
304
|
-
return (
|
|
305
|
-
<div>
|
|
306
|
-
{label && (
|
|
307
|
-
<label
|
|
308
|
-
htmlFor={inputId}
|
|
309
|
-
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
|
310
|
-
>
|
|
311
|
-
{label}
|
|
312
|
-
</label>
|
|
313
|
-
)}
|
|
314
|
-
<input
|
|
315
|
-
ref={ref}
|
|
316
|
-
id={inputId}
|
|
317
|
-
className={`
|
|
318
|
-
w-full px-3 py-2 border rounded-lg transition-colors
|
|
319
|
-
placeholder:text-gray-400
|
|
320
|
-
focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500
|
|
321
|
-
${error
|
|
322
|
-
? 'border-red-500 focus:ring-red-500 focus:border-red-500'
|
|
323
|
-
: 'border-gray-300 dark:border-gray-600'
|
|
324
|
-
}
|
|
325
|
-
${className}
|
|
326
|
-
`}
|
|
327
|
-
aria-invalid={!!error}
|
|
328
|
-
aria-describedby={error ? `${inputId}-error` : hint ? `${inputId}-hint` : undefined}
|
|
329
|
-
{...props}
|
|
330
|
-
/>
|
|
331
|
-
{error && (
|
|
332
|
-
<p id={`${inputId}-error`} className="mt-1 text-sm text-red-600" role="alert">
|
|
333
|
-
{error}
|
|
334
|
-
</p>
|
|
335
|
-
)}
|
|
336
|
-
{hint && !error && (
|
|
337
|
-
<p id={`${inputId}-hint`} className="mt-1 text-sm text-gray-500">
|
|
338
|
-
{hint}
|
|
339
|
-
</p>
|
|
340
|
-
)}
|
|
341
|
-
</div>
|
|
342
|
-
)
|
|
343
|
-
}
|
|
117
|
+
export const Button = ({ variant, size, className, ...props }: ButtonProps) => (
|
|
118
|
+
<button className={buttonVariants({ variant, size, className })} {...props} />
|
|
344
119
|
)
|
|
345
|
-
|
|
346
|
-
Input.displayName = 'Input'
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
## 유용한 유틸리티
|
|
350
|
-
|
|
351
|
-
### cn() 함수 (클래스 병합)
|
|
352
|
-
|
|
353
|
-
```bash
|
|
354
|
-
yarn add clsx tailwind-merge
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
```ts
|
|
358
|
-
// src/lib/utils.ts
|
|
359
|
-
import { clsx, type ClassValue } from 'clsx'
|
|
360
|
-
import { twMerge } from 'tailwind-merge'
|
|
361
|
-
|
|
362
|
-
export const cn = (...inputs: ClassValue[]) => {
|
|
363
|
-
return twMerge(clsx(inputs))
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
```tsx
|
|
368
|
-
// 사용 예시
|
|
369
|
-
import { cn } from '@/lib/utils'
|
|
370
|
-
|
|
371
|
-
<button
|
|
372
|
-
className={cn(
|
|
373
|
-
'px-4 py-2 rounded-lg',
|
|
374
|
-
isActive && 'bg-blue-600 text-white',
|
|
375
|
-
isDisabled && 'opacity-50 cursor-not-allowed',
|
|
376
|
-
className
|
|
377
|
-
)}
|
|
378
|
-
>
|
|
379
120
|
```
|
|
380
121
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
```bash
|
|
384
|
-
yarn add class-variance-authority
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
위의 버튼 컴포넌트 예시 참고.
|
|
388
|
-
|
|
389
|
-
## 반응형 디자인
|
|
390
|
-
|
|
391
|
-
### 브레이크포인트
|
|
122
|
+
## 반응형
|
|
392
123
|
|
|
393
124
|
```css
|
|
394
125
|
sm 640px 모바일 가로
|
|
395
126
|
md 768px 태블릿
|
|
396
127
|
lg 1024px 노트북
|
|
397
128
|
xl 1280px 데스크탑
|
|
398
|
-
2xl 1536px 대형 모니터
|
|
399
129
|
```
|
|
400
130
|
|
|
401
|
-
### 모바일 퍼스트
|
|
402
|
-
|
|
403
131
|
```tsx
|
|
404
|
-
|
|
405
|
-
<div className="
|
|
406
|
-
p-4 /* 기본: 모바일 */
|
|
407
|
-
md:p-6 /* 768px 이상 */
|
|
408
|
-
lg:p-8 /* 1024px 이상 */
|
|
409
|
-
">
|
|
410
|
-
|
|
411
|
-
// 그리드 반응형
|
|
412
|
-
<div className="
|
|
413
|
-
grid
|
|
414
|
-
grid-cols-1 /* 모바일: 1열 */
|
|
415
|
-
md:grid-cols-2 /* 태블릿: 2열 */
|
|
416
|
-
lg:grid-cols-3 /* 데스크탑: 3열 */
|
|
417
|
-
gap-4 md:gap-6
|
|
418
|
-
">
|
|
132
|
+
<div className="p-4 md:p-6 lg:p-8">
|
|
133
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6">
|
|
419
134
|
```
|
|
420
135
|
|
|
421
|
-
## 플러그인
|
|
422
|
-
|
|
423
|
-
### @tailwindcss/forms
|
|
424
|
-
|
|
425
|
-
폼 요소 기본 스타일링:
|
|
426
|
-
|
|
427
|
-
```bash
|
|
428
|
-
yarn add @tailwindcss/forms
|
|
429
|
-
```
|
|
136
|
+
## 플러그인
|
|
430
137
|
|
|
431
138
|
```css
|
|
432
139
|
@import "tailwindcss";
|
|
433
140
|
@plugin "@tailwindcss/forms";
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### @tailwindcss/typography
|
|
437
|
-
|
|
438
|
-
마크다운/리치 텍스트 스타일링:
|
|
439
|
-
|
|
440
|
-
```bash
|
|
441
|
-
yarn add @tailwindcss/typography
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
```css
|
|
445
|
-
@import "tailwindcss";
|
|
446
141
|
@plugin "@tailwindcss/typography";
|
|
447
142
|
```
|
|
448
143
|
|
|
449
144
|
```tsx
|
|
450
145
|
<article className="prose dark:prose-invert">
|
|
451
|
-
{/* 마크다운
|
|
146
|
+
{/* 마크다운 콘텐츠 */}
|
|
452
147
|
</article>
|
|
453
148
|
```
|
|
454
149
|
|
|
455
150
|
## 체크리스트
|
|
456
151
|
|
|
457
|
-
### 설정 시
|
|
458
|
-
|
|
459
152
|
- [ ] @theme으로 디자인 토큰 정의
|
|
460
|
-
- [ ]
|
|
461
|
-
- [ ] 의미론적 색상 정의
|
|
153
|
+
- [ ] 브랜드/의미론적 색상 설정
|
|
462
154
|
- [ ] 폰트 패밀리 설정
|
|
463
155
|
- [ ] 다크 모드 대응
|
|
464
|
-
|
|
465
|
-
### 개발 시
|
|
466
|
-
|
|
467
|
-
- [ ] 일관된 토큰 사용
|
|
468
156
|
- [ ] 모바일 퍼스트 반응형
|
|
469
|
-
- [ ] cn() 함수로 클래스 병합
|
|
470
|
-
- [ ] 접근성 고려 (포커스, 대비)
|