kwon-ui 0.0.0-stage → 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/CATALOG.md +301 -0
- package/CHANGELOG.md +31 -0
- package/LICENSE +4 -0
- package/README.md +71 -2
- package/bin/kwon-ui.mjs +60 -0
- package/check/index.mjs +233 -0
- package/claude/ADOPTING.md +99 -0
- package/claude/APP-CLAUDE.md +15 -0
- package/claude/hook.mjs +46 -0
- package/dist/classes.json +69 -0
- package/dist/kwon-ui.css +438 -0
- package/dist/react/controls.d.ts +20 -0
- package/dist/react/controls.js +19 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +5 -0
- package/dist/react/layout.d.ts +56 -0
- package/dist/react/layout.js +48 -0
- package/dist/react/tone.d.ts +13 -0
- package/dist/react/tone.js +21 -0
- package/dist/react/type.d.ts +27 -0
- package/dist/react/type.js +28 -0
- package/dist/react/util.d.ts +10 -0
- package/dist/react/util.js +4 -0
- package/package.json +62 -4
package/CATALOG.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# kwon-ui 카탈로그
|
|
2
|
+
|
|
3
|
+
버전 0.1.0. 이 파일은 `npm run build` 가 `src/catalog/manifest.tsx` 에서 만든다. 직접 고치지 않는다.
|
|
4
|
+
|
|
5
|
+
화면을 만들기 전에 이 목록에서 고른다. 여기 없는 조각이 필요하면 페이지에서 새로 만들지 않고, kwon-ui 에 추가를 제안한다.
|
|
6
|
+
|
|
7
|
+
## 쓰는 법
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "kwon-ui/kwon-ui.css"; // 앱의 레이아웃에서 한 번
|
|
11
|
+
import { Page, PageHead, Section, SectionHead, Rows, Row, Pill, TextLink } from "kwon-ui";
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- 페이지 맨 바깥에 `.night` 가 있어야 한다(`<Page>` 가 붙인다).
|
|
15
|
+
- 색, 글자 크기, 모서리, 폭은 토큰(`var(--n-…)`)으로만 쓴다. 값을 직접 쓰지 않는다.
|
|
16
|
+
- 링크는 `as` 로 프레임워크의 링크 컴포넌트를 넘긴다: `<Pill as={Link} href="/contact">`.
|
|
17
|
+
- 조각에는 바깥 여백(margin)이 없다. 조각 사이 간격은 앱에서 준다.
|
|
18
|
+
- 제목은 `"**진한 낱말** 나머지"` 꼴의 한 줄로 쓴다. 진한 글자는 핵심 낱말 한두 개에만 준다.
|
|
19
|
+
|
|
20
|
+
## 한눈에
|
|
21
|
+
|
|
22
|
+
| 조각 | 컴포넌트 | 클래스 | 언제 |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| 첫 화면 제목 | `<Display>` | `.n-display` | 첫 화면의 제목. 한 페이지에 한 번만 씁니다. |
|
|
25
|
+
| 구간 제목 | `<Title>` | `.n-title` | 구간과 페이지의 제목. 한 문장 한 줄로 쓰고, ** 로 감싼 핵심 낱말 한두 개만 진하게 둡니다. |
|
|
26
|
+
| 본문 | `<Body>` | `.n-body` | 읽는 문단. 한 구간에 한두 문단까지 둡니다. |
|
|
27
|
+
| 작은 제목 | `<CardTitle>` | `.n-card-title` | 목록 줄이나 카드 안의 제목. 본문과 같은 크기이고 진한 글자입니다. |
|
|
28
|
+
| 작은 글 | `<Small>` | `.n-small` | 캡션, 기준, 라벨. 숫자 폭을 맞춰야 하면 num 을 줍니다. |
|
|
29
|
+
| 페이지와 페이지 머리 | `<Page>` `<PageHead>` | `.n-page` | 하위 페이지의 맨 바깥과 머리. 제목 한 줄, 문단 하나, 버튼 줄로 시작합니다. |
|
|
30
|
+
| 구간 | `<Section>` | `.n-sect` | 페이지를 이루는 구간 하나. 위아래 여백(넓은 화면 128/96px)과 내용 폭을 줍니다. |
|
|
31
|
+
| 구간 머리 | `<SectionHead>` | `.n-head` | 구간의 시작. 왼쪽에 한 줄 제목, 오른쪽에 본문. rule 을 주면 가는 선 아래에서 시작합니다. |
|
|
32
|
+
| 가는 선 | (클래스만) | `.n-rule` | 내용 위에 가는 선 하나를 긋습니다. 구간 머리의 선은 SectionHead 의 rule 로 긋습니다. |
|
|
33
|
+
| 줄 목록 | `<Rows>` `<Row>` | `.n-rows` | 항목이 여럿일 때. 왼쪽 200px 에 작은 라벨, 오른쪽에 본문 한 칸. |
|
|
34
|
+
| 검은 판 | `<Panel>` | `.n-panel` | 앞뒤 구간과 구분해야 하는 구간 하나(후기, 수강료처럼). 한 페이지에 두세 번까지. |
|
|
35
|
+
| 그림 틀 | `<Media>` | `.n-media` | 그림과 영상을 담는 틀. 기본 4:3, wide 는 16:9. 안의 img, video 가 틀을 채웁니다. |
|
|
36
|
+
| 연도별 이력 | (클래스만) | `.n-timeline` | 해마다 쌓인 이력. 왼쪽에 연도, 오른쪽에 그 해의 줄들. 많으면 앞의 몇 줄만 보이고 '외 N건'으로 접습니다. |
|
|
37
|
+
| 문의 띠 | `<CtaBand>` | `.n-cta-band` | 페이지 끝의 마지막 행동. 왼쪽에 한 줄 문장, 오른쪽에 버튼 줄. 한 페이지에 하나. |
|
|
38
|
+
| 알약 버튼 | `<Pill>` | `.n-pill` | 한 화면의 주 행동 하나. 높이 48px. ghost 는 어두운 면(둘째 행동이 꼭 버튼이어야 할 때). |
|
|
39
|
+
| 글자 링크 | `<TextLink>` | `.n-link` | 버튼 옆의 둘째 행동, 본문 아래의 '더 보기'. arrow 를 주면 끝에 화살표가 붙습니다. |
|
|
40
|
+
| 버튼 줄 | `<Actions>` | `.n-actions` | 버튼과 글자 링크를 나란히 놓는 줄. 버튼 하나와 링크 하나까지. |
|
|
41
|
+
|
|
42
|
+
## 글자
|
|
43
|
+
|
|
44
|
+
읽는 글자 크기는 셋입니다. 제목, 본문, 작은 글. 위계는 굵기 대신 진한 글자와 회색 두 톤으로 만듭니다.
|
|
45
|
+
|
|
46
|
+
### 첫 화면 제목
|
|
47
|
+
|
|
48
|
+
`<Display>` · `.n-display`
|
|
49
|
+
|
|
50
|
+
첫 화면의 제목. 한 페이지에 한 번만 씁니다. 구간 제목에는 쓰지 않습니다(Title).
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<Display line="**기술과 사람** 사이를 공부합니다" />
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 구간 제목
|
|
57
|
+
|
|
58
|
+
`<Title>` · `.n-title` `.lo-inline`
|
|
59
|
+
|
|
60
|
+
구간과 페이지의 제목. 한 문장 한 줄로 쓰고, ** 로 감싼 핵심 낱말 한두 개만 진하게 둡니다. 제목과 부제를 두 줄로 쌓지 않습니다. 숫자는 숫자가 요점일 때만 진하게 둡니다.
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
<Title line="**문헌 조사**부터 **논문 작성**까지 다룹니다" label="교육 내용" />
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 본문
|
|
67
|
+
|
|
68
|
+
`<Body>` · `.n-body`
|
|
69
|
+
|
|
70
|
+
읽는 문단. 한 구간에 한두 문단까지 둡니다.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<Body>현재 업무와 자료를 함께 살펴보고 먼저 만들 것을 정합니다.</Body>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 작은 제목
|
|
77
|
+
|
|
78
|
+
`<CardTitle>` · `.n-card-title`
|
|
79
|
+
|
|
80
|
+
목록 줄이나 카드 안의 제목. 본문과 같은 크기이고 진한 글자입니다.
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
<CardTitle>임원 AI 워크숍</CardTitle>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 작은 글
|
|
87
|
+
|
|
88
|
+
`<Small>` · `.n-small` `.n-num`
|
|
89
|
+
|
|
90
|
+
캡션, 기준, 라벨. 숫자 폭을 맞춰야 하면 num 을 줍니다. 본문을 작은 글로 줄여 넣지 않습니다. 길면 빼거나 접습니다.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<Small>홈페이지로 접수된 문의 기준입니다.</Small>
|
|
94
|
+
<Small num>2022 ~ 2026</Small>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 뼈대
|
|
98
|
+
|
|
99
|
+
글은 한 줄기로 흐릅니다. 왼쪽에 제목이나 작은 라벨, 오른쪽 한 칸에 본문을 둡니다.
|
|
100
|
+
|
|
101
|
+
### 페이지와 페이지 머리
|
|
102
|
+
|
|
103
|
+
`<Page>`, `<PageHead>` · `.night` `.n-page` `.n-page-head` `.n-wrap`
|
|
104
|
+
|
|
105
|
+
하위 페이지의 맨 바깥과 머리. 제목 한 줄, 문단 하나, 버튼 줄로 시작합니다.
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
<Page>
|
|
109
|
+
<PageHead
|
|
110
|
+
title="교육 과정"
|
|
111
|
+
lead="직무와 수준에 맞춰 고르실 수 있습니다."
|
|
112
|
+
actions={<Pill as={Link} href="/contact">교육 문의하기</Pill>}
|
|
113
|
+
/>
|
|
114
|
+
…
|
|
115
|
+
</Page>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 구간
|
|
119
|
+
|
|
120
|
+
`<Section>` · `.n-sect` `.n-wrap`
|
|
121
|
+
|
|
122
|
+
페이지를 이루는 구간 하나. 위아래 여백(넓은 화면 128/96px)과 내용 폭을 줍니다. 여백을 구간마다 따로 정하지 않습니다.
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<Section id="courses">
|
|
126
|
+
<SectionHead title="**직무별** 교육 과정" />
|
|
127
|
+
…
|
|
128
|
+
</Section>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 구간 머리
|
|
132
|
+
|
|
133
|
+
`<SectionHead>` · `.n-head` `.ruled` `.n-title` `.n-body`
|
|
134
|
+
|
|
135
|
+
구간의 시작. 왼쪽에 한 줄 제목, 오른쪽에 본문. rule 을 주면 가는 선 아래에서 시작합니다. 본문에는 진한 강조를 두지 않습니다. 제목 칸에는 한 줄에 15자 안팎이 들어갑니다.
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
<SectionHead rule title="**연구실 상황**에 맞춰 범위를 정합니다" label="진행 방식">
|
|
139
|
+
<Body>연구 분야와 일정을 알려 주시면 범위와 시간을 함께 정합니다.</Body>
|
|
140
|
+
</SectionHead>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 가는 선
|
|
144
|
+
|
|
145
|
+
`.n-rule`
|
|
146
|
+
|
|
147
|
+
내용 위에 가는 선 하나를 긋습니다. 구간 머리의 선은 SectionHead 의 rule 로 긋습니다. 상자 테두리로 쓰지 않습니다. 구분은 선 하나와 여백으로 합니다.
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<div className="n-rule">…</div>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 줄 목록
|
|
154
|
+
|
|
155
|
+
`<Rows>`, `<Row>` · `.n-rows` `.n-row` `.n-row-label` `.wide-label`
|
|
156
|
+
|
|
157
|
+
항목이 여럿일 때. 왼쪽 200px 에 작은 라벨, 오른쪽에 본문 한 칸. 한 줄을 번호, 이름, 설명 세 칸으로 나누지 않습니다.
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
<Rows as="ol">
|
|
161
|
+
<Row as="li" label="업무 파악">현재 업무와 자료를 함께 살펴보고 먼저 만들 것을 정합니다.</Row>
|
|
162
|
+
<Row as="li" label="유연한 협업">필요한 만큼 만들고, 쓰면서 범위를 조정합니다.</Row>
|
|
163
|
+
</Rows>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 검은 판
|
|
167
|
+
|
|
168
|
+
`<Panel>` · `.n-panel` `.n-wrap`
|
|
169
|
+
|
|
170
|
+
앞뒤 구간과 구분해야 하는 구간 하나(후기, 수강료처럼). 한 페이지에 두세 번까지. 모든 구간을 판으로 감싸지 않습니다.
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
<Panel id="price">
|
|
174
|
+
<SectionHead title="한 번 결제로 **1년간 수강**합니다" />
|
|
175
|
+
…
|
|
176
|
+
</Panel>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 그림 틀
|
|
180
|
+
|
|
181
|
+
`<Media>` · `.n-media` `.wide`
|
|
182
|
+
|
|
183
|
+
그림과 영상을 담는 틀. 기본 4:3, wide 는 16:9. 안의 img, video 가 틀을 채웁니다.
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
<Media wide>
|
|
187
|
+
<video src="/lab.mp4" muted loop playsInline />
|
|
188
|
+
</Media>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 연도별 이력
|
|
192
|
+
|
|
193
|
+
`.n-timeline` `.n-tl-year` `.n-tl-more` `.chev`
|
|
194
|
+
|
|
195
|
+
해마다 쌓인 이력. 왼쪽에 연도, 오른쪽에 그 해의 줄들. 많으면 앞의 몇 줄만 보이고 '외 N건'으로 접습니다.
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
<div className="n-timeline">
|
|
199
|
+
<div className="n-tl-year">
|
|
200
|
+
<p className="n-card-title n-num">2026</p>
|
|
201
|
+
<ul>
|
|
202
|
+
<li className="n-body">임원 AI 워크숍</li>
|
|
203
|
+
<li className="n-tl-more">
|
|
204
|
+
<details>
|
|
205
|
+
<summary className="n-small">외 12건 <span className="chev" aria-hidden>→</span></summary>
|
|
206
|
+
…
|
|
207
|
+
</details>
|
|
208
|
+
</li>
|
|
209
|
+
</ul>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 문의 띠
|
|
215
|
+
|
|
216
|
+
`<CtaBand>` · `.n-cta-band` `.n-actions`
|
|
217
|
+
|
|
218
|
+
페이지 끝의 마지막 행동. 왼쪽에 한 줄 문장, 오른쪽에 버튼 줄. 한 페이지에 하나.
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
<CtaBand
|
|
222
|
+
title="**시간표**와 **견적서**를 바로 받아 보세요"
|
|
223
|
+
label="교육 문의"
|
|
224
|
+
actions={<>
|
|
225
|
+
<Pill as={Link} href="/contact">교육 문의하기</Pill>
|
|
226
|
+
<TextLink as={Link} href="/courses" arrow>교육 과정 보기</TextLink>
|
|
227
|
+
</>}
|
|
228
|
+
/>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## 조작부
|
|
232
|
+
|
|
233
|
+
버튼은 하나, 링크도 하나. 한 화면의 주 행동은 알약 버튼 하나입니다. 둘째 행동은 글자 링크로 둡니다.
|
|
234
|
+
|
|
235
|
+
### 알약 버튼
|
|
236
|
+
|
|
237
|
+
`<Pill>` · `.n-pill` `.ghost`
|
|
238
|
+
|
|
239
|
+
한 화면의 주 행동 하나. 높이 48px. ghost 는 어두운 면(둘째 행동이 꼭 버튼이어야 할 때). 흰 버튼 둘을 나란히 두지 않습니다.
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
<Pill as={Link} href="/contact">교육 문의하기</Pill>
|
|
243
|
+
<Pill as="button" type="button" ghost onClick={open}>진단 시작</Pill>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### 글자 링크
|
|
247
|
+
|
|
248
|
+
`<TextLink>` · `.n-link`
|
|
249
|
+
|
|
250
|
+
버튼 옆의 둘째 행동, 본문 아래의 '더 보기'. arrow 를 주면 끝에 화살표가 붙습니다.
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
<TextLink as={Link} href="/about" arrow>회사소개 보기</TextLink>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 버튼 줄
|
|
257
|
+
|
|
258
|
+
`<Actions>` · `.n-actions`
|
|
259
|
+
|
|
260
|
+
버튼과 글자 링크를 나란히 놓는 줄. 버튼 하나와 링크 하나까지.
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
<Actions>
|
|
264
|
+
<Pill as={Link} href="/signup">얼리버드로 신청하기</Pill>
|
|
265
|
+
<TextLink as={Link} href="#check" arrow>2분 무료 진단</TextLink>
|
|
266
|
+
</Actions>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## 토큰
|
|
270
|
+
|
|
271
|
+
값은 `src/css/tokens.css` 에만 있다. `.night` 안에서 쓴다.
|
|
272
|
+
|
|
273
|
+
| 이름 | 값 |
|
|
274
|
+
|---|---|
|
|
275
|
+
| `--n-bg` | `#000000` |
|
|
276
|
+
| `--n-panel` | `#0d0d0d` |
|
|
277
|
+
| `--n-card` | `#171717` |
|
|
278
|
+
| `--n-card-2` | `#202020` |
|
|
279
|
+
| `--n-line` | `rgba(255, 255, 255, 0.1)` |
|
|
280
|
+
| `--n-hi` | `#ffffff` |
|
|
281
|
+
| `--n-soft` | `rgba(255, 255, 255, 0.78)` |
|
|
282
|
+
| `--n-mid` | `rgba(255, 255, 255, 0.5)` |
|
|
283
|
+
| `--n-dim` | `rgba(255, 255, 255, 0.32)` |
|
|
284
|
+
| `--n-btn` | `#ffffff` |
|
|
285
|
+
| `--n-btn-ink` | `#000000` |
|
|
286
|
+
| `--n-btn-hover` | `#e9e9e9` |
|
|
287
|
+
| `--n-ghost` | `rgba(255, 255, 255, 0.08)` |
|
|
288
|
+
| `--n-ghost-hover` | `rgba(255, 255, 255, 0.16)` |
|
|
289
|
+
| `--n-focus` | `rgba(255, 255, 255, 0.55)` |
|
|
290
|
+
| `--n-fs-display` | `clamp(34px, 3.8vw, 50px)` |
|
|
291
|
+
| `--n-fs-title` | `clamp(26px, 2.4vw, 32px)` |
|
|
292
|
+
| `--n-fs-body` | `18px` |
|
|
293
|
+
| `--n-fs-small` | `14px` |
|
|
294
|
+
| `--n-fs-control` | `15px` |
|
|
295
|
+
| `--n-radius` | `32px` |
|
|
296
|
+
| `--n-radius-md` | `20px` |
|
|
297
|
+
| `--n-radius-pill` | `999px` |
|
|
298
|
+
| `--n-wrap` | `1064px` |
|
|
299
|
+
| `--n-gutter` | `24px` |
|
|
300
|
+
| `--n-edge` | `clamp(20px, 3.2vw, 48px)` |
|
|
301
|
+
| `--n-font` | `"Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif` |
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 바뀐 것
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-11-16)
|
|
4
|
+
|
|
5
|
+
첫 판. kwonandcompany.com 밤 테마에서 여러 화면이 같이 쓰는 핵심만 값 그대로 옮겼다.
|
|
6
|
+
|
|
7
|
+
- 토큰 27개: 바탕과 면, 글자 네 톤, 버튼, 글자 크기(display, title, body, small, control), 모서리, 폭과 바깥 여백.
|
|
8
|
+
- 글자: `n-display`, `n-title`(두 톤 `lo`, `lo-inline`), `n-body`, `n-card-title`, `n-small`, `n-num`.
|
|
9
|
+
- 뼈대: `n-wrap`, `n-page`, `n-page-head`, `n-sect`, `n-rule`, `n-head`, `n-rows`, `n-row`, `n-row-label`, `n-panel`, `n-media`, `n-cta-band`, `n-timeline`, `n-tl-year`, `n-tl-more`.
|
|
10
|
+
- 조작부: `n-pill`(`ghost`), `n-link`.
|
|
11
|
+
- 컴포넌트 17개: `Display`, `Title`, `Body`, `CardTitle`, `Small`, `Page`, `PageHead`, `Section`, `SectionHead`, `Rows`, `Row`, `Panel`, `Media`, `CtaBand`, `Pill`, `TextLink`, `Actions`. 그리고 `tone()`.
|
|
12
|
+
- 검사기 `kwon-ui check`(기준선 방식), Claude Code 훅 `claude/hook.mjs`.
|
|
13
|
+
|
|
14
|
+
근거와 확인
|
|
15
|
+
|
|
16
|
+
- 범위는 사용 수로 정했다. 홈페이지에서 `n-` 조각을 쓰는 TSX 45개 파일 가운데 `n-small`은 25개, `n-wrap` 24개, `n-body` 22개, `n-title` 21개, `n-head`와 `n-link` 18개, `n-pill` 15개 파일이 쓴다. 여러 화면이 쓰는 이름과, 다른 제품(스킬캠퍼스, Projects 랜딩)에도 있는 이름을 먼저 담았다.
|
|
17
|
+
- 같은 마크업에 홈페이지 원본 CSS와 이 패키지의 CSS를 각각 입혀 계산된 스타일을 대조했다(요소 38개, 속성 47개, 화면 폭 390·768·1024·1440). 다른 것은 줄바꿈 규칙 둘뿐이다: `word-break: keep-all`과 `text-wrap: balance`·`pretty`. 홈페이지는 같은 규칙을 전역 CSS에서 이미 준다.
|
|
18
|
+
|
|
19
|
+
홈페이지에 없던 이름(되풀이되던 조합에 이름을 붙였다. 값은 같다)
|
|
20
|
+
|
|
21
|
+
- `.n-head.ruled`: `n-head n-rule pt-12 md:pt-16`을 28곳에서 손으로 쓰던 것.
|
|
22
|
+
- `.n-actions`: 버튼과 글자 링크를 나란히 놓던 `flex flex-wrap items-center gap-x-8 gap-y-4`(18곳).
|
|
23
|
+
- `Rows`, `Row`: 네 페이지가 저마다 따로 정의해 쓰던 줄 목록 컴포넌트.
|
|
24
|
+
- `.n-sr`: 두 톤 제목 앞의 화면 낭독용 구간 이름(Tailwind `sr-only` 대신).
|
|
25
|
+
- `.n-page-head > .n-head`의 아래 여백 0, `.n-cta-band .n-title + .n-body`의 위 여백과 최대 폭: 인라인 스타일과 유틸리티로 쓰던 값.
|
|
26
|
+
- 글자 크기, 버튼 색, 모서리, 내용 폭 토큰: CSS에 직접 적혀 있던 값.
|
|
27
|
+
|
|
28
|
+
아직 담지 않은 것
|
|
29
|
+
|
|
30
|
+
- 떠 있는 메뉴(세 제품에 다 있지만 제품마다 링크와 동작이 다르다), 첫 화면, 탭, 읽는 페이지(흰 바탕) 조각.
|
|
31
|
+
- 한 제품에서만 쓰는 조각: 그 앱에 둔다.
|
package/LICENSE
ADDED
package/README.md
CHANGED
|
@@ -1,3 +1,72 @@
|
|
|
1
|
-
#
|
|
1
|
+
# kwon-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
권앤컴퍼니의 세 제품(kwonandcompany.com, 스킬캠퍼스, Projects)이 같이 쓰는 디자인 시스템입니다. 화면의 값과 조각을 한 곳에 두고, 앱은 발행된 버전을 받아 씁니다.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install kwon-ui --save-exact
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## 들어 있는 것
|
|
10
|
+
|
|
11
|
+
- **토큰과 CSS** (`kwon-ui/kwon-ui.css`): 색, 글자 크기 셋, 모서리, 폭. 글자(`n-title`, `n-body`, `n-small`), 뼈대(`n-sect`, `n-head`, `n-rows`, `n-panel`), 조작부(`n-pill`, `n-link`).
|
|
12
|
+
- **컴포넌트** (`kwon-ui`): `Page`, `PageHead`, `Section`, `SectionHead`, `Rows`, `Row`, `Panel`, `Media`, `CtaBand`, `Pill`, `TextLink`, `Actions`, `Title`, `Body`, `Small` 등. 서버에서 그려지는 평범한 마크업입니다.
|
|
13
|
+
- **목록** ([CATALOG.md](CATALOG.md)): 조각마다 언제 쓰는지와 사용 예. 화면을 만들기 전에 먼저 읽습니다.
|
|
14
|
+
- **검사기** (`kwon-ui check`): 앱 코드에서 색·글자 값을 직접 쓴 곳, 시스템 조각을 다시 정의한 곳을 찾습니다. 이미 있는 위반은 기준선에 적어 두고 늘어날 때만 실패합니다.
|
|
15
|
+
|
|
16
|
+
## 쓰는 법
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
// 레이아웃에서 한 번
|
|
20
|
+
import "kwon-ui/kwon-ui.css";
|
|
21
|
+
|
|
22
|
+
// 페이지
|
|
23
|
+
import Link from "next/link";
|
|
24
|
+
import { Page, PageHead, Section, SectionHead, Rows, Row, Pill } from "kwon-ui";
|
|
25
|
+
|
|
26
|
+
export default function CoursesPage() {
|
|
27
|
+
return (
|
|
28
|
+
<Page>
|
|
29
|
+
<PageHead
|
|
30
|
+
title="교육 과정"
|
|
31
|
+
lead="직무와 수준에 맞춰 고르실 수 있습니다."
|
|
32
|
+
actions={<Pill as={Link} href="/contact">교육 문의하기</Pill>}
|
|
33
|
+
/>
|
|
34
|
+
<Section>
|
|
35
|
+
<SectionHead rule title="**직무별** 교육 과정" />
|
|
36
|
+
<Rows>
|
|
37
|
+
<Row label="임원">조직의 AI 도입 방향을 정합니다.</Row>
|
|
38
|
+
<Row label="실무자">반복 업무를 AI에게 맡기는 방법을 익힙니다.</Row>
|
|
39
|
+
</Rows>
|
|
40
|
+
</Section>
|
|
41
|
+
</Page>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
글꼴(Pretendard)은 앱이 불러옵니다. 패키지에는 글꼴 파일이 없습니다.
|
|
47
|
+
|
|
48
|
+
## 검사
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx kwon-ui check # 기준선보다 위반이 늘면 실패
|
|
52
|
+
npx kwon-ui check --report # 규칙별 수만 보기
|
|
53
|
+
npx kwon-ui baseline # 지금의 위반 수를 기준선으로 적기
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
앱에 넣는 순서는 [claude/ADOPTING.md](claude/ADOPTING.md)에 있습니다.
|
|
57
|
+
|
|
58
|
+
## 카탈로그 보기
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install
|
|
62
|
+
npm run build
|
|
63
|
+
open site/index.html
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 고치기
|
|
67
|
+
|
|
68
|
+
조각을 더하거나 바꾸는 규칙은 [CLAUDE.md](CLAUDE.md)에 있습니다. 요점은 세 가지입니다. 새로 디자인하지 않고 운영 중인 화면에서 뽑아냅니다. 두 곳 이상에서 쓰는 것만 올립니다. 값은 `src/css/tokens.css`에만 둡니다.
|
|
69
|
+
|
|
70
|
+
## 사용 범위
|
|
71
|
+
|
|
72
|
+
© 2026 Kwon and Company Co., Ltd. 권앤컴퍼니 제품에 쓰려고 만든 것이며, 코드를 공개해 두었을 뿐 다른 곳에서의 사용을 허락하는 라이선스는 붙이지 않았습니다.
|
package/bin/kwon-ui.mjs
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// kwon-ui 명령.
|
|
3
|
+
// kwon-ui check [파일…] [--report] [--json] 검사한다. 기준선보다 위반이 늘면 종료 코드 1
|
|
4
|
+
// kwon-ui baseline 지금의 위반 수를 기준선으로 적는다
|
|
5
|
+
// kwon-ui classes 시스템 조각과 토큰 이름을 찍는다
|
|
6
|
+
import { loadSystem, RULES, run, WARNINGS, writeBaseline } from "../check/index.mjs";
|
|
7
|
+
|
|
8
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
9
|
+
const flags = new Set(rest.filter((a) => a.startsWith("--")));
|
|
10
|
+
const files = rest.filter((a) => !a.startsWith("--"));
|
|
11
|
+
|
|
12
|
+
function total(counts) {
|
|
13
|
+
const byRule = {};
|
|
14
|
+
for (const rules of Object.values(counts)) for (const [r, n] of Object.entries(rules)) byRule[r] = (byRule[r] ?? 0) + n;
|
|
15
|
+
return byRule;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
if (cmd === "check") {
|
|
20
|
+
const r = run({ files });
|
|
21
|
+
if (flags.has("--json")) {
|
|
22
|
+
console.log(JSON.stringify({ over: r.over, counts: r.counts, violations: r.violations }, null, 2));
|
|
23
|
+
process.exit(r.over.length && !flags.has("--report") ? 1 : 0);
|
|
24
|
+
}
|
|
25
|
+
const byRule = total(r.counts);
|
|
26
|
+
const sum = Object.values(byRule).reduce((a, b) => a + b, 0);
|
|
27
|
+
const warn = r.violations.filter((v) => v.rule in WARNINGS).length;
|
|
28
|
+
if (flags.has("--report")) {
|
|
29
|
+
console.log(`kwon-ui ${r.system.version} 검사 보고: 파일 ${r.targets.length}개, 위반 ${sum}건, 경고 ${warn}건`);
|
|
30
|
+
for (const [rule, n] of Object.entries(byRule).sort((a, b) => b[1] - a[1])) console.log(` ${String(n).padStart(5)} ${rule}`);
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
if (!r.over.length) {
|
|
34
|
+
const note = r.baseline ? ` (기준선에 남은 위반 ${sum}건)` : "";
|
|
35
|
+
console.log(`kwon-ui check: 통과${note}`);
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
console.error(`kwon-ui check: 디자인 시스템을 벗어난 곳이 ${r.baseline ? "기준선보다 늘었습니다" : "있습니다"}.\n`);
|
|
39
|
+
for (const o of r.over) {
|
|
40
|
+
console.error(`${o.file} [${o.rule}] ${o.base ? `${o.base}건 → ${o.count}건` : `${o.count}건`}`);
|
|
41
|
+
console.error(` ${RULES[o.rule]}`);
|
|
42
|
+
for (const v of r.violations.filter((x) => x.file === o.file && x.rule === o.rule).slice(0, 8)) console.error(` ${String(v.line).padStart(4)}: ${v.text}`);
|
|
43
|
+
console.error("");
|
|
44
|
+
}
|
|
45
|
+
console.error("조각과 토큰 목록은 node_modules/kwon-ui/CATALOG.md 에 있습니다. 필요한 조각이 없으면 페이지에서 만들지 말고 kwon-ui 에 추가를 제안합니다.");
|
|
46
|
+
process.exit(1);
|
|
47
|
+
} else if (cmd === "baseline") {
|
|
48
|
+
const b = writeBaseline();
|
|
49
|
+
console.log(`기준선을 ${b.path} 에 적었습니다: 파일 ${b.files}개, 위반 ${b.total}건. 이 수는 줄어들기만 해야 합니다.`);
|
|
50
|
+
} else if (cmd === "classes") {
|
|
51
|
+
const s = loadSystem();
|
|
52
|
+
console.log(`kwon-ui ${s.version}\n조각: ${[...s.classes].join(", ")}\n변형: ${[...s.modifiers].join(", ")}\n토큰: ${[...s.tokens].join(", ")}`);
|
|
53
|
+
} else {
|
|
54
|
+
console.log("사용: kwon-ui check [파일…] [--report] [--json] | kwon-ui baseline | kwon-ui classes");
|
|
55
|
+
process.exit(cmd ? 2 : 0);
|
|
56
|
+
}
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.error(`kwon-ui: ${e.message}`);
|
|
59
|
+
process.exit(2);
|
|
60
|
+
}
|