astryx-dracula 0.5.0 → 0.6.2

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 (129) hide show
  1. package/BRAND.md +3 -3
  2. package/README.md +7 -4
  3. package/USAGE.md +49 -49
  4. package/astryx-dracula.d.ts +2 -2
  5. package/astryx-dracula.js +25 -9
  6. package/astryx-dracula.variants.d.ts +2 -2
  7. package/astryx.integration.mjs +1 -1
  8. package/icons.mjs +21 -17
  9. package/icons.tsx +69 -62
  10. package/package.json +125 -120
  11. package/shared/auth-chrome-config.ts +6 -6
  12. package/shared/auth-chrome.tsx +143 -144
  13. package/shared/auth-copy.ts +14 -14
  14. package/shared/chaptered-doc-config.ts +48 -51
  15. package/shared/chaptered-doc.tsx +267 -289
  16. package/shared/chart-hues.ts +25 -10
  17. package/shared/chart-labels.tsx +31 -30
  18. package/shared/chart-legend.tsx +55 -56
  19. package/shared/chart-panel-style.ts +3 -3
  20. package/shared/data-bar.tsx +97 -102
  21. package/shared/format-money.ts +1 -1
  22. package/shared/gallery-image.ts +6 -6
  23. package/shared/login-demo.ts +1 -1
  24. package/shared/metric-card.tsx +101 -105
  25. package/shared/metric-delta.tsx +28 -27
  26. package/shared/order-desk.tsx +205 -216
  27. package/shared/revenue-chart.tsx +145 -165
  28. package/shared/scene-castle.tsx +206 -291
  29. package/shared/scene-frame.tsx +33 -32
  30. package/shared/scene-hues.ts +17 -17
  31. package/shared/scene-tile.tsx +88 -92
  32. package/shared/settings-data.ts +119 -125
  33. package/shared/settings-rows.tsx +122 -159
  34. package/shared/sparkline.tsx +75 -88
  35. package/shared/sso-icons.tsx +10 -22
  36. package/shared/stars.tsx +16 -25
  37. package/templates/ai-chat-landing.template.mjs +5 -4
  38. package/templates/ai-chat-landing.tsx +473 -460
  39. package/templates/ai-chat.template.mjs +5 -4
  40. package/templates/ai-chat.tsx +543 -612
  41. package/templates/blank.template.mjs +5 -4
  42. package/templates/blank.tsx +18 -14
  43. package/templates/centered-hero.template.mjs +5 -4
  44. package/templates/centered-hero.tsx +55 -68
  45. package/templates/classic-gallery.template.mjs +5 -4
  46. package/templates/classic-gallery.tsx +97 -104
  47. package/templates/contact-form.template.mjs +5 -4
  48. package/templates/contact-form.tsx +247 -282
  49. package/templates/dashboard-portfolio.template.mjs +5 -4
  50. package/templates/dashboard-portfolio.tsx +717 -548
  51. package/templates/dashboard.template.mjs +5 -4
  52. package/templates/dashboard.tsx +596 -567
  53. package/templates/detail-page.template.mjs +5 -4
  54. package/templates/detail-page.tsx +546 -603
  55. package/templates/documentation-design.template.mjs +5 -4
  56. package/templates/documentation-design.tsx +231 -243
  57. package/templates/documentation-technical.template.mjs +5 -4
  58. package/templates/documentation-technical.tsx +236 -239
  59. package/templates/documentation.template.mjs +5 -4
  60. package/templates/documentation.tsx +267 -279
  61. package/templates/editor.template.mjs +5 -4
  62. package/templates/editor.tsx +844 -877
  63. package/templates/file-explorer.template.mjs +5 -4
  64. package/templates/file-explorer.tsx +566 -590
  65. package/templates/form-two-column.template.mjs +5 -4
  66. package/templates/form-two-column.tsx +195 -210
  67. package/templates/gallery-hero.template.mjs +5 -4
  68. package/templates/gallery-hero.tsx +93 -114
  69. package/templates/ide.template.mjs +5 -4
  70. package/templates/ide.tsx +407 -453
  71. package/templates/incident-console.template.mjs +5 -4
  72. package/templates/incident-console.tsx +593 -575
  73. package/templates/kanban-board.template.mjs +5 -4
  74. package/templates/kanban-board.tsx +665 -683
  75. package/templates/library.template.mjs +5 -4
  76. package/templates/library.tsx +409 -430
  77. package/templates/login-card.template.mjs +5 -4
  78. package/templates/login-card.tsx +63 -72
  79. package/templates/login-split.template.mjs +5 -4
  80. package/templates/login-split.tsx +192 -193
  81. package/templates/login-sso.template.mjs +5 -4
  82. package/templates/login-sso.tsx +257 -258
  83. package/templates/login.template.mjs +5 -4
  84. package/templates/login.tsx +53 -49
  85. package/templates/messaging-shell.template.mjs +5 -4
  86. package/templates/messaging-shell.tsx +556 -574
  87. package/templates/mixed-gallery.template.mjs +5 -4
  88. package/templates/mixed-gallery.tsx +60 -58
  89. package/templates/payment-form.template.mjs +5 -4
  90. package/templates/payment-form.tsx +882 -991
  91. package/templates/product-detail.template.mjs +5 -4
  92. package/templates/product-detail.tsx +261 -272
  93. package/templates/product-gallery.template.mjs +5 -4
  94. package/templates/product-gallery.tsx +126 -137
  95. package/templates/product-tour.template.mjs +5 -4
  96. package/templates/product-tour.tsx +741 -773
  97. package/templates/settings-dialog.template.mjs +5 -4
  98. package/templates/settings-dialog.tsx +688 -717
  99. package/templates/settings-sidebar.template.mjs +5 -4
  100. package/templates/settings-sidebar.tsx +762 -807
  101. package/templates/settings.template.mjs +5 -4
  102. package/templates/settings.tsx +289 -304
  103. package/templates/shell-nav.template.mjs +5 -4
  104. package/templates/shell-nav.tsx +212 -219
  105. package/templates/shell-side-nav.template.mjs +5 -4
  106. package/templates/shell-side-nav.tsx +135 -157
  107. package/templates/shell-top-nav.template.mjs +5 -4
  108. package/templates/shell-top-nav.tsx +182 -203
  109. package/templates/side-gallery.template.mjs +5 -4
  110. package/templates/side-gallery.tsx +85 -90
  111. package/templates/table-grouped.template.mjs +5 -4
  112. package/templates/table-grouped.tsx +1000 -1053
  113. package/templates/table-page-chart.template.mjs +5 -4
  114. package/templates/table-page-chart.tsx +400 -398
  115. package/templates/table-page-heatmap-status.template.mjs +5 -4
  116. package/templates/table-page-heatmap-status.tsx +483 -512
  117. package/templates/table-page-shoe-store-heatmap.template.mjs +5 -4
  118. package/templates/table-page-shoe-store-heatmap.tsx +748 -746
  119. package/templates/table-page.template.mjs +5 -4
  120. package/templates/table-page.tsx +396 -405
  121. package/templates/table.template.mjs +5 -4
  122. package/templates/table.tsx +92 -93
  123. package/templates/tech-report.template.mjs +5 -4
  124. package/templates/tech-report.tsx +1316 -1304
  125. package/templates/theme-showcase.template.mjs +5 -4
  126. package/templates/theme-showcase.tsx +871 -951
  127. package/theme.css +35 -77
  128. package/theme.css.d.ts +9 -0
  129. package/tokens.css +373 -380
