@mindlogic-ai/logician-ui 5.0.0-alpha.2 → 5.0.0-alpha.3

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.
@@ -0,0 +1,301 @@
1
+ import { Canvas, Meta } from '@storybook/blocks';
2
+
3
+ import { En, Ko, LangToggle } from '../guidelines/_components/Lang';
4
+ import * as BrandColour from './BrandColour.stories';
5
+
6
+ <Meta of={BrandColour} name="Usage" />
7
+
8
+ <LangToggle />
9
+
10
+ <En>
11
+
12
+ # Brand & colour usage
13
+
14
+ BAZE is warm neutral: cream and ivory grounds, black text, and colour only
15
+ where it carries a meaning. This page is the rule set behind the 5.0 palette.
16
+ Every swatch below is read from the shipped theme, so the Light and Dark
17
+ columns are the values your app gets.
18
+
19
+ Values and contrast in all four modes: **Setup/Theme/BAZE Palette**. Which
20
+ token for which surface: **Setup/Theme/Using Semantic Tokens**.
21
+
22
+ ## Principles
23
+
24
+ - **Warm neutrals carry the screen.** Most of a screen is `bg.canvas`,
25
+ `layer.*` and `bg.muted` with `fg.default` text. Add colour only when it
26
+ means something.
27
+ - **No teal or mint in product UI.** The brand book's mint and azure stay on
28
+ landing pages and illustrations. In the app, `teal` and `mint` exist only as
29
+ two of the twelve category hues.
30
+ - **Black does button states.** Default, hover, pressed and selected are steps
31
+ of the warm black (`primary.*`), not a brand hue.
32
+ - **Beige-brown does distinction.** Where 4.x used mint to set something
33
+ apart, 5.0 uses `secondary.fg` / `.fgStrong` / `.border`.
34
+ - **Coral comes in two steps and only as points.** `send.*` / `action.iconOnSolid`
35
+ for run and send, `action.mark` for the AI-working mark, the logo and large
36
+ type. Coral never fills a wide surface.
37
+ - **Status colours mean status.** `danger`, `warning`, `success` and `info`
38
+ are never decoration or a way to tell groups apart.
39
+ - **The twelve system hues are for categories only.** `category.{hue}.*`
40
+ carries no status meaning.
41
+ - **Blue means data and links.** `fg.link` for links; a blue monochrome ramp
42
+ for single-measure charts (see Using Semantic Tokens).
43
+ - **No gradients.** A brand band is one solid colour.
44
+
45
+ ## Neutrals
46
+
47
+ <Canvas of={BrandColour.Neutrals} sourceState="none" />
48
+
49
+ Headings use `fg.default` and weight for emphasis, never a brand colour. The
50
+ sand tint (`secondary.surface`) is not a component background; a soft fill is
51
+ `bg.muted`, a page-level band is `bg.subtle`.
52
+
53
+ ## Button states: black, not a hue
54
+
55
+ <Canvas of={BrandColour.ButtonStates} sourceState="none" />
56
+
57
+ - **Hover** moves one step lighter (`primary.hover`); **pressed** uses
58
+ `primary.active` and a small scale-down.
59
+ - Outline and ghost buttons hover to `primary.wash` and press to
60
+ `primary.washActive`. A selected row or menu item is `primary.selected`.
61
+ - The **focus ring** is `focus.ring`: black in light mode, light beige in dark
62
+ mode. It is never coral, because a coral ring reads as an error border.
63
+ - **Disabled** is a fixed grey (`disabled.bg` / `disabled.fg`) with no opacity
64
+ and no hover change. Beige is already the hover and pressed colour, so a
65
+ beige disabled button would look like one being pressed.
66
+ - Sign-up, payment and upgrade buttons are `Button variant="primary"` (black),
67
+ not coral.
68
+
69
+ ## Distinction: beige-brown
70
+
71
+ <Canvas of={BrandColour.Distinction} sourceState="none" />
72
+
73
+ Use the beige-brown steps for icons, accent numbers (earned credits, a total),
74
+ the neutral Badge text and borders that set something apart without implying a
75
+ state. Separate items by lightness within the same beige family, not by
76
+ borrowing a hue.
77
+
78
+ ## Coral
79
+
80
+ <Canvas of={BrandColour.Coral} sourceState="none" />
81
+
82
+ | Coral goes on | Coral never goes on |
83
+ | --- | --- |
84
+ | The send button and `Button variant="accent"` (`send.*`) | Sign-up, payment and upgrade buttons (`primary`) |
85
+ | The coral icon on the black run button (`action.iconOnSolid`) | Wide surfaces, light backgrounds, card fills |
86
+ | The AI-working mark, the logo mark, large type (`action.mark`) | Promotion badges |
87
+ | The unread count badge (`count.*`, a deeper coral red) | Warning and error text or borders; switches and checkboxes when on; links |
88
+
89
+ - **Points, not surfaces.** Nothing coral is larger than a button, badge or
90
+ icon. Coral and the error red are only a few degrees apart in hue; at light
91
+ tints they become the same colour, so a coral wash reads as an error.
92
+ - **One run signal per screen.** In chat the send button disappears while the
93
+ answer is loading and the loading mark takes its place. A count badge and the
94
+ Super Agent diamond are status and identity marks, so they may appear next to
95
+ a run signal.
96
+
97
+ ## Status
98
+
99
+ <Canvas of={BrandColour.Status} sourceState="none" />
100
+
101
+ Status colours report a status or a well-defined system fact (see
102
+ **Components/Badge/Usage** for where `info` stops). Never colour alone: every
103
+ status carries an icon and words (WCAG 1.4.1). Toast and Banner already pair
104
+ each status with its icon.
105
+
106
+ ## Categories: the twelve system hues
107
+
108
+ <Canvas of={BrandColour.Categories} sourceState="none" />
109
+
110
+ Tiles, tags and avatars that need several colours take
111
+ `category.{hue}.surface` with `category.{hue}.fg` for the icon or accent
112
+ text. Multi-series line charts are the exception: series 1 is the data blue
113
+ and the rest follow the LineGraph series order (see LineGraph). Body text on a category surface stays `fg.default`. All twelve share one
114
+ lightness and chroma, so no hue looks more important than another. In code,
115
+ `<Tag category="…">` is the ready-made form.
116
+
117
+ ## Links
118
+
119
+ <Canvas of={BrandColour.Links} sourceState="none" />
120
+
121
+ Links are blue ink with an underline (`fg.link`, hover `fg.linkHover`), in
122
+ chat, Markdown and app copy alike.
123
+
124
+ ## Dark mode
125
+
126
+ Every token flips with the colour mode; the Dark column above is the value.
127
+ What changes meaning, not just value:
128
+
129
+ - `primary.main` becomes light beige with black text on it (`fg.onPrimary`),
130
+ and the focus ring is beige.
131
+ - The run button (`action.bg`) sits close to the dark canvas, so it gets a
132
+ 1px `action.border`.
133
+ - Coral stays the brand coral; `send.bg` is one step deeper so the dark arrow
134
+ keeps its contrast.
135
+ - Disabled is a dark grey, again with no opacity.
136
+
137
+ ## Open
138
+
139
+ These are not decided yet. Don't build new patterns on them; ask the
140
+ logician-ui maintainers first.
141
+
142
+ - **Category icon tiles** (for example the "More" menu): beige-brown tiles or
143
+ the category hues.
144
+ - **Toast shape:** today `Toast` ships a 1px `{status}.border` outline and
145
+ `Banner` ships a left bar. Whether toasts move to the left bar is open.
146
+ - **Warning toast colour:** the guide showed a beige-brown alternative next to
147
+ the yellow `warning.*` that ships today.
148
+ - **Unread notification dot and row:** a coral dot conflicts with "one coral
149
+ signal per screen".
150
+
151
+ ## Related
152
+
153
+ **Setup/Theme/BAZE Palette** (every value and its contrast) ·
154
+ **Setup/Theme/Using Semantic Tokens** (token per surface) ·
155
+ **Components/Badge/Usage** (status vs category in practice).
156
+
157
+ </En>
158
+
159
+ <Ko>
160
+
161
+ # 브랜드와 색 사용
162
+
163
+ BAZE의 화면은 따뜻한 무채색입니다. 크림·아이보리 바탕에 블랙 글자를 쓰고, 색은
164
+ 의미가 있을 때만 씁니다. 이 페이지는 5.0 팔레트의 사용 규칙입니다. 아래 색 견본은
165
+ 모두 실제 테마에서 읽어 오므로, 라이트·다크 칸의 값이 곧 앱에 적용되는 값입니다.
166
+
167
+ 네 가지 모드의 값과 대비는 **Setup/Theme/BAZE Palette**에, 어떤 면에 어떤 토큰을
168
+ 쓰는지는 **Setup/Theme/Using Semantic Tokens**에 있습니다.
169
+
170
+ ## 원칙
171
+
172
+ - **화면은 따뜻한 무채색으로 채웁니다.** 대부분은 `bg.canvas`, `layer.*`,
173
+ `bg.muted` 바탕에 `fg.default` 글자입니다. 색은 뜻이 있을 때만 더합니다.
174
+ - **앱 화면에는 청록과 민트를 쓰지 않습니다.** 가이드북의 민트와 애저는 랜딩
175
+ 페이지와 일러스트에만 남깁니다. 앱에서 `teal`·`mint`는 열두 가지 카테고리 색 가운데
176
+ 두 가지로만 존재합니다.
177
+ - **버튼 상태는 블랙 단계로 나타냅니다.** 기본·호버·누름·선택은 브랜드 색이 아니라
178
+ 따뜻한 블랙의 단계(`primary.*`)입니다.
179
+ - **구분은 베이지-브라운이 맡습니다.** 4.x에서 민트로 구분하던 자리는 5.0에서
180
+ `secondary.fg` / `.fgStrong` / `.border`를 씁니다.
181
+ - **코랄은 두 단계만, 점으로만 씁니다.** 실행과 보내기에는 `send.*`와
182
+ `action.iconOnSolid`를, AI 작업 중 표시·로고·큰 글씨에는 `action.mark`를 씁니다.
183
+ 넓은 면은 코랄로 칠하지 않습니다.
184
+ - **상태색은 상태를 뜻할 때만 씁니다.** `danger`, `warning`, `success`, `info`를
185
+ 장식이나 그룹 구분에 빌려 쓰지 않습니다.
186
+ - **열두 가지 시스템 색은 카테고리 구분에만 씁니다.** `category.{hue}.*`에는 상태의
187
+ 뜻이 없습니다.
188
+ - **파란색은 데이터와 링크를 뜻합니다.** 링크는 `fg.link`, 하나의 값을 보여 주는
189
+ 차트는 파란색 단색 단계를 씁니다(Using Semantic Tokens 참고).
190
+ - **그라데이션은 쓰지 않습니다.** 브랜드 띠는 단색 하나로 칠합니다.
191
+
192
+ ## 무채색
193
+
194
+ <Canvas of={BrandColour.Neutrals} sourceState="none" />
195
+
196
+ 제목도 `fg.default`를 쓰고, 강조는 색이 아니라 굵기로 합니다. 샌드 틴트
197
+ (`secondary.surface`)는 컴포넌트 바탕으로 쓰지 않습니다. 옅은 면은 `bg.muted`,
198
+ 페이지 단위의 띠는 `bg.subtle`입니다.
199
+
200
+ ## 버튼 상태: 색이 아니라 블랙 단계
201
+
202
+ <Canvas of={BrandColour.ButtonStates} sourceState="none" />
203
+
204
+ - **호버**는 한 단계 밝아지고(`primary.hover`), **누름**은 `primary.active`와 살짝
205
+ 줄어드는 효과로 나타냅니다.
206
+ - 테두리·고스트 버튼은 호버에 `primary.wash`, 누름에 `primary.washActive`를 씁니다.
207
+ 선택된 목록 행이나 메뉴는 `primary.selected`입니다.
208
+ - **포커스 링**은 `focus.ring`으로, 라이트에서는 블랙, 다크에서는 밝은 베이지입니다.
209
+ 코랄 링은 오류 테두리처럼 보이므로 쓰지 않습니다.
210
+ - **비활성**은 고정된 회색(`disabled.bg` / `disabled.fg`)이며 투명도를 쓰지 않고
211
+ 호버해도 바뀌지 않습니다. 베이지는 이미 호버와 누름의 색이라, 비활성까지 베이지면
212
+ 누르는 중인 버튼과 구분되지 않습니다.
213
+ - 가입·결제·업그레이드 버튼은 코랄이 아니라 `Button variant="primary"`(블랙)입니다.
214
+
215
+ ## 구분: 베이지-브라운
216
+
217
+ <Canvas of={BrandColour.Distinction} sourceState="none" />
218
+
219
+ 상태를 뜻하지 않으면서 무언가를 돋보이게 할 때 베이지-브라운 단계를 씁니다.
220
+ 아이콘, 강조 숫자(받은 크레딧, 합계), 중립 배지의 글자, 테두리가 여기에 해당합니다.
221
+ 항목끼리 구분할 때도 다른 색을 빌리지 말고 같은 베이지 계열 안에서 밝기로
222
+ 나눕니다.
223
+
224
+ ## 코랄
225
+
226
+ <Canvas of={BrandColour.Coral} sourceState="none" />
227
+
228
+ | 코랄을 쓰는 곳 | 코랄을 쓰지 않는 곳 |
229
+ | --- | --- |
230
+ | 보내기 버튼과 `Button variant="accent"` (`send.*`) | 가입·결제·업그레이드 버튼 (`primary`) |
231
+ | 블랙 실행 버튼 위의 코랄 아이콘 (`action.iconOnSolid`) | 넓은 면, 옅은 배경, 카드 바탕 |
232
+ | AI 작업 중 표시, 로고 마크, 큰 글씨 (`action.mark`) | 프로모션 배지 |
233
+ | 읽지 않은 숫자 배지 (`count.*`, 조금 더 진한 코랄 레드) | 경고·오류 문구와 테두리, 켜진 스위치·체크박스, 링크 |
234
+
235
+ - **면이 아니라 점으로 씁니다.** 버튼·배지·아이콘보다 큰 면을 코랄로 칠하지 않습니다.
236
+ 코랄과 오류 빨강은 색상 차이가 몇 도밖에 나지 않아 옅게 쓰면 같은 색이 됩니다.
237
+ 그래서 코랄 바탕은 오류처럼 읽힙니다.
238
+ - **실행 신호는 한 화면에 하나만 둡니다.** 채팅에서는 답변을 기다리는 동안 보내기
239
+ 버튼이 사라지고 그 자리에 로딩 표시가 나타납니다. 숫자 배지와 Super Agent 마름모는
240
+ 상태와 정체성을 나타내는 표시라 실행 신호와 함께 보여도 됩니다.
241
+
242
+ ## 상태
243
+
244
+ <Canvas of={BrandColour.Status} sourceState="none" />
245
+
246
+ 상태색은 상태나 명확하게 정의된 시스템 사실을 알릴 때만 씁니다(`info`를 어디까지
247
+ 쓰는지는 **Components/Badge/Usage** 참고). 색만으로 알리지 않고 항상 아이콘과 문구를
248
+ 함께 씁니다(WCAG 1.4.1). Toast와 Banner는 상태마다 아이콘을 이미 붙여 줍니다.
249
+
250
+ ## 카테고리: 열두 가지 시스템 색
251
+
252
+ <Canvas of={BrandColour.Categories} sourceState="none" />
253
+
254
+ 여러 색으로 나눠야 하는 타일, 태그, 아바타에는
255
+ `category.{hue}.surface`를 바탕으로, `category.{hue}.fg`를 아이콘이나 강조 글자로
256
+ 씁니다. 여러 계열 선 차트는 예외로, 첫 계열은 데이터 파랑이고 나머지는 LineGraph의
257
+ 계열 순서를 따릅니다(LineGraph 참고). 그 위의 본문 글자는 `fg.default` 그대로 둡니다. 열두 색은 밝기와 채도가 같아서
258
+ 어느 색도 더 중요해 보이지 않습니다. 코드에서는 `<Tag category="…">`를 바로 쓰면
259
+ 됩니다.
260
+
261
+ ## 링크
262
+
263
+ <Canvas of={BrandColour.Links} sourceState="none" />
264
+
265
+ 링크는 채팅, 마크다운, 앱 문구 어디에서나 밑줄과 함께 파란색 글자(`fg.link`, 호버
266
+ `fg.linkHover`)로 씁니다.
267
+
268
+ ## 다크 모드
269
+
270
+ 모든 토큰은 색 모드에 따라 바뀌며, 위 표의 다크 칸이 그 값입니다. 값만이 아니라
271
+ 쓰임이 달라지는 곳은 아래와 같습니다.
272
+
273
+ - `primary.main`은 밝은 베이지가 되고 그 위 글자(`fg.onPrimary`)는 블랙이 됩니다.
274
+ 포커스 링도 베이지입니다.
275
+ - 실행 버튼 바탕(`action.bg`)은 다크 바탕과 거의 같아 1px `action.border` 테두리를
276
+ 둡니다.
277
+ - 코랄은 같은 브랜드 코랄을 쓰되, 어두운 화살표의 대비를 지키려고 `send.bg`를 한 단계
278
+ 진하게 씁니다.
279
+ - 비활성은 짙은 회색이고, 여기서도 투명도를 쓰지 않습니다.
280
+
281
+ ## 아직 정하지 않은 것
282
+
283
+ 아래는 아직 결정되지 않았습니다. 이 위에 새 패턴을 만들지 말고 먼저
284
+ logician-ui 담당자에게 물어 주세요.
285
+
286
+ - **카테고리 아이콘 타일**(예: 더보기 메뉴): 베이지-브라운 타일로 갈지, 카테고리
287
+ 색으로 갈지 정하지 않았습니다.
288
+ - **토스트 모양:** 지금 `Toast`는 1px `{status}.border` 테두리, `Banner`는 왼쪽 바로
289
+ 나옵니다. 토스트도 왼쪽 바로 바꿀지는 정하지 않았습니다.
290
+ - **경고 토스트 색:** 가이드에는 지금 쓰는 노란색 `warning.*` 옆에 베이지-브라운
291
+ 안도 함께 실려 있습니다.
292
+ - **읽지 않은 알림 점과 행:** 코랄 점은 "실행 신호는 한 화면에 하나" 규칙과
293
+ 부딪힙니다.
294
+
295
+ ## 관련 문서
296
+
297
+ **Setup/Theme/BAZE Palette**(모든 값과 대비) ·
298
+ **Setup/Theme/Using Semantic Tokens**(면별 토큰) ·
299
+ **Components/Badge/Usage**(상태와 카테고리를 실제로 나누는 법).
300
+
301
+ </Ko>
@@ -0,0 +1,334 @@
1
+ import { Flex, Stack } from '@chakra-ui/react';
2
+ import { Meta, StoryObj } from '@storybook/react';
3
+
4
+ import { Badge } from '../components/Badge';
5
+ import { Button } from '../components/Button';
6
+ import { Card } from '../components/Card';
7
+ import { CountBadge } from '../components/CountBadge';
8
+ import { SendIcon, Sparkles } from '../components/Icon';
9
+ import { IconButton } from '../components/IconButton';
10
+ import { Tag } from '../components/Tag';
11
+ import { Link, Text } from '../components/Typography';
12
+ import { T } from '../guidelines/_components/Lang';
13
+ import { TokenTable } from '../guidelines/_components/TokenTable';
14
+ import { SYSTEM_HUE_NAMES } from '../theme/colors';
15
+
16
+ /**
17
+ * Specimens for `BrandColour.mdx` (Foundations / Brand & colour usage).
18
+ *
19
+ * Every swatch is resolved from the shipped theme by `TokenTable`, and every
20
+ * live example is a real component, so the page follows the palette. Hidden
21
+ * from the sidebar (`!dev`); the MDX page is the entry point.
22
+ */
23
+ const meta: Meta = {
24
+ title: 'Foundations/Brand & colour usage',
25
+ tags: ['!dev'],
26
+ parameters: { layout: 'padded' },
27
+ };
28
+ export default meta;
29
+ type Story = StoryObj;
30
+
31
+ export const Neutrals: Story = {
32
+ render: () => (
33
+ <TokenTable
34
+ rows={[
35
+ {
36
+ token: 'bg.canvas',
37
+ use: <T en="Page (layer 0)" ko="페이지 바탕 (layer 0)" />,
38
+ },
39
+ {
40
+ token: 'layer.1',
41
+ use: <T en="Sidebar, panel" ko="사이드바, 패널" />,
42
+ },
43
+ {
44
+ token: 'layer.2',
45
+ use: <T en="Card on a panel" ko="패널 위 카드" />,
46
+ },
47
+ {
48
+ token: 'bg.muted',
49
+ use: (
50
+ <T
51
+ en="Soft fill: neutral badge, wash card"
52
+ ko="옅은 면: 중립 배지, 카드"
53
+ />
54
+ ),
55
+ },
56
+ {
57
+ token: 'border.default',
58
+ use: <T en="Card border" ko="카드 테두리" />,
59
+ },
60
+ {
61
+ token: 'fg.default',
62
+ use: <T en="Body text (brand black)" ko="본문 글자 (브랜드 블랙)" />,
63
+ },
64
+ {
65
+ token: 'fg.muted',
66
+ use: <T en="Secondary text" ko="보조 글자" />,
67
+ },
68
+ {
69
+ token: 'fg.subtle',
70
+ use: <T en="Captions" ko="설명 글자" />,
71
+ },
72
+ {
73
+ token: 'fg.onPrimary',
74
+ use: <T en="Text on a primary fill" ko="주요 버튼 위 글자" />,
75
+ },
76
+ ]}
77
+ />
78
+ ),
79
+ };
80
+
81
+ export const ButtonStates: Story = {
82
+ render: () => (
83
+ <Stack gap={5}>
84
+ <Flex gap={3} wrap="wrap" align="center">
85
+ <Button variant="primary">
86
+ <T en="Subscribe" ko="구독하기" />
87
+ </Button>
88
+ <Button variant="secondary">
89
+ <T en="Cancel" ko="취소" />
90
+ </Button>
91
+ <Button variant="subtle">
92
+ <T en="More" ko="더보기" />
93
+ </Button>
94
+ <Button variant="ghost">
95
+ <T en="Edit" ko="수정" />
96
+ </Button>
97
+ <Button variant="primary" disabled>
98
+ <T en="Current plan" ko="현재 플랜" />
99
+ </Button>
100
+ </Flex>
101
+ <TokenTable
102
+ rows={[
103
+ {
104
+ token: 'primary.main',
105
+ use: (
106
+ <T
107
+ en="Primary fill, checked controls"
108
+ ko="주요 버튼 바탕, 켜진 컨트롤"
109
+ />
110
+ ),
111
+ },
112
+ { token: 'primary.hover', use: <T en="Hover" ko="호버" /> },
113
+ { token: 'primary.active', use: <T en="Pressed" ko="누름" /> },
114
+ {
115
+ token: 'primary.wash',
116
+ use: (
117
+ <T en="Hover on outline / ghost" ko="테두리·고스트 버튼 호버" />
118
+ ),
119
+ },
120
+ {
121
+ token: 'primary.washActive',
122
+ use: (
123
+ <T en="Pressed on outline / ghost" ko="테두리·고스트 버튼 누름" />
124
+ ),
125
+ },
126
+ {
127
+ token: 'primary.selected',
128
+ use: <T en="Selected row or menu item" ko="선택된 목록 행·메뉴" />,
129
+ },
130
+ {
131
+ token: 'focus.ring',
132
+ use: <T en="Focus ring (never coral)" ko="포커스 링 (코랄 금지)" />,
133
+ },
134
+ {
135
+ token: 'disabled.bg',
136
+ use: (
137
+ <T
138
+ en="Disabled fill (grey, no opacity)"
139
+ ko="비활성 바탕 (회색, 투명도 없음)"
140
+ />
141
+ ),
142
+ },
143
+ {
144
+ token: 'disabled.fg',
145
+ use: <T en="Disabled text" ko="비활성 글자" />,
146
+ },
147
+ ]}
148
+ />
149
+ </Stack>
150
+ ),
151
+ };
152
+
153
+ export const Distinction: Story = {
154
+ render: () => (
155
+ <Stack gap={5}>
156
+ <Flex gap={3} wrap="wrap" align="center">
157
+ <Badge>Pro</Badge>
158
+ <Card px={3} py={2} borderColor="secondary.border">
159
+ <Text color="secondary.fgStrong" fontWeight="bold">
160
+ +4,500
161
+ </Text>
162
+ </Card>
163
+ </Flex>
164
+ <TokenTable
165
+ rows={[
166
+ {
167
+ token: 'secondary.fg',
168
+ use: <T en="Icons, accent numbers" ko="아이콘, 강조 숫자" />,
169
+ },
170
+ {
171
+ token: 'secondary.fgStrong',
172
+ use: <T en="Text (neutral Badge)" ko="글자 (중립 배지)" />,
173
+ },
174
+ {
175
+ token: 'secondary.border',
176
+ use: <T en="Borders, dividers" ko="테두리, 구분선" />,
177
+ },
178
+ {
179
+ token: 'secondary.surface',
180
+ use: (
181
+ <T
182
+ en="Tint only — not a background"
183
+ ko="틴트 전용 — 바탕으로 쓰지 않음"
184
+ />
185
+ ),
186
+ },
187
+ ]}
188
+ />
189
+ </Stack>
190
+ ),
191
+ };
192
+
193
+ export const Coral: Story = {
194
+ render: () => (
195
+ <Stack gap={5}>
196
+ <Flex gap={4} wrap="wrap" align="center">
197
+ <Button variant="action">
198
+ <Sparkles />
199
+ <T en="Generate image" ko="이미지 생성" />
200
+ </Button>
201
+ <IconButton variant="action" aria-label="보내기">
202
+ <SendIcon />
203
+ </IconButton>
204
+ <CountBadge count={3} label="읽지 않은 알림 3개" />
205
+ </Flex>
206
+ <TokenTable
207
+ rows={[
208
+ {
209
+ token: 'send.bg',
210
+ use: (
211
+ <T
212
+ en="Send button fill, Button accent"
213
+ ko="보내기 버튼 바탕, Button accent"
214
+ />
215
+ ),
216
+ },
217
+ {
218
+ token: 'send.fg',
219
+ use: <T en="Arrow / label on it" ko="그 위 화살표·글자" />,
220
+ },
221
+ {
222
+ token: 'action.iconOnSolid',
223
+ use: (
224
+ <T
225
+ en="Coral icon on the black run button"
226
+ ko="블랙 실행 버튼의 코랄 아이콘"
227
+ />
228
+ ),
229
+ },
230
+ {
231
+ token: 'action.bg',
232
+ use: <T en="Run button fill" ko="실행 버튼 바탕" />,
233
+ },
234
+ {
235
+ token: 'action.mark',
236
+ use: (
237
+ <T
238
+ en="AI-working mark, logo, large type"
239
+ ko="AI 작업 중 표시, 로고, 큰 글씨"
240
+ />
241
+ ),
242
+ },
243
+ {
244
+ token: 'count.bg',
245
+ use: <T en="Unread count badge" ko="읽지 않은 숫자 배지" />,
246
+ },
247
+ { token: 'count.fg', use: <T en="Number on it" ko="그 위 숫자" /> },
248
+ ]}
249
+ />
250
+ </Stack>
251
+ ),
252
+ };
253
+
254
+ const STATUS = [
255
+ { s: 'danger', en: 'Failed', ko: '실패' },
256
+ { s: 'warning', en: 'Pending', ko: '대기 중' },
257
+ { s: 'success', en: 'Done', ko: '완료' },
258
+ { s: 'info', en: 'This group only', ko: '이 그룹만' },
259
+ ] as const;
260
+
261
+ export const Status: Story = {
262
+ render: () => (
263
+ <Stack gap={5}>
264
+ <Flex gap={2} wrap="wrap">
265
+ {STATUS.map(({ s, en, ko }) => (
266
+ <Badge key={s} variant={s}>
267
+ <T en={en} ko={ko} />
268
+ </Badge>
269
+ ))}
270
+ </Flex>
271
+ <TokenTable
272
+ rows={STATUS.flatMap(({ s }) => [
273
+ {
274
+ token: `${s}.bg`,
275
+ use: <T en={`${s} · surface`} ko={`${s} · 면`} />,
276
+ },
277
+ {
278
+ token: `${s}.fg`,
279
+ use: <T en={`${s} · text, icon`} ko={`${s} · 글자, 아이콘`} />,
280
+ },
281
+ {
282
+ token: `${s}.solid`,
283
+ use: <T en={`${s} · fill, bar`} ko={`${s} · 채움, 바`} />,
284
+ },
285
+ ])}
286
+ />
287
+ </Stack>
288
+ ),
289
+ };
290
+
291
+ export const Categories: Story = {
292
+ render: () => (
293
+ <Stack gap={5}>
294
+ <Flex gap={2} wrap="wrap">
295
+ {SYSTEM_HUE_NAMES.map((hue) => (
296
+ <Tag key={hue} category={hue} icon="#">
297
+ {hue}
298
+ </Tag>
299
+ ))}
300
+ </Flex>
301
+ <TokenTable
302
+ rows={SYSTEM_HUE_NAMES.flatMap((hue) => [
303
+ `category.${hue}.surface`,
304
+ `category.${hue}.fg`,
305
+ ])}
306
+ />
307
+ </Stack>
308
+ ),
309
+ };
310
+
311
+ export const Links: Story = {
312
+ render: () => (
313
+ <Stack gap={5}>
314
+ <Text>
315
+ <T en="Read the " ko="자세한 내용은 " />
316
+ <Link href="#">
317
+ <T en="usage policy" ko="이용 정책" />
318
+ </Link>
319
+ <T en=" before you share a chatbot." ko="을 확인하세요." />
320
+ </Text>
321
+ <TokenTable
322
+ rows={[
323
+ {
324
+ token: 'fg.link',
325
+ use: (
326
+ <T en="Link text, with underline" ko="링크 글자 (밑줄과 함께)" />
327
+ ),
328
+ },
329
+ { token: 'fg.linkHover', use: <T en="Link hover" ko="링크 호버" /> },
330
+ ]}
331
+ />
332
+ </Stack>
333
+ ),
334
+ };