@kood/claude-code 0.1.7 → 0.1.10
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 +137 -3
- package/package.json +8 -2
- package/templates/hono/CLAUDE.md +53 -326
- package/templates/hono/docs/architecture/architecture.md +93 -747
- package/templates/hono/docs/deployment/cloudflare.md +59 -513
- package/templates/hono/docs/deployment/docker.md +41 -356
- package/templates/hono/docs/deployment/index.md +49 -190
- package/templates/hono/docs/deployment/railway.md +36 -306
- package/templates/hono/docs/deployment/vercel.md +49 -434
- package/templates/hono/docs/library/ai-sdk/index.md +53 -290
- package/templates/hono/docs/library/ai-sdk/openrouter.md +19 -387
- package/templates/hono/docs/library/ai-sdk/providers.md +28 -394
- package/templates/hono/docs/library/ai-sdk/streaming.md +52 -353
- package/templates/hono/docs/library/ai-sdk/structured-output.md +63 -395
- package/templates/hono/docs/library/ai-sdk/tools.md +62 -431
- package/templates/hono/docs/library/hono/env-setup.md +24 -313
- package/templates/hono/docs/library/hono/error-handling.md +34 -295
- package/templates/hono/docs/library/hono/index.md +24 -122
- package/templates/hono/docs/library/hono/middleware.md +21 -188
- package/templates/hono/docs/library/hono/rpc.md +40 -341
- package/templates/hono/docs/library/hono/validation.md +35 -195
- package/templates/hono/docs/library/pino/index.md +42 -333
- package/templates/hono/docs/library/prisma/cloudflare-d1.md +64 -367
- package/templates/hono/docs/library/prisma/config.md +19 -260
- package/templates/hono/docs/library/prisma/index.md +64 -320
- package/templates/hono/docs/library/zod/index.md +53 -257
- package/templates/npx/CLAUDE.md +58 -276
- package/templates/npx/docs/references/patterns.md +160 -0
- package/templates/tanstack-start/CLAUDE.md +0 -4
- package/templates/tanstack-start/docs/architecture/architecture.md +44 -589
- package/templates/tanstack-start/docs/design/index.md +119 -12
- package/templates/tanstack-start/docs/guides/conventions.md +103 -0
- package/templates/tanstack-start/docs/guides/env-setup.md +34 -340
- package/templates/tanstack-start/docs/guides/getting-started.md +22 -209
- package/templates/tanstack-start/docs/guides/hooks.md +166 -0
- package/templates/tanstack-start/docs/guides/routes.md +166 -0
- package/templates/tanstack-start/docs/guides/services.md +143 -0
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +18 -2
- package/templates/tanstack-start/docs/library/zod/index.md +16 -1
- package/templates/tanstack-start/docs/design/accessibility.md +0 -163
- package/templates/tanstack-start/docs/design/color.md +0 -93
- package/templates/tanstack-start/docs/design/spacing.md +0 -122
- package/templates/tanstack-start/docs/design/typography.md +0 -80
- package/templates/tanstack-start/docs/guides/best-practices.md +0 -950
- package/templates/tanstack-start/docs/guides/husky-lint-staged.md +0 -303
- package/templates/tanstack-start/docs/guides/prettier.md +0 -189
- package/templates/tanstack-start/docs/guides/project-templates.md +0 -710
- package/templates/tanstack-start/docs/library/tanstack-query/setup.md +0 -48
- package/templates/tanstack-start/docs/library/zod/basic-types.md +0 -74
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Service Layer
|
|
2
|
+
|
|
3
|
+
도메인별 SDK/서비스 레이어 구조.
|
|
4
|
+
|
|
5
|
+
## 폴더 구조
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
services/
|
|
9
|
+
├── user/
|
|
10
|
+
│ ├── index.ts # 진입점 (re-export)
|
|
11
|
+
│ ├── schemas.ts # Zod 스키마
|
|
12
|
+
│ ├── queries.ts # GET 요청 (읽기)
|
|
13
|
+
│ └── mutations.ts # POST 요청 (쓰기)
|
|
14
|
+
├── auth/
|
|
15
|
+
│ ├── index.ts
|
|
16
|
+
│ ├── schemas.ts
|
|
17
|
+
│ ├── queries.ts
|
|
18
|
+
│ └── mutations.ts
|
|
19
|
+
└── post/
|
|
20
|
+
├── index.ts
|
|
21
|
+
├── schemas.ts
|
|
22
|
+
├── queries.ts
|
|
23
|
+
└── mutations.ts
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Schemas 파일
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
// services/user/schemas.ts
|
|
30
|
+
import { z } from 'zod'
|
|
31
|
+
|
|
32
|
+
export const createUserSchema = z.object({
|
|
33
|
+
email: z.email(),
|
|
34
|
+
name: z.string().min(1).max(100).trim(),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
export const updateUserSchema = z.object({
|
|
38
|
+
id: z.string(),
|
|
39
|
+
email: z.email().optional(),
|
|
40
|
+
name: z.string().min(1).max(100).trim().optional(),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export type CreateUserInput = z.infer<typeof createUserSchema>
|
|
44
|
+
export type UpdateUserInput = z.infer<typeof updateUserSchema>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Queries 파일
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// services/user/queries.ts
|
|
51
|
+
import { createServerFn } from '@tanstack/react-start'
|
|
52
|
+
import { prisma } from '@/database/prisma'
|
|
53
|
+
|
|
54
|
+
export const getUsers = createServerFn({ method: 'GET' })
|
|
55
|
+
.handler(async () => {
|
|
56
|
+
return prisma.user.findMany({
|
|
57
|
+
orderBy: { createdAt: 'desc' },
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
export const getUserById = createServerFn({ method: 'GET' })
|
|
62
|
+
.handler(async ({ data: id }: { data: string }) => {
|
|
63
|
+
const user = await prisma.user.findUnique({ where: { id } })
|
|
64
|
+
if (!user) throw new Error('User not found')
|
|
65
|
+
return user
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
export const getUserByEmail = createServerFn({ method: 'GET' })
|
|
69
|
+
.handler(async ({ data: email }: { data: string }) => {
|
|
70
|
+
return prisma.user.findUnique({ where: { email } })
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Mutations 파일
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// services/user/mutations.ts
|
|
78
|
+
import { createServerFn } from '@tanstack/react-start'
|
|
79
|
+
import { prisma } from '@/database/prisma'
|
|
80
|
+
import { createUserSchema, updateUserSchema } from './schemas'
|
|
81
|
+
|
|
82
|
+
export const createUser = createServerFn({ method: 'POST' })
|
|
83
|
+
.inputValidator(createUserSchema)
|
|
84
|
+
.handler(async ({ data }) => {
|
|
85
|
+
return prisma.user.create({ data })
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
export const updateUser = createServerFn({ method: 'POST' })
|
|
89
|
+
.inputValidator(updateUserSchema)
|
|
90
|
+
.handler(async ({ data }) => {
|
|
91
|
+
const { id, ...updateData } = data
|
|
92
|
+
return prisma.user.update({ where: { id }, data: updateData })
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
export const deleteUser = createServerFn({ method: 'POST' })
|
|
96
|
+
.handler(async ({ data: id }: { data: string }) => {
|
|
97
|
+
return prisma.user.delete({ where: { id } })
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 진입점 파일
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// services/user/index.ts
|
|
105
|
+
export * from './schemas'
|
|
106
|
+
export * from './queries'
|
|
107
|
+
export * from './mutations'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 사용 예시
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// routes/users/-hooks/use-users.ts
|
|
114
|
+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
115
|
+
import { getUsers, createUser, deleteUser } from '@/services/user'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Database 폴더
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
database/
|
|
122
|
+
├── prisma.ts # Prisma Client 싱글톤
|
|
123
|
+
└── seed.ts # 시드 스크립트 (선택)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// database/prisma.ts
|
|
128
|
+
import { PrismaClient } from '../../generated/prisma'
|
|
129
|
+
|
|
130
|
+
const globalForPrisma = globalThis as unknown as {
|
|
131
|
+
prisma: PrismaClient | undefined
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const prisma =
|
|
135
|
+
globalForPrisma.prisma ??
|
|
136
|
+
new PrismaClient({
|
|
137
|
+
log: process.env.NODE_ENV === 'development' ? ['query'] : [],
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
141
|
+
globalForPrisma.prisma = prisma
|
|
142
|
+
}
|
|
143
|
+
```
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
> 5.x | React Data Fetching Library
|
|
4
4
|
|
|
5
|
-
@setup.md
|
|
6
5
|
@use-query.md
|
|
7
6
|
@use-mutation.md
|
|
8
7
|
@invalidation.md
|
|
@@ -47,7 +46,15 @@ const mutation = useMutation({
|
|
|
47
46
|
```tsx
|
|
48
47
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
49
48
|
|
|
50
|
-
const queryClient = new QueryClient(
|
|
49
|
+
const queryClient = new QueryClient({
|
|
50
|
+
defaultOptions: {
|
|
51
|
+
queries: {
|
|
52
|
+
staleTime: 1000 * 60 * 5, // 5분
|
|
53
|
+
gcTime: 1000 * 60 * 30, // 30분 (이전 cacheTime)
|
|
54
|
+
retry: 3,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
})
|
|
51
58
|
|
|
52
59
|
function App() {
|
|
53
60
|
return (
|
|
@@ -57,3 +64,12 @@ function App() {
|
|
|
57
64
|
)
|
|
58
65
|
}
|
|
59
66
|
```
|
|
67
|
+
|
|
68
|
+
### Query Keys 패턴
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
['todos'] // 단순
|
|
72
|
+
['todo', { id: 5 }] // 파라미터
|
|
73
|
+
['todos', 'list', { filters }] // 계층적
|
|
74
|
+
['todos', 'detail', todoId]
|
|
75
|
+
```
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
> **v4** | TypeScript Schema Validation
|
|
4
4
|
|
|
5
|
-
@basic-types.md
|
|
6
5
|
@complex-types.md
|
|
7
6
|
@transforms.md
|
|
8
7
|
@validation.md
|
|
@@ -56,3 +55,19 @@ z.looseObject({ name: z.string() }) // 추가 키 통과
|
|
|
56
55
|
// Refinement 체이닝 가능
|
|
57
56
|
z.string().refine(val => val.includes("@")).min(5) // ✅ v4
|
|
58
57
|
```
|
|
58
|
+
|
|
59
|
+
### v4 추가 API
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// 문자열 불리언 (환경변수용)
|
|
63
|
+
z.stringbool() // "true"/"yes"/"1" → true
|
|
64
|
+
|
|
65
|
+
// 날짜/시간 ISO 포맷
|
|
66
|
+
z.iso.date() // 2024-01-15
|
|
67
|
+
z.iso.datetime() // ISO 날짜시간
|
|
68
|
+
z.iso.duration() // P1D, PT1H
|
|
69
|
+
|
|
70
|
+
// 템플릿 리터럴
|
|
71
|
+
const css = z.templateLiteral([z.number(), z.enum(["px", "em", "rem"])])
|
|
72
|
+
// `${number}px` | `${number}em` | `${number}rem`
|
|
73
|
+
```
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
# 접근성 (Accessibility)
|
|
2
|
-
|
|
3
|
-
## WCAG 기준
|
|
4
|
-
|
|
5
|
-
| 레벨 | 설명 |
|
|
6
|
-
|------|------|
|
|
7
|
-
| A | 최소 기준 (필수) |
|
|
8
|
-
| AA | 권장 기준 (일반 목표) |
|
|
9
|
-
| AAA | 최고 기준 |
|
|
10
|
-
|
|
11
|
-
## 색상 대비
|
|
12
|
-
|
|
13
|
-
| 기준 | 대비 | 대상 |
|
|
14
|
-
|------|------|------|
|
|
15
|
-
| AA | 4.5:1 | 일반 텍스트 |
|
|
16
|
-
| AA (큰 텍스트) | 3:1 | 18px 이상 |
|
|
17
|
-
| AAA | 7:1 | 최고 접근성 |
|
|
18
|
-
|
|
19
|
-
```tsx
|
|
20
|
-
// ❌ 색상만으로 구분
|
|
21
|
-
<span className="text-red-600">오류</span>
|
|
22
|
-
|
|
23
|
-
// ✅ 아이콘/텍스트 병행
|
|
24
|
-
<span className="text-red-600 flex items-center gap-1">
|
|
25
|
-
<XCircleIcon className="w-4 h-4" />
|
|
26
|
-
오류가 발생했습니다
|
|
27
|
-
</span>
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## 키보드 접근성
|
|
31
|
-
|
|
32
|
-
| 키 | 동작 |
|
|
33
|
-
|-----|------|
|
|
34
|
-
| Tab | 다음 요소 |
|
|
35
|
-
| Shift+Tab | 이전 요소 |
|
|
36
|
-
| Enter | 클릭, 링크 이동 |
|
|
37
|
-
| Space | 체크박스, 버튼 |
|
|
38
|
-
| Escape | 모달 닫기 |
|
|
39
|
-
|
|
40
|
-
```tsx
|
|
41
|
-
// ✅ 명확한 포커스 스타일
|
|
42
|
-
<button className="focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
|
43
|
-
|
|
44
|
-
// ❌ 포커스 제거 금지
|
|
45
|
-
<button className="outline-none focus:outline-none">
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## 시맨틱 HTML
|
|
49
|
-
|
|
50
|
-
```tsx
|
|
51
|
-
// ✅ 시맨틱 HTML
|
|
52
|
-
<header>...</header>
|
|
53
|
-
<nav>...</nav>
|
|
54
|
-
<main><article><section>...</section></article></main>
|
|
55
|
-
<footer>...</footer>
|
|
56
|
-
|
|
57
|
-
// ❌ div 남용
|
|
58
|
-
<div className="header">...</div>
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### 제목 계층
|
|
62
|
-
```tsx
|
|
63
|
-
// ✅ 순서대로
|
|
64
|
-
<h1>페이지 제목</h1>
|
|
65
|
-
<h2>섹션 1</h2>
|
|
66
|
-
<h3>하위 섹션</h3>
|
|
67
|
-
|
|
68
|
-
// ❌ 건너뛰기 금지
|
|
69
|
-
<h1>제목</h1>
|
|
70
|
-
<h3>섹션</h3>
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## ARIA 속성
|
|
74
|
-
|
|
75
|
-
```tsx
|
|
76
|
-
// 레이블 연결
|
|
77
|
-
<label htmlFor="email">이메일</label>
|
|
78
|
-
<input id="email" type="email" />
|
|
79
|
-
|
|
80
|
-
// aria-label
|
|
81
|
-
<input aria-label="검색어 입력" type="search" />
|
|
82
|
-
|
|
83
|
-
// 에러 상태
|
|
84
|
-
<input aria-invalid="true" aria-describedby="email-error" />
|
|
85
|
-
<p id="email-error" role="alert">오류 메시지</p>
|
|
86
|
-
|
|
87
|
-
// 동적 알림
|
|
88
|
-
<div aria-live="polite">{message}</div>
|
|
89
|
-
|
|
90
|
-
// 숨김 처리 (스크린 리더만)
|
|
91
|
-
<span className="sr-only">메뉴 열기</span>
|
|
92
|
-
|
|
93
|
-
// 장식용 숨김
|
|
94
|
-
<div aria-hidden="true">장식용 아이콘</div>
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## 폼 접근성
|
|
98
|
-
|
|
99
|
-
```tsx
|
|
100
|
-
<div>
|
|
101
|
-
<label htmlFor="email">
|
|
102
|
-
이메일 <span className="text-red-600" aria-hidden="true">*</span>
|
|
103
|
-
<span className="sr-only">(필수)</span>
|
|
104
|
-
</label>
|
|
105
|
-
<input
|
|
106
|
-
id="email"
|
|
107
|
-
required
|
|
108
|
-
aria-required="true"
|
|
109
|
-
aria-invalid={hasError}
|
|
110
|
-
aria-describedby={hasError ? "email-error" : undefined}
|
|
111
|
-
/>
|
|
112
|
-
{hasError && <p id="email-error" role="alert">오류 메시지</p>}
|
|
113
|
-
</div>
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## 이미지 대체 텍스트
|
|
117
|
-
|
|
118
|
-
```tsx
|
|
119
|
-
// 정보 전달 이미지
|
|
120
|
-
<img src="chart.png" alt="2024년 매출: 1월 100만원에서 12월 500만원으로 성장" />
|
|
121
|
-
|
|
122
|
-
// 장식용
|
|
123
|
-
<img src="decorative.png" alt="" />
|
|
124
|
-
|
|
125
|
-
// 아이콘 버튼
|
|
126
|
-
<button aria-label="닫기">
|
|
127
|
-
<img src="close.svg" alt="" />
|
|
128
|
-
</button>
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## 터치 접근성
|
|
132
|
-
|
|
133
|
-
```tsx
|
|
134
|
-
// 최소 44x44px
|
|
135
|
-
<button className="min-w-[44px] min-h-[44px] p-2">
|
|
136
|
-
<Icon className="w-6 h-6" />
|
|
137
|
-
</button>
|
|
138
|
-
|
|
139
|
-
// 터치 타겟 간격 8px 이상
|
|
140
|
-
<div className="flex gap-2">
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## 테스트 도구
|
|
144
|
-
|
|
145
|
-
| 도구 | 용도 |
|
|
146
|
-
|------|------|
|
|
147
|
-
| axe DevTools | 브라우저 확장 |
|
|
148
|
-
| Lighthouse | Chrome 내장 |
|
|
149
|
-
| eslint-plugin-jsx-a11y | 코드 레벨 검사 |
|
|
150
|
-
|
|
151
|
-
## 체크리스트
|
|
152
|
-
|
|
153
|
-
### 필수 (Level A)
|
|
154
|
-
- [ ] 모든 이미지에 alt
|
|
155
|
-
- [ ] 폼 요소에 레이블
|
|
156
|
-
- [ ] 키보드 접근 가능
|
|
157
|
-
- [ ] 포커스 표시 유지
|
|
158
|
-
- [ ] 색상만으로 정보 전달 금지
|
|
159
|
-
|
|
160
|
-
### 권장 (Level AA)
|
|
161
|
-
- [ ] 대비 4.5:1 이상
|
|
162
|
-
- [ ] 제목 계층 논리적
|
|
163
|
-
- [ ] 200% 확대 시 가로 스크롤 없음
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# 색상 시스템
|
|
2
|
-
|
|
3
|
-
## 60-30-10 규칙
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
60% 기본색 - 배경, 여백
|
|
7
|
-
30% 보조색 - 카드, 섹션
|
|
8
|
-
10% 강조색 - 버튼, 링크, CTA
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## 색상 팔레트
|
|
12
|
-
|
|
13
|
-
### 기본색 (Neutral)
|
|
14
|
-
```
|
|
15
|
-
bg-white 가장 밝은 배경
|
|
16
|
-
bg-gray-50 섹션 배경
|
|
17
|
-
bg-gray-100 카드 배경, hover
|
|
18
|
-
bg-gray-200 테두리, 구분선
|
|
19
|
-
text-gray-500 보조 텍스트
|
|
20
|
-
text-gray-700 본문
|
|
21
|
-
text-gray-900 제목, 강조
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### 의미론적 색상
|
|
25
|
-
|
|
26
|
-
| 색상 | 의미 | Tailwind |
|
|
27
|
-
|------|------|----------|
|
|
28
|
-
| 🟢 Green | 성공, 완료 | `text-green-600` |
|
|
29
|
-
| 🔴 Red | 오류, 위험 | `text-red-600` |
|
|
30
|
-
| 🟡 Yellow | 경고, 주의 | `text-yellow-600` |
|
|
31
|
-
| 🔵 Blue | 정보, 안내 | `text-blue-600` |
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
// ✅ 올바른 사용
|
|
35
|
-
<span className="text-green-600">저장되었습니다</span>
|
|
36
|
-
<span className="text-red-600">필수 항목입니다</span>
|
|
37
|
-
|
|
38
|
-
// ❌ 잘못된 사용 - 빨간색을 장식용으로
|
|
39
|
-
<span className="text-red-600">새로운 기능!</span>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## 색상 대비 (WCAG)
|
|
43
|
-
|
|
44
|
-
| 기준 | 최소 대비 | 적용 대상 |
|
|
45
|
-
|------|----------|----------|
|
|
46
|
-
| AA | 4.5:1 | 일반 텍스트 |
|
|
47
|
-
| AA (큰 텍스트) | 3:1 | 18px 이상 |
|
|
48
|
-
| AAA | 7:1 | 최고 접근성 |
|
|
49
|
-
|
|
50
|
-
```tsx
|
|
51
|
-
// ✅ 좋은 대비
|
|
52
|
-
<p className="text-gray-900">대비 15.8:1</p>
|
|
53
|
-
<p className="text-gray-700">대비 8.6:1</p>
|
|
54
|
-
|
|
55
|
-
// ❌ 피해야 함
|
|
56
|
-
<p className="text-gray-400">대비 3.0:1</p>
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## 다크 모드
|
|
60
|
-
|
|
61
|
-
```
|
|
62
|
-
라이트 다크
|
|
63
|
-
bg-white ←→ bg-gray-900
|
|
64
|
-
bg-gray-50 ←→ bg-gray-800
|
|
65
|
-
text-gray-900 ←→ text-white
|
|
66
|
-
text-gray-600 ←→ text-gray-300
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
```tsx
|
|
70
|
-
<div className="bg-white dark:bg-gray-900">
|
|
71
|
-
<h1 className="text-gray-900 dark:text-white">제목</h1>
|
|
72
|
-
<p className="text-gray-600 dark:text-gray-300">본문</p>
|
|
73
|
-
</div>
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Tailwind 설정
|
|
77
|
-
|
|
78
|
-
```css
|
|
79
|
-
@theme {
|
|
80
|
-
--color-primary-500: oklch(0.55 0.2 250);
|
|
81
|
-
--color-primary-600: oklch(0.48 0.22 250);
|
|
82
|
-
--color-success: oklch(0.55 0.15 145);
|
|
83
|
-
--color-error: oklch(0.55 0.2 25);
|
|
84
|
-
--color-warning: oklch(0.75 0.15 85);
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## 체크리스트
|
|
89
|
-
|
|
90
|
-
- [ ] 브랜드 색상 1-2가지만
|
|
91
|
-
- [ ] 의미론적 색상은 해당 의미로만
|
|
92
|
-
- [ ] 대비 4.5:1 이상
|
|
93
|
-
- [ ] 색상만으로 정보 전달 금지 (아이콘/텍스트 병행)
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# 간격과 레이아웃
|
|
2
|
-
|
|
3
|
-
## 8px 그리드
|
|
4
|
-
|
|
5
|
-
```css
|
|
6
|
-
1 → 4px 아주 작은 간격
|
|
7
|
-
2 → 8px 작은 간격
|
|
8
|
-
4 → 16px 기본 간격
|
|
9
|
-
6 → 24px 중간 간격
|
|
10
|
-
8 → 32px 큰 간격
|
|
11
|
-
12 → 48px 섹션 간격
|
|
12
|
-
16 → 64px 페이지 섹션
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
| 용도 | Tailwind | 크기 |
|
|
16
|
-
|------|----------|------|
|
|
17
|
-
| 아이콘-텍스트 | gap-1 | 4px |
|
|
18
|
-
| 인라인 요소 | gap-2 | 8px |
|
|
19
|
-
| 카드 내부 | p-4 | 16px |
|
|
20
|
-
| 카드 간격 | gap-6 | 24px |
|
|
21
|
-
| 섹션 간격 | py-12 | 48px |
|
|
22
|
-
|
|
23
|
-
## Padding vs Margin vs Gap
|
|
24
|
-
|
|
25
|
-
```tsx
|
|
26
|
-
// Padding (내부 여백)
|
|
27
|
-
<div className="p-4"> {/* 전체 16px */}
|
|
28
|
-
<div className="px-4 py-2"> {/* 좌우 16px, 상하 8px */}
|
|
29
|
-
|
|
30
|
-
// Margin (외부 여백)
|
|
31
|
-
<div className="mb-4"> {/* 아래 16px */}
|
|
32
|
-
<div className="mx-auto"> {/* 좌우 중앙 */}
|
|
33
|
-
|
|
34
|
-
// Gap (Flex/Grid 간격)
|
|
35
|
-
<div className="flex gap-4">
|
|
36
|
-
<div className="grid gap-6">
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## 레이아웃 패턴
|
|
40
|
-
|
|
41
|
-
### 카드
|
|
42
|
-
```tsx
|
|
43
|
-
<div className="p-6 rounded-lg border">
|
|
44
|
-
<h3 className="text-lg font-semibold mb-2">제목</h3>
|
|
45
|
-
<p className="text-gray-600 mb-4">본문</p>
|
|
46
|
-
<div className="flex gap-2">
|
|
47
|
-
<button>취소</button>
|
|
48
|
-
<button>확인</button>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### 폼
|
|
54
|
-
```tsx
|
|
55
|
-
<form className="space-y-6">
|
|
56
|
-
<div className="space-y-4">
|
|
57
|
-
<div>
|
|
58
|
-
<label className="block text-sm font-medium mb-1">이름</label>
|
|
59
|
-
<input className="w-full px-3 py-2 border rounded" />
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
<div className="flex justify-end gap-3">
|
|
63
|
-
<button>취소</button>
|
|
64
|
-
<button className="bg-blue-600 text-white">저장</button>
|
|
65
|
-
</div>
|
|
66
|
-
</form>
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### 네비게이션
|
|
70
|
-
```tsx
|
|
71
|
-
<nav className="px-4 py-3 border-b">
|
|
72
|
-
<div className="max-w-6xl mx-auto flex items-center justify-between">
|
|
73
|
-
<div>Logo</div>
|
|
74
|
-
<div className="flex items-center gap-6">{/* 메뉴 */}</div>
|
|
75
|
-
<div className="flex items-center gap-3">{/* 액션 */}</div>
|
|
76
|
-
</div>
|
|
77
|
-
</nav>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## 반응형 간격
|
|
81
|
-
|
|
82
|
-
```tsx
|
|
83
|
-
<section className="py-8 md:py-12 lg:py-16">
|
|
84
|
-
<div className="px-4 md:px-6 lg:px-8">
|
|
85
|
-
<div className="grid gap-4 md:gap-6 lg:gap-8">
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## 시각적 그룹핑
|
|
89
|
-
|
|
90
|
-
```tsx
|
|
91
|
-
// ✅ 관련 요소 가깝게, 다른 그룹 멀리
|
|
92
|
-
<div className="mb-6">
|
|
93
|
-
<h3 className="mb-2">제목</h3> {/* 밀접: 8px */}
|
|
94
|
-
<p>설명</p>
|
|
95
|
-
</div> {/* 분리: 24px */}
|
|
96
|
-
<div className="mb-6">
|
|
97
|
-
<h3 className="mb-2">다른 제목</h3>
|
|
98
|
-
<p>다른 설명</p>
|
|
99
|
-
</div>
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## 컨테이너
|
|
103
|
-
|
|
104
|
-
```tsx
|
|
105
|
-
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> {/* 기본 */}
|
|
106
|
-
<div className="max-w-3xl mx-auto px-4"> {/* 좁은 (블로그) */}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
```css
|
|
110
|
-
max-w-md 448px 폼
|
|
111
|
-
max-w-lg 512px 모달
|
|
112
|
-
max-w-3xl 768px 블로그
|
|
113
|
-
max-w-5xl 1024px 표준
|
|
114
|
-
max-w-7xl 1280px 대시보드
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## 체크리스트
|
|
118
|
-
|
|
119
|
-
- [ ] 8px 배수 사용
|
|
120
|
-
- [ ] 관련 요소 가깝게, 다른 그룹 멀리
|
|
121
|
-
- [ ] 반응형 간격 적용
|
|
122
|
-
- [ ] 터치 영역 최소 44px
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# 타이포그래피
|
|
2
|
-
|
|
3
|
-
## 기본 원칙
|
|
4
|
-
- 폰트 2-3개만 (제목용, 본문용, 코드용)
|
|
5
|
-
- 크기로 계층 표현
|
|
6
|
-
- 일관된 스타일
|
|
7
|
-
|
|
8
|
-
## 폰트 선택
|
|
9
|
-
|
|
10
|
-
| 폰트 | 용도 |
|
|
11
|
-
|------|------|
|
|
12
|
-
| Pretendard | 한글 프로젝트 (권장) |
|
|
13
|
-
| Inter | 영문, 웹 전반 |
|
|
14
|
-
| Noto Sans KR | 다국어 프로젝트 |
|
|
15
|
-
| JetBrains Mono | 코드 |
|
|
16
|
-
|
|
17
|
-
## 크기 시스템
|
|
18
|
-
|
|
19
|
-
```css
|
|
20
|
-
text-xs 12px 작은 레이블
|
|
21
|
-
text-sm 14px 보조 텍스트
|
|
22
|
-
text-base 16px 본문 (기본)
|
|
23
|
-
text-lg 18px 강조 본문
|
|
24
|
-
text-xl 20px 소제목 (h4)
|
|
25
|
-
text-2xl 24px 섹션 제목 (h3)
|
|
26
|
-
text-3xl 30px 부제목 (h2)
|
|
27
|
-
text-4xl 36px 페이지 제목 (h1)
|
|
28
|
-
text-5xl 48px 히어로
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
```tsx
|
|
32
|
-
<h1 className="text-4xl font-bold">제목</h1>
|
|
33
|
-
<h2 className="text-2xl font-semibold">섹션</h2>
|
|
34
|
-
<p className="text-base">본문</p>
|
|
35
|
-
<span className="text-sm text-gray-500">보조</span>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## 줄 간격 (Line Height)
|
|
39
|
-
|
|
40
|
-
```css
|
|
41
|
-
leading-tight 1.25 제목
|
|
42
|
-
leading-normal 1.5 본문 (권장)
|
|
43
|
-
leading-relaxed 1.625 긴 글
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## 굵기 (Font Weight)
|
|
47
|
-
|
|
48
|
-
```css
|
|
49
|
-
font-normal 400 본문
|
|
50
|
-
font-medium 500 약간 강조
|
|
51
|
-
font-semibold 600 부제목, 버튼
|
|
52
|
-
font-bold 700 제목
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## 가독성 최적화
|
|
56
|
-
|
|
57
|
-
```tsx
|
|
58
|
-
// 줄 길이 제한 (45-75자)
|
|
59
|
-
<article className="max-w-prose mx-auto">
|
|
60
|
-
|
|
61
|
-
// 글자 간격
|
|
62
|
-
<h1 className="text-5xl tracking-tight">히어로</h1>
|
|
63
|
-
<span className="text-xs tracking-wide uppercase">LABEL</span>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Tailwind 폰트 설정
|
|
67
|
-
|
|
68
|
-
```css
|
|
69
|
-
@theme {
|
|
70
|
-
--font-sans: "Pretendard", "Inter", system-ui, sans-serif;
|
|
71
|
-
--font-mono: "JetBrains Mono", monospace;
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## 체크리스트
|
|
76
|
-
|
|
77
|
-
- [ ] 폰트 2-3개 이하
|
|
78
|
-
- [ ] 본문 16px 이상
|
|
79
|
-
- [ ] 줄 간격 1.5 이상
|
|
80
|
-
- [ ] 제목/본문 명확한 크기 차이
|