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,6 +1,6 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
  // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (LH > V[g=4] > (H[j=between] > Lk"All orders" + (H[g=2] > B"Restock" + B"Edit")) + (H[g=2 a=center] > Hd"#1001"[level=1] + Bd.warning"Unfulfilled") + (H[j=between] > TL > Tab"Details"! + Tab"Invoices" + Tab"Timeline")) + (LC > V[g=4] > (C > V[g=4] > (H[j=between] > Hd"Items"[level=2] + B"Fulfill item") + UL) + (C > V[g=4] > (H[j=between] > Hd"Invoice"[level=2] + B"Send Invoice") + ML) + (S > V[g=4] > Hd"Timeline"[level=2] + UL)) + (LP[w=320] > V[g=4] > Col"Notes" + Col"Customer" + Col"Fraud Analysis")
3
+ // L > (LH[divider] > V[g=3] > ((H[g=4 a=start] > (SI > V[g=0] > (Lk"All orders" + (V[g=0] > Hd"#1001"[level=1] + (H[g=1 a=center] > Tx"5 ordered items"[t=supporting] + Av"Vlad Dracul" + SD"Unfulfilled" + Tx"02/23/2026"[t=supporting] + Lk"See all")))) + (H[g=2] > B"Restock" + B"Edit")) + (H[g=3 a=center] > (SI > TL > Tab"Details"! + Tab"Invoices" + Tab"Timeline" + TabMenu"More") + B.ghost))) + (LC > V[g=4] > ((S > V[g=4] > ((H[g=2 a=center] > Hd"Items"[level=2] + SD"Unfulfilled") + UL)) + (S > V[g=4] > ((H[g=2 a=center] > Hd"Invoice"[level=2] + SD"Paid") + ML)) + (S > V[g=4] > ((H[g=2 a=center] > Hd"Timeline"[level=2] + B.ghost) + UL)))) + (LP[w=320 p=4] > V[g=4] > Col"Notes" + Col"Customer" + Col"Fraud analysis")
4
4
 
5
5
  import {useState} from 'react';
6
6
  import {useMediaQuery} from '@astryxdesign/core/hooks';
@@ -16,7 +16,7 @@ import {
16
16
  Section,
17
17
  } from '@astryxdesign/core/Layout';
18
18
  import {Text, Heading} from '@astryxdesign/core/Text';
19
- import {Badge} from '@astryxdesign/core/Badge';
19
+ import {StatusDot} from '@astryxdesign/core/StatusDot';
20
20
  import {Avatar} from '@astryxdesign/core/Avatar';
21
21
  import {Button} from '@astryxdesign/core/Button';
22
22
  import {TabList, Tab, TabMenu} from '@astryxdesign/core/TabList';
@@ -28,6 +28,7 @@ import {ProgressBar} from '@astryxdesign/core/ProgressBar';
28
28
  import {Collapsible} from '@astryxdesign/core/Collapsible';
29
29
  import {Icon} from '@astryxdesign/core/Icon';
30
30
  import {Dialog, DialogHeader} from '@astryxdesign/core/Dialog';
31
+ import type {SceneHue} from 'astryx-dracula/shared/scene-hues';
31
32
  import {
32
33
  Calendar,
33
34
  Flag,
@@ -95,9 +96,15 @@ const PRODUCTS = [
95
96
  },
96
97
  ];
97
98
 
