@makitt.io/mds-mcp-server 0.1.3 → 0.2.1

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 (55) hide show
  1. package/README.md +151 -34
  2. package/dist/catalog.d.ts +16 -0
  3. package/dist/catalog.d.ts.map +1 -0
  4. package/dist/catalog.js +383 -0
  5. package/dist/catalog.js.map +1 -0
  6. package/dist/data/catalog.json +41955 -4439
  7. package/dist/data/playbook/ai-fill.md +61 -48
  8. package/dist/data/playbook/anti-patterns.md +112 -110
  9. package/dist/data/playbook/array-input.md +94 -49
  10. package/dist/data/playbook/async-states.md +71 -61
  11. package/dist/data/playbook/data-grid.md +118 -101
  12. package/dist/data/playbook/feedback.md +103 -84
  13. package/dist/data/playbook/form.md +164 -134
  14. package/dist/data/playbook/overlay.md +97 -88
  15. package/dist/data/playbook/page-layout.md +95 -76
  16. package/dist/data/playbook/responsive-tokens.md +77 -58
  17. package/dist/data/recipes/admin-list-page.md +86 -0
  18. package/dist/data/recipes/async-state-section.md +60 -0
  19. package/dist/data/recipes/dashboard-overview.md +65 -0
  20. package/dist/data/recipes/detail-drawer.md +69 -0
  21. package/dist/data/recipes/modal-form.md +67 -0
  22. package/dist/data/recipes/settings-form-page.md +79 -0
  23. package/dist/index.d.ts +4 -23
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +31 -338
  26. package/dist/index.js.map +1 -1
  27. package/dist/loaders.d.ts +8 -0
  28. package/dist/loaders.d.ts.map +1 -0
  29. package/dist/loaders.js +120 -0
  30. package/dist/loaders.js.map +1 -0
  31. package/dist/recipes.d.ts +13 -0
  32. package/dist/recipes.d.ts.map +1 -0
  33. package/dist/recipes.js +82 -0
  34. package/dist/recipes.js.map +1 -0
  35. package/dist/responses.d.ts +8 -0
  36. package/dist/responses.d.ts.map +1 -0
  37. package/dist/responses.js +25 -0
  38. package/dist/responses.js.map +1 -0
  39. package/dist/text.d.ts +4 -0
  40. package/dist/text.d.ts.map +1 -0
  41. package/dist/text.js +20 -0
  42. package/dist/text.js.map +1 -0
  43. package/dist/tool-definitions.d.ts +3 -0
  44. package/dist/tool-definitions.d.ts.map +1 -0
  45. package/dist/tool-definitions.js +199 -0
  46. package/dist/tool-definitions.js.map +1 -0
  47. package/dist/tools.d.ts +4 -0
  48. package/dist/tools.d.ts.map +1 -0
  49. package/dist/tools.js +233 -0
  50. package/dist/tools.js.map +1 -0
  51. package/dist/types.d.ts +107 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +10 -0
  54. package/dist/types.js.map +1 -0
  55. package/package.json +21 -16
@@ -2,94 +2,95 @@
2
2
 
3
3
  화면 위 떠다니는 컨테이너 선택 가이드.
4
4
 
5
- > mds 의 overlay 군 — **Modal / Drawer / Sheet / Dialog / Popover** 5종.
6
- > 각자 의도 분명. 헷갈리면 잘못된 mental model.
5
+ > mds 의 overlay 군 — **Modal / Drawer / Sheet / Dialog / Popover** 5종. 각자
6
+ > 의도 분명. 헷갈리면 잘못된 mental model.
7
7
 
8
8
  ---
9
9
 
10
10
  ## 1. 5 Overlay 의도 분리
11
11
 
12
- | Overlay | 의도 | mental model | 사용 예 |
13
- |---|---|---|---|
14
- | **Modal** | **메인 작업 중단 + 작은 sub-task** (form 입력, 확인) | 페이지 위 작은 창 | 회원 생성, 쿠폰 발급, 설정 변경 |
15
- | **Drawer** | **목록 컨텍스트 유지 + side-by-side 편집** | 메인 옆 슬라이드 | 주문 행 클릭 → drawer 에서 상세, variant 편집 |
16
- | **Sheet** | **모바일 bottom 시트** (mobile-friendly drawer) | 아래에서 올라오는 시트 | 모바일 의 모든 overlay (Modal / Drawer auto 변환) |
17
- | **Dialog** | **확인 / 알림 / prompt** (form 아님, action 만) | 짧은 결정 강제 | "정말 삭제?", "환불 처리하시겠습니까?" |
18
- | **Popover** | **inline 부가 정보 / 작은 picker** | trigger 옆 floating | DatePicker, ColorPicker, dropdown menu |
12
+ | Overlay | 의도 | mental model | 사용 예 |
13
+ | ----------- | ---------------------------------------------------- | ---------------------- | ------------------------------------------------- |
14
+ | **Modal** | **메인 작업 중단 + 작은 sub-task** (form 입력, 확인) | 페이지 위 작은 창 | 회원 생성, 쿠폰 발급, 설정 변경 |
15
+ | **Drawer** | **목록 컨텍스트 유지 + side-by-side 편집** | 메인 옆 슬라이드 | 주문 행 클릭 → drawer 에서 상세, variant 편집 |
16
+ | **Sheet** | **모바일 bottom 시트** (mobile-friendly drawer) | 아래에서 올라오는 시트 | 모바일 의 모든 overlay (Modal / Drawer auto 변환) |
17
+ | **Dialog** | **확인 / 알림 / prompt** (form 아님, action 만) | 짧은 결정 강제 | "정말 삭제?", "환불 처리하시겠습니까?" |
18
+ | **Popover** | **inline 부가 정보 / 작은 picker** | trigger 옆 floating | DatePicker, ColorPicker, dropdown menu |
19
19
 
