sellmate-design-system-react 9.0.0-beta.80 → 9.0.0-beta.85

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.
@@ -50,7 +50,7 @@
50
50
  | **버튼·링크** | `SButton` `SGhostButton` `SMeatballButton`(⋯ 로 '더 보기' 메뉴를 여는 아이콘 버튼) `SDropdownButton` `STextLink` `SSwitch` `SToggle` |
51
51
  | **입력 (폼)** | `SForm` `SField` `SInput` `SChatInput`(대화 입력창) `SSearchInput` `SNumberInput` `STextarea` `SEditor` `SSelect` `SCheckbox` `SRadio` `SRadioGroup` `SRadioButton` `SRadioCard` `SRadioCardGroup` `SChip` `SChipInput` `SBarcodeInput` `SFilePicker` |
52
52
  | **날짜·시간** | `SCalendar` `SCalendarBoard`(한 달치 일정 판) `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` |
53
- | **표·목록** | `SChatMessage`(대화의 메시지 한 건) `SChatAttachedFile`(입력창 위, 아직 보내지 않은 첨부 한 칸) `SChatFile`(대화 흐름에 선, 보낸 파일 한 칸) `SChatSystemMessage`(대화 흐름 가운데 서는 시스템 안내) `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SListItem` `SExpansionList` `SDraggableList` `SDraggableItem` `STree` |
53
+ | **표·목록** | `SChatMessage`(대화의 메시지 한 건) `SChatAttachedFile`(입력창 위, 아직 보내지 않은 첨부 한 칸) `SChatFile`(대화 흐름에 선, 보낸 파일 한 칸) `SChatSystemMessage`(대화 흐름 가운데 서는 시스템 안내) `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SListItem` `SExpansionList` `SDraggableList` `SDraggableItem` `STree` `STimeline`(날짜로 묶인 시간순 기록 — 작업 로그·메모 이력) |
54
54
  | **레이아웃** | `SLayout` `SGnb` `SGnbSystem` `SSystemActionButton`(GNB system 패널에 한 줄씩 쌓는 액션 행 — 버튼 고르기는 §3-5) `SAccountListBox`(계정 행을 눌러 뜨는 계정 패널) `SLauncherListBox`(런처 버튼을 눌러 뜨는 서비스 목록) `SPage` `SPageHeader`(페이지 제목 영역 — `SLayout` 안에서 `SPage` 앞에 둔다) `SSectionHeaderCard` `SCard` `SLoginCard`(통합 계정 로그인 화면의 카드) `SDivider` `SSplitter` `SScrollArea` `SExpansionItem` |
55
55
  | **내비게이션** | `STabs` `SPagination` `SStepper` |
56
56
  | **차트** | `SBarChart`(막대 그래프 — 항목끼리 크기를 견준다. `stacked` 로 항목 안의 구성까지) `SLineChart`(꺾은선 그래프 — 순서가 있는 항목의 추이를 본다. `area` 로 크기까지, `stacked` 로 구성까지) `SPieChart`(원그래프 — 한 시점의 전체를 몇 개의 몫으로 나눈다) `SDonutChart`(도넛 그래프 — 가운데가 빈 원그래프. 구멍에 글자를 두지 않는다) |
@@ -175,7 +175,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
175
175
  | 층 | 무엇인가 | 컴포넌트 |
176
176
  | --- | --- | --- |
177
177
  | **셸** | 앱 전체 뼈대. 페이지가 바뀌어도 남는다 | `SLayout` `SGnb` `SGnbSystem`(GNB 맨 아래 판 · 전폭 상단바 오른쪽 끝) `SPage` `SPageHeader`(`SLayout` 안에서 `SPage` 앞에 둔다) |
178
- | **블록** | `SPage` 의 직계 자식. 페이지를 세로로 쌓는 단위 | `SSectionHeaderCard` `SCard` `SChatMessage` `SChatSystemMessage` `SChatInput` `SLoginCard`(유일하게 `SPage` 밖에 선다 — 로그인 화면 자체가 자기 자리다, §4-6) `SForm` `SSplitter` `SScrollArea` `SCalendarBoard` `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SExpansionList` `SDraggableList` `STree` `SCallout` `SContextAlert` `SBarChart` `SLineChart` `SPieChart` `SDonutChart` `STabs` `SStepper` `SPagination` `SDivider` |
178
+ | **블록** | `SPage` 의 직계 자식. 페이지를 세로로 쌓는 단위 | `SSectionHeaderCard` `SCard` `SChatMessage` `SChatSystemMessage` `SChatInput` `SLoginCard`(유일하게 `SPage` 밖에 선다 — 로그인 화면 자체가 자기 자리다, §4-6) `SForm` `SSplitter` `SScrollArea` `SCalendarBoard` `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SExpansionList` `SDraggableList` `STree` `STimeline` `SCallout` `SContextAlert` `SBarChart` `SLineChart` `SPieChart` `SDonutChart` `STabs` `SStepper` `SPagination` `SDivider` |
179
179
  | **요소** | 블록 **안에** 놓이는 컨트롤. 혼자 페이지에 서지 않는다 | `SButton` `SGhostButton` `SMeatballButton` `SDropdownButton` `SSystemActionButton` `SField` `SInput` `SSearchInput` `SNumberInput` `STextarea` `SEditor` `SSelect` `SCheckbox` `SRadio` `SRadioGroup` `SRadioButton` `SRadioCard` `SRadioCardGroup` `SSwitch` `SToggle` `SChipInput` `SBarcodeInput` `SFilePicker` `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` `SCalendar` `SListItem` `SExpansionItem` `SDraggableItem` `SChatAttachedFile` `SChatFile` `SImage` `SLinearProgress` `SCircleProgress` `SSkeleton` |
180
180
  | **인라인** | 텍스트 흐름·셀·라벨 안에 섞인다. 혼자 블록이 되지 않는다 | `STag` `SBadge` `SIcon` `SLogo` `STextLink` `SChip` |
181
181
  | **레이어** | 문서 흐름 **밖**에 떠서 그려진다. 어느 층에서 띄우든 레이아웃에 영향이 없다 | `SModal` `SActionModal` `SConfirmModal` `SPopup` `SDrawer` `SPopover` `STooltip` `SPortal` `SAccountListBox`(계정 행에 붙어 뜬다 — 직접 띄우지 않는다) `SLauncherListBox`(런처 버튼에 붙어 뜬다 — 직접 띄우지 않는다) `SToast` `SLoadingModal` `SLoadingContainer` `SGuide` |
@@ -571,6 +571,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
571
571
  | 여러 건을 여러 열로 보여주고 열끼리 비교하게 한다 | `STable` | §3-7-6 |
572
572
  | 항목 하나의 속성들을 `라벨: 값` 으로 보여준다 | `SKeyValueTable` | §4-4 |
573
573
  | 한 줄로 읽히는 항목을 세로로 나열한다 | `SList` + `SListItem` | §3-7-6 |
574
+ | 시각이 붙은 기록을 날짜별로 묶어 시간순으로 보여준다 (작업 로그·메모 이력) | `STimeline` | §3-7-6 |
574
575
  | 대화의 메시지 한 건을 보여준다 | `SChatMessage` | |
