astryx-dracula 0.2.1 → 0.3.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 (83) hide show
  1. package/BRAND.md +30 -18
  2. package/README.md +17 -12
  3. package/USAGE.md +29 -10
  4. package/astryx-dracula.js +19 -13
  5. package/astryx-dracula.variants.d.ts +15 -0
  6. package/package.json +59 -17
  7. package/shared/auth-chrome-config.ts +18 -0
  8. package/shared/auth-chrome.tsx +25 -0
  9. package/shared/auth-copy.ts +22 -0
  10. package/shared/chaptered-doc-config.ts +92 -0
  11. package/shared/chaptered-doc.tsx +332 -0
  12. package/shared/chart-hues.ts +27 -0
  13. package/shared/chart-labels.tsx +44 -0
  14. package/shared/chart-legend.tsx +100 -0
  15. package/shared/chart-panel-style.ts +13 -0
  16. package/shared/data-bar.tsx +160 -0
  17. package/shared/gallery-image.ts +20 -0
  18. package/shared/login-demo.ts +7 -0
  19. package/shared/metric-delta.tsx +36 -0
  20. package/shared/order-desk.tsx +273 -0
  21. package/shared/revenue-chart.tsx +174 -0
  22. package/shared/scene-castle.tsx +322 -0
  23. package/shared/scene-frame.tsx +88 -0
  24. package/shared/scene-hues.ts +49 -0
  25. package/shared/scene-tile.tsx +128 -0
  26. package/shared/settings-data.ts +125 -0
  27. package/shared/settings-rows.tsx +179 -0
  28. package/shared/sparkline.tsx +94 -0
  29. package/shared/sso-icons.tsx +30 -0
  30. package/templates/ai-chat-landing.tsx +66 -33
  31. package/templates/ai-chat.tsx +36 -19
  32. package/templates/blank.tsx +4 -3
  33. package/templates/centered-hero.tsx +14 -125
  34. package/templates/classic-gallery.tsx +20 -66
  35. package/templates/contact-form.tsx +59 -39
  36. package/templates/dashboard-portfolio.tsx +143 -226
  37. package/templates/dashboard.tsx +122 -122
  38. package/templates/detail-page.tsx +95 -91
  39. package/templates/documentation-design.template.mjs +1 -1
  40. package/templates/documentation-design.tsx +83 -96
  41. package/templates/documentation-technical.template.mjs +1 -1
  42. package/templates/documentation-technical.tsx +29 -19
  43. package/templates/documentation.template.mjs +1 -1
  44. package/templates/documentation.tsx +52 -74
  45. package/templates/editor.tsx +112 -84
  46. package/templates/file-explorer.tsx +131 -84
  47. package/templates/form-two-column.tsx +61 -125
  48. package/templates/gallery-hero.tsx +15 -171
  49. package/templates/ide.tsx +22 -20
  50. package/templates/incident-console.tsx +104 -70
  51. package/templates/kanban-board.tsx +99 -42
  52. package/templates/library.template.mjs +2 -2
  53. package/templates/library.tsx +37 -42
  54. package/templates/login-card.tsx +58 -87
  55. package/templates/login-split.tsx +88 -126
  56. package/templates/login-sso.tsx +105 -64
  57. package/templates/login.tsx +107 -53
  58. package/templates/messaging-shell.tsx +171 -144
  59. package/templates/mixed-gallery.tsx +29 -130
  60. package/templates/payment-form.tsx +368 -290
  61. package/templates/product-detail.tsx +39 -58
  62. package/templates/product-gallery.tsx +30 -41
  63. package/templates/product-tour.template.mjs +6 -0
  64. package/templates/product-tour.tsx +916 -0
  65. package/templates/settings-dialog.tsx +135 -282
  66. package/templates/settings-sidebar.tsx +178 -268
  67. package/templates/settings.tsx +41 -14
  68. package/templates/shell-nav.tsx +31 -24
  69. package/templates/shell-side-nav.tsx +29 -20
  70. package/templates/shell-top-nav.tsx +80 -44
  71. package/templates/side-gallery.tsx +38 -94
  72. package/templates/table-grouped.tsx +62 -34
  73. package/templates/table-page-chart.tsx +23 -302
  74. package/templates/table-page-heatmap-status.tsx +156 -92
  75. package/templates/table-page-shoe-store-heatmap.tsx +18 -293
  76. package/templates/table-page.tsx +23 -7
  77. package/templates/table.tsx +23 -8
  78. package/templates/tech-report.template.mjs +6 -0
  79. package/templates/tech-report.tsx +1486 -0
  80. package/templates/theme-showcase.template.mjs +1 -1
  81. package/templates/theme-showcase.tsx +299 -237
  82. package/theme.css +76 -14
  83. package/tokens.css +425 -30