20
20
  ### 결정 기준
21
21
 
22
- | 의도 | overlay |
23
- |---|---|
24
- | Form 입력 필요 (sub-entity 생성 / 수정) | Modal (페이지 작업 X) 또는 Drawer (목록 컨텍스트 유지) |
25
- | 확인 / 경고 / 짧은 prompt | Dialog (`Modal.confirm` / `Modal.alert` / `Modal.prompt`) |
26
- | 목록 + 행 클릭 → 상세 | Drawer |
27
- | 모바일 first | Sheet |
28
- | inline trigger 옆 작은 UI | Popover |
22
+ | 의도 | overlay |
23
+ | --------------------------------------- | --------------------------------------------------------- |
24
+ | Form 입력 필요 (sub-entity 생성 / 수정) | Modal (페이지 작업 X) 또는 Drawer (목록 컨텍스트 유지) |
25
+ | 확인 / 경고 / 짧은 prompt | Dialog (`Modal.confirm` / `Modal.alert` / `Modal.prompt`) |
26
+ | 목록 + 행 클릭 → 상세 | Drawer |
27
+ | 모바일 first | Sheet |
28
+ | inline trigger 옆 작은 UI | Popover |
29
29
 
30
30
  ---
31
31
 
32
32
  ## 2. 선택 표 (lookup)
33
33
 
34
- | 케이스 | 답 |
35
- |---|---|
36
- | "고객 새로 만들기 from 페이지" | Modal (sub-task) |
37
- | "고객 행 클릭 → 상세 편집" | Drawer (목록 컨텍스트 유지) |
38
- | "정말 삭제?" | `Modal.confirm` (Dialog) |
39
- | "환불 처리하시겠습니까?" + 사유 입력 | `Modal.prompt` (Dialog with input) |
40
- | "라이선스 만료 임박" 영속 알림 | Banner (Step 4.2 feedback) — Modal 아님 |
41
- | "DatePicker / TimePicker" | Popover (자체 컴포넌트가 사용) |
42
- | "DropdownMenu" | Popover (Menu.* 사용) |
43
- | "큰 form (상품 등록)" | page-form (overlay 아님) |
44
- | "모바일 의 form" | Sheet 또는 full-screen page-form |
45
- | "Variant 추가 in 상품 등록 form" | nested Drawer (modal 안 modal 금지) |
34
+ | 케이스 | 답 |
35
+ | ------------------------------------ | --------------------------------------- |
36
+ | "고객 새로 만들기 from 페이지" | Modal (sub-task) |
37
+ | "고객 행 클릭 → 상세 편집" | Drawer (목록 컨텍스트 유지) |
38
+ | "정말 삭제?" | `Modal.confirm` (Dialog) |
39
+ | "환불 처리하시겠습니까?" + 사유 입력 | `Modal.prompt` (Dialog with input) |
40
+ | "라이선스 만료 임박" 영속 알림 | Banner (Step 4.2 feedback) — Modal 아님 |
41
+ | "DatePicker / TimePicker" | Popover (자체 컴포넌트가 사용) |
42
+ | "DropdownMenu" | Popover (Menu.\* 사용) |
43
+ | "큰 form (상품 등록)" | page-form (overlay 아님) |
44
+ | "모바일 의 form" | Sheet 또는 full-screen page-form |
45
+ | "Variant 추가 in 상품 등록 form" | nested Drawer (modal 안 modal 금지) |
46
46
 
47
47
  ---
48
48
 
49
49
  ## 3. Modal — sub-task 표준
50
50
 
