@conscience-technology/ctds 0.1.8 → 0.1.9

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.
@@ -127,26 +127,29 @@
127
127
  padding: 0 var(--space-2) var(--space-2);
128
128
  }
129
129
 
130
- /* SingleLine */
130
+ /* SingleLine — Shift+Enter로 자라면 textarea 상단으로 확장, 좌/우 버튼은 하단 고정.
131
+ MultiLine과 동일 max-height(≈8줄)에서 스크롤. */
131
132
  .shape-single .body {
132
133
  flex-direction: row;
133
- align-items: center;
134
+ align-items: flex-end; /* 버튼들 하단 고정 */
134
135
  gap: var(--space-0_5);
135
136
  padding: var(--space-2) var(--space-2);
136
137
  }
137
138
  .singleField {
138
139
  flex: 1 1 auto;
139
140
  min-width: 0;
140
- padding: 0 var(--space-1);
141
+ padding: calc((var(--space-8) - var(--text-sm) * 1.5) / 2) var(--space-1);
141
142
  background: transparent;
142
143
  border: 0;
143
144
  outline: none;
144
145
  resize: none;
145
- overflow: hidden;
146
146
  color: var(--fg-strong);
147
147
  font: inherit;
148
148
  font-size: var(--text-sm);
149
149
  line-height: 1.5;
150
+ /* MultiLine과 동일 상한 — 넘으면 textarea 자체 스크롤 */
151
+ max-height: calc(var(--text-sm) * 1.5 * 8);
152
+ overflow-y: auto;
150
153
  }
