astryx-dracula 0.4.0 → 0.5.0
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/package.json +6 -2
- package/shared/auth-chrome.tsx +156 -6
- package/shared/chaptered-doc.tsx +3 -4
- package/shared/chart-hues.ts +0 -5
- package/shared/chart-legend.tsx +2 -3
- package/shared/data-bar.tsx +5 -5
- package/shared/format-money.ts +3 -0
- package/shared/metric-card.tsx +127 -0
- package/shared/scene-hues.ts +0 -8
- package/shared/scene-tile.tsx +3 -11
- package/shared/settings-data.ts +28 -0
- package/shared/settings-rows.tsx +1 -6
- package/shared/stars.tsx +28 -0
- package/templates/ai-chat-landing.tsx +88 -58
- package/templates/ai-chat.tsx +65 -78
- package/templates/centered-hero.tsx +2 -2
- package/templates/dashboard-portfolio.tsx +77 -155
- package/templates/dashboard.tsx +17 -134
- package/templates/detail-page.tsx +14 -18
- package/templates/documentation-design.tsx +66 -519
- package/templates/documentation-technical.tsx +2 -22
- package/templates/editor.tsx +168 -185
- package/templates/file-explorer.tsx +10 -24
- package/templates/ide.tsx +12 -18
- package/templates/incident-console.tsx +48 -46
- package/templates/kanban-board.tsx +36 -85
- package/templates/library.tsx +42 -66
- package/templates/login-card.tsx +33 -126
- package/templates/login-split.tsx +91 -123
- package/templates/login-sso.tsx +12 -33
- package/templates/login.tsx +21 -121
- package/templates/messaging-shell.tsx +162 -168
- package/templates/payment-form.tsx +24 -26
- package/templates/product-detail.tsx +7 -40
- package/templates/product-tour.tsx +38 -60
- package/templates/settings-dialog.tsx +10 -32
- package/templates/settings-sidebar.tsx +44 -77
- package/templates/settings.tsx +208 -121
- package/templates/shell-nav.tsx +20 -75
- package/templates/shell-side-nav.tsx +16 -90
- package/templates/shell-top-nav.tsx +20 -53
- package/templates/side-gallery.tsx +19 -19
- package/templates/table-grouped.tsx +17 -164
- package/templates/table-page-chart.tsx +12 -11
- package/templates/table-page-heatmap-status.tsx +0 -17
- package/templates/table-page-shoe-store-heatmap.tsx +12 -12
- package/templates/table-page.tsx +4 -31
- package/templates/table.tsx +7 -10
- package/templates/tech-report.tsx +58 -72
- package/templates/theme-showcase.tsx +124 -415
|
@@ -9,26 +9,19 @@
|
|
|
9
9
|
import {
|
|
10
10
|
useCallback,
|
|
11
11
|
useState,
|
|
12
|
-
useMemo,
|
|
13
|
-
type CSSProperties,
|
|
14
12
|
type ReactNode,
|
|
15
13
|
} from 'react';
|
|
16
14
|
import {Heading, Text} from '@astryxdesign/core/Text';
|
|
17
15
|
import {Button} from '@astryxdesign/core/Button';
|
|
18
16
|
import {Card} from '@astryxdesign/core/Card';
|
|
19
|
-
import {Avatar} from '@astryxdesign/core/Avatar';
|
|
20
17
|
import {Badge} from '@astryxdesign/core/Badge';
|
|
21
|
-
import {Token} from '@astryxdesign/core/Token';
|
|
22
|
-
import {Banner} from '@astryxdesign/core/Banner';
|
|
23
18
|
import {CodeBlock} from '@astryxdesign/core/CodeBlock';
|
|
24
19
|
import {TabList, Tab} from '@astryxdesign/core/TabList';
|
|
25
20
|
import {Selector} from '@astryxdesign/core/Selector';
|
|
26
21
|
import {HStack, VStack} from '@astryxdesign/core/Stack';
|
|
27
22
|
import {Layout, LayoutContent, LayoutPanel} from '@astryxdesign/core/Layout';
|
|
28
23
|
import {useMediaQuery} from '@astryxdesign/core/hooks';
|
|
29
|
-
import {Dialog, DialogHeader} from '@astryxdesign/core/Dialog';
|
|
30
24
|
import {Divider} from '@astryxdesign/core/Divider';
|
|
31
|
-
import {Tooltip} from '@astryxdesign/core/Tooltip';
|
|
32
25
|
import {Table, pixel, proportional} from '@astryxdesign/core/Table';
|
|
33
26
|
import {Icon} from '@astryxdesign/core/Icon';
|
|
34
27
|
import {Section} from '@astryxdesign/core/Section';
|
|
@@ -37,21 +30,6 @@ import {Outline, type OutlineItem} from '@astryxdesign/core/Outline';
|
|
|
37
30
|
import {Plus} from 'lucide-react';
|
|
38
31
|
import {outlinePanel} from 'astryx-dracula/shared/chaptered-doc-config';
|
|
39
32
|
|
|
40
|
-
// Flush the tab list with the example card's 12px inset (Section padding 3).
|
|
41
|
-
const tabListFlush: CSSProperties = {
|
|
42
|
-
marginInlineStart: 'calc(var(--spacing-3) * -1)',
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// The best-practices table lives in the prose column, where the eye tracks a
|
|
46
|
-
// single measure. Table's scroll wrapper bleeds edge-to-edge by reading the
|
|
47
|
-
// container padding vars LayoutContent publishes (32px here), which pushes
|
|
48
|
-
// its dividers 32px past the measure on both sides at every width. This table
|
|
49
|
-
// never overflows, so the bleed buys nothing — zero the vars for this subtree
|
|
50
|
-
// so it sits on the measure with the headings above it.
|
|
51
|
-
const practicesOnMeasure: CSSProperties = ({
|
|
52
|
-
'--container-padding-inline-start': '0px',
|
|
53
|
-
'--container-padding-inline-end': '0px',
|
|
54
|
-
}) as CSSProperties;
|
|
55
33
|
|
|
56
34
|
const COMPONENT_OUTLINE_ITEMS: OutlineItem[] = [
|
|
57
35
|
{id: 'usage', label: 'Usage', level: 2},
|
|
@@ -64,366 +42,16 @@ const COMPONENT_OUTLINE_OPTIONS = COMPONENT_OUTLINE_ITEMS.map(item => ({
|
|
|
64
42
|
label: item.label,
|
|
65
43
|
}));
|
|
66
44
|
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
// DialogPreview — stateful dialog preview for component previews
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
|
|
71
|
-
function DialogPreview() {
|
|
72
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
73
|
-
return (
|
|
74
|
-
<VStack gap={3}>
|
|
75
|
-
<Text type="body" weight="semibold">
|
|
76
|
-
Dialog
|
|
77
|
-
</Text>
|
|
78
|
-
<Button
|
|
79
|
-
label="Open Dialog"
|
|
80
|
-
variant="primary"
|
|
81
|
-
onClick={() => setIsOpen(true)}
|
|
82
|
-
/>
|
|
83
|
-
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
|
|
84
|
-
<DialogHeader title="Night Dialog" onOpenChange={setIsOpen} />
|
|
85
|
-
<Section padding={4}>
|
|
86
|
-
<Text type="body">
|
|
87
|
-
This is an example dialog. Dialogs are used to require user action
|
|
88
|
-
or display important information that needs acknowledgment.
|
|
89
|
-
</Text>
|
|
90
|
-
</Section>
|
|
91
|
-
</Dialog>
|
|
92
|
-
</VStack>
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
45
|
// ---------------------------------------------------------------------------
|
|
97
46
|
// Data
|
|
98
47
|
// ---------------------------------------------------------------------------
|
|
99
48
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
name: 'AppShell',
|
|
107
|
-
desc: 'AppShell provides a foundational page layout with header, sidebar, and content regions. Use it to establish consistent structure across your application.',
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
key: 'avatar',
|
|
111
|
-
name: 'Avatar',
|
|
112
|
-
desc: 'Avatars represent a person or entity with an image, initials, or icon. They are commonly used in user profiles, comments, and contact lists.',
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
key: 'badge',
|
|
116
|
-
name: 'Badge',
|
|
117
|
-
desc: 'Badges display small counts or status labels. They can be attached to icons, buttons, or list items to surface key information at a glance.',
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
key: 'banner',
|
|
121
|
-
name: 'Banner',
|
|
122
|
-
desc: 'Banners show important, non-modal messages at the top of a page or section. They communicate status, warnings, or promotional information.',
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
key: 'button',
|
|
126
|
-
name: 'Button',
|
|
127
|
-
desc: 'Buttons let people take action. They can be used in forms, dialogs, and toolbars, or as standalone links.',
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
key: 'calendar',
|
|
131
|
-
name: 'Calendar',
|
|
132
|
-
desc: 'Calendar provides a date-picking grid for selecting single dates or date ranges. It integrates with form fields for date input.',
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
key: 'dialog',
|
|
136
|
-
name: 'Dialog',
|
|
137
|
-
desc: 'Dialogs are modal overlays that require user attention or action before continuing. They are used for confirmations, forms, and critical decisions.',
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
key: 'dropdownmenu',
|
|
141
|
-
name: 'DropdownMenu',
|
|
142
|
-
desc: 'DropdownMenu presents a list of actions or options in a floating overlay. It is triggered by a button and supports nested submenus.',
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
key: 'empty-state',
|
|
146
|
-
name: 'EmptyState',
|
|
147
|
-
desc: 'EmptyState provides a placeholder when there is no content to display. It guides users with a message, illustration, and optional call-to-action.',
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
key: 'hovercard',
|
|
151
|
-
name: 'HoverCard',
|
|
152
|
-
desc: 'HoverCard shows a rich preview of content when users hover over a trigger element. It is ideal for previewing profiles, links, or details.',
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
key: 'icon',
|
|
156
|
-
name: 'Icon',
|
|
157
|
-
desc: 'Icons are small visual symbols that represent actions, objects, or concepts. They improve scannability and reinforce meaning alongside text.',
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
key: 'kbd',
|
|
161
|
-
name: 'Kbd',
|
|
162
|
-
desc: 'Kbd renders keyboard shortcut hints in a styled inline element. Use it to show users which key combinations perform specific actions.',
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
key: 'link',
|
|
166
|
-
name: 'Link',
|
|
167
|
-
desc: 'Links provide navigation between pages or to external resources. They follow accessible anchor semantics with visual affordance.',
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
key: 'list',
|
|
171
|
-
name: 'List',
|
|
172
|
-
desc: 'List displays a vertical set of related items. It supports selection, icons, and metadata for building menus, nav lists, and more.',
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
key: 'metadatalist',
|
|
176
|
-
name: 'MetadataList',
|
|
177
|
-
desc: 'MetadataList displays key-value pairs in a structured layout. Use it for detail panels, settings summaries, and record information.',
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
key: 'moremenu',
|
|
181
|
-
name: 'MoreMenu',
|
|
182
|
-
desc: 'MoreMenu provides an overflow menu triggered by an icon button. It collects secondary actions that do not fit in the primary toolbar.',
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
key: 'overflowlist',
|
|
186
|
-
name: 'OverflowList',
|
|
187
|
-
desc: 'OverflowList renders as many items as fit in the available space and collapses the rest into an overflow menu automatically.',
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
key: 'pagination',
|
|
191
|
-
name: 'Pagination',
|
|
192
|
-
desc: 'Pagination lets users navigate through pages of content. It supports page numbers, previous/next controls, and page-size selection.',
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
key: 'popover',
|
|
196
|
-
name: 'Popover',
|
|
197
|
-
desc: 'Popover displays rich content in a floating panel anchored to a trigger element. It is used for forms, filters, and contextual tools.',
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
key: 'progressbar',
|
|
201
|
-
name: 'ProgressBar',
|
|
202
|
-
desc: 'ProgressBar shows the completion status of a task or process. It provides visual feedback for uploads, installations, and multi-step flows.',
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
key: 'skeleton',
|
|
206
|
-
name: 'Skeleton',
|
|
207
|
-
desc: 'Skeleton renders placeholder shapes that mimic content layout while loading. It reduces perceived wait time and prevents layout shifts.',
|
|
208
|
-
},
|
|
209
|
-
{
|
|
210
|
-
key: 'spinner',
|
|
211
|
-
name: 'Spinner',
|
|
212
|
-
desc: 'Spinner indicates that a process is in progress when the duration is unknown. It draws attention without blocking the interface.',
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
key: 'statusdot',
|
|
216
|
-
name: 'StatusDot',
|
|
217
|
-
desc: 'StatusDot shows a small colored indicator for online, offline, busy, or custom statuses. It is often paired with avatars or list items.',
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
key: 'table',
|
|
221
|
-
name: 'Table',
|
|
222
|
-
desc: 'Table displays structured data in rows and columns with support for sorting, selection, and custom cell rendering.',
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
key: 'thumbnail',
|
|
226
|
-
name: 'Thumbnail',
|
|
227
|
-
desc: 'Thumbnail renders a small image preview with consistent sizing and optional rounded corners. It is used in media lists, cards, and galleries.',
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
key: 'timestamp',
|
|
231
|
-
name: 'Timestamp',
|
|
232
|
-
desc: 'Timestamp formats and displays dates and times with relative or absolute labels. It updates automatically to stay current.',
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
key: 'toast',
|
|
236
|
-
name: 'Toast',
|
|
237
|
-
desc: 'Toasts display brief, non-blocking notifications at the edge of the screen. They auto-dismiss and are used for success, error, or info messages.',
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
key: 'togglebutton',
|
|
241
|
-
name: 'ToggleButton',
|
|
242
|
-
desc: 'ToggleButton is a button that switches between an on and off state. Use it for binary options like bookmarking, favoriting, or muting.',
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
key: 'token',
|
|
246
|
-
name: 'Token',
|
|
247
|
-
desc: 'Tokens display compact metadata labels such as tags, categories, or filters. They can be dismissible and support selection state.',
|
|
248
|
-
},
|
|
249
|
-
{
|
|
250
|
-
key: 'tooltip',
|
|
251
|
-
name: 'Tooltip',
|
|
252
|
-
desc: 'Tooltips show concise helper text when users hover over or focus an element. They clarify icons, truncated labels, and controls.',
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
key: 'treelist',
|
|
256
|
-
name: 'TreeList',
|
|
257
|
-
desc: 'TreeList renders hierarchical data in an expandable tree structure. It supports multi-level nesting, selection, and lazy loading.',
|
|
258
|
-
},
|
|
259
|
-
],
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
label: 'Typography',
|
|
263
|
-
items: [
|
|
264
|
-
{
|
|
265
|
-
key: 'heading',
|
|
266
|
-
name: 'Heading',
|
|
267
|
-
desc: 'Heading renders semantic section titles from h1 through h6. It establishes visual hierarchy and supports multiple weight and size options.',
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
key: 'text',
|
|
271
|
-
name: 'Text',
|
|
272
|
-
desc: 'Text renders body copy, labels, and supporting content with consistent typography. It supports sizes from display down to caption.',
|
|
273
|
-
},
|
|
274
|
-
],
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
label: 'Layout',
|
|
278
|
-
items: [
|
|
279
|
-
{
|
|
280
|
-
key: 'aspectratio',
|
|
281
|
-
name: 'AspectRatio',
|
|
282
|
-
desc: 'AspectRatio constrains its child to a specified width-to-height ratio. Use it for responsive images, videos, and embedded media.',
|
|
283
|
-
},
|
|
284
|
-
{
|
|
285
|
-
key: 'card',
|
|
286
|
-
name: 'Card',
|
|
287
|
-
desc: 'Cards group related content and actions in a contained surface. They can include headers, media, body text, and action bars.',
|
|
288
|
-
},
|
|
289
|
-
{
|
|
290
|
-
key: 'center',
|
|
291
|
-
name: 'Center',
|
|
292
|
-
desc: 'Center aligns its child horizontally and vertically within the available space. It is useful for empty states, loading screens, and hero sections.',
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
key: 'divider',
|
|
296
|
-
name: 'Divider',
|
|
297
|
-
desc: 'Dividers separate content into distinct sections with a subtle or strong horizontal line. They can optionally include a label.',
|
|
298
|
-
},
|
|
299
|
-
{
|
|
300
|
-
key: 'grid',
|
|
301
|
-
name: 'Grid',
|
|
302
|
-
desc: 'Grid provides a CSS grid-based layout container with configurable columns, rows, and gap. It simplifies responsive multi-column designs.',
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
key: 'layout',
|
|
306
|
-
name: 'Layout',
|
|
307
|
-
desc: 'Layout provides foundational page-level primitives for header, sidebar, and content regions. It establishes consistent spacing and structure.',
|
|
308
|
-
},
|
|
309
|
-
{
|
|
310
|
-
key: 'section',
|
|
311
|
-
name: 'Section',
|
|
312
|
-
desc: 'Section wraps a block of content with consistent vertical spacing and an optional heading. It structures pages into logical groups.',
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
key: 'stack',
|
|
316
|
-
name: 'Stack',
|
|
317
|
-
desc: 'Stack arranges child elements in a row or column with consistent gap spacing. It is the primary tool for one-dimensional layout composition.',
|
|
318
|
-
},
|
|
319
|
-
{
|
|
320
|
-
key: 'toolbar',
|
|
321
|
-
name: 'Toolbar',
|
|
322
|
-
desc: 'Toolbar arranges a row of action buttons and controls in a compact, aligned strip. It is used at the top of panels, editors, and cards.',
|
|
323
|
-
},
|
|
324
|
-
],
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
label: 'Navigation',
|
|
328
|
-
items: [
|
|
329
|
-
{
|
|
330
|
-
key: 'breadcrumbs',
|
|
331
|
-
name: 'Breadcrumbs',
|
|
332
|
-
desc: "Breadcrumbs show the user's current location within a navigation hierarchy. They provide quick links back to parent pages.",
|
|
333
|
-
},
|
|
334
|
-
{
|
|
335
|
-
key: 'mobilenav',
|
|
336
|
-
name: 'MobileNav',
|
|
337
|
-
desc: 'MobileNav provides a responsive navigation menu optimized for small screens. It typically slides in from the edge of the viewport.',
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
key: 'sidenav',
|
|
341
|
-
name: 'SideNav',
|
|
342
|
-
desc: 'SideNav renders a vertical navigation panel with links, sections, and collapsible groups. It is used as the primary nav in dashboard layouts.',
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
key: 'tablist',
|
|
346
|
-
name: 'TabList',
|
|
347
|
-
desc: 'TabList switches between content views using a horizontal row of tabs. Only one tab is active at a time, and content changes without a page reload.',
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
key: 'topnav',
|
|
351
|
-
name: 'TopNav',
|
|
352
|
-
desc: 'TopNav provides an app-level navigation bar across the top of the page. It holds branding, primary links, search, and user actions.',
|
|
353
|
-
},
|
|
354
|
-
],
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
label: 'Form',
|
|
358
|
-
items: [
|
|
359
|
-
{
|
|
360
|
-
key: 'checkboxinput',
|
|
361
|
-
name: 'CheckboxInput',
|
|
362
|
-
desc: 'CheckboxInput renders a single checkbox with a label. It is used for boolean opt-in choices like terms acceptance or feature toggles.',
|
|
363
|
-
},
|
|
364
|
-
{
|
|
365
|
-
key: 'selector',
|
|
366
|
-
name: 'Selector',
|
|
367
|
-
desc: 'Selector lets users pick a single item from a dropdown list. It supports search, grouping, and custom option rendering.',
|
|
368
|
-
},
|
|
369
|
-
{
|
|
370
|
-
key: 'switch',
|
|
371
|
-
name: 'Switch',
|
|
372
|
-
desc: 'Switch toggles a setting between on and off states with immediate effect. It is used for preferences, feature flags, and real-time controls.',
|
|
373
|
-
},
|
|
374
|
-
{
|
|
375
|
-
key: 'textinput',
|
|
376
|
-
name: 'TextInput',
|
|
377
|
-
desc: 'TextInput is a single-line text field for short user input like names, emails, and search queries. It supports icons, prefixes, and validation.',
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
key: 'typeahead',
|
|
381
|
-
name: 'Typeahead',
|
|
382
|
-
desc: 'Typeahead provides an autocomplete search input that suggests results as the user types. It supports async data sources and custom rendering.',
|
|
383
|
-
},
|
|
384
|
-
],
|
|
385
|
-
},
|
|
386
|
-
{
|
|
387
|
-
label: 'Components',
|
|
388
|
-
items: [
|
|
389
|
-
{
|
|
390
|
-
key: 'codeblock',
|
|
391
|
-
name: 'CodeBlock',
|
|
392
|
-
desc: 'CodeBlock displays formatted, syntax-highlighted source code. It supports line numbers, copy-to-clipboard, and language detection.',
|
|
393
|
-
},
|
|
394
|
-
{
|
|
395
|
-
key: 'collapsible',
|
|
396
|
-
name: 'Collapsible',
|
|
397
|
-
desc: 'Collapsible wraps content that can be expanded or collapsed with a trigger. It is used for FAQs, advanced settings, and progressive disclosure.',
|
|
398
|
-
},
|
|
399
|
-
{
|
|
400
|
-
key: 'markdown',
|
|
401
|
-
name: 'Markdown',
|
|
402
|
-
desc: 'Markdown renders markdown-formatted text into styled HTML. It supports headings, lists, links, code blocks, and inline formatting.',
|
|
403
|
-
},
|
|
404
|
-
],
|
|
405
|
-
},
|
|
406
|
-
{
|
|
407
|
-
label: 'Chat',
|
|
408
|
-
items: [
|
|
409
|
-
{
|
|
410
|
-
key: 'chat',
|
|
411
|
-
name: 'Chat',
|
|
412
|
-
desc: 'Chat provides a conversational message interface with message bubbles, input, and thread support. It is used for AI assistants and messaging UIs.',
|
|
413
|
-
},
|
|
414
|
-
],
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
label: 'CommandPalette',
|
|
418
|
-
items: [
|
|
419
|
-
{
|
|
420
|
-
key: 'commandpalette',
|
|
421
|
-
name: 'CommandPalette',
|
|
422
|
-
desc: 'CommandPalette is a keyboard-driven command menu for quick navigation and actions. It is opened with a hotkey and supports fuzzy search.',
|
|
423
|
-
},
|
|
424
|
-
],
|
|
425
|
-
},
|
|
426
|
-
];
|
|
49
|
+
// This page renders exactly one component's detail. The key is a module
|
|
50
|
+
// constant, not a prop: the only caller passed "button" unconditionally, and
|
|
51
|
+
// the name/docs/previews below index it directly instead of threading a
|
|
52
|
+
// parameter that can never vary.
|
|
53
|
+
// The only caller ever passed 'button': the component name is a literal, not a lookup.
|
|
54
|
+
const ACTIVE_COMPONENT_NAME = 'Button';
|
|
427
55
|
|
|
428
56
|
const COMPONENT_DOCS: Record<
|
|
429
57
|
string,
|
|
@@ -467,111 +95,37 @@ const COMPONENT_DOCS: Record<
|
|
|
467
95
|
},
|
|
468
96
|
};
|
|
469
97
|
|
|
470
|
-
|
|
471
|
-
for (const cat of COMPONENT_CATEGORIES) {
|
|
472
|
-
const item = cat.items.find(i => i.key === key);
|
|
473
|
-
if (item) {
|
|
474
|
-
return item.name;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
return key;
|
|
478
|
-
}
|
|
98
|
+
const ACTIVE_DOCS = COMPONENT_DOCS['button'];
|
|
479
99
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
usage: desc,
|
|
495
|
-
bestPractices: [
|
|
496
|
-
{
|
|
497
|
-
type: 'do' as const,
|
|
498
|
-
text: `Use ${name} in the appropriate context to provide the functionality described above.`,
|
|
499
|
-
},
|
|
500
|
-
{
|
|
501
|
-
type: 'do' as const,
|
|
502
|
-
text: `Pair ${name} with related components to create cohesive, accessible interfaces.`,
|
|
503
|
-
},
|
|
504
|
-
{
|
|
505
|
-
type: 'dont' as const,
|
|
506
|
-
text: `Use ${name} when a simpler alternative achieves the same goal with less complexity.`,
|
|
507
|
-
},
|
|
508
|
-
],
|
|
509
|
-
examples: [
|
|
510
|
-
{
|
|
511
|
-
title: `Basic ${name}`,
|
|
512
|
-
description: `A simple example of the ${name} component with default settings.`,
|
|
513
|
-
code: `<${name} />`,
|
|
514
|
-
},
|
|
515
|
-
],
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
const EXAMPLE_PREVIEWS: Record<string, ReactNode[]> = {
|
|
520
|
-
button: [
|
|
521
|
-
<HStack key="semantics" gap={3} vAlign="center" wrap="wrap">
|
|
522
|
-
<Button label="Flat" variant="ghost" />
|
|
523
|
-
<Button label="Default" variant="secondary" />
|
|
524
|
-
<Button label="Primary" variant="primary" />
|
|
525
|
-
<Button label="Destructive" variant="destructive" />
|
|
526
|
-
</HStack>,
|
|
527
|
-
<Button key="badge" label="Button" variant="secondary" />,
|
|
528
|
-
],
|
|
529
|
-
};
|
|
100
|
+
// One preview node per example in ACTIVE_DOCS.examples, index-aligned. The
|
|
101
|
+
// old EXAMPLE_PREVIEWS record carried only this key, so the record wrapper
|
|
102
|
+
// bought nothing; the avatar/badge/card/banner/dialog/text/divider/token/
|
|
103
|
+
// tooltip entries in the old COMPONENT_PREVIEWS map were reachable only
|
|
104
|
+
// through nav keys this page never renders, so they are gone.
|
|
105
|
+
const EXAMPLE_PREVIEW_NODES: ReactNode[] = [
|
|
106
|
+
<HStack key="semantics" gap={3} vAlign="center" wrap="wrap">
|
|
107
|
+
<Button label="Flat" variant="ghost" />
|
|
108
|
+
<Button label="Default" variant="secondary" />
|
|
109
|
+
<Button label="Primary" variant="primary" />
|
|
110
|
+
<Button label="Destructive" variant="destructive" />
|
|
111
|
+
</HStack>,
|
|
112
|
+
<Button key="badge" label="Button" variant="secondary" />,
|
|
113
|
+
];
|
|
530
114
|
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
),
|
|
540
|
-
avatar: <Avatar name="Vlad" size="lg" />,
|
|
541
|
-
badge: <Badge label="Design" variant="yellow" />,
|
|
542
|
-
card: (
|
|
543
|
-
<Card>
|
|
544
|
-
<VStack gap={2}>
|
|
545
|
-
<Text type="body" weight="semibold">
|
|
546
|
-
Castle Card
|
|
547
|
-
</Text>
|
|
548
|
-
<Text type="body" color="secondary">
|
|
549
|
-
Cards group related content and actions.
|
|
550
|
-
</Text>
|
|
551
|
-
</VStack>
|
|
552
|
-
</Card>
|
|
553
|
-
),
|
|
554
|
-
banner: (
|
|
555
|
-
<Banner status="info" title="Information">
|
|
556
|
-
<Text type="body">This is an informational banner message.</Text>
|
|
557
|
-
</Banner>
|
|
558
|
-
),
|
|
559
|
-
dialog: <DialogPreview />,
|
|
560
|
-
text: <Text type="body">Body text</Text>,
|
|
561
|
-
divider: <Divider />,
|
|
562
|
-
token: <Token label="Dracula" />,
|
|
563
|
-
tooltip: (
|
|
564
|
-
<Tooltip content="Primary action">
|
|
565
|
-
<Button label="Hover me" variant="primary" />
|
|
566
|
-
</Tooltip>
|
|
567
|
-
),
|
|
568
|
-
};
|
|
115
|
+
const HERO_PREVIEW = (
|
|
116
|
+
<Button
|
|
117
|
+
label="Button"
|
|
118
|
+
variant="secondary"
|
|
119
|
+
icon={<Icon icon={Plus} />}
|
|
120
|
+
endContent={<Badge label="New" variant="cyan" />}
|
|
121
|
+
/>
|
|
122
|
+
);
|
|
569
123
|
|
|
570
124
|
// ---------------------------------------------------------------------------
|
|
571
125
|
// ComponentDetailView
|
|
572
126
|
// ---------------------------------------------------------------------------
|
|
573
127
|
|
|
574
|
-
function ComponentDetailView(
|
|
128
|
+
function ComponentDetailView() {
|
|
575
129
|
const [exampleTabs, setExampleTabs] = useState<Record<string, string>>({});
|
|
576
130
|
const [activeId, setActiveId] = useState<string | undefined>(
|
|
577
131
|
COMPONENT_OUTLINE_ITEMS[0]?.id,
|
|
@@ -587,8 +141,8 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
587
141
|
}
|
|
588
142
|
}, []);
|
|
589
143
|
|
|
590
|
-
const docs =
|
|
591
|
-
const previews =
|
|
144
|
+
const docs = ACTIVE_DOCS;
|
|
145
|
+
const previews = EXAMPLE_PREVIEW_NODES;
|
|
592
146
|
|
|
593
147
|
return (
|
|
594
148
|
<Layout
|
|
@@ -612,7 +166,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
612
166
|
<LayoutContent isScrollable={false} padding={8}>
|
|
613
167
|
<VStack gap={8}>
|
|
614
168
|
<VStack gap={2}>
|
|
615
|
-
<Heading level={1} type="display-2">{
|
|
169
|
+
<Heading level={1} type="display-2">{ACTIVE_COMPONENT_NAME}</Heading>
|
|
616
170
|
<Text type="supporting" color="secondary" hasTabularNumbers>
|
|
617
171
|
March 30, 2026 · Updated 5:40 p.m. PST
|
|
618
172
|
</Text>
|
|
@@ -630,11 +184,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
630
184
|
|
|
631
185
|
<Card variant="muted" padding={0}>
|
|
632
186
|
<Center height={360}>
|
|
633
|
-
{
|
|
634
|
-
<Text type="supporting" color="secondary">
|
|
635
|
-
Quiet in the crypt — no preview haunts this shelf yet.
|
|
636
|
-
</Text>
|
|
637
|
-
)}
|
|
187
|
+
{HERO_PREVIEW}
|
|
638
188
|
</Center>
|
|
639
189
|
</Card>
|
|
640
190
|
|
|
@@ -646,37 +196,35 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
646
196
|
<Heading id="best-practices" level={3}>
|
|
647
197
|
Best practices
|
|
648
198
|
</Heading>
|
|
649
|
-
<
|
|
650
|
-
<
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
/>
|
|
679
|
-
</div>
|
|
199
|
+
<Table
|
|
200
|
+
data={docs.bestPractices as Record<string, unknown>[]}
|
|
201
|
+
dividers="none"
|
|
202
|
+
hasHover
|
|
203
|
+
columns={[
|
|
204
|
+
{
|
|
205
|
+
key: 'type',
|
|
206
|
+
header: 'Guidance',
|
|
207
|
+
width: pixel(125),
|
|
208
|
+
renderCell: (item: Record<string, unknown>) => (
|
|
209
|
+
<Badge
|
|
210
|
+
label={item.type === 'do' ? 'Do' : "Don't"}
|
|
211
|
+
variant={item.type === 'do' ? 'green' : 'red'}
|
|
212
|
+
/>
|
|
213
|
+
),
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
key: 'text',
|
|
217
|
+
header: 'Practices',
|
|
218
|
+
width: proportional(1),
|
|
219
|
+
renderCell: (item: Record<string, unknown>) => (
|
|
220
|
+
<Text type="body" textWrap="wrap">
|
|
221
|
+
{item.text as string}
|
|
222
|
+
</Text>
|
|
223
|
+
),
|
|
224
|
+
},
|
|
225
|
+
]}
|
|
226
|
+
density="spacious"
|
|
227
|
+
/>
|
|
680
228
|
</VStack>
|
|
681
229
|
|
|
682
230
|
<Divider />
|
|
@@ -692,7 +240,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
692
240
|
</VStack>
|
|
693
241
|
<VStack gap={8}>
|
|
694
242
|
{docs.examples.map((example, i) => {
|
|
695
|
-
const tabKey =
|
|
243
|
+
const tabKey = `example-${i}`;
|
|
696
244
|
const activeTab = exampleTabs[tabKey] ?? 'description';
|
|
697
245
|
return (
|
|
698
246
|
<Card key={example.title} padding={0}>
|
|
@@ -718,8 +266,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
718
266
|
[tabKey]: value,
|
|
719
267
|
}))
|
|
720
268
|
}
|
|
721
|
-
size="sm"
|
|
722
|
-
style={tabListFlush}>
|
|
269
|
+
size="sm">
|
|
723
270
|
<Tab value="description" label="Description" />
|
|
724
271
|
<Tab value="code" label="Code" />
|
|
725
272
|
</TabList>
|
|
@@ -750,5 +297,5 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
750
297
|
// ---------------------------------------------------------------------------
|
|
751
298
|
|
|
752
299
|
export default function DocumentationDesign() {
|
|
753
|
-
return <ComponentDetailView
|
|
300
|
+
return <ComponentDetailView />;
|
|
754
301
|
}
|