51
- | Slot | mds 컴포넌트 |
52
- |---|---|
53
- | Trigger | imperative API (`Modal.open(...)`) — overlay 가 stack-managed |
54
- | Root | `Modal.Root` (Radix Dialog 의 wrapper) |
55
- | Overlay (backdrop) | `Modal.Overlay` (자동) |
56
- | Container | `Modal.Content` (centered, size variant) |
57
- | Header | `Modal.Header` (title + close button) |
58
- | Body | `Modal.Body` |
59
- | Footer | `Modal.Footer` (cancel + confirm primary, 우측 정렬) |
51
+ | Slot | mds 컴포넌트 |
52
+ | ------------------ | ------------------------------------------------------------- |
53
+ | Trigger | imperative API (`Modal.open(...)`) — overlay 가 stack-managed |
54
+ | Root | `Modal.Root` (Radix Dialog 의 wrapper) |
55
+ | Overlay (backdrop) | `Modal.Overlay` (자동) |
56
+ | Container | `Modal.Content` (centered, size variant) |
57
+ | Header | `Modal.Header` (title + close button) |
58
+ | Body | `Modal.Body` |
59
+ | Footer | `Modal.Footer` (cancel + confirm primary, 우측 정렬) |
60
60
 
61
61
  ### Size variant
62
62
 
63
- | Size | Width | 사용 |
64
- |---|---|---|
65
- | xs | 320px | 짧은 confirm dialog |
66
- | sm | 400px | 단순 form (3-5 필드) |
67
- | md (default) | 480px | 기본 form |
68
- | lg | 640px | 복잡 form / 데이터 list |
69
- | xl | 800px | 대형 (편집기 / 설정 다단) |
63
+ | Size | Width | 사용 |
64
+ | ------------ | ----- | ------------------------- |
65
+ | xs | 320px | 짧은 confirm dialog |
66
+ | sm | 400px | 단순 form (3-5 필드) |
67
+ | md (default) | 480px | 기본 form |
68
+ | lg | 640px | 복잡 form / 데이터 list |
69
+ | xl | 800px | 대형 (편집기 / 설정 다단) |
70
70
 
71
- > Mobile 변형 — md 이상 = full-screen Sheet (자동 변환 — Step 3.4 의 useBreakpoint 활용)
71
+ > Mobile 변형 — md 이상 = full-screen Sheet (자동 변환 — Step 3.4 의
72
+ > useBreakpoint 활용)
72
73
 
73
74
  ---
74
75
 
75
76
  ## 4. Drawer — 목록 컨텍스트 표준
76
77
 
77
- | Slot | mds 컴포넌트 |
78
- |---|---|
79
- | Trigger | row click handler (의도된 사용) |
80
- | Root | `Drawer.Root` |
81
- | Container | `Drawer.Content` (side variant) |
82
- | Header | `Drawer.Header` (title + close) |
83
- | Body | `Drawer.Body` (scroll) |
84
- | Footer | `Drawer.Footer` (action — Modal 과 동일 패턴) |
78
+ | Slot | mds 컴포넌트 |
79
+ | --------- | --------------------------------------------- |
80
+ | Trigger | row click handler (의도된 사용) |
81
+ | Root | `Drawer.Root` |
82
+ | Container | `Drawer.Content` (side variant) |
83
+ | Header | `Drawer.Header` (title + close) |
84
+ | Body | `Drawer.Body` (scroll) |
85
+ | Footer | `Drawer.Footer` (action — Modal 과 동일 패턴) |
85
86
 
86
87
  ### Side variant
87
88
 
88
- | Side | 사용 | Default size |
89
- |---|---|---|
90
- | right (default) | 메인 옆 슬라이드 in (가장 일반) | 480px (--size-drawer-default-horizontal) |
91
- | left | 별 사용 안 함 (sidebar 와 헷갈림) | 480px |
92
- | top / bottom | 모바일 bottom Sheet / 알림 | 320px (--size-drawer-default-vertical) |
89
+ | Side | 사용 | Default size |
90
+ | --------------- | --------------------------------- | ---------------------------------------- |
91
+ | right (default) | 메인 옆 슬라이드 in (가장 일반) | 480px (--size-drawer-default-horizontal) |
92
+ | left | 별 사용 안 함 (sidebar 와 헷갈림) | 480px |
93
+ | top / bottom | 모바일 bottom Sheet / 알림 | 320px (--size-drawer-default-vertical) |
93
94
 
94
95
  ### Drawer vs Modal 결정
95
96
 
@@ -127,17 +128,18 @@ const reason = await Modal.prompt({
127
128
  });
