@conscience-technology/ctds 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/README.md +128 -2
- package/assets/components/AppFrame/AppFrame.module.css +177 -0
- package/assets/components/AppFrame/AppFrame.tsx +93 -0
- package/assets/components/AppFrame/index.ts +6 -0
- package/assets/components/AttachmentChip/AttachmentChip.module.css +71 -0
- package/assets/components/AttachmentChip/AttachmentChip.tsx +74 -0
- package/assets/components/AttachmentChip/index.ts +2 -0
- package/assets/components/AttachmentThumb/AttachmentThumb.module.css +107 -0
- package/assets/components/AttachmentThumb/AttachmentThumb.tsx +91 -0
- package/assets/components/AttachmentThumb/index.ts +2 -0
- package/assets/components/Avatar/Avatar.module.css +167 -0
- package/assets/components/Avatar/Avatar.tsx +228 -0
- package/assets/components/Avatar/index.ts +2 -0
- package/assets/components/AvatarUpload/AvatarUpload.module.css +130 -0
- package/assets/components/AvatarUpload/AvatarUpload.tsx +139 -0
- package/assets/components/AvatarUpload/index.ts +2 -0
- package/assets/components/Badge/Badge.module.css +76 -0
- package/assets/components/Badge/Badge.tsx +68 -0
- package/assets/components/Badge/index.ts +2 -0
- package/assets/components/Breadcrumb/Breadcrumb.module.css +213 -0
- package/assets/components/Breadcrumb/Breadcrumb.tsx +279 -0
- package/assets/components/Breadcrumb/index.ts +8 -0
- package/assets/components/Button/Button.module.css +216 -0
- package/assets/components/Button/Button.tsx +149 -0
- package/assets/components/Button/index.ts +2 -0
- package/assets/components/Callout/Callout.module.css +146 -0
- package/assets/components/Callout/Callout.tsx +138 -0
- package/assets/components/Callout/index.ts +2 -0
- package/assets/components/ChatInput/ChatInput.module.css +241 -0
- package/assets/components/ChatInput/ChatInput.tsx +322 -0
- package/assets/components/ChatInput/ModelSelector.tsx +40 -0
- package/assets/components/ChatInput/SendButton.tsx +41 -0
- package/assets/components/ChatInput/index.ts +10 -0
- package/assets/components/Checkbox/Checkbox.module.css +66 -0
- package/assets/components/Checkbox/Checkbox.tsx +36 -0
- package/assets/components/Checkbox/index.ts +2 -0
- package/assets/components/Chip/Chip.module.css +128 -0
- package/assets/components/Chip/Chip.tsx +103 -0
- package/assets/components/Chip/index.ts +2 -0
- package/assets/components/ChoiceCard/ChoiceCard.module.css +142 -0
- package/assets/components/ChoiceCard/ChoiceCard.tsx +132 -0
- package/assets/components/ChoiceCard/index.ts +2 -0
- package/assets/components/ContextMenu/ContextMenu.module.css +102 -0
- package/assets/components/ContextMenu/ContextMenu.tsx +392 -0
- package/assets/components/ContextMenu/index.ts +9 -0
- package/assets/components/DatePicker/Calendar.tsx +234 -0
- package/assets/components/DatePicker/DESIGN_NOTES.md +106 -0
- package/assets/components/DatePicker/DESIGN_NOTES_TIME.md +125 -0
- package/assets/components/DatePicker/DatePicker.module.css +295 -0
- package/assets/components/DatePicker/DatePicker.tsx +387 -0
- package/assets/components/DatePicker/TimeSelector.tsx +69 -0
- package/assets/components/DatePicker/index.ts +8 -0
- package/assets/components/DatePicker/presets.ts +80 -0
- package/assets/components/DatePicker/utils.ts +148 -0
- package/assets/components/Disclosure/Disclosure.module.css +73 -0
- package/assets/components/Disclosure/Disclosure.tsx +129 -0
- package/assets/components/Disclosure/index.ts +6 -0
- package/assets/components/Drawer/Drawer.module.css +257 -0
- package/assets/components/Drawer/Drawer.tsx +126 -0
- package/assets/components/Drawer/index.ts +7 -0
- package/assets/components/EmptyState/EmptyState.module.css +102 -0
- package/assets/components/EmptyState/EmptyState.tsx +80 -0
- package/assets/components/EmptyState/index.ts +2 -0
- package/assets/components/FileIcon/FileIcon.module.css +66 -0
- package/assets/components/FileIcon/FileIcon.tsx +84 -0
- package/assets/components/FileIcon/fileExtMap.ts +112 -0
- package/assets/components/FileIcon/index.ts +9 -0
- package/assets/components/FilterButton/FilterButton.module.css +130 -0
- package/assets/components/FilterButton/FilterButton.tsx +94 -0
- package/assets/components/FilterButton/index.ts +2 -0
- package/assets/components/GalleryItem/GalleryItem.module.css +220 -0
- package/assets/components/GalleryItem/GalleryItem.tsx +163 -0
- package/assets/components/GalleryItem/index.ts +7 -0
- package/assets/components/Icon/Icon.tsx +616 -0
- package/assets/components/Icon/context.tsx +39 -0
- package/assets/components/Icon/index.ts +4 -0
- package/assets/components/IconButton/IconButton.module.css +109 -0
- package/assets/components/IconButton/IconButton.tsx +110 -0
- package/assets/components/IconButton/index.ts +2 -0
- package/assets/components/Input/Input.module.css +338 -0
- package/assets/components/Input/Input.tsx +371 -0
- package/assets/components/Input/index.ts +2 -0
- package/assets/components/ListItem/ListItem.module.css +318 -0
- package/assets/components/ListItem/ListItem.tsx +262 -0
- package/assets/components/ListItem/index.ts +9 -0
- package/assets/components/MenuItem/MenuItem.module.css +437 -0
- package/assets/components/MenuItem/MenuItem.tsx +529 -0
- package/assets/components/MenuItem/index.ts +8 -0
- package/assets/components/MetricCard/MetricCard.module.css +153 -0
- package/assets/components/MetricCard/MetricCard.tsx +140 -0
- package/assets/components/MetricCard/index.ts +2 -0
- package/assets/components/Modal/Modal.module.css +175 -0
- package/assets/components/Modal/Modal.tsx +98 -0
- package/assets/components/Modal/index.ts +2 -0
- package/assets/components/Onboarding/DocsIndex.tsx +82 -0
- package/assets/components/Onboarding/LayoutBuilder.tsx +160 -0
- package/assets/components/Onboarding/Onboarding.module.css +1394 -0
- package/assets/components/Onboarding/OnboardingAxisPanel.tsx +515 -0
- package/assets/components/Onboarding/OnboardingPage.tsx +1193 -0
- package/assets/components/Onboarding/PresetsGallery.tsx +65 -0
- package/assets/components/Onboarding/actions.ts +250 -0
- package/assets/components/Onboarding/index.ts +8 -0
- package/assets/components/Onboarding/palette.css +40 -0
- package/assets/components/Onboarding/wizardData.ts +265 -0
- package/assets/components/Pagination/Pagination.module.css +82 -0
- package/assets/components/Pagination/Pagination.tsx +248 -0
- package/assets/components/Pagination/index.ts +6 -0
- package/assets/components/ProgressBar/ProgressBar.module.css +64 -0
- package/assets/components/ProgressBar/ProgressBar.tsx +54 -0
- package/assets/components/ProgressBar/index.ts +2 -0
- package/assets/components/QuotationBar/QuotationBar.module.css +61 -0
- package/assets/components/QuotationBar/QuotationBar.tsx +48 -0
- package/assets/components/QuotationBar/index.ts +2 -0
- package/assets/components/Radio/Radio.module.css +63 -0
- package/assets/components/Radio/Radio.tsx +33 -0
- package/assets/components/Radio/index.ts +2 -0
- package/assets/components/Select/Select.module.css +151 -0
- package/assets/components/Select/Select.tsx +425 -0
- package/assets/components/Select/index.ts +10 -0
- package/assets/components/SelectableCard/SelectableCard.module.css +177 -0
- package/assets/components/SelectableCard/SelectableCard.tsx +83 -0
- package/assets/components/SelectableCard/index.ts +2 -0
- package/assets/components/Shortcut/Shortcut.module.css +56 -0
- package/assets/components/Shortcut/Shortcut.tsx +156 -0
- package/assets/components/Shortcut/index.ts +2 -0
- package/assets/components/Sidebar/Sidebar.module.css +242 -0
- package/assets/components/Sidebar/Sidebar.tsx +264 -0
- package/assets/components/Sidebar/index.ts +7 -0
- package/assets/components/SidebarSplit/SidebarSplit.module.css +126 -0
- package/assets/components/SidebarSplit/SidebarSplit.tsx +222 -0
- package/assets/components/SidebarSplit/index.ts +6 -0
- package/assets/components/Slider/Slider.module.css +120 -0
- package/assets/components/Slider/Slider.tsx +88 -0
- package/assets/components/Slider/index.ts +2 -0
- package/assets/components/SplitButton/SplitButton.module.css +190 -0
- package/assets/components/SplitButton/SplitButton.tsx +145 -0
- package/assets/components/SplitButton/index.ts +6 -0
- package/assets/components/Stepper/Stepper.module.css +182 -0
- package/assets/components/Stepper/Stepper.tsx +185 -0
- package/assets/components/Stepper/index.ts +2 -0
- package/assets/components/Switch/Switch.module.css +116 -0
- package/assets/components/Switch/Switch.tsx +58 -0
- package/assets/components/Switch/index.ts +2 -0
- package/assets/components/TableCell/TableCell.module.css +137 -0
- package/assets/components/TableCell/TableCellAvatar.tsx +42 -0
- package/assets/components/TableCell/TableCellBadge.tsx +23 -0
- package/assets/components/TableCell/TableCellIcon.tsx +39 -0
- package/assets/components/TableCell/TableCellImage.tsx +49 -0
- package/assets/components/TableCell/TableCellLink.tsx +33 -0
- package/assets/components/TableCell/TableCellMeter.tsx +55 -0
- package/assets/components/TableCell/TableCellNumber.tsx +43 -0
- package/assets/components/TableCell/TableCellText.tsx +30 -0
- package/assets/components/TableCell/index.ts +23 -0
- package/assets/components/TableHeader/TableHeader.module.css +287 -0
- package/assets/components/TableHeader/TableHeader.tsx +590 -0
- package/assets/components/TableHeader/index.ts +9 -0
- package/assets/components/TableRow/TableRow.module.css +290 -0
- package/assets/components/TableRow/TableRow.tsx +253 -0
- package/assets/components/TableRow/index.ts +8 -0
- package/assets/components/TableRowEdit/TableRowEdit.module.css +126 -0
- package/assets/components/TableRowEdit/TableRowEdit.tsx +247 -0
- package/assets/components/TableRowEdit/index.ts +2 -0
- package/assets/components/TableRowSelect/TableRowSelect.module.css +23 -0
- package/assets/components/TableRowSelect/TableRowSelect.tsx +175 -0
- package/assets/components/TableRowSelect/index.ts +2 -0
- package/assets/components/Tabs/Tabs.module.css +234 -0
- package/assets/components/Tabs/Tabs.tsx +426 -0
- package/assets/components/Tabs/index.ts +9 -0
- package/assets/components/Textarea/Textarea.module.css +318 -0
- package/assets/components/Textarea/Textarea.tsx +426 -0
- package/assets/components/Textarea/index.ts +7 -0
- package/assets/components/ThemeController.tsx +271 -0
- package/assets/components/TimePicker/TimePicker.module.css +317 -0
- package/assets/components/TimePicker/TimePicker.tsx +821 -0
- package/assets/components/TimePicker/index.ts +8 -0
- package/assets/components/TimePicker/utils.ts +115 -0
- package/assets/components/Toast/Toast.module.css +264 -0
- package/assets/components/Toast/Toast.tsx +243 -0
- package/assets/components/Toast/index.ts +15 -0
- package/assets/components/Toolbar/Toolbar.module.css +72 -0
- package/assets/components/Toolbar/Toolbar.tsx +75 -0
- package/assets/components/Toolbar/index.ts +2 -0
- package/assets/components/Tooltip/Tooltip.module.css +42 -0
- package/assets/components/Tooltip/Tooltip.tsx +332 -0
- package/assets/components/Tooltip/index.ts +2 -0
- package/assets/components/Topbar/Topbar.module.css +26 -0
- package/assets/components/Topbar/Topbar.tsx +47 -0
- package/assets/components/Topbar/index.ts +2 -0
- package/assets/components/_cn.ts +3 -0
- package/assets/components/_color.ts +48 -0
- package/assets/components/_data.ts +659 -0
- package/assets/components/_utils.css +19 -0
- package/assets/components/axisOptions.ts +24 -0
- package/assets/components/tokens.css +742 -0
- package/assets/prompts/GUIDE.md +251 -0
- package/assets/prompts/OVERRIDE.md +170 -0
- package/assets/prompts/PRINCIPLES.md +130 -0
- package/assets/prompts/axes/density.md +38 -0
- package/assets/prompts/axes/font.md +36 -0
- package/assets/prompts/axes/hue.md +36 -0
- package/assets/prompts/axes/icon.md +48 -0
- package/assets/prompts/axes/mode.md +50 -0
- package/assets/prompts/axes/motion.md +77 -0
- package/assets/prompts/axes/palette.md +35 -0
- package/assets/prompts/axes/shape.md +33 -0
- package/assets/prompts/axes/voice.md +54 -0
- package/assets/prompts/components/README.md +84 -0
- package/assets/prompts/components/app-frame.md +94 -0
- package/assets/prompts/components/attachment-chip.md +46 -0
- package/assets/prompts/components/attachment-thumb.md +49 -0
- package/assets/prompts/components/avatar.md +86 -0
- package/assets/prompts/components/badge.md +104 -0
- package/assets/prompts/components/breadcrumb.md +77 -0
- package/assets/prompts/components/button.md +99 -0
- package/assets/prompts/components/callout.md +81 -0
- package/assets/prompts/components/chat-input.md +84 -0
- package/assets/prompts/components/checkbox.md +46 -0
- package/assets/prompts/components/chip.md +84 -0
- package/assets/prompts/components/choice-card.md +127 -0
- package/assets/prompts/components/context-menu.md +145 -0
- package/assets/prompts/components/date-picker.md +104 -0
- package/assets/prompts/components/drawer.md +152 -0
- package/assets/prompts/components/empty-state.md +69 -0
- package/assets/prompts/components/file-icon.md +73 -0
- package/assets/prompts/components/filter-button.md +42 -0
- package/assets/prompts/components/form-field.md +74 -0
- package/assets/prompts/components/gallery-item.md +158 -0
- package/assets/prompts/components/icon-button.md +82 -0
- package/assets/prompts/components/icon.md +68 -0
- package/assets/prompts/components/input.md +95 -0
- package/assets/prompts/components/list-item.md +235 -0
- package/assets/prompts/components/menu-item.md +234 -0
- package/assets/prompts/components/metric-card.md +132 -0
- package/assets/prompts/components/modal.md +131 -0
- package/assets/prompts/components/pagination.md +92 -0
- package/assets/prompts/components/progress-bar.md +61 -0
- package/assets/prompts/components/quotation-bar.md +39 -0
- package/assets/prompts/components/radio.md +41 -0
- package/assets/prompts/components/select.md +104 -0
- package/assets/prompts/components/selectable-card.md +67 -0
- package/assets/prompts/components/shortcut.md +76 -0
- package/assets/prompts/components/sidebar.md +107 -0
- package/assets/prompts/components/slider.md +89 -0
- package/assets/prompts/components/split-button.md +71 -0
- package/assets/prompts/components/stepper.md +93 -0
- package/assets/prompts/components/switch.md +86 -0
- package/assets/prompts/components/table-cell.md +87 -0
- package/assets/prompts/components/table-header.md +157 -0
- package/assets/prompts/components/table-row-edit.md +129 -0
- package/assets/prompts/components/table-row-select.md +82 -0
- package/assets/prompts/components/table-row.md +156 -0
- package/assets/prompts/components/tabs.md +122 -0
- package/assets/prompts/components/textarea.md +105 -0
- package/assets/prompts/components/toast.md +149 -0
- package/assets/prompts/components/tooltip.md +71 -0
- package/assets/prompts/components/topbar.md +148 -0
- package/assets/prompts/primitives/emerge.md +43 -0
- package/assets/prompts/primitives/fade.md +31 -0
- package/assets/prompts/primitives/scale.md +32 -0
- package/assets/prompts/primitives/scroll.md +75 -0
- package/assets/prompts/primitives/slide.md +31 -0
- package/assets/prompts/themes/_SCHEMA.md +135 -0
- package/assets/prompts/themes/_TEMPLATE.md +73 -0
- package/assets/prompts/themes/expressive.md +118 -0
- package/assets/prompts/themes/pure.md +87 -0
- package/assets/prompts/themes/spare.md +73 -0
- package/assets/prompts/tokens/breakpoint.md +29 -0
- package/assets/prompts/tokens/color.md +78 -0
- package/assets/prompts/tokens/radius.md +33 -0
- package/assets/prompts/tokens/shadow.md +35 -0
- package/assets/prompts/tokens/spacing.md +86 -0
- package/assets/prompts/tokens/typography.md +76 -0
- package/assets/prompts/tokens/z-index.md +35 -0
- package/assets/public/expressive.png +0 -0
- package/assets/public/pure.png +0 -0
- package/assets/public/spare.png +0 -0
- package/assets/skill/SKILL.md +36 -0
- package/bin/ctds.js +76 -0
- package/package.json +35 -4
- package/src/commands/init.js +215 -0
- package/src/commands/update.js +275 -0
- package/src/utils/assets.js +78 -0
- package/src/utils/deps.js +51 -0
- package/src/utils/detect.js +47 -0
- package/src/utils/diff.js +52 -0
- package/src/utils/hash.js +16 -0
- package/src/utils/log.js +41 -0
- package/src/utils/meta.js +73 -0
- package/src/utils/prompt.js +28 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
axis: icon
|
|
3
|
+
selector: '[data-icon-family]'
|
|
4
|
+
values: [phosphor, solar, lucide]
|
|
5
|
+
default: phosphor
|
|
6
|
+
layer: 1
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Icon
|
|
10
|
+
|
|
11
|
+
### 원칙
|
|
12
|
+
Icon 축은 **Family** 하나만 담당. 한 페이지 = 한 Family.
|
|
13
|
+
Weight는 축이 아니라 `<Icon weight="..." />` prop (컴포넌트별 자유 지정) — 상태 표시용.
|
|
14
|
+
|
|
15
|
+
### Do
|
|
16
|
+
- 아이콘은 항상 의미 기반 이름으로 참조: `<Icon name="check" />`.
|
|
17
|
+
- 프로젝트 시작 시 Family 하나 결정. 리스킨 아닌 이상 안 바꾼다.
|
|
18
|
+
- 활성/선택 상태 표시엔 `weight=fill`, 그 외에는 `weight=regular`.
|
|
19
|
+
|
|
20
|
+
### Don't
|
|
21
|
+
- 한 페이지에서 두 Family를 섞지 않는다.
|
|
22
|
+
- 아이콘을 SVG로 하드코딩하지 않는다. 항상 `<Icon />` 경유.
|
|
23
|
+
- Lucide에서 `weight=fill`을 요구하지 않는다 (원본이 fill 미제공).
|
|
24
|
+
|
|
25
|
+
### Fallback
|
|
26
|
+
Family는 `phosphor`, Weight는 `regular`.
|
|
27
|
+
|
|
28
|
+
### 값
|
|
29
|
+
|
|
30
|
+
**Family** (`data-icon-family`)
|
|
31
|
+
- `phosphor` — regular/fill 매트릭 매칭. 가장 유연.
|
|
32
|
+
- `solar` — 6-스타일 팩. Linear(regular)/Bold(fill) 매칭.
|
|
33
|
+
- `lucide` — Feather 계승. 얇은 stroke. regular만.
|
|
34
|
+
|
|
35
|
+
**Weight** (`<Icon weight="…" />` prop — 축 아님)
|
|
36
|
+
- `regular` — 기본 outline.
|
|
37
|
+
- `fill` — 채움. 활성/선택 상태.
|
|
38
|
+
|
|
39
|
+
### 기본값
|
|
40
|
+
`family=phosphor`, `weight=regular`
|
|
41
|
+
|
|
42
|
+
### 페어링
|
|
43
|
+
- `phosphor`·`solar` — regular/fill 모두 매칭. 활성 상태 표시 필요한 프로젝트 표준
|
|
44
|
+
- `lucide` — regular만 지원. 활성 상태를 색·배경으로만 표현하는 프로젝트에 적합
|
|
45
|
+
- 특정 [[axes/shape]] 값과의 강한 페어링은 없음. Family 선택은 브랜드 톤 기준
|
|
46
|
+
|
|
47
|
+
### 관련
|
|
48
|
+
N/A
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Mode
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
전체 배경·전경·그림자의 명도를 결정하는 축. OS 선호와 콘텐츠 성격 반영.
|
|
5
|
+
|
|
6
|
+
### Do
|
|
7
|
+
- 첫 진입 시 OS `prefers-color-scheme`을 존중한다.
|
|
8
|
+
- 데이터 밀도가 높은 대시보드/관리도구는 `dark` 기본 검토 (장시간 응시 완화).
|
|
9
|
+
- `mode`만 스왑해도 시각적 완성도가 유지되도록 semantic 토큰만 참조한다.
|
|
10
|
+
|
|
11
|
+
### Don't
|
|
12
|
+
- 특정 mode에만 존재하는 컴포넌트 만들지 않는다. 모든 컴포넌트가 두 mode 지원.
|
|
13
|
+
- 순백(`#fff`)·순흑을 직접 지정하지 않는다. 항상 `--bg` 경유.
|
|
14
|
+
|
|
15
|
+
### Fallback
|
|
16
|
+
지정 없으면 `light`. OS 힌트 있으면 그 값.
|
|
17
|
+
|
|
18
|
+
### 값
|
|
19
|
+
- `light` — 밝은 배경, 어두운 텍스트. 일반 웹 UI 기본.
|
|
20
|
+
- `dark` — 어두운 배경, 밝은 텍스트. 야간·장시간 응시·대시보드.
|
|
21
|
+
- `high-contrast` — 접근성 강화 대비. KWCAG/WCAG AAA 대응. (미구현, 로드맵)
|
|
22
|
+
|
|
23
|
+
### 기본값
|
|
24
|
+
`light`
|
|
25
|
+
|
|
26
|
+
### 국소 스코프 (라이트 페이지 안의 어두운 영역)
|
|
27
|
+
라이트 모드 페이지 내에서 특정 영역만 다크로 뒤집고 싶을 때 (예: 이미지 위 오버레이, 어두운 카드/배너, 검정 툴바 위 IconButton) — 해당 컨테이너에 `data-mode="dark"`를 그대로 씌운다. `--bg`·`--fg`·`--border`·`--shadow` 등 시맨틱 토큰이 서브트리 안에서 다크 값으로 자동 반전되므로, 안쪽 컴포넌트는 별도 tone/inverse prop 없이 기존 토큰만 참조하면 된다.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<div data-mode="dark" style={{ background: 'var(--bg)', padding: 'var(--space-4)' }}>
|
|
31
|
+
<IconButton icon="close" /> {/* --fg가 밝은 값으로 자동 반전 */}
|
|
32
|
+
</div>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Do (국소 스코프)
|
|
36
|
+
- 어두운 표면 위에 컴포넌트를 얹을 때는 컨테이너를 `data-mode="dark"`로 감싸고, 배경은 반드시 `var(--bg)` 또는 `var(--bg-subtle/muted)`로 지정한다 (컨테이너 자체가 반전된 토큰을 사용해야 안쪽과 일관).
|
|
37
|
+
- 국소 스코프는 palette·shape 등 다른 축은 상속받고 Mode만 바꾼다.
|
|
38
|
+
|
|
39
|
+
### Don't (국소 스코프)
|
|
40
|
+
- 컴포넌트에 `tone="inverse"`·`variant="onDark"` 같은 prop을 새로 만들지 않는다. 컨텍스트가 스타일을 결정한다.
|
|
41
|
+
- 컨테이너 배경을 `#000`·`black`·하드코딩 hex로 지정하지 않는다. `var(--bg)` 경유.
|
|
42
|
+
- 현재는 **다크 방향 반전만 지원**한다 (다크 페이지 안에 라이트 영역을 뚫는 `data-mode="light"` 국소 스코프는 미지원 — 필요해지면 별도 논의).
|
|
43
|
+
|
|
44
|
+
### 페어링
|
|
45
|
+
- `dark` + [[axes/density]] `compact` — 장시간 응시 대시보드 표준 조합
|
|
46
|
+
- `high-contrast` — 다른 축과 무관하게 접근성 우선 ([[PRINCIPLES]] §5)
|
|
47
|
+
- 특정 Mode + Palette 조합 제한 없음. 모든 Palette가 두 Mode 모두 지원해야 함
|
|
48
|
+
|
|
49
|
+
### 관련
|
|
50
|
+
- [[tokens/color]] — Mode가 스왑하는 semantic 컬러
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Motion
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
애니메이션의 **성격**을 결정 — duration, easing, 이동 거리 3요소를 세트로 스왑.
|
|
5
|
+
컴포넌트의 모든 애니는 모션 토큰 또는 프리미티브 경유. 하드코딩 금지.
|
|
6
|
+
|
|
7
|
+
### Do
|
|
8
|
+
- 프로젝트 성격에 맞춰 하나 선택. 화면마다 다르게 쓰지 않는다.
|
|
9
|
+
- 컴포넌트의 모든 트랜지션/애니메이션은 `--duration-*` 토큰 또는 모션 프리미티브 경유.
|
|
10
|
+
- 인터랙티브 컴포넌트(hover/press/focus)는 반드시 `--transition-colors` / `--transition-ring` / `--transition-press` 3종 시맨틱 프리셋 조합만 사용.
|
|
11
|
+
- `prefers-reduced-motion: reduce`가 오면 축 값과 무관하게 즉시 정지.
|
|
12
|
+
|
|
13
|
+
### Don't
|
|
14
|
+
- `transition-duration`이나 `animation-duration`에 밀리초 하드코딩 금지.
|
|
15
|
+
- 두 개 이상 프리미티브를 겹치지 않는다 (예외: 오버레이는 fade+scale 조합만 허용).
|
|
16
|
+
- `motion=none`이라도 스피너·프로그레스는 예외적으로 동작 유지 (기능성 우선).
|
|
17
|
+
|
|
18
|
+
### Fallback
|
|
19
|
+
`standard`
|
|
20
|
+
|
|
21
|
+
### 값
|
|
22
|
+
- `bouncy` — 크고 오래(400ms 기본). Spring easing. 브랜드·마케팅·온보딩.
|
|
23
|
+
- `standard` — 표준(200ms). Ease-out. 일반 웹 UI.
|
|
24
|
+
- `calm` — 짧고 은은(100ms). Linear. 관리 도구·데이터 대시보드.
|
|
25
|
+
- `none` — 즉시(0ms). 접근성 우선·저사양·정적 프리뷰.
|
|
26
|
+
|
|
27
|
+
### 기본값
|
|
28
|
+
`standard`
|
|
29
|
+
|
|
30
|
+
### 페어링
|
|
31
|
+
- `bouncy` + [[axes/shape]] `soft` — 부드러운 촉감 + 표현력 있는 모션
|
|
32
|
+
- `calm` + [[axes/shape]] `crisp` — 신뢰·전문 인상 + 절제된 모션
|
|
33
|
+
- `calm` + [[axes/density]] `compact` — 밀도 높은 화면에서 모션 이동 거리도 자동 축소
|
|
34
|
+
- `none` — `prefers-reduced-motion: reduce` 사용자에게 강제 (다른 축 값과 무관, [[PRINCIPLES]] §5)
|
|
35
|
+
|
|
36
|
+
### 인터랙션 트랜지션 시맨틱 프리셋
|
|
37
|
+
모든 인터랙티브 컴포넌트(Button/IconButton/MenuItem/Input/Tabs 등)의 hover/press/focus는 아래 3종을 조합해서 사용. 컴포넌트가 `transition` 속성에 duration·easing을 직접 적지 않는다.
|
|
38
|
+
|
|
39
|
+
- `--transition-colors` — background/color/border-color, `slow` + `ease-out`. hover가 스르륵 물듦 (소음 최소).
|
|
40
|
+
- `--transition-ring` — box-shadow(focus ring), `fast` + `ease-out`. 키보드 사용자에게 즉각 피드백.
|
|
41
|
+
- `--transition-press` — transform(press), `base` + `ease-out`. 진입·해제 대칭.
|
|
42
|
+
|
|
43
|
+
```css
|
|
44
|
+
.root {
|
|
45
|
+
transition: var(--transition-colors), var(--transition-ring), var(--transition-press);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
색이 안 변하면 `--transition-colors` 생략, press가 없으면 `--transition-press` 생략 — 필요한 프리셋만 조합. 값 튜닝은 globals.css의 토큰 정의에서만 (컴포넌트에서 override 금지).
|
|
50
|
+
|
|
51
|
+
### 플로팅 서페이스 In/Out — `.m-float` 유틸 강제
|
|
52
|
+
Tooltip · ContextMenu · DropdownMenu · Select · Popover · DatePicker · HoverCard 등 **떠오르는 표면(overlay/popover)은 예외 없이** globals.css의 전역 유틸 `.m-float`을 사용한다. 컴포넌트별로 자체 keyframe(`dp-emerge`, `menu-in` 등)이나 자체 `animation:` 규칙을 만들지 않는다.
|
|
53
|
+
|
|
54
|
+
**적용법 (Radix 기반):**
|
|
55
|
+
```tsx
|
|
56
|
+
<Radix.Content
|
|
57
|
+
className={[styles.content, "m-float"].filter(Boolean).join(" ")}
|
|
58
|
+
{/* ... */}
|
|
59
|
+
/>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**작동 원리:**
|
|
63
|
+
- `data-state`(`open`|`closed`|`delayed-open`) × `data-side`(`top`|`bottom`|`left`|`right`) 조합으로 자동 매칭.
|
|
64
|
+
- open은 앵커 반대편에서 자라남 (`--duration-base` + `--ease-emphasized`).
|
|
65
|
+
- close는 앵커 쪽으로 되감김 (`--duration-fast` + `--ease-in`, 이동량 절반).
|
|
66
|
+
- `prefers-reduced-motion: reduce`면 자동 정지.
|
|
67
|
+
|
|
68
|
+
**왜 전역 유틸인가:**
|
|
69
|
+
Turbopack CSS Modules는 컴포넌트 CSS 안의 `animation: <name>` shorthand에서 keyframe identifier를 hash로 rewrite한다 → globals.css의 전역 `@keyframes m-emerge-*`가 매칭 실패. `.m-float` 규칙 자체를 globals.css에 두어 스코핑을 회피하면 컴포넌트는 클래스 문자열만 붙이면 된다.
|
|
70
|
+
|
|
71
|
+
**Don't:**
|
|
72
|
+
- 컴포넌트 CSS에 `@keyframes` 새로 만들어 오버레이 등장 애니메이션 정의.
|
|
73
|
+
- 오버레이 Content에 `animation:` 또는 `animation-*` 재정의.
|
|
74
|
+
- `data-state="closed"` 애니메이션 생략 (인·아웃 대칭이 원칙).
|
|
75
|
+
|
|
76
|
+
### 관련
|
|
77
|
+
- [[primitives/fade]] · [[primitives/emerge]] · [[primitives/recede]] — Motion 축이 파라미터를 스왑, `.m-float`이 side별 매핑
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Palette
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
브랜드 컬러의 **강도**를 결정. Hue가 "어떤 색"이라면 Palette는 "얼마나 강한 색".
|
|
5
|
+
OKLCH의 chroma·lightness를 스왑.
|
|
6
|
+
|
|
7
|
+
### Do
|
|
8
|
+
- 프로젝트의 톤을 정하는 첫 축. Hue보다 Palette를 먼저 결정한다.
|
|
9
|
+
- 정보 밀도가 높은 화면은 `calm` 또는 `standard`.
|
|
10
|
+
- 마케팅·랜딩·온보딩은 `vivid` 또는 `pastel`.
|
|
11
|
+
|
|
12
|
+
### Don't
|
|
13
|
+
- Palette를 컴포넌트별로 다르게 쓰지 않는다. 프로젝트 전체가 한 Palette.
|
|
14
|
+
- `pastel` 컬러 위에 흰 텍스트를 얹지 않는다 (대비 부족).
|
|
15
|
+
|
|
16
|
+
### Fallback
|
|
17
|
+
`standard`
|
|
18
|
+
|
|
19
|
+
### 값
|
|
20
|
+
- `vivid` — 채도 높음. 강한 인상, 브랜드 강조.
|
|
21
|
+
- `standard` — 기본. 일반 웹 UI.
|
|
22
|
+
- `calm` — 채도 낮음. 차분, 신뢰. 금융·의료·공공.
|
|
23
|
+
- `pastel` — 매우 낮은 채도 + 밝은 명도. 부드러움. 교육·유아·라이프스타일.
|
|
24
|
+
|
|
25
|
+
### 기본값
|
|
26
|
+
`standard`
|
|
27
|
+
|
|
28
|
+
### 페어링
|
|
29
|
+
- `calm` + [[axes/hue]] `ocean`·`forest`·`slate` — 신뢰·안정 인상 (금융·의료·공공)
|
|
30
|
+
- `vivid` + [[axes/hue]] `sunset`·`crimson` — 강한 브랜드 인상 (스타트업·프로모션)
|
|
31
|
+
- `pastel` + [[axes/hue]] `lavender` — 부드러움 (교육·라이프스타일)
|
|
32
|
+
- `pastel` + [[axes/mode]] `dark` — 비권장. 파스텔은 밝은 배경에서 최적화됨
|
|
33
|
+
|
|
34
|
+
### 관련
|
|
35
|
+
- [[axes/hue]] — Palette와 조합해 최종 브랜드 컬러 생성
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Shape
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
컴포넌트의 **촉감**(radius + shadow + border 두께). 세 요소를 세트로 스왑해 시각적 일관성 유지.
|
|
5
|
+
|
|
6
|
+
### Do
|
|
7
|
+
- 프로젝트 성격에 맞춰 하나 선택. 컴포넌트별로 다르게 쓰지 않는다.
|
|
8
|
+
- 데이터 밀도 높은 화면은 `crisp` — 각진 경계가 정보 구분에 유리.
|
|
9
|
+
- 콘텐츠·마케팅 화면은 `soft` — 친근함·여유.
|
|
10
|
+
|
|
11
|
+
### Don't
|
|
12
|
+
- radius/shadow/border를 개별 하드코딩하지 않는다. Shape 축으로만 조정.
|
|
13
|
+
- 특정 컴포넌트만 다른 shape를 갖게 만들지 않는다 (예: Modal만 soft).
|
|
14
|
+
|
|
15
|
+
### Fallback
|
|
16
|
+
`standard`
|
|
17
|
+
|
|
18
|
+
### 값
|
|
19
|
+
- `soft` — 큰 radius, 부드러운 넓은 그림자, 얇은 border. 캐주얼·친근.
|
|
20
|
+
- `standard` — soft와 crisp의 산술 중간. 무난한 표준.
|
|
21
|
+
- `crisp` — 작은 radius, 짧고 예리한 그림자 + 아웃라인, 뚜렷한 border. 신뢰·전문.
|
|
22
|
+
|
|
23
|
+
### 기본값
|
|
24
|
+
`standard`
|
|
25
|
+
|
|
26
|
+
### 페어링
|
|
27
|
+
- `soft` + [[axes/motion]] `bouncy` — 부드러운 촉감과 표현력 있는 모션이 자연스러움
|
|
28
|
+
- `crisp` + [[axes/motion]] `calm` — 신뢰·전문 인상에는 절제된 모션
|
|
29
|
+
- `crisp` + [[axes/density]] `compact` — 데이터 밀도 화면의 표준 조합
|
|
30
|
+
- `soft` + [[axes/density]] `compact` — 비권장. 부드러운 촉감과 밀도가 충돌
|
|
31
|
+
|
|
32
|
+
### 관련
|
|
33
|
+
- [[tokens/radius]] · [[tokens/shadow]] — Shape가 스왑하는 토큰들
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
axis: voice
|
|
3
|
+
selector: '[data-voice]'
|
|
4
|
+
values: [formal, neutral, casual]
|
|
5
|
+
default: neutral
|
|
6
|
+
layer: 2
|
|
7
|
+
css_tokens: none
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Voice
|
|
11
|
+
|
|
12
|
+
### 원칙
|
|
13
|
+
Voice는 **카피 톤만** 지배. 토큰·CSS 변수 없는 Layer 2 전용 축.
|
|
14
|
+
Theme과 독립 — editorial이든 mechanical이든 어떤 Theme에도 어떤 Voice든 결합 가능.
|
|
15
|
+
서비스 성격 기준으로 선택하며, 다른 축(색·간격·모션)에 전혀 연쇄하지 않는다.
|
|
16
|
+
|
|
17
|
+
### Do
|
|
18
|
+
- 카피를 생성할 때 현재 `data-voice` 또는 사용자 지시된 Voice를 **먼저 확인**하고 그 톤으로 작성.
|
|
19
|
+
- 톤 전환은 종결어미만 바꾸지 말고 **어휘 선택까지** 바꾼다 (예: "오류" ↔ "앗").
|
|
20
|
+
- Preset(`gov-formal` 등) 적용 후에도 Voice는 사용자가 별도로 선택한 값을 유지한다.
|
|
21
|
+
|
|
22
|
+
### Don't
|
|
23
|
+
- Voice를 색·간격·radius와 같은 기준으로 변경하지 않는다. 다른 축에 영향 없음.
|
|
24
|
+
- 접근성 문구(에러 설명, 필수 필드 안내, 스크린리더 라벨)는 Voice와 무관하게 **명확성 우선**.
|
|
25
|
+
`casual`이어도 필수 정보를 희석하지 않는다 (예: "비밀번호는 필수입니다" 수준은 유지).
|
|
26
|
+
- Voice에 CSS 변수나 토큰을 할당하지 않는다. 코드 레벨 영향은 `data-voice` 속성 노출뿐.
|
|
27
|
+
- **제목·헤딩·버튼 라벨·메뉴명에 em dash(—), en dash(–), 하이픈(-)으로 부제를 잇지 않는다.**
|
|
28
|
+
모든 Voice 공통 하드 룰. 문서·UI 카피·AI 생성물 전부 해당.
|
|
29
|
+
나쁜 예: "온보딩 — 테마를 고릅니다", "설정 — 기본값", "저장 — 완료".
|
|
30
|
+
대신: 한 줄 제목으로 끝내거나(`"테마 고르기"`), 부제가 꼭 필요하면 별도 하위 텍스트로 분리.
|
|
31
|
+
|
|
32
|
+
### Fallback
|
|
33
|
+
`neutral`.
|
|
34
|
+
|
|
35
|
+
### 값
|
|
36
|
+
|
|
37
|
+
**Voice** (`data-voice`)
|
|
38
|
+
- `formal` — 격식체. 종결어미 "···합니다". 공공·금융·법무·엔터프라이즈.
|
|
39
|
+
예: "저장되었습니다.", "요청을 처리할 수 없습니다."
|
|
40
|
+
- `neutral` — 표준 존대. 종결어미 "···입니다 / ···해요" 혼용. 일반 웹 UI 기본.
|
|
41
|
+
예: "저장했어요.", "다시 시도해 주세요."
|
|
42
|
+
- `casual` — 친근체. 말 놓기 톤 허용. 소셜·게임·내부 도구.
|
|
43
|
+
예: "저장 완료!", "앗, 뭔가 잘못됐어요."
|
|
44
|
+
|
|
45
|
+
### 기본값
|
|
46
|
+
`voice=neutral`
|
|
47
|
+
|
|
48
|
+
### 페어링
|
|
49
|
+
- 특정 Theme과의 강한 페어링 없음. Theme이 묶는 축 바깥에 있음.
|
|
50
|
+
- 선택 기준은 **서비스 성격**: B2G/금융 → `formal`, 일반 B2C → `neutral`, 소셜·게임·사내툴 → `casual`.
|
|
51
|
+
- 특정 [[axes/palette]]·[[axes/shape]]와의 강제 조합도 없음.
|
|
52
|
+
|
|
53
|
+
### 관련
|
|
54
|
+
- [[themes/_SCHEMA]] — Theme이 묶는 축에서 Voice는 제외됨 (Palette/Hue와 함께 Theme 바깥 3축).
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# prompts/components/
|
|
2
|
+
|
|
3
|
+
> **이 폴더는 CTDS 관리자용.**
|
|
4
|
+
> CTDS를 사용하는 개발자는 [../../USAGE.md](../../USAGE.md)를 본다.
|
|
5
|
+
|
|
6
|
+
CTDS 컴포넌트별 프롬프트 문서. Layer 2 (AI 프롬프트 컨텍스트).
|
|
7
|
+
|
|
8
|
+
각 파일은 `web/components/<Name>/`의 코드 컴포넌트와 **쌍으로** 존재해야 한다.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 파일 규칙
|
|
13
|
+
|
|
14
|
+
- 파일 하나 = 컴포넌트 하나 (`button.md`, `input.md`, `select.md` ...)
|
|
15
|
+
- 파일명은 kebab-case, 소문자
|
|
16
|
+
- 문서 골격은 [../GUIDE.md](../GUIDE.md) §3.3 참고
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 최소 골격
|
|
21
|
+
|
|
22
|
+
```markdown
|
|
23
|
+
## <컴포넌트 이름>
|
|
24
|
+
|
|
25
|
+
### 원칙
|
|
26
|
+
<1~2줄. 이 컴포넌트가 왜 존재하고 언제 쓰는가.>
|
|
27
|
+
|
|
28
|
+
### Do
|
|
29
|
+
- <명령형 규칙>
|
|
30
|
+
|
|
31
|
+
### Don't
|
|
32
|
+
- <하드 리젝 사유>
|
|
33
|
+
|
|
34
|
+
### Fallback
|
|
35
|
+
<규칙이 애매할 때의 기본값.>
|
|
36
|
+
|
|
37
|
+
### 관련
|
|
38
|
+
- [[axes/density]] — <왜 관련되는지>
|
|
39
|
+
- [[tokens/spacing]] — <왜 관련되는지>
|
|
40
|
+
|
|
41
|
+
### Props 시그니처
|
|
42
|
+
```tsx
|
|
43
|
+
<Button variant="primary | secondary | ghost" size="sm | md | lg" />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Variant 매트릭스
|
|
47
|
+
| variant | 용도 | 금지 조합 |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `primary` | 주요 액션 | 한 화면에 2개 이상 금지 |
|
|
50
|
+
| `secondary` | 보조 액션 | — |
|
|
51
|
+
|
|
52
|
+
### 조합 예시
|
|
53
|
+
<규칙을 종합한 최소 예시 1개. 코드 블록.>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
빈 헤딩은 `N/A` 한 줄로 표시. 헤딩 자체를 생략하지 않는다.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 크로스 참조
|
|
61
|
+
|
|
62
|
+
- 축 참조: `[[axes/density]]`
|
|
63
|
+
- 토큰 참조: `[[tokens/spacing]]`
|
|
64
|
+
- 다른 컴포넌트: `[[components/button]]`
|
|
65
|
+
- 프리미티브: `[[primitives/fade]]`
|
|
66
|
+
- 최상위 문서: `[[PRINCIPLES]]`, `[[GUIDE]]`
|
|
67
|
+
|
|
68
|
+
상대 경로(`../axes/density.md`)나 URL 금지.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 작성 우선순위
|
|
73
|
+
|
|
74
|
+
[PROJECT_OVERVIEW.md](../../PROJECT_OVERVIEW.md) §핵심 컴포넌트 목록의 순서를 따른다.
|
|
75
|
+
사용 빈도 높은 컴포넌트부터: Button → Input → Select → Table → Modal → Form ...
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 코드와의 연결
|
|
80
|
+
|
|
81
|
+
- 코드: `web/components/<Name>/<Name>.tsx` + `.module.css`
|
|
82
|
+
- 이 문서: `prompts/components/<name>.md`
|
|
83
|
+
- 둘이 어긋나면 AI 에이전트가 사용자에게 알림 (기본 동작)
|
|
84
|
+
- 새 컴포넌트 추가·수정 시 **코드와 문서를 함께 커밋** ([../../CONTRIBUTING.md](../../CONTRIBUTING.md))
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# AppFrame
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
앱 전체 쉘의 grid 레이아웃. Sidebar + Topbar + Tabs(선택) + Content의 자리를 **CSS Grid**로 배정. compound 슬롯 패턴 — 자식 slot을 넣은 만큼 grid-template이 자동 조정. `variant`로 컨테이너 표현(outlined/floating/flat), `layout`으로 Sidebar/Topbar 배치 축을 결정.
|
|
5
|
+
|
|
6
|
+
### Do
|
|
7
|
+
- 모든 페이지 쉘의 **진입점** — layout.tsx 또는 섹션 쉘의 최상위에 둔다.
|
|
8
|
+
- `AppFrame.Sidebar` / `AppFrame.Topbar` / `AppFrame.Tabs` / `AppFrame.Content` 슬롯을 쓴다. 자식 순서는 자유 (grid-area가 배정).
|
|
9
|
+
- 비어있는 슬롯은 아예 **생략**. `data-has-*`가 자동 감지해 grid-template 축소.
|
|
10
|
+
- `variant`로 컨테이너 톤을 결정: outlined(기본, 테두리) / floating(그림자, 떠있는) / flat(배경만, 쉘 티 안 남).
|
|
11
|
+
- `layout`은 서비스 성격 기준: sidebar-first(Linear·Slack·Figma 패턴) / topbar-first(Jira·Vercel 패턴).
|
|
12
|
+
|
|
13
|
+
### Don't
|
|
14
|
+
- Content 안쪽에서 다시 AppFrame을 중첩하지 않는다 — grid 규칙 깨짐.
|
|
15
|
+
- Sidebar·Topbar 안에서 flex/grid를 override로 조립하지 않는다. 각자 자신의 레이아웃 컴포넌트([[components/sidebar]], [[components/topbar]])에 위임.
|
|
16
|
+
- 슬롯을 custom DOM으로 대체하지 않는다 — `data-has-*` 감지가 깨짐. 반드시 `AppFrame.X` 사용.
|
|
17
|
+
- padding/gap을 override 금지. `--control-h-*`, `--sidebar-w*`, `--topbar-h*` 토큰이 전담.
|
|
18
|
+
|
|
19
|
+
### Fallback
|
|
20
|
+
variant 애매하면 `outlined`. layout 애매하면 `sidebar-first`.
|
|
21
|
+
|
|
22
|
+
### 관련
|
|
23
|
+
- [[components/sidebar]] — Sidebar 슬롯 안에 담김
|
|
24
|
+
- [[components/topbar]] — Topbar 슬롯 안
|
|
25
|
+
- [[components/tabs]] — Tabs 슬롯 (optional, Topbar 아래 contextual nav)
|
|
26
|
+
- [[axes/density]] — sidebar/topbar 폭·높이 토큰이 Density에 반응
|
|
27
|
+
- [[axes/shape]] — outlined/floating의 radius·shadow가 Shape 축에 반응
|
|
28
|
+
|
|
29
|
+
### Props 시그니처
|
|
30
|
+
```tsx
|
|
31
|
+
<AppFrame
|
|
32
|
+
variant="outlined | floating | flat" // default: outlined
|
|
33
|
+
layout="sidebar-first | topbar-first" // default: sidebar-first
|
|
34
|
+
>
|
|
35
|
+
<AppFrame.Sidebar>
|
|
36
|
+
<Sidebar>...</Sidebar>
|
|
37
|
+
</AppFrame.Sidebar>
|
|
38
|
+
|
|
39
|
+
<AppFrame.Topbar>
|
|
40
|
+
<Topbar>...</Topbar>
|
|
41
|
+
</AppFrame.Topbar>
|
|
42
|
+
|
|
43
|
+
<AppFrame.Tabs> {/* optional */}
|
|
44
|
+
<Tabs>...</Tabs>
|
|
45
|
+
</AppFrame.Tabs>
|
|
46
|
+
|
|
47
|
+
<AppFrame.Content>
|
|
48
|
+
{page}
|
|
49
|
+
</AppFrame.Content>
|
|
50
|
+
</AppFrame>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Variant × Layout 매트릭스
|
|
54
|
+
| variant | 시각 | 자리 |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `outlined` | 전체 bg + hairline border | 기본 — 관리·대시보드 |
|
|
57
|
+
| `floating` | 쉘이 떠있는 느낌, shadow | 랜딩·마케팅·모던 SaaS |
|
|
58
|
+
| `flat` | 쉘 티 안 남, 콘텐츠가 바탕에 직접 | 미니멀·docs·에디터 |
|
|
59
|
+
|
|
60
|
+
| layout | 구조 | 레퍼런스 |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `sidebar-first` | 사이드바가 세로 전체, 탑바는 오른쪽만 | Linear · Slack · Figma |
|
|
63
|
+
| `topbar-first` | 탑바가 가로 전체, 사이드바는 아래 왼쪽만 | Jira · Vercel · Confluence |
|
|
64
|
+
|
|
65
|
+
### 조합 예시
|
|
66
|
+
```tsx
|
|
67
|
+
// 가장 흔한 쉘 — Sidebar + Topbar + Content
|
|
68
|
+
<AppFrame variant="outlined" layout="sidebar-first">
|
|
69
|
+
<AppFrame.Sidebar><Sidebar>…</Sidebar></AppFrame.Sidebar>
|
|
70
|
+
<AppFrame.Topbar><Topbar>…</Topbar></AppFrame.Topbar>
|
|
71
|
+
<AppFrame.Content>{children}</AppFrame.Content>
|
|
72
|
+
</AppFrame>
|
|
73
|
+
|
|
74
|
+
// Topbar 아래 Tabs가 있는 상세 페이지
|
|
75
|
+
<AppFrame>
|
|
76
|
+
<AppFrame.Sidebar><Sidebar>…</Sidebar></AppFrame.Sidebar>
|
|
77
|
+
<AppFrame.Topbar><Topbar title="프로젝트" />.</AppFrame.Topbar>
|
|
78
|
+
<AppFrame.Tabs>
|
|
79
|
+
<Tabs value={tab} onValueChange={setTab}>
|
|
80
|
+
<Tabs.List>
|
|
81
|
+
<Tabs.Trigger value="overview">Overview</Tabs.Trigger>
|
|
82
|
+
<Tabs.Trigger value="activity">Activity</Tabs.Trigger>
|
|
83
|
+
</Tabs.List>
|
|
84
|
+
</Tabs>
|
|
85
|
+
</AppFrame.Tabs>
|
|
86
|
+
<AppFrame.Content>{tab === "overview" ? <Overview /> : <Activity />}</AppFrame.Content>
|
|
87
|
+
</AppFrame>
|
|
88
|
+
|
|
89
|
+
// 랜딩 — Topbar만, Sidebar 없음
|
|
90
|
+
<AppFrame variant="flat" layout="topbar-first">
|
|
91
|
+
<AppFrame.Topbar><Topbar variant="landing" /></AppFrame.Topbar>
|
|
92
|
+
<AppFrame.Content><Hero /></AppFrame.Content>
|
|
93
|
+
</AppFrame>
|
|
94
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Attachment Chip
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
파일 첨부 1건 pill — `[FileIcon] filename [X]`. 파일명에서 확장자를 뽑아 [[components/file-icon]] 색/라벨을 자동 결정. 긴 파일명은 **중간 ellipsis** + 끝 확장자 유지. ChatInput·Message 양쪽 공용.
|
|
5
|
+
|
|
6
|
+
### Do
|
|
7
|
+
- 파일명 통째로 넘기면 끝 — `filename="report.pdf"` 하나로 아이콘·라벨·식별까지 다 해결.
|
|
8
|
+
- 삭제 가능한 자리엔 `onRemove` 지정 — X 상시 노출 (hover 틴트).
|
|
9
|
+
- Thumb(이미지)·Chip(파일) 섞여 흐를 자리는 `flex-wrap: wrap` + `gap: space-2`로 조립.
|
|
10
|
+
- 긴 파일명은 middle ellipsis가 알아서 자름 — maxLen 초과면 `name… + ext` 형태.
|
|
11
|
+
|
|
12
|
+
### Don't
|
|
13
|
+
- 파일명과 확장자를 **따로** 받는 props 추가하지 않는다 — 소비처에서 자르면 FileIcon 매핑이 어긋남.
|
|
14
|
+
- X를 호버 전용으로 숨기지 않는다 — ChatInput 안에선 상시 노출이 원칙 (이미지 썸네일과 다름).
|
|
15
|
+
- Chip 안에 메뉴/추가 액션 넣지 않는다 — 삭제 외엔 상위 ChatInput이 책임.
|
|
16
|
+
- 배경을 과한 톤으로 덮지 않는다 — bg는 `var(--bg)`, 테두리는 hairline. ChatInput 안에서 두드러지지 않게.
|
|
17
|
+
|
|
18
|
+
### Fallback
|
|
19
|
+
size 애매하면 `md`. 모르는 확장자는 FileIcon이 `others`로 폴백하니 그대로 넘겨도 됨.
|
|
20
|
+
|
|
21
|
+
### 관련
|
|
22
|
+
- [[components/file-icon]] — 좌측 뱃지
|
|
23
|
+
- [[components/attachment-thumb]] — 이미지 첨부
|
|
24
|
+
- [[components/chat-input]] — 상위 소비처
|
|
25
|
+
- [[components/message-bubble]] — 메시지 내 파일 인용에서도 재사용
|
|
26
|
+
|
|
27
|
+
### Props 시그니처
|
|
28
|
+
```tsx
|
|
29
|
+
<AttachmentChip
|
|
30
|
+
filename={string} // 필수. 확장자 자동 추출
|
|
31
|
+
size="sm | md" // default: md
|
|
32
|
+
onRemove={(e) => void} // 지정 시 우측 X 노출
|
|
33
|
+
/>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 비율·레이아웃
|
|
37
|
+
- 외곽 `--radius-full` (pill)
|
|
38
|
+
- `--hairline` 1px border, `var(--border)` 색
|
|
39
|
+
- 내부 gap: `--space-2`
|
|
40
|
+
- padding: md = `space-1_5 space-3 space-1_5 space-1_5` (왼쪽은 FileIcon 바싹 붙게 좁게)
|
|
41
|
+
- X: `--space-5` (md) / `--space-4` (sm) 정사각, radius full
|
|
42
|
+
|
|
43
|
+
### Middle ellipsis 규칙
|
|
44
|
+
`filename.length > 28`이면 `name… + ext`로 치환.
|
|
45
|
+
- `"super-long-project-pitch.pptx"` → `"super-long-pr… .pptx"` 식.
|
|
46
|
+
- 확장자 없거나 너무 짧으면 일반 ellipsis.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Attachment Thumb
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
Chat Input·Message의 **이미지 첨부 썸네일**. 정사각 radius ~22%(size × 0.22) 고정, 세 가지 상태 — `src` 있음(이미지)/없음(블루톤 image glyph)/`loading`(pulse). 전부 inner hairline으로 edge definition. hover 시 코너에 X 삭제 버튼 노출(`onRemove` 지정 시).
|
|
5
|
+
|
|
6
|
+
### Do
|
|
7
|
+
- 이미지 첨부(png/jpg/gif/webp)엔 썸네일, 그 외 포맷은 [[components/file-icon]] 또는 [[components/attachment-chip]].
|
|
8
|
+
- 업로드 처리 중/디코딩 전엔 `loading` → pulse. 끝나면 `src` 세팅.
|
|
9
|
+
- 메타만 받고 썸네일 URL이 늦게 오면 `src` 비워두면 image glyph placeholder — 로딩이 길어 답답한 자리를 메움.
|
|
10
|
+
- 삭제 UI가 필요하면 `onRemove`를 넘김 — hover/focus-visible에서 코너 X 활성.
|
|
11
|
+
|
|
12
|
+
### Don't
|
|
13
|
+
- 썸네일 안에 캡션·메뉴 넣지 않는다 — 레퍼런스는 "순수한 미리보기".
|
|
14
|
+
- `object-fit: contain` 금지 — 비율은 crop(`cover`).
|
|
15
|
+
- radius를 Shape 축에 반응시키지 않는다 — 소형 치수라 [[components/file-icon]]과 같은 이유로 고정.
|
|
16
|
+
- placeholder 그라데이션 등 "꾸미기" 금지 — mp3 음악 노트와 같은 패턴, 단일 톤 glyph만.
|
|
17
|
+
|
|
18
|
+
### Fallback
|
|
19
|
+
size 애매하면 `md`(40). `src`·`loading` 둘 다 없으면 자동 placeholder.
|
|
20
|
+
|
|
21
|
+
### 관련
|
|
22
|
+
- [[components/attachment-chip]] — 파일형 첨부
|
|
23
|
+
- [[components/file-icon]] — 브랜드 사각 뱃지
|
|
24
|
+
- [[components/chat-input]] — 상위 소비처
|
|
25
|
+
|
|
26
|
+
### Props 시그니처
|
|
27
|
+
```tsx
|
|
28
|
+
<AttachmentThumb
|
|
29
|
+
src={string} // 이미지 URL. 없으면 image glyph placeholder
|
|
30
|
+
alt={string}
|
|
31
|
+
size="sm | md | lg" // default: md (32 / 40 / 56)
|
|
32
|
+
loading={boolean} // true면 pulse (src 무시)
|
|
33
|
+
onRemove={(e) => void} // 지정 시 hover에서 X 노출
|
|
34
|
+
/>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 비율 (고정 — FileIcon과 통일)
|
|
38
|
+
- `radius / size` = 0.25 → sm=8, md=10, lg=14
|
|
39
|
+
- `glyph / size` = 0.60
|
|
40
|
+
- Remove 버튼: `size × 0.42`, 코너에 `-12%` offset으로 overlap
|
|
41
|
+
- 가로세로 1:1 crop
|
|
42
|
+
|
|
43
|
+
### Placeholder 색 (Mode 축 자동 전환)
|
|
44
|
+
| 모드 | bg | fg |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| Light | `#D5E8FD` | `#2D7FD3` |
|
|
47
|
+
| Dark | `#1E3A5F` | `#C5DFF8` |
|
|
48
|
+
|
|
49
|
+
브랜드 자산 범주 — [[components/file-icon]]과 같은 하드코딩 예외. 토큰으로 추상화 X.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Avatar
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
사람·팀의 **식별 마커**. 이미지 → 이니셜 → 아이콘 순서로 자동 폴백. 10색 tint 팔레트에서 이름 해시 기반 안정 매핑 — 같은 사람은 항상 같은 색. shape으로 **사람/조직** 구분(circle/rounded), status로 **접속 상태** 뱃지. 축 영향 안 받는 고정 팔레트 (사용자 식별은 흔들리면 안 됨).
|
|
5
|
+
|
|
6
|
+
### Do
|
|
7
|
+
- 가능하면 `name` 전달 — 이니셜 폴백 + tint seed + aria 라벨 공용.
|
|
8
|
+
- `shape="circle"`은 사람·개인, `shape="rounded"`는 팀·조직·봇.
|
|
9
|
+
- `src` 로드 실패 시 자동으로 이니셜 폴백. `onError` 수동 처리 불필요.
|
|
10
|
+
- 접속 상태는 `status` prop. online/offline 두 값만.
|
|
11
|
+
- Sidebar.Profile·TableCell.Avatar에 쓰는 패스스루 패턴 활용.
|
|
12
|
+
|
|
13
|
+
### Don't
|
|
14
|
+
- hex·custom 색으로 tint 덮지 않는다. 10색 팔레트가 자동.
|
|
15
|
+
- status에 커스텀 값 금지 (busy/away 아직 미지원).
|
|
16
|
+
- aria-label 생략 금지 (`alt` 또는 `name` 중 하나는 필수).
|
|
17
|
+
- Avatar 안에 그라데이션·이모지·텍스트 2글자 넘김 금지 — 식별 신호 혼탁.
|
|
18
|
+
- 크기를 CSS로 override 금지. `size` prop만.
|
|
19
|
+
|
|
20
|
+
### Fallback
|
|
21
|
+
size 애매하면 `md`, shape 애매하면 `circle` (사람).
|
|
22
|
+
|
|
23
|
+
### 관련
|
|
24
|
+
- [[components/sidebar]] — Sidebar.Profile 안쪽
|
|
25
|
+
- [[components/table-cell]] — TableCellAvatar 안쪽
|
|
26
|
+
- [[components/badge]] — status 뱃지 시각 쌍
|
|
27
|
+
- [[components/avatar-upload]] — 업로드 가능한 Avatar wrapper (별도)
|
|
28
|
+
- [[tokens/color]] — `--avatar-tint-N-bg`·`--avatar-tint-N-fg` 10색
|
|
29
|
+
|
|
30
|
+
### Props 시그니처
|
|
31
|
+
```tsx
|
|
32
|
+
<Avatar
|
|
33
|
+
size="xs | sm | md | lg | xl" // default: md
|
|
34
|
+
shape="circle | rounded" // default: circle
|
|
35
|
+
src={string} // 이미지 URL (실패 시 자동 폴백)
|
|
36
|
+
alt={string} // 접근성 대체 텍스트
|
|
37
|
+
name={string} // 이니셜 추출 + tint seed + aria
|
|
38
|
+
initials={string} // 이니셜 직접 지정 (name보다 우선)
|
|
39
|
+
icon={ReactNode} // 이미지·이니셜 대신 아이콘
|
|
40
|
+
status="online | offline" // 접속 뱃지 (미지정 시 뱃지 없음)
|
|
41
|
+
/>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Size 가이드
|
|
45
|
+
| size | 쓰임 |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `xs` | 10 — Chip leftIcon, 밀도 극한 리스트 |
|
|
48
|
+
| `sm` | 14 — TableCell.Avatar, 리스트 아이템 |
|
|
49
|
+
| `md` | 18 — **기본**, Sidebar.Profile |
|
|
50
|
+
| `lg` | 24 — 프로필 카드 |
|
|
51
|
+
| `xl` | 40 — 설정 페이지의 큰 아바타 |
|
|
52
|
+
|
|
53
|
+
### 폴백 체인
|
|
54
|
+
1. `src`가 있고 로드 성공 → 이미지
|
|
55
|
+
2. `initials` 또는 `name`에서 추출된 이니셜 → 색 배경 + 이니셜 2글자
|
|
56
|
+
3. `icon` → 아이콘 (`--fg-muted`)
|
|
57
|
+
4. 전부 없으면 → "?" 이니셜
|
|
58
|
+
|
|
59
|
+
**이니셜 추출 규칙**:
|
|
60
|
+
- 한글: 첫 글자 1개 (`"김희영"` → `"김"`)
|
|
61
|
+
- 영문: 첫 단어 앞 2글자 (`"Kim Heeyoung"` → `"Ki"`, `"AB"` → `"Ab"`)
|
|
62
|
+
|
|
63
|
+
**Tint 매핑**: `name` 또는 `initials` 해시 → 10색 중 하나. 같은 입력 = 같은 색 (사용자 식별 안정).
|
|
64
|
+
|
|
65
|
+
### 조합 예시
|
|
66
|
+
```tsx
|
|
67
|
+
// 가장 흔한 — 이름 + 이미지 + 상태
|
|
68
|
+
<Avatar size="md" name="희영" src="/avatars/hy.jpg" status="online" />
|
|
69
|
+
|
|
70
|
+
// 조직·팀 — rounded
|
|
71
|
+
<Avatar size="lg" name="디자인팀" shape="rounded" />
|
|
72
|
+
|
|
73
|
+
// 이미지 없고 이니셜만
|
|
74
|
+
<Avatar size="sm" name="Alex Johnson" />
|
|
75
|
+
|
|
76
|
+
// 커스텀 아이콘 (봇·시스템)
|
|
77
|
+
<Avatar size="md" shape="rounded" icon={<Icon name="robot" />} alt="시스템 봇" />
|
|
78
|
+
|
|
79
|
+
// TableCell.Avatar 안 — label·sublabel
|
|
80
|
+
<TableCellAvatar
|
|
81
|
+
src={user.avatar}
|
|
82
|
+
name={user.name}
|
|
83
|
+
sublabel={user.email}
|
|
84
|
+
status={user.online ? "online" : "offline"}
|
|
85
|
+
/>
|
|
86
|
+
```
|