@@ -4,66 +4,53 @@
4
4
  // the one shared chart-panel style until the theme pins a Card variant
5
5
  // (wave 2): import CHART_PANEL_STYLE rather than restating it.
6
6
 
7
- import type {CSSProperties} from 'react';
8
- import {CHART_PANEL_STYLE} from 'astryx-dracula/shared/chart-panel-style';
9
- import {CHART_HUES} from 'astryx-dracula/shared/chart-hues';
10
- import {VStack, HStack} from '@astryxdesign/core/Layout';
11
- import {Text} from '@astryxdesign/core/Text';
12
- import {Card} from '@astryxdesign/core/Card';
13
- import {Icon} from '@astryxdesign/core/Icon';
14
- import {Square} from 'lucide-react';
15
- import {ChartLabel, CHART_LABEL_SIZE} from 'astryx-dracula/shared/chart-labels';
16
- import type {SceneHue} from 'astryx-dracula/shared/scene-hues';
7
+ import { Card } from "@astryxdesign/core/Card";
8
+ import { Icon } from "@astryxdesign/core/Icon";
9
+ import { HStack, VStack } from "@astryxdesign/core/Layout";
10
+ import { Text } from "@astryxdesign/core/Text";
11
+ import { CHART_HUES } from "astryx-dracula/shared/chart-hues";
12
+ import { CHART_LABEL_SIZE, ChartLabel } from "astryx-dracula/shared/chart-labels";
13
+ import { CHART_PANEL_STYLE } from "astryx-dracula/shared/chart-panel-style";
14
+ import type { SceneHue } from "astryx-dracula/shared/scene-hues";
15
+ import { Square } from "lucide-react";
16
+ import type { CSSProperties } from "react";
17
17
 