128
129
  ```
129
130
 
130
- > mds 의 ConfirmDialog / AlertDialog / PromptDialog — `imperative API` (forwardRef-required 룰 예외).
131
+ > mds 의 ConfirmDialog / AlertDialog / PromptDialog — `imperative API`
132
+ > (forwardRef-required 룰 예외).
131
133
 
132
134
  ---
133
135
 
134
136
  ## 6. Popover — inline floating
135
137
 
136
- | Slot | mds 컴포넌트 |
137
- |---|---|
138
+ | Slot | mds 컴포넌트 |
139
+ | ------- | ---------------------------------------------- |
138
140
  | Trigger | `Popover.Trigger` (자체 컴포넌트 또는 asChild) |
139
- | Content | `Popover.Content` (자동 positioning by Radix) |
140
- | Arrow | `Popover.Arrow` (선택) |
141
+ | Content | `Popover.Content` (자동 positioning by Radix) |
142
+ | Arrow | `Popover.Arrow` (선택) |
141
143
 
142
144
  ### Popover vs Modal
143
145
 
@@ -150,33 +152,35 @@ const reason = await Modal.prompt({
150
152
 
151
153
  ### 허용 합성
152
154
 
153
- | 합성 | 사용 |
154
- |---|---|
155
- | Modal 안 Form | sub-task 의 form (modal-form) |
156
- | Drawer 안 Form | 목록 옆 편집 (drawer-form) |
157
- | Modal 안 Popover | DatePicker / DropdownMenu 가 modal 안 ok |
158
- | Drawer 안 Popover | 동일 |
155
+ | 합성 | 사용 |
156
+ | ----------------- | ------------------------------------------------------------ |
157
+ | Modal 안 Form | sub-task 의 form (modal-form) |
158
+ | Drawer 안 Form | 목록 옆 편집 (drawer-form) |
159
+ | Modal 안 Popover | DatePicker / DropdownMenu 가 modal 안 ok |
160
+ | Drawer 안 Popover | 동일 |
159
161
  | **nested Drawer** | 메인 form (page or drawer) 안 sub-entity 편집 (variant 추가) |
160
162
 
161
163
  ### 절대 금지
162
164
 
163
165
  - ❌ **Modal 안 Modal** — 3단 mental stack. drawer 또는 페이지 이동
164
166
  - ❌ **Drawer 안 Drawer** — 동일 이유
165
- - ❌ **Modal 안 Drawer** / **Drawer 안 Modal** — sub-overlay 의 layer / focus 충돌
166
- - ❌ **Popover 안 Popover** — Radix Popover Root 의 자식이 또 다른 Popover (auto-position 충돌)
167
+ - ❌ **Modal 안 Drawer** / **Drawer 안 Modal** — sub-overlay 의 layer / focus
168
+ 충돌
169
+ - ❌ **Popover 안 Popover** — Radix Popover Root 의 자식이 또 다른 Popover
170
+ (auto-position 충돌)
167
171
 
168
172
  ---
169
173
 
170
174
  ## 8. Mobile 변형
171
175
 
172
- | Desktop | Mobile (< md) |
173
- |---|---|
174
- | Modal (xs / sm) | 그대로 (작아서 모바일 OK) |
175
- | Modal (md+) | full-screen Sheet 또는 그대로 |
176
+ | Desktop | Mobile (< md) |
177
+ | --------------------- | ------------------------------ |
178
+ | Modal (xs / sm) | 그대로 (작아서 모바일 OK) |
179
+ | Modal (md+) | full-screen Sheet 또는 그대로 |
176
180
  | Drawer (right / left) | bottom Sheet (`side="bottom"`) |
177
- | Sheet | 그대로 |
178
- | Dialog | 그대로 |
179
- | Popover | 그대로 (자체 positioning) |
181
+ | Sheet | 그대로 |
182
+ | Dialog | 그대로 |
183
+ | Popover | 그대로 (자체 positioning) |
180
184
 
181
185
  > Mobile 변환 mechanism — `useIsBreakpointUp('md')` hook 으로 caller 가 명시.
182
186
  > 자동 변환 — mds 의 SheetAdapter 추가 (TBD).
@@ -186,7 +190,8 @@ const reason = await Modal.prompt({
186
190
  ## 9. 안티 패턴
187
191
 
188
192
  - ❌ Modal 안 Modal (nested form 강제)
189
- - ❌ Dialog (`Modal.confirm`) 안 form (input multiple) — `Modal.prompt` 또는 form Modal 사용
193
+ - ❌ Dialog (`Modal.confirm`) 안 form (input multiple) — `Modal.prompt` 또는
194
+ form Modal 사용
190
195
  - ❌ Popover 안 큰 form — Popover 의 의도 (작은 inline) 아님
191
196
  - ❌ Drawer 의 width 변경 (사용자 resize 가능) — caller 가 fix size
192
197
  - ❌ Modal close 시 force confirmation 없음 — `isDirty` 시 confirm
@@ -196,20 +201,22 @@ const reason = await Modal.prompt({
196
201
 
197
202
  ## 10. Cross-cutting
198
203
 
199
- | Axis | 적용 |
200
- |---|---|
201
- | **Responsive** | useIsBreakpointUp + side 변환 |
202
- | **A11y** | Radix Dialog 기반 — focus trap / aria / esc 자동 |
204
+ | Axis | 적용 |
205
+ | ------------------ | ----------------------------------------------------------------------- |
206
+ | **Responsive** | useIsBreakpointUp + side 변환 |
207
+ | **A11y** | Radix Dialog 기반 — focus trap / aria / esc 자동 |
203
208
  | **Imperative API** | Modal.confirm / Modal.open — overlay stack 관리 (caller 가 ref 안 받음) |
204
- | **Telemetry** | overlay 의 open/close 추적 (Step 7) |
209
+ | **Telemetry** | overlay 의 open/close 추적 (Step 7) |
205
210
 
206
211
  ---
207
212
 
208
213
  ## 11. TBD
209
214
 
210
- 1. **SheetAdapter 자동 변환** — `<Modal>` 가 mobile 에서 `<Sheet>` 자동 변환 컴포넌트 추가 여부
215
+ 1. **SheetAdapter 자동 변환** — `<Modal>` 가 mobile 에서 `<Sheet>` 자동 변환
216
+ 컴포넌트 추가 여부
211
217
  2. **isDirty 감지** — form 안 dirty 자동 confirm dialog (RHF 의 isDirty 의존)
212
- 3. **Modal stacking** 최대 depth — 1 default, 2 까지 허용? (현재 nested Drawer 만)
218
+ 3. **Modal stacking** 최대 depth — 1 default, 2 까지 허용? (현재 nested Drawer
219
+ 만)
213
220
  4. **Drawer resize handle** — 사용자 resize 가능 vs caller fix
214
221
  5. **Sheet 의 default snap point** — 30% / 60% / 100% (Vaul 같은 패턴)
215
222
 
@@ -218,5 +225,7 @@ const reason = await Modal.prompt({
218
225
  ## Related Playbooks
219
226
 
220
227
  - [form.md](./form.md) — Modal-form / Drawer-form / nested-drawer (Step 4.1)
221
- - [feedback.md](./feedback.md) — Toast / Notification / Banner / Modal Dialog (Step 4.2)
222
- - [page-layout.md](./page-layout.md) — Page Shell / Sidebar 와 overlay 관계 (Step 4.5)
228
+ - [feedback.md](./feedback.md) — Toast / Notification / Banner / Modal Dialog
229
+ (Step 4.2)
230
+ - [page-layout.md](./page-layout.md) — Page Shell / Sidebar 와 overlay 관계
231
+ (Step 4.5)
@@ -2,7 +2,8 @@
2
2
 
3
3
  페이지 layout 에 대한 약속.
4
4
 
5
- > 모든 셀러 admin 페이지가 **같은 layout structure** 따라야 균일. mds 의 shells 활용.
5
+ > 모든 셀러 admin 페이지가 **같은 layout structure** 따라야 균일. mds 의 shells
6
+ > 활용.
6
7
 
7
8
  ---
8
9
 
@@ -20,14 +21,14 @@
20
21
  </AppShell>
21
22
  ```
