@conscience-technology/ctds 0.3.4 → 0.4.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 (53) hide show
  1. package/assets/components/Button/Button.module.css +2 -2
  2. package/assets/components/EventListItem/EventListItem.module.css +220 -0
  3. package/assets/components/EventListItem/EventListItem.tsx +205 -0
  4. package/assets/components/EventListItem/index.ts +8 -0
  5. package/assets/components/Icon/Icon.tsx +80 -41
  6. package/assets/components/Kanban/Kanban.module.css +339 -0
  7. package/assets/components/Kanban/Kanban.tsx +371 -0
  8. package/assets/components/Kanban/index.ts +10 -0
  9. package/assets/components/ListItem/ListItem.module.css +91 -211
  10. package/assets/components/ListItem/ListItem.tsx +130 -154
  11. package/assets/components/ListItem/index.ts +2 -2
  12. package/assets/components/MetricCard/MetricCard.module.css +5 -5
  13. package/assets/components/PageHeader/PageHeader.module.css +109 -0
  14. package/assets/components/PageHeader/PageHeader.tsx +112 -0
  15. package/assets/components/PageHeader/index.ts +2 -0
  16. package/assets/components/Sidebar/Sidebar.module.css +81 -4
  17. package/assets/components/Sidebar/Sidebar.tsx +11 -2
  18. package/assets/components/SplitButton/SplitButton.module.css +3 -3
  19. package/assets/components/Stepper/Stepper.module.css +196 -52
  20. package/assets/components/Stepper/Stepper.tsx +68 -13
  21. package/assets/components/Switch/Switch.module.css +1 -9
  22. package/assets/components/Topbar/Topbar.module.css +33 -5
  23. package/assets/components/Topbar/Topbar.tsx +62 -7
  24. package/assets/components/_data.ts +11 -4
  25. package/assets/components/index.ts +2 -0
  26. package/assets/components/tokens.css +23 -10
  27. package/assets/prompts/ASSEMBLY.md +219 -0
  28. package/assets/prompts/PRINCIPLES.md +70 -0
  29. package/assets/prompts/axes/icon.md +7 -1
  30. package/assets/prompts/axes/palette.md +11 -0
  31. package/assets/prompts/components/_variants.md +5 -1
  32. package/assets/prompts/components/callout.md +3 -3
  33. package/assets/prompts/components/event-list-item.md +103 -0
  34. package/assets/prompts/components/generated-image.md +80 -0
  35. package/assets/prompts/components/hint.md +57 -0
  36. package/assets/prompts/components/kanban.md +167 -0
  37. package/assets/prompts/components/list-item.md +182 -204
  38. package/assets/prompts/components/metric-card.md +2 -2
  39. package/assets/prompts/components/page-header.md +155 -0
  40. package/assets/prompts/components/toast.md +1 -0
  41. package/assets/prompts/components/topbar.md +77 -59
  42. package/assets/prompts/recipes/README.md +102 -0
  43. package/assets/prompts/recipes/card-row.md +58 -0
  44. package/assets/prompts/recipes/form-footer.md +76 -0
  45. package/assets/prompts/recipes/meta-line.md +61 -0
  46. package/assets/prompts/recipes/page-banner.md +121 -0
  47. package/assets/prompts/recipes/page-header.md +93 -0
  48. package/assets/prompts/recipes/section-header.md +90 -0
  49. package/assets/prompts/themes/focus.md +72 -0
  50. package/assets/skills/ctds/SKILL.md +1 -0
  51. package/assets/skills/ctds-page/SKILL.md +12 -2
  52. package/assets/skills/ctds-wireframe/SKILL.md +35 -1
  53. package/package.json +2 -4