575
576
  | 대화 중간에 시스템이 알리는 사실을 끼운다 (상담사 배정·대화 종료 등) | `SChatSystemMessage` | 사람이 보낸 말이면 `SChatMessage` |
576
577
  | 나열한 항목을 펼쳐 하위 내용을 보여준다 | `SExpansionList` + `SExpansionItem` | §3-7-7 |
@@ -1425,6 +1426,7 @@ tableRef.current.scrollToRow(row); // 복원
1425
1426
  | **`default`**(기본) | `#888888` | **대부분** — 닫기, 복사, 드래그, 펼치기, 행 삭제 |
1426
1427
  | `action` | `#025497` | 진입·추가처럼 **의미 있는 조작** — 편집 모드 진입, 항목 추가, 행 수정 |
1427
1428
  | `subAction` | `#5CB0F3` | `action` 다음 계층 — `action`·`default` 사이의 중의적 의미 + 부분 강조 |
1429
+ | `complete` | `#00973C` | **완료**를 나타내는 조작 — 완료 처리(`check`) 등 |
1428
1430
  | `danger` | `#E30000` | **되돌릴 수 없는 삭제** |
1429
1431
  | `inverse` | `#FFFFFF` | 어두운 배경 위 (GNB 접기 등) |
1430
1432
 
@@ -1906,15 +1908,17 @@ const [from, setFrom] = useState<string | null>(null);
1906
1908
 
1907
1909
  직접 쓰는 경우는 하나뿐이다 — **디자인 시스템에 없는 컨트롤**에 다른 필드와 똑같은 라벨·필수·에러 모양을 붙일 때.
1908
1910
 
1909
- #### 3-7-6. 여러 건을 나열하는 셋 — STable vs SList vs SDraggableList
1911
+ #### 3-7-6. 여러 건을 나열하는 넷 — STable vs SList vs SDraggableList vs STimeline
1910
1912
 
1911
1913
  | 판별 | 사용 |
1912
1914
  | --- | --- |
1913
1915
  | 열이 둘 이상이고 **열끼리 값을 비교**한다 (정렬·합계·자릿수 맞춤) | `STable` |
1914
1916
  | 한 항목이 **한 줄로 읽힌다** (제목 + 보조 텍스트) | `SList` + `SListItem` |
1915
1917
  | **순서 자체가 데이터**라 사용자가 끌어서 바꾼다 | `SDraggableList` + `SDraggableItem` |
1918
+ | 항목마다 **시각**이 있고 날짜 머리글로 묶여 위에서 아래로 흐른다 (작업 로그·메모 이력) | `STimeline` |
1916
1919
 
1917
1920
  - **항목 하나의 속성을 나열하는 것은 목록이 아니다.** `라벨: 값` 이 세로로 쌓이는 것은 `SKeyValueTable` 이다 (§4-4).
1921
+ - **`STimeline` 의 레일(점·선)과 머리글·시각 열은 컴포넌트가 그린다.** `groups` 에 데이터만 넘기고, 점·선을 `border-l` 이나 절대 위치 `span` 으로 직접 그리지 않는다 — 선이 묶음 경계와 마지막 줄에서 끊기는 규칙을 컴포넌트가 계산한다. 작성자·편집 버튼 같은 업무 내용은 각 항목의 `content` 에 넣는다. 빈 상태 안내도 `emptyText` 로 넘기고, 불러오는 중에는 `emptyText={null}` 로 빈 안내를 숨긴다.
1918
1922
  - `SList` 는 레이아웃만 담당한다. depth 별 단일 펼침이 필요하면 `SExpansionList` 다 (§3-7-7).
1919
1923
  - **`SList` 의 자식은 `SListItem` 을 권장한다.** 다른 자식도 그대로 렌더되지만, 펼치는 항목은 `SExpansionList` + `SExpansionItem` 이, 끌어서 순서를 바꾸는 항목은 `SDraggableList` + `SDraggableItem` 이 여닫힘·정렬 동작까지 함께 관리하므로 그쪽을 쓴다 (§3-7-7).
1920
1924
  - **항목 사이 구분선은 리스트가 알아서 그린다.** `SListItem`·`SExpansionItem`·`SDraggableItem` 셋 다 스스로 구분선을 그리지 않는다. `SList`·`SExpansionList`·`SDraggableList` 가 자식 **사이에** 구분선을 넣으므로 아이템에 `border-b` 를 직접 붙이지 않고, 켜는 prop 도 따로 없다. 마지막 항목 아래에는 선이 남지 않는다. 테두리형(`bordered`)은 테두리가 구분 역할을 하므로 리스트가 구분선을 빼고, `gap` 으로 띄운다 — `gap` 을 준 목록에도 구분선은 들어가지 않는다.
@@ -1927,6 +1931,8 @@ const [from, setFrom] = useState<string | null>(null);
1927
1931
  ❌ <SList><SListItem title="일반 문의" className="border-b" />…</SList> {/* 구분선을 직접 붙이지 않는다 */}
1928
1932
  ❌ <SList><><SListItem title="일반 문의" /><SListItem title="결제 문의" /></></SList> {/* Fragment 로 묶으면 그 안쪽은 구분되지 않는다 */}
1929
1933
  ❌ <SListItem title="일반 문의" selected /> {/* clickable 없으면 선택 표시가 안 나온다 */}
1934
+ ✅ <STimeline groups={[{ heading: '2026-10-07', entries: [{ key: id, time: '14:32', content: <Memo … /> }] }]} />
1935
+ ❌ <div className="grid grid-cols-[52px_8px_1fr]"><span className="rounded-full …" />…</div> {/* 타임라인 레일을 직접 그리지 않는다 */}
1930
1936
  ```
1931
1937
 
1932
1938
  ##### 행 안에 컨트롤을 둘 때
@@ -2177,6 +2183,7 @@ const [selectedId, setSelectedId] = useState<string>();
2177
2183
  - **실제 레이아웃을 그대로 따라 그린다.** 폼 컨트롤 자리는 `type="input"`·`"button"`·`"checkbox"` 처럼 DS 모양을 쓴다. 해당 컴포넌트 기본 size 의 크기·모서리를 토큰으로 넣으므로 **높이·radius 를 직접 주지 않는다** — 직접 주면 데이터가 왔을 때 레이아웃이 튄다. checkbox·radio·switch 는 크기를 바꾸지 않는다.
2178
2184
  - **텍스트 줄은 `type="text"` 를 실제 텍스트와 같은 typo 클래스 안에 둔다.** 줄 높이를 부모 line-height 에서 받으므로 typo 밖에 두면 높이가 어긋난다. `text` 에 `height` 를 주지 않는다 — 높이가 필요하면 `rect` 다.
2179
2185
  - **원은 `size` 하나로 준다.** `width`·`height` 를 따로 주면 타원이 된다.
2186
+ - **색은 바탕 밝기로 `mode` 만 고른다.** 흰 면·회색 면 위는 기본(`light`), 어두운 면 위는 `mode="dark"`. 색·투명도·모서리는 `--cmp-skeleton-*` 토큰으로 이미 들어가므로 `background`·`opacity`·`rounded-*` 를 직접 주지 않는다.
2180
2187
  - **넓은 영역에는 `pulse` 를 쓰지 않는다.** 블록 전체가 줄었다 커져 레이아웃이 흔들려 보인다. 기본 `wave` 를 쓰고, 한 화면에 아주 많으면 `none`.
2181
2188
  - **로딩 중이라는 사실은 감싸는 영역에 `aria-busy` 로 알린다.** `SSkeleton` 자체는 장식이라 보조기기에 숨겨져 있다.
2182
2189
 
@@ -2189,6 +2196,7 @@ const [selectedId, setSelectedId] = useState<string>();
2189
2196
 
2190
2197
  ❌ <SSkeleton type="input" height={40} /> {/* 실제 SInput 과 높이가 달라 데이터가 오면 튄다 */}
2191
2198
  ❌ <SSkeleton type="text" height={24} /> {/* text 는 세로 절반만 칠한다 — rect 를 쓴다 */}
2199
+ ❌ <SSkeleton className="bg-grey-20" /> {/* 색은 토큰이 넣는다 — 어두운 면이면 mode="dark" */}
2192
2200
  ```