98
- // Dracula accent per product row.
99
- const PRODUCT_HUES = [
100
- 'var(--dracula-purple)',
99
+ // Per-product art tint, read positionally out of a never-reordered array so
100
+ // "Crypt Cup" keeps its hue for the life of the page. Typed `SceneHue` for two
101
+ // reasons, not one: the union is the enforcement, and it also pins the key set
102
+ // so the array cannot grow a sixth entry that silently reuses slot 1 (the old
103
+ // `index % length` wrapped at n>5 — a latent bug, not a live one).
104
+ // The art-treatment remit bans purple, so the leading entry changes to cyan on
105
+ // the same pass.
106
+ const PRODUCT_HUES: readonly SceneHue[] = [
107
+ 'var(--dracula-cyan)',
101
108
  'var(--dracula-cyan)',
102
109
  'var(--dracula-pink)',
103
110
  'var(--dracula-yellow)',
@@ -111,7 +118,7 @@ const sigilClip: CSSProperties = {
111
118
  flexShrink: 0,
112
119
  };
113
120
 
114
- function ProductSigil({name, index}: {name: string; index: number}) {
121
+ function ProductSigil({index}: {name: string; index: number}) {
115
122
  const hue = PRODUCT_HUES[index % PRODUCT_HUES.length];
116
123
  return (
117
124
  <Card padding={0} style={sigilClip}>
@@ -119,8 +126,7 @@ function ProductSigil({name, index}: {name: string; index: number}) {
119
126
  viewBox="0 0 40 40"
120
127
  width={40}
121
128
  height={40}
122
- role="img"
123
- aria-label={name}>
129
+ aria-hidden="true">
124
130
  <rect width="40" height="40" fill="var(--dracula-bg-light)" />
125
131
  <circle cx={28} cy={11} r={7} fill={hue} />
126
132
  <circle
@@ -151,7 +157,7 @@ const fmt = (n: number) => `$${n.toFixed(2)}`;
151
157
  const ACTIVITY = [
152
158
  {
153
159
  type: 'event' as const,
154
- user: 'Jane Doe',
160
+ user: 'Vlad Dracul',
155
161
  text: 'placed order #1001',
156
162
  reactions: 2,
157
163
  time: 'Feb 23 at 9:12 AM',
@@ -159,7 +165,7 @@ const ACTIVITY = [
159
165
  {
160
166
  type: 'comment' as const,
161
167
  user: 'Alex Rivera',
162
- text: "Customer requested gift wrapping for the mug & plate set. I've added a note to the packing slip — warehouse team should wrap in recycled kraft paper.",
168
+ text: "Customer requested gift wrapping for the mug & plate set. I've added a note to the packing slip. Warehouse team should wrap in recycled kraft paper.",
163
169
  reactions: 3,
164
170
  time: 'Feb 23 at 10:45 AM',
165
171
  },
@@ -169,8 +175,8 @@ const ACTIVITY = [
169
175
  text: 'has several information changes',
170
176
  time: 'Feb 23 at 11:30 AM',
171
177
  changes: [
172
- 'Payment verified via Visa ...7482',
173
- 'Fraud check passed — low risk',
178
+ 'Payment verified via Visa …7482',
179
+ 'Fraud check passed, low risk',
174
180
  ],
175
181
  },
176
182
  {
@@ -185,7 +191,7 @@ const ACTIVITY = [
185
191
  // ─── Bullet separator ───────────────────────────────────────────────────────
186
192
  function Bullet() {
187
193
  return (
188
- <Text type="supporting" color="secondary">
194
+ <Text type="supporting" color="secondary" aria-hidden="true">
189
195
  {'・'}
190
196
  </Text>
191
197
  );
@@ -206,7 +212,7 @@ function PageHeader({
206
212
  isNarrow: boolean;
207
213
  }) {
208
214
  return (
209
- <LayoutHeader hasDivider padding={4}>
215
+ <LayoutHeader hasDivider padding={6}>
210
216
  <VStack gap={3}>
211
217
  <HStack gap={4} vAlign="start">
212
218
  <StackItem size="fill">
@@ -229,14 +235,17 @@ function PageHeader({
229
235
  </Text>
230
236
  <HStack gap={1} vAlign="center">
231
237
  <Bullet />
232
- <Avatar name="Jane Doe" size="sm" />
238
+ <Avatar name="Vlad Dracul" size="sm" />
233
239
  <Text type="supporting" color="secondary" maxLines={1}>
234
- Jane Doe
240
+ Vlad Dracul
235
241
  </Text>
236
242
  </HStack>
237
243
  <HStack gap={1} vAlign="center">
238
244
  <Bullet />
239
- <Badge variant="orange" label="Unfulfilled" />
245
+ <StatusDot variant="warning" label="Unfulfilled" />
246
+ <Text type="supporting" color="secondary">
247
+ Unfulfilled
248
+ </Text>
240
249
  </HStack>
241
250
  <HStack gap={1} vAlign="center">
242
251
  <Bullet />
@@ -330,7 +339,10 @@ function ItemsCard() {
330
339
  <StackItem size="fill">
331
340
  <HStack gap={2} vAlign="center">
332
341
  <Heading level={2}>Items</Heading>
333
- <Badge variant="orange" label="Unfulfilled" />
342
+ <StatusDot variant="warning" label="Unfulfilled" />
343
+ <Text type="supporting" color="secondary">
344
+ Unfulfilled
345
+ </Text>
334
346
  </HStack>
335
347
  </StackItem>
336
348
  <HStack gap={2}>
@@ -342,13 +354,13 @@ function ItemsCard() {
342
354
  <List density="spacious" style={itemsList}>
343
355
  {PRODUCTS.map((product, i) => (
344
356
  <ListItem
345
- key={i}
357
+ key={product.name}
346
358
  label={product.name}
347
359
  description={
348
360
  <VStack gap={0}>
349
- {product.details.split('\n').map((line, j) => (
361
+ {product.details.split('\n').map(line => (
350
362
  <Text
351
- key={j}
363
+ key={line}
352
364
  type="supporting"
353
365
  color="secondary"
354
366
  hasTabularNumbers>
@@ -357,7 +369,6 @@ function ItemsCard() {
357
369
  ))}
358
370
  </VStack>
359
371
  }
360
- onClick={() => {}}
361
372
  startContent={
362
373
  <ProductSigil name={product.name} index={i} />
363
374
  }
@@ -396,7 +407,10 @@ function InvoiceCard() {
396
407
  <StackItem size="fill">
397
408
  <HStack gap={2} vAlign="center">
398
409
  <Heading level={2}>Invoice</Heading>
399
- <Badge variant="green" label="Paid" />
410
+ <StatusDot variant="success" label="Paid" />
411
+ <Text type="supporting" color="secondary">
412
+ Paid
413
+ </Text>
400
414
  </HStack>
401
415
  </StackItem>
402
416
  <HStack gap={2}>
@@ -469,7 +483,7 @@ function InvoiceCard() {
469
483
  <HStack>
470
484
  <StackItem size="fill">
471
485
  <Text type="body" hasTabularNumbers>
472
- Visa ...7482
486
+ Visa …7482
473
487
  </Text>
474
488
  </StackItem>
475
489
  <Text type="body" hasTabularNumbers>
@@ -488,7 +502,11 @@ function TimelineSection() {
488
502
  return (
489
503
  <Section>
490
504
  <VStack gap={4}>
491
- <HStack vAlign="center">
505
+ {/* gap={2}, matching the byte-identical header rows at :338 and
506
+ :407. Core's Stack has no default gap (Stack.tsx:211, pass-through
507
+ at :255/:285), so this rendered 0px -- the heading and the Filters
508
+ button touched -- while both siblings render 8px. */}
509
+ <HStack gap={2} vAlign="center">
492
510
  <StackItem size="fill">
493
511
  <Heading level={2}>Timeline</Heading>
494
512
  </StackItem>
@@ -500,73 +518,58 @@ function TimelineSection() {
500
518
  />
501
519
  </HStack>
502
520
 
503
- <VStack gap={4}>
504
- {ACTIVITY.map((item, i) => (
505
- <VStack key={i} gap={2}>
506
- <HStack gap={3} vAlign="start">
507
- <Avatar name={item.user} size="md" />
508
- <StackItem size="fill">
509
- <VStack gap={2}>
510
- <Card variant="muted" padding={3}>
511
- <VStack gap={1}>
512
- <Text type="body" weight="semibold">
513
- {item.user}
514
- </Text>
515
- <Text type="body">{item.text}</Text>
516
- {item.changes && (
517
- <VStack gap={1}>
518
- {item.changes.map((change, j) => (
519
- <HStack key={j} gap={2} vAlign="center">
520
- <Icon
521
- icon={SquarePen}
522
- size="sm"
523
- color="secondary"
524
- />
525
- <Text type="supporting" color="secondary">
526
- {change}
527
- </Text>
528
- </HStack>
529
- ))}
530
- </VStack>
531
- )}
532
- </VStack>
533
- </Card>
534
- <HStack gap={3} vAlign="center">
535
- <HStack gap={1} vAlign="center">
536
- <Icon
537
- icon={ThumbsUp}
538
- size="xsm"
539
- color="secondary"
540
- />
541
- <Icon icon={Heart} size="xsm" color="secondary" />
542
- <Text
543
- type="supporting"
544
- color="secondary"
545
- hasTabularNumbers>
546
- {item.reactions}
547
- </Text>
548
- </HStack>
549
- <Text type="supporting" color="secondary">
550
- Like
551
- </Text>
552
- <Bullet />
553
- <Text type="supporting" color="secondary">
554
- Reply
555
- </Text>
556
- <Bullet />
521
+ <List density="spacious" style={itemsList}>
522
+ {ACTIVITY.map(item => (
523
+ <ListItem
524
+ key={`${item.user}-${item.time}`}
525
+ label={item.user}
526
+ description={
527
+ <VStack gap={2}>
528
+ <Text type="body">{item.text}</Text>
529
+ {item.changes && (
530
+ <VStack gap={1}>
531
+ {item.changes.map(change => (
532
+ <HStack key={change} gap={2} vAlign="center">
533
+ <Icon icon={SquarePen} size="sm" color="secondary" />
534
+ <Text type="supporting" color="secondary">
535
+ {change}
536
+ </Text>
537
+ </HStack>
538
+ ))}
539
+ </VStack>
540
+ )}
541
+ <HStack gap={3} vAlign="center">
542
+ <HStack gap={1} vAlign="center">
543
+ <Icon icon={ThumbsUp} size="xsm" color="secondary" />
544
+ <Icon icon={Heart} size="xsm" color="secondary" />
557
545
  <Text
558
546
  type="supporting"
559
547
  color="secondary"
560
548
  hasTabularNumbers>
561
- {item.time}
549
+ {item.reactions}
562
550
  </Text>
563
551
  </HStack>
564
- </VStack>
565
- </StackItem>
566
- </HStack>
567
- </VStack>
552
+ <Text type="supporting" color="secondary">
553
+ Like
554
+ </Text>
555
+ <Bullet />
556
+ <Text type="supporting" color="secondary">
557
+ Reply
558
+ </Text>
559
+ <Bullet />
560
+ <Text
561
+ type="supporting"
562
+ color="secondary"
563
+ hasTabularNumbers>
564
+ {item.time}
565
+ </Text>
566
+ </HStack>
567
+ </VStack>
568
+ }
569
+ startContent={<Avatar name={item.user} size="md" />}
570
+ />
568
571
  ))}
569
- </VStack>
572
+ </List>
570
573
  </VStack>
571
574
  </Section>
572
575
  );
@@ -578,9 +581,9 @@ function TimelineSection() {
578
581
  function PanelContent() {
579
582
  return (
580
583
  <VStack gap={4}>
581
- <Collapsible trigger={<Heading level={4}>Notes</Heading>}>
584
+ <Collapsible trigger={<Heading level={3}>Notes</Heading>}>
582
585
  <Text type="body">
583
- Customer is a repeat buyer — 3rd order this quarter. Prefers
586
+ Customer is a repeat buyer, 3rd order this quarter. Prefers
584
587
  moonlight and sage glazes. Requested gift wrapping for the mug set.
585
588
  Ships to a residential address in CA.{' '}
586
589
  <Link href="#/templates/detail-page">
@@ -588,20 +591,20 @@ function PanelContent() {
588
591
  </Link>
589
592
  </Text>
590
593
  </Collapsible>
591
- <Collapsible trigger={<Heading level={4}>Customer</Heading>}>
594
+ <Collapsible trigger={<Heading level={3}>Customer</Heading>}>
592
595
  <MetadataList>
593
- <MetadataListItem label="Name">Jane Doe</MetadataListItem>
596
+ <MetadataListItem label="Name">Vlad Dracul</MetadataListItem>
594
597
  <MetadataListItem label="Address">
595
598
  321 Smith Road, CA 38238
596
599
  </MetadataListItem>
597
600
  <MetadataListItem label="Phone">234-555-0134</MetadataListItem>
598
- <MetadataListItem label="Email">janedoe@email.com</MetadataListItem>
601
+ <MetadataListItem label="Email">vlad@castle-dracula.transylvania</MetadataListItem>
599
602
  <MetadataListItem label="Billing Address">
600
603
  Same as shipping address
601
604
  </MetadataListItem>
602
605
  </MetadataList>
603
606
  </Collapsible>
604
- <Collapsible trigger={<Heading level={4}>Fraud Analysis</Heading>}>
607
+ <Collapsible trigger={<Heading level={3}>Fraud analysis</Heading>}>
605
608
  <VStack gap={1}>
606
609
  <ProgressBar
607
610
  label="Risk level"
@@ -679,6 +682,7 @@ export default function DetailPage() {
679
682
  isOpen={isNarrow && isPanelDialogOpen}
680
683
  onOpenChange={setPanelDialogOpen}>
681
684
  <Layout
685
+ height="auto"
682
686
  header={
683
687
  <DialogHeader
684
688
  title="Order details"
@@ -2,5 +2,5 @@ export default {
2
2
  type: 'page',
3
3
  name: 'Design Documentation',
4
4
  description: 'Live preview, usage guide, and code examples',
5
- category: 'marketing',
5
+ category: 'docs',
6
6
  };
@@ -1,11 +1,20 @@
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"Button" + Tx"March 30, 2026"[t=supporting]) + (C.muted[p=0] > Ctr[h=360]) + (V[g=4] > Hd"Usage"[level=2] + Tx.lg"Usage" + Hd"Best practices"[level=3] + T) + D + (V[g=4] > Hd"Examples"[level=2] + Tx.lg"Explore") + (V[g=8] > (C[p=0] > (S[p=3] > H[j=between] > Tx"Title"[t=body] + (H[g=1] > B"Open in Craft" + IB)) + Ctr[h=280] + (S.muted[p=3] > V[g=3] > (TL > Tab"Description"! + Tab"Code") + Tx"Description"[t=body]))*2)) + (LP > Outline)
3
+ // L > (LC > V[g=8] > (V[g=2] > Hd"Button"[level=1] + Tx"March 30, 2026"[t=supporting]) + (C.muted[p=0] > Ctr[h=360]) + (V[g=4] > Hd"Usage"[level=2] + Tx"Usage"[t=body] + Hd"Best practices"[level=3] + T) + D + (V[g=4] > Hd"Examples"[level=2] + Tx"Explore"[t=body]) + (V[g=8] > (C[p=0] > (S[p=3] > Tx"Semantics"[t=body]) + Ctr[h=280] + (S.muted[p=3] > V[g=3] > (TL > Tab"Description"! + Tab"Code") + Tx"We have four"[t=body])) + (C[p=0] > (S[p=3] > Tx"Default button with badge"[t=body]) + Ctr[h=280] + (S.muted[p=3] > V[g=3] > (TL > Tab"Description"! + Tab"Code") + Tx"Buttons can include"[t=body])))) + (LP > Outline)
4
4
 
5
- import {useCallback, useState, useMemo, type CSSProperties} from 'react';
5
+ /**
6
+ * Documentation detail — one component, its usage, its guidance and its live examples. (Frame/responsive/container: see XLE header above.)
7
+ */
8
+
9
+ import {
10
+ useCallback,
11
+ useState,
12
+ useMemo,
13
+ type CSSProperties,
14
+ type ReactNode,
15
+ } from 'react';
6
16
  import {Heading, Text} from '@astryxdesign/core/Text';
7
17
  import {Button} from '@astryxdesign/core/Button';
8
- import {IconButton} from '@astryxdesign/core/IconButton';
9
18
  import {Card} from '@astryxdesign/core/Card';
10
19
  import {Avatar} from '@astryxdesign/core/Avatar';
11
20
  import {Badge} from '@astryxdesign/core/Badge';
@@ -14,7 +23,7 @@ import {Banner} from '@astryxdesign/core/Banner';
14
23
  import {CodeBlock} from '@astryxdesign/core/CodeBlock';
15
24
  import {TabList, Tab} from '@astryxdesign/core/TabList';
16
25
  import {Selector} from '@astryxdesign/core/Selector';
17
- import {HStack, VStack, StackItem} from '@astryxdesign/core/Stack';
26
+ import {HStack, VStack} from '@astryxdesign/core/Stack';
18
27
  import {Layout, LayoutContent, LayoutPanel} from '@astryxdesign/core/Layout';
19
28
  import {useMediaQuery} from '@astryxdesign/core/hooks';
20
29
  import {Dialog, DialogHeader} from '@astryxdesign/core/Dialog';
@@ -25,14 +34,12 @@ import {Icon} from '@astryxdesign/core/Icon';
25
34
  import {Section} from '@astryxdesign/core/Section';
26
35
  import {Center} from '@astryxdesign/core/Center';
27
36
  import {Outline, type OutlineItem} from '@astryxdesign/core/Outline';
28
- import {ExternalLink, Expand, Plus} from 'lucide-react';
37
+ import {Plus} from 'lucide-react';
38
+ import {outlinePanel} from 'astryx-dracula/shared/chaptered-doc-config';
29
39
 
30
- const tabListFlush: CSSProperties = {marginInlineStart: '-12px'};
31
- const outlinePanel: CSSProperties = {
32
- position: 'sticky',
33
- top: 24,
34
- alignSelf: 'start',
35
- paddingBlockStart: 120,
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)',
36
43
  };
37
44
 
38
45
  const COMPONENT_OUTLINE_ITEMS: OutlineItem[] = [
@@ -54,7 +61,9 @@ function DialogPreview() {
54
61
  const [isOpen, setIsOpen] = useState(false);
55
62
  return (
56
63
  <VStack gap={3}>
57
- <Heading level={3}>Dialog</Heading>
64
+ <Text type="body" weight="semibold">
65
+ Dialog
66
+ </Text>
58
67
  <Button
59
68
  label="Open Dialog"
60
69
  variant="primary"
@@ -441,7 +450,7 @@ const COMPONENT_DOCS: Record<
441
450
  title: 'Default button with badge',
442
451
  description:
443
452
  'Buttons can include a badge to highlight new or updated actions.',
444
- code: `<Button\n label="Button"\n variant="default"\n/>`,
453
+ code: `<Button\n label="Button"\n variant="secondary"\n/>`,
445
454
  },
446
455
  ],
447
456
  },
@@ -496,6 +505,57 @@ function getComponentDocs(key: string) {
496
505
  };
497
506
  }
498
507
 
508
+ const EXAMPLE_PREVIEWS: Record<string, ReactNode[]> = {
509
+ button: [
510
+ <HStack key="semantics" gap={3} vAlign="center" wrap="wrap">
511
+ <Button label="Flat" variant="ghost" />
512
+ <Button label="Default" variant="secondary" />
513
+ <Button label="Primary" variant="primary" />
514
+ <Button label="Destructive" variant="destructive" />
515
+ </HStack>,
516
+ <Button key="badge" label="Button" variant="secondary" />,
517
+ ],
518
+ };
519
+
520
+ const COMPONENT_PREVIEWS: Record<string, ReactNode> = {
521
+ button: (
522
+ <Button
523
+ label="Button"
524
+ variant="secondary"
525
+ icon={<Icon icon={Plus} />}
526
+ endContent={<Badge label="New" variant="cyan" />}
527
+ />
528
+ ),
529
+ avatar: <Avatar name="Vlad" size="lg" />,
530
+ badge: <Badge label="Design" variant="yellow" />,
531
+ card: (
532
+ <Card>
533
+ <VStack gap={2}>
534
+ <Text type="body" weight="semibold">
535
+ Castle Card
536
+ </Text>
537
+ <Text type="body" color="secondary">
538
+ Cards group related content and actions.
539
+ </Text>
540
+ </VStack>
541
+ </Card>
542
+ ),
543
+ banner: (
544
+ <Banner status="info" title="Information">
545
+ <Text type="body">This is an informational banner message.</Text>
546
+ </Banner>
547
+ ),
548
+ dialog: <DialogPreview />,
549
+ text: <Text type="body">Body text</Text>,
550
+ divider: <Divider />,
551
+ token: <Token label="Dracula" />,
552
+ tooltip: (
553
+ <Tooltip content="Primary action">
554
+ <Button label="Hover me" variant="primary" />
555
+ </Tooltip>
556
+ ),
557
+ };
558
+
499
559
  // ---------------------------------------------------------------------------
500
560
  // ComponentDetailView
501
561
  // ---------------------------------------------------------------------------
@@ -516,55 +576,6 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
516
576
  }
517
577
  }, []);
518
578
 
519
- const EXAMPLE_PREVIEWS: Record<string, React.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
- };
530
-
531
- const COMPONENT_PREVIEWS: Record<string, React.ReactNode> = {
532
- button: (
533
- <Button
534
- label="Button"
535
- variant="secondary"
536
- icon={<Icon icon={Plus} />}
537
- endContent={<Badge label="New" variant="cyan" />}
538
- />
539
- ),
540
- avatar: <Avatar name="Vlad" size="lg" />,
541
- badge: <Badge label="Success" variant="green" />,
542
- card: (
543
- <Card>
544
- <VStack gap={2}>
545
- <Heading level={4}>Castle Card</Heading>
546
- <Text type="body" color="secondary">
547
- Cards group related content and actions.
548
- </Text>
549
- </VStack>
550
- </Card>
551
- ),
552
- banner: (
553
- <Banner status="info" title="Information">
554
- <Text type="body">This is an informational banner message.</Text>
555
- </Banner>
556
- ),
557
- dialog: <DialogPreview />,
558
- text: <Text type="body">Body text</Text>,
559
- divider: <Divider />,
560
- token: <Token label="Dracula" />,
561
- tooltip: (
562
- <Tooltip content="Primary action">
563
- <Button label="Hover me" variant="primary" />
564
- </Tooltip>
565
- ),
566
- };
567
-
568
579
  const docs = useMemo(() => getComponentDocs(activeNav), [activeNav]);
569
580
  const previews = EXAMPLE_PREVIEWS[activeNav] ?? [];
570
581
 
@@ -590,7 +601,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
590
601
  <LayoutContent isScrollable={false} padding={8}>
591
602
  <VStack gap={8}>
592
603
  <VStack gap={2}>
593
- <Text type="display-1">{getComponentName(activeNav)}</Text>
604
+ <Heading level={1} type="display-2">{getComponentName(activeNav)}</Heading>
594
605
  <Text type="supporting" color="secondary" hasTabularNumbers>
595
606
  March 30, 2026 · Updated 5:40 p.m. PST
596
607
  </Text>
@@ -610,7 +621,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
610
621
  <Center height={360}>
611
622
  {COMPONENT_PREVIEWS[activeNav] ?? (
612
623
  <Text type="supporting" color="secondary">
613
- Preview coming soon
624
+ Quiet in the crypt — no preview haunts this shelf yet.
614
625
  </Text>
615
626
  )}
616
627
  </Center>
@@ -620,15 +631,14 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
620
631
  <Heading id="usage" level={2}>
621
632
  Usage
622
633
  </Heading>
623
- <Text type="large" weight="normal">
624
- {docs.usage}
625
- </Text>
634
+ <Text type="body">{docs.usage}</Text>
626
635
  <Heading id="best-practices" level={3}>
627
636
  Best practices
628
637
  </Heading>
629
638
  <Table
630
639
  data={docs.bestPractices as Record<string, unknown>[]}
631
640
  dividers="none"
641
+ hasHover
632
642
  columns={[
633
643
  {
634
644
  key: 'type',
@@ -661,7 +671,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
661
671
  <Heading id="examples" level={2}>
662
672
  Examples
663
673
  </Heading>
664
- <Text type="large" weight="normal">
674
+ <Text type="body">
665
675
  Explore common configurations, variations, and states for this
666
676
  component.
667
677
  </Text>
@@ -671,39 +681,16 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
671
681
  const tabKey = `${activeNav}-${i}`;
672
682
  const activeTab = exampleTabs[tabKey] ?? 'description';
673
683
  return (
674
- <Card key={i} padding={0}>
684
+ <Card key={example.title} padding={0}>
675
685
  <Section padding={3} variant="transparent">
676
- <HStack gap={3} vAlign="center" wrap="wrap">
677
- <StackItem size="fill">
678
- <Text type="body" weight="medium">
679
- {example.title}
680
- </Text>
681
- </StackItem>
682
- <HStack gap={1} vAlign="center" wrap="wrap">
683
- <Button
684
- label="Open in Craft"
685
- variant="ghost"
686
- size="sm"
687
- icon={<Icon icon={ExternalLink} />}
688
- />
689
- <Button
690
- label="Send to CLI"
691
- variant="ghost"
692
- size="sm"
693
- />
694
- <IconButton
695
- label="Fullscreen"
696
- variant="ghost"
697
- size="sm"
698
- icon={<Icon icon={Expand} />}
699
- />
700
- </HStack>
701
- </HStack>
686
+ <Text type="body" weight="semibold">
687
+ {example.title}
688
+ </Text>
702
689
  </Section>
703
690
  <Center height={280}>
704
691
  {previews[i] ?? (
705
692
  <Text type="supporting" color="secondary">
706
- Preview coming soon
693
+ Quiet in the crypt — no preview haunts this shelf yet.
707
694
  </Text>
708
695
  )}
709
696
  </Center>
@@ -2,5 +2,5 @@ export default {
2
2
  type: 'page',
3
3
  name: 'Technical Documentation',
4
4
  description: 'Install steps, theming setup, and next steps',
5
- category: 'marketing',
5
+ category: 'docs',
6
6
  };