@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.
- package/README.md +81 -0
- package/bin/server.js +331 -0
- package/data/contract.md +215 -0
- package/data/manifest.json +286 -0
- package/data/references/accessibility.md +243 -0
- package/data/references/forbidden-patterns.md +462 -0
- package/data/references/guide-import.md +93 -0
- package/data/references/html-semantics.md +475 -0
- package/data/references/krds-components.md +1426 -0
- package/data/references/krds-source.md +1125 -0
- package/data/references/krds-tokens.md +201 -0
- package/data/references/project-profiles.md +99 -0
- package/data/references/snippet-template.md +185 -0
- package/data/references/tailwind-mapping.md +53 -0
- package/data/rules.json +780 -0
- package/data/snippets/accordion.md +49 -0
- package/data/snippets/alert.md +37 -0
- package/data/snippets/badge.md +29 -0
- package/data/snippets/boilerplate.md +125 -0
- package/data/snippets/breadcrumb.md +26 -0
- package/data/snippets/btn.md +63 -0
- package/data/snippets/calendar.md +64 -0
- package/data/snippets/card.md +50 -0
- package/data/snippets/carousel.md +43 -0
- package/data/snippets/check-radio.md +55 -0
- package/data/snippets/disclosure.md +44 -0
- package/data/snippets/file-upload.md +34 -0
- package/data/snippets/form.md +68 -0
- package/data/snippets/header.md +56 -0
- package/data/snippets/list.md +64 -0
- package/data/snippets/main-menu.md +49 -0
- package/data/snippets/modal.md +54 -0
- package/data/snippets/pagination.md +41 -0
- package/data/snippets/progress.md +30 -0
- package/data/snippets/select.md +34 -0
- package/data/snippets/side-panel.md +57 -0
- package/data/snippets/spinner.md +24 -0
- package/data/snippets/step-indicator.md +38 -0
- package/data/snippets/switch.md +32 -0
- package/data/snippets/tab.md +52 -0
- package/data/snippets/table.md +63 -0
- package/data/snippets/tag.md +42 -0
- package/data/snippets/toast.md +48 -0
- package/data/snippets/tooltip.md +38 -0
- package/data/tokens.css +390 -0
- package/data/workflows/change-token.md +20 -0
- package/data/workflows/create-component.md +71 -0
- package/data/workflows/design-form.md +20 -0
- package/data/workflows/design-page.md +22 -0
- package/data/workflows/design-widget.md +19 -0
- package/data/workflows/init-project.md +68 -0
- package/data/workflows/review-ui.md +14 -0
- 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`
|
package/data/tokens.css
ADDED
|
@@ -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을 만들지 않는다.
|