@conscience-technology/ctds 0.4.0 → 0.4.2
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/assets/components/Hint/Hint.module.css +39 -0
- package/assets/components/Hint/Hint.tsx +48 -0
- package/assets/components/Hint/index.ts +2 -0
- package/assets/components/Kanban/Kanban.module.css +339 -0
- package/assets/components/Kanban/Kanban.tsx +371 -0
- package/assets/components/Kanban/index.ts +10 -0
- package/assets/components/PageHeader/PageHeader.module.css +109 -0
- package/assets/components/PageHeader/PageHeader.tsx +112 -0
- package/assets/components/PageHeader/index.ts +2 -0
- package/assets/components/index.ts +1 -0
- package/assets/prompts/components/hint.md +57 -0
- package/assets/prompts/components/kanban.md +167 -0
- package/assets/prompts/components/page-header.md +155 -0
- package/assets/prompts/recipes/README.md +102 -0
- package/assets/prompts/recipes/card-row.md +58 -0
- package/assets/prompts/recipes/form-footer.md +76 -0
- package/assets/prompts/recipes/meta-line.md +61 -0
- package/assets/prompts/recipes/page-banner.md +121 -0
- package/assets/prompts/recipes/page-header.md +93 -0
- package/assets/prompts/recipes/section-header.md +90 -0
- package/package.json +1 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Page Banner
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
페이지 폭에 걸치는 **안내 바**. 공유 상태·만료 안내·시스템 공지·권한 경고 등 "이 페이지 전체에 적용되는 메타 상태"를 알린다. Callout과 다름 — Callout은 사이드바·리스트 끝의 **국소** 블록, Banner는 페이지 **상단/하단**의 전면 바.
|
|
5
|
+
|
|
6
|
+
관찰: 유저 페이지에서 ①상단 "공유 열람 10.20 만료" ②중간 "`</>` 자동 처리 안내" ③하단 "열람 권한 접속" 셋 다 Banner 성격인데 서로 다른 스타일로 조립됐다 — 이 레시피가 그 셋을 하나의 리듬으로 묶는다.
|
|
7
|
+
|
|
8
|
+
### Anatomy
|
|
9
|
+
한 줄 row.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
[leading icon] [text (1~2줄)] [...spacer...] [action/dismiss]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- leading icon: 20px, [[components/icon]]
|
|
16
|
+
- text: `flex: 1 1 auto`, 1~2줄, `line-height: 1.4`
|
|
17
|
+
- action: [[components/button]] `variant="ghost"` 또는 간단한 link. **banner에서 primary 금지** — primary 액션이 필요하면 banner가 아니라 modal/dialog
|
|
18
|
+
- dismiss: [[components/icon-button]] `ghost` + close 아이콘 (옵션)
|
|
19
|
+
|
|
20
|
+
**padding:**
|
|
21
|
+
- 단일라인 (title만, 또는 1줄 메시지): 상하 `space-2`, 좌우 `space-3`
|
|
22
|
+
- 멀티라인 (title + sub, 또는 메타 라인 포함): 상하 `space-3`, 좌우 `space-4`
|
|
23
|
+
- 하단 조용한 안내: `data-size="sm"`로 다운스케일 — 상하 `space-2`, 좌우 `space-3`
|
|
24
|
+
|
|
25
|
+
**radius:** `var(--radius-md)` (단, 페이지 full-bleed로 쓰면 radius 0).
|
|
26
|
+
|
|
27
|
+
**gap:**
|
|
28
|
+
- leading↔text: 단일라인 `space-2`, 멀티라인 `space-3`
|
|
29
|
+
- text↔action: `space-3`
|
|
30
|
+
- banner.text 내부 title↔sub: `space-1` (space-0.5는 너무 타이트 — 두 줄이 녹아보임)
|
|
31
|
+
|
|
32
|
+
**leading icon 수직 정렬:** 멀티라인일 때 `align-self: flex-start` + `margin-top: space-0.5` — 센터 정렬이면 title보다 아이콘이 내려가 보임.
|
|
33
|
+
|
|
34
|
+
### Tone 체계
|
|
35
|
+
Banner는 톤 3종만 지원 — Callout과 통일.
|
|
36
|
+
|
|
37
|
+
| Tone | 자리 | 색 조합 |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `info` | 상태 공지 (만료, 공유 모드) | `background: var(--bg-subtle)` + border 없음 |
|
|
40
|
+
| `warning` | 주의 (권한 제한, 임시 상태) | `background: var(--bg-warning-subtle)` + border 없음 |
|
|
41
|
+
| `critical` | 위험 (만료 임박, 오류) | `background: var(--bg-critical-subtle)` + border 없음 |
|
|
42
|
+
|
|
43
|
+
### Do
|
|
44
|
+
- leading icon은 tone에 맞춤 — info=`info`/`share-network`, warning=`warning-circle`, critical=`warning`. **아이콘 이름은 `web/components/Icon/Icon.tsx` 레지스트리에서 확인**
|
|
45
|
+
- 텍스트는 **1문장 명제 + (옵션) 부가 1문장** — 길어지면 banner가 아니라 Callout이나 dedicated page
|
|
46
|
+
- 액션 라벨은 **동사**로 짧게 ("공유 열람 종료", "자세히")
|
|
47
|
+
- 상단 banner면 Page Header 위에 둠. 블록 아래 gap: `space-4`
|
|
48
|
+
- 하단 banner면 섹션들 다 끝난 뒤, `space-6` 간격
|
|
49
|
+
|
|
50
|
+
### Don't
|
|
51
|
+
- [HARD] **배경 + 테두리 동시 사용 금지** ([[PRINCIPLES]] §5b). Banner는 **배경 톤만**, border는 transparent
|
|
52
|
+
- [HARD] primary 버튼 금지 — banner는 "알림" 자리, 주 액션은 다른 곳
|
|
53
|
+
- [HARD] banner 안에 chip·Badge 섞지 않는다 — 톤이 겹쳐 시끄러워짐. 상태 분류가 필요하면 Banner tone을 바꾼다
|
|
54
|
+
- [HARD] 아이콘 인라인 `<svg>` 금지 — [[components/icon]] 경유
|
|
55
|
+
- [SOFT] banner 3개 이상 동시에 쌓지 않는다. 2개 이상이 쌓이면 "뭐가 중요한지" 판독 불가. 정보가 많으면 하나의 banner + "자세히" 액션으로
|
|
56
|
+
|
|
57
|
+
### Fallback
|
|
58
|
+
- action 없으면 그 자리 생략, text가 끝까지 참
|
|
59
|
+
- dismiss만 있고 action 없으면 dismiss는 trailing 우측 끝
|
|
60
|
+
|
|
61
|
+
### 조립 예시
|
|
62
|
+
```tsx
|
|
63
|
+
{/* info: 공유 열람 상태 */}
|
|
64
|
+
<aside className="page-banner" data-tone="info">
|
|
65
|
+
<Icon name="share-network" size={20} className="leading" />
|
|
66
|
+
<div className="text">
|
|
67
|
+
<strong>Kailey Kim님 프로젝트 공유 열람</strong>
|
|
68
|
+
<span className="sub">
|
|
69
|
+
조회 전용
|
|
70
|
+
<span className="sep" aria-hidden="true" />
|
|
71
|
+
10월 20일 오후 9시 53분 만료
|
|
72
|
+
<span className="sep" aria-hidden="true" />
|
|
73
|
+
Kailey 프로젝트 전체 공유
|
|
74
|
+
</span>
|
|
75
|
+
</div>
|
|
76
|
+
<Button variant="ghost" size="sm">공유 열람 종료</Button>
|
|
77
|
+
</aside>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```css
|
|
81
|
+
/* 테두리 선언 없이 배경만 — bg+stroke 조합 금지 ([[PRINCIPLES]] §5b) */
|
|
82
|
+
.page-banner {
|
|
83
|
+
display: flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
gap: var(--space-3);
|
|
86
|
+
padding: var(--space-3) var(--space-4);
|
|
87
|
+
border-radius: var(--radius-md);
|
|
88
|
+
}
|
|
89
|
+
.page-banner[data-size="sm"] {
|
|
90
|
+
padding: var(--space-2) var(--space-3);
|
|
91
|
+
gap: var(--space-2);
|
|
92
|
+
}
|
|
93
|
+
.page-banner[data-tone="info"] { background: var(--bg-subtle); }
|
|
94
|
+
.page-banner[data-tone="warning"] { background: var(--bg-warning-subtle); }
|
|
95
|
+
.page-banner[data-tone="critical"] { background: var(--bg-critical-subtle); }
|
|
96
|
+
|
|
97
|
+
.page-banner .leading {
|
|
98
|
+
color: var(--fg-muted);
|
|
99
|
+
flex: 0 0 auto;
|
|
100
|
+
align-self: flex-start;
|
|
101
|
+
margin-top: var(--space-0\.5);
|
|
102
|
+
}
|
|
103
|
+
.page-banner .text {
|
|
104
|
+
flex: 1 1 auto;
|
|
105
|
+
display: flex;
|
|
106
|
+
flex-direction: column;
|
|
107
|
+
gap: var(--space-1);
|
|
108
|
+
line-height: 1.4;
|
|
109
|
+
}
|
|
110
|
+
.page-banner .text .sub {
|
|
111
|
+
font-size: var(--text-sm);
|
|
112
|
+
color: var(--fg-muted);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 관련
|
|
117
|
+
- [[components/callout]] — 국소 안내 블록 (사이드바·리스트 끝). Banner와 자리가 다름
|
|
118
|
+
- [[components/button]] — ghost 액션
|
|
119
|
+
- [[components/icon-button]] — dismiss
|
|
120
|
+
- [[tokens/color]] — bg-subtle, bg-warning-subtle, bg-critical-subtle
|
|
121
|
+
- [[PRINCIPLES]] §5b — 배경 또는 테두리
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Page Header
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
페이지 바디 최상단에 쓰는 **"이 페이지가 뭘 하는 곳인가"** 블록. Topbar가 shell chrome(ID·전역 action)을 담는다면, Page Header는 **콘텐츠 레이어의 첫 블록**이다. [[components/topbar]]가 명시한 "큰 타이틀은 body 첫 블록 자리"를 받는 자리.
|
|
5
|
+
|
|
6
|
+
### Anatomy
|
|
7
|
+
3개 요소가 수직으로 쌓인다. (옵션 요소는 생략 가능)
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
[eyebrow] ← 옵션: 상위 맥락 (breadcrumb·카테고리) — xs/muted
|
|
11
|
+
[h1 title] [actions] ← 필수: 큰 타이틀 + 우측 액션 (옵션)
|
|
12
|
+
[description] ← 옵션: 1~2줄 서브텍스트, muted
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- eyebrow와 title 사이: `space-1`
|
|
16
|
+
- title과 description 사이: `space-2`
|
|
17
|
+
- 블록 전체 아래 (다음 섹션까지): `space-6` (앱 리듬) / `space-10` (랜딩 리듬)
|
|
18
|
+
- actions는 title과 같은 row — `align-items: center`, `flex: 1 1 auto` title / `flex: 0 0 auto` actions
|
|
19
|
+
|
|
20
|
+
### Do
|
|
21
|
+
- h1: `text-4xl` (랜딩) / `text-3xl` (앱), **`font-medium` 또는 그 이하** ([[tokens/typography]] font weight cap)
|
|
22
|
+
- h1에 **반드시 `line-height: var(--lh-tight)`** 명시 ([[tokens/spacing]] "텍스트 gap·line-height")
|
|
23
|
+
- description: `text-base` / `color: var(--fg-muted)` / `max-width: 60ch`
|
|
24
|
+
- actions는 [[components/_variants]] 액션 매핑에 따름 — 중요=`primary`, 서브=`outline`
|
|
25
|
+
- 액션 2개 이상이면 서로 간 gap은 `space-1` 고정 ([[tokens/spacing]])
|
|
26
|
+
|
|
27
|
+
### Don't
|
|
28
|
+
- [HARD] h1 아래 `margin-bottom`을 자식(h1)이 걸고 **동시에** 부모 wrapper도 gap을 걸지 않는다 — 이중 여백 ([[tokens/spacing]] Don't)
|
|
29
|
+
- [HARD] h1을 `font-semibold`/`font-bold`로 쓰지 않는다 — [[tokens/typography]] font weight cap
|
|
30
|
+
- [HARD] uppercase + letter-spacing 조합 금지 — 메모리 [no-uppercase]
|
|
31
|
+
- [SOFT] eyebrow 없이 breadcrumb만 Topbar leading에 두는 패턴은 피한다 — 페이지 식별이 shell로 샌다. Topbar leading에는 workspace/section만, 페이지 이름은 body로
|
|
32
|
+
|
|
33
|
+
### Fallback
|
|
34
|
+
서브텍스트가 애매하면 생략. 설명이 1줄 미만이면 쓰지 않는다. actions도 없으면 h1 단독으로.
|
|
35
|
+
|
|
36
|
+
### 조립 예시
|
|
37
|
+
```tsx
|
|
38
|
+
<header className="page-header">
|
|
39
|
+
{/* eyebrow 옵션 */}
|
|
40
|
+
<div className="eyebrow">프로젝트</div>
|
|
41
|
+
<div className="title-row">
|
|
42
|
+
<h1>개발 계획·실행</h1>
|
|
43
|
+
<div className="actions">
|
|
44
|
+
<Button variant="outline" size="md">가져오기</Button>
|
|
45
|
+
<Button variant="primary" size="md">새 계획</Button>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<p className="description">
|
|
49
|
+
확정본을 선택해 개발 계획을 요청하고, 계획과 작업 범위를 승인한 뒤 실행하세요.
|
|
50
|
+
</p>
|
|
51
|
+
</header>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```css
|
|
55
|
+
.page-header {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: column;
|
|
58
|
+
gap: var(--space-1); /* eyebrow→title */
|
|
59
|
+
margin-bottom: var(--space-6);
|
|
60
|
+
}
|
|
61
|
+
.page-header .title-row {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
gap: var(--space-3);
|
|
65
|
+
}
|
|
66
|
+
.page-header h1 {
|
|
67
|
+
flex: 1 1 auto;
|
|
68
|
+
font-size: var(--text-3xl);
|
|
69
|
+
font-weight: var(--font-weight-medium);
|
|
70
|
+
line-height: var(--lh-tight);
|
|
71
|
+
}
|
|
72
|
+
.page-header .actions {
|
|
73
|
+
display: flex;
|
|
74
|
+
gap: var(--space-1);
|
|
75
|
+
flex: 0 0 auto;
|
|
76
|
+
}
|
|
77
|
+
.page-header .description {
|
|
78
|
+
color: var(--fg-muted);
|
|
79
|
+
margin-top: var(--space-1); /* title→description은 더 가깝게 */
|
|
80
|
+
max-width: 60ch;
|
|
81
|
+
}
|
|
82
|
+
.page-header .eyebrow {
|
|
83
|
+
font-size: var(--text-xs);
|
|
84
|
+
color: var(--fg-muted);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 관련
|
|
89
|
+
- [[recipes/section-header]] — 하위 섹션의 유사 패턴
|
|
90
|
+
- [[components/topbar]] — shell 쪽. "큰 타이틀은 body 첫 블록 자리" 지침의 수신처
|
|
91
|
+
- [[components/breadcrumb]] — eyebrow 자리에 쓸 수 있는 vendor
|
|
92
|
+
- [[tokens/spacing]] — 블록 아래 리듬 선택
|
|
93
|
+
- [[tokens/typography]] — font weight cap, lh-tight
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Section Header
|
|
2
|
+
|
|
3
|
+
### 원칙
|
|
4
|
+
페이지 바디 안의 **섹션 경계**를 알리는 중간 블록. Page Header보다 작고 조용하다. 섹션이 반복될 때 **같은 리듬·같은 위계**로 등장해야 페이지가 흩어지지 않는다.
|
|
5
|
+
|
|
6
|
+
### Anatomy
|
|
7
|
+
한 줄 row + (옵션) 설명.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
[h2 title] [count] [actions] ← 필수: h2, 옵션: count badge / 우측 액션
|
|
11
|
+
[description] ← 옵션: 1줄 설명 (muted)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- title과 count: `space-2` (한 줄 안)
|
|
15
|
+
- title row와 description: `space-1`
|
|
16
|
+
- 섹션 header와 body(리스트/카드 등) 사이: `space-3`. **body 내부 아이템끼리 gap(space-1)보다 반드시 한 단계 더 넓어야** 위계 성립. 둘이 같으면 "타이틀과 아이템이 같은 레벨"로 뭉쳐 보임
|
|
17
|
+
- 섹션끼리는 **반복되는 작업 단위**면 `space-20`(80px), 섹션 내부 블록 묶음이면 `space-6` ([[ASSEMBLY]] §2a 갭 가이드)
|
|
18
|
+
|
|
19
|
+
### Do
|
|
20
|
+
- h2: **`text-lg` 기본**, 랜딩 리듬이면 `text-xl` 까지. **`font-medium`** ([[tokens/typography]] "섹션 h2/h3는 semibold 금지"). text-xl 이상은 "크고 얇은" 함정에 빠지기 쉬움 — 콘솔 리듬에서는 피함
|
|
21
|
+
- count badge: [[components/badge]] `soft` variant, title 바로 오른쪽
|
|
22
|
+
- actions는 title row 끝에 — `flex: 0 0 auto`
|
|
23
|
+
- actions 중 가장 흔한 "새로고침·더보기"는 [[components/icon-button]] `ghost` 또는 `outline`
|
|
24
|
+
- 액션이 2개 이상이면 서로 간 gap `space-1`
|
|
25
|
+
|
|
26
|
+
### Don't
|
|
27
|
+
- [HARD] `<section>` 태그를 쓰지 않는다 — AppShell의 `.content section`이 `padding-top: space-20`(80px)을 꽂아 "섹션 머리에 거대한 여백" 함정 발생. `<div>`로 짠다 ([[feedback-no-semantic-tags-in-components]])
|
|
28
|
+
- [HARD] h2를 `font-semibold`/`font-bold`로 쓰지 않는다 — [[tokens/typography]] font weight cap
|
|
29
|
+
- [HARD] h2 아래에 `border-bottom`을 깔지 않는다. 섹션 분리는 **gap**이 담당. 선 + 공간은 이중 분리
|
|
30
|
+
- [HARD] 섹션끼리 `space-6` 이상 gap으로 분리하지 않는다 — 각 섹션이 border/배경으로 분리돼 있으면 과한 공간은 "구조가 끊긴" 결과 ([[tokens/spacing]] Don't)
|
|
31
|
+
- [SOFT] title row에 액션이 **3개 이상**이면 Toolbar를 쓴다. 액션이 많으면 섹션이 아니라 toolbar가 맞음
|
|
32
|
+
|
|
33
|
+
### Fallback
|
|
34
|
+
설명이 애매하면 생략. actions도 없으면 h2 단독으로. count badge는 숫자가 **의미 있을 때만**(총 몇 개인지 알아야 하는 리스트 등) — 장식용 금지.
|
|
35
|
+
|
|
36
|
+
### 조립 예시
|
|
37
|
+
```tsx
|
|
38
|
+
<div>
|
|
39
|
+
<header className="section-header">
|
|
40
|
+
<div className="title-row">
|
|
41
|
+
<h2>작업 계획</h2>
|
|
42
|
+
<Badge variant="soft">4</Badge>
|
|
43
|
+
<div className="actions">
|
|
44
|
+
<IconButton icon={<Icon name="arrow-clockwise" />} variant="ghost" aria-label="새로고침" />
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<p className="description">
|
|
48
|
+
요청한 계획을 검토하고 승인하세요.
|
|
49
|
+
</p>
|
|
50
|
+
</header>
|
|
51
|
+
<div className="section-body">
|
|
52
|
+
{/* 섹션 바디 */}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```css
|
|
58
|
+
.section-header {
|
|
59
|
+
display: flex;
|
|
60
|
+
flex-direction: column;
|
|
61
|
+
gap: var(--space-1);
|
|
62
|
+
margin-bottom: var(--space-3);
|
|
63
|
+
}
|
|
64
|
+
.section-header .title-row {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: var(--space-2);
|
|
68
|
+
}
|
|
69
|
+
.section-header h2 {
|
|
70
|
+
font-size: var(--text-lg);
|
|
71
|
+
font-weight: var(--font-weight-medium);
|
|
72
|
+
line-height: var(--lh-tight);
|
|
73
|
+
}
|
|
74
|
+
.section-header .actions {
|
|
75
|
+
display: flex;
|
|
76
|
+
gap: var(--space-1);
|
|
77
|
+
margin-left: auto;
|
|
78
|
+
}
|
|
79
|
+
.section-header .description {
|
|
80
|
+
color: var(--fg-muted);
|
|
81
|
+
font-size: var(--text-sm);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 관련
|
|
86
|
+
- [[recipes/page-header]] — 상위 블록. 위계상 h1 → h2
|
|
87
|
+
- [[components/badge]] — count badge
|
|
88
|
+
- [[components/icon-button]] — 섹션 액션
|
|
89
|
+
- [[tokens/spacing]] — 섹션 간 gap
|
|
90
|
+
- [[tokens/typography]] — font weight cap
|