22
23
 
23
- | Shell 컴포넌트 | 역할 | 위치 |
24
- |---|---|---|
25
- | `AppShell` | top-level wrapper (Sidebar + Page) | route layout (Next.js) |
26
- | `Sidebar` | nav menu (sticky left) | desktop left, mobile drawer |
27
- | `Topbar` (선택) | global header (logo / user / breadcrumb) | top sticky |
28
- | `Page` | content area | sidebar 우측 |
29
- | `PageHeader` | title + breadcrumb + actions | content 상단 |
30
- | `Section` (선택) | content 안 의미 단위 분할 | Page 안 |
24
+ | Shell 컴포넌트 | 역할 | 위치 |
25
+ | ---------------- | ---------------------------------------- | --------------------------- |
26
+ | `AppShell` | top-level wrapper (Sidebar + Page) | route layout (Next.js) |
27
+ | `Sidebar` | nav menu (sticky left) | desktop left, mobile drawer |
28
+ | `Topbar` (선택) | global header (logo / user / breadcrumb) | top sticky |
29
+ | `Page` | content area | sidebar 우측 |
30
+ | `PageHeader` | title + breadcrumb + actions | content 상단 |
31
+ | `Section` (선택) | content 안 의미 단위 분할 | Page 안 |
31
32
 
32
33
  ---
33
34
 
@@ -35,19 +36,21 @@
35
36
 
36
37
  ### 결정 표
37
38
 
38
- | 페이지 종류 | max-width | 이유 |
39
- |---|---|---|
40
- | **DataGrid list 페이지** (customers / orders) | **full-bleed** (max-width X) | table 의 column 다 보임. 큰 모니터에서 더 좋음 |
41
- | **단순 form 페이지** (회원가입 / 단일 entity) | **640px** (modal-sm 와 같음) | 가독성 (긴 가로 input 어색) |
42
- | **복잡 form 페이지** (상품 등록 — Section + AnchorNav) | **content 자체 max-width X**, AnchorNav 좌측 + form 우측 (둘 다 fill) | 큰 form 은 넓은 공간 활용 |
43
- | **분석 / dashboard** (KPI + chart) | **full-bleed** | grid layout 의 cols 활용 |
44
- | **정보 페이지** (about / docs / blog) | **800-960px** | 글 가독성 |
39
+ | 페이지 종류 | max-width | 이유 |
40
+ | ------------------------------------------------------ | --------------------------------------------------------------------- | ---------------------------------------------- |
41
+ | **DataGrid list 페이지** (customers / orders) | **full-bleed** (max-width X) | table 의 column 다 보임. 큰 모니터에서 더 좋음 |
42
+ | **단순 form 페이지** (회원가입 / 단일 entity) | **640px** (modal-sm 와 같음) | 가독성 (긴 가로 input 어색) |
43
+ | **복잡 form 페이지** (상품 등록 — Section + AnchorNav) | **content 자체 max-width X**, AnchorNav 좌측 + form 우측 (둘 다 fill) | 큰 form 은 넓은 공간 활용 |
44
+ | **분석 / dashboard** (KPI + chart) | **full-bleed** | grid layout 의 cols 활용 |
45
+ | **정보 페이지** (about / docs / blog) | **800-960px** | 글 가독성 |
45
46
 
