@siyahi/ui 0.1.9-next.21 → 0.1.9-next.23
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/DESIGN.md +16 -3
- package/agents/examples/accordion.tsx +7 -7
- package/agents/examples/alert.tsx +16 -15
- package/agents/examples/app-sidebar.tsx +3 -1
- package/agents/examples/badge.tsx +20 -12
- package/agents/examples/bar-list-labels.tsx +6 -6
- package/agents/examples/bar-list-sides.tsx +18 -16
- package/agents/examples/bar-list.tsx +8 -8
- package/agents/examples/breadcrumb.tsx +3 -3
- package/agents/examples/calendar.tsx +3 -7
- package/agents/examples/callout.tsx +15 -15
- package/agents/examples/card.tsx +5 -3
- package/agents/examples/change-bar.tsx +21 -21
- package/agents/examples/chart-area.tsx +11 -11
- package/agents/examples/chart-bar-flows.tsx +1 -1
- package/agents/examples/chart-bar-hourly.tsx +1 -1
- package/agents/examples/chart-bar-losses.tsx +3 -3
- package/agents/examples/chart-bar-teams.tsx +72 -0
- package/agents/examples/chart-bar-years.tsx +5 -5
- package/agents/examples/chart-bar.tsx +10 -10
- package/agents/examples/chart-category-ticks.tsx +6 -6
- package/agents/examples/chart-line.tsx +17 -17
- package/agents/examples/collapsible.tsx +5 -3
- package/agents/examples/command.tsx +23 -21
- package/agents/examples/context-menu.tsx +6 -4
- package/agents/examples/data-bar.tsx +32 -45
- package/agents/examples/data-table-compact.tsx +31 -30
- package/agents/examples/data-table-filters.tsx +20 -20
- package/agents/examples/data-table.tsx +31 -30
- package/agents/examples/dialog.tsx +3 -3
- package/agents/examples/distribution-bar-tug.tsx +36 -34
- package/agents/examples/dropdown-menu.tsx +2 -2
- package/agents/examples/heatmap-calendar.tsx +12 -10
- package/agents/examples/heatmap-status.tsx +11 -9
- package/agents/examples/heatmap-weekday.tsx +27 -30
- package/agents/examples/input-states.tsx +9 -9
- package/agents/examples/input.tsx +3 -3
- package/agents/examples/local-time.tsx +1 -1
- package/agents/examples/metric-strip.tsx +8 -8
- package/agents/examples/page-hero.tsx +2 -2
- package/agents/examples/popover.tsx +3 -3
- package/agents/examples/price-chart.tsx +5 -5
- package/agents/examples/progress-tone.tsx +10 -9
- package/agents/examples/progress.tsx +1 -1
- package/agents/examples/range-position-table.tsx +31 -31
- package/agents/examples/range-position.tsx +31 -29
- package/agents/examples/scroll-area.tsx +12 -10
- package/agents/examples/section-cards-select.tsx +11 -10
- package/agents/examples/section-cards-trend.tsx +4 -4
- package/agents/examples/section-cards.tsx +13 -13
- package/agents/examples/select.tsx +9 -9
- package/agents/examples/separator.tsx +3 -3
- package/agents/examples/sheet.tsx +1 -1
- package/agents/examples/slider.tsx +1 -1
- package/agents/examples/surfaces.tsx +16 -16
- package/agents/examples/tabs.tsx +7 -7
- package/agents/examples/target-rows.tsx +31 -27
- package/agents/examples/tooltip.tsx +2 -2
- package/agents/examples/treemap.tsx +38 -33
- package/agents/manifest.json +15 -15
- package/dist/components/registry/charts/bar-chart-card.d.ts +1 -1
- package/dist/components/registry/charts/bar-chart-card.js +6 -2
- package/dist/components/registry/charts/line-chart-card.d.ts +1 -1
- package/dist/components/registry/charts/line-chart-card.js +1 -1
- package/dist/components/registry/dashboard-01/section-cards.js +1 -1
- package/dist/components/registry/dashboardcn/distribution-bar.js +5 -3
- package/dist/components/registry/heatmap/status-heatmap.js +1 -1
- package/dist/components/siyahi/callout.d.ts +5 -12
- package/dist/components/siyahi/callout.js +5 -11
- package/dist/components/siyahi/delta.d.ts +5 -1
- package/dist/components/siyahi/delta.js +14 -9
- package/dist/components/siyahi/status-alert.d.ts +15 -0
- package/dist/components/siyahi/status-alert.js +29 -0
- package/dist/components/siyahi/status-badge.d.ts +15 -0
- package/dist/components/siyahi/status-badge.js +24 -0
- package/dist/components/siyahi/tone-progress.d.ts +1 -1
- package/dist/components/siyahi/tone-progress.js +1 -1
- package/dist/components/siyahi/treemap.d.ts +4 -4
- package/dist/components/siyahi/treemap.js +5 -5
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -2
- package/dist/lib/chart-frame.js +1 -1
- package/dist/lib/chart-series.d.ts +1 -1
- package/dist/lib/format.d.ts +1 -1
- package/dist/lib/format.js +1 -1
- package/dist/lib/tone.d.ts +36 -0
- package/dist/lib/tone.js +35 -0
- package/package.json +1 -1
- package/report.css +14 -14
- package/styles/siyahi.css +92 -20
- package/agents/examples/chart-bar-sectors.tsx +0 -72
- package/dist/components/siyahi/warning-alert.d.ts +0 -10
- package/dist/components/siyahi/warning-alert.js +0 -20
|
@@ -16,61 +16,61 @@ import {
|
|
|
16
16
|
type DataTableColumnDef,
|
|
17
17
|
} from "@siyahi/ui";
|
|
18
18
|
|
|
19
|
-
interface
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
|
|
19
|
+
interface Service {
|
|
20
|
+
service: string;
|
|
21
|
+
/** Today's 95th-percentile response time and the fastest and slowest day of the last 30, in ms; made-up figures. */
|
|
22
|
+
today: number;
|
|
23
23
|
low: number;
|
|
24
24
|
high: number;
|
|
25
|
-
/** How far up its range
|
|
25
|
+
/** How far up its range today sits, 0 at the fastest day and 1 at the slowest, so the column sorts. */
|
|
26
26
|
position: number;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
const service = (name: string, today: number, low: number, high: number): Service => ({
|
|
30
|
+
service: name,
|
|
31
|
+
today,
|
|
32
32
|
low,
|
|
33
33
|
high,
|
|
34
|
-
position: (
|
|
34
|
+
position: (today - low) / (high - low),
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
const services: Service[] = [
|
|
38
|
+
service("search", 284, 241, 292),
|
|
39
|
+
service("catalogue", 187, 131, 201),
|
|
40
|
+
service("checkout", 329, 265, 342),
|
|
41
|
+
service("images", 415, 359, 459),
|
|
42
|
+
service("payments", 460, 399, 529),
|
|
43
|
+
service("login", 175, 161, 203),
|
|
44
44
|
];
|
|
45
45
|
|
|
46
|
-
function
|
|
47
|
-
return useFormat().
|
|
46
|
+
function Milliseconds({ value }: { value: number }) {
|
|
47
|
+
return `${useFormat().count(value)} ms`;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
const header = () => <DataTableSortHeader />;
|
|
51
51
|
|
|
52
|
-
const columns: DataTableColumnDef<
|
|
53
|
-
{ accessorKey: "
|
|
52
|
+
const columns: DataTableColumnDef<Service>[] = [
|
|
53
|
+
{ accessorKey: "service", header, size: 130, meta: { label: "Service", compact: true } },
|
|
54
54
|
{
|
|
55
|
-
accessorKey: "
|
|
55
|
+
accessorKey: "today",
|
|
56
56
|
header,
|
|
57
57
|
size: 120,
|
|
58
|
-
meta: { label: "
|
|
59
|
-
cell: ({ row }) => <
|
|
58
|
+
meta: { label: "p95 today", variant: "number" },
|
|
59
|
+
cell: ({ row }) => <Milliseconds value={row.original.today} />,
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
62
|
accessorKey: "position",
|
|
63
63
|
header,
|
|
64
64
|
size: 200,
|
|
65
|
-
meta: { label: "
|
|
65
|
+
meta: { label: "30-day range", compact: true },
|
|
66
66
|
cell: ({ row }) => (
|
|
67
67
|
<RangePosition
|
|
68
68
|
variant="compact"
|
|
69
69
|
low={row.original.low}
|
|
70
70
|
high={row.original.high}
|
|
71
|
-
value={row.original.
|
|
72
|
-
lowLabel="
|
|
73
|
-
highLabel="
|
|
71
|
+
value={row.original.today}
|
|
72
|
+
lowLabel="30-day fastest"
|
|
73
|
+
highLabel="30-day slowest"
|
|
74
74
|
/>
|
|
75
75
|
),
|
|
76
76
|
},
|
|
@@ -80,17 +80,17 @@ export default function RangePositionTableExample() {
|
|
|
80
80
|
return (
|
|
81
81
|
<Card>
|
|
82
82
|
<CardHeader>
|
|
83
|
-
<CardTitle>
|
|
83
|
+
<CardTitle>Search is near its slowest of the month, login near its fastest</CardTitle>
|
|
84
84
|
<CardDescription>
|
|
85
|
-
Each
|
|
85
|
+
Each service's response time today on a track from its fastest day to its slowest; sort to rank them
|
|
86
86
|
</CardDescription>
|
|
87
87
|
</CardHeader>
|
|
88
88
|
<CardContent>
|
|
89
|
-
<DataTableRoot data={
|
|
89
|
+
<DataTableRoot data={services} columns={columns}>
|
|
90
90
|
<DataTableToolbarSection>
|
|
91
91
|
<DataTableCompactColumnsToggle />
|
|
92
92
|
</DataTableToolbarSection>
|
|
93
|
-
<DataTable aria-label="
|
|
93
|
+
<DataTable aria-label="Services in their 30-day range">
|
|
94
94
|
<DataTableHeader />
|
|
95
95
|
<DataTableBody />
|
|
96
96
|
</DataTable>
|
|
@@ -10,43 +10,45 @@ import {
|
|
|
10
10
|
useFormat,
|
|
11
11
|
} from "@siyahi/ui";
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
const low =
|
|
15
|
-
const high =
|
|
16
|
-
const
|
|
13
|
+
// Checkout's daily 95th-percentile response time over the last 30 days, in ms; made-up figures.
|
|
14
|
+
const low = 161;
|
|
15
|
+
const high = 203;
|
|
16
|
+
const today = 175;
|
|
17
17
|
|
|
18
18
|
export default function RangePositionExample() {
|
|
19
19
|
const f = useFormat();
|
|
20
|
-
const
|
|
20
|
+
const ms = (value: number) => `${f.count(value)} ms`;
|
|
21
21
|
return (
|
|
22
22
|
// Side by side once the card, not the screen, has room: in a narrow panel on a wide screen they stack.
|
|
23
23
|
<Card className="@container/range">
|
|
24
24
|
<CardHeader>
|
|
25
|
-
<CardTitle>
|
|
26
|
-
<CardDescription>
|
|
25
|
+
<CardTitle>Checkout sits {f.pct((today - low) / (high - low), 0)} of the way up its 30-day range</CardTitle>
|
|
26
|
+
<CardDescription>Today's response time against the month's fastest and slowest day</CardDescription>
|
|
27
27
|
</CardHeader>
|
|
28
|
-
<CardContent
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
28
|
+
<CardContent>
|
|
29
|
+
<div className="flex flex-col gap-8 @xl/range:flex-row @xl/range:items-end">
|
|
30
|
+
<DataList className="@xl/range:w-56 @xl/range:shrink-0">
|
|
31
|
+
<DataListItem label="Fastest day, 3 weeks ago">
|
|
32
|
+
<span className="tabular-nums">{ms(low)}</span>
|
|
33
|
+
</DataListItem>
|
|
34
|
+
<DataListItem label="Slowest day, 9 days ago">
|
|
35
|
+
<span className="tabular-nums">{ms(high)}</span>
|
|
36
|
+
</DataListItem>
|
|
37
|
+
<DataListItem label="Today, 95th percentile">
|
|
38
|
+
<span className="tabular-nums">{ms(today)}</span>
|
|
39
|
+
</DataListItem>
|
|
40
|
+
</DataList>
|
|
41
|
+
<RangePosition
|
|
42
|
+
low={low}
|
|
43
|
+
high={high}
|
|
44
|
+
value={today}
|
|
45
|
+
lowLabel="30-day fastest"
|
|
46
|
+
highLabel="30-day slowest"
|
|
47
|
+
caption="of the way up the 30-day range"
|
|
48
|
+
valueFormatter={ms}
|
|
49
|
+
className="@xl/range:flex-1"
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
50
52
|
</CardContent>
|
|
51
53
|
</Card>
|
|
52
54
|
);
|
|
@@ -6,15 +6,17 @@ const months = Array.from({ length: 24 }, (_, i) =>
|
|
|
6
6
|
|
|
7
7
|
export default function ScrollAreaExample() {
|
|
8
8
|
return (
|
|
9
|
-
<
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<div
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
<div className="h-48 w-56 overflow-hidden rounded-lg border">
|
|
10
|
+
<ScrollArea className="h-full">
|
|
11
|
+
<div className="p-4">
|
|
12
|
+
{months.map((month) => (
|
|
13
|
+
<div key={month}>
|
|
14
|
+
<div className="text-sm">{month}</div>
|
|
15
|
+
<Separator className="my-2" />
|
|
16
|
+
</div>
|
|
17
|
+
))}
|
|
18
|
+
</div>
|
|
19
|
+
</ScrollArea>
|
|
20
|
+
</div>
|
|
19
21
|
);
|
|
20
22
|
}
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { Delta, SectionCards, SiyahiProvider, useFormat, type SectionCard } from "@siyahi/ui";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
{ label: "
|
|
7
|
-
{ label: "
|
|
8
|
-
{ label: "
|
|
4
|
+
// Each sales channel's profit this quarter and its orders; made-up figures.
|
|
5
|
+
const channels = [
|
|
6
|
+
{ label: "All", net: 110200, orders: 181 },
|
|
7
|
+
{ label: "Online", net: 171400, orders: 164 },
|
|
8
|
+
{ label: "Wholesale", net: 0, orders: 0 },
|
|
9
|
+
{ label: "Marketplace", net: -61200, orders: 17 },
|
|
9
10
|
];
|
|
10
11
|
|
|
11
12
|
export default function SectionCardsSelectExample() {
|
|
12
13
|
const [scope, setScope] = useState("All");
|
|
13
14
|
const { count } = useFormat();
|
|
14
|
-
const items: SectionCard[] =
|
|
15
|
+
const items: SectionCard[] = channels.map((c) => ({
|
|
15
16
|
label: c.label,
|
|
16
17
|
value: <Delta value={c.net} format="money" />,
|
|
17
|
-
detail: `${count(c.
|
|
18
|
-
// Nothing to show for a
|
|
19
|
-
disabled: c.
|
|
18
|
+
detail: `${count(c.orders)} orders`,
|
|
19
|
+
// Nothing to show for a channel with no orders, so it cannot be picked.
|
|
20
|
+
disabled: c.orders === 0,
|
|
20
21
|
}));
|
|
21
22
|
return (
|
|
22
|
-
// On a ruled surface the tiles part with hairlines, as on a
|
|
23
|
+
// On a ruled surface the tiles part with hairlines, as on a dense operations screen, instead of sitting as cards.
|
|
23
24
|
<SiyahiProvider surface="ruled">
|
|
24
25
|
<div className="flex flex-col gap-3">
|
|
25
26
|
<SectionCards items={items} selected={scope} onSelect={setScope} />
|
|
@@ -4,14 +4,14 @@ export default function SectionCardsTrendExample() {
|
|
|
4
4
|
const { money, moneyCompact } = useFormat();
|
|
5
5
|
const items: SectionCard[] = [
|
|
6
6
|
{
|
|
7
|
-
label: "
|
|
7
|
+
label: "Revenue",
|
|
8
8
|
value: money(4512300),
|
|
9
9
|
badge: <Delta value={0.031} />,
|
|
10
10
|
trend: <Sparkline data={[3820000, 3950000, 4110000, 4020000, 4380000, 4512300]} />,
|
|
11
11
|
detail: "Month-end, last six months",
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
|
-
label: "
|
|
14
|
+
label: "Cash flow this year",
|
|
15
15
|
value: moneyCompact(-61200),
|
|
16
16
|
badge: <Delta value={-61200} format="money" />,
|
|
17
17
|
// A run of losses: the meaning colour, not a chart slot.
|
|
@@ -19,11 +19,11 @@ export default function SectionCardsTrendExample() {
|
|
|
19
19
|
detail: "Running total since April",
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
|
-
label: "
|
|
22
|
+
label: "Gift cards this year",
|
|
23
23
|
value: moneyCompact(38400),
|
|
24
24
|
badge: <Delta value={0.18} />,
|
|
25
25
|
trend: <Sparkline data={[4100, 0, 12800, 3300, 9900, 8300]} variant="line" curve="linear" />,
|
|
26
|
-
detail: "
|
|
26
|
+
detail: "Sold each month",
|
|
27
27
|
},
|
|
28
28
|
];
|
|
29
29
|
return <SectionCards items={items} />;
|
|
@@ -4,38 +4,38 @@ export default function SectionCardsExample() {
|
|
|
4
4
|
const { money, moneyCompact } = useFormat();
|
|
5
5
|
const items: SectionCard[] = [
|
|
6
6
|
{
|
|
7
|
-
label: "
|
|
7
|
+
label: "Revenue",
|
|
8
8
|
value: money(4512300),
|
|
9
9
|
badge: <Delta value={0.031} />,
|
|
10
10
|
headline: "Up for the third month",
|
|
11
|
-
detail: "
|
|
11
|
+
detail: "Paid orders, less refunds",
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
|
-
label: "
|
|
14
|
+
label: "Target",
|
|
15
15
|
value: money(4025000),
|
|
16
|
-
headline: "
|
|
17
|
-
detail: "Across 4
|
|
16
|
+
headline: "Set at the start of the quarter",
|
|
17
|
+
detail: "Across 4 stores",
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
label: "
|
|
20
|
+
label: "Ahead of target",
|
|
21
21
|
value: moneyCompact(487300),
|
|
22
22
|
badge: <Delta value={0.121} />,
|
|
23
|
-
headline: "
|
|
24
|
-
detail: "Since
|
|
23
|
+
headline: "Gross margin 14.2%",
|
|
24
|
+
detail: "Since April",
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
label: "
|
|
27
|
+
label: "Cash flow this year",
|
|
28
28
|
value: moneyCompact(-61200),
|
|
29
29
|
badge: <Delta value={-61200} format="money" />,
|
|
30
|
-
headline: "Two
|
|
30
|
+
headline: "Two large inventory buys",
|
|
31
31
|
detail: "Before tax",
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
|
-
label: "
|
|
34
|
+
label: "Gift cards this year",
|
|
35
35
|
value: moneyCompact(38400),
|
|
36
36
|
badge: <Delta value={0.18} />,
|
|
37
|
-
headline: "
|
|
38
|
-
detail: "
|
|
37
|
+
headline: "Sold in 11 stores",
|
|
38
|
+
detail: "Paid at purchase",
|
|
39
39
|
},
|
|
40
40
|
];
|
|
41
41
|
return (
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@siyahi/ui";
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
{ label: "All
|
|
5
|
-
{ label: "
|
|
6
|
-
{ label: "
|
|
7
|
-
{ label: "
|
|
3
|
+
const stores = [
|
|
4
|
+
{ label: "All stores", value: "all" },
|
|
5
|
+
{ label: "Online", value: "online" },
|
|
6
|
+
{ label: "Retail", value: "retail" },
|
|
7
|
+
{ label: "Wholesale", value: "wholesale" },
|
|
8
8
|
];
|
|
9
9
|
|
|
10
10
|
export default function SelectExample() {
|
|
11
11
|
return (
|
|
12
|
-
<Select items={
|
|
12
|
+
<Select items={stores} defaultValue="all">
|
|
13
13
|
<SelectTrigger className="w-48">
|
|
14
14
|
<SelectValue />
|
|
15
15
|
</SelectTrigger>
|
|
16
16
|
<SelectContent>
|
|
17
17
|
<SelectGroup>
|
|
18
|
-
{
|
|
19
|
-
<SelectItem key={
|
|
20
|
-
{
|
|
18
|
+
{stores.map((store) => (
|
|
19
|
+
<SelectItem key={store.value} value={store.value}>
|
|
20
|
+
{store.label}
|
|
21
21
|
</SelectItem>
|
|
22
22
|
))}
|
|
23
23
|
</SelectGroup>
|
|
@@ -3,11 +3,11 @@ import { Separator } from "@siyahi/ui";
|
|
|
3
3
|
export default function SeparatorExample() {
|
|
4
4
|
return (
|
|
5
5
|
<div className="flex h-6 items-center gap-4 text-sm">
|
|
6
|
-
<span>
|
|
6
|
+
<span>Orders</span>
|
|
7
7
|
<Separator orientation="vertical" />
|
|
8
|
-
<span>
|
|
8
|
+
<span>Customers</span>
|
|
9
9
|
<Separator orientation="vertical" />
|
|
10
|
-
<span>
|
|
10
|
+
<span>Products</span>
|
|
11
11
|
</div>
|
|
12
12
|
);
|
|
13
13
|
}
|
|
@@ -7,7 +7,7 @@ export default function SheetExample() {
|
|
|
7
7
|
<SheetContent>
|
|
8
8
|
<SheetHeader>
|
|
9
9
|
<SheetTitle>Filters</SheetTitle>
|
|
10
|
-
<SheetDescription>Narrow the
|
|
10
|
+
<SheetDescription>Narrow the orders by store, status or date.</SheetDescription>
|
|
11
11
|
</SheetHeader>
|
|
12
12
|
</SheetContent>
|
|
13
13
|
</Sheet>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Slider } from "@siyahi/ui";
|
|
2
2
|
|
|
3
3
|
export default function SliderExample() {
|
|
4
|
-
return <Slider defaultValue={[20, 80]} max={100} step={5} aria-label="
|
|
4
|
+
return <Slider defaultValue={[20, 80]} max={100} step={5} aria-label="Price range" className="max-w-sm" />;
|
|
5
5
|
}
|
|
@@ -32,19 +32,19 @@ const orders = [
|
|
|
32
32
|
{ hour: 15, orders: 38 },
|
|
33
33
|
];
|
|
34
34
|
|
|
35
|
-
const
|
|
36
|
-
{
|
|
37
|
-
{
|
|
38
|
-
{
|
|
35
|
+
const products = [
|
|
36
|
+
{ product: "Dinner set", revenue: 276000 },
|
|
37
|
+
{ product: "Standing desk", revenue: 224400 },
|
|
38
|
+
{ product: "Bookshelf", revenue: 166000 },
|
|
39
39
|
];
|
|
40
40
|
|
|
41
41
|
function Dashboard() {
|
|
42
42
|
const { money, moneyCompact, pct } = useFormat();
|
|
43
43
|
const kpis: MetricStripItem[] = [
|
|
44
|
-
{ label: "
|
|
45
|
-
{ label: "
|
|
46
|
-
{ label: "
|
|
47
|
-
{ label: "
|
|
44
|
+
{ label: "Revenue", value: money(4512300), change: 0.031 },
|
|
45
|
+
{ label: "Target", value: moneyCompact(4025000), change: 85000, changeFormat: "money" },
|
|
46
|
+
{ label: "Gross margin", value: pct(0.142), change: -0.004 },
|
|
47
|
+
{ label: "Cash flow", value: moneyCompact(-61200), change: -61200, changeFormat: "money" },
|
|
48
48
|
];
|
|
49
49
|
return (
|
|
50
50
|
<div className="flex flex-col gap-6">
|
|
@@ -61,22 +61,22 @@ function Dashboard() {
|
|
|
61
61
|
/>
|
|
62
62
|
<Card>
|
|
63
63
|
<CardHeader>
|
|
64
|
-
<CardTitle>
|
|
65
|
-
<CardDescription>Largest three</CardDescription>
|
|
64
|
+
<CardTitle>Top products</CardTitle>
|
|
65
|
+
<CardDescription>Largest three by revenue</CardDescription>
|
|
66
66
|
</CardHeader>
|
|
67
67
|
<CardContent>
|
|
68
68
|
<Table>
|
|
69
69
|
<TableHeader>
|
|
70
70
|
<TableRow>
|
|
71
|
-
<TableHead>
|
|
72
|
-
<TableHead>
|
|
71
|
+
<TableHead>Product</TableHead>
|
|
72
|
+
<TableHead>Revenue</TableHead>
|
|
73
73
|
</TableRow>
|
|
74
74
|
</TableHeader>
|
|
75
75
|
<TableBody>
|
|
76
|
-
{
|
|
77
|
-
<TableRow key={row.
|
|
78
|
-
<TableCell
|
|
79
|
-
<TableCell
|
|
76
|
+
{products.map((row) => (
|
|
77
|
+
<TableRow key={row.product}>
|
|
78
|
+
<TableCell>{row.product}</TableCell>
|
|
79
|
+
<TableCell>{money(row.revenue)}</TableCell>
|
|
80
80
|
</TableRow>
|
|
81
81
|
))}
|
|
82
82
|
</TableBody>
|
package/agents/examples/tabs.tsx
CHANGED
|
@@ -2,15 +2,15 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@siyahi/ui";
|
|
|
2
2
|
|
|
3
3
|
export default function TabsExample() {
|
|
4
4
|
return (
|
|
5
|
-
<Tabs defaultValue="
|
|
5
|
+
<Tabs defaultValue="orders">
|
|
6
6
|
<TabsList>
|
|
7
|
-
<TabsTrigger value="
|
|
8
|
-
<TabsTrigger value="
|
|
9
|
-
<TabsTrigger value="
|
|
7
|
+
<TabsTrigger value="orders">Orders</TabsTrigger>
|
|
8
|
+
<TabsTrigger value="returns">Returns</TabsTrigger>
|
|
9
|
+
<TabsTrigger value="payouts">Payouts</TabsTrigger>
|
|
10
10
|
</TabsList>
|
|
11
|
-
<TabsContent value="
|
|
12
|
-
<TabsContent value="
|
|
13
|
-
<TabsContent value="
|
|
11
|
+
<TabsContent value="orders">Every order placed, newest first.</TabsContent>
|
|
12
|
+
<TabsContent value="returns">Items sent back and the refunds paid for them.</TabsContent>
|
|
13
|
+
<TabsContent value="payouts">Money paid out to sellers each week.</TabsContent>
|
|
14
14
|
</Tabs>
|
|
15
15
|
);
|
|
16
16
|
}
|
|
@@ -10,60 +10,64 @@ import {
|
|
|
10
10
|
type TargetStatus,
|
|
11
11
|
} from "@siyahi/ui";
|
|
12
12
|
|
|
13
|
-
interface
|
|
13
|
+
interface Team {
|
|
14
14
|
name: string;
|
|
15
|
-
|
|
16
|
-
/**
|
|
15
|
+
costs: string;
|
|
16
|
+
/** The team's share of this year's spend so far and the budget's share, as fractions; made-up figures. */
|
|
17
17
|
weight: number;
|
|
18
18
|
target: number;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
{ name: "
|
|
23
|
-
{ name: "
|
|
24
|
-
{ name: "
|
|
25
|
-
{ name: "
|
|
26
|
-
{ name: "
|
|
21
|
+
const teams: Team[] = [
|
|
22
|
+
{ name: "Engineering", costs: "Cloud hosting, tools, contractors", weight: 0.426, target: 0.4 },
|
|
23
|
+
{ name: "Marketing", costs: "Ads, events, design agency", weight: 0.189, target: 0.2 },
|
|
24
|
+
{ name: "Sales", costs: "Travel, commissions, CRM seats", weight: 0.194, target: 0.25 },
|
|
25
|
+
{ name: "Support", costs: "Help desk seats, training", weight: 0.093, target: 0.1 },
|
|
26
|
+
{ name: "Operations", costs: "Office rent, facilities", weight: 0.098, target: 0.05 },
|
|
27
27
|
];
|
|
28
28
|
|
|
29
|
-
// Within two points of the
|
|
29
|
+
// Within two points of the budget is on target; past five is far enough to review it.
|
|
30
30
|
const NEAR = 0.02;
|
|
31
31
|
const FAR = 0.05;
|
|
32
32
|
|
|
33
33
|
const pts = (value: number) => `${(value * 100).toFixed(1)} pts`;
|
|
34
34
|
|
|
35
|
-
function statusOf({ weight, target }:
|
|
35
|
+
function statusOf({ weight, target }: Team): TargetStatus {
|
|
36
36
|
const gap = weight - target;
|
|
37
37
|
const size = `${pts(Math.abs(gap))} ${gap > 0 ? "over" : "under"}`;
|
|
38
38
|
if (Math.abs(gap) <= NEAR) return { kind: "met", label: "On target" };
|
|
39
39
|
if (Math.abs(gap) <= FAR) return { kind: "missed", label: size };
|
|
40
|
-
return { kind: "warning", label: `${size},
|
|
40
|
+
return { kind: "warning", label: `${size}, review` };
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export default function TargetRowsExample() {
|
|
44
44
|
const f = useFormat();
|
|
45
|
-
const rows: TargetRow[] =
|
|
46
|
-
label:
|
|
47
|
-
detail:
|
|
48
|
-
value:
|
|
49
|
-
target:
|
|
45
|
+
const rows: TargetRow[] = teams.map((team) => ({
|
|
46
|
+
label: team.name,
|
|
47
|
+
detail: team.costs,
|
|
48
|
+
value: team.weight,
|
|
49
|
+
target: team.target,
|
|
50
50
|
bands: [
|
|
51
|
-
[
|
|
52
|
-
[
|
|
51
|
+
[team.target - FAR, team.target + FAR],
|
|
52
|
+
[team.target - NEAR, team.target + NEAR],
|
|
53
53
|
],
|
|
54
|
-
status: statusOf(
|
|
54
|
+
status: statusOf(team),
|
|
55
55
|
}));
|
|
56
56
|
return (
|
|
57
57
|
<Card>
|
|
58
58
|
<CardHeader>
|
|
59
|
-
<CardTitle>
|
|
60
|
-
<CardDescription>
|
|
59
|
+
<CardTitle>Sales is 5.6 points under its budget</CardTitle>
|
|
60
|
+
<CardDescription>
|
|
61
|
+
Each team's share of spend against its share of the budget, on one 0–50% scale
|
|
62
|
+
</CardDescription>
|
|
61
63
|
</CardHeader>
|
|
62
|
-
<CardContent
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
<CardContent>
|
|
65
|
+
<div className="grid gap-2">
|
|
66
|
+
<p className="text-sm text-muted-foreground">
|
|
67
|
+
Bar: the share spent so far. Tall tick: the budgeted share. Shading: within 5 points of it, darker within 2.
|
|
68
|
+
</p>
|
|
69
|
+
<TargetRows rows={rows} domain={[0, 0.5]} valueFormatter={(value) => f.pct(value)} />
|
|
70
|
+
</div>
|
|
67
71
|
</CardContent>
|
|
68
72
|
</Card>
|
|
69
73
|
);
|
|
@@ -4,10 +4,10 @@ import { InfoIcon } from "lucide-react";
|
|
|
4
4
|
export default function TooltipExample() {
|
|
5
5
|
return (
|
|
6
6
|
<Tooltip>
|
|
7
|
-
<TooltipTrigger render={<Button variant="outline" size="icon" aria-label="About
|
|
7
|
+
<TooltipTrigger render={<Button variant="outline" size="icon" aria-label="About churn" />}>
|
|
8
8
|
<InfoIcon />
|
|
9
9
|
</TooltipTrigger>
|
|
10
|
-
<TooltipContent>
|
|
10
|
+
<TooltipContent>Churn counts customers who did not renew this month.</TooltipContent>
|
|
11
11
|
</Tooltip>
|
|
12
12
|
);
|
|
13
13
|
}
|