@kood/claude-code 0.3.12 → 0.3.15
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 +30 -8
- package/package.json +4 -4
- package/templates/.claude/skills/korea-uiux-design/SKILL.md +444 -0
- package/templates/.claude/skills/korea-uiux-design/references/accessibility.md +298 -0
- package/templates/.claude/skills/korea-uiux-design/references/checklist.md +107 -0
- package/templates/.claude/skills/korea-uiux-design/references/color-system.md +156 -0
- package/templates/.claude/skills/korea-uiux-design/references/design-philosophy.md +25 -0
- package/templates/.claude/skills/korea-uiux-design/references/icon-guide.md +180 -0
- package/templates/.claude/skills/korea-uiux-design/references/micro-interactions.md +259 -0
- package/templates/.claude/skills/korea-uiux-design/references/responsive-patterns.md +115 -0
- package/templates/.claude/skills/korea-uiux-design/references/service-patterns.md +206 -0
- package/templates/.claude/skills/korea-uiux-design/references/state-patterns.md +320 -0
- package/templates/.claude/skills/korea-uiux-design/references/typography.md +70 -0
- package/templates/.claude/skills/nextjs-react-best-practices/AGENTS.md +663 -0
- package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +269 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +751 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +431 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-defer-await.md +80 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-dependencies.md +36 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-loader.md +44 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/async-parallel.md +28 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-conditional.md +31 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-lazy-routes.md +67 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-preload.md +50 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-event-listeners.md +74 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-tanstack-query.md +77 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-cache-storage.md +70 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-early-exit.md +50 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-index-maps.md +37 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-length-check-first.md +49 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-memo.md +44 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-transitions.md +40 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-cache-lru.md +41 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +67 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-parallel-fetching.md +60 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +38 -0
- package/templates/.claude/skills/vercel-react-best-practices/AGENTS.md +0 -2249
- package/templates/.claude/skills/vercel-react-best-practices/SKILL.md +0 -125
- package/templates/.claude/skills/vs-design-diverge/SKILL.md +0 -307
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/advanced-event-handler-refs.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/advanced-use-latest.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-api-routes.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-defer-await.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-dependencies.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-parallel.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/async-suspense-boundaries.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-barrel-imports.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-conditional.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-defer-third-party.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-dynamic-imports.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/bundle-preload.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/client-event-listeners.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/client-swr-dedup.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-batch-dom-css.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-cache-function-results.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-cache-property-access.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-cache-storage.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-combine-iterations.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-early-exit.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-hoist-regexp.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-index-maps.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-length-check-first.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-min-max-loop.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-set-map-lookups.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/js-tosorted-immutable.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-activity.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-animate-svg-wrapper.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-conditional-render.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-content-visibility.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-hoist-jsx.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-hydration-no-flicker.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rendering-svg-precision.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-defer-reads.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-dependencies.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-derived-state.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-functional-setstate.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-lazy-state-init.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-memo.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/rerender-transitions.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-after-nonblocking.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-cache-lru.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-cache-react.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-parallel-fetching.md +0 -0
- /package/templates/.claude/skills/{vercel-react-best-practices → nextjs-react-best-practices}/rules/server-serialization.md +0 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# 주요 서비스 패턴
|
|
2
|
+
|
|
3
|
+
<toss>
|
|
4
|
+
|
|
5
|
+
**산업:** 핀테크 | **키워드:** 신뢰, 명확성, 미니멀리즘
|
|
6
|
+
|
|
7
|
+
| 요소 | 내용 |
|
|
8
|
+
|------|------|
|
|
9
|
+
| **Primary** | Blue #3182F6 (신뢰감, 안정감) |
|
|
10
|
+
| **Secondary** | Gray (정보 위계 명확) |
|
|
11
|
+
| **폰트** | Pretendard, Spoqa Han Sans |
|
|
12
|
+
| **특징** | 단순 명확, 강한 파란색, 카드 중심, 흰색/밝은 회색 배경 |
|
|
13
|
+
| **UX 라이팅** | "어떤 이름으로 불러드릴까요?", "잠깐, 문제가 생겼어요" |
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
{/* 금액 강조 */}
|
|
17
|
+
<div className="text-4xl font-bold">15,000원</div>
|
|
18
|
+
<div className="text-sm text-gray-600 mt-1">이번 달 총 지출</div>
|
|
19
|
+
|
|
20
|
+
{/* 카드 */}
|
|
21
|
+
<div className="p-6 bg-white rounded-2xl border">
|
|
22
|
+
<h2 className="text-lg font-semibold mb-4">내 자산</h2>
|
|
23
|
+
<div className="text-3xl font-bold">1,250,000원</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
{/* 버튼 */}
|
|
27
|
+
<button className="w-full h-14 bg-primary-500 text-white rounded-xl">다음</button>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
</toss>
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
<kakao>
|
|
35
|
+
|
|
36
|
+
**산업:** 메신저 | **키워드:** 친근함, 노란색, 말풍선
|
|
37
|
+
|
|
38
|
+
| 요소 | 내용 |
|
|
39
|
+
|------|------|
|
|
40
|
+
| **Primary** | Yellow #FEE500 (친근, 밝음) |
|
|
41
|
+
| **Secondary** | Brown #3C1E1E (안정감) |
|
|
42
|
+
| **특징** | 말풍선 모티브, 노란색 브랜드, radius 12px |
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
{/* 로그인 버튼 (디자인 가이드) */}
|
|
46
|
+
<button className="w-full h-12 bg-[#FEE500] rounded-xl flex items-center justify-center gap-2">
|
|
47
|
+
<img src="/kakao-symbol.svg" className="w-5 h-5" />
|
|
48
|
+
<span className="text-[#000000]/85 text-[15px] font-medium">카카오 로그인</span>
|
|
49
|
+
</button>
|
|
50
|
+
|
|
51
|
+
{/* 말풍선 */}
|
|
52
|
+
<div className="relative p-4 bg-yellow-400 rounded-2xl rounded-tl-none">
|
|
53
|
+
<div className="absolute -top-2 left-0 w-4 h-4 bg-yellow-400 rounded-br-full" />
|
|
54
|
+
<p>메시지</p>
|
|
55
|
+
</div>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**규칙:** 말풍선 심볼 필수 (형태/비율/색상 변경 불가), radius 12px, 폰트 15pt
|
|
59
|
+
|
|
60
|
+
</kakao>
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
<baemin>
|
|
65
|
+
|
|
66
|
+
**산업:** 음식 배달 | **키워드:** 감성, 손글씨, 일러스트
|
|
67
|
+
|
|
68
|
+
| 요소 | 내용 |
|
|
69
|
+
|------|------|
|
|
70
|
+
| **Primary** | Teal #2AC1BC (신선, 활기) |
|
|
71
|
+
| **Secondary** | Coral/Pink (따뜻함) |
|
|
72
|
+
| **폰트** | 배민 주아체, 도현체, 연성체, 기랑해랑체, 글림체, WORK (앱 전용, 2025) |
|
|
73
|
+
| **특징** | 손글씨, 다채로운 일러스트, 유쾌한 톤 |
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
{/* 음식점 카드 */}
|
|
77
|
+
<div className="rounded-2xl overflow-hidden bg-white border">
|
|
78
|
+
<img className="w-full aspect-[4/3] object-cover" src="/food.jpg" />
|
|
79
|
+
<div className="p-4">
|
|
80
|
+
<h3 className="font-bold text-base">식당 이름</h3>
|
|
81
|
+
<div className="flex items-center gap-1 text-sm text-gray-600">
|
|
82
|
+
<span>⭐ 4.8</span><span>•</span><span>리뷰 1,234</span>
|
|
83
|
+
</div>
|
|
84
|
+
<div className="flex items-center justify-between mt-2">
|
|
85
|
+
<span className="text-sm text-gray-600">배달 30분</span>
|
|
86
|
+
<span className="text-sm font-semibold text-primary-500">최소 15,000원</span>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
{/* 빈 상태 */}
|
|
92
|
+
<div className="flex flex-col items-center py-12 gap-4">
|
|
93
|
+
<img src="/empty-illustration.svg" className="w-32 h-32" />
|
|
94
|
+
<h3 className="font-bold text-lg">주문 내역이 없어요</h3>
|
|
95
|
+
<p className="text-sm text-gray-600">배민에서 맛있는 음식을 주문해보세요!</p>
|
|
96
|
+
</div>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
</baemin>
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
<flex>
|
|
104
|
+
|
|
105
|
+
**산업:** 기업 금융 | **키워드:** 프로페셔널, 효율성, B2B
|
|
106
|
+
|
|
107
|
+
| 요소 | 내용 |
|
|
108
|
+
|------|------|
|
|
109
|
+
| **Primary** | Purple #8B5CF6 (프로페셔널) |
|
|
110
|
+
| **Secondary** | Gray #6B7280 (차분, 신뢰) |
|
|
111
|
+
| **특징** | 정보 밀도 높은 대시보드, 데이터 시각화, 효율적 워크플로우 |
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
{/* 통계 카드 그리드 */}
|
|
115
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
116
|
+
<div className="p-6 bg-white rounded-xl border">
|
|
117
|
+
<div className="text-sm text-gray-600">라벨</div>
|
|
118
|
+
<div className="text-2xl font-bold text-gray-900">값</div>
|
|
119
|
+
<div className="text-xs text-green-600 mt-1">↑ +12%</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
{/* 테이블 */}
|
|
124
|
+
<table className="w-full">
|
|
125
|
+
<thead className="bg-gray-50 border-b">
|
|
126
|
+
<tr>
|
|
127
|
+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-600">항목</th>
|
|
128
|
+
</tr>
|
|
129
|
+
</thead>
|
|
130
|
+
</table>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
</flex>
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
<karrot>
|
|
138
|
+
|
|
139
|
+
**산업:** 중고거래 | **키워드:** 동네, 따뜻함, 신뢰
|
|
140
|
+
|
|
141
|
+
| 요소 | 내용 |
|
|
142
|
+
|------|------|
|
|
143
|
+
| **Primary** | Orange #FF6F0F (당근색, 따뜻함, 친근) |
|
|
144
|
+
| **특징** | 지역 기반 UI, 당근 모티브, 신뢰 중심 거래 |
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
{/* 상품 카드 */}
|
|
148
|
+
<div className="flex gap-3 p-4 border-b">
|
|
149
|
+
<img className="w-24 h-24 rounded-lg object-cover" src="/product.jpg" />
|
|
150
|
+
<div className="flex-1 min-w-0">
|
|
151
|
+
<h3 className="font-semibold truncate">상품 이름</h3>
|
|
152
|
+
<div className="text-sm text-gray-600 truncate">우리동네 • 1시간 전</div>
|
|
153
|
+
<div className="text-base font-bold">15,000원</div>
|
|
154
|
+
</div>
|
|
155
|
+
<div className="flex items-end">
|
|
156
|
+
<div className="flex items-center gap-1 text-sm text-gray-500">
|
|
157
|
+
<svg className="w-4 h-4" /><span>3</span>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
{/* 동네 선택 */}
|
|
163
|
+
<button className="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-100">
|
|
164
|
+
<svg className="w-5 h-5 text-gray-700" />
|
|
165
|
+
<span className="font-semibold">우리동네</span>
|
|
166
|
+
<svg className="w-4 h-4 text-gray-400" />
|
|
167
|
+
</button>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
</karrot>
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
<common_patterns>
|
|
175
|
+
|
|
176
|
+
| 패턴 | 적용 |
|
|
177
|
+
|------|------|
|
|
178
|
+
| **모바일 우선** | 모바일 앱 우선 설계 |
|
|
179
|
+
| **카드 기반** | 정보를 카드로 그룹화 |
|
|
180
|
+
| **큰 터치 타겟** | 최소 44-48px |
|
|
181
|
+
| **명확한 CTA** | 주요 액션 명확 |
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
{/* 모바일 우선 + 반응형 */}
|
|
185
|
+
<div className="px-4 md:px-6 lg:px-8 max-w-7xl mx-auto" />
|
|
186
|
+
|
|
187
|
+
{/* 카드 */}
|
|
188
|
+
<div className="p-4 md:p-6 bg-white rounded-xl md:rounded-2xl border" />
|
|
189
|
+
|
|
190
|
+
{/* CTA */}
|
|
191
|
+
<button className="w-full h-14 bg-primary-500 text-white rounded-xl">주요 액션</button>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
</common_patterns>
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
<sources>
|
|
199
|
+
|
|
200
|
+
- [토스 디자인 시스템 가이드](https://toss.tech/article/toss-design-system-guide)
|
|
201
|
+
- [토스 TDS 개발자센터](https://developers-apps-in-toss.toss.im/design/components.html)
|
|
202
|
+
- [카카오 로그인 디자인 가이드](https://developers.kakao.com/docs/latest/ko/kakaologin/design-guide)
|
|
203
|
+
- [배민 디자인 스토리](https://story.baemin.com/)
|
|
204
|
+
- [우아한형제들 기술블로그](https://techblog.woowahan.com/6305/)
|
|
205
|
+
|
|
206
|
+
</sources>
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# 상태 패턴
|
|
2
|
+
|
|
3
|
+
<empty>
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
{/* 기본 빈 상태 */}
|
|
7
|
+
<div className="flex flex-col items-center py-12 gap-4">
|
|
8
|
+
<div className="w-20 h-20 rounded-full bg-gray-100 flex items-center justify-center">
|
|
9
|
+
<svg className="w-10 h-10 text-gray-400" />
|
|
10
|
+
</div>
|
|
11
|
+
<div className="text-center">
|
|
12
|
+
<h3 className="font-semibold text-gray-900">아직 내용이 없어요</h3>
|
|
13
|
+
<p className="text-sm text-gray-600 mt-1">첫 번째 항목을 추가해보세요</p>
|
|
14
|
+
</div>
|
|
15
|
+
<button className="h-11 px-4 bg-primary-500 text-white rounded-lg">추가하기</button>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
{/* 검색 결과 없음 */}
|
|
19
|
+
<div className="flex flex-col items-center py-12 gap-3">
|
|
20
|
+
<svg className="w-16 h-16 text-gray-300" />
|
|
21
|
+
<h3 className="font-semibold">검색 결과가 없어요</h3>
|
|
22
|
+
<p className="text-sm text-gray-600">다른 검색어로 시도해보세요</p>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
{/* 필터 결과 없음 */}
|
|
26
|
+
<div className="flex flex-col items-center py-12 gap-3">
|
|
27
|
+
<svg className="w-16 h-16 text-gray-300" />
|
|
28
|
+
<h3 className="font-semibold">조건에 맞는 항목이 없어요</h3>
|
|
29
|
+
<p className="text-sm text-gray-600">필터를 조정해보세요</p>
|
|
30
|
+
<button onClick={resetFilters} className="text-sm text-primary-500 font-medium">
|
|
31
|
+
필터 초기화
|
|
32
|
+
</button>
|
|
33
|
+
</div>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
</empty>
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
<loading>
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
{/* 스켈레톤 UI */}
|
|
44
|
+
<div className="space-y-4 animate-pulse">
|
|
45
|
+
{[1, 2, 3].map(i => (
|
|
46
|
+
<div key={i} className="p-4 border rounded-xl">
|
|
47
|
+
<div className="flex gap-3">
|
|
48
|
+
<div className="w-12 h-12 bg-gray-200 rounded-lg" />
|
|
49
|
+
<div className="flex-1 space-y-2">
|
|
50
|
+
<div className="h-4 bg-gray-200 rounded w-3/4" />
|
|
51
|
+
<div className="h-4 bg-gray-200 rounded w-1/2" />
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
))}
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
{/* 버튼 로딩 */}
|
|
59
|
+
<button disabled className="h-11 px-4 bg-primary-500 text-white rounded-lg flex items-center gap-2 opacity-70">
|
|
60
|
+
<svg className="w-5 h-5 animate-spin" />처리 중...
|
|
61
|
+
</button>
|
|
62
|
+
|
|
63
|
+
{/* 인라인 스피너 */}
|
|
64
|
+
<div className="flex items-center gap-2 text-sm text-gray-600">
|
|
65
|
+
<svg className="w-4 h-4 animate-spin" />
|
|
66
|
+
<span>불러오는 중...</span>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
{/* 풀페이지 로딩 */}
|
|
70
|
+
<div className="fixed inset-0 bg-white z-50 flex flex-col items-center justify-center gap-4">
|
|
71
|
+
<img src="/logo.svg" className="w-16 h-16" />
|
|
72
|
+
<svg className="w-8 h-8 animate-spin text-primary-500" />
|
|
73
|
+
<p className="text-sm text-gray-600">잠시만 기다려주세요</p>
|
|
74
|
+
</div>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
</loading>
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
<success>
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
{/* 토스트 (하단) */}
|
|
85
|
+
<div className="fixed bottom-4 left-1/2 -translate-x-1/2 z-50">
|
|
86
|
+
<div className="bg-gray-900 text-white px-4 py-3 rounded-lg shadow-lg flex items-center gap-2">
|
|
87
|
+
<svg className="w-5 h-5 text-green-400" />
|
|
88
|
+
<span className="text-sm">저장되었습니다</span>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
{/* 토스트 (우측 상단) */}
|
|
93
|
+
<div className="fixed top-4 right-4 z-50">
|
|
94
|
+
<div className="bg-white border border-green-500 px-4 py-3 rounded-lg shadow-lg flex items-center gap-3">
|
|
95
|
+
<div className="w-8 h-8 rounded-full bg-green-100 flex items-center justify-center">
|
|
96
|
+
<svg className="w-5 h-5 text-green-600" />
|
|
97
|
+
</div>
|
|
98
|
+
<div>
|
|
99
|
+
<div className="font-semibold">성공</div>
|
|
100
|
+
<div className="text-sm text-gray-600">작업이 완료되었습니다</div>
|
|
101
|
+
</div>
|
|
102
|
+
<button className="text-gray-400 hover:text-gray-600">✕</button>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
{/* 인라인 성공 */}
|
|
107
|
+
<div className="p-3 bg-green-50 border border-green-200 rounded-lg flex items-start gap-2">
|
|
108
|
+
<svg className="w-5 h-5 text-green-600 mt-0.5" />
|
|
109
|
+
<p className="text-sm text-green-800">이메일이 성공적으로 전송되었습니다</p>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
{/* 성공 페이지 */}
|
|
113
|
+
<div className="flex flex-col items-center py-16 gap-4">
|
|
114
|
+
<div className="w-20 h-20 rounded-full bg-green-100 flex items-center justify-center">
|
|
115
|
+
<svg className="w-10 h-10 text-green-600" />
|
|
116
|
+
</div>
|
|
117
|
+
<div className="text-center">
|
|
118
|
+
<h2 className="text-2xl font-bold mb-2">결제 완료</h2>
|
|
119
|
+
<p className="text-gray-600">주문이 성공적으로 처리되었습니다</p>
|
|
120
|
+
</div>
|
|
121
|
+
<div className="flex gap-2 mt-4">
|
|
122
|
+
<button className="h-11 px-4 border rounded-lg">주문 내역</button>
|
|
123
|
+
<button className="h-11 px-4 bg-primary-500 text-white rounded-lg">계속 쇼핑하기</button>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
</success>
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
<error>
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
{/* 인풋 에러 */}
|
|
136
|
+
<div>
|
|
137
|
+
<input className="w-full h-11 px-3 border-2 border-red-500 rounded-lg" aria-invalid="true" />
|
|
138
|
+
<p className="text-sm text-red-600 mt-1 flex items-center gap-1">
|
|
139
|
+
<svg className="w-4 h-4" />올바른 이메일을 입력해주세요
|
|
140
|
+
</p>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
{/* 알림 박스 */}
|
|
144
|
+
<div className="p-3 bg-red-50 border border-red-200 rounded-lg flex items-start gap-2">
|
|
145
|
+
<svg className="w-5 h-5 text-red-600 mt-0.5" />
|
|
146
|
+
<div>
|
|
147
|
+
<h4 className="font-semibold text-red-900 text-sm mb-1">오류가 발생했습니다</h4>
|
|
148
|
+
<p className="text-sm text-red-800">네트워크 연결을 확인하고 다시 시도해주세요</p>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
{/* 에러 페이지 */}
|
|
153
|
+
<div className="flex flex-col items-center min-h-screen px-4 gap-4 justify-center">
|
|
154
|
+
<div className="w-20 h-20 rounded-full bg-red-100 flex items-center justify-center">
|
|
155
|
+
<svg className="w-10 h-10 text-red-600" />
|
|
156
|
+
</div>
|
|
157
|
+
<div className="text-center">
|
|
158
|
+
<h2 className="text-2xl font-bold mb-2">페이지를 불러올 수 없어요</h2>
|
|
159
|
+
<p className="text-gray-600">일시적인 오류가 발생했습니다</p>
|
|
160
|
+
</div>
|
|
161
|
+
<button onClick={() => window.location.reload()} className="h-11 px-4 bg-primary-500 text-white rounded-lg">
|
|
162
|
+
새로고침
|
|
163
|
+
</button>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
{/* 404 페이지 */}
|
|
167
|
+
<div className="flex flex-col items-center min-h-screen px-4 gap-4 justify-center">
|
|
168
|
+
<h1 className="text-6xl font-bold text-gray-900">404</h1>
|
|
169
|
+
<h2 className="text-2xl font-semibold">페이지를 찾을 수 없어요</h2>
|
|
170
|
+
<p className="text-gray-600">요청하신 페이지가 존재하지 않거나 이동했을 수 있습니다</p>
|
|
171
|
+
<button onClick={() => router.push('/')} className="h-11 px-4 bg-primary-500 text-white rounded-lg">
|
|
172
|
+
홈으로 가기
|
|
173
|
+
</button>
|
|
174
|
+
</div>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
</error>
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
<warning>
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
{/* 경고 알림 */}
|
|
185
|
+
<div className="p-3 bg-yellow-50 border border-yellow-200 rounded-lg flex items-start gap-2">
|
|
186
|
+
<svg className="w-5 h-5 text-yellow-600 mt-0.5" />
|
|
187
|
+
<div>
|
|
188
|
+
<h4 className="font-semibold text-yellow-900 text-sm mb-1">주의하세요</h4>
|
|
189
|
+
<p className="text-sm text-yellow-800">이 작업은 되돌릴 수 없습니다</p>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
{/* 확인 모달 */}
|
|
194
|
+
<div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
|
|
195
|
+
<div className="bg-white rounded-2xl max-w-sm w-full p-6">
|
|
196
|
+
<div className="w-12 h-12 rounded-full bg-yellow-100 flex items-center justify-center mx-auto mb-4">
|
|
197
|
+
<svg className="w-6 h-6 text-yellow-600" />
|
|
198
|
+
</div>
|
|
199
|
+
<h2 className="text-lg font-semibold text-center mb-2">정말 삭제하시겠어요?</h2>
|
|
200
|
+
<p className="text-sm text-gray-600 text-center mb-6">삭제한 항목은 복구할 수 없습니다</p>
|
|
201
|
+
<div className="flex gap-2">
|
|
202
|
+
<button onClick={onCancel} className="flex-1 h-11 border rounded-lg">취소</button>
|
|
203
|
+
<button onClick={onConfirm} className="flex-1 h-11 bg-red-500 text-white rounded-lg">삭제</button>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
</warning>
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
<info>
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
{/* 정보 알림 */}
|
|
217
|
+
<div className="p-3 bg-blue-50 border border-blue-200 rounded-lg flex items-start gap-2">
|
|
218
|
+
<svg className="w-5 h-5 text-blue-600 mt-0.5" />
|
|
219
|
+
<p className="text-sm text-blue-900 flex-1">새로운 기능이 추가되었습니다. 확인해보세요!</p>
|
|
220
|
+
<button className="text-blue-600 hover:text-blue-800 text-sm font-medium">자세히</button>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
{/* 배너 알림 */}
|
|
224
|
+
<div className="w-full bg-primary-50 border-b border-primary-200 py-3 px-4">
|
|
225
|
+
<div className="max-w-7xl mx-auto flex items-center justify-between gap-4">
|
|
226
|
+
<div className="flex items-center gap-2 flex-1">
|
|
227
|
+
<svg className="w-5 h-5 text-primary-600" />
|
|
228
|
+
<p className="text-sm text-primary-900">현재 시스템 점검이 예정되어 있습니다</p>
|
|
229
|
+
</div>
|
|
230
|
+
<button className="text-primary-600 hover:text-primary-800">✕</button>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
</info>
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
<disabled>
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
{/* 비활성 버튼 */}
|
|
243
|
+
<button disabled className="h-11 px-4 bg-gray-300 text-gray-500 rounded-lg cursor-not-allowed">
|
|
244
|
+
버튼
|
|
245
|
+
</button>
|
|
246
|
+
|
|
247
|
+
{/* 툴팁 포함 */}
|
|
248
|
+
<div className="relative group">
|
|
249
|
+
<button disabled className="h-11 px-4 bg-gray-300 text-gray-500 rounded-lg cursor-not-allowed">
|
|
250
|
+
저장하기
|
|
251
|
+
</button>
|
|
252
|
+
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-3 py-2 bg-gray-900 text-white text-xs rounded-lg opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap pointer-events-none">
|
|
253
|
+
모든 필드를 입력해주세요
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
|
|
257
|
+
{/* 비활성 카드 */}
|
|
258
|
+
<div className="p-4 border rounded-xl opacity-50 cursor-not-allowed">
|
|
259
|
+
<div className="relative">
|
|
260
|
+
<div className="absolute inset-0 bg-white/50" />
|
|
261
|
+
{/* 내용 */}
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
</disabled>
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
<offline>
|
|
271
|
+
|
|
272
|
+
```tsx
|
|
273
|
+
{/* 오프라인 배너 */}
|
|
274
|
+
<div className="fixed top-0 inset-x-0 bg-gray-900 text-white py-2 px-4 z-50">
|
|
275
|
+
<div className="max-w-7xl mx-auto flex items-center justify-center gap-2">
|
|
276
|
+
<svg className="w-5 h-5" />
|
|
277
|
+
<span className="text-sm">인터넷 연결이 끊어졌습니다</span>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
</offline>
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
<progress>
|
|
287
|
+
|
|
288
|
+
```tsx
|
|
289
|
+
{/* 단계 표시 */}
|
|
290
|
+
<div className="flex items-center justify-between">
|
|
291
|
+
{steps.map((step, index) => (
|
|
292
|
+
<div key={step.id} className="flex items-center">
|
|
293
|
+
<div className={`w-10 h-10 rounded-full flex items-center justify-center font-semibold ${
|
|
294
|
+
index < currentStep
|
|
295
|
+
? 'bg-primary-500 text-white'
|
|
296
|
+
: index === currentStep
|
|
297
|
+
? 'bg-primary-100 text-primary-600 border-2 border-primary-500'
|
|
298
|
+
: 'bg-gray-100 text-gray-400'
|
|
299
|
+
}`}>
|
|
300
|
+
{index < currentStep ? '✓' : index + 1}
|
|
301
|
+
</div>
|
|
302
|
+
{index < steps.length - 1 && (
|
|
303
|
+
<div className={`h-1 w-16 ${index < currentStep ? 'bg-primary-500' : 'bg-gray-200'}`} />
|
|
304
|
+
)}
|
|
305
|
+
</div>
|
|
306
|
+
))}
|
|
307
|
+
</div>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
</progress>
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
<sources>
|
|
315
|
+
|
|
316
|
+
- [디자인베이스 - Empty State](https://designbase.co.kr/dictionary/emptystate/)
|
|
317
|
+
- [토스 - UX 라이팅](https://toss.im/career/article/ux-writing)
|
|
318
|
+
- [KRDS](https://www.krds.go.kr/)
|
|
319
|
+
|
|
320
|
+
</sources>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# 타이포그래피
|
|
2
|
+
|
|
3
|
+
<fonts>
|
|
4
|
+
|
|
5
|
+
**기본:** Pretendard | Spoqa Han Sans | Noto Sans KR
|
|
6
|
+
**시스템:** `-apple-system, BlinkMacSystemFont, sans-serif`
|
|
7
|
+
**영문 숫자:** Inter, SF Pro
|
|
8
|
+
|
|
9
|
+
</fonts>
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<size_system>
|
|
14
|
+
|
|
15
|
+
| 용도 | 크기 | Tailwind |
|
|
16
|
+
|------|------|----------|
|
|
17
|
+
| 캡션/뱃지 | 11-12px | text-xs |
|
|
18
|
+
| 부가 정보 | 13px | text-[13px] |
|
|
19
|
+
| 본문 | 14-15px | text-sm/text-base |
|
|
20
|
+
| 강조 본문 | 16-17px | text-base/text-lg |
|
|
21
|
+
| 소제목 | 18-20px | text-lg/text-xl |
|
|
22
|
+
| 섹션 제목 | 22-24px | text-xl/text-2xl |
|
|
23
|
+
| 페이지 제목 | 26-32px | text-2xl/text-3xl |
|
|
24
|
+
|
|
25
|
+
</size_system>
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
<weight_system>
|
|
30
|
+
|
|
31
|
+
| 용도 | 웨이트 | Tailwind |
|
|
32
|
+
|------|--------|----------|
|
|
33
|
+
| 본문, 설명 | Regular(400) | font-normal |
|
|
34
|
+
| 버튼, 강조 | Medium(500) | font-medium |
|
|
35
|
+
| 제목, 레이블 | Semibold(600) | font-semibold |
|
|
36
|
+
| 대제목, 숫자 | Bold(700) | font-bold |
|
|
37
|
+
|
|
38
|
+
</weight_system>
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
<korean_specifics>
|
|
43
|
+
|
|
44
|
+
**자간:** `tracking-tight (-0.01em)` | `tracking-tighter (-0.02em)`
|
|
45
|
+
**행간:** 제목 `leading-tight (1.3)` | 본문 `leading-relaxed (1.6)` | `leading-loose (1.7)`
|
|
46
|
+
|
|
47
|
+
</korean_specifics>
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
<examples>
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
{/* 페이지 제목 */}
|
|
55
|
+
<h1 className="text-3xl font-bold tracking-tight leading-tight">대시보드</h1>
|
|
56
|
+
|
|
57
|
+
{/* 섹션 제목 */}
|
|
58
|
+
<h2 className="text-xl font-semibold tracking-tight">최근 활동</h2>
|
|
59
|
+
|
|
60
|
+
{/* 본문 */}
|
|
61
|
+
<p className="text-sm font-normal leading-relaxed text-gray-700">본문</p>
|
|
62
|
+
|
|
63
|
+
{/* 부가 정보 */}
|
|
64
|
+
<span className="text-[13px] text-gray-500">2시간 전</span>
|
|
65
|
+
|
|
66
|
+
{/* 캡션/뱃지 */}
|
|
67
|
+
<span className="text-xs font-medium text-gray-600">신규</span>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
</examples>
|