46
47
  → **default = full-bleed**. 가독성 필요한 경우 (form / 정보) 만 max-width.
47
48
 
48
49
  ### 이전 발견 (apps/web 의 max-width 답답함)
49
50
 
50
- 기존 apps/web 의 content 가 `max-w-7xl` (1280px) 같은 작은 fix → 1920px+ 모니터에서 양쪽 빔. **수정 필요**:
51
+ 기존 apps/web 의 content 가 `max-w-7xl` (1280px) 같은 작은 fix → 1920px+
52
+ 모니터에서 양쪽 빔. **수정 필요**:
53
+
51
54
  - DataGrid 페이지 → full-bleed
52
55
  - form 페이지 → 명시적 max-width (640 or 800)
53
56
 
@@ -55,25 +58,26 @@
55
58
 
56
59
  ## 3. Padding 표준
57
60
 
58
- | Level | Padding token | 사용 |
59
- |---|---|---|
60
- | Page (content area 의 outer) | `var(--space-6)` ~ `var(--space-8)` (24~32px) | desktop |
61
- | Page (mobile) | `var(--space-4)` (16px) | mobile |
62
- | Section gap | `var(--section-gap)` (theme 별 — admin-light = 48px) | section 사이 |
63
- | Card padding | `var(--space-4)` (16px) — default | Card 안 |
64
- | Form 안 row gap | `var(--space-3)` (12px) | field 사이 |
61
+ | Level | Padding token | 사용 |
62
+ | ---------------------------- | ---------------------------------------------------- | ------------ |
63
+ | Page (content area 의 outer) | `var(--space-6)` ~ `var(--space-8)` (24~32px) | desktop |
64
+ | Page (mobile) | `var(--space-4)` (16px) | mobile |
65
+ | Section gap | `var(--section-gap)` (theme 별 — admin-light = 48px) | section 사이 |
66
+ | Card padding | `var(--space-4)` (16px) — default | Card 안 |
67
+ | Form 안 row gap | `var(--space-3)` (12px) | field 사이 |
65
68
 
66
- > Padding 의 mobile 자동 — Page shell 의 prop 또는 SCSS `@media (max-width: 768px)` 분기.
69
+ > Padding 의 mobile 자동 — Page shell 의 prop 또는 SCSS
70
+ > `@media (max-width: 768px)` 분기.
67
71
 
68
72
  ---
69
73
 
70
74
  ## 4. Sidebar — desktop vs mobile
71
75
 
72
- | State | Desktop | Mobile |
73
- |---|---|---|
74
- | 항상 표시 | `Sidebar` (sticky left) | drawer (top trigger 의 hamburger menu) |
75
- | Collapsed (icon only) | `Sidebar collapsed` | drawer + 그대로 |
76
- | Active route | `Sidebar.SubItem` 의 `data-active="true"` (Sidebar.subItemActive style) | drawer 안 동일 |
76
+ | State | Desktop | Mobile |
77
+ | --------------------- | ----------------------------------------------------------------------- | -------------------------------------- |
78
+ | 항상 표시 | `Sidebar` (sticky left) | drawer (top trigger 의 hamburger menu) |
79
+ | Collapsed (icon only) | `Sidebar collapsed` | drawer + 그대로 |
80
+ | Active route | `Sidebar.SubItem` 의 `data-active="true"` (Sidebar.subItemActive style) | drawer 안 동일 |
77
81
 
78
82
  > Mobile 변환 — `useIsBreakpointUp('lg')` (1024px) — 그 미만 = drawer.
79
83
 
@@ -95,15 +99,16 @@
95
99
  />
96
100
  ```
97
101
 
98
- | Slot | 사용 |
99
- |---|---|
100
- | `title` | h1 — 페이지 이름 |
101
- | `description` | 부제 (optional) |
102
- | `breadcrumb` | 위치 (홈 → category → 현 페이지) |
103
- | `actions` | 우측 primary / secondary buttons (예: "+ 새 주문") |
104
- | `tabs` | (선택) 페이지 안 sub-section 탭 |
102
+ | Slot | 사용 |
103
+ | ------------- | -------------------------------------------------- |
104
+ | `title` | h1 — 페이지 이름 |
105
+ | `description` | 부제 (optional) |
106
+ | `breadcrumb` | 위치 (홈 → category → 현 페이지) |
107
+ | `actions` | 우측 primary / secondary buttons (예: "+ 새 주문") |
108
+ | `tabs` | (선택) 페이지 안 sub-section 탭 |
105
109
 
106
- > PageHeader 의 actions = **페이지 단위 primary action**. row-level action 은 DataGrid 의 column action.
110
+ > PageHeader 의 actions = **페이지 단위 primary action**. row-level action 은
111
+ > DataGrid 의 column action.
107
112
 
108
113
  ---
109
114
 
@@ -119,15 +124,25 @@
119
124
  ```tsx