@@ -1,59 +1,73 @@
1
1
  /*
2
- * ListItem — row 레벨 수평 anatomy. 수직 리듬은 parent gap/hairline에 위임.
2
+ * ListItem — 3구역 뼈대: [leading] [content] [trailing]
3
3
  *
4
- * padding/border/bg는 자체적으로 걸지 않지만, hover bg는 "chrome"이 아니라
5
- * "상호작용 피드백"이므로 row 레벨에서 담당.
4
+ * 수직 리듬은 CSS 변수로 조절:
5
+ * --li-pad-y 세로 padding (hit area)
6
+ * --li-gap-x leading↔content↔trailing 가로 gap
7
+ * --li-gap-title Title↔Description 간격 (조밀)
8
+ * --li-gap-body Description↔Meta·Note 간격 (한 숨 벌림)
9
+ * --li-gap-header Header 아이템 간 가로 gap
10
+ * --li-gap-meta Meta 라인 아이템 간 가로 gap
6
11
  *
7
- * 색상 훅 (부모 컨테이너에서 오버라이드):
8
- * --list-item-fg body 서술 색 (default: --fg)
9
- * --list-item-from-fg from(누구) 색 (default: --fg-strong)
10
- * --list-item-meta-fg meta/상대시간 색 (default: --fg-muted)
11
- * --list-item-hover-bg hover 시 row bg (default: --hover). transparent로 끄기
12
+ * chrome 없음 — bg·border·radius 자체 공급 X. 리스트 분리는 부모가 담당.
13
+ * 블록 외형이 필요하면 [[Callout]] 사용.
12
14
  */
13
15
 
14
16
  .root {
17
+ --li-pad-y: var(--space-3);
18
+ --li-pad-x: var(--space-2);
19
+ --li-gap-x: var(--space-3);
20
+ --li-gap-title: var(--space-0_5);
21
+ --li-gap-body: var(--space-2);
22
+ --li-gap-header: var(--space-2);
23
+ --li-gap-meta: var(--space-2);
24
+
15
25
  display: flex;
16
- align-items: flex-start;
17
- gap: var(--space-3);
18
- color: var(--list-item-fg, var(--fg));
19
- text-decoration: none;
26
+ gap: var(--li-gap-x);
20
27
  min-width: 0;
21
- /* 좌우 padding 없음 — 가로 anatomy는 flex gap만 담당해서 좌우 비대칭 방지.
22
- 세로 padding만 걸어 hover hit area 확보. 부모 li가 세로 hairline/padding을
23
- 담당하면 음의 margin으로 리듬 유지. 좌우로 hover bg를 넓히고 싶으면
24
- 부모 wrapper에 padding/negative margin을 걸어 조정한다. */
25
- padding-block: var(--space-3);
26
- margin-block: calc(var(--space-3) * -1);
28
+ color: var(--fg);
29
+ text-decoration: none;
30
+ /* hit area를 좌우로 넓혀 hover bg가 한 숨 바깥까지 번지도록 (negative margin으로 정렬 유지) */
31
+ padding: var(--li-pad-y) var(--li-pad-x);
32
+ margin-inline: calc(var(--li-pad-x) * -1);
33
+ border-radius: var(--radius-md);
27
34
  transition: var(--transition-colors);
28
35
  }
29
36
 
