astryx-dracula 0.2.0 → 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 +22 -11
  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 +67 -32
  31. package/templates/ai-chat.tsx +41 -20
  32. package/templates/blank.tsx +5 -2
  33. package/templates/centered-hero.tsx +15 -124
  34. package/templates/classic-gallery.tsx +21 -65
  35. package/templates/contact-form.tsx +62 -40
  36. package/templates/dashboard-portfolio.tsx +146 -227
  37. package/templates/dashboard.tsx +123 -121
  38. package/templates/detail-page.tsx +101 -95
  39. package/templates/documentation-design.template.mjs +1 -1
  40. package/templates/documentation-design.tsx +85 -96
  41. package/templates/documentation-technical.template.mjs +1 -1
  42. package/templates/documentation-technical.tsx +33 -21
  43. package/templates/documentation.template.mjs +1 -1
  44. package/templates/documentation.tsx +54 -74
  45. package/templates/editor.tsx +119 -89
  46. package/templates/file-explorer.tsx +133 -84
  47. package/templates/form-two-column.tsx +62 -124
  48. package/templates/gallery-hero.tsx +17 -171
  49. package/templates/ide.tsx +27 -21
  50. package/templates/incident-console.tsx +105 -69
  51. package/templates/kanban-board.tsx +100 -41
  52. package/templates/library.template.mjs +2 -2
  53. package/templates/library.tsx +38 -41
  54. package/templates/login-card.tsx +59 -86
  55. package/templates/login-split.tsx +88 -128
  56. package/templates/login-sso.tsx +107 -68
  57. package/templates/login.tsx +108 -52
  58. package/templates/messaging-shell.tsx +172 -143
  59. package/templates/mixed-gallery.tsx +31 -130
  60. package/templates/payment-form.tsx +369 -289
  61. package/templates/product-detail.tsx +40 -57
  62. package/templates/product-gallery.tsx +31 -40
  63. package/templates/product-tour.template.mjs +6 -0
  64. package/templates/product-tour.tsx +916 -0
  65. package/templates/settings-dialog.tsx +145 -286
  66. package/templates/settings-sidebar.tsx +179 -267
  67. package/templates/settings.tsx +42 -13
  68. package/templates/shell-nav.tsx +32 -23
  69. package/templates/shell-side-nav.tsx +30 -19
  70. package/templates/shell-top-nav.tsx +81 -43
  71. package/templates/side-gallery.tsx +39 -93
  72. package/templates/table-grouped.tsx +63 -33
  73. package/templates/table-page-chart.tsx +24 -297
  74. package/templates/table-page-heatmap-status.tsx +157 -91
  75. package/templates/table-page-shoe-store-heatmap.tsx +19 -288
  76. package/templates/table-page.tsx +24 -6
  77. package/templates/table.tsx +24 -7
  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 +313 -249
  82. package/theme.css +76 -14
  83. package/tokens.css +425 -30
@@ -1,4 +1,6 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ // XLE (canonical structure, validated with `bunx astryx layout check`):
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")
2
4
 
3
5
  import {useState} from 'react';
4
6
  import {useMediaQuery} from '@astryxdesign/core/hooks';
@@ -14,7 +16,7 @@ import {
14
16
  Section,
15
17
  } from '@astryxdesign/core/Layout';
16
18
  import {Text, Heading} from '@astryxdesign/core/Text';
17
- import {Badge} from '@astryxdesign/core/Badge';
19
+ import {StatusDot} from '@astryxdesign/core/StatusDot';
18
20
  import {Avatar} from '@astryxdesign/core/Avatar';
19
21
  import {Button} from '@astryxdesign/core/Button';
20
22
  import {TabList, Tab, TabMenu} from '@astryxdesign/core/TabList';
@@ -26,6 +28,7 @@ import {ProgressBar} from '@astryxdesign/core/ProgressBar';
26
28
  import {Collapsible} from '@astryxdesign/core/Collapsible';
27
29
  import {Icon} from '@astryxdesign/core/Icon';
28
30
  import {Dialog, DialogHeader} from '@astryxdesign/core/Dialog';
31
+ import type {SceneHue} from 'astryx-dracula/shared/scene-hues';
29
32
  import {
30
33
  Calendar,
31
34
  Flag,
@@ -93,9 +96,15 @@ const PRODUCTS = [
93
96
  },
94
97
  ];
