@siyahi/ui 0.1.9-next.3 → 0.1.9-next.31
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 +251 -0
- package/README.md +94 -177
- package/THIRD_PARTY_NOTICES.md +11 -11
- package/agents/examples/accordion.tsx +39 -0
- package/agents/examples/alert.tsx +24 -0
- package/agents/examples/app-sidebar.tsx +40 -0
- package/agents/examples/avatar.tsx +24 -0
- package/agents/examples/badge.tsx +26 -0
- package/agents/examples/bar-list-labels.tsx +22 -0
- package/agents/examples/bar-list-sides.tsx +40 -0
- package/agents/examples/bar-list.tsx +24 -0
- package/agents/examples/breadcrumb.tsx +28 -0
- package/agents/examples/button-states.tsx +23 -0
- package/agents/examples/button.tsx +21 -0
- package/agents/examples/calendar.tsx +11 -0
- package/agents/examples/callout.tsx +33 -0
- package/agents/examples/card.tsx +36 -0
- package/agents/examples/change-bar.tsx +104 -0
- package/agents/examples/change-grid-money.tsx +36 -0
- package/agents/examples/change-grid.tsx +43 -0
- package/agents/examples/chart-area-log.tsx +45 -0
- package/agents/examples/chart-area.tsx +39 -0
- package/agents/examples/chart-bar-flows.tsx +32 -0
- package/agents/examples/chart-bar-hourly.tsx +28 -0
- package/agents/examples/chart-bar-losses.tsx +29 -0
- package/agents/examples/chart-bar-teams.tsx +72 -0
- package/agents/examples/chart-bar-years.tsx +42 -0
- package/agents/examples/chart-bar.tsx +56 -0
- package/agents/examples/chart-category-ticks.tsx +50 -0
- package/agents/examples/chart-line-events.tsx +47 -0
- package/agents/examples/chart-line-forecast.tsx +36 -0
- package/agents/examples/chart-line-log.tsx +39 -0
- package/agents/examples/chart-line-quiet.tsx +114 -0
- package/agents/examples/chart-line-timeline.tsx +41 -0
- package/agents/examples/chart-line.tsx +57 -0
- package/agents/examples/chart-panels.tsx +94 -0
- package/agents/examples/code-block.tsx +40 -0
- package/agents/examples/collapsible.tsx +18 -0
- package/agents/examples/command.tsx +29 -0
- package/agents/examples/context-menu.tsx +17 -0
- package/agents/examples/copy-button.tsx +8 -0
- package/agents/examples/data-bar.tsx +114 -0
- package/agents/examples/data-table-compact.tsx +93 -0
- package/agents/examples/data-table-filters.tsx +103 -0
- package/agents/examples/data-table.tsx +96 -0
- package/agents/examples/delta.tsx +18 -0
- package/agents/examples/dialog.tsx +28 -0
- package/agents/examples/distribution-bar-budget.tsx +30 -0
- package/agents/examples/distribution-bar-tug.tsx +74 -0
- package/agents/examples/drawdown-chart.tsx +35 -0
- package/agents/examples/dropdown-menu.tsx +31 -0
- package/agents/examples/field.tsx +108 -0
- package/agents/examples/formatters.tsx +42 -0
- package/agents/examples/heatmap-calendar-signed.tsx +67 -0
- package/agents/examples/heatmap-calendar.tsx +62 -0
- package/agents/examples/heatmap-status.tsx +61 -0
- package/agents/examples/heatmap-weekday.tsx +72 -0
- package/agents/examples/histogram-chart.tsx +28 -0
- package/agents/examples/input-states.tsx +23 -0
- package/agents/examples/input.tsx +17 -0
- package/agents/examples/local-time.tsx +14 -0
- package/agents/examples/metric-strip.tsx +46 -0
- package/agents/examples/overview-dashboard.tsx +180 -0
- package/agents/examples/page-hero.tsx +38 -0
- package/agents/examples/page-section.tsx +52 -0
- package/agents/examples/popover.tsx +23 -0
- package/agents/examples/price-chart.tsx +32 -0
- package/agents/examples/progress-tone.tsx +29 -0
- package/agents/examples/progress.tsx +10 -0
- package/agents/examples/range-position-table.tsx +113 -0
- package/agents/examples/range-position.tsx +55 -0
- package/agents/examples/scatter-chart-quadrants.tsx +63 -0
- package/agents/examples/scatter-chart-scales.tsx +46 -0
- package/agents/examples/scatter-chart.tsx +78 -0
- package/agents/examples/scroll-area.tsx +22 -0
- package/agents/examples/section-cards-select.tsx +28 -0
- package/agents/examples/section-cards-trend.tsx +32 -0
- package/agents/examples/section-cards.tsx +48 -0
- package/agents/examples/select.tsx +27 -0
- package/agents/examples/separator.tsx +13 -0
- package/agents/examples/sheet.tsx +15 -0
- package/agents/examples/skeleton.tsx +11 -0
- package/agents/examples/slider.tsx +5 -0
- package/agents/examples/slope-chart-market.tsx +33 -0
- package/agents/examples/slope-chart.tsx +26 -0
- package/agents/examples/stale-blocks.tsx +56 -0
- package/agents/examples/surfaces.tsx +116 -0
- package/agents/examples/table.tsx +60 -0
- package/agents/examples/tabs.tsx +16 -0
- package/agents/examples/target-rows.tsx +74 -0
- package/agents/examples/toggle-group.tsx +12 -0
- package/agents/examples/toggle.tsx +11 -0
- package/agents/examples/tooltip.tsx +13 -0
- package/agents/examples/treemap.tsx +93 -0
- package/agents/examples/waterfall-chart-stores.tsx +27 -0
- package/agents/examples/waterfall-chart.tsx +37 -0
- package/agents/manifest.json +1391 -0
- package/agents/report-rules.json +7 -0
- package/dist/components/registry/charts/area-chart-card.d.ts +7 -3
- package/dist/components/registry/charts/area-chart-card.js +56 -10
- package/dist/components/registry/charts/bar-chart-card.d.ts +1 -1
- package/dist/components/registry/charts/bar-chart-card.js +20 -22
- package/dist/components/registry/charts/line-chart-card.d.ts +3 -3
- package/dist/components/registry/charts/line-chart-card.js +44 -9
- package/dist/components/registry/dashboard-01/section-cards.d.ts +6 -0
- package/dist/components/registry/dashboard-01/section-cards.js +51 -35
- package/dist/components/registry/dashboardcn/bar-list.js +17 -10
- package/dist/components/registry/dashboardcn/distribution-bar.js +6 -4
- package/dist/components/registry/dashboardcn/kpi-row-card.d.ts +29 -0
- package/dist/components/registry/dashboardcn/kpi-row-card.js +81 -0
- package/dist/components/registry/dashboardcn/sparkline.d.ts +22 -0
- package/dist/components/registry/dashboardcn/sparkline.js +117 -0
- package/dist/components/registry/heatmap/calendar-heatmap.d.ts +11 -3
- package/dist/components/registry/heatmap/calendar-heatmap.js +164 -45
- package/dist/components/registry/heatmap/status-heatmap.d.ts +5 -3
- package/dist/components/registry/heatmap/status-heatmap.js +115 -54
- package/dist/components/registry/heatmap/weekday-heatmap.d.ts +9 -3
- package/dist/components/registry/heatmap/weekday-heatmap.js +83 -53
- package/dist/components/registry/niko-table/core/data-table-context.d.ts +18 -1
- package/dist/components/registry/niko-table/core/data-table-context.js +7 -1
- package/dist/components/registry/niko-table/core/data-table-grouped-row.js +3 -1
- package/dist/components/registry/niko-table/core/data-table-root.js +39 -4
- package/dist/components/registry/niko-table/core/data-table-structure.js +17 -12
- package/dist/components/registry/niko-table/core/data-table.d.ts +2 -2
- package/dist/components/registry/niko-table/core/data-table.js +5 -1
- package/dist/components/registry/niko-table/filters/table-faceted-filter.js +5 -5
- package/dist/components/registry/niko-table/filters/table-search-filter.js +1 -1
- package/dist/components/registry/niko-table/lib/flex-columns.d.ts +1 -1
- package/dist/components/registry/niko-table/lib/flex-columns.js +3 -3
- package/dist/components/registry/niko-table/lib/styles.d.ts +1 -1
- package/dist/components/registry/niko-table/lib/styles.js +3 -3
- package/dist/components/registry/niko-table/types/index.d.ts +9 -0
- package/dist/components/registry/niko-table/ui/table.js +2 -2
- package/dist/components/registry/sidebar-07/app-sidebar.d.ts +1 -1
- package/dist/components/registry/sidebar-07/app-sidebar.js +3 -1
- package/dist/components/registry/sidebar-07/nav-main.d.ts +2 -1
- package/dist/components/registry/sidebar-07/nav-main.js +16 -3
- package/dist/components/siyahi/callout.d.ts +17 -0
- package/dist/components/siyahi/callout.js +34 -0
- package/dist/components/siyahi/change-bar.d.ts +21 -0
- package/dist/components/siyahi/change-bar.js +35 -0
- package/dist/components/siyahi/change-grid.d.ts +31 -0
- package/dist/components/siyahi/change-grid.js +74 -0
- package/dist/components/siyahi/data-bar.d.ts +19 -0
- package/dist/components/siyahi/data-bar.js +29 -0
- package/dist/components/siyahi/data-table-compact-columns-toggle.d.ts +4 -0
- package/dist/components/siyahi/data-table-compact-columns-toggle.js +19 -0
- package/dist/components/siyahi/data-table-footnote.d.ts +12 -0
- package/dist/components/siyahi/data-table-footnote.js +35 -0
- package/dist/components/siyahi/default-sidebar-open.d.ts +8 -0
- package/dist/components/siyahi/default-sidebar-open.js +13 -0
- package/dist/components/siyahi/delta.d.ts +5 -1
- package/dist/components/siyahi/delta.js +14 -9
- package/dist/components/siyahi/drawdown-chart.d.ts +34 -0
- package/dist/components/siyahi/drawdown-chart.js +102 -0
- package/dist/components/siyahi/histogram-chart.d.ts +57 -0
- package/dist/components/siyahi/histogram-chart.js +134 -0
- package/dist/components/siyahi/page-hero.d.ts +23 -0
- package/dist/components/siyahi/page-hero.js +43 -0
- package/dist/components/siyahi/page-section.d.ts +4 -1
- package/dist/components/siyahi/page-section.js +6 -3
- package/dist/components/siyahi/page-toc.d.ts +20 -0
- package/dist/components/siyahi/page-toc.js +76 -0
- package/dist/components/siyahi/panel-grid.d.ts +24 -0
- package/dist/components/siyahi/panel-grid.js +37 -0
- package/dist/components/siyahi/quote.d.ts +12 -0
- package/dist/components/siyahi/quote.js +23 -0
- package/dist/components/siyahi/range-position.d.ts +24 -0
- package/dist/components/siyahi/range-position.js +105 -0
- package/dist/components/siyahi/scale-toggle.d.ts +32 -0
- package/dist/components/siyahi/scale-toggle.js +61 -0
- package/dist/components/siyahi/scatter-chart.d.ts +69 -0
- package/dist/components/siyahi/scatter-chart.js +395 -0
- package/dist/components/siyahi/siyahi-provider.d.ts +15 -2
- package/dist/components/siyahi/siyahi-provider.js +17 -4
- package/dist/components/siyahi/slope-chart.d.ts +35 -0
- package/dist/components/siyahi/slope-chart.js +159 -0
- package/dist/components/siyahi/stale-note.d.ts +9 -0
- package/dist/components/siyahi/stale-note.js +12 -0
- 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/target-rows.d.ts +34 -0
- package/dist/components/siyahi/target-rows.js +97 -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 +8 -5
- package/dist/components/siyahi/treemap.js +80 -34
- package/dist/components/siyahi/waterfall-chart.d.ts +51 -0
- package/dist/components/siyahi/waterfall-chart.js +147 -0
- package/dist/components/ui/accordion.js +5 -5
- package/dist/components/ui/alert.js +2 -2
- package/dist/components/ui/badge.js +1 -1
- package/dist/components/ui/breadcrumb.js +2 -2
- package/dist/components/ui/button.js +10 -10
- package/dist/components/ui/calendar.js +1 -1
- package/dist/components/ui/card.js +4 -4
- package/dist/components/ui/chart.js +1 -1
- package/dist/components/ui/code-block.js +13 -12
- package/dist/components/ui/command.js +7 -6
- package/dist/components/ui/context-menu.js +7 -7
- package/dist/components/ui/dialog.js +5 -5
- package/dist/components/ui/dropdown-menu.js +8 -8
- package/dist/components/ui/field.d.ts +26 -0
- package/dist/components/ui/field.js +109 -0
- package/dist/components/ui/input-group.js +11 -11
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/label.d.ts +5 -0
- package/dist/components/ui/label.js +13 -0
- package/dist/components/ui/popover.js +3 -3
- package/dist/components/ui/progress.js +1 -1
- package/dist/components/ui/select.js +6 -6
- package/dist/components/ui/sheet.js +5 -5
- package/dist/components/ui/sidebar.js +17 -18
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/slider.js +2 -2
- package/dist/components/ui/table.js +2 -2
- package/dist/components/ui/tabs.js +2 -2
- package/dist/components/ui/textarea.js +1 -1
- package/dist/components/ui/toggle-group.js +2 -2
- package/dist/components/ui/toggle.js +4 -4
- package/dist/components/ui/tooltip.js +2 -2
- package/dist/index.d.ts +35 -8
- package/dist/index.js +30 -4
- package/dist/lib/chart-frame.d.ts +51 -7
- package/dist/lib/chart-frame.js +390 -133
- package/dist/lib/chart-marks.d.ts +83 -0
- package/dist/lib/chart-marks.js +216 -0
- package/dist/lib/chart-series.d.ts +42 -10
- package/dist/lib/compact-columns.d.ts +19 -0
- package/dist/lib/compact-columns.js +55 -0
- package/dist/lib/fit-text.d.ts +6 -0
- package/dist/lib/fit-text.js +11 -0
- package/dist/lib/format.d.ts +8 -3
- package/dist/lib/format.js +55 -17
- package/dist/lib/heat.d.ts +7 -0
- package/dist/lib/heat.js +14 -0
- package/dist/lib/heatmap-navigation.d.ts +8 -0
- package/dist/lib/heatmap-navigation.js +49 -0
- package/dist/lib/scatter.d.ts +88 -0
- package/dist/lib/scatter.js +179 -0
- package/dist/lib/ticks.d.ts +27 -0
- package/dist/lib/ticks.js +67 -0
- package/dist/lib/tone.d.ts +36 -0
- package/dist/lib/tone.js +35 -0
- package/dist/lib/treemap.d.ts +0 -5
- package/dist/lib/treemap.js +1 -11
- package/dist/lib/use-element-width.d.ts +5 -0
- package/dist/lib/use-element-width.js +15 -0
- package/package.json +5 -1
- package/registry.lock.json +16 -0
- package/report.css +63 -47
- package/styles/siyahi.css +708 -55
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { ScatterChartCard, useFormat, type ScatterPoint } from "@siyahi/ui";
|
|
3
|
+
|
|
4
|
+
// A grocer's products this quarter against last: x is the change in shelf price, y the change in units sold, and
|
|
5
|
+
// size the quarter's revenue; made-up figures. Largest first, so the biggest sellers take the labels.
|
|
6
|
+
const products: ScatterPoint[] = [
|
|
7
|
+
{ name: "Basmati rice 5 kg", x: 0.06, y: -0.04, size: 1_840_000 },
|
|
8
|
+
{ name: "Sunflower oil 1 L", x: -0.08, y: 0.12, size: 1_520_000 },
|
|
9
|
+
{ name: "Full-cream milk", x: 0.03, y: 0.05, size: 1_310_000 },
|
|
10
|
+
{ name: "Atta 10 kg", x: 0.04, y: -0.09, size: 1_120_000 },
|
|
11
|
+
{ name: "Tea 500 g", x: -0.02, y: 0.08, size: 760_000 },
|
|
12
|
+
{ name: "Paneer 200 g", x: 0.09, y: 0.11, size: 640_000 },
|
|
13
|
+
{ name: "Toor dal 1 kg", x: 0.12, y: -0.18, size: 590_000 },
|
|
14
|
+
{ name: "Biscuits family pack", x: -0.05, y: -0.03, size: 420_000 },
|
|
15
|
+
{ name: "Instant noodles", x: 0.01, y: 0.21, size: 380_000 },
|
|
16
|
+
{ name: "Dish soap", x: -0.1, y: -0.07, size: 260_000 },
|
|
17
|
+
{ name: "Ghee 500 ml", x: 0.07, y: 0.02, size: 240_000 },
|
|
18
|
+
{ name: "Coffee 200 g", x: -0.04, y: 0.15, size: 190_000 },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export default function ScatterChartQuadrantsExample() {
|
|
22
|
+
const [selected, setSelected] = useState<ScatterPoint | null>(null);
|
|
23
|
+
const { moneyCompact, pct } = useFormat();
|
|
24
|
+
const signed = (value: number) => `${value > 0 ? "+" : value < 0 ? "−" : ""}${pct(Math.abs(value))}`;
|
|
25
|
+
return (
|
|
26
|
+
<ScatterChartCard
|
|
27
|
+
title="Products by price and sales"
|
|
28
|
+
description="This quarter against last. Across is the change in shelf price, up the change in units sold; a dot's area is the quarter's revenue."
|
|
29
|
+
points={products}
|
|
30
|
+
height={380}
|
|
31
|
+
xLabel="Change in price"
|
|
32
|
+
yLabel="Change in units sold"
|
|
33
|
+
xFormatter={signed}
|
|
34
|
+
yFormatter={signed}
|
|
35
|
+
sizeLabel="Revenue"
|
|
36
|
+
sizeFormatter={(value) => moneyCompact(value)}
|
|
37
|
+
selected={selected}
|
|
38
|
+
onSelect={setSelected}
|
|
39
|
+
footer={
|
|
40
|
+
<p data-slot="scatter-selection" aria-live="polite" className="tabular-nums">
|
|
41
|
+
{selected ? (
|
|
42
|
+
<>
|
|
43
|
+
<span className="font-medium">{selected.name}</span> · price {signed(selected.x)} · units{" "}
|
|
44
|
+
{signed(selected.y ?? 0)} · {moneyCompact(selected.size ?? 0)} revenue
|
|
45
|
+
</>
|
|
46
|
+
) : (
|
|
47
|
+
<span className="text-muted-foreground">Tap a dot, or Tab to the chart and use the arrow keys</span>
|
|
48
|
+
)}
|
|
49
|
+
</p>
|
|
50
|
+
}
|
|
51
|
+
quadrants={{
|
|
52
|
+
x: 0,
|
|
53
|
+
y: 0,
|
|
54
|
+
labels: {
|
|
55
|
+
topLeft: "Cheaper, sells more",
|
|
56
|
+
topRight: "Dearer, still sells more",
|
|
57
|
+
bottomLeft: "Cheaper, sells less",
|
|
58
|
+
bottomRight: "Dearer, sells less",
|
|
59
|
+
},
|
|
60
|
+
}}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ScatterChartCard, useFormat, type ScatterPoint } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
// A shop's products this month: x is units sold, y the shelf price; made-up figures. Both run from a few to
|
|
4
|
+
// thousands, so both axes open on log. Largest sellers first, so they take the labels.
|
|
5
|
+
const products: ScatterPoint[] = [
|
|
6
|
+
{ name: "Milk 500 ml", x: 38000, y: 32 },
|
|
7
|
+
{ name: "Bread", x: 21000, y: 45 },
|
|
8
|
+
{ name: "Eggs, 6", x: 14500, y: 60 },
|
|
9
|
+
{ name: "Tea 250 g", x: 6200, y: 140 },
|
|
10
|
+
{ name: "Atta 5 kg", x: 4800, y: 260 },
|
|
11
|
+
{ name: "Rice 5 kg", x: 3900, y: 420 },
|
|
12
|
+
{ name: "Oil 1 L", x: 3100, y: 180 },
|
|
13
|
+
{ name: "Ghee 500 ml", x: 1400, y: 340 },
|
|
14
|
+
{ name: "Coffee 200 g", x: 900, y: 480 },
|
|
15
|
+
{ name: "Dry fruit box", x: 260, y: 1200 },
|
|
16
|
+
{ name: "Saffron 1 g", x: 120, y: 350 },
|
|
17
|
+
{ name: "Olive oil 1 L", x: 95, y: 980 },
|
|
18
|
+
{ name: "Gift hamper", x: 40, y: 3500 },
|
|
19
|
+
{ name: "Mixer grinder", x: 18, y: 4200 },
|
|
20
|
+
{ name: "Pressure cooker", x: 25, y: 2100 },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
export default function ScatterChartScalesExample() {
|
|
24
|
+
const { count, money } = useFormat();
|
|
25
|
+
return (
|
|
26
|
+
<ScatterChartCard
|
|
27
|
+
title="A few cheap products sell most of the units"
|
|
28
|
+
description="Units sold this month against shelf price. Both axes switch: each pair of buttons is named for its axis."
|
|
29
|
+
points={products}
|
|
30
|
+
height={360}
|
|
31
|
+
xLabel="Units sold"
|
|
32
|
+
yLabel="Price"
|
|
33
|
+
xScale="log"
|
|
34
|
+
xScaleToggle
|
|
35
|
+
yScale="log"
|
|
36
|
+
yScaleToggle
|
|
37
|
+
xFormatter={count}
|
|
38
|
+
yFormatter={(value) => money(value)}
|
|
39
|
+
quadrants={{
|
|
40
|
+
x: 1000,
|
|
41
|
+
y: 500,
|
|
42
|
+
labels: { topLeft: "Dear, few sold", bottomRight: "Cheap, many sold" },
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Badge, ScatterChartCard, useFormat, type ScatterPoint } from "@siyahi/ui";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
|
|
4
|
+
interface Store extends ScatterPoint {
|
|
5
|
+
region: string;
|
|
6
|
+
sales: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// x is the store's share of the month's sales and y its growth on the same month last year; the numbers are made up
|
|
10
|
+
// for the catalogue. The Guwahati store opened this year, so it has no growth to plot. Largest first, so the biggest
|
|
11
|
+
// stores take the labels.
|
|
12
|
+
const stores: Store[] = [
|
|
13
|
+
{ name: "Delhi Saket", region: "North", x: 0.112, y: 0.27, sales: 2760000 },
|
|
14
|
+
{ name: "Bengaluru MG", region: "South", x: 0.106, y: -0.06, sales: 2625000 },
|
|
15
|
+
{ name: "Chennai T Nagar", region: "South", x: 0.104, y: 0.44, sales: 2580000 },
|
|
16
|
+
{ name: "Kolkata Park St", region: "East", x: 0.103, y: 0.16, sales: 2556000 },
|
|
17
|
+
{ name: "Mumbai Online", key: "mumbai-online", region: "West", x: 0.091, y: 0.38, sales: 2244000 },
|
|
18
|
+
{ name: "Pune Camp", region: "West", x: 0.067, y: 0.09, sales: 1660000 },
|
|
19
|
+
{ name: "Mumbai Bandra", key: "mumbai-bandra", region: "West", x: 0.061, y: 0.12, sales: 1520000 },
|
|
20
|
+
{ name: "Hyderabad", region: "South", x: 0.052, y: -0.14, sales: 1290000 },
|
|
21
|
+
{ name: "Ahmedabad", region: "West", x: 0.044, y: 0.05, sales: 1090000 },
|
|
22
|
+
{ name: "Surat", region: "West", x: 0.04, y: -0.21, sales: 980000 },
|
|
23
|
+
{ name: "Kochi", region: "South", x: 0.035, y: 0.58, sales: 870000 },
|
|
24
|
+
{ name: "Lucknow", region: "North", x: 0.031, y: -0.02, sales: 770000 },
|
|
25
|
+
{ name: "Jaipur", region: "North", x: 0.026, y: -0.33, sales: 640000 },
|
|
26
|
+
{ name: "Bhubaneswar", region: "East", x: 0.021, y: 0.22, sales: 520000 },
|
|
27
|
+
{ name: "Indore", region: "Central", x: 0.018, y: 0.31, sales: 450000 },
|
|
28
|
+
{ name: "Bhopal", region: "Central", x: 0.012, y: -0.09, sales: 300000 },
|
|
29
|
+
{ name: "Patna", region: "East", x: 0.009, y: 0.47, sales: 220000 },
|
|
30
|
+
{ name: "Nagpur", region: "Central", x: 0.007, y: 0.02, sales: 170000 },
|
|
31
|
+
{ name: "Shillong", region: "Northeast", x: 0.004, y: -0.18, sales: 100000 },
|
|
32
|
+
{ name: "Guwahati", region: "Northeast", x: 0.021, y: null, sales: 520000 },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export default function ScatterChartExample() {
|
|
36
|
+
const [selected, setSelected] = useState<Store | null>(null);
|
|
37
|
+
const { money, pct } = useFormat();
|
|
38
|
+
const growth = (y: number | null) => (y === null ? "new this year" : `${y < 0 ? "−" : "+"}${pct(Math.abs(y))}`);
|
|
39
|
+
const missing = stores.filter((s) => s.y === null).length;
|
|
40
|
+
return (
|
|
41
|
+
<ScatterChartCard
|
|
42
|
+
title="Stores by size and growth"
|
|
43
|
+
description="Across is the store's share of sales, up its growth on last year. Log spreads out the small stores; Linear shows how far ahead the largest are."
|
|
44
|
+
action={<Badge variant="outline">This month</Badge>}
|
|
45
|
+
points={stores}
|
|
46
|
+
height={360}
|
|
47
|
+
xLabel="Share of sales"
|
|
48
|
+
yLabel="Growth"
|
|
49
|
+
// Log is selected first; the buttons in the header let the reader switch.
|
|
50
|
+
xScale="log"
|
|
51
|
+
xScaleToggle
|
|
52
|
+
xFormatter={(x) => pct(x)}
|
|
53
|
+
yFormatter={(y) => growth(y)}
|
|
54
|
+
details={(s) => [
|
|
55
|
+
["Region", s.region],
|
|
56
|
+
["Sales", money(s.sales)],
|
|
57
|
+
["Growth", growth(s.y)],
|
|
58
|
+
]}
|
|
59
|
+
selected={selected}
|
|
60
|
+
onSelect={setSelected}
|
|
61
|
+
footer={
|
|
62
|
+
<>
|
|
63
|
+
<p data-slot="scatter-selection" aria-live="polite" className="tabular-nums">
|
|
64
|
+
{selected ? (
|
|
65
|
+
<>
|
|
66
|
+
<span className="font-medium">{selected.name}</span> · {selected.region} · {money(selected.sales)} ·{" "}
|
|
67
|
+
{growth(selected.y)}
|
|
68
|
+
</>
|
|
69
|
+
) : (
|
|
70
|
+
<span className="text-muted-foreground">Tap a dot for its figures</span>
|
|
71
|
+
)}
|
|
72
|
+
</p>
|
|
73
|
+
<p className="text-muted-foreground">{missing} store opened this year and has no growth to plot.</p>
|
|
74
|
+
</>
|
|
75
|
+
}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ScrollArea, Separator } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
const months = Array.from({ length: 24 }, (_, i) =>
|
|
4
|
+
new Date(2025, i, 1).toLocaleString("en-IN", { month: "long", year: "numeric" }),
|
|
5
|
+
);
|
|
6
|
+
|
|
7
|
+
export default function ScrollAreaExample() {
|
|
8
|
+
return (
|
|
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>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Delta, SectionCards, useFormat, type SectionCard } from "@siyahi/ui";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
|
|
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 },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export default function SectionCardsSelectExample() {
|
|
13
|
+
const [scope, setScope] = useState("All");
|
|
14
|
+
const { count } = useFormat();
|
|
15
|
+
const items: SectionCard[] = channels.map((c) => ({
|
|
16
|
+
label: c.label,
|
|
17
|
+
value: <Delta value={c.net} format="money" />,
|
|
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,
|
|
21
|
+
}));
|
|
22
|
+
return (
|
|
23
|
+
<div className="flex flex-col gap-3">
|
|
24
|
+
<SectionCards items={items} selected={scope} onSelect={setScope} />
|
|
25
|
+
<p className="text-sm text-muted-foreground">Showing {scope}</p>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Delta, SectionCards, Sparkline, useFormat, type SectionCard } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function SectionCardsTrendExample() {
|
|
4
|
+
const { money, moneyCompact } = useFormat();
|
|
5
|
+
const items: SectionCard[] = [
|
|
6
|
+
{
|
|
7
|
+
label: "Revenue",
|
|
8
|
+
value: money(4512300),
|
|
9
|
+
badge: <Delta value={0.031} />,
|
|
10
|
+
trend: <Sparkline data={[3820000, 3950000, 4110000, 4020000, 4380000, 4512300]} />,
|
|
11
|
+
detail: "Month-end, last six months",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
label: "Cash flow this year",
|
|
15
|
+
value: moneyCompact(-61200),
|
|
16
|
+
badge: <Delta value={-61200} format="money" />,
|
|
17
|
+
// A run of losses: the meaning colour, not a chart slot.
|
|
18
|
+
trend: <Sparkline data={[0, -8200, -14100, -30400, -52800, -61200]} color="var(--negative)" />,
|
|
19
|
+
detail: "Running total since April",
|
|
20
|
+
// The one figure on the page that needs a look, marked by the page: a falling cost would not be.
|
|
21
|
+
tone: "negative",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
label: "Gift cards this year",
|
|
25
|
+
value: moneyCompact(38400),
|
|
26
|
+
badge: <Delta value={0.18} />,
|
|
27
|
+
trend: <Sparkline data={[4100, 0, 12800, 3300, 9900, 8300]} variant="line" curve="linear" />,
|
|
28
|
+
detail: "Sold each month",
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
return <SectionCards items={items} />;
|
|
32
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Delta, SectionCards, type SectionCard, useFormat } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function SectionCardsExample() {
|
|
4
|
+
const { money, moneyCompact } = useFormat();
|
|
5
|
+
const items: SectionCard[] = [
|
|
6
|
+
{
|
|
7
|
+
label: "Revenue",
|
|
8
|
+
value: money(4512300),
|
|
9
|
+
badge: <Delta value={0.031} />,
|
|
10
|
+
headline: "Up for the third month",
|
|
11
|
+
detail: "Paid orders, less refunds",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
label: "Target",
|
|
15
|
+
value: money(4025000),
|
|
16
|
+
headline: "Set at the start of the quarter",
|
|
17
|
+
detail: "Across 4 stores",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: "Ahead of target",
|
|
21
|
+
value: moneyCompact(487300),
|
|
22
|
+
badge: <Delta value={0.121} />,
|
|
23
|
+
headline: "Gross margin 14.2%",
|
|
24
|
+
detail: "Since April",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: "Cash flow this year",
|
|
28
|
+
value: moneyCompact(-61200),
|
|
29
|
+
badge: <Delta value={-61200} format="money" />,
|
|
30
|
+
headline: "Two large inventory buys",
|
|
31
|
+
detail: "Before tax",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
label: "Gift cards this year",
|
|
35
|
+
value: moneyCompact(38400),
|
|
36
|
+
badge: <Delta value={0.18} />,
|
|
37
|
+
headline: "Sold in 11 stores",
|
|
38
|
+
detail: "Paid at purchase",
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
return (
|
|
42
|
+
<div className="flex flex-col gap-6">
|
|
43
|
+
<SectionCards items={items.slice(0, 3)} />
|
|
44
|
+
<SectionCards items={items.slice(0, 4)} />
|
|
45
|
+
<SectionCards items={items} />
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@siyahi/ui";
|
|
2
|
+
|
|
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
|
+
];
|
|
9
|
+
|
|
10
|
+
export default function SelectExample() {
|
|
11
|
+
return (
|
|
12
|
+
<Select items={stores} defaultValue="all">
|
|
13
|
+
<SelectTrigger className="w-48">
|
|
14
|
+
<SelectValue />
|
|
15
|
+
</SelectTrigger>
|
|
16
|
+
<SelectContent>
|
|
17
|
+
<SelectGroup>
|
|
18
|
+
{stores.map((store) => (
|
|
19
|
+
<SelectItem key={store.value} value={store.value}>
|
|
20
|
+
{store.label}
|
|
21
|
+
</SelectItem>
|
|
22
|
+
))}
|
|
23
|
+
</SelectGroup>
|
|
24
|
+
</SelectContent>
|
|
25
|
+
</Select>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Separator } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function SeparatorExample() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="flex h-6 items-center gap-4 text-sm">
|
|
6
|
+
<span>Orders</span>
|
|
7
|
+
<Separator orientation="vertical" />
|
|
8
|
+
<span>Customers</span>
|
|
9
|
+
<Separator orientation="vertical" />
|
|
10
|
+
<span>Products</span>
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Button, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function SheetExample() {
|
|
4
|
+
return (
|
|
5
|
+
<Sheet>
|
|
6
|
+
<SheetTrigger render={<Button variant="outline" className="w-fit" />}>Filters</SheetTrigger>
|
|
7
|
+
<SheetContent>
|
|
8
|
+
<SheetHeader>
|
|
9
|
+
<SheetTitle>Filters</SheetTitle>
|
|
10
|
+
<SheetDescription>Narrow the orders by store, status or date.</SheetDescription>
|
|
11
|
+
</SheetHeader>
|
|
12
|
+
</SheetContent>
|
|
13
|
+
</Sheet>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Skeleton } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function SkeletonExample() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="flex max-w-sm flex-col gap-2">
|
|
6
|
+
<Skeleton className="h-4 w-32" />
|
|
7
|
+
<Skeleton className="h-8 w-48" />
|
|
8
|
+
<Skeleton className="h-4 w-full" />
|
|
9
|
+
</div>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle, SlopeChart, type SlopeItem } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
// Each aisle's share of one grocery store's sales against its share across the region's stores; made-up figures.
|
|
4
|
+
const items: SlopeItem[] = [
|
|
5
|
+
{ name: "Fresh fruit and vegetables", from: 0.18, to: 0.24 },
|
|
6
|
+
{ name: "Dairy and eggs", from: 0.14, to: 0.15 },
|
|
7
|
+
{ name: "Bakery", from: 0.07, to: 0.11 },
|
|
8
|
+
{ name: "Rice, flour and pulses", from: 0.16, to: 0.12 },
|
|
9
|
+
{ name: "Snacks and drinks", from: 0.15, to: 0.13 },
|
|
10
|
+
{ name: "Household and cleaning", from: 0.11, to: 0.08 },
|
|
11
|
+
{ name: "Personal care", from: 0.09, to: 0.08 },
|
|
12
|
+
{ name: "Frozen food", from: 0.06, to: 0.05 },
|
|
13
|
+
{ name: "Baby care", from: 0.04, to: 0.04 },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// The aisles at least three points away from the region, either way.
|
|
17
|
+
const apart = items.filter(({ from, to }) => Math.abs(to - from) >= 0.03).map(({ name }) => name);
|
|
18
|
+
|
|
19
|
+
export default function SlopeChartMarketExample() {
|
|
20
|
+
return (
|
|
21
|
+
<Card>
|
|
22
|
+
<CardHeader>
|
|
23
|
+
<CardTitle>Our aisles against the region</CardTitle>
|
|
24
|
+
<CardDescription>
|
|
25
|
+
Share of sales by aisle. Aisles three points or more away from the region are drawn in colour.
|
|
26
|
+
</CardDescription>
|
|
27
|
+
</CardHeader>
|
|
28
|
+
<CardContent>
|
|
29
|
+
<SlopeChart items={items} fromLabel="Region" toLabel="This store, this year" highlighted={apart} />
|
|
30
|
+
</CardContent>
|
|
31
|
+
</Card>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle, SlopeChart, type SlopeItem } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
// Each channel's share of a bookshop's sales, last year and this; made-up figures.
|
|
4
|
+
const items: SlopeItem[] = [
|
|
5
|
+
{ name: "In store", from: 0.46, to: 0.38 },
|
|
6
|
+
{ name: "Own website", from: 0.18, to: 0.27 },
|
|
7
|
+
{ name: "Marketplaces", from: 0.21, to: 0.2 },
|
|
8
|
+
{ name: "Schools and libraries", from: 0.09, to: 0.1 },
|
|
9
|
+
{ name: "Events and fairs", from: 0.06, to: 0.05 },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export default function SlopeChartExample() {
|
|
13
|
+
return (
|
|
14
|
+
<Card>
|
|
15
|
+
<CardHeader>
|
|
16
|
+
<CardTitle>Sales by channel</CardTitle>
|
|
17
|
+
<CardDescription>
|
|
18
|
+
Each channel's share of the year's sales. The website gained what the shop lost.
|
|
19
|
+
</CardDescription>
|
|
20
|
+
</CardHeader>
|
|
21
|
+
<CardContent>
|
|
22
|
+
<SlopeChart items={items} fromLabel="2025" toLabel="2026" highlighted={["In store", "Own website"]} />
|
|
23
|
+
</CardContent>
|
|
24
|
+
</Card>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { AreaChartCard, Delta, SectionCards, Sparkline, useFormat, type SectionCard } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
const value = [
|
|
4
|
+
{ month: "May", equity: 2150000, debt: 600000, gold: 320000, intl: 390000, cash: 150000 },
|
|
5
|
+
{ month: "Jun", equity: 2230000, debt: 612000, gold: 334000, intl: 402000, cash: 160000 },
|
|
6
|
+
{ month: "Jul", equity: 2390000, debt: 625000, gold: 352000, intl: 421000, cash: 172000 },
|
|
7
|
+
{ month: "Aug", equity: 2310000, debt: 637000, gold: 371000, intl: 447000, cash: 185000 },
|
|
8
|
+
{ month: "Sep", equity: 2620000, debt: 648000, gold: 390000, intl: 462000, cash: 198000 },
|
|
9
|
+
{ month: "Oct", equity: 2800000, debt: 655000, gold: 410500, intl: 486300, cash: 212000 },
|
|
10
|
+
];
|
|
11
|
+
const kinds = [
|
|
12
|
+
{ key: "equity", label: "Equity", color: "var(--chart-1)" },
|
|
13
|
+
{ key: "debt", label: "Debt", color: "var(--chart-2)" },
|
|
14
|
+
{ key: "gold", label: "Gold", color: "var(--chart-3)" },
|
|
15
|
+
{ key: "intl", label: "International", color: "var(--chart-4)" },
|
|
16
|
+
{ key: "cash", label: "Cash", color: "var(--chart-5)" },
|
|
17
|
+
] as const;
|
|
18
|
+
|
|
19
|
+
// The gift card sales and the holdings' values last came in on 3 November: the page marks both blocks stale, and each
|
|
20
|
+
// loses its colour and says since when. The page decides; nothing is inferred from dates.
|
|
21
|
+
export default function StaleBlocksExample() {
|
|
22
|
+
const { money, moneyCompact } = useFormat();
|
|
23
|
+
const tiles: SectionCard[] = [
|
|
24
|
+
{
|
|
25
|
+
label: "Revenue",
|
|
26
|
+
value: money(4512300),
|
|
27
|
+
badge: <Delta value={0.031} />,
|
|
28
|
+
trend: <Sparkline data={[3820000, 3950000, 4110000, 4020000, 4380000, 4512300]} />,
|
|
29
|
+
detail: "Month-end, last six months",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: "Gift cards this year",
|
|
33
|
+
value: moneyCompact(38400),
|
|
34
|
+
badge: <Delta value={0.18} />,
|
|
35
|
+
trend: <Sparkline data={[4100, 0, 12800, 3300, 9900, 8300]} variant="line" curve="linear" />,
|
|
36
|
+
detail: "Sold each month",
|
|
37
|
+
stale: "3 Nov",
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
return (
|
|
41
|
+
<div className="flex flex-col gap-6">
|
|
42
|
+
<SectionCards items={tiles} />
|
|
43
|
+
<AreaChartCard
|
|
44
|
+
title="Value by kind"
|
|
45
|
+
description="Month-end value of each kind of holding"
|
|
46
|
+
data={value}
|
|
47
|
+
xKey="month"
|
|
48
|
+
series={kinds}
|
|
49
|
+
valueFormatter={money}
|
|
50
|
+
yTickFormatter={moneyCompact}
|
|
51
|
+
height={256}
|
|
52
|
+
stale="3 Nov"
|
|
53
|
+
/>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BarChartCard,
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
CardDescription,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle,
|
|
8
|
+
MetricStrip,
|
|
9
|
+
PanelGrid,
|
|
10
|
+
SiyahiProvider,
|
|
11
|
+
Table,
|
|
12
|
+
TableBody,
|
|
13
|
+
TableCell,
|
|
14
|
+
TableHead,
|
|
15
|
+
TableHeader,
|
|
16
|
+
TableRow,
|
|
17
|
+
ToggleGroup,
|
|
18
|
+
ToggleGroupItem,
|
|
19
|
+
useFormat,
|
|
20
|
+
type MetricStripItem,
|
|
21
|
+
type Surface,
|
|
22
|
+
} from "@siyahi/ui";
|
|
23
|
+
import { useState } from "react";
|
|
24
|
+
|
|
25
|
+
const orders = [
|
|
26
|
+
{ hour: 9, orders: 42 },
|
|
27
|
+
{ hour: 10, orders: 31 },
|
|
28
|
+
{ hour: 11, orders: 18 },
|
|
29
|
+
{ hour: 12, orders: 12 },
|
|
30
|
+
{ hour: 13, orders: 15 },
|
|
31
|
+
{ hour: 14, orders: 24 },
|
|
32
|
+
{ hour: 15, orders: 38 },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const products = [
|
|
36
|
+
{ product: "Dinner set", revenue: 276000 },
|
|
37
|
+
{ product: "Standing desk", revenue: 224400 },
|
|
38
|
+
{ product: "Bookshelf", revenue: 166000 },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
function Dashboard() {
|
|
42
|
+
const { money, moneyCompact, pct } = useFormat();
|
|
43
|
+
const kpis: MetricStripItem[] = [
|
|
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
|
+
];
|
|
49
|
+
return (
|
|
50
|
+
<div className="flex flex-col gap-6">
|
|
51
|
+
<MetricStrip items={kpis} />
|
|
52
|
+
<PanelGrid>
|
|
53
|
+
<BarChartCard
|
|
54
|
+
title="Orders by hour"
|
|
55
|
+
description="Today, IST"
|
|
56
|
+
data={orders}
|
|
57
|
+
xKey="hour"
|
|
58
|
+
xFormatter={(hour) => `${String(hour).padStart(2, "0")}:00`}
|
|
59
|
+
series={[{ key: "orders", label: "Orders", color: "var(--chart-1)" }]}
|
|
60
|
+
height={200}
|
|
61
|
+
/>
|
|
62
|
+
<Card>
|
|
63
|
+
<CardHeader>
|
|
64
|
+
<CardTitle>Top products</CardTitle>
|
|
65
|
+
<CardDescription>Largest three by revenue</CardDescription>
|
|
66
|
+
</CardHeader>
|
|
67
|
+
<CardContent>
|
|
68
|
+
<Table>
|
|
69
|
+
<TableHeader>
|
|
70
|
+
<TableRow>
|
|
71
|
+
<TableHead>Product</TableHead>
|
|
72
|
+
<TableHead>Revenue</TableHead>
|
|
73
|
+
</TableRow>
|
|
74
|
+
</TableHeader>
|
|
75
|
+
<TableBody>
|
|
76
|
+
{products.map((row) => (
|
|
77
|
+
<TableRow key={row.product}>
|
|
78
|
+
<TableCell>{row.product}</TableCell>
|
|
79
|
+
<TableCell>{money(row.revenue)}</TableCell>
|
|
80
|
+
</TableRow>
|
|
81
|
+
))}
|
|
82
|
+
</TableBody>
|
|
83
|
+
</Table>
|
|
84
|
+
</CardContent>
|
|
85
|
+
</Card>
|
|
86
|
+
</PanelGrid>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default function SurfacesExample() {
|
|
92
|
+
const [surface, setSurface] = useState<Surface>("ruled");
|
|
93
|
+
return (
|
|
94
|
+
<div className="flex flex-col gap-4">
|
|
95
|
+
<ToggleGroup
|
|
96
|
+
value={[surface]}
|
|
97
|
+
onValueChange={([next]) => {
|
|
98
|
+
// Pressing the selected surface again would leave none selected; keep it.
|
|
99
|
+
if (next) setSurface(next as Surface);
|
|
100
|
+
}}
|
|
101
|
+
variant="outline"
|
|
102
|
+
size="sm"
|
|
103
|
+
aria-label="Surface"
|
|
104
|
+
>
|
|
105
|
+
{/* The default first. */}
|
|
106
|
+
<ToggleGroupItem value="ruled">Ruled</ToggleGroupItem>
|
|
107
|
+
<ToggleGroupItem value="card">Card</ToggleGroupItem>
|
|
108
|
+
<ToggleGroupItem value="open">Open</ToggleGroupItem>
|
|
109
|
+
</ToggleGroup>
|
|
110
|
+
{/* A nested provider sets the surface for its part of the page. */}
|
|
111
|
+
<SiyahiProvider surface={surface}>
|
|
112
|
+
<Dashboard />
|
|
113
|
+
</SiyahiProvider>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|