120
125
  <Page>
121
126
  <PageHeader title="상품 등록" actions={<Button>저장</Button>} />
122
- <div style={{ display: 'grid', gridTemplateColumns: '200px 1fr', gap: 'var(--space-6)' }}>
127
+ <div
128
+ style={{
129
+ display: 'grid',
130
+ gridTemplateColumns: '200px 1fr',
131
+ gap: 'var(--space-6)',
132
+ }}
133
+ >
123
134
  <AnchorNav sticky>
124
135
  <AnchorNav.Item href="#basic">기본 정보</AnchorNav.Item>
125
136
  <AnchorNav.Item href="#images">이미지</AnchorNav.Item>
126
137
  {/* ... */}
127
138
  </AnchorNav>
128
139
  <div>
129
- <Section id="basic" title="기본 정보">...</Section>
130
- <Section id="images" title="이미지">...</Section>
140
+ <Section id="basic" title="기본 정보">
141
+ ...
142
+ </Section>
143
+ <Section id="images" title="이미지">
144
+ ...
145
+ </Section>
131
146
  {/* ... */}
132
147
  </div>
133
148
  </div>
@@ -140,38 +155,40 @@
140
155
 
141
156
  ## 7. 결정 표 (lookup)
142
157
 
143
- | 케이스 | 답 |
144
- |---|---|
145
- | "list 페이지 (DataGrid)" | full-bleed AppShell + PageHeader + DataGrid |
146
- | "단일 entity form" | AppShell + PageHeader + max-width 640 form |
147
- | "큰 form (상품 등록)" | AppShell + PageHeader + Section/AnchorNav layout |
148
- | "dashboard (KPI + chart)" | full-bleed AppShell + Grid cols=4 (KPI) + Grid cols=2 (chart) |
149
- | "단순 정보 페이지" | AppShell + max-width 800 + body text |
150
- | "mobile" | Sidebar → drawer (`useIsBreakpointUp('lg')`) + Page padding 축소 |
151
- | "settings 페이지 (다 section)" | AppShell + PageHeader + Section/AnchorNav (left nav) |
152
- | "page 안 sub-page tabs" | PageHeader 의 `tabs` slot |
158
+ | 케이스 | 답 |
159
+ | ------------------------------ | ---------------------------------------------------------------- |
160
+ | "list 페이지 (DataGrid)" | full-bleed AppShell + PageHeader + DataGrid |
161
+ | "단일 entity form" | AppShell + PageHeader + max-width 640 form |
162
+ | "큰 form (상품 등록)" | AppShell + PageHeader + Section/AnchorNav layout |
163
+ | "dashboard (KPI + chart)" | full-bleed AppShell + Grid cols=4 (KPI) + Grid cols=2 (chart) |
164
+ | "단순 정보 페이지" | AppShell + max-width 800 + body text |
165
+ | "mobile" | Sidebar → drawer (`useIsBreakpointUp('lg')`) + Page padding 축소 |
166
+ | "settings 페이지 (다 section)" | AppShell + PageHeader + Section/AnchorNav (left nav) |
167
+ | "page 안 sub-page tabs" | PageHeader 의 `tabs` slot |
153
168
 
154
169
  ---
155
170
 
156
171
  ## 8. Mobile 변형
157
172
 
158
- | Desktop | Mobile (< lg) |
159
- |---|---|
160
- | Sidebar (left sticky) | Drawer (top trigger의 hamburger) |
161
- | Page padding (24-32px) | Page padding 16px |
162
- | Section/AnchorNav (2-col) | Section only + AnchorNav drawer |
163
- | DataGrid (table) | Card list (data-grid.md §3) |
164
- | PageHeader (1줄) | PageHeader (vertical stack — title / breadcrumb / actions 분리) |
165
- | max-width 640 form | full-width form |
173
+ | Desktop | Mobile (< lg) |
174
+ | ------------------------- | --------------------------------------------------------------- |
175
+ | Sidebar (left sticky) | Drawer (top trigger의 hamburger) |
176
+ | Page padding (24-32px) | Page padding 16px |
177
+ | Section/AnchorNav (2-col) | Section only + AnchorNav drawer |
178
+ | DataGrid (table) | Card list (data-grid.md §3) |
179
+ | PageHeader (1줄) | PageHeader (vertical stack — title / breadcrumb / actions 분리) |
180
+ | max-width 640 form | full-width form |
166
181
 
167
182
  ---
168
183
 
169
184
  ## 9. 안티 패턴
170
185
 