2193
2201
 
2194
2202
  ---
@@ -3358,14 +3366,17 @@ export default function SalesDashboardPage() {
3358
3366
  <SCard key={s.label} bordered className="flex flex-col gap-sd-4 p-sd-16">
3359
3367
  <span className="typo-body-sm-default text-fg-secondary">{s.label}</span>
3360
3368
  {/* 카드 안의 메인 수치는 typo-heading-xl — 제목에는 쓰지 않는다 (§2-1) */}
3361
- <span className="typo-heading-xl">
3369
+ <span className="typo-heading-xl text-right">
3362
3370
  {s.value.toLocaleString()}
3363
3371
  {s.unit}
3364
3372
  </span>
3365
- {/* 증감은 숫자 앞 부호와 색으로 함께 말한다 — 색만으로 뜻을 싣지 않는다 */}
3366
- <span className="typo-body-sm-default text-fg-tertiary">
3373
+ {/* 증감은 숫자 앞 부호와 색으로 함께 말한다 — 색만으로 뜻을 싣지 않는다.
3374
+ 문장 안 강조라 굵기는 typo-body-sm-medium 프리셋으로 준다 (§2-1) */}
3375
+ <span className="typo-body-sm-default text-right text-fg-tertiary">
3367
3376
  전기간 대비{' '}
3368
- <span className={s.change >= 0 ? 'text-fg-success' : 'text-fg-danger'}>
3377
+ <span
3378
+ className={`typo-body-sm-medium ${s.change >= 0 ? 'text-fg-success' : 'text-fg-danger'}`}
3379
+ >
3369
3380
  {s.change >= 0 ? '+' : ''}
3370
3381
  {s.change.toLocaleString()}%
3371
3382
  </span>
@@ -3376,16 +3387,20 @@ export default function SalesDashboardPage() {
3376
3387
 
3377
3388
  {/* 차트는 섹션 카드에 담는다. 차트 이름은 카드의 title 이 맡으므로 차트의 title 은 주지 않는다 —
3378
3389
  둘 다 주면 제목이 두 줄이 된다. 단위(unit)는 차트가 오른쪽 위에 적는다.
3379
- 한 페이지에 섹션 카드가 여럿이라 marker 를 켠다 (§4-5) */}
3390
+ 한 페이지 안의 카드 헤더(titleSize·배경)는 전부 같게 간다 (§4-5) */}
3380
3391
  {/* 날짜순 흐름이라 선 — 순서가 있는 항목의 추이 (§3-0 B). 항목(날짜)이 많아 한 줄을 다 쓴다 */}
3381
- <SSectionHeaderCard title="일별 매출" marker>
3392
+ <SSectionHeaderCard
3393
+ title="일별 매출"
3394
+ titleSize="sm"
3395
+ headerClassName="bg-bg-neutralBright!"
3396
+ padding="none"
3397
+ >
3382
3398
  <SLineChart
3383
3399
  categories={daily.categories}
3384
3400
  series={[{ name: '매출', data: daily.data }]}
3385
3401
  unit="원"
3386
3402
  area
3387
3403
  showLegend={false}
3388
- height={280}
3389
3404
  formatValue={won}
3390
3405
  // 차트는 "어느 쪽이 큰가" 까지만 답한다 — 정확한 값은 그날의 주문 목록에서 본다
3391
3406
  onPointClick={p => navigate(`/orders?date=${daily.dates[p.categoryIndex]}`)}
@@ -3394,26 +3409,36 @@ export default function SalesDashboardPage() {
3394
3409
 
3395
3410
  <div className="grid grid-cols-2 gap-sd-12">
3396
3411
  {/* 합계는 도넛 구멍이 아니라 카드 subtitle 에 적는다 (§3-0 B) */}
3397
- <SSectionHeaderCard title="판매처별 비중" marker subtitle={`합계 ${won(channelTotal)}`}>
3412
+ <SSectionHeaderCard
3413
+ title="판매처별 비중"
3414
+ titleSize="sm"
3415
+ subtitle={`합계 ${won(channelTotal)}`}
3416
+ padding="none"
3417
+ headerClassName="bg-bg-neutralBright!"
3418
+ >
3398
3419
  <SDonutChart
3399
3420
  data={channelShare}
3400
3421
  legendPosition="bottom"
3401
3422
  formatValue={won}
3402
3423
  // 그림은 폭만큼의 정사각형이다 — 칸을 다 채우면 옆 카드보다 훨씬 길어지므로
3403
3424
  // 화면 고유 치수로 폭을 묶는다 (§1-2)
3404
- className="mx-auto max-w-[280px]"
3425
+ className="mx-auto max-w-[310px]"
3405
3426
  />
3406
3427
  </SSectionHeaderCard>
3407
3428
 
3408
3429
  {/* 항목끼리 크기를 견주므로 막대. 상품명이 길어 가로 막대로 눕힌다 */}
3409
- <SSectionHeaderCard title="상품별 판매량 TOP 5" marker>
3430
+ <SSectionHeaderCard
3431
+ title="상품별 판매량 TOP 5"
3432
+ titleSize="sm"
3433
+ padding="none"
3434
+ headerClassName="bg-bg-neutralBright!"
3435
+ >
3410
3436
  <SBarChart
3411
3437
  categories={topProducts.categories}
3412
3438
  series={[{ name: '판매량', data: topProducts.data }]}
3413
3439
  unit="개"
3414
3440
  direction="horizontal"
3415
3441
  showLegend={false}
3416
- height={320}
3417
3442
  formatValue={v => `${v.toLocaleString()}개`}
3418
3443
  />
3419
3444
  </SSectionHeaderCard>
@@ -5385,7 +5410,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
5385
5410
  - oceanblue: 15 25 50 60 65 70 75 80 85 90 95 99
5386
5411
  - brilliantblue: 10 20 25 40 50 60 70 75 80 85 90 95 99 05
5387
5412
  - purple: 15 25 45 55 65 70 75 80 85 90 95 99 strong moderate subtle
5388
- - bg: screen frame brand subtle accent accentLight accentBright accentFaint deep danger dangerLight warning caution progress success neutralLight neutralBright tableHeader
5413
+ - bg: screen frame brand subtle accent accentLight accentBright accentFaint deep danger dangerLight warning caution progress success successLight neutralLight neutralBright tableHeader
5389
5414
  - fg: primary secondary tertiary quaternary brand subtleWarm subtleCool deep success successLight dangerLight accent accentLight danger warning warningLight inverse
5390
5415
  - border: default strong bold accent accentLight danger warning success
5391
5416
  - disabled: bg text icon border
@@ -5450,7 +5475,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
5450
5475
  | typo-field-sm-bold | 12px | 700 | 20px |
5451
5476
  | typo-field-md-default | 14px | 400 | 24px |
5452
5477
  | typo-field-md-medium | 14px | 500 | 24px |
5453
- | typo-field-md-bold | 14px | 700 | 24px |
5478
+ | typo-field-md-bold | 14px | 600 | 24px |
5454
5479
  | typo-field-lg-default | 16px | 400 | 26px |
5455
5480
  | typo-field-lg-medium | 16px | 500 | 26px |
5456
5481
  | typo-field-lg-bold | 16px | 700 | 26px |
@@ -5487,6 +5512,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
5487
5512
  --sys-color-bg-screen
5488
5513
  --sys-color-bg-subtle
5489
5514
  --sys-color-bg-success
5515
+ --sys-color-bg-successLight
5490
5516
  --sys-color-bg-tableHeader
5491
5517
  --sys-color-bg-warning
5492
5518
  --sys-color-blue-moderate
@@ -8505,7 +8531,8 @@ export type SGhostButtonSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg';
8505
8531
  ### SGhostButtonIntent
8506
8532
 
8507
8533
  ```ts
8508
- export type SGhostButtonIntent = 'default' | 'danger' | 'action' | 'subAction' | 'inverse';
8534
+ export type SGhostButtonIntent =
8535
+ 'default' | 'danger' | 'action' | 'subAction' | 'complete' | 'inverse';
8509
8536
  ```
8510
8537
 
8511
8538
  ## Dependencies
@@ -10889,6 +10916,7 @@ export type SRadioValue = string | number | boolean;
10889
10916
  | `value?` | `string \| number \| null` | — | 현재 선택 값 |
10890
10917
  | `size?` | `SRadioButtonSize` | `'sm'` | 크기 |
10891
10918
  | `disabled?` | `boolean` | `false` | 전체 비활성 |
10919
+ | `readOnly?` | `boolean` | `false` | 읽기 전용. 선택 값을 보여주기만 하고 바꿀 수 없다. 모든 버튼이 readOnly 배경, 선택된 버튼만 readOnly 테두리로 구분하며 글자는 기본색이다. 포커스·툴팁은 유지된다. `disabled`(그룹·옵션)가 함께 오면 disabled 가 우선한다. |
10892
10920
  | `name?` | `string` | — | input name 속성 |
10893
10921
  | `showTooltip?` | `boolean` | `false` | 옵션 호버 시 툴팁 노출. 문구는 옵션별 `tooltip` 으로 주며, 문구가 없는 옵션은 툴팁을 띄우지 않는다. 툴팁 타입은 `accent` 고정이다. |
10894
10922
  | `className?` | `string` | — | |
@@ -11314,10 +11342,10 @@ export type SSelectValueDisplay = 'text' | 'chip';
11314
11342
  | Prop | Type | Default | Description |
11315
11343
  |------|------|---------|-------------|
11316
11344
  | `type?` | `SSkeletonType` | `'rect'` | 자리표시 모양 - `rect`: 사각형. 폭은 부모를, 높이는 한 줄 높이를 따른다 — 이미지·카드 영역은 `height` 를 준다 - `circle`: 원형(아바타 등) - `text`: 텍스트 한 줄. 부모 타이포의 line-height 를 따르고 세로로 절반만 칠한다 - `button`·`input`·`tag`·`checkbox`·`radio`·`switch`: 해당 컴포넌트 기본 size 의 크기·모서리 |
11345
+ | `mode?` | `SSkeletonMode` | `'light'` | 놓이는 바탕의 밝기 - `light`: 흰 면·회색 면 위. 바탕보다 짙은 반투명 회색 - `dark`: 어두운 면 위. 바탕보다 밝은 반투명 회색 |
11317
11346
  | `animation?` | `SSkeletonAnimation` | `'wave'` | 로딩 애니메이션 - `wave`: 하이라이트 띠가 왼쪽에서 오른쪽으로 지나간다 - `pulse`: 크기가 숨쉬듯 줄었다 커진다. 블록 전체가 움직이므로 아바타처럼 작은 모양에만 쓴다 - `fade`: 투명도가 숨쉬듯 바뀐다 - `none`: 애니메이션 없음 OS 의 동작 줄이기 설정이 켜져 있으면 어떤 값이든 멈춘다. |
11318
11347
  | `animationSpeed?` | `number` | `1500` | 애니메이션 한 주기 (ms) |
11319
11348
  | `square?` | `boolean` | `false` | 모서리를 각지게 |
11320
- | `bordered?` | `boolean` | `false` | 테두리 |
11321
11349
  | `size?` | `string \| number` | — | 가로·세로를 한 번에 지정. `width`·`height` 가 있으면 그쪽이 우선한다. 숫자는 px |
11322
11350
  | `width?` | `string \| number` | — | 폭. 숫자는 px |
11323
11351
  | `height?` | `string \| number` | — | 높이. 숫자는 px |
@@ -11330,6 +11358,12 @@ export type SSelectValueDisplay = 'text' | 'chip';
11330
11358
  export type SSkeletonType = (typeof SKELETON_TYPES)[number];
11331
11359
  ```
11332
11360
 
11361
+ ### SSkeletonMode
11362
+
11363
+ ```ts
11364
+ export type SSkeletonMode = (typeof SKELETON_MODES)[number];
11365
+ ```
11366
+
11333
11367
  ### SSkeletonAnimation
11334
11368
 
11335
11369
  ```ts
@@ -11352,6 +11386,12 @@ export const SKELETON_TYPES = [
11352
11386
  ] as const;
11353
11387
  ```
11354
11388
 
11389
+ ### SKELETON_MODES
11390
+
11391
+ ```ts
11392
+ export const SKELETON_MODES = ['light', 'dark'] as const;
11393
+ ```
11394
+
11355
11395
  ### SKELETON_ANIMATIONS
11356
11396
 
11357
11397
  ```ts
@@ -12378,6 +12418,49 @@ export type STimeRangePickerRangeOrder = 'strict' | 'allow-cross-day';
12378
12418
 
12379
12419
  ---
12380
12420
 
12421
+ # STimeline
12422
+
12423
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
12424
+
12425
+ ### STimeline
12426
+
12427
+ #### Props
12428
+
12429
+ | Prop | Type | Default | Description |
12430
+ |------|------|---------|-------------|
12431
+ | `groups` | `STimelineGroup[]` | — | 머리글로 묶은 항목 목록. 순서 그대로 그린다 |
12432
+ | `emptyText?` | `ReactNode` | `'내역이 없습니다.'` | 항목이 하나도 없을 때 가운데 띄우는 안내. 불러오는 중에는 `null` 을 넘겨 빈 안내가 먼저 깜빡이지 않게 한다. |
12433
+
12434
+ ## Types
12435
+
12436
+ ### STimelineGroup
12437
+
12438
+ ```ts
12439
+ export interface STimelineGroup {
12440
+ /** React key. 생략하면 순서로 대신한다 */
12441
+ key?: Key;
12442
+ /** 묶음 머리글 (예: 날짜) */
12443
+ heading: ReactNode;
12444
+ /** 머리글 아래 항목. 비어 있으면 머리글째 그리지 않는다 */
12445
+ entries: STimelineEntry[];
12446
+ }
12447
+ ```
12448
+
12449
+ ### STimelineEntry
12450
+
12451
+ ```ts
12452
+ export interface STimelineEntry {
12453
+ /** React key — 묶음 안에서 유일해야 한다 */
12454
+ key: Key;
12455
+ /** 레일 왼쪽 열에 오른쪽 정렬로 서는 시각 (예: `14:32`) */
12456
+ time?: ReactNode;
12457
+ /** 레일 오른쪽 본문. 타이포·색은 감싸는 쪽을 따른다 — 업무 내용은 소비 앱이 그린다 */
12458
+ content: ReactNode;
12459
+ }
12460
+ ```
12461
+
12462
+ ---
12463
+
12381
12464
  # SToast
12382
12465
 
12383
12466
  > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
package/dist/llms.txt CHANGED
@@ -51,7 +51,7 @@
51
51
  | **버튼·링크** | `SButton` `SGhostButton` `SMeatballButton`(⋯ 로 '더 보기' 메뉴를 여는 아이콘 버튼) `SDropdownButton` `STextLink` `SSwitch` `SToggle` |
52
52
  | **입력 (폼)** | `SForm` `SField` `SInput` `SChatInput`(대화 입력창) `SSearchInput` `SNumberInput` `STextarea` `SEditor` `SSelect` `SCheckbox` `SRadio` `SRadioGroup` `SRadioButton` `SRadioCard` `SRadioCardGroup` `SChip` `SChipInput` `SBarcodeInput` `SFilePicker` |
53
53
  | **날짜·시간** | `SCalendar` `SCalendarBoard`(한 달치 일정 판) `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` |
54
- | **표·목록** | `SChatMessage`(대화의 메시지 한 건) `SChatAttachedFile`(입력창 위, 아직 보내지 않은 첨부 한 칸) `SChatFile`(대화 흐름에 선, 보낸 파일 한 칸) `SChatSystemMessage`(대화 흐름 가운데 서는 시스템 안내) `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SListItem` `SExpansionList` `SDraggableList` `SDraggableItem` `STree` |
54
+ | **표·목록** | `SChatMessage`(대화의 메시지 한 건) `SChatAttachedFile`(입력창 위, 아직 보내지 않은 첨부 한 칸) `SChatFile`(대화 흐름에 선, 보낸 파일 한 칸) `SChatSystemMessage`(대화 흐름 가운데 서는 시스템 안내) `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SListItem` `SExpansionList` `SDraggableList` `SDraggableItem` `STree` `STimeline`(날짜로 묶인 시간순 기록 — 작업 로그·메모 이력) |
55
55
  | **레이아웃** | `SLayout` `SGnb` `SGnbSystem` `SSystemActionButton`(GNB system 패널에 한 줄씩 쌓는 액션 행 — 버튼 고르기는 §3-5) `SAccountListBox`(계정 행을 눌러 뜨는 계정 패널) `SLauncherListBox`(런처 버튼을 눌러 뜨는 서비스 목록) `SPage` `SPageHeader`(페이지 제목 영역 — `SLayout` 안에서 `SPage` 앞에 둔다) `SSectionHeaderCard` `SCard` `SLoginCard`(통합 계정 로그인 화면의 카드) `SDivider` `SSplitter` `SScrollArea` `SExpansionItem` |
56
56
  | **내비게이션** | `STabs` `SPagination` `SStepper` |
57
57
  | **차트** | `SBarChart`(막대 그래프 — 항목끼리 크기를 견준다. `stacked` 로 항목 안의 구성까지) `SLineChart`(꺾은선 그래프 — 순서가 있는 항목의 추이를 본다. `area` 로 크기까지, `stacked` 로 구성까지) `SPieChart`(원그래프 — 한 시점의 전체를 몇 개의 몫으로 나눈다) `SDonutChart`(도넛 그래프 — 가운데가 빈 원그래프. 구멍에 글자를 두지 않는다) |
@@ -176,7 +176,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
176
176
  | 층 | 무엇인가 | 컴포넌트 |
177
177
  | --- | --- | --- |
178
178
  | **셸** | 앱 전체 뼈대. 페이지가 바뀌어도 남는다 | `SLayout` `SGnb` `SGnbSystem`(GNB 맨 아래 판 · 전폭 상단바 오른쪽 끝) `SPage` `SPageHeader`(`SLayout` 안에서 `SPage` 앞에 둔다) |
179
- | **블록** | `SPage` 의 직계 자식. 페이지를 세로로 쌓는 단위 | `SSectionHeaderCard` `SCard` `SChatMessage` `SChatSystemMessage` `SChatInput` `SLoginCard`(유일하게 `SPage` 밖에 선다 — 로그인 화면 자체가 자기 자리다, §4-6) `SForm` `SSplitter` `SScrollArea` `SCalendarBoard` `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SExpansionList` `SDraggableList` `STree` `SCallout` `SContextAlert` `SBarChart` `SLineChart` `SPieChart` `SDonutChart` `STabs` `SStepper` `SPagination` `SDivider` |
179
+ | **블록** | `SPage` 의 직계 자식. 페이지를 세로로 쌓는 단위 | `SSectionHeaderCard` `SCard` `SChatMessage` `SChatSystemMessage` `SChatInput` `SLoginCard`(유일하게 `SPage` 밖에 선다 — 로그인 화면 자체가 자기 자리다, §4-6) `SForm` `SSplitter` `SScrollArea` `SCalendarBoard` `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SExpansionList` `SDraggableList` `STree` `STimeline` `SCallout` `SContextAlert` `SBarChart` `SLineChart` `SPieChart` `SDonutChart` `STabs` `SStepper` `SPagination` `SDivider` |
180
180
  | **요소** | 블록 **안에** 놓이는 컨트롤. 혼자 페이지에 서지 않는다 | `SButton` `SGhostButton` `SMeatballButton` `SDropdownButton` `SSystemActionButton` `SField` `SInput` `SSearchInput` `SNumberInput` `STextarea` `SEditor` `SSelect` `SCheckbox` `SRadio` `SRadioGroup` `SRadioButton` `SRadioCard` `SRadioCardGroup` `SSwitch` `SToggle` `SChipInput` `SBarcodeInput` `SFilePicker` `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` `SCalendar` `SListItem` `SExpansionItem` `SDraggableItem` `SChatAttachedFile` `SChatFile` `SImage` `SLinearProgress` `SCircleProgress` `SSkeleton` |
181
181
  | **인라인** | 텍스트 흐름·셀·라벨 안에 섞인다. 혼자 블록이 되지 않는다 | `STag` `SBadge` `SIcon` `SLogo` `STextLink` `SChip` |
182
182
  | **레이어** | 문서 흐름 **밖**에 떠서 그려진다. 어느 층에서 띄우든 레이아웃에 영향이 없다 | `SModal` `SActionModal` `SConfirmModal` `SPopup` `SDrawer` `SPopover` `STooltip` `SPortal` `SAccountListBox`(계정 행에 붙어 뜬다 — 직접 띄우지 않는다) `SLauncherListBox`(런처 버튼에 붙어 뜬다 — 직접 띄우지 않는다) `SToast` `SLoadingModal` `SLoadingContainer` `SGuide` |
@@ -572,6 +572,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
572
572
  | 여러 건을 여러 열로 보여주고 열끼리 비교하게 한다 | `STable` | §3-7-6 |
573
573
  | 항목 하나의 속성들을 `라벨: 값` 으로 보여준다 | `SKeyValueTable` | §4-4 |
574
574
  | 한 줄로 읽히는 항목을 세로로 나열한다 | `SList` + `SListItem` | §3-7-6 |
575
+ | 시각이 붙은 기록을 날짜별로 묶어 시간순으로 보여준다 (작업 로그·메모 이력) | `STimeline` | §3-7-6 |
575
576
  | 대화의 메시지 한 건을 보여준다 | `SChatMessage` | |
576
577
  | 대화 중간에 시스템이 알리는 사실을 끼운다 (상담사 배정·대화 종료 등) | `SChatSystemMessage` | 사람이 보낸 말이면 `SChatMessage` |
577
578
  | 나열한 항목을 펼쳐 하위 내용을 보여준다 | `SExpansionList` + `SExpansionItem` | §3-7-7 |
@@ -1426,6 +1427,7 @@ tableRef.current.scrollToRow(row); // 복원
1426
1427
  | **`default`**(기본) | `#888888` | **대부분** — 닫기, 복사, 드래그, 펼치기, 행 삭제 |
1427
1428
  | `action` | `#025497` | 진입·추가처럼 **의미 있는 조작** — 편집 모드 진입, 항목 추가, 행 수정 |
1428
1429
  | `subAction` | `#5CB0F3` | `action` 다음 계층 — `action`·`default` 사이의 중의적 의미 + 부분 강조 |
1430
+ | `complete` | `#00973C` | **완료**를 나타내는 조작 — 완료 처리(`check`) 등 |
1429
1431
  | `danger` | `#E30000` | **되돌릴 수 없는 삭제** |
1430
1432
  | `inverse` | `#FFFFFF` | 어두운 배경 위 (GNB 접기 등) |
1431
1433
 
@@ -1907,15 +1909,17 @@ const [from, setFrom] = useState<string | null>(null);
1907
1909
 
1908
1910
  직접 쓰는 경우는 하나뿐이다 — **디자인 시스템에 없는 컨트롤**에 다른 필드와 똑같은 라벨·필수·에러 모양을 붙일 때.
1909
1911
 
1910
- #### 3-7-6. 여러 건을 나열하는 셋 — STable vs SList vs SDraggableList
1912
+ #### 3-7-6. 여러 건을 나열하는 넷 — STable vs SList vs SDraggableList vs STimeline
1911
1913
 
1912
1914
  | 판별 | 사용 |
1913
1915
  | --- | --- |
1914
1916
  | 열이 둘 이상이고 **열끼리 값을 비교**한다 (정렬·합계·자릿수 맞춤) | `STable` |
1915
1917
  | 한 항목이 **한 줄로 읽힌다** (제목 + 보조 텍스트) | `SList` + `SListItem` |
1916
1918
  | **순서 자체가 데이터**라 사용자가 끌어서 바꾼다 | `SDraggableList` + `SDraggableItem` |
1919
+ | 항목마다 **시각**이 있고 날짜 머리글로 묶여 위에서 아래로 흐른다 (작업 로그·메모 이력) | `STimeline` |
1917
1920
 
1918
1921
  - **항목 하나의 속성을 나열하는 것은 목록이 아니다.** `라벨: 값` 이 세로로 쌓이는 것은 `SKeyValueTable` 이다 (§4-4).
1922
+ - **`STimeline` 의 레일(점·선)과 머리글·시각 열은 컴포넌트가 그린다.** `groups` 에 데이터만 넘기고, 점·선을 `border-l` 이나 절대 위치 `span` 으로 직접 그리지 않는다 — 선이 묶음 경계와 마지막 줄에서 끊기는 규칙을 컴포넌트가 계산한다. 작성자·편집 버튼 같은 업무 내용은 각 항목의 `content` 에 넣는다. 빈 상태 안내도 `emptyText` 로 넘기고, 불러오는 중에는 `emptyText={null}` 로 빈 안내를 숨긴다.
1919
1923
  - `SList` 는 레이아웃만 담당한다. depth 별 단일 펼침이 필요하면 `SExpansionList` 다 (§3-7-7).
1920
1924
  - **`SList` 의 자식은 `SListItem` 을 권장한다.** 다른 자식도 그대로 렌더되지만, 펼치는 항목은 `SExpansionList` + `SExpansionItem` 이, 끌어서 순서를 바꾸는 항목은 `SDraggableList` + `SDraggableItem` 이 여닫힘·정렬 동작까지 함께 관리하므로 그쪽을 쓴다 (§3-7-7).
1921
1925
  - **항목 사이 구분선은 리스트가 알아서 그린다.** `SListItem`·`SExpansionItem`·`SDraggableItem` 셋 다 스스로 구분선을 그리지 않는다. `SList`·`SExpansionList`·`SDraggableList` 가 자식 **사이에** 구분선을 넣으므로 아이템에 `border-b` 를 직접 붙이지 않고, 켜는 prop 도 따로 없다. 마지막 항목 아래에는 선이 남지 않는다. 테두리형(`bordered`)은 테두리가 구분 역할을 하므로 리스트가 구분선을 빼고, `gap` 으로 띄운다 — `gap` 을 준 목록에도 구분선은 들어가지 않는다.
@@ -1928,6 +1932,8 @@ const [from, setFrom] = useState<string | null>(null);
1928
1932
  ❌ <SList><SListItem title="일반 문의" className="border-b" />…</SList> {/* 구분선을 직접 붙이지 않는다 */}
1929
1933
  ❌ <SList><><SListItem title="일반 문의" /><SListItem title="결제 문의" /></></SList> {/* Fragment 로 묶으면 그 안쪽은 구분되지 않는다 */}
1930
1934
  ❌ <SListItem title="일반 문의" selected /> {/* clickable 없으면 선택 표시가 안 나온다 */}
1935
+ ✅ <STimeline groups={[{ heading: '2026-10-07', entries: [{ key: id, time: '14:32', content: <Memo … /> }] }]} />
1936
+ ❌ <div className="grid grid-cols-[52px_8px_1fr]"><span className="rounded-full …" />…</div> {/* 타임라인 레일을 직접 그리지 않는다 */}
1931
1937
  ```
1932
1938
 
1933
1939
  ##### 행 안에 컨트롤을 둘 때
@@ -2178,6 +2184,7 @@ const [selectedId, setSelectedId] = useState<string>();
2178
2184
  - **실제 레이아웃을 그대로 따라 그린다.** 폼 컨트롤 자리는 `type="input"`·`"button"`·`"checkbox"` 처럼 DS 모양을 쓴다. 해당 컴포넌트 기본 size 의 크기·모서리를 토큰으로 넣으므로 **높이·radius 를 직접 주지 않는다** — 직접 주면 데이터가 왔을 때 레이아웃이 튄다. checkbox·radio·switch 는 크기를 바꾸지 않는다.
2179
2185
  - **텍스트 줄은 `type="text"` 를 실제 텍스트와 같은 typo 클래스 안에 둔다.** 줄 높이를 부모 line-height 에서 받으므로 typo 밖에 두면 높이가 어긋난다. `text` 에 `height` 를 주지 않는다 — 높이가 필요하면 `rect` 다.
2180
2186
  - **원은 `size` 하나로 준다.** `width`·`height` 를 따로 주면 타원이 된다.
2187
+ - **색은 바탕 밝기로 `mode` 만 고른다.** 흰 면·회색 면 위는 기본(`light`), 어두운 면 위는 `mode="dark"`. 색·투명도·모서리는 `--cmp-skeleton-*` 토큰으로 이미 들어가므로 `background`·`opacity`·`rounded-*` 를 직접 주지 않는다.
2181
2188
  - **넓은 영역에는 `pulse` 를 쓰지 않는다.** 블록 전체가 줄었다 커져 레이아웃이 흔들려 보인다. 기본 `wave` 를 쓰고, 한 화면에 아주 많으면 `none`.
2182
2189
  - **로딩 중이라는 사실은 감싸는 영역에 `aria-busy` 로 알린다.** `SSkeleton` 자체는 장식이라 보조기기에 숨겨져 있다.
2183
2190
 
@@ -2190,6 +2197,7 @@ const [selectedId, setSelectedId] = useState<string>();
2190
2197
 
2191
2198
  ❌ <SSkeleton type="input" height={40} /> {/* 실제 SInput 과 높이가 달라 데이터가 오면 튄다 */}
2192
2199
  ❌ <SSkeleton type="text" height={24} /> {/* text 는 세로 절반만 칠한다 — rect 를 쓴다 */}
2200
+ ❌ <SSkeleton className="bg-grey-20" /> {/* 색은 토큰이 넣는다 — 어두운 면이면 mode="dark" */}
2193
2201
  ```
2194
2202
 
2195
2203
  ---
@@ -3359,14 +3367,17 @@ export default function SalesDashboardPage() {
3359
3367
  <SCard key={s.label} bordered className="flex flex-col gap-sd-4 p-sd-16">
3360
3368
  <span className="typo-body-sm-default text-fg-secondary">{s.label}</span>
3361
3369
  {/* 카드 안의 메인 수치는 typo-heading-xl — 제목에는 쓰지 않는다 (§2-1) */}
3362
- <span className="typo-heading-xl">
3370
+ <span className="typo-heading-xl text-right">
3363
3371
  {s.value.toLocaleString()}
3364
3372
  {s.unit}
3365
3373
  </span>
3366
- {/* 증감은 숫자 앞 부호와 색으로 함께 말한다 — 색만으로 뜻을 싣지 않는다 */}
3367
- <span className="typo-body-sm-default text-fg-tertiary">
3374
+ {/* 증감은 숫자 앞 부호와 색으로 함께 말한다 — 색만으로 뜻을 싣지 않는다.
3375
+ 문장 안 강조라 굵기는 typo-body-sm-medium 프리셋으로 준다 (§2-1) */}
3376
+ <span className="typo-body-sm-default text-right text-fg-tertiary">
3368
3377
  전기간 대비{' '}
3369
- <span className={s.change >= 0 ? 'text-fg-success' : 'text-fg-danger'}>
3378
+ <span
3379
+ className={`typo-body-sm-medium ${s.change >= 0 ? 'text-fg-success' : 'text-fg-danger'}`}
3380
+ >
3370
3381
  {s.change >= 0 ? '+' : ''}
3371
3382
  {s.change.toLocaleString()}%
3372
3383
  </span>
@@ -3377,16 +3388,20 @@ export default function SalesDashboardPage() {
3377
3388
 
3378
3389
  {/* 차트는 섹션 카드에 담는다. 차트 이름은 카드의 title 이 맡으므로 차트의 title 은 주지 않는다 —
3379
3390
  둘 다 주면 제목이 두 줄이 된다. 단위(unit)는 차트가 오른쪽 위에 적는다.
3380
- 한 페이지에 섹션 카드가 여럿이라 marker 를 켠다 (§4-5) */}
3391
+ 한 페이지 안의 카드 헤더(titleSize·배경)는 전부 같게 간다 (§4-5) */}
3381
3392
  {/* 날짜순 흐름이라 선 — 순서가 있는 항목의 추이 (§3-0 B). 항목(날짜)이 많아 한 줄을 다 쓴다 */}
3382
- <SSectionHeaderCard title="일별 매출" marker>
3393
+ <SSectionHeaderCard
3394
+ title="일별 매출"
3395
+ titleSize="sm"
3396
+ headerClassName="bg-bg-neutralBright!"
3397
+ padding="none"
3398
+ >
3383
3399
  <SLineChart
3384
3400
  categories={daily.categories}
3385
3401
  series={[{ name: '매출', data: daily.data }]}
3386
3402
  unit="원"
3387
3403
  area
3388
3404
  showLegend={false}
3389
- height={280}
3390
3405
  formatValue={won}
3391
3406
  // 차트는 "어느 쪽이 큰가" 까지만 답한다 — 정확한 값은 그날의 주문 목록에서 본다
3392
3407
  onPointClick={p => navigate(`/orders?date=${daily.dates[p.categoryIndex]}`)}
@@ -3395,26 +3410,36 @@ export default function SalesDashboardPage() {
3395
3410
 
3396
3411
  <div className="grid grid-cols-2 gap-sd-12">
3397
3412
  {/* 합계는 도넛 구멍이 아니라 카드 subtitle 에 적는다 (§3-0 B) */}
3398
- <SSectionHeaderCard title="판매처별 비중" marker subtitle={`합계 ${won(channelTotal)}`}>
3413
+ <SSectionHeaderCard
3414
+ title="판매처별 비중"
3415
+ titleSize="sm"
3416
+ subtitle={`합계 ${won(channelTotal)}`}
3417
+ padding="none"
3418
+ headerClassName="bg-bg-neutralBright!"
3419
+ >
3399
3420
  <SDonutChart
3400
3421
  data={channelShare}
3401
3422
  legendPosition="bottom"
3402
3423
  formatValue={won}
3403
3424
  // 그림은 폭만큼의 정사각형이다 — 칸을 다 채우면 옆 카드보다 훨씬 길어지므로
3404
3425
  // 화면 고유 치수로 폭을 묶는다 (§1-2)
3405
- className="mx-auto max-w-[280px]"
3426
+ className="mx-auto max-w-[310px]"
3406
3427
  />
3407
3428
  </SSectionHeaderCard>
3408
3429
 
3409
3430
  {/* 항목끼리 크기를 견주므로 막대. 상품명이 길어 가로 막대로 눕힌다 */}
3410
- <SSectionHeaderCard title="상품별 판매량 TOP 5" marker>
3431
+ <SSectionHeaderCard
3432
+ title="상품별 판매량 TOP 5"
3433
+ titleSize="sm"
3434
+ padding="none"
3435
+ headerClassName="bg-bg-neutralBright!"
3436
+ >
3411
3437
  <SBarChart
3412
3438
  categories={topProducts.categories}
3413
3439
  series={[{ name: '판매량', data: topProducts.data }]}
3414
3440
  unit="개"
3415
3441
  direction="horizontal"
3416
3442
  showLegend={false}
3417
- height={320}
3418
3443
  formatValue={v => `${v.toLocaleString()}개`}
3419
3444
  />
3420
3445
  </SSectionHeaderCard>
@@ -5386,7 +5411,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
5386
5411
  - oceanblue: 15 25 50 60 65 70 75 80 85 90 95 99
5387
5412
  - brilliantblue: 10 20 25 40 50 60 70 75 80 85 90 95 99 05
5388
5413
  - purple: 15 25 45 55 65 70 75 80 85 90 95 99 strong moderate subtle
5389
- - bg: screen frame brand subtle accent accentLight accentBright accentFaint deep danger dangerLight warning caution progress success neutralLight neutralBright tableHeader
5414
+ - bg: screen frame brand subtle accent accentLight accentBright accentFaint deep danger dangerLight warning caution progress success successLight neutralLight neutralBright tableHeader
5390
5415
  - fg: primary secondary tertiary quaternary brand subtleWarm subtleCool deep success successLight dangerLight accent accentLight danger warning warningLight inverse
5391
5416
  - border: default strong bold accent accentLight danger warning success
5392
5417
  - disabled: bg text icon border
@@ -5451,7 +5476,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
5451
5476
  | typo-field-sm-bold | 12px | 700 | 20px |
5452
5477
  | typo-field-md-default | 14px | 400 | 24px |
5453
5478
  | typo-field-md-medium | 14px | 500 | 24px |
5454
- | typo-field-md-bold | 14px | 700 | 24px |
5479
+ | typo-field-md-bold | 14px | 600 | 24px |
5455
5480
  | typo-field-lg-default | 16px | 400 | 26px |
5456
5481
  | typo-field-lg-medium | 16px | 500 | 26px |
5457
5482
  | typo-field-lg-bold | 16px | 700 | 26px |
@@ -5488,6 +5513,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
5488
5513
  --sys-color-bg-screen
5489
5514
  --sys-color-bg-subtle
5490
5515
  --sys-color-bg-success
5516
+ --sys-color-bg-successLight
5491
5517
  --sys-color-bg-tableHeader
5492
5518
  --sys-color-bg-warning
5493
5519
  --sys-color-blue-moderate
@@ -5563,7 +5589,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
5563
5589
  --sys-color-purple-strong
5564
5590
  --sys-color-purple-subtle
5565
5591
 
5566
- ## 3. 컴포넌트 인덱스 (87종)
5592
+ ## 3. 컴포넌트 인덱스 (88종)
5567
5593
 
5568
5594
  **Props 는 이 문서에 없다.** 쓸 컴포넌트를 정했으면 그 컴포넌트의 README 를 읽는다.
5569
5595
 
@@ -5572,4 +5598,4 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
5572
5598
  예) SButton 을 쓴다면 `dist/components/SButton/README.md`.
5573
5599
  prop 을 추측해서 쓰지 말고 반드시 README 로 확인한다 (분류별 용도는 §1 의 "전체 컴포넌트 인덱스" 참조).
5574
5600
 
5575
- SAccountListBox · SActionModal · SBadge · SBarChart · SBarcodeInput · SButton · SCalendar · SCalendarBoard · SCallout · SCard · SChatAttachedFile · SChatFile · SChatInput · SChatMessage · SChatSystemMessage · SCheckbox · SChip · SChipFilter · SChipInput · SCircleProgress · SConfirmModal · SContextAlert · SDatePicker · SDateRangePicker · SDivider · SDonutChart · SDraggableItem · SDraggableList · SDrawer · SDropdownButton · SEditor · SExpansionItem · SExpansionList · SField · SFilePicker · SForm · SGhostButton · SGnb · SGnbSystem · SGuide · SIcon · SImage · SInput · SKeyValueTable · SLauncherListBox · SLayout · SLineChart · SLinearProgress · SList · SListItem · SLoadingContainer · SLoadingModal · SLoginCard · SLogo · SMeatballButton · SModal · SNumberInput · SPage · SPagination · SPieChart · SPopover · SPopup · SPortal · SRadio · SRadioButton · SRadioCard · SScrollArea · SSearchInput · SSectionHeaderCard · SSelect · SSkeleton · SSplitter · SStepper · SSwitch · SSystemActionButton · STable · STableBar · STabs · STag · STextLink · STextarea · STimePicker · STimeRangePicker · SToast · SToggle · STooltip · STree
5601
+ SAccountListBox · SActionModal · SBadge · SBarChart · SBarcodeInput · SButton · SCalendar · SCalendarBoard · SCallout · SCard · SChatAttachedFile · SChatFile · SChatInput · SChatMessage · SChatSystemMessage · SCheckbox · SChip · SChipFilter · SChipInput · SCircleProgress · SConfirmModal · SContextAlert · SDatePicker · SDateRangePicker · SDivider · SDonutChart · SDraggableItem · SDraggableList · SDrawer · SDropdownButton · SEditor · SExpansionItem · SExpansionList · SField · SFilePicker · SForm · SGhostButton · SGnb · SGnbSystem · SGuide · SIcon · SImage · SInput · SKeyValueTable · SLauncherListBox · SLayout · SLineChart · SLinearProgress · SList · SListItem · SLoadingContainer · SLoadingModal · SLoginCard · SLogo · SMeatballButton · SModal · SNumberInput · SPage · SPagination · SPieChart · SPopover · SPopup · SPortal · SRadio · SRadioButton · SRadioCard · SScrollArea · SSearchInput · SSectionHeaderCard · SSelect · SSkeleton · SSplitter · SStepper · SSwitch · SSystemActionButton · STable · STableBar · STabs · STag · STextLink · STextarea · STimePicker · STimeRangePicker · STimeline · SToast · SToggle · STooltip · STree