95
98
 
96
- // Dracula accent per product row.
97
- const PRODUCT_HUES = [
98
- '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)',
99
108
  'var(--dracula-cyan)',
100
109
  'var(--dracula-pink)',
101
110
  'var(--dracula-yellow)',
@@ -109,7 +118,7 @@ const sigilClip: CSSProperties = {
109
118
  flexShrink: 0,
110
119
  };
111
120
 
112
- function ProductSigil({name, index}: {name: string; index: number}) {
121
+ function ProductSigil({index}: {name: string; index: number}) {
113
122
  const hue = PRODUCT_HUES[index % PRODUCT_HUES.length];
114
123
  return (
115
124
  <Card padding={0} style={sigilClip}>
@@ -117,8 +126,7 @@ function ProductSigil({name, index}: {name: string; index: number}) {
117
126
  viewBox="0 0 40 40"
118
127
  width={40}
119
128
  height={40}
120
- role="img"
121
- aria-label={name}>
129
+ aria-hidden="true">
122
130
  <rect width="40" height="40" fill="var(--dracula-bg-light)" />
123
131
  <circle cx={28} cy={11} r={7} fill={hue} />
124
132
  <circle
@@ -149,7 +157,7 @@ const fmt = (n: number) => `$${n.toFixed(2)}`;
149
157
  const ACTIVITY = [
150
158
  {
151
159
  type: 'event' as const,
152
- user: 'Jane Doe',
160
+ user: 'Vlad Dracul',
153
161
  text: 'placed order #1001',
154
162
  reactions: 2,
155
163
  time: 'Feb 23 at 9:12 AM',
@@ -157,7 +165,7 @@ const ACTIVITY = [
157
165
  {
158
166
  type: 'comment' as const,
159
167
  user: 'Alex Rivera',
160
- 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.",
161
169
  reactions: 3,
162
170
  time: 'Feb 23 at 10:45 AM',
163
171
  },
@@ -167,8 +175,8 @@ const ACTIVITY = [
167
175
  text: 'has several information changes',
168
176
  time: 'Feb 23 at 11:30 AM',
169
177
  changes: [
170
- 'Payment verified via Visa ...7482',
171
- 'Fraud check passed — low risk',
178
+ 'Payment verified via Visa …7482',
179
+ 'Fraud check passed, low risk',
172
180
  ],
173
181
  },
174
182
  {
@@ -183,7 +191,7 @@ const ACTIVITY = [
183
191
  // ─── Bullet separator ───────────────────────────────────────────────────────
184
192
  function Bullet() {
185
193
  return (
186
- <Text type="supporting" color="secondary">
194
+ <Text type="supporting" color="secondary" aria-hidden="true">
187
195
  {'・'}
188
196
  </Text>
189
197
  );
@@ -204,12 +212,12 @@ function PageHeader({
204
212
  isNarrow: boolean;
205
213
  }) {
206
214
  return (
207
- <LayoutHeader hasDivider padding={4}>
215
+ <LayoutHeader hasDivider padding={6}>
208
216
  <VStack gap={3}>
209
217
  <HStack gap={4} vAlign="start">
210
218
  <StackItem size="fill">
211
219
  <VStack gap={0}>
212
- <Link href="#/templates/detail-page" color="secondary">
220
+ <Link href="#/templates/detail-page">
213
221
  <HStack gap={1} vAlign="center">
214
222
  <Icon icon={ArrowLeft} size="sm" color="inherit" />
215
223
  All orders
@@ -227,14 +235,17 @@ function PageHeader({
227
235
  </Text>
228
236
  <HStack gap={1} vAlign="center">
229
237
  <Bullet />
230
- <Avatar name="Jane Doe" size="sm" />
238
+ <Avatar name="Vlad Dracul" size="sm" />
231
239
  <Text type="supporting" color="secondary" maxLines={1}>
232
- Jane Doe
240
+ Vlad Dracul
233
241
  </Text>
234
242
  </HStack>
235
243
  <HStack gap={1} vAlign="center">
236
244
  <Bullet />
237
- <Badge variant="warning" label="Unfulfilled" />
245
+ <StatusDot variant="warning" label="Unfulfilled" />
246
+ <Text type="supporting" color="secondary">
247
+ Unfulfilled
248
+ </Text>
238
249
  </HStack>
239
250
  <HStack gap={1} vAlign="center">
240
251
  <Bullet />
@@ -256,7 +267,7 @@ function PageHeader({
256
267
  </HStack>
257
268
  <HStack gap={1} vAlign="center">
258
269
  <Bullet />
259
- <Link href="#/templates/detail-page" color="secondary">
270
+ <Link href="#/templates/detail-page">
260
271
  See all
261
272
  </Link>
262
273
  </HStack>
@@ -328,7 +339,10 @@ function ItemsCard() {
328
339
  <StackItem size="fill">
329
340
  <HStack gap={2} vAlign="center">
330
341
  <Heading level={2}>Items</Heading>
331
- <Badge variant="warning" label="Unfulfilled" />
342
+ <StatusDot variant="warning" label="Unfulfilled" />
343
+ <Text type="supporting" color="secondary">
344
+ Unfulfilled
345
+ </Text>
332
346
  </HStack>
333
347
  </StackItem>
334
348
  <HStack gap={2}>
@@ -340,13 +354,13 @@ function ItemsCard() {
340
354
  <List density="spacious" style={itemsList}>
341
355
  {PRODUCTS.map((product, i) => (
342
356
  <ListItem
343
- key={i}
357
+ key={product.name}
344
358
  label={product.name}
345
359
  description={
346
360
  <VStack gap={0}>
347
- {product.details.split('\n').map((line, j) => (
361
+ {product.details.split('\n').map(line => (
348
362
  <Text
349
- key={j}
363
+ key={line}
350
364
  type="supporting"
351
365
  color="secondary"
352
366
  hasTabularNumbers>
@@ -355,7 +369,6 @@ function ItemsCard() {
355
369
  ))}
356
370
  </VStack>
357
371
  }
358
- onClick={() => {}}
359
372
  startContent={
360
373
  <ProductSigil name={product.name} index={i} />
361
374
  }
@@ -363,7 +376,7 @@ function ItemsCard() {
363
376
  <VStack gap={0} hAlign="end">
364
377
  <Text
365
378
  type="body"
366
- weight="bold"
379
+ weight="semibold"
367
380
  maxLines={1}
368
381
  hasTabularNumbers>
369
382
  {fmt(product.price * product.qty)}
@@ -394,7 +407,10 @@ function InvoiceCard() {
394
407
  <StackItem size="fill">
395
408
  <HStack gap={2} vAlign="center">
396
409
  <Heading level={2}>Invoice</Heading>
397
- <Badge variant="success" label="Paid" />
410
+ <StatusDot variant="success" label="Paid" />
411
+ <Text type="supporting" color="secondary">
412
+ Paid
413
+ </Text>
398
414
  </HStack>
399
415
  </StackItem>
400
416
  <HStack gap={2}>
@@ -453,7 +469,7 @@ function InvoiceCard() {
453
469
  <MetadataListItem label="Total">
454
470
  <HStack>
455
471
  <StackItem size="fill" />
456
- <Text type="body" weight="bold" hasTabularNumbers>
472
+ <Text type="body" weight="semibold" hasTabularNumbers>
457
473
  {fmt(TOTAL)}
458
474
  </Text>
459
475
  </HStack>
@@ -467,7 +483,7 @@ function InvoiceCard() {
467
483
  <HStack>
468
484
  <StackItem size="fill">
469
485
  <Text type="body" hasTabularNumbers>
470
- Visa ...7482
486
+ Visa …7482
471
487
  </Text>
472
488
  </StackItem>
473
489
  <Text type="body" hasTabularNumbers>
@@ -486,7 +502,11 @@ function TimelineSection() {
486
502
  return (
487
503
  <Section>
488
504
  <VStack gap={4}>
489
- <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">
490
510
  <StackItem size="fill">
491
511
  <Heading level={2}>Timeline</Heading>
492
512
  </StackItem>
@@ -498,73 +518,58 @@ function TimelineSection() {
498
518
  />
499
519
  </HStack>
500
520
 
501
- <VStack gap={4}>
502
- {ACTIVITY.map((item, i) => (
503
- <VStack key={i} gap={2}>
504
- <HStack gap={3} vAlign="start">
505
- <Avatar name={item.user} size="md" />
506
- <StackItem size="fill">
507
- <VStack gap={2}>
508
- <Card variant="muted" padding={3}>
509
- <VStack gap={1}>
510
- <Text type="body" weight="bold">
511
- {item.user}
512
- </Text>
513
- <Text type="body">{item.text}</Text>
514
- {item.changes && (
515
- <VStack gap={1}>
516
- {item.changes.map((change, j) => (
517
- <HStack key={j} gap={2} vAlign="center">
518
- <Icon
519
- icon={SquarePen}
520
- size="sm"
521
- color="secondary"
522
- />
523
- <Text type="supporting" color="secondary">
524
- {change}
525
- </Text>
526
- </HStack>
527
- ))}
528
- </VStack>
529
- )}
530
- </VStack>
531
- </Card>
532
- <HStack gap={3} vAlign="center">
533
- <HStack gap={1} vAlign="center">
534
- <Icon
535
- icon={ThumbsUp}
536
- size="xsm"
537
- color="secondary"
538
- />
539
- <Icon icon={Heart} size="xsm" color="secondary" />
540
- <Text
541
- type="supporting"
542
- color="secondary"
543
- hasTabularNumbers>
544
- {item.reactions}
545
- </Text>
546
- </HStack>
547
- <Text type="supporting" color="secondary">
548
- Like
549
- </Text>
550
- <Bullet />
551
- <Text type="supporting" color="secondary">
552
- Reply
553
- </Text>
554
- <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" />
555
545
  <Text
556
546
  type="supporting"
557
547
  color="secondary"
558
548
  hasTabularNumbers>
559
- {item.time}
549
+ {item.reactions}
560
550
  </Text>
561
551
  </HStack>
562
- </VStack>
563
- </StackItem>
564
- </HStack>
565
- </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
+ />
566
571
  ))}
567
- </VStack>
572
+ </List>
568
573
  </VStack>
569
574
  </Section>
570
575
  );
@@ -576,30 +581,30 @@ function TimelineSection() {
576
581
  function PanelContent() {
577
582
  return (
578
583
  <VStack gap={4}>
579
- <Collapsible trigger={<Heading level={4}>Notes</Heading>}>
584
+ <Collapsible trigger={<Heading level={3}>Notes</Heading>}>
580
585
  <Text type="body">
581
- Customer is a repeat buyer — 3rd order this quarter. Prefers
586
+ Customer is a repeat buyer, 3rd order this quarter. Prefers
582
587
  moonlight and sage glazes. Requested gift wrapping for the mug set.
583
588
  Ships to a residential address in CA.{' '}
584
- <Link href="#/templates/detail-page" color="secondary">
589
+ <Link href="#/templates/detail-page">
585
590
  Show more
586
591
  </Link>
587
592
  </Text>
588
593
  </Collapsible>
589
- <Collapsible trigger={<Heading level={4}>Customer</Heading>}>
594
+ <Collapsible trigger={<Heading level={3}>Customer</Heading>}>
590
595
  <MetadataList>
591
- <MetadataListItem label="Name">Jane Doe</MetadataListItem>
596
+ <MetadataListItem label="Name">Vlad Dracul</MetadataListItem>
592
597
  <MetadataListItem label="Address">
593
598
  321 Smith Road, CA 38238
594
599
  </MetadataListItem>
595
600
  <MetadataListItem label="Phone">234-555-0134</MetadataListItem>
596
- <MetadataListItem label="Email">janedoe@email.com</MetadataListItem>
601
+ <MetadataListItem label="Email">vlad@castle-dracula.transylvania</MetadataListItem>
597
602
  <MetadataListItem label="Billing Address">
598
603
  Same as shipping address
599
604
  </MetadataListItem>
600
605
  </MetadataList>
601
606
  </Collapsible>
602
- <Collapsible trigger={<Heading level={4}>Fraud Analysis</Heading>}>
607
+ <Collapsible trigger={<Heading level={3}>Fraud analysis</Heading>}>
603
608
  <VStack gap={1}>
604
609
  <ProgressBar
605
610
  label="Risk level"
@@ -677,6 +682,7 @@ export default function DetailPage() {
677
682
  isOpen={isNarrow && isPanelDialogOpen}
678
683
  onOpenChange={setPanelDialogOpen}>
679
684
  <Layout
685
+ height="auto"
680
686
  header={
681
687
  <DialogHeader
682
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
  };