18
18
  // ============= SHARED CHART-PANEL CARD STYLE =============
19
19
 
20
-
21
20
  // ============= PRODUCT SWATCH =============
22
21
 
23
- const swatchStyle: CSSProperties = {flexShrink: 0};
22
+ const swatchStyle: CSSProperties = { flexShrink: 0 };
24
23
 
25
24
  // Rounded product swatch: Dracula surface with a per-product accent glyph (one 36px size).
26
25
  // `accent` is an art treatment, so it takes the same `SceneHue` union as
27
26
  // `SceneTile.hue` — one art-treatment vocabulary, two consumers. A free-form
28
27
  // `string` here is what let `--dracula-purple` reach a product swatch.
29
- export function ProductSwatch({
30
- accent,
31
- label,
32
- }: {
33
- accent: SceneHue;
34
- label: string;
35
- }) {
36
- return (
37
- <svg
38
- viewBox="0 0 36 36"
39
- width={36}
40
- height={36}
41
- style={swatchStyle}
42
- role="img"
43
- aria-label={`${label} swatch`}>
44
- {/* A surface, not a data mark: the plate behind a product swatch wears the
28
+ export function ProductSwatch({ accent, label }: { accent: SceneHue; label: string }) {
29
+ return (
30
+ <svg
31
+ viewBox="0 0 36 36"
32
+ width={36}
33
+ height={36}
34
+ style={swatchStyle}
35
+ role="img"
36
+ aria-label={`${label} swatch`}
37
+ >
38
+ {/* A surface, not a data mark: the plate behind a product swatch wears the
45
39
  card tier. --color-background-card is byte-identical to the old
46
40
  --dracula-bg-light (#343746). */}
47
- <rect width={36} height={36} rx={5} fill="var(--color-background-card)" />
48
- <rect
49
- x={1}
50
- y={1}
51
- width={34}
52
- height={34}
53
- rx={4}
54
- fill="none"
55
- stroke="var(--color-widget-content-border)"
56
- />
57
- <circle
58
- cx={18}
59
- cy={18}
60
- r={7}
61
- fill="none"
62
- stroke={accent}
63
- strokeWidth={3}
64
- />
65
- </svg>
66
- );
41
+ <rect width={36} height={36} rx={5} fill="var(--color-background-card)" />
42
+ <rect
43
+ x={1}
44
+ y={1}
45
+ width={34}
46
+ height={34}
47
+ rx={4}
48
+ fill="none"
49
+ stroke="var(--color-widget-content-border)"
50
+ />
51
+ <circle cx={18} cy={18} r={7} fill="none" stroke={accent} strokeWidth={3} />
52
+ </svg>
53
+ );
67
54
  }