171
- - ❌ **Page 마다 다른 layout** (사용자 mental model 깨짐) — 모든 페이지 같은 AppShell + PageHeader
186
+ - ❌ **Page 마다 다른 layout** (사용자 mental model 깨짐) — 모든 페이지 같은
187
+ AppShell + PageHeader
172
188
  - ❌ **DataGrid 페이지에 max-width** — content 가 자연스럽지 못함. full-bleed
173
189
  - ❌ **form 페이지에 max-width 없음** — 1920px 의 가로 input 한 줄 어색
174
- - ❌ **PageHeader 의 actions 가 row-level** (예: row 의 "edit" 버튼) — DataGrid column action
190
+ - ❌ **PageHeader 의 actions 가 row-level** (예: row 의 "edit" 버튼) — DataGrid
191
+ column action
175
192
  - ❌ **Sidebar 안 sub-Item 3 단계 이상** — 깊이 제한 (mental load)
176
193
  - ❌ **section 사이 gap 의 hardcoded px** — `var(--section-gap)` 사용
177
194
  - ❌ **page padding 의 hardcoded** — `var(--space-*)` token
@@ -181,36 +198,38 @@
181
198
 
182
199
  ## 10. Cross-cutting
183
200
 
184
- | Axis | 적용 |
185
- |---|---|
201
+ | Axis | 적용 |
202
+ | -------------- | ------------------------------------------------------------------------------- |
186
203
  | **Responsive** | Sidebar → drawer / padding 축소 / Section/AnchorNav 변환 / DataGrid → card list |
187
- | **A11y** | Sidebar `<nav>` semantic / PageHeader `<h1>` / Breadcrumb aria-label |
188
- | **i18n** | nav label / title / breadcrumb 모두 `t()` |
189
- | **Permission** | Sidebar.Item 의 권한별 hide (Step 7 Web Playbook) |
190
- | **Telemetry** | nav click / page view 자동 log (Step 7) |
204
+ | **A11y** | Sidebar `<nav>` semantic / PageHeader `<h1>` / Breadcrumb aria-label |
205
+ | **i18n** | nav label / title / breadcrumb 모두 `t()` |
206
+ | **Permission** | Sidebar.Item 의 권한별 hide (Step 7 Web Playbook) |
207
+ | **Telemetry** | nav click / page view 자동 log (Step 7) |
191
208
 
192
209
  ---
193
210
 
194
211
  ## 11. apps/web 의 실 사용 (Step 7 Web Playbook 의 baseline)
195
212
 
196
- | Route | Layout |
197
- |---|---|
198
- | `/merchant/customers`, `/merchant/orders` etc. | AppShell + PageHeader + DataGrid (full-bleed) |
199
- | `/merchant/products/new`, `/merchant/products/[id]` | AppShell + PageHeader + Section/AnchorNav (큰 form) |
200
- | `/merchant/shop/business-info`, `/merchant/account/security` | AppShell + PageHeader + max-width 640 단순 form |
201
- | `/merchant/dashboard` (home) | AppShell + PageHeader + Grid (KPI / chart) full-bleed |
202
- | `/merchant/shop` (settings 종합) | AppShell + PageHeader + Section/AnchorNav (다 section) |
213
+ | Route | Layout |
214
+ | ------------------------------------------------------------ | ------------------------------------------------------ |
215
+ | `/merchant/customers`, `/merchant/orders` etc. | AppShell + PageHeader + DataGrid (full-bleed) |
216
+ | `/merchant/products/new`, `/merchant/products/[id]` | AppShell + PageHeader + Section/AnchorNav (큰 form) |
217
+ | `/merchant/shop/business-info`, `/merchant/account/security` | AppShell + PageHeader + max-width 640 단순 form |
218
+ | `/merchant/dashboard` (home) | AppShell + PageHeader + Grid (KPI / chart) full-bleed |
219
+ | `/merchant/shop` (settings 종합) | AppShell + PageHeader + Section/AnchorNav (다 section) |
203
220
 
204
221
  ---
205
222
 
206
223
  ## 12. TBD
207
224
 
208
225
  1. **max-width 정확 px** — form 640? 720? 800? 페이지 종류별 정확 token
209
- 2. **Sidebar collapsed (icon only) trigger** — 자동 (viewport 작음) vs 사용자 button
226
+ 2. **Sidebar collapsed (icon only) trigger** — 자동 (viewport 작음) vs 사용자
227
+ button
210
228
  3. **PageHeader sticky** — 스크롤 시 항상 위 또는 page top 만
211
229
  4. **AnchorNav drawer (mobile)** — top trigger vs bottom Sheet
212
230
  5. **Section gap responsive** — desktop 48px / mobile 32px 자동
213
- 6. **container queries** — Page 안 Card 의 internal layout 이 Page width 아닌 Card width 기반
231
+ 6. **container queries** — Page 안 Card 의 internal layout 이 Page width 아닌
232
+ Card width 기반
214
233
 
215
234
  ---
216
235