30
- .inline {
31
- align-items: center;
37
+ .root:hover {
38
+ background: var(--hover);
32
39
  }
33
40
 
34
- .stacked {
41
+ .align-center {
42
+ align-items: center;
43
+ }
44
+ .align-top {
35
45
  align-items: flex-start;
36
- /* 두 줄짜리는 세로 호흡을 한 단계 더. margin-block은 root 기본값(-space-3) 유지해
37
- 실제 레이아웃 박스가 벌어지도록. */
38
- padding-block: var(--space-4);
39
46
  }
40
47
 
41
- /* row hover — 모든 리스트 항목에서 "지금 이 줄" 신호.
42
- pure 좌표에서 끄려면 --list-item-hover-bg: transparent. */
43
- .root:hover {
44
- background: var(--list-item-hover-bg, var(--hover));
48
+ /* size=md (기본) — 작업/자원 리스트 밀도. 전체 호흡은 넉넉하되
49
+ Title↔Description은 조밀하게 묶어 "제목+부제" 유닛감 유지. */
50
+ .size-md {
51
+ --li-pad-y: var(--space-3);
52
+ --li-gap-title: var(--space-0_5);
53
+ --li-gap-body: var(--space-2);
54
+ }
55
+
56
+ /* size=sm — 활동 로그·추출 완료처럼 타이트하게 쌓이는 리스트. */
57
+ .size-sm {
58
+ --li-pad-y: var(--space-2);
59
+ --li-gap-title: var(--space-0_5);
60
+ --li-gap-body: var(--space-1);
45
61
  }
46
62
 
47
63
  .interactive {
48
64
  cursor: pointer;
49
65
  }
50
-
51
66
  .interactive:focus-visible {
52
67
  outline: none;
53
68
  box-shadow: var(--ring-shadow);
54
69
  }
55
70
 
56
- /* Leading — Avatar / Icon / 커스텀 */
57
71
  .leading {
58
72
  flex-shrink: 0;
59
73
  display: inline-flex;
@@ -62,16 +76,20 @@
62
76
  color: var(--fg-muted);
63
77
  }
64
78
 
65
- /* leading 안쪽에 size=auto인 leadingIcon이 있으면 wrapper를 투명화해서
66
- leadingIcon이 root flex의 직접 자식이 되게 한다 — 그래야 align-self: stretch가
67
- root content 전체 높이를 받고, root gap이 leadingIcon에 직접 적용됨. */
68
- .leading:has(.leadingIcon.auto) {
69
- display: contents;
79
+ /* leading/trailing 안 raw Icon(svg)은 리스트 밀도에 맞춰 16px로 축소.
80
+ LeadingIcon·Avatar·Badge·DateStamp·Button·IconButton 등 wrapped 요소는 자체 크기를 가지므로
81
+ :scope > svg 직접 자식만 겨냥 — 중첩된 아이콘(Badge 안 icon 등)에는 영향 없음. */
82
+ .leading > svg,
83
+ .trailing > svg {
84
+ width: var(--space-4);
85
+ height: var(--space-4);
86
+ }
87
+
88
+ .align-top > .leading {
89
+ align-items: flex-start;
90
+ padding-top: var(--space-0_5);
70
91
  }
71
92
 
72
- /* ListItemLeadingIcon — "배경색 + 아이콘" leading 타입.
73
- Avatar와 같은 사이즈 트랙에 올려 리스트에서 섞여도 정렬이 깨지지 않는다.
74
- bg/fg는 tone 프리셋 또는 CSS 변수로 자유 조절. */
75
93
  .leadingIcon {
76
94
  flex-shrink: 0;
77
95
  display: inline-flex;
@@ -81,28 +99,16 @@
81
99
  color: var(--leading-icon-fg, var(--fg));
82
100
  border-radius: var(--radius-sm);
83
101
  }
84
-
85
- .leadingIcon.xs { width: var(--space-4); height: var(--space-4); border-radius: var(--radius-xs); }
86
- .leadingIcon.sm { width: var(--space-6); height: var(--space-6); border-radius: var(--radius-sm); }
87
- .leadingIcon.md { width: var(--space-8); height: var(--space-8); border-radius: var(--radius-md); }
88
- .leadingIcon.lg { width: var(--space-12); height: var(--space-12); border-radius: var(--radius-lg); }
89
-
90
- /* auto — stacked 두 줄 content 높이에 딱 맞는 정사각 마크.
91
- flex 아이템에서 aspect-ratio + align-self: stretch 조합은 width가 min-content로
92
- 풀려 세로로 길어진다. 그래서 height를 토큰 기반으로 명시해 폭을 그에 묶는다.
93
- 계산: stacked content 두 줄 = from(text-sm × lh-tight) + body(text-sm × lh-sm) + gap(space-1).
94
- 오버라이드가 필요하면 --leading-icon-size로 통째로 교체. */
95
- .leadingIcon.auto {
96
- align-self: center;
97
- height: var(--leading-icon-size,
98
- calc(var(--text-sm) * var(--lh-tight) + var(--lh-sm) + var(--space-1))
99
- );
102
+ .leadingIcon.li-xs { width: var(--space-4); height: var(--space-4); border-radius: var(--radius-xs); }
103
+ .leadingIcon.li-sm { width: var(--space-6); height: var(--space-6); border-radius: var(--radius-sm); }
104
+ .leadingIcon.li-md { width: var(--space-8); height: var(--space-8); border-radius: var(--radius-md); }
105
+ .leadingIcon.li-lg { width: var(--space-12); height: var(--space-12); border-radius: var(--radius-lg); }
106
+ .leadingIcon.li-auto {
107
+ align-self: stretch;
100
108
  aspect-ratio: 1 / 1;
101
- width: auto;
102
109
  border-radius: var(--radius-md);
103
110
  }
104
111
 
105
- /* tone 프리셋 — subtle bg + solid fg 쌍. */
106
112
  .leadingIcon[data-tone="neutral"] {
107
113
  --leading-icon-bg: var(--bg-muted);
108
114
  --leading-icon-fg: var(--fg);
@@ -128,191 +134,65 @@
128
134
  --leading-icon-fg: var(--info);
129
135
  }
130
136
 
131
- /* Read-state 톤 신호 ──────────────────────────────────
132
- dot/badge 없이 텍스트 톤만으로 읽음/안읽음을 표현.
133
- - unread: 전체 톤이 가장 진하게 (body=fg-strong), meta는 primary로 "지금"을 강조
134
- - read: 전체 톤이 한두 단계 뒤로 물러남
135
- - 둘 다 미지정: 중립 — 리드 개념 없는 자리 */
136
-
137
- /* unread — meta primary, body/from 가장 진한 톤 */
138
- .unread .body,
139
- .unread .target,
140
- .unread .narrativeBody {
141
- color: var(--fg-strong, var(--fg));
142
- }
143
- .unread .from {
144
- color: var(--fg-strong, var(--fg));
145
- font-weight: var(--font-weight-medium);
146
- }
147
- .unread .meta {
148
- color: var(--primary);
149
- font-weight: var(--font-weight-regular);
150
- }
151
-
152
- /* read — 전체 한 단계 뒤로 */
153
- .read .body,
154
- .read .target,
155
- .read .narrativeBody {
156
- color: var(--fg-muted);
157
- }
158
- .read .from {
159
- color: var(--fg-muted);
160
- font-weight: var(--font-weight-regular);
161
- }
162
- .read .meta,
163
- .read .verb,
164
- .read .surface {
165
- color: var(--fg-subtle);
166
- }
167
- .read .leading {
168
- opacity: 0.7;
169
- }
170
-
171
- /* Content wrapper. stacked에서 title↔subtitle gap은 xs(space-1). */
172
137
  .content {
173
138
  flex: 1;
174
139
  min-width: 0;
175
140
  display: flex;
176
141
  flex-direction: column;
177
- gap: var(--space-1);
142
+ gap: 0;
178
143
  }
179
144
 
180
- /* 서술 모드 (A): from body (inline). dash 없이 공백으로만 분리. */
181
- .narrativeBody {
182
- display: inline;
145
+ .title {
183
146
  font-size: var(--text-sm);
184
147
  line-height: var(--lh-sm);
185
- color: var(--list-item-fg, var(--fg));
186
- font-weight: var(--font-weight-regular);
148
+ color: var(--fg-strong, var(--fg));
149
+ font-weight: var(--font-weight-medium);
187
150
  min-width: 0;
188
- }
189
-
190
- .narrativeBody .from {
191
- margin-inline-end: var(--space-2);
192
- }
193
-
194
- /* 서술 모드 (B): from · verb · target · surface */
195
- .actionBody {
151
+ /* Badge 등 inline 요소가 Title 앞에 섞여도 수직 중앙 정렬 유지 */
196
152
  display: inline-flex;
197
153
  flex-wrap: wrap;
198
- align-items: baseline;
199
- gap: var(--space-1_5);
200
- font-size: var(--text-sm);
201
- line-height: var(--lh-sm);
202
- min-width: 0;
203
- }
204
-
205
- /* stacked: content가 flex-column이라 from·body가 자동 2줄로. */
206
- .stacked .from {
207
- font-size: var(--text-sm);
208
- line-height: var(--lh-tight);
154
+ align-items: center;
155
+ gap: var(--space-2);
209
156
  }
210
157
 
211
- .stacked .body {
158
+ .description {
159
+ margin: var(--li-gap-title) 0 0;
212
160
  font-size: var(--text-sm);
213
161
  line-height: var(--lh-sm);
214
- color: var(--list-item-fg, var(--fg));
215
- }
216
-
217
- .from {
218
- font-weight: var(--font-weight-medium);
219
- color: var(--list-item-from-fg, var(--fg-strong));
220
- }
221
-
222
- .body {
223
- color: var(--list-item-fg, var(--fg));
224
- font-weight: var(--font-weight-regular);
225
- }
226
-
227
- .verb {
228
- color: var(--list-item-meta-fg, var(--fg-muted));
229
- font-weight: var(--font-weight-regular);
230
- }
231
-
232
- .target {
233
- color: var(--list-item-fg, var(--fg));
162
+ color: var(--fg-muted);
234
163
  font-weight: var(--font-weight-regular);
235
164
  }
236
165
 
237
- /* 작은 글자(surface, meta)는 본문보다 한 단계 더 연하게 — subtle. */
238
- .surface {
239
- font-size: var(--text-xs);
240
- color: var(--list-item-meta-fg, var(--fg-subtle));
241
- margin-inline-start: var(--space-1);
242
- }
243
-
244
- /* Meta — 오른쪽 끝 상대시간. 작은 글자라 subtle 톤. */
245
166
  .meta {
246
- flex-shrink: 0;
167
+ margin-top: var(--li-gap-title);
168
+ display: flex;
169
+ align-items: center;
170
+ gap: var(--li-gap-meta);
247
171
  font-size: var(--text-xs);
248
- color: var(--list-item-meta-fg, var(--fg-subtle));
172
+ line-height: var(--lh-sm);
173
+ color: var(--fg-subtle);
249
174
  font-variant-numeric: tabular-nums;
250
- align-self: center;
251
175
  }
252
-
253
- .stacked .meta {
254
- align-self: flex-start;
255
- margin-top: var(--space-0_5);
176
+ .meta time {
177
+ color: inherit;
256
178
  }
257
179
 
258
- /* Trailing — meta 자리 커스텀 */
259
- .trailing {
180
+ .metaDivider {
181
+ display: inline-block;
182
+ width: var(--hairline);
183
+ height: var(--space-3);
184
+ background: var(--border);
260
185
  flex-shrink: 0;
261
- display: inline-flex;
262
- align-items: center;
263
- gap: var(--space-2);
264
- color: var(--list-item-meta-fg, var(--fg-muted));
265
- font-size: var(--text-xs);
266
186
  }
267
187
 
268
- /* hoverActions — 평상시 숨김, row hover/focus에서 등장 */
269
- .hoverActions {
188
+ .trailing {
189
+ flex-shrink: 0;
270
190
  display: inline-flex;
271
191
  align-items: center;
272
192
  gap: var(--space-1);
273
- flex-shrink: 0;
274
- width: 0;
275
- margin-inline-start: 0;
276
- opacity: 0;
277
- pointer-events: none;
278
- overflow: hidden;
279
- transition:
280
- width var(--duration-fast) var(--ease-out),
281
- margin-inline-start var(--duration-fast) var(--ease-out),
282
- opacity var(--duration-fast) var(--ease-out);
283
- }
284
-
285
- .root:hover .hoverActions,
286
- .root:focus-visible .hoverActions,
287
- .root:focus-within .hoverActions {
288
- width: auto;
289
- margin-inline-start: var(--space-2);
290
- opacity: 1;
291
- pointer-events: auto;
292
- }
293
-
294
- @media (hover: none) {
295
- .hoverActions {
296
- width: auto;
297
- margin-inline-start: var(--space-2);
298
- opacity: 1;
299
- pointer-events: auto;
300
- }
301
- }
302
-
303
- /* Variant별 default — anatomy는 공통. */
304
- .activity {
305
- /* no-op */
306
- }
307
-
308
- .notification {
309
- /* TSX에서 unread default true 처리 */
310
- }
311
-
312
- .mention .body {
313
- font-style: italic;
314
- }
315
-
316
- .system .leading {
317
193
  color: var(--fg-muted);
194
+ align-self: center;
195
+ }
196
+ .align-top > .trailing {
197
+ align-self: flex-start;
318
198
  }