@siyahi/ui 0.1.9-next.2 → 0.1.9-next.21
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 +30 -0
- package/README.md +82 -176
- package/THIRD_PARTY_NOTICES.md +11 -11
- package/agents/examples/accordion.tsx +39 -0
- package/agents/examples/alert.tsx +23 -0
- package/agents/examples/app-sidebar.tsx +38 -0
- package/agents/examples/avatar.tsx +14 -0
- package/agents/examples/badge.tsx +18 -0
- package/agents/examples/bar-list-labels.tsx +22 -0
- package/agents/examples/bar-list-sides.tsx +38 -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 +15 -0
- package/agents/examples/callout.tsx +33 -0
- package/agents/examples/card.tsx +34 -0
- package/agents/examples/change-bar.tsx +104 -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-sectors.tsx +72 -0
- package/agents/examples/chart-bar-years.tsx +40 -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-timeline.tsx +41 -0
- package/agents/examples/chart-line.tsx +57 -0
- package/agents/examples/code-block.tsx +38 -0
- package/agents/examples/collapsible.tsx +16 -0
- package/agents/examples/command.tsx +27 -0
- package/agents/examples/context-menu.tsx +15 -0
- package/agents/examples/copy-button.tsx +8 -0
- package/agents/examples/data-bar.tsx +121 -0
- package/agents/examples/data-table-compact.tsx +95 -0
- package/agents/examples/data-table-filters.tsx +103 -0
- package/agents/examples/data-table.tsx +98 -0
- package/agents/examples/delta.tsx +13 -0
- package/agents/examples/dialog.tsx +28 -0
- package/agents/examples/distribution-bar-budget.tsx +30 -0
- package/agents/examples/distribution-bar-tug.tsx +72 -0
- package/agents/examples/dropdown-menu.tsx +31 -0
- package/agents/examples/formatters.tsx +42 -0
- package/agents/examples/heatmap-calendar.tsx +60 -0
- package/agents/examples/heatmap-status.tsx +57 -0
- package/agents/examples/heatmap-weekday.tsx +75 -0
- package/agents/examples/input-states.tsx +33 -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 +18 -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 +28 -0
- package/agents/examples/progress.tsx +10 -0
- package/agents/examples/range-position-table.tsx +101 -0
- package/agents/examples/range-position.tsx +53 -0
- package/agents/examples/scroll-area.tsx +20 -0
- package/agents/examples/section-cards-select.tsx +30 -0
- package/agents/examples/section-cards-trend.tsx +30 -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/surfaces.tsx +116 -0
- package/agents/examples/table.tsx +50 -0
- package/agents/examples/tabs.tsx +16 -0
- package/agents/examples/target-rows.tsx +70 -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 +88 -0
- package/agents/manifest.json +1081 -0
- package/agents/report-rules.json +7 -0
- package/dist/components/registry/charts/area-chart-card.js +25 -7
- package/dist/components/registry/charts/bar-chart-card.d.ts +0 -1
- package/dist/components/registry/charts/bar-chart-card.js +40 -26
- package/dist/components/registry/charts/line-chart-card.js +2 -2
- package/dist/components/registry/dashboard-01/section-cards.d.ts +2 -0
- package/dist/components/registry/dashboard-01/section-cards.js +42 -35
- package/dist/components/registry/dashboardcn/bar-list.js +18 -11
- package/dist/components/registry/dashboardcn/distribution-bar.js +1 -1
- 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 +4 -2
- package/dist/components/registry/heatmap/calendar-heatmap.js +74 -33
- package/dist/components/registry/heatmap/status-heatmap.d.ts +5 -3
- package/dist/components/registry/heatmap/status-heatmap.js +37 -15
- package/dist/components/registry/heatmap/weekday-heatmap.d.ts +9 -3
- package/dist/components/registry/heatmap/weekday-heatmap.js +82 -47
- 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 +4 -4
- 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 +24 -0
- package/dist/components/siyahi/callout.js +40 -0
- package/dist/components/siyahi/change-bar.d.ts +21 -0
- package/dist/components/siyahi/change-bar.js +35 -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/page-hero.d.ts +25 -0
- package/dist/components/siyahi/page-hero.js +41 -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 +22 -0
- package/dist/components/siyahi/panel-grid.js +34 -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/siyahi-provider.d.ts +13 -2
- package/dist/components/siyahi/siyahi-provider.js +17 -4
- package/dist/components/siyahi/target-rows.d.ts +34 -0
- package/dist/components/siyahi/target-rows.js +97 -0
- package/dist/components/siyahi/treemap.d.ts +4 -1
- package/dist/components/siyahi/treemap.js +78 -28
- package/dist/components/siyahi/warning-alert.d.ts +10 -0
- package/dist/components/siyahi/warning-alert.js +20 -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/input-group.js +11 -11
- package/dist/components/ui/input.js +1 -1
- 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 +21 -7
- package/dist/index.js +18 -4
- package/dist/lib/chart-frame.d.ts +25 -7
- package/dist/lib/chart-frame.js +251 -127
- package/dist/lib/chart-series.d.ts +12 -6
- package/dist/lib/compact-columns.d.ts +19 -0
- package/dist/lib/compact-columns.js +55 -0
- package/dist/lib/format.d.ts +7 -2
- package/dist/lib/format.js +54 -16
- package/dist/lib/heatmap-navigation.d.ts +8 -0
- package/dist/lib/heatmap-navigation.js +49 -0
- package/dist/lib/treemap.js +6 -1
- package/dist/lib/use-element-width.d.ts +5 -0
- package/dist/lib/use-element-width.js +15 -0
- package/package.json +4 -1
- package/registry.lock.json +16 -0
- package/report.css +33 -32
- package/styles/siyahi.css +221 -39
- package/dist/lib/recharts.d.ts +0 -2
- package/dist/lib/recharts.js +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ToneProgress, useFormat } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
const positions = [
|
|
4
|
+
{ symbol: "INFY", realized: 84200, share: 0.41 },
|
|
5
|
+
{ symbol: "ITC", realized: -61200, share: 0.3 },
|
|
6
|
+
{ symbol: "TCS", realized: 21000, share: 0.1 },
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
export default function ProgressToneExample() {
|
|
10
|
+
const { pct } = useFormat();
|
|
11
|
+
return (
|
|
12
|
+
<div className="flex max-w-sm flex-col gap-3 text-sm">
|
|
13
|
+
{positions.map((p) => (
|
|
14
|
+
<div key={p.symbol} className="flex items-center gap-3">
|
|
15
|
+
<span className="w-16 font-medium">{p.symbol}</span>
|
|
16
|
+
<ToneProgress
|
|
17
|
+
tone={p.realized >= 0 ? "positive" : "negative"}
|
|
18
|
+
value={p.share * 100}
|
|
19
|
+
aria-label={`${p.symbol}'s share of the booked P&L`}
|
|
20
|
+
getAriaValueText={() => pct(p.share)}
|
|
21
|
+
className="w-24"
|
|
22
|
+
/>
|
|
23
|
+
<span className="tabular-nums">{pct(p.share)}</span>
|
|
24
|
+
</div>
|
|
25
|
+
))}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Progress, ProgressLabel, ProgressValue } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function ProgressExample() {
|
|
4
|
+
return (
|
|
5
|
+
<Progress value={64} className="max-w-sm">
|
|
6
|
+
<ProgressLabel>Statements imported</ProgressLabel>
|
|
7
|
+
<ProgressValue />
|
|
8
|
+
</Progress>
|
|
9
|
+
);
|
|
10
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Card,
|
|
3
|
+
CardContent,
|
|
4
|
+
CardDescription,
|
|
5
|
+
CardHeader,
|
|
6
|
+
CardTitle,
|
|
7
|
+
DataTable,
|
|
8
|
+
DataTableBody,
|
|
9
|
+
DataTableCompactColumnsToggle,
|
|
10
|
+
DataTableHeader,
|
|
11
|
+
DataTableRoot,
|
|
12
|
+
DataTableSortHeader,
|
|
13
|
+
DataTableToolbarSection,
|
|
14
|
+
RangePosition,
|
|
15
|
+
useFormat,
|
|
16
|
+
type DataTableColumnDef,
|
|
17
|
+
} from "@siyahi/ui";
|
|
18
|
+
|
|
19
|
+
interface Holding {
|
|
20
|
+
symbol: string;
|
|
21
|
+
/** Last close and the 52-week low and high closes, in rupees; made-up figures. */
|
|
22
|
+
close: number;
|
|
23
|
+
low: number;
|
|
24
|
+
high: number;
|
|
25
|
+
/** How far up its range the close sits, 0 at the low and 1 at the high, so the column sorts. */
|
|
26
|
+
position: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const holding = (symbol: string, close: number, low: number, high: number): Holding => ({
|
|
30
|
+
symbol,
|
|
31
|
+
close,
|
|
32
|
+
low,
|
|
33
|
+
high,
|
|
34
|
+
position: (close - low) / (high - low),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const holdings: Holding[] = [
|
|
38
|
+
holding("NIFTYBEES", 284, 241.2, 291.8),
|
|
39
|
+
holding("INFY", 1870, 1307, 2006.45),
|
|
40
|
+
holding("ICICIBANK", 1290, 1051.05, 1362.35),
|
|
41
|
+
holding("TCS", 4150, 3591.5, 4592.25),
|
|
42
|
+
holding("ITC", 460, 399.35, 528.5),
|
|
43
|
+
holding("HDFCBANK", 1750, 1613.6, 2027.4),
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
function Price({ amount }: { amount: number }) {
|
|
47
|
+
return useFormat().money(amount, 2);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const header = () => <DataTableSortHeader />;
|
|
51
|
+
|
|
52
|
+
const columns: DataTableColumnDef<Holding>[] = [
|
|
53
|
+
{ accessorKey: "symbol", header, size: 130, meta: { label: "Symbol", compact: true } },
|
|
54
|
+
{
|
|
55
|
+
accessorKey: "close",
|
|
56
|
+
header,
|
|
57
|
+
size: 120,
|
|
58
|
+
meta: { label: "Close", variant: "number" },
|
|
59
|
+
cell: ({ row }) => <Price amount={row.original.close} />,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
accessorKey: "position",
|
|
63
|
+
header,
|
|
64
|
+
size: 200,
|
|
65
|
+
meta: { label: "52-week range", compact: true },
|
|
66
|
+
cell: ({ row }) => (
|
|
67
|
+
<RangePosition
|
|
68
|
+
variant="compact"
|
|
69
|
+
low={row.original.low}
|
|
70
|
+
high={row.original.high}
|
|
71
|
+
value={row.original.close}
|
|
72
|
+
lowLabel="52-week low"
|
|
73
|
+
highLabel="52-week high"
|
|
74
|
+
/>
|
|
75
|
+
),
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
export default function RangePositionTableExample() {
|
|
80
|
+
return (
|
|
81
|
+
<Card>
|
|
82
|
+
<CardHeader>
|
|
83
|
+
<CardTitle>NIFTYBEES trades near its 52-week high, HDFCBANK near its low</CardTitle>
|
|
84
|
+
<CardDescription>
|
|
85
|
+
Each close on a track from the year's low close to its high; sort to rank them
|
|
86
|
+
</CardDescription>
|
|
87
|
+
</CardHeader>
|
|
88
|
+
<CardContent>
|
|
89
|
+
<DataTableRoot data={holdings} columns={columns}>
|
|
90
|
+
<DataTableToolbarSection>
|
|
91
|
+
<DataTableCompactColumnsToggle />
|
|
92
|
+
</DataTableToolbarSection>
|
|
93
|
+
<DataTable aria-label="Holdings in their 52-week range">
|
|
94
|
+
<DataTableHeader />
|
|
95
|
+
<DataTableBody />
|
|
96
|
+
</DataTable>
|
|
97
|
+
</DataTableRoot>
|
|
98
|
+
</CardContent>
|
|
99
|
+
</Card>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Card,
|
|
3
|
+
CardContent,
|
|
4
|
+
CardDescription,
|
|
5
|
+
CardHeader,
|
|
6
|
+
CardTitle,
|
|
7
|
+
DataList,
|
|
8
|
+
DataListItem,
|
|
9
|
+
RangePosition,
|
|
10
|
+
useFormat,
|
|
11
|
+
} from "@siyahi/ui";
|
|
12
|
+
|
|
13
|
+
// HDFCBANK over the last 52 weeks; made-up figures.
|
|
14
|
+
const low = 1613.6;
|
|
15
|
+
const high = 2027.4;
|
|
16
|
+
const close = 1750.0;
|
|
17
|
+
|
|
18
|
+
export default function RangePositionExample() {
|
|
19
|
+
const f = useFormat();
|
|
20
|
+
const price = (value: number) => f.money(value, 2);
|
|
21
|
+
return (
|
|
22
|
+
// Side by side once the card, not the screen, has room: in a narrow panel on a wide screen they stack.
|
|
23
|
+
<Card className="@container/range">
|
|
24
|
+
<CardHeader>
|
|
25
|
+
<CardTitle>HDFCBANK sits {f.pct((close - low) / (high - low), 0)} of the way up its 52-week range</CardTitle>
|
|
26
|
+
<CardDescription>The last close against the year's lowest and highest close</CardDescription>
|
|
27
|
+
</CardHeader>
|
|
28
|
+
<CardContent className="flex flex-col gap-8 @xl/range:flex-row @xl/range:items-end">
|
|
29
|
+
<DataList className="@xl/range:w-56 @xl/range:shrink-0">
|
|
30
|
+
<DataListItem label="52-week low, 7 months ago">
|
|
31
|
+
<span className="tabular-nums">{price(low)}</span>
|
|
32
|
+
</DataListItem>
|
|
33
|
+
<DataListItem label="52-week high, 11 weeks ago">
|
|
34
|
+
<span className="tabular-nums">{price(high)}</span>
|
|
35
|
+
</DataListItem>
|
|
36
|
+
<DataListItem label="Last close">
|
|
37
|
+
<span className="tabular-nums">{price(close)}</span>
|
|
38
|
+
</DataListItem>
|
|
39
|
+
</DataList>
|
|
40
|
+
<RangePosition
|
|
41
|
+
low={low}
|
|
42
|
+
high={high}
|
|
43
|
+
value={close}
|
|
44
|
+
lowLabel="52-week low"
|
|
45
|
+
highLabel="52-week high"
|
|
46
|
+
caption="of the way up the 52-week range"
|
|
47
|
+
valueFormatter={price}
|
|
48
|
+
className="@xl/range:flex-1"
|
|
49
|
+
/>
|
|
50
|
+
</CardContent>
|
|
51
|
+
</Card>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
<ScrollArea className="h-48 w-56 rounded-lg border">
|
|
10
|
+
<div className="p-4">
|
|
11
|
+
{months.map((month) => (
|
|
12
|
+
<div key={month}>
|
|
13
|
+
<div className="text-sm">{month}</div>
|
|
14
|
+
<Separator className="my-2" />
|
|
15
|
+
</div>
|
|
16
|
+
))}
|
|
17
|
+
</div>
|
|
18
|
+
</ScrollArea>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Delta, SectionCards, SiyahiProvider, useFormat, type SectionCard } from "@siyahi/ui";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
|
|
4
|
+
const classes = [
|
|
5
|
+
{ label: "All", net: 110200, positions: 181 },
|
|
6
|
+
{ label: "Equity", net: 171400, positions: 164 },
|
|
7
|
+
{ label: "Gold bonds", net: 0, positions: 0 },
|
|
8
|
+
{ label: "F&O", net: -61200, positions: 17 },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export default function SectionCardsSelectExample() {
|
|
12
|
+
const [scope, setScope] = useState("All");
|
|
13
|
+
const { count } = useFormat();
|
|
14
|
+
const items: SectionCard[] = classes.map((c) => ({
|
|
15
|
+
label: c.label,
|
|
16
|
+
value: <Delta value={c.net} format="money" />,
|
|
17
|
+
detail: `${count(c.positions)} positions`,
|
|
18
|
+
// Nothing to show for a class with no positions, so it cannot be picked.
|
|
19
|
+
disabled: c.positions === 0,
|
|
20
|
+
}));
|
|
21
|
+
return (
|
|
22
|
+
// On a ruled surface the tiles part with hairlines, as on a trading screen, instead of sitting as cards.
|
|
23
|
+
<SiyahiProvider surface="ruled">
|
|
24
|
+
<div className="flex flex-col gap-3">
|
|
25
|
+
<SectionCards items={items} selected={scope} onSelect={setScope} />
|
|
26
|
+
<p className="text-sm text-muted-foreground">Showing {scope}</p>
|
|
27
|
+
</div>
|
|
28
|
+
</SiyahiProvider>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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: "Portfolio value",
|
|
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: "Realised 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
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label: "Dividends this year",
|
|
23
|
+
value: moneyCompact(38400),
|
|
24
|
+
badge: <Delta value={0.18} />,
|
|
25
|
+
trend: <Sparkline data={[4100, 0, 12800, 3300, 9900, 8300]} variant="line" curve="linear" />,
|
|
26
|
+
detail: "Credited each month",
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
return <SectionCards items={items} />;
|
|
30
|
+
}
|
|
@@ -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: "Portfolio value",
|
|
8
|
+
value: money(4512300),
|
|
9
|
+
badge: <Delta value={0.031} />,
|
|
10
|
+
headline: "Up for the third month",
|
|
11
|
+
detail: "Valued at the last close",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
label: "Invested",
|
|
15
|
+
value: money(4025000),
|
|
16
|
+
headline: "SIPs on the 5th and 20th",
|
|
17
|
+
detail: "Across 4 accounts",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: "Unrealised gain",
|
|
21
|
+
value: moneyCompact(487300),
|
|
22
|
+
badge: <Delta value={0.121} />,
|
|
23
|
+
headline: "XIRR 14.2%",
|
|
24
|
+
detail: "Since the first buy",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: "Realised this year",
|
|
28
|
+
value: moneyCompact(-61200),
|
|
29
|
+
badge: <Delta value={-61200} format="money" />,
|
|
30
|
+
headline: "Two loss-making exits",
|
|
31
|
+
detail: "Before tax",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
label: "Dividends this year",
|
|
35
|
+
value: moneyCompact(38400),
|
|
36
|
+
badge: <Delta value={0.18} />,
|
|
37
|
+
headline: "From 11 holdings",
|
|
38
|
+
detail: "Credited to the bank",
|
|
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 accounts = [
|
|
4
|
+
{ label: "All accounts", value: "all" },
|
|
5
|
+
{ label: "Equity", value: "equity" },
|
|
6
|
+
{ label: "Mutual funds", value: "funds" },
|
|
7
|
+
{ label: "Bonds", value: "bonds" },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
export default function SelectExample() {
|
|
11
|
+
return (
|
|
12
|
+
<Select items={accounts} defaultValue="all">
|
|
13
|
+
<SelectTrigger className="w-48">
|
|
14
|
+
<SelectValue />
|
|
15
|
+
</SelectTrigger>
|
|
16
|
+
<SelectContent>
|
|
17
|
+
<SelectGroup>
|
|
18
|
+
{accounts.map((account) => (
|
|
19
|
+
<SelectItem key={account.value} value={account.value}>
|
|
20
|
+
{account.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>Equity</span>
|
|
7
|
+
<Separator orientation="vertical" />
|
|
8
|
+
<span>Debt</span>
|
|
9
|
+
<Separator orientation="vertical" />
|
|
10
|
+
<span>Gold</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 ledger by account, symbol 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,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 holdings = [
|
|
36
|
+
{ symbol: "ITC", value: 276000 },
|
|
37
|
+
{ symbol: "INFY", value: 224400 },
|
|
38
|
+
{ symbol: "TCS", value: 166000 },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
function Dashboard() {
|
|
42
|
+
const { money, moneyCompact, pct } = useFormat();
|
|
43
|
+
const kpis: MetricStripItem[] = [
|
|
44
|
+
{ label: "Portfolio value", value: money(4512300), change: 0.031 },
|
|
45
|
+
{ label: "Invested", value: moneyCompact(4025000), change: 85000, changeFormat: "money" },
|
|
46
|
+
{ label: "XIRR", value: pct(0.142), change: -0.004 },
|
|
47
|
+
{ label: "Realised", 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>Holdings</CardTitle>
|
|
65
|
+
<CardDescription>Largest three</CardDescription>
|
|
66
|
+
</CardHeader>
|
|
67
|
+
<CardContent>
|
|
68
|
+
<Table>
|
|
69
|
+
<TableHeader>
|
|
70
|
+
<TableRow>
|
|
71
|
+
<TableHead>Symbol</TableHead>
|
|
72
|
+
<TableHead>Value</TableHead>
|
|
73
|
+
</TableRow>
|
|
74
|
+
</TableHeader>
|
|
75
|
+
<TableBody>
|
|
76
|
+
{holdings.map((row) => (
|
|
77
|
+
<TableRow key={row.symbol}>
|
|
78
|
+
<TableCell className="font-mono">{row.symbol}</TableCell>
|
|
79
|
+
<TableCell className="tabular-nums">{money(row.value)}</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>("card");
|
|
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="card">Card</ToggleGroupItem>
|
|
107
|
+
<ToggleGroupItem value="ruled">Ruled</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
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Card,
|
|
3
|
+
CardContent,
|
|
4
|
+
CardHeader,
|
|
5
|
+
CardTitle,
|
|
6
|
+
Table,
|
|
7
|
+
TableBody,
|
|
8
|
+
TableCell,
|
|
9
|
+
TableHead,
|
|
10
|
+
TableHeader,
|
|
11
|
+
TableRow,
|
|
12
|
+
useFormat,
|
|
13
|
+
} from "@siyahi/ui";
|
|
14
|
+
|
|
15
|
+
const rows = [
|
|
16
|
+
{ month: "July", in: 85000, out: 12000 },
|
|
17
|
+
{ month: "August", in: 85000, out: 64000 },
|
|
18
|
+
{ month: "September", in: 92000, out: 8000 },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export default function TableExample() {
|
|
22
|
+
const { money } = useFormat();
|
|
23
|
+
return (
|
|
24
|
+
<Card>
|
|
25
|
+
<CardHeader>
|
|
26
|
+
<CardTitle>Cash flow</CardTitle>
|
|
27
|
+
</CardHeader>
|
|
28
|
+
<CardContent>
|
|
29
|
+
<Table>
|
|
30
|
+
<TableHeader>
|
|
31
|
+
<TableRow>
|
|
32
|
+
<TableHead>Month</TableHead>
|
|
33
|
+
<TableHead className="text-right">In</TableHead>
|
|
34
|
+
<TableHead className="text-right">Out</TableHead>
|
|
35
|
+
</TableRow>
|
|
36
|
+
</TableHeader>
|
|
37
|
+
<TableBody>
|
|
38
|
+
{rows.map((row) => (
|
|
39
|
+
<TableRow key={row.month}>
|
|
40
|
+
<TableCell>{row.month}</TableCell>
|
|
41
|
+
<TableCell className="text-right">{money(row.in)}</TableCell>
|
|
42
|
+
<TableCell className="text-right">{money(row.out)}</TableCell>
|
|
43
|
+
</TableRow>
|
|
44
|
+
))}
|
|
45
|
+
</TableBody>
|
|
46
|
+
</Table>
|
|
47
|
+
</CardContent>
|
|
48
|
+
</Card>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function TabsExample() {
|
|
4
|
+
return (
|
|
5
|
+
<Tabs defaultValue="holdings">
|
|
6
|
+
<TabsList>
|
|
7
|
+
<TabsTrigger value="holdings">Holdings</TabsTrigger>
|
|
8
|
+
<TabsTrigger value="realized">Realized</TabsTrigger>
|
|
9
|
+
<TabsTrigger value="cash">Cash flow</TabsTrigger>
|
|
10
|
+
</TabsList>
|
|
11
|
+
<TabsContent value="holdings">What you own today, valued at the last close.</TabsContent>
|
|
12
|
+
<TabsContent value="realized">Gains and losses booked by selling.</TabsContent>
|
|
13
|
+
<TabsContent value="cash">Money in and out of every account.</TabsContent>
|
|
14
|
+
</Tabs>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Card,
|
|
3
|
+
CardContent,
|
|
4
|
+
CardDescription,
|
|
5
|
+
CardHeader,
|
|
6
|
+
CardTitle,
|
|
7
|
+
TargetRows,
|
|
8
|
+
useFormat,
|
|
9
|
+
type TargetRow,
|
|
10
|
+
type TargetStatus,
|
|
11
|
+
} from "@siyahi/ui";
|
|
12
|
+
|
|
13
|
+
interface Sleeve {
|
|
14
|
+
name: string;
|
|
15
|
+
holdings: string;
|
|
16
|
+
/** Today's share of the portfolio and the plan's share, as fractions; made-up figures. */
|
|
17
|
+
weight: number;
|
|
18
|
+
target: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const sleeves: Sleeve[] = [
|
|
22
|
+
{ name: "Large-cap equity", holdings: "HDFCBANK, ICICIBANK, INFY, TCS", weight: 0.426, target: 0.4 },
|
|
23
|
+
{ name: "Mid and small cap", holdings: "Two mid-cap funds", weight: 0.189, target: 0.2 },
|
|
24
|
+
{ name: "Debt", holdings: "Corporate bond fund, PPF", weight: 0.194, target: 0.25 },
|
|
25
|
+
{ name: "Gold", holdings: "GOLDBEES, Sovereign Gold Bonds", weight: 0.093, target: 0.1 },
|
|
26
|
+
{ name: "International", holdings: "Nasdaq 100 fund of funds", weight: 0.098, target: 0.05 },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
// Within two points of the plan is on target; past five is far enough to rebalance.
|
|
30
|
+
const NEAR = 0.02;
|
|
31
|
+
const FAR = 0.05;
|
|
32
|
+
|
|
33
|
+
const pts = (value: number) => `${(value * 100).toFixed(1)} pts`;
|
|
34
|
+
|
|
35
|
+
function statusOf({ weight, target }: Sleeve): TargetStatus {
|
|
36
|
+
const gap = weight - target;
|
|
37
|
+
const size = `${pts(Math.abs(gap))} ${gap > 0 ? "over" : "under"}`;
|
|
38
|
+
if (Math.abs(gap) <= NEAR) return { kind: "met", label: "On target" };
|
|
39
|
+
if (Math.abs(gap) <= FAR) return { kind: "missed", label: size };
|
|
40
|
+
return { kind: "warning", label: `${size}, rebalance` };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default function TargetRowsExample() {
|
|
44
|
+
const f = useFormat();
|
|
45
|
+
const rows: TargetRow[] = sleeves.map((sleeve) => ({
|
|
46
|
+
label: sleeve.name,
|
|
47
|
+
detail: sleeve.holdings,
|
|
48
|
+
value: sleeve.weight,
|
|
49
|
+
target: sleeve.target,
|
|
50
|
+
bands: [
|
|
51
|
+
[sleeve.target - FAR, sleeve.target + FAR],
|
|
52
|
+
[sleeve.target - NEAR, sleeve.target + NEAR],
|
|
53
|
+
],
|
|
54
|
+
status: statusOf(sleeve),
|
|
55
|
+
}));
|
|
56
|
+
return (
|
|
57
|
+
<Card>
|
|
58
|
+
<CardHeader>
|
|
59
|
+
<CardTitle>Debt is 5.6 points under its target</CardTitle>
|
|
60
|
+
<CardDescription>Each sleeve's share of the portfolio against the plan, on one 0–50% scale</CardDescription>
|
|
61
|
+
</CardHeader>
|
|
62
|
+
<CardContent className="grid gap-2">
|
|
63
|
+
<p className="text-sm text-muted-foreground">
|
|
64
|
+
Bar: today's weight. Tall tick: the target. Shading: within 5 points of it, darker within 2.
|
|
65
|
+
</p>
|
|
66
|
+
<TargetRows rows={rows} domain={[0, 0.5]} valueFormatter={(value) => f.pct(value)} />
|
|
67
|
+
</CardContent>
|
|
68
|
+
</Card>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ToggleGroup, ToggleGroupItem } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function ToggleGroupExample() {
|
|
4
|
+
return (
|
|
5
|
+
<ToggleGroup defaultValue={["1Y"]} variant="outline" size="sm" aria-label="Range">
|
|
6
|
+
<ToggleGroupItem value="1M">1M</ToggleGroupItem>
|
|
7
|
+
<ToggleGroupItem value="6M">6M</ToggleGroupItem>
|
|
8
|
+
<ToggleGroupItem value="1Y">1Y</ToggleGroupItem>
|
|
9
|
+
<ToggleGroupItem value="All">All</ToggleGroupItem>
|
|
10
|
+
</ToggleGroup>
|
|
11
|
+
);
|
|
12
|
+
}
|