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.
- package/BRAND.md +1 -1
- package/README.md +2 -0
- package/USAGE.md +13 -0
- package/astryx-dracula.js +4 -4
- package/astryx.integration.mjs +3 -0
- package/package.json +4 -2
- package/templates/ai-chat-landing.template.mjs +6 -0
- package/templates/ai-chat-landing.tsx +476 -0
- package/templates/ai-chat.template.mjs +6 -0
- package/templates/ai-chat.tsx +762 -0
- package/templates/blank.template.mjs +6 -0
- package/templates/blank.tsx +16 -0
- package/templates/centered-hero.template.mjs +6 -0
- package/templates/centered-hero.tsx +188 -0
- package/templates/classic-gallery.template.mjs +6 -0
- package/templates/classic-gallery.tsx +181 -0
- package/templates/contact-form.template.mjs +6 -0
- package/templates/contact-form.tsx +292 -0
- package/templates/dashboard-portfolio.template.mjs +6 -0
- package/templates/dashboard-portfolio.tsx +800 -0
- package/templates/dashboard.template.mjs +6 -0
- package/templates/dashboard.tsx +774 -0
- package/templates/detail-page.template.mjs +6 -0
- package/templates/detail-page.tsx +695 -0
- package/templates/documentation-design.template.mjs +6 -0
- package/templates/documentation-design.tsx +751 -0
- package/templates/documentation-technical.template.mjs +6 -0
- package/templates/documentation-technical.tsx +292 -0
- package/templates/documentation.template.mjs +6 -0
- package/templates/documentation.tsx +347 -0
- package/templates/editor.template.mjs +6 -0
- package/templates/editor.tsx +959 -0
- package/templates/file-explorer.template.mjs +6 -0
- package/templates/file-explorer.tsx +577 -0
- package/templates/form-two-column.template.mjs +6 -0
- package/templates/form-two-column.tsx +314 -0
- package/templates/gallery-hero.template.mjs +6 -0
- package/templates/gallery-hero.tsx +287 -0
- package/templates/ide.template.mjs +6 -0
- package/templates/ide.tsx +533 -0
- package/templates/incident-console.template.mjs +6 -0
- package/templates/incident-console.tsx +584 -0
- package/templates/kanban-board.template.mjs +6 -0
- package/templates/kanban-board.tsx +746 -0
- package/templates/library.template.mjs +6 -0
- package/templates/library.tsx +489 -0
- package/templates/login-card.template.mjs +6 -0
- package/templates/login-card.tsx +200 -0
- package/templates/login-split.template.mjs +6 -0
- package/templates/login-split.tsx +318 -0
- package/templates/login-sso.template.mjs +6 -0
- package/templates/login-sso.tsx +277 -0
- package/templates/login.template.mjs +6 -0
- package/templates/login.tsx +98 -0
- package/templates/messaging-shell.template.mjs +6 -0
- package/templates/messaging-shell.tsx +675 -0
- package/templates/mixed-gallery.template.mjs +6 -0
- package/templates/mixed-gallery.tsx +190 -0
- package/templates/payment-form.template.mjs +6 -0
- package/templates/payment-form.tsx +990 -0
- package/templates/product-detail.template.mjs +6 -0
- package/templates/product-detail.tsx +366 -0
- package/templates/product-gallery.template.mjs +6 -0
- package/templates/product-gallery.tsx +173 -0
- package/templates/settings-dialog.template.mjs +6 -0
- package/templates/settings-dialog.tsx +920 -0
- package/templates/settings-sidebar.template.mjs +6 -0
- package/templates/settings-sidebar.tsx +952 -0
- package/templates/settings.template.mjs +6 -0
- package/templates/settings.tsx +235 -0
- package/templates/shell-nav.template.mjs +6 -0
- package/templates/shell-nav.tsx +306 -0
- package/templates/shell-side-nav.template.mjs +6 -0
- package/templates/shell-side-nav.tsx +238 -0
- package/templates/shell-top-nav.template.mjs +6 -0
- package/templates/shell-top-nav.tsx +243 -0
- package/templates/side-gallery.template.mjs +6 -0
- package/templates/side-gallery.tsx +179 -0
- package/templates/table-grouped.template.mjs +6 -0
- package/templates/table-grouped.tsx +1174 -0
- package/templates/table-page-chart.template.mjs +6 -0
- package/templates/table-page-chart.tsx +693 -0
- package/templates/table-page-heatmap-status.template.mjs +6 -0
- package/templates/table-page-heatmap-status.tsx +547 -0
- package/templates/table-page-shoe-store-heatmap.template.mjs +6 -0
- package/templates/table-page-shoe-store-heatmap.tsx +1038 -0
- package/templates/table-page.template.mjs +6 -0
- package/templates/table-page.tsx +445 -0
- package/templates/table.template.mjs +6 -0
- package/templates/table.tsx +84 -0
- package/templates/theme-showcase.template.mjs +6 -0
- package/templates/theme-showcase.tsx +1282 -0
- package/theme.css +4 -4
- package/tokens.css +4 -4
|
@@ -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,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
|
+
}
|