68
55
 
69
56
  // ============= REVENUE CHART =============
@@ -98,13 +85,13 @@ const CHART_LAST_TICK_X = CHART_W - CHART_PAD_RIGHT - 2;
98
85
  const CHART_TICK_PIN = CHART_PAD_LEFT + CHART_PLOT_W - CHART_LAST_TICK_X;
99
86
 
100
87
  interface RevenuePoint {
101
- date: string;
102
- revenue: number;
88
+ date: string;
89
+ revenue: number;
103
90
  }
104
91
 
105
92
  // Axis ticks switch to thousands once the scale leaves the hundreds.
106
93
  function formatRevenueTick(tick: number): string {
107
- return tick >= 1000 ? `$${tick / 1000}k` : `$${tick}`;
94
+ return tick >= 1000 ? `$${tick / 1000}k` : `$${tick}`;
108
95
  }
109
96
 
110
97
  // Which points get a date tick. A fixed stride cannot answer this: `i % 3`
@@ -115,123 +102,116 @@ function formatRevenueTick(tick: number): string {
115
102
  // crowded grid tick gives way instead, so the axis ends on a gap wider than
116
103
  // every other one rather than on the narrowest one.
117
104
  function xTickIndices(dates: string[]): number[] {
118
- const last = dates.length - 1;
119
- if (last < 1) return [last];
120
- const step = CHART_PLOT_W / last;
121
- const width = (i: number) => dates[i].length * CHART_TICK_ADVANCE;
122
- // Clear space between two ticks: `slots` apart, less the half-box each side
123
- // shows. The final tick is the exception — it shows its whole box to the left
124
- // of its anchor, so its pair is the one that has to clear the most.
125
- const gap = (a: number, b: number) =>
126
- (b - a) * step -
127
- (width(a) + width(b)) / 2 -
128
- (b === last ? CHART_TICK_PIN + width(b) / 2 : 0);
129
- const stride = Math.max(1, Math.ceil(last / (CHART_MAX_X_TICKS - 1)));
130
- // The grid, minus whatever the pinned final tick has crowded out. Every
131
- // step of `end` down leaves the grid spacing even and gives the last pair
132
- // one stride more room, so the first grid that clears is the one to keep.
133
- let ticks = [0, last];
134
- for (let end = Math.floor(last / stride) * stride; end >= 0; end -= stride) {
135
- const grid: number[] = [];
136
- for (let i = 0; i <= end; i += stride) grid.push(i);
137
- if (grid[grid.length - 1] !== last) grid.push(last);
138
- // Every pair, in order, so the last one can be held to the tightest of
139
- // the rest instead of to the average.
140
- const gaps = grid
141
- .slice(0, -1)
142
- .map((t, k) => gap(t, grid[k + 1]));
143
- const interior = gaps.slice(0, -1);
144
- if (interior.length === 0 || gaps[gaps.length - 1] >= Math.min(...interior)) {
145
- ticks = grid;
146
- break;
147
- }
148
- }
149
- return ticks;
105
+ const last = dates.length - 1;
106
+ if (last < 1) return [last];
107
+ const step = CHART_PLOT_W / last;
108
+ const width = (i: number) => dates[i].length * CHART_TICK_ADVANCE;
109
+ // Clear space between two ticks: `slots` apart, less the half-box each side
110
+ // shows. The final tick is the exception — it shows its whole box to the left
111
+ // of its anchor, so its pair is the one that has to clear the most.
112
+ const gap = (a: number, b: number) =>
113
+ (b - a) * step - (width(a) + width(b)) / 2 - (b === last ? CHART_TICK_PIN + width(b) / 2 : 0);
114
+ const stride = Math.max(1, Math.ceil(last / (CHART_MAX_X_TICKS - 1)));
115
+ // The grid, minus whatever the pinned final tick has crowded out. Every
116
+ // step of `end` down leaves the grid spacing even and gives the last pair
117
+ // one stride more room, so the first grid that clears is the one to keep.
118
+ let ticks = [0, last];
119
+ for (let end = Math.floor(last / stride) * stride; end >= 0; end -= stride) {
120
+ const grid: number[] = [];
121
+ for (let i = 0; i <= end; i += stride) grid.push(i);
122
+ if (grid[grid.length - 1] !== last) grid.push(last);
123
+ // Every pair, in order, so the last one can be held to the tightest of
124
+ // the rest instead of to the average.
125
+ const gaps = grid.slice(0, -1).map((t, k) => gap(t, grid[k + 1]));
126
+ const interior = gaps.slice(0, -1);
127
+ if (interior.length === 0 || gaps[gaps.length - 1] >= Math.min(...interior)) {
128
+ ticks = grid;
129
+ break;
130
+ }
131
+ }
132
+ return ticks;
150
133
  }
151
134
 
152
135
  export function RevenueChart({
153
- data,
154
- chartMax,
155
- gridTicks,
156
- ariaLabel = 'Daily revenue, January 1 to 15',
157
- caption = 'Daily revenue · Jan 1–15',
136
+ data,
137
+ chartMax,
138
+ gridTicks,
139
+ ariaLabel = "Daily revenue, January 1 to 15",
140
+ caption = "Daily revenue · Jan 1–15",
158
141
  }: {
159
- data: RevenuePoint[];
160
- chartMax: number;
161
- gridTicks: number[];
162
- ariaLabel?: string;
163
- caption?: string;
142
+ data: RevenuePoint[];
143
+ chartMax: number;
144
+ gridTicks: number[];
145
+ ariaLabel?: string;
146
+ caption?: string;
164
147
  }) {
165
- const plotH = CHART_BASELINE - CHART_PAD_TOP;
166
- const points = data.map((d, i) => ({
167
- ...d,
168
- x: CHART_PAD_LEFT + (i / (data.length - 1)) * CHART_PLOT_W,
169
- y: CHART_BASELINE - (d.revenue / chartMax) * plotH,
170
- }));
171
- const dateTicks = new Set(xTickIndices(data.map(d => d.date)));
172
- const linePath = points
173
- .map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`)
174
- .join(' ');
175
- const areaPath = `${linePath} L${points[points.length - 1].x.toFixed(1)},${CHART_BASELINE} L${points[0].x.toFixed(1)},${CHART_BASELINE} Z`;
176
- return (
177
- <VStack gap={3}>
178
- <Card padding={4} style={CHART_PANEL_STYLE}>
179
- <svg
180
- viewBox={`0 0 ${CHART_W} ${CHART_H}`}
181
- width="100%"
182
- role="img"
183
- aria-label={ariaLabel}>
184
- {gridTicks.map(tick => {
185
- const y = CHART_BASELINE - (tick / chartMax) * plotH;
186
- return (
187
- <g key={tick}>
188
- <line
189
- x1={CHART_PAD_LEFT}
190
- y1={y}
191
- x2={CHART_W - CHART_PAD_RIGHT}
192
- y2={y}
193
- stroke="var(--color-separator)"
194
- strokeDasharray={tick === 0 ? undefined : '3 3'}
195
- opacity={tick === 0 ? 1 : 0.5}
196
- />
197
- <ChartLabel x={CHART_PAD_LEFT - 6} y={y + 3} textAnchor="end">
198
- {formatRevenueTick(tick)}
199
- </ChartLabel>
200
- </g>
201
- );
202
- })}
203
- <path d={areaPath} fill={REVENUE_LINE} opacity={0.25} />
204
- <path
205
- d={linePath}
206
- fill="none"
207
- stroke={REVENUE_LINE}
208
- strokeWidth={2}
209
- strokeLinejoin="round"
210
- strokeLinecap="round"
211
- />
212
- {points.map(
213
- (p, i) =>
214
- dateTicks.has(i) && (
215
- <ChartLabel
216
- key={p.date}
217
- x={i === points.length - 1 ? CHART_LAST_TICK_X : p.x}
218
- y={CHART_H - 8}
219
- textAnchor={i === points.length - 1 ? 'end' : 'middle'}>
220
- {p.date}
221
- </ChartLabel>
222
- ),
223
- )}
224
- </svg>
225
- </Card>
226
- <Text type="supporting" color="secondary">
227
- {caption}
228
- </Text>
229
- <HStack gap={2} vAlign="center">
230
- <Icon icon={Square} size="xsm" style={{color: REVENUE_LINE}} />
231
- <Text type="supporting" color="secondary">
232
- Revenue
233
- </Text>
234
- </HStack>
235
- </VStack>
236
- );
148
+ const plotH = CHART_BASELINE - CHART_PAD_TOP;
149
+ const points = data.map((d, i) => ({
150
+ ...d,
151
+ x: CHART_PAD_LEFT + (i / (data.length - 1)) * CHART_PLOT_W,
152
+ y: CHART_BASELINE - (d.revenue / chartMax) * plotH,
153
+ }));
154
+ const dateTicks = new Set(xTickIndices(data.map((d) => d.date)));
155
+ const linePath = points
156
+ .map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`)
157
+ .join(" ");
158
+ const areaPath = `${linePath} L${points[points.length - 1].x.toFixed(1)},${CHART_BASELINE} L${points[0].x.toFixed(1)},${CHART_BASELINE} Z`;
159
+ return (
160
+ <VStack gap={3}>
161
+ <Card padding={4} style={CHART_PANEL_STYLE}>
162
+ <svg viewBox={`0 0 ${CHART_W} ${CHART_H}`} width="100%" role="img" aria-label={ariaLabel}>
163
+ {gridTicks.map((tick) => {
164
+ const y = CHART_BASELINE - (tick / chartMax) * plotH;
165
+ return (
166
+ <g key={tick}>
167
+ <line
168
+ x1={CHART_PAD_LEFT}
169
+ y1={y}
170
+ x2={CHART_W - CHART_PAD_RIGHT}
171
+ y2={y}
172
+ stroke="var(--color-separator)"
173
+ strokeDasharray={tick === 0 ? undefined : "3 3"}
174
+ opacity={tick === 0 ? 1 : 0.5}
175
+ />
176
+ <ChartLabel x={CHART_PAD_LEFT - 6} y={y + 3} textAnchor="end">
177
+ {formatRevenueTick(tick)}
178
+ </ChartLabel>
179
+ </g>
180
+ );
181
+ })}
182
+ <path d={areaPath} fill={REVENUE_LINE} opacity={0.25} />
183
+ <path
184
+ d={linePath}
185
+ fill="none"
186
+ stroke={REVENUE_LINE}
187
+ strokeWidth={2}
188
+ strokeLinejoin="round"
189
+ strokeLinecap="round"
190
+ />
191
+ {points.map(
192
+ (p, i) =>
193
+ dateTicks.has(i) && (
194
+ <ChartLabel
195
+ key={p.date}
196
+ x={i === points.length - 1 ? CHART_LAST_TICK_X : p.x}
197
+ y={CHART_H - 8}
198
+ textAnchor={i === points.length - 1 ? "end" : "middle"}
199
+ >
200
+ {p.date}
201
+ </ChartLabel>
202
+ ),
203
+ )}
204
+ </svg>
205
+ </Card>
206
+ <Text type="supporting" color="secondary">
207
+ {caption}
208
+ </Text>
209
+ <HStack gap={2} vAlign="center">
210
+ <Icon icon={Square} size="xsm" style={{ color: REVENUE_LINE }} />
211
+ <Text type="supporting" color="secondary">
212
+ Revenue
213
+ </Text>
214
+ </HStack>
215
+ </VStack>
216
+ );
237
217
  }