astryx-dracula 0.1.3 → 0.2.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.
Files changed (94) hide show
  1. package/BRAND.md +1 -1
  2. package/README.md +2 -0
  3. package/USAGE.md +13 -0
  4. package/astryx-dracula.js +4 -4
  5. package/astryx.integration.mjs +3 -0
  6. package/package.json +4 -2
  7. package/templates/ai-chat-landing.template.mjs +6 -0
  8. package/templates/ai-chat-landing.tsx +476 -0
  9. package/templates/ai-chat.template.mjs +6 -0
  10. package/templates/ai-chat.tsx +762 -0
  11. package/templates/blank.template.mjs +6 -0
  12. package/templates/blank.tsx +16 -0
  13. package/templates/centered-hero.template.mjs +6 -0
  14. package/templates/centered-hero.tsx +188 -0
  15. package/templates/classic-gallery.template.mjs +6 -0
  16. package/templates/classic-gallery.tsx +181 -0
  17. package/templates/contact-form.template.mjs +6 -0
  18. package/templates/contact-form.tsx +292 -0
  19. package/templates/dashboard-portfolio.template.mjs +6 -0
  20. package/templates/dashboard-portfolio.tsx +800 -0
  21. package/templates/dashboard.template.mjs +6 -0
  22. package/templates/dashboard.tsx +774 -0
  23. package/templates/detail-page.template.mjs +6 -0
  24. package/templates/detail-page.tsx +695 -0
  25. package/templates/documentation-design.template.mjs +6 -0
  26. package/templates/documentation-design.tsx +751 -0
  27. package/templates/documentation-technical.template.mjs +6 -0
  28. package/templates/documentation-technical.tsx +292 -0
  29. package/templates/documentation.template.mjs +6 -0
  30. package/templates/documentation.tsx +347 -0
  31. package/templates/editor.template.mjs +6 -0
  32. package/templates/editor.tsx +959 -0
  33. package/templates/file-explorer.template.mjs +6 -0
  34. package/templates/file-explorer.tsx +577 -0
  35. package/templates/form-two-column.template.mjs +6 -0
  36. package/templates/form-two-column.tsx +314 -0
  37. package/templates/gallery-hero.template.mjs +6 -0
  38. package/templates/gallery-hero.tsx +287 -0
  39. package/templates/ide.template.mjs +6 -0
  40. package/templates/ide.tsx +533 -0
  41. package/templates/incident-console.template.mjs +6 -0
  42. package/templates/incident-console.tsx +584 -0
  43. package/templates/kanban-board.template.mjs +6 -0
  44. package/templates/kanban-board.tsx +746 -0
  45. package/templates/library.template.mjs +6 -0
  46. package/templates/library.tsx +489 -0
  47. package/templates/login-card.template.mjs +6 -0
  48. package/templates/login-card.tsx +200 -0
  49. package/templates/login-split.template.mjs +6 -0
  50. package/templates/login-split.tsx +318 -0
  51. package/templates/login-sso.template.mjs +6 -0
  52. package/templates/login-sso.tsx +277 -0
  53. package/templates/login.template.mjs +6 -0
  54. package/templates/login.tsx +98 -0
  55. package/templates/messaging-shell.template.mjs +6 -0
  56. package/templates/messaging-shell.tsx +675 -0
  57. package/templates/mixed-gallery.template.mjs +6 -0
  58. package/templates/mixed-gallery.tsx +190 -0
  59. package/templates/payment-form.template.mjs +6 -0
  60. package/templates/payment-form.tsx +990 -0
  61. package/templates/product-detail.template.mjs +6 -0
  62. package/templates/product-detail.tsx +366 -0
  63. package/templates/product-gallery.template.mjs +6 -0
  64. package/templates/product-gallery.tsx +173 -0
  65. package/templates/settings-dialog.template.mjs +6 -0
  66. package/templates/settings-dialog.tsx +920 -0
  67. package/templates/settings-sidebar.template.mjs +6 -0
  68. package/templates/settings-sidebar.tsx +952 -0
  69. package/templates/settings.template.mjs +6 -0
  70. package/templates/settings.tsx +235 -0
  71. package/templates/shell-nav.template.mjs +6 -0
  72. package/templates/shell-nav.tsx +306 -0
  73. package/templates/shell-side-nav.template.mjs +6 -0
  74. package/templates/shell-side-nav.tsx +238 -0
  75. package/templates/shell-top-nav.template.mjs +6 -0
  76. package/templates/shell-top-nav.tsx +243 -0
  77. package/templates/side-gallery.template.mjs +6 -0
  78. package/templates/side-gallery.tsx +179 -0
  79. package/templates/table-grouped.template.mjs +6 -0
  80. package/templates/table-grouped.tsx +1174 -0
  81. package/templates/table-page-chart.template.mjs +6 -0
  82. package/templates/table-page-chart.tsx +693 -0
  83. package/templates/table-page-heatmap-status.template.mjs +6 -0
  84. package/templates/table-page-heatmap-status.tsx +547 -0
  85. package/templates/table-page-shoe-store-heatmap.template.mjs +6 -0
  86. package/templates/table-page-shoe-store-heatmap.tsx +1038 -0
  87. package/templates/table-page.template.mjs +6 -0
  88. package/templates/table-page.tsx +445 -0
  89. package/templates/table.template.mjs +6 -0
  90. package/templates/table.tsx +84 -0
  91. package/templates/theme-showcase.template.mjs +6 -0
  92. package/templates/theme-showcase.tsx +1282 -0
  93. package/theme.css +4 -4
  94. package/tokens.css +4 -4