@@ -1,8 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
  // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (LC > V[g=8] > (V[g=2] > Tx.display-1"Getting started with Astryx Dracula" + Tx"Last updated March 30, 2026"[t=supporting]) + (C > V[g=3] > (H[j=between] > (H[g=2] > Ic + Tx"AI Assistance"[t=body]) + (H > B"Copy prompt" + DM)) + Tx"Prompt description"[t=body]) + (V[g=4] > Hd"Prerequisites"[level=2] + UL) + D + (V[g=4] > Hd"Install the package"[level=2] + Tx"Description"[t=body] + (V[g=2] > Tx"Step"[t=body] + Cd)*3) + D + (V[g=4] > Hd"Configure theming"[level=2] + Tx"Description"[t=body] + Cd + Tx"Note"[t=body]) + D + (V[g=4] > Hd"Next steps"[level=2] + UL)) + (LP > Outline)
3
+ // L > (LC > V[g=8] > (V[g=2] > Hd"Getting started with Astryx Dracula"[level=1] + Tx"Last updated March 30, 2026"[t=supporting]) + (C > V[g=3] > (H[j=between] > (H[g=2] > Ic + Tx"AI Assistance"[t=body]) + (H > B"Copy prompt" + DM)) + Tx"Prompt description"[t=body]) + (V[g=4] > Hd"Prerequisites"[level=2] + UL) + D + (V[g=4] > Hd"Install the package"[level=2] + Tx"Description"[t=body] + (V[g=2] > Tx"Step"[t=body] + Cd)*3) + D + (V[g=4] > Hd"Configure theming"[level=2] + Tx"Description"[t=body] + Cd + Tx"Note"[t=body]) + D + (V[g=4] > Hd"Next steps"[level=2] + UL)) + (LP > Outline)
4
4
 
5
- import {useCallback, useState, type CSSProperties} from 'react';
5
+ import {useCallback, useState} from 'react';
6
6
  import {Heading, Text} from '@astryxdesign/core/Text';
7
7
  import {Button} from '@astryxdesign/core/Button';
8
8
  import {Card} from '@astryxdesign/core/Card';
@@ -17,11 +17,31 @@ import {Icon} from '@astryxdesign/core/Icon';
17
17
  import {Outline, type OutlineItem} from '@astryxdesign/core/Outline';
18
18
  import {useMediaQuery} from '@astryxdesign/core/hooks';
19
19
  import {Sparkles, ClipboardCopy, ChevronDown} from 'lucide-react';
20
+ import {outlinePanel} from 'astryx-dracula/shared/chaptered-doc-config';
20
21
 
21
22
  // ---------------------------------------------------------------------------
22
23
  // Main component
23
24
  // ---------------------------------------------------------------------------
24
25
 
