@infomind-ux/infoux-mcp 0.1.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 (53) hide show
  1. package/README.md +81 -0
  2. package/bin/server.js +331 -0
  3. package/data/contract.md +215 -0
  4. package/data/manifest.json +286 -0
  5. package/data/references/accessibility.md +243 -0
  6. package/data/references/forbidden-patterns.md +462 -0
  7. package/data/references/guide-import.md +93 -0
  8. package/data/references/html-semantics.md +475 -0
  9. package/data/references/krds-components.md +1426 -0
  10. package/data/references/krds-source.md +1125 -0
  11. package/data/references/krds-tokens.md +201 -0
  12. package/data/references/project-profiles.md +99 -0
  13. package/data/references/snippet-template.md +185 -0
  14. package/data/references/tailwind-mapping.md +53 -0
  15. package/data/rules.json +780 -0
  16. package/data/snippets/accordion.md +49 -0
  17. package/data/snippets/alert.md +37 -0
  18. package/data/snippets/badge.md +29 -0
  19. package/data/snippets/boilerplate.md +125 -0
  20. package/data/snippets/breadcrumb.md +26 -0
  21. package/data/snippets/btn.md +63 -0
  22. package/data/snippets/calendar.md +64 -0
  23. package/data/snippets/card.md +50 -0
  24. package/data/snippets/carousel.md +43 -0
  25. package/data/snippets/check-radio.md +55 -0
  26. package/data/snippets/disclosure.md +44 -0
  27. package/data/snippets/file-upload.md +34 -0
  28. package/data/snippets/form.md +68 -0
  29. package/data/snippets/header.md +56 -0
  30. package/data/snippets/list.md +64 -0
  31. package/data/snippets/main-menu.md +49 -0
  32. package/data/snippets/modal.md +54 -0
  33. package/data/snippets/pagination.md +41 -0
  34. package/data/snippets/progress.md +30 -0
  35. package/data/snippets/select.md +34 -0
  36. package/data/snippets/side-panel.md +57 -0
  37. package/data/snippets/spinner.md +24 -0
  38. package/data/snippets/step-indicator.md +38 -0
  39. package/data/snippets/switch.md +32 -0
  40. package/data/snippets/tab.md +52 -0
  41. package/data/snippets/table.md +63 -0
  42. package/data/snippets/tag.md +42 -0
  43. package/data/snippets/toast.md +48 -0
  44. package/data/snippets/tooltip.md +38 -0
  45. package/data/tokens.css +390 -0
  46. package/data/workflows/change-token.md +20 -0
  47. package/data/workflows/create-component.md +71 -0
  48. package/data/workflows/design-form.md +20 -0
  49. package/data/workflows/design-page.md +22 -0
  50. package/data/workflows/design-widget.md +19 -0
  51. package/data/workflows/init-project.md +68 -0
  52. package/data/workflows/review-ui.md +14 -0
  53. package/package.json +34 -0