@@ -0,0 +1,6 @@
1
+ export default {
2
+ type: 'page',
3
+ name: 'Technical Documentation',
4
+ description: 'Install steps, theming setup, and next steps',
5
+ category: 'marketing',
6
+ };
@@ -0,0 +1,292 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {useCallback, useState, type CSSProperties} from 'react';
4
+ import {Heading, Text} from '@astryxdesign/core/Text';
5
+ import {Button} from '@astryxdesign/core/Button';
6
+ import {Card} from '@astryxdesign/core/Card';
7
+ import {DropdownMenu} from '@astryxdesign/core/DropdownMenu';
8
+ import {List, ListItem} from '@astryxdesign/core/List';
9
+ import {CodeBlock} from '@astryxdesign/core/CodeBlock';
10
+ import {Selector} from '@astryxdesign/core/Selector';
11
+ import {HStack, VStack, StackItem} from '@astryxdesign/core/Stack';
12
+ import {Layout, LayoutContent, LayoutPanel} from '@astryxdesign/core/Layout';
13
+ import {Divider} from '@astryxdesign/core/Divider';
14
+ import {Icon} from '@astryxdesign/core/Icon';
15
+ import {Outline, type OutlineItem} from '@astryxdesign/core/Outline';
16
+ import {useMediaQuery} from '@astryxdesign/core/hooks';
17
+ import {Sparkles, ClipboardCopy, ChevronDown} from 'lucide-react';
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Main component
21
+ // ---------------------------------------------------------------------------
22
+
23
+ const OUTLINE_ITEMS: OutlineItem[] = [
24
+ {id: 'prerequisites', label: 'Prerequisites', level: 2},
25
+ {id: 'install-package', label: 'Install the package', level: 2},
26
+ {id: 'configure-theming', label: 'Configure theming', level: 2},
27
+ {id: 'next-steps', label: 'Next steps', level: 2},
28
+ ];
29
+
30
+ const OUTLINE_OPTIONS = OUTLINE_ITEMS.map(item => ({
31
+ value: item.id,
32
+ label: item.label,
33
+ }));
34
+
35
+ const outlinePanel: CSSProperties = {
36
+ position: 'sticky',
37
+ top: 24,
38
+ alignSelf: 'start',
39
+ paddingBlockStart: 120,
40
+ };
41
+
42
+ export default function DocumentationTechnical() {
43
+ const [activeId, setActiveId] = useState<string | undefined>(
44
+ OUTLINE_ITEMS[0]?.id,
45
+ );
46
+ const isMobile = useMediaQuery('(max-width: 768px)');
47
+
48
+ const scrollToId = useCallback((id: string) => {
49
+ setActiveId(id);
50
+ const target = document.getElementById(id);
51
+ if (target != null) {
52
+ target.scrollIntoView({behavior: 'smooth', block: 'start'});
53
+ window.history.pushState(null, '', `#${id}`);
54
+ }
55
+ }, []);
56
+
57
+ return (
58
+ <Layout
59
+ height="auto"
60
+ contentWidth={960}
61
+ end={
62
+ isMobile ? undefined : (
63
+ <LayoutPanel
64
+ isScrollable={false}
65
+ label="On this page"
66
+ role="complementary"
67
+ style={outlinePanel}>
68
+ <Outline items={OUTLINE_ITEMS} onActiveIdChange={setActiveId} />
69
+ </LayoutPanel>
70
+ )
71
+ }
72
+ content={
73
+ <LayoutContent isScrollable={false} padding={8}>
74
+ <VStack gap={8}>
75
+ <VStack gap={2}>
76
+ <Text type="display-1">Getting started with Astryx Dracula</Text>
77
+ <Text type="supporting" color="secondary" hasTabularNumbers>
78
+ Last updated March 30, 2026
79
+ </Text>
80
+ {isMobile && (
81
+ <Selector
82
+ label="On this page"
83
+ isLabelHidden
84
+ options={OUTLINE_OPTIONS}
85
+ value={activeId}
86
+ onChange={scrollToId}
87
+ width="100%"
88
+ />
89
+ )}
90
+ </VStack>
91
+
92
+ <Card>
93
+ <VStack gap={3}>
94
+ <HStack gap={2} vAlign="center">
95
+ <StackItem size="fill">
96
+ <HStack gap={2} vAlign="center">
97
+ <Icon icon={Sparkles} size="sm" color="secondary" />
98
+ <Text type="body" weight="semibold">
99
+ AI Assistance
100
+ </Text>
101
+ </HStack>
102
+ </StackItem>
103
+ <Button
104
+ label="Copy prompt"
105
+ variant="ghost"
106
+ size="sm"
107
+ icon={<Icon icon={ClipboardCopy} />}
108
+ onClick={() => {
109
+ void navigator.clipboard.writeText(
110
+ 'Help me get set up with Astryx Dracula. Based on my project, do the following: 1. Install @astryxdesign/core and the StyleX compiler. 2. Wrap my app in ThemeProvider. 3. Replace one existing component with an Astryx equivalent. After setup, suggest relevant next steps based on my project.',
111
+ );
112
+ }}
113
+ />
114
+ <DropdownMenu
115
+ button={{
116
+ label: 'More options',
117
+ variant: 'ghost',
118
+ size: 'sm',
119
+ isIconOnly: true,
120
+ icon: <Icon icon={ChevronDown} />,
121
+ }}
122
+ items={[
123
+ {label: 'Open in v0', onClick: () => {}},
124
+ {label: 'Open in Claude', onClick: () => {}},
125
+ {label: 'Open in ChatGPT', onClick: () => {}},
126
+ {label: 'Open in Cursor', onClick: () => {}},
127
+ ]}
128
+ />
129
+ </HStack>
130
+ <Text type="body" color="secondary">
131
+ Help me get set up with Astryx Dracula. Based on my project,
132
+ do the following: 1. Install @astryxdesign/core and the
133
+ StyleX compiler. 2. Wrap my app in ThemeProvider. 3. Replace
134
+ one existing component with an Astryx equivalent.
135
+ </Text>
136
+ </VStack>
137
+ </Card>
138
+
139
+ <VStack gap={4}>
140
+ <Heading id="prerequisites" level={2}>
141
+ Prerequisites
142
+ </Heading>
143
+ <List density="compact" listStyle="disc">
144
+ <ListItem label="Node.js 18+" />
145
+ <ListItem label="React 18 or 19" />
146
+ <ListItem
147
+ label="A package manager"
148
+ description={
149
+ <Text type="body" color="secondary" textWrap="wrap">
150
+ npm, yarn, or pnpm
151
+ </Text>
152
+ }
153
+ />
154
+ </List>
155
+ </VStack>
156
+
157
+ <Divider />
158
+
159
+ <VStack gap={4}>
160
+ <Heading id="install-package" level={2}>
161
+ Install the package
162
+ </Heading>
163
+ <Text type="body">
164
+ Every project starts with installing the core package. This
165
+ gives you access to all components, tokens, and utilities.
166
+ </Text>
167
+ <VStack gap={2}>
168
+ <Text type="body" weight="bold">
169
+ Step 1: Install the core package
170
+ </Text>
171
+ <CodeBlock
172
+ code="npm install @astryxdesign/core"
173
+ language="bash"
174
+ width="100%"
175
+ />
176
+ </VStack>
177
+ <VStack gap={2}>
178
+ <Text type="body" weight="bold">
179
+ Step 2: Import the precompiled styles
180
+ </Text>
181
+ <Text type="body" color="secondary">
182
+ Astryx ships precompiled CSS, so there is no build plugin to
183
+ configure. Import the reset and component stylesheets once at
184
+ your app entry point.
185
+ </Text>
186
+ <CodeBlock
187
+ code={`import '@astryxdesign/core/reset.css';
188
+ import '@astryxdesign/core/astryx.css';`}
189
+ language="tsx"
190
+ width="100%"
191
+ />
192
+ </VStack>
193
+ <VStack gap={2}>
194
+ <Text type="body" weight="bold">
195
+ Step 3: Import your first component
196
+ </Text>
197
+ <CodeBlock
198
+ code={`import { Button } from '@astryxdesign/core/Button';
199
+
200
+ export default function App() {
201
+ return <Button label="Hello Astryx" variant="primary" />;
202
+ }`}
203
+ language="tsx"
204
+ width="100%"
205
+ />
206
+ </VStack>
207
+ </VStack>
208
+
209
+ <Divider />
210
+
211
+ <VStack gap={4}>
212
+ <Heading id="configure-theming" level={2}>
213
+ Configure theming
214
+ </Heading>
215
+ <Text type="body">
216
+ Astryx ships with a default theme that works out of the box. To
217
+ customize colors, typography, and spacing, wrap your app in a
218
+ theme provider.
219
+ </Text>
220
+ <CodeBlock
221
+ code={`import { ThemeProvider } from '@astryxdesign/core/Theme';
222
+
223
+ export default function App({ children }) {
224
+ return (
225
+ <ThemeProvider theme="default">
226
+ {children}
227
+ </ThemeProvider>
228
+ );
229
+ }`}
230
+ language="tsx"
231
+ width="100%"
232
+ />
233
+ <Text type="body" color="secondary">
234
+ See the theming guide for the full list of customizable tokens.
235
+ </Text>
236
+ </VStack>
237
+
238
+ <Divider />
239
+
240
+ <VStack gap={4}>
241
+ <Heading id="next-steps" level={2}>
242
+ Next steps
243
+ </Heading>
244
+ <List density="compact" listStyle="disc">
245
+ <ListItem
246
+ label="Fundamental concepts"
247
+ description={
248
+ <Text type="body" color="secondary" textWrap="wrap">
249
+ How theming, layout, and composition work
250
+ </Text>
251
+ }
252
+ />
253
+ <ListItem
254
+ label="Component API reference"
255
+ description={
256
+ <Text type="body" color="secondary" textWrap="wrap">
257
+ Props, variants, and examples for every component
258
+ </Text>
259
+ }
260
+ />
261
+ <ListItem
262
+ label="Accessibility"
263
+ description={
264
+ <Text type="body" color="secondary" textWrap="wrap">
265
+ Built-in a11y features and ARIA patterns
266
+ </Text>
267
+ }
268
+ />
269
+ <ListItem
270
+ label="CLI tools"
271
+ description={
272
+ <Text type="body" color="secondary" textWrap="wrap">
273
+ Scaffold projects and manage templates
274
+ </Text>
275
+ }
276
+ />
277
+ <ListItem
278
+ label="Design tokens"
279
+ description={
280
+ <Text type="body" color="secondary" textWrap="wrap">
281
+ Colors, spacing, typography, and sizing
282
+ </Text>
283
+ }
284
+ />
285
+ </List>
286
+ </VStack>
287
+ </VStack>
288
+ </LayoutContent>
289
+ }
290
+ />
291
+ );
292
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ type: 'page',
3
+ name: 'Component Catalog',
4
+ description: 'Hero plus categorized component grid',
5
+ category: 'marketing',
6
+ };
@@ -0,0 +1,347 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import type {CSSProperties} from 'react';
4
+ import {Heading, Text} from '@astryxdesign/core/Text';
5
+ import {Button} from '@astryxdesign/core/Button';
6
+ import {Card} from '@astryxdesign/core/Card';
7
+ import {ClickableCard} from '@astryxdesign/core/ClickableCard';
8
+ import {HStack, VStack, StackItem} from '@astryxdesign/core/Stack';
9
+ import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
10
+ import {Grid} from '@astryxdesign/core/Grid';
11
+
12
+ const previewArt: CSSProperties = {
13
+ width: '100%',
14
+ height: '100%',
15
+ display: 'block',
16
+ };
17
+ const previewClip: CSSProperties = {
18
+ borderRadius: 'var(--radius-element)',
19
+ overflow: 'clip',
20
+ };
21
+ // Negative margin offsets each card's 8px padding so the grid content stays
22
+ // visually aligned while giving every card a padded hover/click target.
23
+ const cardGrid: CSSProperties = {
24
+ margin: -8,
25
+ };
26
+
27
+ // Dracula accent per grimoire shelf.
28
+ const SHELF_HUES: Record<string, string> = {
29
+ Core: 'var(--dracula-purple)',
30
+ Layout: 'var(--dracula-cyan)',
31
+ Navigation: 'var(--dracula-green)',
32
+ Form: 'var(--dracula-yellow)',
33
+ };
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Data
37
+ // ---------------------------------------------------------------------------
38
+
39
+ const COMPONENT_CATEGORIES = [
40
+ {
41
+ label: 'Core',
42
+ items: [
43
+ {
44
+ key: 'appshell',
45
+ name: 'AppShell',
46
+ desc: 'AppShell provides a foundational page layout with header, sidebar, and content regions. Use it to establish consistent structure across your application.',
47
+ },
48
+ {
49
+ key: 'avatar',
50
+ name: 'Avatar',
51
+ desc: 'Avatars represent a person or entity with an image, initials, or icon. They are commonly used in user profiles, comments, and contact lists.',
52
+ },
53
+ {
54
+ key: 'badge',
55
+ name: 'Badge',
56
+ 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.',
57
+ },
58
+ {
59
+ key: 'banner',
60
+ name: 'Banner',
61
+ desc: 'Banners show important, non-modal messages at the top of a page or section. They communicate status, warnings, or promotional information.',
62
+ },
63
+ {
64
+ key: 'button',
65
+ name: 'Button',
66
+ desc: 'Buttons let people take action. They can be used in forms, dialogs, and toolbars, or as standalone links.',
67
+ },
68
+ {
69
+ key: 'calendar',
70
+ name: 'Calendar',
71
+ desc: 'Calendar provides a date-picking grid for selecting single dates or date ranges. It integrates with form fields for date input.',
72
+ },
73
+ {
74
+ key: 'dialog',
75
+ name: 'Dialog',
76
+ desc: 'Dialogs are modal overlays that require user attention or action before continuing. They are used for confirmations, forms, and critical decisions.',
77
+ },
78
+ {
79
+ key: 'dropdownmenu',
80
+ name: 'DropdownMenu',
81
+ desc: 'DropdownMenu presents a list of actions or options in a floating overlay. It is triggered by a button and supports nested submenus.',
82
+ },
83
+ {
84
+ key: 'empty-state',
85
+ name: 'EmptyState',
86
+ desc: 'EmptyState provides a placeholder when there is no content to display. It guides users with a message, illustration, and optional call-to-action.',
87
+ },
88
+ {
89
+ key: 'hovercard',
90
+ name: 'HoverCard',
91
+ desc: 'HoverCard shows a rich preview of content when users hover over a trigger element. It is ideal for previewing profiles, links, or details.',
92
+ },
93
+ {
94
+ key: 'icon',
95
+ name: 'Icon',
96
+ desc: 'Icons are small visual symbols that represent actions, objects, or concepts. They improve scannability and reinforce meaning alongside text.',
97
+ },
98
+ {
99
+ key: 'kbd',
100
+ name: 'Kbd',
101
+ desc: 'Kbd renders keyboard shortcut hints in a styled inline element. Use it to show users which key combinations perform specific actions.',
102
+ },
103
+ {
104
+ key: 'link',
105
+ name: 'Link',
106
+ desc: 'Links provide navigation between pages or to external resources. They follow accessible anchor semantics with visual affordance.',
107
+ },
108
+ {
109
+ key: 'list',
110
+ name: 'List',
111
+ desc: 'List displays a vertical set of related items. It supports selection, icons, and metadata for building menus, nav lists, and more.',
112
+ },
113
+ {
114
+ key: 'popover',
115
+ name: 'Popover',
116
+ desc: 'Popover displays rich content in a floating panel anchored to a trigger element. It is used for forms, filters, and contextual tools.',
117
+ },
118
+ {
119
+ key: 'table',
120
+ name: 'Table',
121
+ desc: 'Table displays structured data in rows and columns with support for sorting, selection, and custom cell rendering.',
122
+ },
123
+ {
124
+ key: 'token',
125
+ name: 'Token',
126
+ desc: 'Tokens display compact metadata labels such as tags, categories, or filters. They can be dismissible and support selection state.',
127
+ },
128
+ {
129
+ key: 'tooltip',
130
+ name: 'Tooltip',
131
+ desc: 'Tooltips show concise helper text when users hover over or focus an element. They clarify icons, truncated labels, and controls.',
132
+ },
133
+ ],
134
+ },
135
+ {
136
+ label: 'Layout',
137
+ items: [
138
+ {
139
+ key: 'card',
140
+ name: 'Card',
141
+ desc: 'Cards group related content and actions in a contained surface. They can include headers, media, body text, and action bars.',
142
+ },
143
+ {
144
+ key: 'divider',
145
+ name: 'Divider',
146
+ desc: 'Dividers separate content into distinct sections with a subtle or strong horizontal line. They can optionally include a label.',
147
+ },
148
+ {
149
+ key: 'grid',
150
+ name: 'Grid',
151
+ desc: 'Grid provides a CSS grid-based layout container with configurable columns, rows, and gap. It simplifies responsive multi-column designs.',
152
+ },
153
+ {
154
+ key: 'stack',
155
+ name: 'Stack',
156
+ desc: 'Stack arranges child elements in a row or column with consistent gap spacing. It is the primary tool for one-dimensional layout composition.',
157
+ },
158
+ ],
159
+ },
160
+ {
161
+ label: 'Navigation',
162
+ items: [
163
+ {
164
+ key: 'breadcrumbs',
165
+ name: 'Breadcrumbs',
166
+ desc: "Breadcrumbs show the user's current location within a navigation hierarchy. They provide quick links back to parent pages.",
167
+ },
168
+ {
169
+ key: 'sidenav',
170
+ name: 'SideNav',
171
+ desc: 'SideNav renders a vertical navigation panel with links, sections, and collapsible groups. It is used as the primary nav in dashboard layouts.',
172
+ },
173
+ {
174
+ key: 'tablist',
175
+ name: 'TabList',
176
+ 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.',
177
+ },
178
+ {
179
+ key: 'topnav',
180
+ name: 'TopNav',
181
+ desc: 'TopNav provides an app-level navigation bar across the top of the page. It holds branding, primary links, search, and user actions.',
182
+ },
183
+ ],
184
+ },
185
+ {
186
+ label: 'Form',
187
+ items: [
188
+ {
189
+ key: 'checkboxinput',
190
+ name: 'CheckboxInput',
191
+ desc: 'CheckboxInput renders a single checkbox with a label. It is used for boolean opt-in choices like terms acceptance or feature toggles.',
192
+ },
193
+ {
194
+ key: 'selector',
195
+ name: 'Selector',
196
+ desc: 'Selector lets users pick a single item from a dropdown list. It supports search, grouping, and custom option rendering.',
197
+ },
198
+ {
199
+ key: 'switch',
200
+ name: 'Switch',
201
+ desc: 'Switch toggles a setting between on and off states with immediate effect. It is used for preferences, feature flags, and real-time controls.',
202
+ },
203
+ {
204
+ key: 'textinput',
205
+ name: 'TextInput',
206
+ desc: 'TextInput is a single-line text field for short user input like names, emails, and search queries. It supports icons, prefixes, and validation.',
207
+ },
208
+ {
209
+ key: 'typeahead',
210
+ name: 'Typeahead',
211
+ desc: 'Typeahead provides an autocomplete search input that suggests results as the user types. It supports async data sources and custom rendering.',
212
+ },
213
+ ],
214
+ },
215
+ ];
216
+
217
+ // ---------------------------------------------------------------------------
218
+ // Preview art
219
+ // ---------------------------------------------------------------------------
220
+
221
+ function PreviewArt({name, shelf}: {name: string; shelf: string}) {
222
+ const hue = SHELF_HUES[shelf] ?? 'var(--dracula-purple)';
223
+ return (
224
+ <svg
225
+ viewBox="0 0 400 300"
226
+ preserveAspectRatio="xMidYMid slice"
227
+ style={previewArt}
228
+ role="img"
229
+ aria-label={`${name} sigil`}>
230
+ <rect width="400" height="300" fill="var(--dracula-bg-light)" />
231
+ <circle cx="316" cy="66" r="26" fill={hue} opacity={0.85} />
232
+ <circle
233
+ cx="306"
234
+ cy="60"
235
+ r="21"
236
+ fill="var(--dracula-bg-light)"
237
+ opacity={0.5}
238
+ />
239
+ <path
240
+ d="M0 208 Q110 168 210 198 T400 184 V300 H0 Z"
241
+ fill="var(--dracula-current-line)"
242
+ />
243
+ <path
244
+ d="M0 236 Q130 206 260 230 T400 222 V300 H0 Z"
245
+ fill="var(--dracula-bg)"
246
+ />
247
+ <g
248
+ transform="translate(140 150)"
249
+ fill="none"
250
+ stroke="var(--dracula-comment)"
251
+ strokeWidth="5"
252
+ strokeLinecap="round"
253
+ strokeLinejoin="round">
254
+ <rect x="-44" y="-44" width="88" height="88" rx="5" />
255
+ <circle cx="18" cy="-18" r="2.5" fill={hue} stroke="none" />
256
+ <path d="M-34 30 L-8 0 L10 18 L20 8 L34 24" />
257
+ </g>
258
+ </svg>
259
+ );
260
+ }
261
+
262
+ // ---------------------------------------------------------------------------
263
+ // Main component
264
+ // ---------------------------------------------------------------------------
265
+
266
+ export default function DocumentationCatalog() {
267
+ return (
268
+ <Layout
269
+ height="fill"
270
+ contentWidth={1200}
271
+ content={
272
+ <LayoutContent padding={8}>
273
+ <VStack gap={10}>
274
+ <Card variant="gray" padding={10}>
275
+ <HStack gap={8} vAlign="center">
276
+ <StackItem size="fill">
277
+ <VStack gap={4}>
278
+ <Text type="display-1">The coven grimoire</Text>
279
+ <Text type="large" weight="normal" color="secondary">
280
+ Every incantation in the Astryx spellbook — thirty-one
281
+ components for building beautiful, accessible products
282
+ after dark.
283
+ </Text>
284
+ <HStack>
285
+ <Button
286
+ label="Enter the grimoire"
287
+ variant="primary"
288
+ size="lg"
289
+ />
290
+ </HStack>
291
+ </VStack>
292
+ </StackItem>
293
+ <StackItem size="fill" />
294
+ </HStack>
295
+ </Card>
296
+
297
+ {COMPONENT_CATEGORIES.map(category => (
298
+ <VStack key={category.label} gap={4}>
299
+ <HStack justify="between" vAlign="center">
300
+ <Heading level={2}>{category.label}</Heading>
301
+ <Text
302
+ type="supporting"
303
+ color="secondary"
304
+ hasTabularNumbers>
305
+ {category.items.length}{' '}
306
+ {category.items.length === 1 ? 'spell' : 'spells'}
307
+ </Text>
308
+ </HStack>
309
+ <Grid columns={{minWidth: 260}} gap={2} style={cardGrid}>
310
+ {category.items.map(item => (
311
+ <ClickableCard
312
+ key={item.key}
313
+ label={`Open ${item.name}`}
314
+ onClick={() => {}}
315
+ variant="transparent"
316
+ padding={2}>
317
+ <VStack gap={3}>
318
+ <Card
319
+ variant="muted"
320
+ padding={0}
321
+ minHeight={160}
322
+ style={previewClip}>
323
+ <PreviewArt
324
+ name={item.name}
325
+ shelf={category.label}
326
+ />
327
+ </Card>
328
+ <VStack gap={0.5}>
329
+ <Text type="body" weight="bold">
330
+ {item.name}
331
+ </Text>
332
+ <Text type="body" color="secondary" maxLines={3}>
333
+ {item.desc}
334
+ </Text>
335
+ </VStack>
336
+ </VStack>
337
+ </ClickableCard>
338
+ ))}
339
+ </Grid>
340
+ </VStack>
341
+ ))}
342
+ </VStack>
343
+ </LayoutContent>
344
+ }
345
+ />
346
+ );
347
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ type: 'page',
3
+ name: 'Page Editor',
4
+ description: 'Block builder with sidebar config and preview',
5
+ category: 'tooling',
6
+ };