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.
- package/BRAND.md +3 -3
- package/README.md +7 -4
- package/USAGE.md +49 -49
- package/astryx-dracula.d.ts +2 -2
- package/astryx-dracula.js +25 -9
- package/astryx-dracula.variants.d.ts +2 -2
- package/astryx.integration.mjs +1 -1
- package/icons.mjs +21 -17
- package/icons.tsx +69 -62
- package/package.json +125 -120
- package/shared/auth-chrome-config.ts +6 -6
- package/shared/auth-chrome.tsx +143 -144
- package/shared/auth-copy.ts +14 -14
- package/shared/chaptered-doc-config.ts +48 -51
- package/shared/chaptered-doc.tsx +267 -289
- package/shared/chart-hues.ts +25 -10
- package/shared/chart-labels.tsx +31 -30
- package/shared/chart-legend.tsx +55 -56
- package/shared/chart-panel-style.ts +3 -3
- package/shared/data-bar.tsx +97 -102
- package/shared/format-money.ts +1 -1
- package/shared/gallery-image.ts +6 -6
- package/shared/login-demo.ts +1 -1
- package/shared/metric-card.tsx +101 -105
- package/shared/metric-delta.tsx +28 -27
- package/shared/order-desk.tsx +205 -216
- package/shared/revenue-chart.tsx +145 -165
- package/shared/scene-castle.tsx +206 -291
- package/shared/scene-frame.tsx +33 -32
- package/shared/scene-hues.ts +17 -17
- package/shared/scene-tile.tsx +88 -92
- package/shared/settings-data.ts +119 -125
- package/shared/settings-rows.tsx +122 -159
- package/shared/sparkline.tsx +75 -88
- package/shared/sso-icons.tsx +10 -22
- package/shared/stars.tsx +16 -25
- package/templates/ai-chat-landing.template.mjs +5 -4
- package/templates/ai-chat-landing.tsx +473 -460
- package/templates/ai-chat.template.mjs +5 -4
- package/templates/ai-chat.tsx +543 -612
- package/templates/blank.template.mjs +5 -4
- package/templates/blank.tsx +18 -14
- package/templates/centered-hero.template.mjs +5 -4
- package/templates/centered-hero.tsx +55 -68
- package/templates/classic-gallery.template.mjs +5 -4
- package/templates/classic-gallery.tsx +97 -104
- package/templates/contact-form.template.mjs +5 -4
- package/templates/contact-form.tsx +247 -282
- package/templates/dashboard-portfolio.template.mjs +5 -4
- package/templates/dashboard-portfolio.tsx +717 -548
- package/templates/dashboard.template.mjs +5 -4
- package/templates/dashboard.tsx +596 -567
- package/templates/detail-page.template.mjs +5 -4
- package/templates/detail-page.tsx +546 -603
- package/templates/documentation-design.template.mjs +5 -4
- package/templates/documentation-design.tsx +231 -243
- package/templates/documentation-technical.template.mjs +5 -4
- package/templates/documentation-technical.tsx +236 -239
- package/templates/documentation.template.mjs +5 -4
- package/templates/documentation.tsx +267 -279
- package/templates/editor.template.mjs +5 -4
- package/templates/editor.tsx +844 -877
- package/templates/file-explorer.template.mjs +5 -4
- package/templates/file-explorer.tsx +566 -590
- package/templates/form-two-column.template.mjs +5 -4
- package/templates/form-two-column.tsx +195 -210
- package/templates/gallery-hero.template.mjs +5 -4
- package/templates/gallery-hero.tsx +93 -114
- package/templates/ide.template.mjs +5 -4
- package/templates/ide.tsx +407 -453
- package/templates/incident-console.template.mjs +5 -4
- package/templates/incident-console.tsx +593 -575
- package/templates/kanban-board.template.mjs +5 -4
- package/templates/kanban-board.tsx +665 -683
- package/templates/library.template.mjs +5 -4
- package/templates/library.tsx +409 -430
- package/templates/login-card.template.mjs +5 -4
- package/templates/login-card.tsx +63 -72
- package/templates/login-split.template.mjs +5 -4
- package/templates/login-split.tsx +192 -193
- package/templates/login-sso.template.mjs +5 -4
- package/templates/login-sso.tsx +257 -258
- package/templates/login.template.mjs +5 -4
- package/templates/login.tsx +53 -49
- package/templates/messaging-shell.template.mjs +5 -4
- package/templates/messaging-shell.tsx +556 -574
- package/templates/mixed-gallery.template.mjs +5 -4
- package/templates/mixed-gallery.tsx +60 -58
- package/templates/payment-form.template.mjs +5 -4
- package/templates/payment-form.tsx +882 -991
- package/templates/product-detail.template.mjs +5 -4
- package/templates/product-detail.tsx +261 -272
- package/templates/product-gallery.template.mjs +5 -4
- package/templates/product-gallery.tsx +126 -137
- package/templates/product-tour.template.mjs +5 -4
- package/templates/product-tour.tsx +741 -773
- package/templates/settings-dialog.template.mjs +5 -4
- package/templates/settings-dialog.tsx +688 -717
- package/templates/settings-sidebar.template.mjs +5 -4
- package/templates/settings-sidebar.tsx +762 -807
- package/templates/settings.template.mjs +5 -4
- package/templates/settings.tsx +289 -304
- package/templates/shell-nav.template.mjs +5 -4
- package/templates/shell-nav.tsx +212 -219
- package/templates/shell-side-nav.template.mjs +5 -4
- package/templates/shell-side-nav.tsx +135 -157
- package/templates/shell-top-nav.template.mjs +5 -4
- package/templates/shell-top-nav.tsx +182 -203
- package/templates/side-gallery.template.mjs +5 -4
- package/templates/side-gallery.tsx +85 -90
- package/templates/table-grouped.template.mjs +5 -4
- package/templates/table-grouped.tsx +1000 -1053
- package/templates/table-page-chart.template.mjs +5 -4
- package/templates/table-page-chart.tsx +400 -398
- package/templates/table-page-heatmap-status.template.mjs +5 -4
- package/templates/table-page-heatmap-status.tsx +483 -512
- package/templates/table-page-shoe-store-heatmap.template.mjs +5 -4
- package/templates/table-page-shoe-store-heatmap.tsx +748 -746
- package/templates/table-page.template.mjs +5 -4
- package/templates/table-page.tsx +396 -405
- package/templates/table.template.mjs +5 -4
- package/templates/table.tsx +92 -93
- package/templates/tech-report.template.mjs +5 -4
- package/templates/tech-report.tsx +1316 -1304
- package/templates/theme-showcase.template.mjs +5 -4
- package/templates/theme-showcase.tsx +871 -951
- package/theme.css +35 -77
- package/theme.css.d.ts +9 -0
- package/tokens.css +373 -380
package/shared/revenue-chart.tsx
CHANGED
|
@@ -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
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import type {
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
136
|
+
data,
|
|
137
|
+
chartMax,
|
|
138
|
+
gridTicks,
|
|
139
|
+
ariaLabel = "Daily revenue, January 1 to 15",
|
|
140
|
+
caption = "Daily revenue · Jan 1–15",
|
|
158
141
|
}: {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
142
|
+
data: RevenuePoint[];
|
|
143
|
+
chartMax: number;
|
|
144
|
+
gridTicks: number[];
|
|
145
|
+
ariaLabel?: string;
|
|
146
|
+
caption?: string;
|
|
164
147
|
}) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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
|
}
|