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.
- package/BRAND.md +30 -18
- package/README.md +22 -11
- package/USAGE.md +29 -10
- package/astryx-dracula.js +19 -13
- package/astryx-dracula.variants.d.ts +15 -0
- package/package.json +59 -17
- package/shared/auth-chrome-config.ts +18 -0
- package/shared/auth-chrome.tsx +25 -0
- package/shared/auth-copy.ts +22 -0
- package/shared/chaptered-doc-config.ts +92 -0
- package/shared/chaptered-doc.tsx +332 -0
- package/shared/chart-hues.ts +27 -0
- package/shared/chart-labels.tsx +44 -0
- package/shared/chart-legend.tsx +100 -0
- package/shared/chart-panel-style.ts +13 -0
- package/shared/data-bar.tsx +160 -0
- package/shared/gallery-image.ts +20 -0
- package/shared/login-demo.ts +7 -0
- package/shared/metric-delta.tsx +36 -0
- package/shared/order-desk.tsx +273 -0
- package/shared/revenue-chart.tsx +174 -0
- package/shared/scene-castle.tsx +322 -0
- package/shared/scene-frame.tsx +88 -0
- package/shared/scene-hues.ts +49 -0
- package/shared/scene-tile.tsx +128 -0
- package/shared/settings-data.ts +125 -0
- package/shared/settings-rows.tsx +179 -0
- package/shared/sparkline.tsx +94 -0
- package/shared/sso-icons.tsx +30 -0
- package/templates/ai-chat-landing.tsx +67 -32
- package/templates/ai-chat.tsx +41 -20
- package/templates/blank.tsx +5 -2
- package/templates/centered-hero.tsx +15 -124
- package/templates/classic-gallery.tsx +21 -65
- package/templates/contact-form.tsx +62 -40
- package/templates/dashboard-portfolio.tsx +146 -227
- package/templates/dashboard.tsx +123 -121
- package/templates/detail-page.tsx +101 -95
- package/templates/documentation-design.template.mjs +1 -1
- package/templates/documentation-design.tsx +85 -96
- package/templates/documentation-technical.template.mjs +1 -1
- package/templates/documentation-technical.tsx +33 -21
- package/templates/documentation.template.mjs +1 -1
- package/templates/documentation.tsx +54 -74
- package/templates/editor.tsx +119 -89
- package/templates/file-explorer.tsx +133 -84
- package/templates/form-two-column.tsx +62 -124
- package/templates/gallery-hero.tsx +17 -171
- package/templates/ide.tsx +27 -21
- package/templates/incident-console.tsx +105 -69
- package/templates/kanban-board.tsx +100 -41
- package/templates/library.template.mjs +2 -2
- package/templates/library.tsx +38 -41
- package/templates/login-card.tsx +59 -86
- package/templates/login-split.tsx +88 -128
- package/templates/login-sso.tsx +107 -68
- package/templates/login.tsx +108 -52
- package/templates/messaging-shell.tsx +172 -143
- package/templates/mixed-gallery.tsx +31 -130
- package/templates/payment-form.tsx +369 -289
- package/templates/product-detail.tsx +40 -57
- package/templates/product-gallery.tsx +31 -40
- package/templates/product-tour.template.mjs +6 -0
- package/templates/product-tour.tsx +916 -0
- package/templates/settings-dialog.tsx +145 -286
- package/templates/settings-sidebar.tsx +179 -267
- package/templates/settings.tsx +42 -13
- package/templates/shell-nav.tsx +32 -23
- package/templates/shell-side-nav.tsx +30 -19
- package/templates/shell-top-nav.tsx +81 -43
- package/templates/side-gallery.tsx +39 -93
- package/templates/table-grouped.tsx +63 -33
- package/templates/table-page-chart.tsx +24 -297
- package/templates/table-page-heatmap-status.tsx +157 -91
- package/templates/table-page-shoe-store-heatmap.tsx +19 -288
- package/templates/table-page.tsx +24 -6
- package/templates/table.tsx +24 -7
- package/templates/tech-report.template.mjs +6 -0
- package/templates/tech-report.tsx +1486 -0
- package/templates/theme-showcase.template.mjs +1 -1
- package/templates/theme-showcase.tsx +313 -249
- package/theme.css +76 -14
- package/tokens.css +425 -30
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
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)
|
|
2
4
|
|
|
3
|
-
|
|
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';
|
|
4
16
|
import {Heading, Text} from '@astryxdesign/core/Text';
|
|
5
17
|
import {Button} from '@astryxdesign/core/Button';
|
|
6
|
-
import {IconButton} from '@astryxdesign/core/IconButton';
|
|
7
18
|
import {Card} from '@astryxdesign/core/Card';
|
|
8
19
|
import {Avatar} from '@astryxdesign/core/Avatar';
|
|
9
20
|
import {Badge} from '@astryxdesign/core/Badge';
|
|
@@ -12,7 +23,7 @@ import {Banner} from '@astryxdesign/core/Banner';
|
|
|
12
23
|
import {CodeBlock} from '@astryxdesign/core/CodeBlock';
|
|
13
24
|
import {TabList, Tab} from '@astryxdesign/core/TabList';
|
|
14
25
|
import {Selector} from '@astryxdesign/core/Selector';
|
|
15
|
-
import {HStack, VStack
|
|
26
|
+
import {HStack, VStack} from '@astryxdesign/core/Stack';
|
|
16
27
|
import {Layout, LayoutContent, LayoutPanel} from '@astryxdesign/core/Layout';
|
|
17
28
|
import {useMediaQuery} from '@astryxdesign/core/hooks';
|
|
18
29
|
import {Dialog, DialogHeader} from '@astryxdesign/core/Dialog';
|
|
@@ -23,14 +34,12 @@ import {Icon} from '@astryxdesign/core/Icon';
|
|
|
23
34
|
import {Section} from '@astryxdesign/core/Section';
|
|
24
35
|
import {Center} from '@astryxdesign/core/Center';
|
|
25
36
|
import {Outline, type OutlineItem} from '@astryxdesign/core/Outline';
|
|
26
|
-
import {
|
|
37
|
+
import {Plus} from 'lucide-react';
|
|
38
|
+
import {outlinePanel} from 'astryx-dracula/shared/chaptered-doc-config';
|
|
27
39
|
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
top: 24,
|
|
32
|
-
alignSelf: 'start',
|
|
33
|
-
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)',
|
|
34
43
|
};
|
|
35
44
|
|
|
36
45
|
const COMPONENT_OUTLINE_ITEMS: OutlineItem[] = [
|
|
@@ -52,7 +61,9 @@ function DialogPreview() {
|
|
|
52
61
|
const [isOpen, setIsOpen] = useState(false);
|
|
53
62
|
return (
|
|
54
63
|
<VStack gap={3}>
|
|
55
|
-
<
|
|
64
|
+
<Text type="body" weight="semibold">
|
|
65
|
+
Dialog
|
|
66
|
+
</Text>
|
|
56
67
|
<Button
|
|
57
68
|
label="Open Dialog"
|
|
58
69
|
variant="primary"
|
|
@@ -439,7 +450,7 @@ const COMPONENT_DOCS: Record<
|
|
|
439
450
|
title: 'Default button with badge',
|
|
440
451
|
description:
|
|
441
452
|
'Buttons can include a badge to highlight new or updated actions.',
|
|
442
|
-
code: `<Button\n label="Button"\n variant="
|
|
453
|
+
code: `<Button\n label="Button"\n variant="secondary"\n/>`,
|
|
443
454
|
},
|
|
444
455
|
],
|
|
445
456
|
},
|
|
@@ -494,6 +505,57 @@ function getComponentDocs(key: string) {
|
|
|
494
505
|
};
|
|
495
506
|
}
|
|
496
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
|
+
|
|
497
559
|
// ---------------------------------------------------------------------------
|
|
498
560
|
// ComponentDetailView
|
|
499
561
|
// ---------------------------------------------------------------------------
|
|
@@ -514,55 +576,6 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
514
576
|
}
|
|
515
577
|
}, []);
|
|
516
578
|
|
|
517
|
-
const EXAMPLE_PREVIEWS: Record<string, React.ReactNode[]> = {
|
|
518
|
-
button: [
|
|
519
|
-
<HStack key="semantics" gap={3} vAlign="center" wrap="wrap">
|
|
520
|
-
<Button label="Flat" variant="ghost" />
|
|
521
|
-
<Button label="Default" variant="secondary" />
|
|
522
|
-
<Button label="Primary" variant="primary" />
|
|
523
|
-
<Button label="Destructive" variant="destructive" />
|
|
524
|
-
</HStack>,
|
|
525
|
-
<Button key="badge" label="Button" variant="secondary" />,
|
|
526
|
-
],
|
|
527
|
-
};
|
|
528
|
-
|
|
529
|
-
const COMPONENT_PREVIEWS: Record<string, React.ReactNode> = {
|
|
530
|
-
button: (
|
|
531
|
-
<Button
|
|
532
|
-
label="Button"
|
|
533
|
-
variant="secondary"
|
|
534
|
-
icon={<Icon icon={Plus} />}
|
|
535
|
-
endContent={<Badge label="New" variant="info" />}
|
|
536
|
-
/>
|
|
537
|
-
),
|
|
538
|
-
avatar: <Avatar name="Vlad" size="lg" />,
|
|
539
|
-
badge: <Badge label="Success" variant="success" />,
|
|
540
|
-
card: (
|
|
541
|
-
<Card>
|
|
542
|
-
<VStack gap={2}>
|
|
543
|
-
<Heading level={4}>Castle Card</Heading>
|
|
544
|
-
<Text type="body" color="secondary">
|
|
545
|
-
Cards group related content and actions.
|
|
546
|
-
</Text>
|
|
547
|
-
</VStack>
|
|
548
|
-
</Card>
|
|
549
|
-
),
|
|
550
|
-
banner: (
|
|
551
|
-
<Banner status="info" title="Information">
|
|
552
|
-
<Text type="body">This is an informational banner message.</Text>
|
|
553
|
-
</Banner>
|
|
554
|
-
),
|
|
555
|
-
dialog: <DialogPreview />,
|
|
556
|
-
text: <Text type="body">Body text</Text>,
|
|
557
|
-
divider: <Divider />,
|
|
558
|
-
token: <Token label="Dracula" />,
|
|
559
|
-
tooltip: (
|
|
560
|
-
<Tooltip content="Primary action">
|
|
561
|
-
<Button label="Hover me" variant="primary" />
|
|
562
|
-
</Tooltip>
|
|
563
|
-
),
|
|
564
|
-
};
|
|
565
|
-
|
|
566
579
|
const docs = useMemo(() => getComponentDocs(activeNav), [activeNav]);
|
|
567
580
|
const previews = EXAMPLE_PREVIEWS[activeNav] ?? [];
|
|
568
581
|
|
|
@@ -588,7 +601,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
588
601
|
<LayoutContent isScrollable={false} padding={8}>
|
|
589
602
|
<VStack gap={8}>
|
|
590
603
|
<VStack gap={2}>
|
|
591
|
-
<
|
|
604
|
+
<Heading level={1} type="display-2">{getComponentName(activeNav)}</Heading>
|
|
592
605
|
<Text type="supporting" color="secondary" hasTabularNumbers>
|
|
593
606
|
March 30, 2026 · Updated 5:40 p.m. PST
|
|
594
607
|
</Text>
|
|
@@ -608,7 +621,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
608
621
|
<Center height={360}>
|
|
609
622
|
{COMPONENT_PREVIEWS[activeNav] ?? (
|
|
610
623
|
<Text type="supporting" color="secondary">
|
|
611
|
-
|
|
624
|
+
Quiet in the crypt — no preview haunts this shelf yet.
|
|
612
625
|
</Text>
|
|
613
626
|
)}
|
|
614
627
|
</Center>
|
|
@@ -618,15 +631,14 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
618
631
|
<Heading id="usage" level={2}>
|
|
619
632
|
Usage
|
|
620
633
|
</Heading>
|
|
621
|
-
<Text type="
|
|
622
|
-
{docs.usage}
|
|
623
|
-
</Text>
|
|
634
|
+
<Text type="body">{docs.usage}</Text>
|
|
624
635
|
<Heading id="best-practices" level={3}>
|
|
625
636
|
Best practices
|
|
626
637
|
</Heading>
|
|
627
638
|
<Table
|
|
628
639
|
data={docs.bestPractices as Record<string, unknown>[]}
|
|
629
640
|
dividers="none"
|
|
641
|
+
hasHover
|
|
630
642
|
columns={[
|
|
631
643
|
{
|
|
632
644
|
key: 'type',
|
|
@@ -635,7 +647,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
635
647
|
renderCell: (item: Record<string, unknown>) => (
|
|
636
648
|
<Badge
|
|
637
649
|
label={item.type === 'do' ? 'Do' : "Don't"}
|
|
638
|
-
variant={item.type === 'do' ? '
|
|
650
|
+
variant={item.type === 'do' ? 'green' : 'red'}
|
|
639
651
|
/>
|
|
640
652
|
),
|
|
641
653
|
},
|
|
@@ -659,7 +671,7 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
659
671
|
<Heading id="examples" level={2}>
|
|
660
672
|
Examples
|
|
661
673
|
</Heading>
|
|
662
|
-
<Text type="
|
|
674
|
+
<Text type="body">
|
|
663
675
|
Explore common configurations, variations, and states for this
|
|
664
676
|
component.
|
|
665
677
|
</Text>
|
|
@@ -669,39 +681,16 @@ function ComponentDetailView({activeNav}: {activeNav: string}) {
|
|
|
669
681
|
const tabKey = `${activeNav}-${i}`;
|
|
670
682
|
const activeTab = exampleTabs[tabKey] ?? 'description';
|
|
671
683
|
return (
|
|
672
|
-
<Card key={
|
|
684
|
+
<Card key={example.title} padding={0}>
|
|
673
685
|
<Section padding={3} variant="transparent">
|
|
674
|
-
<
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
{example.title}
|
|
678
|
-
</Text>
|
|
679
|
-
</StackItem>
|
|
680
|
-
<HStack gap={1} vAlign="center" wrap="wrap">
|
|
681
|
-
<Button
|
|
682
|
-
label="Open in Craft"
|
|
683
|
-
variant="ghost"
|
|
684
|
-
size="sm"
|
|
685
|
-
icon={<Icon icon={ExternalLink} />}
|
|
686
|
-
/>
|
|
687
|
-
<Button
|
|
688
|
-
label="Send to CLI"
|
|
689
|
-
variant="ghost"
|
|
690
|
-
size="sm"
|
|
691
|
-
/>
|
|
692
|
-
<IconButton
|
|
693
|
-
label="Fullscreen"
|
|
694
|
-
variant="ghost"
|
|
695
|
-
size="sm"
|
|
696
|
-
icon={<Icon icon={Expand} />}
|
|
697
|
-
/>
|
|
698
|
-
</HStack>
|
|
699
|
-
</HStack>
|
|
686
|
+
<Text type="body" weight="semibold">
|
|
687
|
+
{example.title}
|
|
688
|
+
</Text>
|
|
700
689
|
</Section>
|
|
701
690
|
<Center height={280}>
|
|
702
691
|
{previews[i] ?? (
|
|
703
692
|
<Text type="supporting" color="secondary">
|
|
704
|
-
|
|
693
|
+
Quiet in the crypt — no preview haunts this shelf yet.
|
|
705
694
|
</Text>
|
|
706
695
|
)}
|
|
707
696
|
</Center>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
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)
|
|
2
4
|
|
|
3
|
-
import {useCallback, useState
|
|
5
|
+
import {useCallback, useState} from 'react';
|
|
4
6
|
import {Heading, Text} from '@astryxdesign/core/Text';
|
|
5
7
|
import {Button} from '@astryxdesign/core/Button';
|
|
6
8
|
import {Card} from '@astryxdesign/core/Card';
|
|
@@ -15,11 +17,31 @@ import {Icon} from '@astryxdesign/core/Icon';
|
|
|
15
17
|
import {Outline, type OutlineItem} from '@astryxdesign/core/Outline';
|
|
16
18
|
import {useMediaQuery} from '@astryxdesign/core/hooks';
|
|
17
19
|
import {Sparkles, ClipboardCopy, ChevronDown} from 'lucide-react';
|
|
20
|
+
import {outlinePanel} from 'astryx-dracula/shared/chaptered-doc-config';
|
|
18
21
|
|
|
19
22
|
// ---------------------------------------------------------------------------
|
|
20
23
|
// Main component
|
|
21
24
|
// ---------------------------------------------------------------------------
|
|
22
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
|
+
|
|
23
45
|
const OUTLINE_ITEMS: OutlineItem[] = [
|
|
24
46
|
{id: 'prerequisites', label: 'Prerequisites', level: 2},
|
|
25
47
|
{id: 'install-package', label: 'Install the package', level: 2},
|
|
@@ -32,13 +54,6 @@ const OUTLINE_OPTIONS = OUTLINE_ITEMS.map(item => ({
|
|
|
32
54
|
label: item.label,
|
|
33
55
|
}));
|
|
34
56
|
|
|
35
|
-
const outlinePanel: CSSProperties = {
|
|
36
|
-
position: 'sticky',
|
|
37
|
-
top: 24,
|
|
38
|
-
alignSelf: 'start',
|
|
39
|
-
paddingBlockStart: 120,
|
|
40
|
-
};
|
|
41
|
-
|
|
42
57
|
export default function DocumentationTechnical() {
|
|
43
58
|
const [activeId, setActiveId] = useState<string | undefined>(
|
|
44
59
|
OUTLINE_ITEMS[0]?.id,
|
|
@@ -73,7 +88,7 @@ export default function DocumentationTechnical() {
|
|
|
73
88
|
<LayoutContent isScrollable={false} padding={8}>
|
|
74
89
|
<VStack gap={8}>
|
|
75
90
|
<VStack gap={2}>
|
|
76
|
-
<
|
|
91
|
+
<Heading level={1}>Getting started with Astryx Dracula</Heading>
|
|
77
92
|
<Text type="supporting" color="secondary" hasTabularNumbers>
|
|
78
93
|
Last updated March 30, 2026
|
|
79
94
|
</Text>
|
|
@@ -106,9 +121,7 @@ export default function DocumentationTechnical() {
|
|
|
106
121
|
size="sm"
|
|
107
122
|
icon={<Icon icon={ClipboardCopy} />}
|
|
108
123
|
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
|
-
);
|
|
124
|
+
void navigator.clipboard.writeText(SETUP_PROMPT);
|
|
112
125
|
}}
|
|
113
126
|
/>
|
|
114
127
|
<DropdownMenu
|
|
@@ -119,12 +132,7 @@ export default function DocumentationTechnical() {
|
|
|
119
132
|
isIconOnly: true,
|
|
120
133
|
icon: <Icon icon={ChevronDown} />,
|
|
121
134
|
}}
|
|
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
|
-
]}
|
|
135
|
+
items={PROMPT_TARGETS}
|
|
128
136
|
/>
|
|
129
137
|
</HStack>
|
|
130
138
|
<Text type="body" color="secondary">
|
|
@@ -165,17 +173,18 @@ export default function DocumentationTechnical() {
|
|
|
165
173
|
gives you access to all components, tokens, and utilities.
|
|
166
174
|
</Text>
|
|
167
175
|
<VStack gap={2}>
|
|
168
|
-
<Text type="body" weight="
|
|
176
|
+
<Text type="body" weight="semibold">
|
|
169
177
|
Step 1: Install the core package
|
|
170
178
|
</Text>
|
|
171
179
|
<CodeBlock
|
|
172
180
|
code="npm install @astryxdesign/core"
|
|
173
181
|
language="bash"
|
|
174
182
|
width="100%"
|
|
183
|
+
hasCopyButton
|
|
175
184
|
/>
|
|
176
185
|
</VStack>
|
|
177
186
|
<VStack gap={2}>
|
|
178
|
-
<Text type="body" weight="
|
|
187
|
+
<Text type="body" weight="semibold">
|
|
179
188
|
Step 2: Import the precompiled styles
|
|
180
189
|
</Text>
|
|
181
190
|
<Text type="body" color="secondary">
|
|
@@ -188,10 +197,11 @@ export default function DocumentationTechnical() {
|
|
|
188
197
|
import '@astryxdesign/core/astryx.css';`}
|
|
189
198
|
language="tsx"
|
|
190
199
|
width="100%"
|
|
200
|
+
hasCopyButton
|
|
191
201
|
/>
|
|
192
202
|
</VStack>
|
|
193
203
|
<VStack gap={2}>
|
|
194
|
-
<Text type="body" weight="
|
|
204
|
+
<Text type="body" weight="semibold">
|
|
195
205
|
Step 3: Import your first component
|
|
196
206
|
</Text>
|
|
197
207
|
<CodeBlock
|
|
@@ -202,6 +212,7 @@ export default function App() {
|
|
|
202
212
|
}`}
|
|
203
213
|
language="tsx"
|
|
204
214
|
width="100%"
|
|
215
|
+
hasCopyButton
|
|
205
216
|
/>
|
|
206
217
|
</VStack>
|
|
207
218
|
</VStack>
|
|
@@ -229,6 +240,7 @@ export default function App({ children }) {
|
|
|
229
240
|
}`}
|
|
230
241
|
language="tsx"
|
|
231
242
|
width="100%"
|
|
243
|
+
hasCopyButton
|
|
232
244
|
/>
|
|
233
245
|
<Text type="body" color="secondary">
|
|
234
246
|
See the theming guide for the full list of customizable tokens.
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
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
|
+
*/
|
|
2
12
|
|
|
3
13
|
import type {CSSProperties} from 'react';
|
|
4
14
|
import {Heading, Text} from '@astryxdesign/core/Text';
|
|
@@ -8,25 +18,25 @@ import {ClickableCard} from '@astryxdesign/core/ClickableCard';
|
|
|
8
18
|
import {HStack, VStack, StackItem} from '@astryxdesign/core/Stack';
|
|
9
19
|
import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
10
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';
|
|
11
24
|
|
|
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
25
|
// Negative margin offsets each card's 8px padding so the grid content stays
|
|
22
26
|
// visually aligned while giving every card a padded hover/click target.
|
|
23
27
|
const cardGrid: CSSProperties = {
|
|
24
|
-
margin: -
|
|
28
|
+
margin: 'calc(var(--spacing-2) * -1)',
|
|
25
29
|
};
|
|
26
30
|
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
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)',
|
|
30
40
|
Layout: 'var(--dracula-cyan)',
|
|
31
41
|
Navigation: 'var(--dracula-green)',
|
|
32
42
|
Form: 'var(--dracula-yellow)',
|
|
@@ -214,50 +224,16 @@ const COMPONENT_CATEGORIES = [
|
|
|
214
224
|
},
|
|
215
225
|
];
|
|
216
226
|
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
}
|
|
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
|
+
);
|
|
261
237
|
|
|
262
238
|
// ---------------------------------------------------------------------------
|
|
263
239
|
// Main component
|
|
@@ -271,26 +247,26 @@ export default function DocumentationCatalog() {
|
|
|
271
247
|
content={
|
|
272
248
|
<LayoutContent padding={8}>
|
|
273
249
|
<VStack gap={10}>
|
|
274
|
-
<Card variant="
|
|
250
|
+
<Card variant="transparent" padding={10}>
|
|
275
251
|
<HStack gap={8} vAlign="center">
|
|
276
252
|
<StackItem size="fill">
|
|
277
253
|
<VStack gap={4}>
|
|
278
|
-
<
|
|
254
|
+
<Heading level={1} type="display-1">
|
|
255
|
+
The coven grimoire
|
|
256
|
+
</Heading>
|
|
279
257
|
<Text type="large" weight="normal" color="secondary">
|
|
280
|
-
Every incantation in the Astryx spellbook
|
|
281
|
-
components for building beautiful,
|
|
282
|
-
after dark.
|
|
258
|
+
Every incantation in the Astryx spellbook, with{' '}
|
|
259
|
+
{COMPONENT_TOTAL} components for building beautiful,
|
|
260
|
+
accessible products after dark.
|
|
283
261
|
</Text>
|
|
284
262
|
<HStack>
|
|
285
263
|
<Button
|
|
286
264
|
label="Enter the grimoire"
|
|
287
265
|
variant="primary"
|
|
288
|
-
size="lg"
|
|
289
266
|
/>
|
|
290
267
|
</HStack>
|
|
291
268
|
</VStack>
|
|
292
269
|
</StackItem>
|
|
293
|
-
<StackItem size="fill" />
|
|
294
270
|
</HStack>
|
|
295
271
|
</Card>
|
|
296
272
|
|
|
@@ -299,34 +275,38 @@ export default function DocumentationCatalog() {
|
|
|
299
275
|
<HStack justify="between" vAlign="center">
|
|
300
276
|
<Heading level={2}>{category.label}</Heading>
|
|
301
277
|
<Text
|
|
302
|
-
type="
|
|
278
|
+
type="body"
|
|
303
279
|
color="secondary"
|
|
304
280
|
hasTabularNumbers>
|
|
305
281
|
{category.items.length}{' '}
|
|
306
282
|
{category.items.length === 1 ? 'spell' : 'spells'}
|
|
307
283
|
</Text>
|
|
308
284
|
</HStack>
|
|
309
|
-
<Grid columns={{minWidth: 260}} gap={
|
|
285
|
+
<Grid columns={{minWidth: 260}} gap={4} style={cardGrid}>
|
|
310
286
|
{category.items.map(item => (
|
|
311
287
|
<ClickableCard
|
|
312
288
|
key={item.key}
|
|
313
289
|
label={`Open ${item.name}`}
|
|
314
|
-
|
|
290
|
+
href={SELF_HASH}
|
|
315
291
|
variant="transparent"
|
|
316
|
-
padding={
|
|
292
|
+
padding={4}>
|
|
317
293
|
<VStack gap={3}>
|
|
318
294
|
<Card
|
|
319
295
|
variant="muted"
|
|
320
296
|
padding={0}
|
|
321
297
|
minHeight={160}
|
|
322
|
-
style={
|
|
323
|
-
<
|
|
324
|
-
|
|
325
|
-
|
|
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"
|
|
326
306
|
/>
|
|
327
307
|
</Card>
|
|
328
|
-
<VStack gap={
|
|
329
|
-
<Text type="body" weight="
|
|
308
|
+
<VStack gap={1}>
|
|
309
|
+
<Text type="body" weight="semibold">
|
|
330
310
|
{item.name}
|
|
331
311
|
</Text>
|
|
332
312
|
<Text type="body" color="secondary" maxLines={3}>
|