26
+ /**
27
+ * Documentation technical — the getting-started guide: prerequisites, install steps, theming, and next steps. (Frame/responsive/container: see XLE header above.)
28
+ */
29
+
30
+ // Same prompt in the copy action and the visible body: one string, so the
31
+ // two can never drift.
32
+ const SETUP_PROMPT =
33
+ '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.';
34
+
35
+ // Copies the setup prompt in the shape each tool wants to receive it. The
36
+ // menu cannot navigate anywhere from a static template, so the action says
37
+ // what it does.
38
+ const PROMPT_TARGETS = ['v0', 'Claude', 'ChatGPT', 'Cursor'].map(target => ({
39
+ label: `Copy for ${target}`,
40
+ onClick: () => {
41
+ void navigator.clipboard.writeText(SETUP_PROMPT);
42
+ },
43
+ }));
44
+
25
45
  const OUTLINE_ITEMS: OutlineItem[] = [
26
46
  {id: 'prerequisites', label: 'Prerequisites', level: 2},
27
47
  {id: 'install-package', label: 'Install the package', level: 2},
@@ -34,13 +54,6 @@ const OUTLINE_OPTIONS = OUTLINE_ITEMS.map(item => ({
34
54
  label: item.label,
35
55
  }));
36
56
 
37
- const outlinePanel: CSSProperties = {
38
- position: 'sticky',
39
- top: 24,
40
- alignSelf: 'start',
41
- paddingBlockStart: 120,
42
- };
43
-
44
57
  export default function DocumentationTechnical() {
45
58
  const [activeId, setActiveId] = useState<string | undefined>(
46
59
  OUTLINE_ITEMS[0]?.id,
@@ -75,7 +88,7 @@ export default function DocumentationTechnical() {
75
88
  <LayoutContent isScrollable={false} padding={8}>
76
89
  <VStack gap={8}>
77
90
  <VStack gap={2}>
78
- <Text type="display-1">Getting started with Astryx Dracula</Text>
91
+ <Heading level={1}>Getting started with Astryx Dracula</Heading>
79
92
  <Text type="supporting" color="secondary" hasTabularNumbers>
80
93
  Last updated March 30, 2026
81
94
  </Text>
@@ -108,9 +121,7 @@ export default function DocumentationTechnical() {
108
121
  size="sm"
109
122
  icon={<Icon icon={ClipboardCopy} />}
110
123
  onClick={() => {
111
- void navigator.clipboard.writeText(
112
- '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.',
113
- );
124
+ void navigator.clipboard.writeText(SETUP_PROMPT);
114
125
  }}
115
126
  />
116
127
  <DropdownMenu
@@ -121,12 +132,7 @@ export default function DocumentationTechnical() {
121
132
  isIconOnly: true,
122
133
  icon: <Icon icon={ChevronDown} />,
123
134
  }}
124
- items={[
125
- {label: 'Open in v0', onClick: () => {}},
126
- {label: 'Open in Claude', onClick: () => {}},
127
- {label: 'Open in ChatGPT', onClick: () => {}},
128
- {label: 'Open in Cursor', onClick: () => {}},
129
- ]}
135
+ items={PROMPT_TARGETS}
130
136
  />
131
137
  </HStack>
132
138
  <Text type="body" color="secondary">
@@ -174,6 +180,7 @@ export default function DocumentationTechnical() {
174
180
  code="npm install @astryxdesign/core"
175
181
  language="bash"
176
182
  width="100%"
183
+ hasCopyButton
177
184
  />
178
185
  </VStack>
179
186
  <VStack gap={2}>
@@ -190,6 +197,7 @@ export default function DocumentationTechnical() {
190
197
  import '@astryxdesign/core/astryx.css';`}
191
198
  language="tsx"
192
199
  width="100%"
200
+ hasCopyButton
193
201
  />
194
202
  </VStack>
195
203
  <VStack gap={2}>
@@ -204,6 +212,7 @@ export default function App() {
204
212
  }`}
205
213
  language="tsx"
206
214
  width="100%"
215
+ hasCopyButton
207
216
  />
208
217
  </VStack>
209
218
  </VStack>
@@ -231,6 +240,7 @@ export default function App({ children }) {
231
240
  }`}
232
241
  language="tsx"
233
242
  width="100%"
243
+ hasCopyButton
234
244
  />
235
245
  <Text type="body" color="secondary">
236
246
  See the theming guide for the full list of customizable tokens.
@@ -2,5 +2,5 @@ export default {
2
2
  type: 'page',
3
3
  name: 'Component Catalog',
4
4
  description: 'Hero plus categorized component grid',
5
- category: 'marketing',
5
+ category: 'docs',
6
6
  };
@@ -1,6 +1,14 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
  // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > LC > V[g=10] > (C[p=10] > (H[g=8 a=center] > (V[g=4] > Tx.display-1"The coven grimoire" + Tx.lg"Every incantation in the Astryx spellbook"[t=large] + (H > B.primary"Enter the grimoire")))) + (V[g=4] > (H[j=between a=center] > Hd"Category"[level=2] + Tx"18 spells"[t=supporting]) + (G[c=4 g=2] > (CC[p=2] > V[g=3] > C[p=0] + (V[g=1] > Tx"AppShell"[t=body] + Tx"Description"[t=body]))*4))*4
3
+ // Counts: 31 total, Core 18 / Layout 4 / Navigation 4 / Form 5. Derived at
4
+ // render from COMPONENT_CATEGORIES, so these numerals must move together with
5
+ // the array -- the gate in scripts/check.ts reads the rendered count, not this
6
+ // comment.
7
+ // L > LC > V[g=10] > (C[p=10] > (H[g=8 a=center] > (V[g=4] > Hd"The coven grimoire"[level=1 t=display-1] + Tx.lg"Every incantation in the Astryx spellbook"[t=large] + (H > B.primary"Enter the grimoire")))) + (V[g=4] > (H[j=between a=center] > Hd"Core"[level=2] + Tx"18 spells"[t=body]) + (H[j=between a=center] > Hd"Layout"[level=2] + Tx"4 spells"[t=body]) + (H[j=between a=center] > Hd"Navigation"[level=2] + Tx"4 spells"[t=body]) + (H[j=between a=center] > Hd"Form"[level=2] + Tx"5 spells"[t=body]) + (G[c={min:260} g=4] > (CC[p=4] > V[g=3] > C[p=0] + (V[g=1] > Tx"Avatar"[t=body] + Tx"Avatars represent"[t=body]))*4))
8
+
9
+ /**
10
+ * Documentation catalog — every component shelf in the grimoire. Frame-first layout (see `bunx astryx docs layout`): (Frame/responsive/container: see XLE header above.)
11
+ */
4
12
 
5
13
  import type {CSSProperties} from 'react';
6
14
  import {Heading, Text} from '@astryxdesign/core/Text';
@@ -10,25 +18,25 @@ import {ClickableCard} from '@astryxdesign/core/ClickableCard';
10
18
  import {HStack, VStack, StackItem} from '@astryxdesign/core/Stack';
11
19
  import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
12
20
  import {Grid} from '@astryxdesign/core/Grid';
21
+ import {SceneTile} from 'astryx-dracula/shared/scene-tile';
22
+ import {galleryImageClip} from 'astryx-dracula/shared/gallery-image';
23
+ import type {SceneHue} from 'astryx-dracula/shared/scene-hues';
13
24
 
14
- const previewArt: CSSProperties = {
15
- width: '100%',
16
- height: '100%',
17
- display: 'block',
18
- };
19
- const previewClip: CSSProperties = {
20
- borderRadius: 'var(--radius-element)',
21
- overflow: 'clip',
22
- };
23
25
  // Negative margin offsets each card's 8px padding so the grid content stays
24
26
  // visually aligned while giving every card a padded hover/click target.
25
27
  const cardGrid: CSSProperties = {
26
- margin: -8,
28
+ margin: 'calc(var(--spacing-2) * -1)',
27
29
  };
28
30
 
29
- // Dracula accent per grimoire shelf.
30
- const SHELF_HUES: Record<string, string> = {
31
- Core: 'var(--dracula-purple)',
31
+ // Same-route hash: demo links stay focusable anchors without escaping the
32
+ // template through the hash router (bare "#" would drop back to the home page).
33
+ const SELF_HASH = '#/templates/documentation';
34
+
35
+ // Decorative accent per grimoire shelf. None of them is purple: the sigils
36
+ // are not interactive, and purple belongs to the things that are. Art lives
37
+ // in shared/scene-tile (lg fork: centered glyph on a flat field).
38
+ const SHELF_HUES: Record<string, SceneHue> = {
39
+ Core: 'var(--dracula-pink)',
32
40
  Layout: 'var(--dracula-cyan)',
33
41
  Navigation: 'var(--dracula-green)',
34
42
  Form: 'var(--dracula-yellow)',
@@ -216,50 +224,16 @@ const COMPONENT_CATEGORIES = [
216
224
  },
217
225
  ];
218
226
 
219
- // ---------------------------------------------------------------------------
220
- // Preview art
221
- // ---------------------------------------------------------------------------
222
-
223
- function PreviewArt({name, shelf}: {name: string; shelf: string}) {
224
- const hue = SHELF_HUES[shelf] ?? 'var(--dracula-purple)';
225
- return (
226
- <svg
227
- viewBox="0 0 400 300"
228
- preserveAspectRatio="xMidYMid slice"
229
- style={previewArt}
230
- role="img"
231
- aria-label={`${name} sigil`}>
232
- <rect width="400" height="300" fill="var(--dracula-bg-light)" />
233
- <circle cx="316" cy="66" r="26" fill={hue} opacity={0.85} />
234
- <circle
235
- cx="306"
236
- cy="60"
237
- r="21"
238
- fill="var(--dracula-bg-light)"
239
- opacity={0.5}
240
- />
241
- <path
242
- d="M0 208 Q110 168 210 198 T400 184 V300 H0 Z"
243
- fill="var(--dracula-current-line)"
244
- />
245
- <path
246
- d="M0 236 Q130 206 260 230 T400 222 V300 H0 Z"
247
- fill="var(--dracula-bg)"
248
- />
249
- <g
250
- transform="translate(140 150)"
251
- fill="none"
252
- stroke="var(--dracula-comment)"
253
- strokeWidth="5"
254
- strokeLinecap="round"
255
- strokeLinejoin="round">
256
- <rect x="-44" y="-44" width="88" height="88" rx="5" />
257
- <circle cx="18" cy="-18" r="2.5" fill={hue} stroke="none" />
258
- <path d="M-34 30 L-8 0 L10 18 L20 8 L34 24" />
259
- </g>
260
- </svg>
261
- );
262
- }
227
+ // Every count in this template is DERIVED from the array above, never written as
228
+ // a numeral. The hero copy and the per-category "N spells" line both read this
229
+ // and `items.length`, so adding a component can no longer make the page lie
230
+ // about its own size -- which is what happened while the hero copy said
231
+ // "twenty-eight" against 31 entries and the XLE header said 15 for a category
232
+ // of 18.
233
+ const COMPONENT_TOTAL = COMPONENT_CATEGORIES.reduce(
234
+ (sum, category) => sum + category.items.length,
235
+ 0,
236
+ );
263
237
 
264
238
  // ---------------------------------------------------------------------------
265
239
  // Main component
@@ -273,26 +247,26 @@ export default function DocumentationCatalog() {
273
247
  content={
274
248
  <LayoutContent padding={8}>
275
249
  <VStack gap={10}>
276
- <Card variant="gray" padding={10}>
250
+ <Card variant="transparent" padding={10}>
277
251
  <HStack gap={8} vAlign="center">
278
252
  <StackItem size="fill">
279
253
  <VStack gap={4}>
280
- <Text type="display-1">The coven grimoire</Text>
254
+ <Heading level={1} type="display-1">
255
+ The coven grimoire
256
+ </Heading>
281
257
  <Text type="large" weight="normal" color="secondary">
282
- Every incantation in the Astryx spellbook — thirty-one
283
- components for building beautiful, accessible products
284
- after dark.
258
+ Every incantation in the Astryx spellbook, with{' '}
259
+ {COMPONENT_TOTAL} components for building beautiful,
260
+ accessible products after dark.
285
261
  </Text>
286
262
  <HStack>
287
263
  <Button
288
264
  label="Enter the grimoire"
289
265
  variant="primary"
290
- size="lg"
291
266
  />
292
267
  </HStack>
293
268
  </VStack>
294
269
  </StackItem>
295
- <StackItem size="fill" />
296
270
  </HStack>
297
271
  </Card>
298
272
 
@@ -301,33 +275,37 @@ export default function DocumentationCatalog() {
301
275
  <HStack justify="between" vAlign="center">
302
276
  <Heading level={2}>{category.label}</Heading>
303
277
  <Text
304
- type="supporting"
278
+ type="body"
305
279
  color="secondary"
306
280
  hasTabularNumbers>
307
281
  {category.items.length}{' '}
308
282
  {category.items.length === 1 ? 'spell' : 'spells'}
309
283
  </Text>
310
284
  </HStack>
311
- <Grid columns={{minWidth: 260}} gap={2} style={cardGrid}>
285
+ <Grid columns={{minWidth: 260}} gap={4} style={cardGrid}>
312
286
  {category.items.map(item => (
313
287
  <ClickableCard
314
288
  key={item.key}
315
289
  label={`Open ${item.name}`}
316
- onClick={() => {}}
290
+ href={SELF_HASH}
317
291
  variant="transparent"
318
- padding={2}>
292
+ padding={4}>
319
293
  <VStack gap={3}>
320
294
  <Card
321
295
  variant="muted"
322
296
  padding={0}
323
297
  minHeight={160}
324
- style={previewClip}>
325
- <PreviewArt
326
- name={item.name}
327
- shelf={category.label}
298
+ style={galleryImageClip}>
299
+ <SceneTile
300
+ label={`${item.name} sigil`}
301
+ hue={
302
+ SHELF_HUES[category.label] ??
303
+ 'var(--dracula-comment)'
304
+ }
305
+ size="lg"
328
306
  />
329
307
  </Card>
330
- <VStack gap={0.5}>
308
+ <VStack gap={1}>
331
309
  <Text type="body" weight="semibold">
332
310
  {item.name}
333
311
  </Text>