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,91 +1,30 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ // XLE (canonical structure, validated with `bunx astryx layout check`):
3
+ // L > LC[p=6] > V[g=8] > ((V[g=2 a=center] > Hd"Every corner of the castle, caught after dark."[level=1] + Tx"Relics, sketches, and moonlit views from the coven archives, collected over one long Transylvanian night."[t=body]) + (V[g=3] > (V[g=2] > AR[ratio=3/1] + Tx"The castle at moonrise"[t=body]) + (G[c={min:280} g=4] > (V[g=2] > AR[ratio=3/2] + Tx"Coven gathering"[t=body]) + (V[g=2] > AR[ratio=3/2] + Tx"Belfry view"[t=body]) + (V[g=2] > AR[ratio=3/2] + Tx"Crypt archives"[t=body]) + (V[g=2] > AR[ratio=3/2] + Tx"Midnight garden"[t=body]))))
2
4
 
3
- import type {CSSProperties} from 'react';
4
5
  import {VStack, Layout, LayoutContent} from '@astryxdesign/core/Layout';
5
6
  import {Text, Heading} from '@astryxdesign/core/Text';
6
7
  import {AspectRatio} from '@astryxdesign/core/AspectRatio';
8
+ import {Grid} from '@astryxdesign/core/Grid';
9
+ import {galleryImageClip} from 'astryx-dracula/shared/gallery-image';
10
+ import {SceneTile} from 'astryx-dracula/shared/scene-tile';
11
+ import type {SceneHue} from 'astryx-dracula/shared/scene-hues';
7
12
 
8
13
  // ─── Styles ────────────────────────────────────────────────────────────────
9
- // The masonry needs a responsive column count AND a hero that spans 2 columns
10
- // on desktop but goes full-width on mobile. Grid forces grid-template-columns
11
- // inline, so a responsive span can't be expressed through its props — this is a
12
- // @container grid (the sanctioned Astryx pattern for container-responsive layout).
13
- // The container query lives in a plain <style> tag below so it needs NO CSS
14
- // compiler. Image fill + radius are custom because Astryx has no image
15
- // primitive (#2582).
16
-
17
- // Named inline-size container on the page column so the grid responds to the
18
- // available content width (works inside the sandbox's resizable preview).
19
- const containerStyle: CSSProperties = {
20
- containerType: 'inline-size',
21
- containerName: 'gallery',
22
- };
23
- // Fills the AspectRatio box with a Dracula placeholder scene. No Image
24
- // primitive in Astryx (#2582), so gallery tiles are inline SVG on brand
25
- // tokens instead of light-mode data-URI bitmaps.
26
- const svgStyle: CSSProperties = {
27
- width: '100%',
28
- height: '100%',
29
- display: 'block',
30
- };
31
- // Rounds the image corners. No radius prop on AspectRatio (#2582).
32
- const clipStyle: CSSProperties = {
33
- borderRadius: 'var(--radius-element)',
34
- };
35
-
36
- // 3 columns on desktop, dropping straight to 1 column below 720px (no 2-col
37
- // middle state). minmax(0, 1fr) (not 1fr) so tracks split evenly and ignore the
38
- // images' intrinsic min-width. The hero spans 2 columns on desktop, then fills
39
- // the row once it's single-column.
40
- const GALLERY_CSS = `
41
- .mixed-gallery-grid {
42
- display: grid;
43
- gap: var(--spacing-3);
44
- grid-template-columns: repeat(3, minmax(0, 1fr));
45
- }
46
- .mixed-gallery-hero {
47
- grid-column: span 2;
48
- }
49
- /* The hero image stretches to the row height instead of keeping its own
50
- ratio: a 3:1 hero spanning 2 columns + 1 gap is taller than the 3:2 sidebar
51
- by exactly gap/3, so ratio-driven heights can never align. The sidebar keeps
52
- its ratio (it defines the row height); the hero flex-fills the leftover cell
53
- height. flex-basis is 0px — not 0%: a percentage basis falls back to content
54
- size against the indefinite grid-row measurement, which would let the hero's
55
- own ratio define the row again. 0px contributes nothing, so the row follows
56
- the sidebar exactly (equal single-line captions keep the math exact), and
57
- the hero grows into it. AspectRatio's aspect-ratio yields once flex gives it
58
- a definite height; the svg slice-fills either way. */
59
- .mixed-gallery-hero > :first-child {
60
- flex: 1 1 0px;
61
- min-height: 0;
62
- }
63
- @container gallery (max-width: 720px) {
64
- .mixed-gallery-grid {
65
- grid-template-columns: minmax(0, 1fr);
66
- }
67
- .mixed-gallery-hero {
68
- grid-column: 1 / -1;
69
- }
70
- /* Single column: no sibling defines the row, so the hero falls back to its
71
- own 3:1 ratio. */
72
- .mixed-gallery-hero > :first-child {
73
- flex: none;
74
- }
75
- }
76
- `;
14
+ // Image fill + radius live in shared/gallery-image (no Image primitive in
15
+ // Astryx, #2582). Tile art lives in shared/scene-tile (large fork).
77
16
 
78
17
  // ─── Gallery Data ───────────────────────────────────────────────────────────
79
18
 
80
19
  interface GalleryImage {
81
20
  title: string;
82
- hue: string;
21
+ hue: SceneHue;
83
22
  }
84
23
 
85
24
  // One accent per tile from the fixed badge vocabulary; the SVG scenes below
86
25
  // resolve to Dracula tokens so tiles stay on-brand in the dark-only theme.
