astryx-dracula 0.2.1 → 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 +17 -12
- 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 +66 -33
- package/templates/ai-chat.tsx +36 -19
- package/templates/blank.tsx +4 -3
- package/templates/centered-hero.tsx +14 -125
- package/templates/classic-gallery.tsx +20 -66
- package/templates/contact-form.tsx +59 -39
- package/templates/dashboard-portfolio.tsx +143 -226
- package/templates/dashboard.tsx +122 -122
- package/templates/detail-page.tsx +95 -91
- package/templates/documentation-design.template.mjs +1 -1
- package/templates/documentation-design.tsx +83 -96
- package/templates/documentation-technical.template.mjs +1 -1
- package/templates/documentation-technical.tsx +29 -19
- package/templates/documentation.template.mjs +1 -1
- package/templates/documentation.tsx +52 -74
- package/templates/editor.tsx +112 -84
- package/templates/file-explorer.tsx +131 -84
- package/templates/form-two-column.tsx +61 -125
- package/templates/gallery-hero.tsx +15 -171
- package/templates/ide.tsx +22 -20
- package/templates/incident-console.tsx +104 -70
- package/templates/kanban-board.tsx +99 -42
- package/templates/library.template.mjs +2 -2
- package/templates/library.tsx +37 -42
- package/templates/login-card.tsx +58 -87
- package/templates/login-split.tsx +88 -126
- package/templates/login-sso.tsx +105 -64
- package/templates/login.tsx +107 -53
- package/templates/messaging-shell.tsx +171 -144
- package/templates/mixed-gallery.tsx +29 -130
- package/templates/payment-form.tsx +368 -290
- package/templates/product-detail.tsx +39 -58
- package/templates/product-gallery.tsx +30 -41
- package/templates/product-tour.template.mjs +6 -0
- package/templates/product-tour.tsx +916 -0
- package/templates/settings-dialog.tsx +135 -282
- package/templates/settings-sidebar.tsx +178 -268
- package/templates/settings.tsx +41 -14
- package/templates/shell-nav.tsx +31 -24
- package/templates/shell-side-nav.tsx +29 -20
- package/templates/shell-top-nav.tsx +80 -44
- package/templates/side-gallery.tsx +38 -94
- package/templates/table-grouped.tsx +62 -34
- package/templates/table-page-chart.tsx +23 -302
- package/templates/table-page-heatmap-status.tsx +156 -92
- package/templates/table-page-shoe-store-heatmap.tsx +18 -293
- package/templates/table-page.tsx +23 -7
- package/templates/table.tsx +23 -8
- 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 +299 -237
- package/theme.css +76 -14
- package/tokens.css +425 -30
|
@@ -1,76 +1,20 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
3
|
-
// L > (LH > H[g2 a=center] > Hd"Midnight Kicks"[level=1] + IB
|
|
3
|
+
// L > (LH[divider] > H[g2 a=center] > Hd"Midnight Kicks"[level=1] + IB"Filter"[variant=ghost] + IB"Export"[variant=ghost] + B.primary"New order") + (LC[p3] > V[g4] > (V[g3] > C[p=4] + Tx"Daily revenue"[t=supporting] + (H[g2 a=center] > Ic + Tx"Revenue"[t=supporting])) + (T[hover] > (TR > THC"Order" + THC"Product" + THC"Amount" + THC"Customer" + THC"Email" + THC"Status" + THC"Date") + (TR > TC"ORD-1001" + TC"Air Max 90" + TC"$130" + TC"Sarah Chen" + TC"sarah.chen@acme.co" + (TC > Tk.green"Completed") + TC"2025-01-12")*5))
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
HStack,
|
|
9
|
-
StackItem,
|
|
10
|
-
Layout,
|
|
11
|
-
LayoutContent,
|
|
12
|
-
LayoutHeader,
|
|
13
|
-
} from '@astryxdesign/core/Layout';
|
|
14
|
-
import {Text, Heading} from '@astryxdesign/core/Text';
|
|
15
|
-
import {Button} from '@astryxdesign/core/Button';
|
|
16
|
-
import {IconButton} from '@astryxdesign/core/IconButton';
|
|
17
|
-
import {Icon} from '@astryxdesign/core/Icon';
|
|
18
|
-
import {Badge} from '@astryxdesign/core/Badge';
|
|
19
|
-
import {Card} from '@astryxdesign/core/Card';
|
|
20
|
-
import {Link} from '@astryxdesign/core/Link';
|
|
21
|
-
import {Table, proportional, pixel} from '@astryxdesign/core/Table';
|
|
22
|
-
import type {TableColumn} from '@astryxdesign/core/Table';
|
|
23
|
-
import {Filter, Download, Plus, Square} from 'lucide-react';
|
|
5
|
+
/**
|
|
6
|
+
* Midnight Kicks — sneaker order desk: a daily revenue line over the order log. Frame: page header (title + icon actions) | content column (c (Frame/responsive/container: see XLE header above.)
|
|
7
|
+
*/
|
|
24
8
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// Square marks the chart legend swatch.
|
|
28
|
-
|
|
29
|
-
const swatchStyle: CSSProperties = {flexShrink: 0};
|
|
30
|
-
|
|
31
|
-
// Rounded product swatch: Dracula surface with a per-product accent glyph.
|
|
32
|
-
function ProductSwatch({accent, label}: {accent: string; label: string}) {
|
|
33
|
-
return (
|
|
34
|
-
<svg
|
|
35
|
-
viewBox="0 0 36 36"
|
|
36
|
-
width={36}
|
|
37
|
-
height={36}
|
|
38
|
-
style={swatchStyle}
|
|
39
|
-
role="img"
|
|
40
|
-
aria-label={`${label} swatch`}>
|
|
41
|
-
<rect width={36} height={36} rx={5} fill="var(--dracula-bg-light)" />
|
|
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
|
-
);
|
|
54
|
-
}
|
|
9
|
+
import {OrderDesk, type OrderDeskRow} from 'astryx-dracula/shared/order-desk';
|
|
10
|
+
import type {SceneHue} from 'astryx-dracula/shared/scene-hues';
|
|
55
11
|
|
|
56
12
|
// ============= DATA =============
|
|
57
13
|
|
|
58
14
|
type ProductCategory =
|
|
59
15
|
'Running' | 'Lifestyle' | 'Basketball' | 'Training' | 'Skateboarding';
|
|
60
16
|
|
|
61
|
-
|
|
62
|
-
id: string;
|
|
63
|
-
customer: string;
|
|
64
|
-
email: string;
|
|
65
|
-
product: string;
|
|
66
|
-
category: ProductCategory;
|
|
67
|
-
imageIndex: number;
|
|
68
|
-
amount: number;
|
|
69
|
-
status: 'completed' | 'processing' | 'shipped' | 'refunded';
|
|
70
|
-
date: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const PRODUCTS = [
|
|
17
|
+
const PRODUCTS: Array<{name: string; category: string; accent: SceneHue; price: number}> = [
|
|
74
18
|
{
|
|
75
19
|
name: 'Air Max 90',
|
|
76
20
|
category: 'Lifestyle' as ProductCategory,
|
|
@@ -92,7 +36,7 @@ const PRODUCTS = [
|
|
|
92
36
|
{
|
|
93
37
|
name: 'Jordan 1 Retro',
|
|
94
38
|
category: 'Basketball' as ProductCategory,
|
|
95
|
-
accent: 'var(--dracula-
|
|
39
|
+
accent: 'var(--dracula-red)',
|
|
96
40
|
price: 180,
|
|
97
41
|
},
|
|
98
42
|
{
|
|
@@ -109,7 +53,7 @@ const PRODUCTS = [
|
|
|
109
53
|
},
|
|
110
54
|
];
|
|
111
55
|
|
|
112
|
-
const orders:
|
|
56
|
+
const orders: OrderDeskRow[] = [
|
|
113
57
|
// Sun (0) — spread across 9am–5pm, very hot
|
|
114
58
|
{
|
|
115
59
|
id: 'ORD-1001',
|
|
@@ -808,237 +752,18 @@ const revenueData = [
|
|
|
808
752
|
{date: 'Jan 15', revenue: 7100},
|
|
809
753
|
];
|
|
810
754
|
|
|
811
|
-
|
|
812
|
-
completed: 'green',
|
|
813
|
-
shipped: 'blue',
|
|
814
|
-
processing: 'orange',
|
|
815
|
-
refunded: 'red',
|
|
816
|
-
};
|
|
817
|
-
|
|
818
|
-
const columns: TableColumn<OrderRow>[] = [
|
|
819
|
-
{
|
|
820
|
-
key: 'id',
|
|
821
|
-
header: 'Order',
|
|
822
|
-
width: pixel(110),
|
|
823
|
-
renderCell: (item: OrderRow) => (
|
|
824
|
-
<Link href="#/templates/table-page-shoe-store-heatmap" isStandalone>
|
|
825
|
-
{item.id}
|
|
826
|
-
</Link>
|
|
827
|
-
),
|
|
828
|
-
},
|
|
829
|
-
{
|
|
830
|
-
key: 'product',
|
|
831
|
-
header: 'Product',
|
|
832
|
-
width: proportional(3),
|
|
833
|
-
renderCell: (item: OrderRow) => (
|
|
834
|
-
<HStack gap={3} vAlign="center">
|
|
835
|
-
<ProductSwatch
|
|
836
|
-
accent={PRODUCTS[item.imageIndex].accent}
|
|
837
|
-
label={item.product}
|
|
838
|
-
/>
|
|
839
|
-
<VStack gap={0}>
|
|
840
|
-
<Text type="body">{item.product}</Text>
|
|
841
|
-
<Text type="supporting" color="secondary">
|
|
842
|
-
{item.category}
|
|
843
|
-
</Text>
|
|
844
|
-
</VStack>
|
|
845
|
-
</HStack>
|
|
846
|
-
),
|
|
847
|
-
},
|
|
848
|
-
{
|
|
849
|
-
key: 'amount',
|
|
850
|
-
header: 'Amount',
|
|
851
|
-
width: pixel(90),
|
|
852
|
-
renderCell: (item: OrderRow) => (
|
|
853
|
-
<Text type="body" hasTabularNumbers>
|
|
854
|
-
${item.amount}
|
|
855
|
-
</Text>
|
|
856
|
-
),
|
|
857
|
-
},
|
|
858
|
-
{
|
|
859
|
-
key: 'customer',
|
|
860
|
-
header: 'Customer',
|
|
861
|
-
width: proportional(2),
|
|
862
|
-
renderCell: (item: OrderRow) => <Text type="body">{item.customer}</Text>,
|
|
863
|
-
},
|
|
864
|
-
{
|
|
865
|
-
key: 'email',
|
|
866
|
-
header: 'Email',
|
|
867
|
-
width: proportional(2),
|
|
868
|
-
renderCell: (item: OrderRow) => <Text type="body">{item.email}</Text>,
|
|
869
|
-
},
|
|
870
|
-
{
|
|
871
|
-
key: 'status',
|
|
872
|
-
header: 'Status',
|
|
873
|
-
width: pixel(120),
|
|
874
|
-
renderCell: (item: OrderRow) => (
|
|
875
|
-
<Badge
|
|
876
|
-
label={item.status.charAt(0).toUpperCase() + item.status.slice(1)}
|
|
877
|
-
variant={statusColor[item.status]}
|
|
878
|
-
/>
|
|
879
|
-
),
|
|
880
|
-
},
|
|
881
|
-
{
|
|
882
|
-
key: 'date',
|
|
883
|
-
header: 'Date',
|
|
884
|
-
width: pixel(110),
|
|
885
|
-
renderCell: (item: OrderRow) => (
|
|
886
|
-
<Text type="body" hasTabularNumbers>
|
|
887
|
-
{item.date}
|
|
888
|
-
</Text>
|
|
889
|
-
),
|
|
890
|
-
},
|
|
891
|
-
];
|
|
892
|
-
|
|
893
|
-
// ============= REVENUE CHART (hand SVG, Dracula ramp) =============
|
|
894
|
-
|
|
895
|
-
const revenueLine = 'var(--dracula-cyan)';
|
|
896
|
-
|
|
897
|
-
function RevenueChart() {
|
|
898
|
-
const W = 540;
|
|
899
|
-
const H = 200;
|
|
900
|
-
const padLeft = 44;
|
|
901
|
-
const padRight = 12;
|
|
902
|
-
const padTop = 12;
|
|
903
|
-
const baseline = 164;
|
|
904
|
-
const max = 10000;
|
|
905
|
-
const plotW = W - padLeft - padRight;
|
|
906
|
-
const plotH = baseline - padTop;
|
|
907
|
-
const points = revenueData.map((d, i) => ({
|
|
908
|
-
...d,
|
|
909
|
-
x: padLeft + (i / (revenueData.length - 1)) * plotW,
|
|
910
|
-
y: baseline - (d.revenue / max) * plotH,
|
|
911
|
-
}));
|
|
912
|
-
const linePath = points
|
|
913
|
-
.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`)
|
|
914
|
-
.join(' ');
|
|
915
|
-
const areaPath = `${linePath} L${points[points.length - 1].x.toFixed(1)},${baseline} L${points[0].x.toFixed(1)},${baseline} Z`;
|
|
916
|
-
const gridTicks = [0, 2000, 4000, 6000, 8000, 10000];
|
|
917
|
-
return (
|
|
918
|
-
<VStack gap={3}>
|
|
919
|
-
<Card
|
|
920
|
-
padding={3}
|
|
921
|
-
style={{
|
|
922
|
-
backgroundColor: 'var(--color-background)',
|
|
923
|
-
border: 'var(--border-width) solid var(--color-separator)',
|
|
924
|
-
}}>
|
|
925
|
-
<svg
|
|
926
|
-
viewBox={`0 0 ${W} ${H}`}
|
|
927
|
-
width="100%"
|
|
928
|
-
role="img"
|
|
929
|
-
aria-label="Daily revenue, January 1 to 15">
|
|
930
|
-
{gridTicks.map(tick => {
|
|
931
|
-
const y = baseline - (tick / max) * plotH;
|
|
932
|
-
return (
|
|
933
|
-
<g key={tick}>
|
|
934
|
-
<line
|
|
935
|
-
x1={padLeft}
|
|
936
|
-
y1={y}
|
|
937
|
-
x2={W - padRight}
|
|
938
|
-
y2={y}
|
|
939
|
-
stroke="var(--color-separator)"
|
|
940
|
-
strokeDasharray={tick === 0 ? undefined : '3 3'}
|
|
941
|
-
opacity={tick === 0 ? 1 : 0.5}
|
|
942
|
-
/>
|
|
943
|
-
<text
|
|
944
|
-
x={padLeft - 6}
|
|
945
|
-
y={y + 3}
|
|
946
|
-
textAnchor="end"
|
|
947
|
-
fontSize={9}
|
|
948
|
-
fill="var(--color-text-paragraph)"
|
|
949
|
-
fontFamily="var(--font-family-mono)">
|
|
950
|
-
{tick === 0 ? '$0' : `$${tick / 1000}k`}
|
|
951
|
-
</text>
|
|
952
|
-
</g>
|
|
953
|
-
);
|
|
954
|
-
})}
|
|
955
|
-
<path d={areaPath} fill={revenueLine} opacity={0.25} />
|
|
956
|
-
<path
|
|
957
|
-
d={linePath}
|
|
958
|
-
fill="none"
|
|
959
|
-
stroke={revenueLine}
|
|
960
|
-
strokeWidth={2}
|
|
961
|
-
strokeLinejoin="round"
|
|
962
|
-
strokeLinecap="round"
|
|
963
|
-
/>
|
|
964
|
-
{points.map(
|
|
965
|
-
(p, i) =>
|
|
966
|
-
(i % 3 === 0 || i === points.length - 1) && (
|
|
967
|
-
<text
|
|
968
|
-
key={p.date}
|
|
969
|
-
x={i === points.length - 1 ? W - padRight - 2 : p.x}
|
|
970
|
-
y={H - 8}
|
|
971
|
-
textAnchor={i === points.length - 1 ? 'end' : 'middle'}
|
|
972
|
-
fontSize={9}
|
|
973
|
-
fill="var(--color-text-paragraph)"
|
|
974
|
-
fontFamily="var(--font-family-mono)">
|
|
975
|
-
{p.date}
|
|
976
|
-
</text>
|
|
977
|
-
),
|
|
978
|
-
)}
|
|
979
|
-
</svg>
|
|
980
|
-
</Card>
|
|
981
|
-
<Text type="supporting" color="secondary">
|
|
982
|
-
Daily revenue · Jan 1–15
|
|
983
|
-
</Text>
|
|
984
|
-
<HStack gap={2} vAlign="center">
|
|
985
|
-
<Icon icon={Square} size="xsm" style={{color: revenueLine}} />
|
|
986
|
-
<Text type="supporting" color="secondary">
|
|
987
|
-
Revenue
|
|
988
|
-
</Text>
|
|
989
|
-
</HStack>
|
|
990
|
-
</VStack>
|
|
991
|
-
);
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
// ============= PAGE =============
|
|
755
|
+
// ============= PAGE (parametric OrderDesk; catalogue + rows + scale only) =============
|
|
995
756
|
|
|
996
757
|
export default function ShoeStoreTable() {
|
|
997
758
|
return (
|
|
998
|
-
<
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
<IconButton
|
|
1007
|
-
label="Filter"
|
|
1008
|
-
icon={<Icon icon={Filter} size="sm" />}
|
|
1009
|
-
variant="ghost"
|
|
1010
|
-
tooltip="Filter"
|
|
1011
|
-
/>
|
|
1012
|
-
<IconButton
|
|
1013
|
-
label="Export"
|
|
1014
|
-
icon={<Icon icon={Download} size="sm" />}
|
|
1015
|
-
variant="ghost"
|
|
1016
|
-
tooltip="Export"
|
|
1017
|
-
/>
|
|
1018
|
-
<Button
|
|
1019
|
-
label="New order"
|
|
1020
|
-
variant="primary"
|
|
1021
|
-
icon={<Icon icon={Plus} size="sm" />}
|
|
1022
|
-
/>
|
|
1023
|
-
</HStack>
|
|
1024
|
-
</LayoutHeader>
|
|
1025
|
-
}
|
|
1026
|
-
content={
|
|
1027
|
-
<LayoutContent padding={3}>
|
|
1028
|
-
<VStack gap={4}>
|
|
1029
|
-
<RevenueChart />
|
|
1030
|
-
|
|
1031
|
-
<Table<OrderRow>
|
|
1032
|
-
data={orders}
|
|
1033
|
-
columns={columns}
|
|
1034
|
-
idKey="id"
|
|
1035
|
-
density="balanced"
|
|
1036
|
-
dividers="rows"
|
|
1037
|
-
hasHover
|
|
1038
|
-
/>
|
|
1039
|
-
</VStack>
|
|
1040
|
-
</LayoutContent>
|
|
1041
|
-
}
|
|
759
|
+
<OrderDesk
|
|
760
|
+
title="Midnight Kicks"
|
|
761
|
+
selfHash="#/templates/table-page-shoe-store-heatmap"
|
|
762
|
+
products={PRODUCTS}
|
|
763
|
+
orders={orders}
|
|
764
|
+
revenueData={revenueData}
|
|
765
|
+
chartMax={10000}
|
|
766
|
+
gridTicks={[0, 2000, 4000, 6000, 8000, 10000]}
|
|
1042
767
|
/>
|
|
1043
768
|
);
|
|
1044
769
|
}
|
package/templates/table-page.tsx
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
3
|
-
// L > (LH[divider] > H[g=2 a=center] > (SI[fill] > Hd"Familiars"[level=1]) + IB"Filter" + IB"Download" + B.primary"Add") + (LC[p=3] > V[g=4] > PS + (T[hover] > (TR > THC*3) + (TR > TC*3)*3))
|
|
3
|
+
// L > (LH[divider] > H[g=2 a=center] > (SI[fill] > Hd"Familiars"[level=1]) + IB"Filter"[variant=ghost] + IB"Download"[variant=ghost] + B.primary"Add") + (LC[p=3] > V[g=4] > PS + (T[hover] > (TR > THC*3) + (TR > TC*3)*3))
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Familiars — the full roster of the crypt's companions, with a PowerSearch field filter bar above one dense table. (Frame/responsive/container: see XLE header above.)
|
|
7
|
+
*/
|
|
4
8
|
|
|
5
9
|
import {useState, useMemo} from 'react';
|
|
6
10
|
import {
|
|
@@ -43,7 +47,7 @@ const allFamiliars: FamiliarRow[] = [
|
|
|
43
47
|
name: 'Vlad',
|
|
44
48
|
kind: 'Vampire Bat',
|
|
45
49
|
biography:
|
|
46
|
-
'I love brooding in the belfry and hate garlic bread
|
|
50
|
+
'I love brooding in the belfry and hate garlic bread, and you might wonder how well those things mix. The answer is "not that well."',
|
|
47
51
|
age: 17,
|
|
48
52
|
},
|
|
49
53
|
{
|
|
@@ -123,7 +127,7 @@ const allFamiliars: FamiliarRow[] = [
|
|
|
123
127
|
name: 'Bruno',
|
|
124
128
|
kind: 'Gargoyle',
|
|
125
129
|
biography:
|
|
126
|
-
"Bruno is a gargoyle. He's a stony fellow
|
|
130
|
+
"Bruno is a gargoyle. He's a stony fellow. I never needed more than a day to teach him to scowl.",
|
|
127
131
|
age: 5,
|
|
128
132
|
},
|
|
129
133
|
{
|
|
@@ -400,22 +404,34 @@ export default function TablePage() {
|
|
|
400
404
|
<Layout
|
|
401
405
|
height="fill"
|
|
402
406
|
header={
|
|
403
|
-
<LayoutHeader hasDivider>
|
|
407
|
+
<LayoutHeader hasDivider padding={6}>
|
|
404
408
|
<HStack gap={2} vAlign="center">
|
|
405
409
|
<StackItem size="fill">
|
|
406
|
-
|
|
410
|
+
{/* maxLines={1} for symmetry with the other order-desk headers.
|
|
411
|
+
"Familiars" measures 189px at 35px and fits on one line today,
|
|
412
|
+
so this is a floor against a longer title rather than a fix
|
|
413
|
+
for a visible break — but the row has 129.2px of controls and
|
|
414
|
+
24px of gaps against a 342px content box, so it has ~0px of
|
|
415
|
+
slack. Tooltip keeps the full value reachable (SC 1.4.10). */}
|
|
416
|
+
<Heading level={1} type="display-2" maxLines={1}>Familiars</Heading>
|
|
407
417
|
</StackItem>
|
|
408
418
|
<IconButton
|
|
409
419
|
label="Filter"
|
|
410
420
|
icon={<Icon icon={Filter} size="sm" />}
|
|
411
421
|
variant="ghost"
|
|
422
|
+
tooltip="Filter"
|
|
412
423
|
/>
|
|
413
424
|
<IconButton
|
|
414
425
|
label="Download"
|
|
415
426
|
icon={<Icon icon={Download} size="sm" />}
|
|
416
427
|
variant="ghost"
|
|
428
|
+
tooltip="Export"
|
|
429
|
+
/>
|
|
430
|
+
<Button
|
|
431
|
+
label="Add"
|
|
432
|
+
variant="primary"
|
|
433
|
+
icon={<Icon icon={Plus} size="sm" />}
|
|
417
434
|
/>
|
|
418
|
-
<Button label="Add" icon={<Icon icon={Plus} size="sm" />} />
|
|
419
435
|
</HStack>
|
|
420
436
|
</LayoutHeader>
|
|
421
437
|
}
|
|
@@ -428,7 +444,7 @@ export default function TablePage() {
|
|
|
428
444
|
onChange={newFilters => {
|
|
429
445
|
setFilters([...newFilters]);
|
|
430
446
|
}}
|
|
431
|
-
placeholder="Search familiars
|
|
447
|
+
placeholder="Search familiars…"
|
|
432
448
|
resultCount={filtered.length}
|
|
433
449
|
/>
|
|
434
450
|
<Table<FamiliarRow>
|
package/templates/table.tsx
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
3
|
-
// L >
|
|
3
|
+
// L > (LH[divider] > H[a=center j=between] > Hd"Artifacts"[level=1] + B.primary"Add artifact") + (LC > T[hover] > (TR > THC"Name" + THC"Status" + THC"Updated" + THC"Actions") + (TR > TC"Blood Vial" + (TC > SD.success + Tx"Active") + TC"2025-01-15" + (TC > B.secondary"Edit"))*3)
|
|
4
4
|
|
|
5
|
-
import {useState} from 'react';
|
|
6
5
|
import {Layout, LayoutHeader, LayoutContent, HStack} from '@astryxdesign/core/Layout';
|
|
7
6
|
import {Text, Heading} from '@astryxdesign/core/Text';
|
|
8
7
|
import {Button} from '@astryxdesign/core/Button';
|
|
9
8
|
import {Table} from '@astryxdesign/core/Table';
|
|
10
|
-
import {
|
|
9
|
+
import {StatusDot} from '@astryxdesign/core/StatusDot';
|
|
11
10
|
import type {TableColumn} from '@astryxdesign/core/Table';
|
|
12
11
|
|
|
13
12
|
type Relic = {
|
|
@@ -17,6 +16,16 @@ type Relic = {
|
|
|
17
16
|
updatedAt: string;
|
|
18
17
|
};
|
|
19
18
|
|
|
19
|
+
const STATUS_LABEL: Record<Relic['status'], string> = {
|
|
20
|
+
active: 'Active',
|
|
21
|
+
inactive: 'Inactive',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const STATUS_VARIANT: Record<Relic['status'], 'success' | 'neutral'> = {
|
|
25
|
+
active: 'success',
|
|
26
|
+
inactive: 'neutral',
|
|
27
|
+
};
|
|
28
|
+
|
|
20
29
|
const SAMPLE_DATA: Relic[] = [
|
|
21
30
|
{id: '1', name: 'Blood Vial', status: 'active', updatedAt: '2025-01-15'},
|
|
22
31
|
{id: '2', name: 'Garlic Charm', status: 'inactive', updatedAt: '2025-01-14'},
|
|
@@ -37,10 +46,15 @@ const columns: TableColumn<Relic>[] = [
|
|
|
37
46
|
key: 'status',
|
|
38
47
|
header: 'Status',
|
|
39
48
|
renderCell: (item: Relic) => (
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
<HStack gap={1} vAlign="center">
|
|
50
|
+
<StatusDot
|
|
51
|
+
variant={STATUS_VARIANT[item.status]}
|
|
52
|
+
label={STATUS_LABEL[item.status]}
|
|
53
|
+
/>
|
|
54
|
+
<Text type="body" color="secondary">
|
|
55
|
+
{STATUS_LABEL[item.status]}
|
|
56
|
+
</Text>
|
|
57
|
+
</HStack>
|
|
44
58
|
),
|
|
45
59
|
},
|
|
46
60
|
{
|
|
@@ -64,10 +78,11 @@ const columns: TableColumn<Relic>[] = [
|
|
|
64
78
|
];
|
|
65
79
|
|
|
66
80
|
export default function SimpleTable() {
|
|
67
|
-
const
|
|
81
|
+
const data = SAMPLE_DATA;
|
|
68
82
|
|
|
69
83
|
return (
|
|
70
84
|
<Layout
|
|
85
|
+
height="auto"
|
|
71
86
|
header={
|
|
72
87
|
<LayoutHeader hasDivider>
|
|
73
88
|
<HStack vAlign="center" hAlign="between">
|