151
154
  .singleField::placeholder {
152
155
  color: var(--fg-muted);
@@ -108,14 +108,15 @@ export const ChatInput = forwardRef<HTMLDivElement, ChatInputProps>(
108
108
  const canSend = !disabled && (value.trim().length > 0 || attachments.length > 0);
109
109
  const showStop = isStreaming && !!onStop;
110
110
 
111
- /* autoResize — multi/single 둘 다. textarea는 content에 맞춰 자람(scroll 아님).
112
- 외부 scroll wrapper(multi)가 max-height 책임. single은 wrapper 없이 textarea가 직접 자람.
113
- Shift+Enter로 줄바꿈 → textarea가 즉시 자라고, SingleLine도 자연스레 늘어남. */
111
+ /* autoResize — multi/single 둘 다. textarea는 content에 맞춰 자람.
112
+ Shift+Enter로 줄바꿈 → textarea 즉시 확장. max 넘으면 CSS max-height가 scroll 생성. */
114
113
  useLayoutEffect(() => {
115
114
  const el = taRef.current;
116
115
  if (!el) return;
117
116
  el.style.height = "auto";
118
- el.style.height = `${el.scrollHeight}px`;
117
+ // scrollHeight로 설정하되 CSS max-height가 override하도록 직접 min
118
+ const nextH = el.scrollHeight;
119
+ el.style.height = `${nextH}px`;
119
120
  }, [shape, value]);
120
121
 
121
122
  const handleKeyDown = useCallback(
@@ -19,7 +19,7 @@ root는 `<div role="menuitem">`이다 — `leadingActions`/`trailingActions`에
19
19
  ### Don't
20
20
  - MenuItem 안에 두 개 이상의 &ldquo;주된 액션&rdquo;을 두지 않는다 — 아이템 전체가 하나의 selection. 부가 액션(즐겨찾기 토글·⋯메뉴)만 slot에 얹는다.
21
21
  - 라벨을 두 줄 이상 넣지 않는다. 설명이 필요하면 [[components/command-palette]] description 슬롯이나 [[components/tooltip]].
22
- - 페이지 이동에 root click 시맨틱 금지. 라우팅 아이템이면 `asChild`로 `<Link>`/`<a>`에 위임.
22
+ - 페이지 이동에 root click 시맨틱 금지. 라우팅 아이템이면 `asChild`로 `<Link>`/`<a>`에 위임. **단, `asChild`일 땐 라벨 `.label` 래퍼가 적용되지 않는다** — 자식(`<Link>`) 자체가 라벨 역할이라 truncation·color·weight가 자동 상속되지 않음. 긴 라벨이면 `<Link>` 쪽에 truncate 유틸을 걸거나, 짧게 유지하는 설계로.
23
23
  - height를 CSS로 덮어쓰지 않는다. `size` prop 경유 (Density 축이 스왑).
24
24
  - hover-only 액션을 &ldquo;시각적으로 숨김&rdquo;으로만 처리하지 않는다 — `opacity: 0` + `pointer-events: none`이 짝. 안 그러면 안 보이는 버튼이 클릭됨.
25
25
 
@@ -81,6 +81,7 @@ type MenuItemAction =
81
81
  checked={boolean} // leadingActions 맨 앞에 checkmark 자동 삽입
82
82
  active={boolean} // 현재 페이지/선택 아이템 강조
83
83
  disabled={boolean}
84
+ collapsed={boolean} // icon-only. leading 하나만 남기고 label/trailing/shortcut 전부 숨김. (Sidebar가 자동 주입)
84
85
  asChild={boolean} // Radix Slot — <Link>/<a>/DropdownMenu.Item 등에 위임
85
86
  onClick={(e) => void}
86
87
  />
@@ -1,23 +1,38 @@
1
1
  # Sidebar
2
2
 
3
3
  ### 원칙
4
- 좌측 세로 nav. **라우팅 전용** — Tabs/필터는 쓸 곳이 아님. Brand(home 링크) + Section(그룹 라벨) + Item(라우트 링크) + Profile(사용자) + Footer가 compound 조합. `collapsed`로 icon-only 축소. Item은 [[components/menu-item]]을 그대로 어댑트 — 시각·상태 규칙 공유.
4
+ 좌측 세로 nav. **라우팅 전용** — Tabs/필터는 쓸 곳이 아님. Header(고정) + Body(스크롤) + Footer(고정) 3영역 세로 쉘에, Brand + Section + Item + Separator + Profile을 compound로 조합. `collapsed`로 icon-only 축소. Item은 [[components/menu-item]]을 그대로 어댑트 — 시각·상태 규칙 공유.
5
+
6
+ ### 3영역 구조 (중요)
7
+ Sidebar는 **Header / Body / Footer 세 영역으로 강제 분리**된다. 역할 혼동이 레이아웃 사고의 1순위 원인.
8
+
9
+ | 영역 | 스크롤 | 레이아웃 | 담는 것 |
10
+ |---|---|---|---|
11
+ | `Sidebar.Header` | ❌ 고정 | **가로 flex 행** (brand symbol + wordmark 나란히) | `Sidebar.Brand` 전용 |
12
+ | `Sidebar.Body` | ✅ 세로 스크롤 | 세로 flex 열 | `Sidebar.Section` · `Sidebar.Separator` 전부 여기 |
13
+ | `Sidebar.Footer` | ❌ 고정 | 가로 flex 행 | `Sidebar.Profile` 또는 보조 액션 |
14
+
15
+ Header는 **가로 행**이기 때문에 Section을 넣으면 nav 전체가 가로 1줄로 눌려 겹친다. Section·Item·Separator는 반드시 `Sidebar.Body` 안에.
5
16
 
6
17
  ### Do
7
- - 라우트 이동은 Item에 `asChild` + Next `<Link>`.
18
+ - Section·Separator는 반드시 **`Sidebar.Body` 안에** 둔다 — Body만 스크롤되는 영역.
19
+ - 라우트 이동은 Item에 `asChild` + Next `<Link>`. 단, `asChild`일 땐 라벨 truncation이 `<Link>` 쪽 책임이 된다 ([[components/menu-item]] Slot 동작) — 긴 라벨이면 Link에 `truncate` 유틸 또는 `title` 속성을 걸 것.
8
20
  - 현재 라우트는 `active`로 명시 (MenuItem의 active 시각 그대로).
9
21
  - Brand는 Home 링크 자리로. `symbol`(항상 노출) + `wordmark`(expanded만).
10
22
  - Section 묶음은 `title`로 그룹. collapsed일 땐 title 자동 숨김.
11
23
  - `collapsed` 상태에서는 `aria-label`과 `title`을 자동으로 걸어 접근성 유지.
24
+ - 콘텐츠 영역과의 **경계선은 [[components/app-frame]] `variant="outlined"`** 가 그린다 — Sidebar 자체는 border를 그리지 않음. 사이드바가 녹아 보이면 AppFrame variant부터 확인.
12
25
 
13
26
  ### Don't
27
+ - **Header에 Section·Item·nav를 넣지 않는다** — Header는 가로 flex 행이라 세로 nav가 깔리면 전부 눌려 겹친다. Brand 전용.
14
28
  - 페이지 안 뷰 전환에 쓰지 않는다 — 그건 [[components/tabs]].
15
29
  - Item 안에 variant로 다른 톤을 쓰지 않는다. active 외의 강조 금지.
16
30
  - Sidebar 자체에 padding/width를 CSS로 덮지 않는다. `--sidebar-w*` 토큰 경유.
31
+ - `.root`에 padding을 꽂지 않는다 — Body가 스크롤 컨테이너라 스크롤바가 안쪽으로 밀려 가장자리에 안 붙는다. 좌우 여백은 Header/Section/Footer가 각자 담당([[project_scroll_rule]]).
17
32
  - Brand symbol·wordmark 크기 override 금지. `--sidebar-brand-symbol-max`·`--sidebar-brand-wordmark-max` 상한 안에서만.
18
33
 
19
34
  ### Fallback
20
- collapsed 결정 애매하면 `false`. Section title 애매하면 생략.
35
+ collapsed 결정 애매하면 `false`. Section title 애매하면 생략. 경계선 애매하면 AppFrame `variant="outlined"`.
21
36
 
22
37
  ### 관련
23
38
  - [[components/menu-item]] — Item 시각·상태 전부 재사용
@@ -29,26 +44,31 @@ collapsed 결정 애매하면 `false`. Section title 애매하면 생략.
29
44
  ### Props 시그니처
30
45
  ```tsx
31
46
  <Sidebar collapsed={boolean}> // default: false
47
+ {/* Header — 고정, 가로 행. Brand 전용. */}
32
48
  <Sidebar.Header>
33
49
  <Sidebar.Brand symbol={<Icon />} wordmark={<Logo /> | "CTDS"} />
34
50
  </Sidebar.Header>
35
51
 
36
- <Sidebar.Section title="워크스페이스">
37
- <Sidebar.Item
38
- icon={<Icon name="house" />}
39
- label="대시보드"
40
- active={boolean}
41
- trailing={ReactNode} // 배지·카운트
42
- shortcut="⌘1"
43
- hasSubmenu={boolean}
44
- disabled={boolean}
45
- asChild={boolean}
46
- onClick={(e) => void}
47
- />
48
- </Sidebar.Section>
49
-
50
- <Sidebar.Separator />
51
-
52
+ {/* Body — 세로 스크롤 트랙. Section·Separator 전부 여기. 여러 개 두면 각자 독립 스크롤. */}
53
+ <Sidebar.Body>
54
+ <Sidebar.Section title="워크스페이스">
55
+ <Sidebar.Item
56
+ icon={<Icon name="house" />}
57
+ label="대시보드"
58
+ active={boolean}
59
+ trailing={ReactNode} // 배지·카운트
60
+ shortcut="⌘1"
61
+ hasSubmenu={boolean}
62
+ disabled={boolean}
63
+ asChild={boolean}
64
+ onClick={(e) => void}
65
+ />
66
+ </Sidebar.Section>
67
+
68
+ <Sidebar.Separator />
69
+ </Sidebar.Body>
70
+
71
+ {/* Footer — 고정, 하단. Profile 또는 보조 액션. */}
52
72
  <Sidebar.Footer>
53
73
  <Sidebar.Profile
54
74
  name="희영"
@@ -69,26 +89,28 @@ collapsed 결정 애매하면 `false`. Section title 애매하면 생략.
69
89
 
70
90
  ### 조합 예시
71
91
  ```tsx
72
- // 기본 — 섹션 2개 + Profile
92
+ // 기본 — 섹션 2개 + Profile. Section·Separator는 Body 안.
73
93
  <Sidebar>
74
94
  <Sidebar.Header>
75
95
  <Sidebar.Brand symbol={<Icon name="rocket-launch" />} wordmark="CTDS" />
76
96
  </Sidebar.Header>
77
97
 
78
- <Sidebar.Section title="워크스페이스">
79
- <Sidebar.Item asChild icon={<Icon name="house" />} label="대시보드" active>
80
- <Link href="/">대시보드</Link>
81
- </Sidebar.Item>
82
- <Sidebar.Item asChild icon={<Icon name="chart-line" />} label="분석">
83
- <Link href="/analytics">분석</Link>
84
- </Sidebar.Item>
85
- </Sidebar.Section>
98
+ <Sidebar.Body>
99
+ <Sidebar.Section title="워크스페이스">
100
+ <Sidebar.Item asChild icon={<Icon name="house" />} label="대시보드" active>
101
+ <Link href="/">대시보드</Link>
102
+ </Sidebar.Item>
103
+ <Sidebar.Item asChild icon={<Icon name="chart-line" />} label="분석">
104
+ <Link href="/analytics">분석</Link>
105
+ </Sidebar.Item>
106
+ </Sidebar.Section>
86
107
 
87
- <Sidebar.Separator />
108
+ <Sidebar.Separator />
88
109
 
89
- <Sidebar.Section title="설정">
90
- <Sidebar.Item icon={<Icon name="gear" />} label="환경설정" shortcut="⌘," />
91
- </Sidebar.Section>
110
+ <Sidebar.Section title="설정">
111
+ <Sidebar.Item icon={<Icon name="gear" />} label="환경설정" shortcut="⌘," />
112
+ </Sidebar.Section>
113
+ </Sidebar.Body>
92
114
 
93
115
  <Sidebar.Footer>
94
116
  <Sidebar.Profile name="희영" sub="admin@ctds.dev" avatar={{ status: "online" }} />
@@ -100,8 +122,10 @@ collapsed 결정 애매하면 `false`. Section title 애매하면 생략.
100
122
  <Sidebar.Header>
101
123
  <Sidebar.Brand symbol={<Icon name="rocket-launch" />} />
102
124
  </Sidebar.Header>
103
- <Sidebar.Section>
104
- <Sidebar.Item icon={<Icon name="house" />} label="대시보드" active />
105
- </Sidebar.Section>
125
+ <Sidebar.Body>
126
+ <Sidebar.Section>
127
+ <Sidebar.Item icon={<Icon name="house" />} label="대시보드" active />
128
+ </Sidebar.Section>
129
+ </Sidebar.Body>
106
130
  </Sidebar>
107
131
  ```
@@ -29,6 +29,7 @@ Layer 1(shadcn 방식 컴포넌트 코드) + Layer 2(AI 프롬프트 컨텍스
29
29
  |---|---|
30
30
  | 컴포넌트 신규 제작·variant/prop 수정 (`web/components/<Name>/` 또는 `prompts/components/<name>.md`) | `ctds-component` |
31
31
  | 페이지·대시보드·레이아웃 조합 (`web/app/**/page.tsx`) | `ctds-page` |
32
+ | **와이어프레임/기존 페이지를 CTDS로 번역·교체** (사용자가 "CTDS로 바꿔줘/교체해줘/일괄 변경" 요청, 또는 와이어프레임 코드·이미지를 입력) | `ctds-wireframe` |
32
33
  | 테마 프리셋 생성·수정 (`prompts/themes/*` 또는 `web/app/theme-demo/*`) | `ctds-theme` |
33
34
  | 코드 검증 (하드코딩·유령 토큰·메모리 규칙·문서-코드 동기화) | `ctds-validate` |
34
35
  | 3D 아이콘 일러스트 자산 생성 | `ctds-illust` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conscience-technology/ctds",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "CTDS — 하이브리드 디자인 시스템 설치 · 온보딩 CLI",
5
5
  "type": "module",
6
6
  "bin": {