87
26
  const IMAGES: GalleryImage[] = [
88
- {title: 'The castle at moonrise', hue: 'var(--dracula-purple)'},
27
+ {title: 'The castle at moonrise', hue: 'var(--dracula-orange)'},
89
28
  {title: 'Coven gathering', hue: 'var(--dracula-cyan)'},
90
29
  {title: 'Belfry view', hue: 'var(--dracula-pink)'},
91
30
  {title: 'Crypt archives', hue: 'var(--dracula-yellow)'},
@@ -96,42 +35,15 @@ const IMAGES: GalleryImage[] = [
96
35
  // Each tile is an image plus its caption (titles lived only in aria-labels
97
36
  // before, leaving the tiles cryptic). AspectRatio gives every image a
98
37
  // definite, self-contained height from its ratio, so images can't overflow
99
- // their grid cell (no row-track guesswork). The hero image stretches to the
100
- // row height instead via GALLERY_CSS (see above).
38
+ // their grid cell and no tile depends on a neighbour's caption height.
101
39
 
102
- function GalleryCard({
103
- image,
104
- ratio,
105
- className,
106
- }: {
107
- image: GalleryImage;
108
- ratio: number;
109
- className?: string;
110
- }) {
40
+ function GalleryCard({image, ratio}: {image: GalleryImage; ratio: number}) {
111
41
  return (
112
- <VStack gap={2} className={className}>
113
- <AspectRatio ratio={ratio} style={clipStyle}>
114
- <svg
115
- viewBox="0 0 400 300"
116
- preserveAspectRatio="xMidYMid slice"
117
- style={svgStyle}
118
- role="img"
119
- aria-label={image.title}>
120
- <rect width="400" height="300" fill="var(--dracula-bg-light)" />
121
- <g
122
- transform="translate(200 150)"
123
- fill="none"
124
- stroke="var(--dracula-comment)"
125
- strokeWidth="5"
126
- strokeLinecap="round"
127
- strokeLinejoin="round">
128
- <rect x="-44" y="-44" width="88" height="88" rx="5" />
129
- <circle cx="18" cy="-18" r="2.5" fill={image.hue} stroke="none" />
130
- <path d="M-34 30 L-8 0 L10 18 L20 8 L34 24" />
131
- </g>
132
- </svg>
42
+ <VStack gap={2}>
43
+ <AspectRatio ratio={ratio} style={galleryImageClip}>
44
+ <SceneTile label={image.title} hue={image.hue} size="lg" />
133
45
  </AspectRatio>
134
- <Text type="supporting" justify="center">
46
+ <Text type="body" color="secondary" justify="center">
135
47
  {image.title}
136
48
  </Text>
137
49
  </VStack>
@@ -147,41 +59,30 @@ export default function MixedGallery() {
147
59
  contentWidth={1400}
148
60
  content={
149
61
  <LayoutContent padding={6}>
150
- <style>{GALLERY_CSS}</style>
151
- <VStack gap={6} style={containerStyle}>
62
+ <VStack gap={8}>
152
63
  {/* Header */}
153
64
  <VStack gap={2} hAlign="center">
154
65
  <Heading level={1} justify="center">
155
66
  Every corner of the castle, caught after dark.
156
67
  </Heading>
157
- <Text type="body" justify="center">
158
- Relics, sketches, and moonlit views from the coven archives —
68
+ <Text type="body" color="secondary" justify="center">
69
+ Relics, sketches, and moonlit views from the coven archives,
159
70
  collected over one long Transylvanian night.
160
71
  </Text>
161
72
  </VStack>
162
73
 
163
- {/* Featured layout — a wide hero next to a single tile, above a row
164
- of three. The sidebar's 3:2 image defines the top-row height and
165
- the hero stretches to it exactly (equal captions keep the math
166
- exact). The bottom row is three equal 3:2 tiles. Responsive via
167
- @container: 3 columns → 1 column at ≤720px, where the hero
168
- falls back to its 3:1 ratio. */}
169
- <div className="mixed-gallery-grid">
170
- {/* Hero — spans 2 columns and stretches to the sidebar's height */}
171
- <GalleryCard
172
- image={IMAGES[0]}
173
- ratio={3 / 1}
174
- className="mixed-gallery-hero"
175
- />
176
-
177
- {/* Sidebar — its ratio defines the row height */}
178
- <GalleryCard image={IMAGES[2]} ratio={3 / 2} />
179
-
180
- {/* Bottom row — three equal tiles */}
181
- <GalleryCard image={IMAGES[3]} ratio={3 / 2} />
182
- <GalleryCard image={IMAGES[4]} ratio={3 / 2} />
183
- <GalleryCard image={IMAGES[1]} ratio={3 / 2} />
184
- </div>
74
+ {/* Featured layout: the wide 3:1 hero heads the page, then the rest
75
+ of the set reflows as a grid (4 → 2 → 1 columns). Every tile
76
+ keeps its own ratio, so no tile's height depends on another's
77
+ caption wrapping. */}
78
+ <VStack gap={3}>
79
+ <GalleryCard image={IMAGES[0]} ratio={3 / 1} />
80
+ <Grid columns={{minWidth: 280}} gap={4}>
81
+ {IMAGES.slice(1).map(image => (
82
+ <GalleryCard key={image.title} image={image} ratio={3 / 2} />
83
+ ))}
84
+ </Grid>
85
+ </VStack>
185
86
  </VStack>
186
87
  </LayoutContent>
187
88
  }