@@ -0,0 +1,42 @@
1
+ # 태그 (Tag) — KRDS
2
+
3
+ 카테고리, 필터, 속성 라벨.
4
+
5
+ ## 기본 마크업
6
+
7
+ ```html
8
+ <!-- 정적 태그 -->
9
+ <span class="tag">기본</span>
10
+
11
+ <!-- 클릭 가능 (필터 등) -->
12
+ <button type="button" class="tag tag--primary">선택됨</button>
13
+
14
+ <!-- 제거 가능 (선택된 필터) -->
15
+ <span class="tag tag--info">
16
+ 카테고리: 디자인
17
+ <button type="button" class="tag__close" aria-label="카테고리: 디자인 제거">×</button>
18
+ </span>
19
+
20
+ <!-- 링크형 -->
21
+ <a class="tag tag--success" href="?category=ui">UI</a>
22
+ ```
23
+
24
+ ## Variant
25
+
26
+ - 기본 (회색 outline)
27
+ - 시맨틱: `.tag--primary` / `.tag--info` / `.tag--success` / `.tag--warning` / `.tag--danger`
28
+
29
+ ## 사이즈
30
+
31
+ - `.tag--small` (20px)
32
+ - 기본 (24px)
33
+ - `.tag--large` (32px)
34
+
35
+ ## 접근성
36
+
37
+ - 제거 버튼은 `aria-label="태그명 제거"` 형식으로 컨텍스트 명시
38
+ - 클릭 가능 태그는 `<button>` 또는 `<a>` 사용 (div onclick 금지)
39
+
40
+ ## 출처
41
+
42
+ - CSS: `src/styles/6-components/tag.css`
@@ -0,0 +1,48 @@
1
+ # 토스트 (Toast) — KRDS
2
+
3
+ 일시적 피드백 메시지. 화면 우측 상단/하단에 잠시 노출 후 자동 사라짐.
4
+
5
+ ## 기본 마크업
6
+
7
+ ```html
8
+ <div class="toast-stack">
9
+ <div class="toast toast--success" role="status">
10
+ <span class="toast__icon" aria-hidden="true">✓</span>
11
+ <p class="toast__message">저장되었습니다</p>
12
+ <button type="button" class="toast__close" aria-label="닫기">×</button>
13
+ </div>
14
+ </div>
15
+ ```
16
+
17
+ ## 위치
18
+
19
+ - `.toast-stack` (기본) — 우측 상단
20
+ - `.toast-stack--bottom` — 우측 하단
21
+
22
+ ## Variant
23
+
24
+ - `.toast--info` / `.toast--success` / `.toast--warning` / `.toast--danger`
25
+
26
+ ## 동작 (JS)
27
+
28
+ - 보통 3~5초 후 자동 닫기 (사용자 액션 결과 통보)
29
+ - 사용자가 닫기 버튼으로 즉시 닫기 가능
30
+ - 다중 토스트는 위에서 아래로 누적
31
+
32
+ ## Alert vs Toast 사용 기준
33
+
34
+ | | Alert | Toast |
35
+ |---|-------|-------|
36
+ | 위치 | 페이지 인라인 | 화면 고정 |
37
+ | 지속시간 | 사용자가 닫을 때까지 | 자동 사라짐 |
38
+ | 용도 | 페이지 컨텍스트 알림 | 즉시 피드백 (저장 완료 등) |
39
+
40
+ ## 접근성
41
+
42
+ - `role="status"` + `aria-live="polite"` (스크린리더 정중 안내)
43
+ - 위급 시에만 `role="alert"` + `aria-live="assertive"`
44
+ - 자동 닫힘 토스트도 사용자 옵션으로 일시정지/지속 가능해야 함 (WCAG 2.2.1)
45
+
46
+ ## 출처
47
+
48
+ - CSS: `src/styles/6-components/toast.css`
@@ -0,0 +1,38 @@
1
+ # 툴팁 (Tooltip) — KRDS
2
+
3
+ 짧은 보조 설명 팝업. **JS 트리거 변형 권장** (키보드/터치 호환).
4
+
5
+ ## 기본 마크업 (JS 변형)
6
+
7
+ ```html
8
+ <button type="button" class="tooltip-trigger" aria-describedby="tip-1">
9
+ 도움말
10
+ </button>
11
+ <div id="tip-1" class="tooltip" role="tooltip" hidden>
12
+ 도움말 설명 텍스트
13
+ </div>
14
+ ```
15
+
16
+ JS: focus/mouseenter 시 `tooltip.removeAttribute('hidden')`, blur/mouseleave 시 `setAttribute('hidden', '')`.
17
+
18
+ ## CSS-only hover 변형 (단순 케이스)
19
+
20
+ ```html
21
+ <span class="tooltip-wrap">
22
+ <button type="button" aria-label="도움말">?</button>
23
+ <span class="tooltip" role="tooltip">설명 텍스트</span>
24
+ </span>
25
+ ```
26
+
27
+ > 키보드 사용자는 호버할 수 없으므로 중요 정보는 JS 변형 사용.
28
+
29
+ ## 접근성
30
+
31
+ - 트리거에 `aria-describedby="툴팁id"` 연결
32
+ - 툴팁에 `role="tooltip"` 필수
33
+ - ESC로 닫기 가능 (JS 처리)
34
+ - 툴팁은 hover/focus 양쪽으로 트리거 가능해야 함 (WCAG 1.4.13)
35
+
36
+ ## 출처
37
+
38
+ - CSS: `src/styles/6-components/tooltip.css`
@@ -0,0 +1,390 @@
1
+ /**
2
+ * AUTO-GENERATED — tokens/build/tokens.css
3
+ * 출처: tokens/foundation.json
4
+ * 직접 수정 금지. 변경은 tokens/foundation.json에서 한다.
5
+ *
6
+ * 공개 토큰은 색상, 기본 폰트, 브레이크포인트만 발행한다.
7
+ * 간격·크기·타이포 스케일·반경·모션·그림자·z-index는 CSS/Tailwind 직접값으로 작성한다.
8
+ */
9
+
10
+ :root {
11
+ /* Font families */
12
+ --font-sans: 'Pretendard GOV', 'Apple SD Gothic Neo', 'Noto Sans KR', system-ui, sans-serif;
13
+ --font-mono: 'JetBrains Mono', 'D2Coding', SFMono-Regular, Consolas, monospace;
14
+
15
+ /* Breakpoints */
16
+ --breakpoint-mobile: 360px;
17
+ --breakpoint-tablet: 768px;
18
+ --breakpoint-pc: 1280px;
19
+
20
+ /* Semantic colors */
21
+ --color-primary: #256ef4;
22
+ --color-primary-hover: #0b50d0;
23
+ --color-primary-pressed: #083891;
24
+ --color-secondary: #346fb2;
25
+ --color-text: #1e2124;
26
+ --color-text-bolder: #131416;
27
+ --color-text-subtle: #464c53;
28
+ --color-text-disabled: #8a949e;
29
+ --color-text-inverse: #ffffff;
30
+ --color-bg: #ffffff;
31
+ --color-bg-subtler: #f4f5f6;
32
+ --color-bg-subtle: #e6e8ea;
33
+ --color-bg-inverse: #1e2124;
34
+ --color-bg-dim: #000000bf;
35
+ --color-surface: #ffffff;
36
+ --color-surface-subtler: #f4f5f6;
37
+ --color-surface-disabled: #cdd1d5;
38
+ --color-surface-primary-subtler: #ecf2fe;
39
+ --color-surface-information-subtler: #e7f4fe;
40
+ --color-surface-success-subtler: #eaf6ec;
41
+ --color-surface-warning-subtler: #fff3db;
42
+ --color-surface-danger-subtler: #fdefec;
43
+ --color-border: #b1b8be;
44
+ --color-border-light: #cdd1d5;
45
+ --color-border-dark: #58616a;
46
+ --color-border-primary: #256ef4;
47
+ --color-border-primary-light: #d8e5fd;
48
+ --color-border-information-light: #d3ebfd;
49
+ --color-border-success-light: #d8eedd;
50
+ --color-border-warning-light: #ffe0a3;
51
+ --color-border-danger-light: #fcdfd9;
52
+ --color-border-disabled: #b1b8be;
53
+ --color-link: #256ef4;
54
+ --color-link-hover: #0b50d0;
55
+ --color-link-pressed: #083891;
56
+ --color-link-visited: #5917b8;
57
+ --color-button-primary-fill: #0b50d0;
58
+ --color-button-primary-fill-hover: #083891;
59
+ --color-button-primary-fill-pressed: #052561;
60
+ --color-button-secondary-fill: #ecf2fe;
61
+ --color-button-secondary-fill-hover: #d8e5fd;
62
+ --color-button-secondary-fill-pressed: #b1cefb;
63
+ --color-button-secondary-border: #256ef4;
64
+ --color-button-tertiary-fill: #ffffff00;
65
+ --color-button-tertiary-fill-hover: #f4f5f6;
66
+ --color-button-tertiary-fill-pressed: #e6e8ea;
67
+ --color-button-tertiary-border: #58616a;
68
+ --color-button-text-fill: #ffffff00;
69
+ --color-button-text-fill-hover: #eef2f7;
70
+ --color-button-text-fill-pressed: #d6e0eb;
71
+ --color-button-text-border: #00000000;
72
+ --color-button-disabled-fill: #cdd1d5;
73
+ --color-button-disabled-border: #b1b8be;
74
+ --color-input-surface: #ffffff;
75
+ --color-input-surface-disabled: #cdd1d5;
76
+ --color-input-border: #58616a;
77
+ --color-input-border-active: #256ef4;
78
+ --color-input-border-disabled: #b1b8be;
79
+ --color-input-border-error: #de3412;
80
+ --color-danger: #de3412;
81
+ --color-danger-text: #bd2c0f;
82
+ --color-danger-surface: #fdefec;
83
+ --color-warning: #9e6a00;
84
+ --color-warning-text: #8a5c00;
85
+ --color-warning-surface: #fff3db;
86
+ --color-success: #228738;
87
+ --color-success-text: #267337;
88
+ --color-success-surface: #eaf6ec;
89
+ --color-info: #0b78cb;
90
+ --color-info-text: #096ab3;
91
+ --color-info-surface: #e7f4fe;
92
+ --color-point: #d63d4a;
93
+
94
+ /* 단계 색상: 필요한 경우에만 제한적으로 사용 */
95
+ --color-primary-5: #ecf2fe;
96
+ --color-primary-10: #d8e5fd;
97
+ --color-primary-20: #b1cefb;
98
+ --color-primary-30: #86aff9;
99
+ --color-primary-40: #4c87f6;
100
+ --color-primary-50: #256ef4;
101
+ --color-primary-60: #0b50d0;
102
+ --color-primary-70: #083891;
103
+ --color-primary-80: #052561;
104
+ --color-primary-90: #03163a;
105
+ --color-primary-95: #020f27;
106
+ --color-secondary-5: #eef2f7;
107
+ --color-secondary-10: #d6e0eb;
108
+ --color-secondary-20: #bacbde;
109
+ --color-secondary-30: #90b0d5;
110
+ --color-secondary-40: #6b96c7;
111
+ --color-secondary-50: #346fb2;
112
+ --color-secondary-60: #1c589c;
113
+ --color-secondary-70: #063a74;
114
+ --color-secondary-80: #052b57;
115
+ --color-secondary-90: #031f3f;
116
+ --color-secondary-95: #02162c;
117
+ --color-gray-0: #ffffff;
118
+ --color-gray-5: #f4f5f6;
119
+ --color-gray-10: #e6e8ea;
120
+ --color-gray-20: #cdd1d5;
121
+ --color-gray-30: #b1b8be;
122
+ --color-gray-40: #8a949e;
123
+ --color-gray-50: #6d7882;
124
+ --color-gray-60: #58616a;
125
+ --color-gray-70: #464c53;
126
+ --color-gray-80: #33363d;
127
+ --color-gray-90: #1e2124;
128
+ --color-gray-95: #131416;
129
+ --color-gray-100: #000000;
130
+ --color-danger-5: #fdefec;
131
+ --color-danger-10: #fcdfd9;
132
+ --color-danger-20: #f7afa1;
133
+ --color-danger-30: #f48771;
134
+ --color-danger-40: #f05f42;
135
+ --color-danger-50: #de3412;
136
+ --color-danger-60: #bd2c0f;
137
+ --color-danger-70: #8a240f;
138
+ --color-danger-80: #5c180a;
139
+ --color-danger-90: #390d05;
140
+ --color-danger-95: #260903;
141
+ --color-warning-5: #fff3db;
142
+ --color-warning-10: #ffe0a3;
143
+ --color-warning-20: #ffc95c;
144
+ --color-warning-30: #ffb114;
145
+ --color-warning-40: #c78500;
146
+ --color-warning-50: #9e6a00;
147
+ --color-warning-60: #8a5c00;
148
+ --color-warning-70: #614100;
149
+ --color-warning-80: #422c00;
150
+ --color-warning-90: #2e1f00;
151
+ --color-warning-95: #241800;
152
+ --color-success-5: #eaf6ec;
153
+ --color-success-10: #d8eedd;
154
+ --color-success-20: #a9dab4;
155
+ --color-success-30: #7ec88e;
156
+ --color-success-40: #3fa654;
157
+ --color-success-50: #228738;
158
+ --color-success-60: #267337;
159
+ --color-success-70: #285d33;
160
+ --color-success-80: #1f4727;
161
+ --color-success-90: #122b18;
162
+ --color-success-95: #0e2012;
163
+ --color-information-5: #e7f4fe;
164
+ --color-information-10: #d3ebfd;
165
+ --color-information-20: #9ed2fa;
166
+ --color-information-30: #5fb5f7;
167
+ --color-information-40: #2098f3;
168
+ --color-information-50: #0b78cb;
169
+ --color-information-60: #096ab3;
170
+ --color-information-70: #085691;
171
+ --color-information-80: #053961;
172
+ --color-information-90: #03253f;
173
+ --color-information-95: #021a2c;
174
+ --color-point-5: #fbeff0;
175
+ --color-point-10: #f5d6d9;
176
+ --color-point-20: #ebadb2;
177
+ --color-point-30: #e0858c;
178
+ --color-point-40: #d65c66;
179
+ --color-point-50: #d63d4a;
180
+ --color-point-60: #ab2b36;
181
+ --color-point-70: #7a1f26;
182
+ --color-point-80: #521419;
183
+ --color-point-90: #310c0f;
184
+ --color-point-95: #21080a;
185
+ --color-alpha-black-50: #00000080;
186
+ --color-alpha-black-75: #000000bf;
187
+ }
188
+
189
+ [data-color-mode="high-contrast"] {
190
+ --color-primary: #256ef4;
191
+ --color-primary-hover: #0b50d0;
192
+ --color-primary-pressed: #083891;
193
+ --color-text: #f4f5f6;
194
+ --color-text-bolder: #e6e8ea;
195
+ --color-text-subtle: #cdd1d5;
196
+ --color-text-disabled: #58616a;
197
+ --color-text-inverse: #1e2124;
198
+ --color-bg: #000000;
199
+ --color-bg-subtler: #131416;
200
+ --color-bg-subtle: #1e2124;
201
+ --color-bg-inverse: #e6e8ea;
202
+ --color-bg-dim: #000000bf;
203
+ --color-surface: #000000;
204
+ --color-surface-subtler: #131416;
205
+ --color-surface-disabled: #464c53;
206
+ --color-border: #464c53;
207
+ --color-border-light: #33363d;
208
+ --color-border-dark: #8a949e;
209
+ --color-border-primary: #256ef4;
210
+ --color-border-disabled: #464c53;
211
+ }
212
+
213
+ @theme {
214
+ /* Tailwind 기본 색상 팔레트 비활성화 — INFOUX 색상만 노출 */
215
+ --color-*: initial;
216
+
217
+ --font-sans: 'Pretendard GOV', 'Apple SD Gothic Neo', 'Noto Sans KR', system-ui, sans-serif;
218
+ --font-mono: 'JetBrains Mono', 'D2Coding', SFMono-Regular, Consolas, monospace;
219
+
220
+ /* Tailwind responsive variants: mobile:, tablet:, pc: */
221
+ --breakpoint-*: initial;
222
+ --breakpoint-mobile: 360px;
223
+ --breakpoint-tablet: 768px;
224
+ --breakpoint-pc: 1280px;
225
+
226
+ --color-primary: var(--color-primary);
227
+ --color-primary-hover: var(--color-primary-hover);
228
+ --color-primary-pressed: var(--color-primary-pressed);
229
+ --color-secondary: var(--color-secondary);
230
+ --color-text: var(--color-text);
231
+ --color-text-bolder: var(--color-text-bolder);
232
+ --color-text-subtle: var(--color-text-subtle);
233
+ --color-text-disabled: var(--color-text-disabled);
234
+ --color-text-inverse: var(--color-text-inverse);
235
+ --color-bg: var(--color-bg);
236
+ --color-bg-subtler: var(--color-bg-subtler);
237
+ --color-bg-subtle: var(--color-bg-subtle);
238
+ --color-bg-inverse: var(--color-bg-inverse);
239
+ --color-bg-dim: var(--color-bg-dim);
240
+ --color-surface: var(--color-surface);
241
+ --color-surface-subtler: var(--color-surface-subtler);
242
+ --color-surface-disabled: var(--color-surface-disabled);
243
+ --color-surface-primary-subtler: var(--color-surface-primary-subtler);
244
+ --color-surface-information-subtler: var(--color-surface-information-subtler);
245
+ --color-surface-success-subtler: var(--color-surface-success-subtler);
246
+ --color-surface-warning-subtler: var(--color-surface-warning-subtler);
247
+ --color-surface-danger-subtler: var(--color-surface-danger-subtler);
248
+ --color-border: var(--color-border);
249
+ --color-border-light: var(--color-border-light);
250
+ --color-border-dark: var(--color-border-dark);
251
+ --color-border-primary: var(--color-border-primary);
252
+ --color-border-primary-light: var(--color-border-primary-light);
253
+ --color-border-information-light: var(--color-border-information-light);
254
+ --color-border-success-light: var(--color-border-success-light);
255
+ --color-border-warning-light: var(--color-border-warning-light);
256
+ --color-border-danger-light: var(--color-border-danger-light);
257
+ --color-border-disabled: var(--color-border-disabled);
258
+ --color-link: var(--color-link);
259
+ --color-link-hover: var(--color-link-hover);
260
+ --color-link-pressed: var(--color-link-pressed);
261
+ --color-link-visited: var(--color-link-visited);
262
+ --color-button-primary-fill: var(--color-button-primary-fill);
263
+ --color-button-primary-fill-hover: var(--color-button-primary-fill-hover);
264
+ --color-button-primary-fill-pressed: var(--color-button-primary-fill-pressed);
265
+ --color-button-secondary-fill: var(--color-button-secondary-fill);
266
+ --color-button-secondary-fill-hover: var(--color-button-secondary-fill-hover);
267
+ --color-button-secondary-fill-pressed: var(--color-button-secondary-fill-pressed);
268
+ --color-button-secondary-border: var(--color-button-secondary-border);
269
+ --color-button-tertiary-fill: var(--color-button-tertiary-fill);
270
+ --color-button-tertiary-fill-hover: var(--color-button-tertiary-fill-hover);
271
+ --color-button-tertiary-fill-pressed: var(--color-button-tertiary-fill-pressed);
272
+ --color-button-tertiary-border: var(--color-button-tertiary-border);
273
+ --color-button-text-fill: var(--color-button-text-fill);
274
+ --color-button-text-fill-hover: var(--color-button-text-fill-hover);
275
+ --color-button-text-fill-pressed: var(--color-button-text-fill-pressed);
276
+ --color-button-text-border: var(--color-button-text-border);
277
+ --color-button-disabled-fill: var(--color-button-disabled-fill);
278
+ --color-button-disabled-border: var(--color-button-disabled-border);
279
+ --color-input-surface: var(--color-input-surface);
280
+ --color-input-surface-disabled: var(--color-input-surface-disabled);
281
+ --color-input-border: var(--color-input-border);
282
+ --color-input-border-active: var(--color-input-border-active);
283
+ --color-input-border-disabled: var(--color-input-border-disabled);
284
+ --color-input-border-error: var(--color-input-border-error);
285
+ --color-danger: var(--color-danger);
286
+ --color-danger-text: var(--color-danger-text);
287
+ --color-danger-surface: var(--color-danger-surface);
288
+ --color-warning: var(--color-warning);
289
+ --color-warning-text: var(--color-warning-text);
290
+ --color-warning-surface: var(--color-warning-surface);
291
+ --color-success: var(--color-success);
292
+ --color-success-text: var(--color-success-text);
293
+ --color-success-surface: var(--color-success-surface);
294
+ --color-info: var(--color-info);
295
+ --color-info-text: var(--color-info-text);
296
+ --color-info-surface: var(--color-info-surface);
297
+ --color-point: var(--color-point);
298
+ --color-alpha-black-50: var(--color-alpha-black-50);
299
+ --color-alpha-black-75: var(--color-alpha-black-75);
300
+ --color-primary-5: var(--color-primary-5);
301
+ --color-primary-10: var(--color-primary-10);
302
+ --color-primary-20: var(--color-primary-20);
303
+ --color-primary-30: var(--color-primary-30);
304
+ --color-primary-40: var(--color-primary-40);
305
+ --color-primary-50: var(--color-primary-50);
306
+ --color-primary-60: var(--color-primary-60);
307
+ --color-primary-70: var(--color-primary-70);
308
+ --color-primary-80: var(--color-primary-80);
309
+ --color-primary-90: var(--color-primary-90);
310
+ --color-primary-95: var(--color-primary-95);
311
+ --color-secondary-5: var(--color-secondary-5);
312
+ --color-secondary-10: var(--color-secondary-10);
313
+ --color-secondary-20: var(--color-secondary-20);
314
+ --color-secondary-30: var(--color-secondary-30);
315
+ --color-secondary-40: var(--color-secondary-40);
316
+ --color-secondary-50: var(--color-secondary-50);
317
+ --color-secondary-60: var(--color-secondary-60);
318
+ --color-secondary-70: var(--color-secondary-70);
319
+ --color-secondary-80: var(--color-secondary-80);
320
+ --color-secondary-90: var(--color-secondary-90);
321
+ --color-secondary-95: var(--color-secondary-95);
322
+ --color-gray-0: var(--color-gray-0);
323
+ --color-gray-5: var(--color-gray-5);
324
+ --color-gray-10: var(--color-gray-10);
325
+ --color-gray-20: var(--color-gray-20);
326
+ --color-gray-30: var(--color-gray-30);
327
+ --color-gray-40: var(--color-gray-40);
328
+ --color-gray-50: var(--color-gray-50);
329
+ --color-gray-60: var(--color-gray-60);
330
+ --color-gray-70: var(--color-gray-70);
331
+ --color-gray-80: var(--color-gray-80);
332
+ --color-gray-90: var(--color-gray-90);
333
+ --color-gray-95: var(--color-gray-95);
334
+ --color-gray-100: var(--color-gray-100);
335
+ --color-danger-5: var(--color-danger-5);
336
+ --color-danger-10: var(--color-danger-10);
337
+ --color-danger-20: var(--color-danger-20);
338
+ --color-danger-30: var(--color-danger-30);
339
+ --color-danger-40: var(--color-danger-40);
340
+ --color-danger-50: var(--color-danger-50);
341
+ --color-danger-60: var(--color-danger-60);
342
+ --color-danger-70: var(--color-danger-70);
343
+ --color-danger-80: var(--color-danger-80);
344
+ --color-danger-90: var(--color-danger-90);
345
+ --color-danger-95: var(--color-danger-95);
346
+ --color-warning-5: var(--color-warning-5);
347
+ --color-warning-10: var(--color-warning-10);
348
+ --color-warning-20: var(--color-warning-20);
349
+ --color-warning-30: var(--color-warning-30);
350
+ --color-warning-40: var(--color-warning-40);
351
+ --color-warning-50: var(--color-warning-50);
352
+ --color-warning-60: var(--color-warning-60);
353
+ --color-warning-70: var(--color-warning-70);
354
+ --color-warning-80: var(--color-warning-80);
355
+ --color-warning-90: var(--color-warning-90);
356
+ --color-warning-95: var(--color-warning-95);
357
+ --color-success-5: var(--color-success-5);
358
+ --color-success-10: var(--color-success-10);
359
+ --color-success-20: var(--color-success-20);
360
+ --color-success-30: var(--color-success-30);
361
+ --color-success-40: var(--color-success-40);
362
+ --color-success-50: var(--color-success-50);
363
+ --color-success-60: var(--color-success-60);
364
+ --color-success-70: var(--color-success-70);
365
+ --color-success-80: var(--color-success-80);
366
+ --color-success-90: var(--color-success-90);
367
+ --color-success-95: var(--color-success-95);
368
+ --color-information-5: var(--color-information-5);
369
+ --color-information-10: var(--color-information-10);
370
+ --color-information-20: var(--color-information-20);
371
+ --color-information-30: var(--color-information-30);
372
+ --color-information-40: var(--color-information-40);
373
+ --color-information-50: var(--color-information-50);
374
+ --color-information-60: var(--color-information-60);
375
+ --color-information-70: var(--color-information-70);
376
+ --color-information-80: var(--color-information-80);
377
+ --color-information-90: var(--color-information-90);
378
+ --color-information-95: var(--color-information-95);
379
+ --color-point-5: var(--color-point-5);
380
+ --color-point-10: var(--color-point-10);
381
+ --color-point-20: var(--color-point-20);
382
+ --color-point-30: var(--color-point-30);
383
+ --color-point-40: var(--color-point-40);
384
+ --color-point-50: var(--color-point-50);
385
+ --color-point-60: var(--color-point-60);
386
+ --color-point-70: var(--color-point-70);
387
+ --color-point-80: var(--color-point-80);
388
+ --color-point-90: var(--color-point-90);
389
+ --color-point-95: var(--color-point-95);
390
+ }
@@ -0,0 +1,20 @@
1
+ # change-token
2
+
3
+ > **언제 쓰나** — 색상, 폰트, 브레이크포인트 등 INFOUX 토큰을 추가·변경·재매핑할 때 사용. foundation, semantic alias, 생성 CSS와 starter 영향 범위를 먼저 확인한다.
4
+
5
+ ## 절차
6
+
7
+ 1. 변경 목적이 **브랜드 교체**(brand.json)인지 **표준 변경**(foundation.json)인지 먼저 가른다. 프로젝트 사정이면 brand.json만 고친다.
8
+ 2. `references/krds-tokens.md`와 `tokens/foundation.json`·`tokens/brand.json`에서 기존 토큰으로 해결 가능한지 확인한다.
9
+ 3. 사용처를 검색하고 대비, 상태, 다크 표면 등 영향 범위를 기록한다.
10
+ 4. 원본(`brand.json` 또는 `foundation.json`)만 수정하고 생성물은 빌드로 갱신한다. 브랜드 팔레트는 light·high-contrast 두 모드를 함께 채운다.
11
+ 5. `npm run build:tokens` → `npm run check:contrast` 후 원본과 starter의 drift를 확인한다.
12
+
13
+ ## 금지
14
+
15
+ - CSS에서 raw 색상으로 우회
16
+ - 기존 의미와 다른 용도로 semantic token 재사용
17
+ - 생성된 `tokens/build/tokens.css` 직접 수정
18
+ - 사용처 조사 없이 토큰 삭제 또는 이름 변경
19
+ - 상태색(danger/warning/success/information)을 브랜드색으로 재정의 — 발주처 CI 요구는 `point`로 받는다
20
+ - 대비 위반을 `tokens/contrast-baseline.json`에 추가해 덮기
@@ -0,0 +1,71 @@
1
+ # create-component
2
+
3
+ > **언제 쓰나** — BEM 컴포넌트 일괄 생성. 컴포넌트명 입력 시 CSS + 스니펫 + playground HTML + site 문서 페이지를 생성한다. "컴포넌트 추가", "새 컴포넌트", "create component" 요청 시 사용.
4
+
5
+ INFOUX 카탈로그를 먼저 확인한 뒤 재사용 가치가 있는 BEM 컴포넌트를 추가한다.
6
+
7
+ ## 사전 판단
8
+
9
+ 1. `references/project-profiles.md`에서 사이트 유형을 판정한다.
10
+ 2. `references/krds-components.md`에서 기존 컴포넌트 조합으로 해결 가능한지 확인한다.
11
+ 3. 신규 패턴이면 일회성 프로젝트 패턴인지 공통 컴포넌트 후보인지 사용자에게 보고한다.
12
+ 4. 공통 컴포넌트로 확정된 경우에만 아래 파일을 생성한다.
13
+
14
+ ## 생성 파일
15
+
16
+ | 파일 | 용도 |
17
+ |------|------|
18
+ | `src/styles/6-components/{name}.css` | Tailwind v4 + 표준 CSS nesting 스타일 |
19
+ | `src/snippets/{name}.md` | HTML, variant, 접근성, 키보드 동작 |
20
+ | `src/playground/{name}.html` | 브라우저 미리보기 |
21
+ | `site/components/{name}.md` | 문서 사이트 페이지 |
22
+
23
+ ## CSS 기준
24
+
25
+ ```css
26
+ /* {name} 컴포넌트 */
27
+ .{name} {
28
+ @apply relative;
29
+ color: var(--color-text);
30
+
31
+ &__body {
32
+ @apply flex flex-col;
33
+ gap: 1.6rem;
34
+ }
35
+
36
+ &--selected {
37
+ border-color: var(--color-border-primary);
38
+ }
39
+
40
+ @media (min-width: 1280px) {
41
+ &__body {
42
+ @apply flex-row;
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ - SCSS, `@use`, `@forward`, 믹스인을 사용하지 않는다.
49
+ - 레이아웃·정렬·표시 속성은 `@apply`를 우선한다.
50
+ - 색상은 `var(--color-*)`, 기본 폰트는 `var(--font-sans)`를 사용한다.
51
+ - 간격·크기·타이포·반경은 프로젝트 맥락의 직접값을 허용한다.
52
+ - 상태는 BEM modifier와 ARIA 속성을 함께 사용한다.
53
+ - 컴포넌트 파일을 `src/styles/6-components/index.css`에 `@import`한다.
54
+
55
+ ## 마크업 기준
56
+
57
+ - root 태그와 ARIA는 `references/html-semantics.md`를 따른다.
58
+ - 인터랙티브 요소는 `button`, `a`, native form control을 사용한다.
59
+ - 이미지 `alt`, 폼 label, 키보드 조작, 44px 터치 영역을 확인한다.
60
+ - 위젯은 WAI-ARIA APG 관계 속성과 연결 대상 id까지 작성한다.
61
+
62
+ ## 검증
63
+
64
+ ```bash
65
+ npm run check
66
+ npm run lint
67
+ npm run build
68
+ npm run test:unit
69
+ ```
70
+
71
+ 위반이나 기존 카탈로그와의 중복이 있으면 생성 완료로 보고하지 않는다.
@@ -0,0 +1,20 @@
1
+ # design-form
2
+
3
+ > **언제 쓰나** — 입력폼, 신청, 문의, 검색 조건, 로그인, 결제 정보 등 form UI를 설계하거나 수정할 때 사용. label, 도움말, 오류, 필수 상태와 제출 흐름을 구현 전에 확정한다.
4
+
5
+ ## 구현 전 결정
6
+
7
+ 1. 폼의 목적과 제출 후 결과를 Task Contract의 `primaryTask`에 기록한다.
8
+ 2. 필드 목록, 필수 여부, 입력 형식, 도움말, 오류 메시지를 정한다.
9
+ 3. 관련 필드는 `fieldset`과 `legend`로 그룹화한다.
10
+ 4. `references/html-semantics.md`의 form, select, check-radio 패턴을 선택한다.
11
+ 5. 오류 요약이 필요한 긴 폼인지 판정한다.
12
+
13
+ ## 필수 패턴
14
+
15
+ - 모든 컨트롤은 보이는 `label` 또는 동등한 접근 가능한 이름을 가진다.
16
+ - 도움말과 오류는 고유 id로 `aria-describedby`에 연결한다.
17
+ - 오류 상태는 BEM modifier와 `aria-invalid="true"`를 함께 사용한다.
18
+ - placeholder는 label을 대체하지 않는다.
19
+ - 제출은 native `form`과 `button type="submit"`을 사용한다.
20
+ - 모바일 인터랙티브 영역은 44x44px 이상이다.
@@ -0,0 +1,22 @@
1
+ # design-page
2
+
3
+ > **언제 쓰나** — INFOUX 기준으로 새 페이지, 화면, 랜딩, 상세, 목록, 관리자 화면을 설계하거나 구현할 때 사용. 코드 작성 전에 사이트 유형, 사용자 핵심 과업, page shell, section 패턴과 재사용 컴포넌트를 확정한다.
4
+
5
+ 페이지 코드를 바로 작성하지 않는다. 먼저 `contracts/task-contract.md` 형식으로 Task Contract를 선언한다.
6
+
7
+ ## 절차
8
+
9
+ 1. `references/project-profiles.md`에서 사이트 유형과 기본 section 흐름을 판정한다.
10
+ 2. 사용자의 핵심 과업을 한 문장으로 쓴다.
11
+ 3. `references/krds-components.md`에서 재사용할 컴포넌트를 고른다.
12
+ 4. `contracts/html-page-contract.json`으로 page shell과 section 구조를 확정한다.
13
+ 5. 인터랙티브 위젯이 있으면 `design-widget` 절차를 함께 적용한다.
14
+ 6. Task Contract의 필수 항목이 채워진 뒤에만 구현한다.
15
+
16
+ ## 생성 원칙
17
+
18
+ - `main` 직계 자식은 목적 기반 `section`이다.
19
+ - 각 section은 `.container`와 접근 가능한 이름을 가진다.
20
+ - 정부·공공 요소는 `publicIdentity: required`일 때만 생성한다.
21
+ - 기존 section·컴포넌트 조합으로 해결할 수 있으면 새 block을 만들지 않는다.
22
+ - 구현 후 검사는 선택을 대신하는 단계가 아니라 마지막 확인 단계다.
@@ -0,0 +1,19 @@
1
+ # design-widget
2
+
3
+ > **언제 쓰나** — modal, tab, accordion, disclosure, tooltip, carousel, calendar, combobox 같은 인터랙티브 위젯을 설계하거나 구현할 때 사용. 상태 모델, ARIA 관계, 키보드와 포커스 이동을 코드 전에 확정한다.
4
+
5
+ ## 구현 전 결정
6
+
7
+ 1. native HTML로 해결 가능한지 먼저 확인한다.
8
+ 2. `references/html-semantics.md`에서 해당 위젯 패턴을 선택한다.
9
+ 3. Task Contract의 `interactive`에 위젯명과 상태를 기록한다.
10
+ 4. 트리거, 제어 대상, id 관계, 초기 상태, 종료 조건을 정한다.
11
+ 5. Tab, Enter, Space, Escape, 화살표 키와 포커스 복귀 규칙을 정한다.
12
+
13
+ ## 필수 패턴
14
+
15
+ - 시각 상태는 의미 기반 BEM modifier로 표현한다.
16
+ - 의미 상태는 `aria-expanded`, `aria-selected`, `aria-pressed`, `aria-hidden` 등으로 표현한다.
17
+ - `aria-controls`, `aria-labelledby`의 대상 id가 실제로 존재해야 한다.
18
+ - modal은 열릴 때 내부로 포커스를 이동하고 닫힐 때 트리거로 복귀한다.
19
+ - 단순 표시/숨김을 이유로 불필요한 ARIA widget role을 만들지 않는다.