@siyahi/ui 0.1.9-next.29 → 0.1.9-next.30
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 +79 -10
- package/agents/examples/avatar.tsx +15 -5
- package/agents/examples/chart-line-forecast.tsx +36 -0
- package/agents/examples/chart-line-quiet.tsx +114 -0
- package/agents/examples/chart-panels.tsx +94 -0
- package/agents/examples/code-block.tsx +5 -3
- package/agents/examples/field.tsx +108 -0
- package/agents/examples/formatters.tsx +14 -14
- package/agents/examples/input-states.tsx +12 -22
- package/agents/examples/overview-dashboard.tsx +6 -6
- package/agents/examples/stale-blocks.tsx +56 -0
- package/agents/examples/table.tsx +6 -6
- package/agents/manifest.json +104 -3
- package/dist/components/registry/charts/area-chart-card.d.ts +7 -3
- package/dist/components/registry/charts/area-chart-card.js +52 -25
- package/dist/components/registry/charts/bar-chart-card.d.ts +1 -0
- package/dist/components/registry/charts/bar-chart-card.js +8 -24
- package/dist/components/registry/charts/line-chart-card.d.ts +2 -2
- package/dist/components/registry/charts/line-chart-card.js +42 -7
- package/dist/components/registry/dashboard-01/section-cards.d.ts +2 -0
- package/dist/components/registry/dashboard-01/section-cards.js +3 -0
- package/dist/components/registry/heatmap/calendar-heatmap.js +2 -2
- package/dist/components/registry/heatmap/status-heatmap.js +2 -2
- package/dist/components/registry/heatmap/weekday-heatmap.js +2 -2
- package/dist/components/registry/niko-table/filters/table-faceted-filter.js +1 -1
- package/dist/components/siyahi/histogram-chart.js +8 -8
- package/dist/components/siyahi/scatter-chart.js +1 -1
- package/dist/components/siyahi/slope-chart.js +1 -1
- package/dist/components/siyahi/stale-note.d.ts +9 -0
- package/dist/components/siyahi/stale-note.js +12 -0
- package/dist/components/siyahi/treemap.js +1 -1
- package/dist/components/siyahi/waterfall-chart.js +4 -4
- package/dist/components/ui/field.d.ts +26 -0
- package/dist/components/ui/field.js +109 -0
- package/dist/components/ui/label.d.ts +5 -0
- package/dist/components/ui/label.js +13 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -2
- package/dist/lib/chart-frame.d.ts +28 -4
- package/dist/lib/chart-frame.js +256 -153
- package/dist/lib/chart-marks.d.ts +83 -0
- package/dist/lib/chart-marks.js +216 -0
- package/dist/lib/chart-series.d.ts +15 -0
- package/package.json +1 -1
- package/report.css +6 -4
- package/styles/siyahi.css +260 -18
package/DESIGN.md
CHANGED
|
@@ -10,8 +10,8 @@ component; this file says how to use them.
|
|
|
10
10
|
Colour is placed, not spread. A page is neutral greys plus colour that carries
|
|
11
11
|
a meaning:
|
|
12
12
|
|
|
13
|
-
- **Ink indigo** is the accent: links,
|
|
14
|
-
|
|
13
|
+
- **Ink indigo** is the accent: links, the selected sidebar item, the first
|
|
14
|
+
chart series, a chart's "today" rule and an `accent` `Callout`. Buttons, badges, toggles and focus
|
|
15
15
|
stay monochrome.
|
|
16
16
|
- **Green and red** mean a gain and a loss. A signed figure is `Delta`: the figure in the text colour with its
|
|
17
17
|
`+` or `−`, and only a small trend icon in green or red. In plain text (labels, tooltips) write the sign; never
|
|
@@ -22,8 +22,9 @@ a meaning:
|
|
|
22
22
|
apart is `Callout` (`neutral`, `accent`, `warning`, `positive`,
|
|
23
23
|
`negative`); a quotation is `Quote`. Each takes a faint wash of its colour
|
|
24
24
|
inside a 1px border of the same colour all round. Large marks follow the same
|
|
25
|
-
rule:
|
|
26
|
-
|
|
25
|
+
rule: every bar is a tint inside a 1px full-colour edge, not a solid slab.
|
|
26
|
+
A bar is read by its edge, which reaches 3:1 against the card; the tint is a
|
|
27
|
+
fill carried by that edge.
|
|
27
28
|
- **Never a stripe down one side.** Do not mark a notice, card, row or quote
|
|
28
29
|
with a left (or any single-side) coloured border; tint the box or add an
|
|
29
30
|
icon. 1px neutral dividers between columns are separators, not accents, and
|
|
@@ -33,8 +34,13 @@ a meaning:
|
|
|
33
34
|
canvas and the card; dividers, card rings, gridlines and the outlines of
|
|
34
35
|
buttons, toggles and code blocks are the `--border` hairline (the text colour
|
|
35
36
|
at 18% in light, white at 20% in dark), firm enough to carry the page's
|
|
36
|
-
structure. Focus is
|
|
37
|
-
|
|
37
|
+
structure. Focus is drawn inside the control, so no neighbour or clipping box
|
|
38
|
+
covers it: a 2px ring in the text colour (`--ring`) on its edge with a 2px
|
|
39
|
+
ring of the page colour inside, which reads on a black, white or hovered
|
|
40
|
+
fill alike. A field shows it as its own edge, 2px in the text colour; a chart
|
|
41
|
+
mark as a dashed stroke, apart from a picked mark's solid one. A destructive
|
|
42
|
+
control and an invalid field focus in the destructive red. Menu items show
|
|
43
|
+
focus as their highlight. A selected
|
|
38
44
|
toggle or pill tab fills with the foreground. A chart bar that a selection
|
|
39
45
|
dims keeps its full-colour outline and fades only inside.
|
|
40
46
|
- **Destructive is not loss.** `--destructive` (delete, an invalid field) is a
|
|
@@ -82,6 +88,9 @@ mono face and the link colour, so the text can point to one.
|
|
|
82
88
|
`rounded-*` class to a box.
|
|
83
89
|
- **Joined toggles.** The items of a `ToggleGroup` sit flush and share their
|
|
84
90
|
borders, one control; the pressed item fills with the foreground.
|
|
91
|
+
- **A code block's copy button sits in a header row** (`CodeBlockHeader`),
|
|
92
|
+
beside its title or alone, never floating over the code, where it would
|
|
93
|
+
cover the end of a line. An untitled snippet takes the extra row.
|
|
85
94
|
- Badges stay boxed (an outline), the primary button and the pressed toggle
|
|
86
95
|
black (white in dark), titles in the sans face, at normal spacing.
|
|
87
96
|
|
|
@@ -93,9 +102,69 @@ the actions at the right, and a hairline under it. One per page; no hero card.
|
|
|
93
102
|
|
|
94
103
|
## Labels and totals
|
|
95
104
|
|
|
96
|
-
- **Labels
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
105
|
+
- **Labels are small monospaced capitals**: a stat tile's label and footer
|
|
106
|
+
lines, a `MetricStrip` label, a table's column heads, a sidebar group's
|
|
107
|
+
label, and a form field's label (muted, above the field). The components and
|
|
108
|
+
the theme set them; never set a label in this style by hand elsewhere, and
|
|
109
|
+
never set a figure or a title in it.
|
|
100
110
|
- **A total row reads as a ledger's**: in `TableFooter`, one rule above it and
|
|
101
111
|
a double rule under it in the text colour, no band.
|
|
112
|
+
|
|
113
|
+
## Charts
|
|
114
|
+
|
|
115
|
+
- **Names at the line ends.** A line chart and overlapping areas name each
|
|
116
|
+
series at its line's end, in the text colour beside a square of its colour,
|
|
117
|
+
in a gutter after the last point; ends that crowd are spread 14px apart with
|
|
118
|
+
a short leader. A legend goes below instead on a card under 400px wide (a
|
|
119
|
+
phone), where the names would take more than 30% of it or not fit the
|
|
120
|
+
plot's height, and where a line ends short of the plot's right edge (a
|
|
121
|
+
missing last reading, a single point, an x axis running past the data). Bars and stacks
|
|
122
|
+
keep a legend.
|
|
123
|
+
- **Five colours, then grey.** Past five series, the page names the few it is
|
|
124
|
+
about in chart colours and gives the rest `var(--muted-foreground)`: they
|
|
125
|
+
draw first, in grey. Every line is still named: a grey one's name at its end
|
|
126
|
+
is muted with no square, and its place says which line it is. Never a count
|
|
127
|
+
standing in for names. In the legend a grey name is a button that raises its
|
|
128
|
+
line in the text colour, since a shared grey square cannot tell lines apart;
|
|
129
|
+
a stack's grey bands read in the legend's order, bottom to top.
|
|
130
|
+
- **No fill under overlapping areas**: from three series on, fills bury each
|
|
131
|
+
other. A stack fills each band with a flat tint, never a gradient.
|
|
132
|
+
- **Forecast and today.** `forecastFrom` dashes every line from that point,
|
|
133
|
+
hatches the stretch faintly behind lines on card-coloured halos, labels it
|
|
134
|
+
FORECAST and hollows the end dots (a stack keeps solid edges and no hatching:
|
|
135
|
+
its fills cover the stretch);
|
|
136
|
+
`today` is a 1px rule in the link colour, labelled TODAY.
|
|
137
|
+
- Gridlines are solid hairlines. Lines draw in left to right over 1.3s on
|
|
138
|
+
first draw, a stack's fills revealed with them; then the names fade in, and
|
|
139
|
+
each end dot as its line finishes; bars fade in rather than grow. Reduced
|
|
140
|
+
motion shows them at once.
|
|
141
|
+
- **Stale data is marked by the page**: `stale` on a chart card or a
|
|
142
|
+
`SectionCards` tile, with since when ("3 Nov"). The block greys and its
|
|
143
|
+
chart or sparkline draws at about 65% strength, a tile's figure and badge
|
|
144
|
+
turn muted, and a small "Stale · 3 Nov" note says so. A stale block is meant
|
|
145
|
+
to be harder to read, so its marks are exempt from the 3:1 mark bar; the
|
|
146
|
+
note and the figure keep their text contrast. Never infer it from dates.
|
|
147
|
+
|
|
148
|
+
## Tables
|
|
149
|
+
|
|
150
|
+
Tables are dense, as a ledger is: compact rows, a 1px rule in the text colour
|
|
151
|
+
under the column heads, the first column (what the row is) in medium weight,
|
|
152
|
+
and figures in the mono face. A figure is a cell marked `data-numeric`, which
|
|
153
|
+
also right-aligns it (the data table marks its number columns; a plain
|
|
154
|
+
`TableCell` or `TableHead` takes the attribute), and any `Delta` in a cell.
|
|
155
|
+
Alignment alone is not a figure. Row hairlines stay; never stripes, never
|
|
156
|
+
column rules.
|
|
157
|
+
|
|
158
|
+
## Forms
|
|
159
|
+
|
|
160
|
+
- Every field is a `Field` with a `FieldLabel` above the control, a
|
|
161
|
+
`FieldDescription` hint or a `FieldError` under it. Never write a bare
|
|
162
|
+
`<label>` with its own styles.
|
|
163
|
+
- An invalid field (`aria-invalid` on the control, `data-invalid` on its
|
|
164
|
+
`Field`) keeps its red edge and takes a faint red wash.
|
|
165
|
+
|
|
166
|
+
## Sidebar
|
|
167
|
+
|
|
168
|
+
The sidebar is parted from the page by a hairline on its page-side edge, its
|
|
169
|
+
group labels are small monospaced capitals and its rows are compact. Its fill,
|
|
170
|
+
icons and the current page's mark stay as shadcn draws them.
|
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
import { Avatar, AvatarFallback } from "@siyahi/ui";
|
|
1
|
+
import { Avatar, AvatarBadge, AvatarFallback, AvatarGroup } from "@siyahi/ui";
|
|
2
2
|
|
|
3
3
|
export default function AvatarExample() {
|
|
4
4
|
return (
|
|
5
|
-
<div className="flex gap-
|
|
5
|
+
<div className="flex items-center gap-6">
|
|
6
6
|
<Avatar>
|
|
7
7
|
<AvatarFallback>JB</AvatarFallback>
|
|
8
8
|
</Avatar>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
{/* A group overlaps its avatars; the first one's badge stays over its neighbour. */}
|
|
10
|
+
<AvatarGroup>
|
|
11
|
+
<Avatar>
|
|
12
|
+
<AvatarFallback>JB</AvatarFallback>
|
|
13
|
+
<AvatarBadge aria-label="Online" />
|
|
14
|
+
</Avatar>
|
|
15
|
+
<Avatar>
|
|
16
|
+
<AvatarFallback>HU</AvatarFallback>
|
|
17
|
+
</Avatar>
|
|
18
|
+
<Avatar>
|
|
19
|
+
<AvatarFallback>AK</AvatarFallback>
|
|
20
|
+
</Avatar>
|
|
21
|
+
</AvatarGroup>
|
|
12
22
|
</div>
|
|
13
23
|
);
|
|
14
24
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { LineChartCard, useFormat, type ChartSeries } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
// Net worth's growth against the plan since May; November and December are a forecast.
|
|
4
|
+
const worth = [
|
|
5
|
+
{ month: "May", actual: 0, plan: 0 },
|
|
6
|
+
{ month: "Jun", actual: 0.025, plan: 0.022 },
|
|
7
|
+
{ month: "Jul", actual: 0.061, plan: 0.044 },
|
|
8
|
+
{ month: "Aug", actual: 0.047, plan: 0.067 },
|
|
9
|
+
{ month: "Sep", actual: 0.11, plan: 0.089 },
|
|
10
|
+
{ month: "Oct", actual: 0.156, plan: 0.111 },
|
|
11
|
+
{ month: "Nov", actual: 0.177, plan: 0.133 },
|
|
12
|
+
{ month: "Dec", actual: 0.202, plan: 0.156 },
|
|
13
|
+
];
|
|
14
|
+
const series: ChartSeries<(typeof worth)[number]> = [
|
|
15
|
+
{ key: "actual", label: "Net worth", color: "var(--chart-1)" },
|
|
16
|
+
{ key: "plan", label: "Plan", color: "var(--chart-2)" },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
// Today is a rule in the link colour; from forecastFrom the lines dash, a hatched band covers the stretch and the end
|
|
20
|
+
// dots are hollow.
|
|
21
|
+
export default function ChartLineForecastExample() {
|
|
22
|
+
const { pct } = useFormat();
|
|
23
|
+
return (
|
|
24
|
+
<LineChartCard
|
|
25
|
+
title="Growth against plan"
|
|
26
|
+
description="Since May, month-end; November and December are a forecast"
|
|
27
|
+
data={worth}
|
|
28
|
+
xKey="month"
|
|
29
|
+
series={series}
|
|
30
|
+
today="Oct"
|
|
31
|
+
forecastFrom="Oct"
|
|
32
|
+
valueFormatter={pct}
|
|
33
|
+
height={256}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { LineChartCard, useFormat, type ChartSeries } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
// Eight funds' month-end growth; November and December are a forecast.
|
|
4
|
+
const growth = [
|
|
5
|
+
{ month: "May", flexi: 0, debt: 0, small: 0, intl: 0, liquid: 0, midcap: 0, nifty: 0, gold: 0 },
|
|
6
|
+
{
|
|
7
|
+
month: "Jun",
|
|
8
|
+
flexi: 0.018,
|
|
9
|
+
debt: 0.006,
|
|
10
|
+
small: 0.034,
|
|
11
|
+
intl: 0.012,
|
|
12
|
+
liquid: 0.005,
|
|
13
|
+
midcap: 0.022,
|
|
14
|
+
nifty: 0.025,
|
|
15
|
+
gold: 0.041,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
month: "Jul",
|
|
19
|
+
flexi: 0.049,
|
|
20
|
+
debt: 0.013,
|
|
21
|
+
small: 0.012,
|
|
22
|
+
intl: 0.038,
|
|
23
|
+
liquid: 0.011,
|
|
24
|
+
midcap: 0.03,
|
|
25
|
+
nifty: 0.061,
|
|
26
|
+
gold: 0.072,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
month: "Aug",
|
|
30
|
+
flexi: 0.058,
|
|
31
|
+
debt: 0.02,
|
|
32
|
+
small: -0.041,
|
|
33
|
+
intl: 0.066,
|
|
34
|
+
liquid: 0.017,
|
|
35
|
+
midcap: 0.011,
|
|
36
|
+
nifty: 0.047,
|
|
37
|
+
gold: 0.118,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
month: "Sep",
|
|
41
|
+
flexi: 0.094,
|
|
42
|
+
debt: 0.027,
|
|
43
|
+
small: -0.018,
|
|
44
|
+
intl: 0.081,
|
|
45
|
+
liquid: 0.023,
|
|
46
|
+
midcap: 0.052,
|
|
47
|
+
nifty: 0.11,
|
|
48
|
+
gold: 0.153,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
month: "Oct",
|
|
52
|
+
flexi: 0.141,
|
|
53
|
+
debt: 0.034,
|
|
54
|
+
small: -0.052,
|
|
55
|
+
intl: 0.119,
|
|
56
|
+
liquid: 0.029,
|
|
57
|
+
midcap: 0.078,
|
|
58
|
+
nifty: 0.156,
|
|
59
|
+
gold: 0.196,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
month: "Nov",
|
|
63
|
+
flexi: 0.166,
|
|
64
|
+
debt: 0.043,
|
|
65
|
+
small: -0.04,
|
|
66
|
+
intl: 0.142,
|
|
67
|
+
liquid: 0.037,
|
|
68
|
+
midcap: 0.099,
|
|
69
|
+
nifty: 0.177,
|
|
70
|
+
gold: 0.221,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
month: "Dec",
|
|
74
|
+
flexi: 0.189,
|
|
75
|
+
debt: 0.052,
|
|
76
|
+
small: -0.031,
|
|
77
|
+
intl: 0.164,
|
|
78
|
+
liquid: 0.046,
|
|
79
|
+
midcap: 0.12,
|
|
80
|
+
nifty: 0.202,
|
|
81
|
+
gold: 0.245,
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
// The palette has five colours, so past five the page names the few it is about in colour; the rest are muted, draw
|
|
86
|
+
// first in grey, each still named at its end.
|
|
87
|
+
const QUIET = "var(--muted-foreground)";
|
|
88
|
+
const series: ChartSeries<(typeof growth)[number]> = [
|
|
89
|
+
{ key: "flexi", label: "Flexi cap", color: QUIET },
|
|
90
|
+
{ key: "debt", label: "Debt", color: QUIET },
|
|
91
|
+
{ key: "small", label: "Small cap", color: QUIET },
|
|
92
|
+
{ key: "intl", label: "International", color: QUIET },
|
|
93
|
+
{ key: "liquid", label: "Liquid", color: QUIET },
|
|
94
|
+
{ key: "midcap", label: "Mid cap", color: QUIET },
|
|
95
|
+
{ key: "nifty", label: "Nifty 50", color: "var(--chart-1)" },
|
|
96
|
+
{ key: "gold", label: "Gold", color: "var(--chart-2)" },
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
export default function ChartLineQuietExample() {
|
|
100
|
+
const { pct } = useFormat();
|
|
101
|
+
return (
|
|
102
|
+
<LineChartCard
|
|
103
|
+
title="Growth by fund"
|
|
104
|
+
description="Eight funds; the two you are watching in colour"
|
|
105
|
+
data={growth}
|
|
106
|
+
xKey="month"
|
|
107
|
+
series={series}
|
|
108
|
+
today="Oct"
|
|
109
|
+
forecastFrom="Oct"
|
|
110
|
+
valueFormatter={pct}
|
|
111
|
+
height={256}
|
|
112
|
+
/>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { AreaChartCard, BarChartCard, LineChartCard, PanelGrid, useFormat, type ChartSeries } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
// Month-end growth of five funds; November and December are a forecast.
|
|
4
|
+
const growth = [
|
|
5
|
+
{ month: "May", nifty: 0, flexi: 0, gold: 0, debt: 0, small: 0 },
|
|
6
|
+
{ month: "Jun", nifty: 0.025, flexi: 0.018, gold: 0.041, debt: 0.006, small: 0.034 },
|
|
7
|
+
{ month: "Jul", nifty: 0.061, flexi: 0.049, gold: 0.072, debt: 0.013, small: 0.012 },
|
|
8
|
+
{ month: "Aug", nifty: 0.047, flexi: 0.058, gold: 0.118, debt: 0.02, small: -0.041 },
|
|
9
|
+
{ month: "Sep", nifty: 0.11, flexi: 0.094, gold: 0.153, debt: 0.027, small: -0.018 },
|
|
10
|
+
{ month: "Oct", nifty: 0.156, flexi: 0.141, gold: 0.196, debt: 0.034, small: -0.052 },
|
|
11
|
+
{ month: "Nov", nifty: 0.177, flexi: 0.166, gold: 0.221, debt: 0.043, small: -0.04 },
|
|
12
|
+
{ month: "Dec", nifty: 0.202, flexi: 0.189, gold: 0.245, debt: 0.052, small: -0.031 },
|
|
13
|
+
];
|
|
14
|
+
const funds: ChartSeries<(typeof growth)[number]> = [
|
|
15
|
+
{ key: "nifty", label: "Nifty 50", color: "var(--chart-1)" },
|
|
16
|
+
{ key: "flexi", label: "Flexi cap", color: "var(--chart-2)" },
|
|
17
|
+
{ key: "gold", label: "Gold", color: "var(--chart-3)" },
|
|
18
|
+
{ key: "debt", label: "Debt", color: "var(--chart-4)" },
|
|
19
|
+
{ key: "small", label: "Small cap", color: "var(--chart-5)" },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const value = [
|
|
23
|
+
{ month: "May", equity: 2150000, debt: 600000, gold: 320000, intl: 390000, cash: 150000 },
|
|
24
|
+
{ month: "Jun", equity: 2230000, debt: 612000, gold: 334000, intl: 402000, cash: 160000 },
|
|
25
|
+
{ month: "Jul", equity: 2390000, debt: 625000, gold: 352000, intl: 421000, cash: 172000 },
|
|
26
|
+
{ month: "Aug", equity: 2310000, debt: 637000, gold: 371000, intl: 447000, cash: 185000 },
|
|
27
|
+
{ month: "Sep", equity: 2620000, debt: 648000, gold: 390000, intl: 462000, cash: 198000 },
|
|
28
|
+
{ month: "Oct", equity: 2800000, debt: 655000, gold: 410500, intl: 486300, cash: 212000 },
|
|
29
|
+
];
|
|
30
|
+
const added = [
|
|
31
|
+
{ quarter: "Q1", equity: 180000, debt: 60000, gold: 20000, intl: 40000, cash: 25000 },
|
|
32
|
+
{ quarter: "Q2", equity: 220000, debt: 40000, gold: 45000, intl: 35000, cash: 15000 },
|
|
33
|
+
{ quarter: "Q3", equity: 150000, debt: 80000, gold: 30000, intl: 55000, cash: 30000 },
|
|
34
|
+
{ quarter: "Q4", equity: 260000, debt: 50000, gold: 60000, intl: 70000, cash: 20000 },
|
|
35
|
+
];
|
|
36
|
+
const kinds = [
|
|
37
|
+
{ key: "equity", label: "Equity", color: "var(--chart-1)" },
|
|
38
|
+
{ key: "debt", label: "Debt", color: "var(--chart-2)" },
|
|
39
|
+
{ key: "gold", label: "Gold", color: "var(--chart-3)" },
|
|
40
|
+
{ key: "intl", label: "International", color: "var(--chart-4)" },
|
|
41
|
+
{ key: "cash", label: "Cash", color: "var(--chart-5)" },
|
|
42
|
+
] as const;
|
|
43
|
+
|
|
44
|
+
// Four charts in a PanelGrid: lines named at their ends, a forecast after today, overlapping areas as lines, and bars
|
|
45
|
+
// as tints inside full-colour edges, grouped and stacked.
|
|
46
|
+
export default function ChartPanelsExample() {
|
|
47
|
+
const { pct, money, moneyCompact } = useFormat();
|
|
48
|
+
return (
|
|
49
|
+
<PanelGrid>
|
|
50
|
+
<LineChartCard
|
|
51
|
+
title="Growth by fund"
|
|
52
|
+
description="Since May, month-end; November and December are a forecast"
|
|
53
|
+
data={growth}
|
|
54
|
+
xKey="month"
|
|
55
|
+
series={funds}
|
|
56
|
+
today="Oct"
|
|
57
|
+
forecastFrom="Oct"
|
|
58
|
+
valueFormatter={pct}
|
|
59
|
+
height={256}
|
|
60
|
+
/>
|
|
61
|
+
<AreaChartCard
|
|
62
|
+
title="Value by kind"
|
|
63
|
+
description="Month-end value of each kind of holding"
|
|
64
|
+
data={value}
|
|
65
|
+
xKey="month"
|
|
66
|
+
series={kinds}
|
|
67
|
+
valueFormatter={money}
|
|
68
|
+
yTickFormatter={moneyCompact}
|
|
69
|
+
height={256}
|
|
70
|
+
/>
|
|
71
|
+
<BarChartCard
|
|
72
|
+
title="Money added by kind and quarter"
|
|
73
|
+
description="Side by side"
|
|
74
|
+
data={added}
|
|
75
|
+
xKey="quarter"
|
|
76
|
+
series={kinds}
|
|
77
|
+
valueFormatter={money}
|
|
78
|
+
yTickFormatter={moneyCompact}
|
|
79
|
+
height={256}
|
|
80
|
+
/>
|
|
81
|
+
<BarChartCard
|
|
82
|
+
title="Money added by kind and quarter"
|
|
83
|
+
description="Stacked into the quarter's total"
|
|
84
|
+
data={added}
|
|
85
|
+
xKey="quarter"
|
|
86
|
+
series={kinds}
|
|
87
|
+
stacked
|
|
88
|
+
valueFormatter={money}
|
|
89
|
+
yTickFormatter={moneyCompact}
|
|
90
|
+
height={256}
|
|
91
|
+
/>
|
|
92
|
+
</PanelGrid>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -28,9 +28,11 @@ export default function CodeBlockExample() {
|
|
|
28
28
|
<CodeBlockContent wrap>{CHECK}</CodeBlockContent>
|
|
29
29
|
</CodeBlock>
|
|
30
30
|
<CodeBlock size="sm">
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
|
|
31
|
+
<CodeBlockHeader>
|
|
32
|
+
<CodeBlockActions>
|
|
33
|
+
<CodeBlockCopyButton value={LOG} />
|
|
34
|
+
</CodeBlockActions>
|
|
35
|
+
</CodeBlockHeader>
|
|
34
36
|
<CodeBlockContent className="max-h-48">{LOG}</CodeBlockContent>
|
|
35
37
|
</CodeBlock>
|
|
36
38
|
</div>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
CardDescription,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle,
|
|
8
|
+
Field,
|
|
9
|
+
FieldDescription,
|
|
10
|
+
FieldError,
|
|
11
|
+
FieldLabel,
|
|
12
|
+
Input,
|
|
13
|
+
InputGroup,
|
|
14
|
+
InputGroupAddon,
|
|
15
|
+
InputGroupInput,
|
|
16
|
+
Select,
|
|
17
|
+
SelectContent,
|
|
18
|
+
SelectGroup,
|
|
19
|
+
SelectItem,
|
|
20
|
+
SelectTrigger,
|
|
21
|
+
SelectValue,
|
|
22
|
+
Textarea,
|
|
23
|
+
ToggleGroup,
|
|
24
|
+
ToggleGroupItem,
|
|
25
|
+
} from "@siyahi/ui";
|
|
26
|
+
import { IndianRupeeIcon } from "lucide-react";
|
|
27
|
+
|
|
28
|
+
const kinds = [
|
|
29
|
+
{ value: "equity", label: "Equity" },
|
|
30
|
+
{ value: "debt", label: "Debt" },
|
|
31
|
+
{ value: "gold", label: "Gold" },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
// Each field is a Field: its label above (small mono capitals, from the theme), the control, and a hint or an error.
|
|
35
|
+
export default function FieldExample() {
|
|
36
|
+
return (
|
|
37
|
+
<Card>
|
|
38
|
+
<CardHeader>
|
|
39
|
+
<CardTitle>Add a holding</CardTitle>
|
|
40
|
+
<CardDescription>What you bought, how much, and how often to review it</CardDescription>
|
|
41
|
+
</CardHeader>
|
|
42
|
+
<CardContent>
|
|
43
|
+
<form className="grid max-w-3xl gap-x-8 gap-y-5 sm:grid-cols-2" onSubmit={(event) => event.preventDefault()}>
|
|
44
|
+
<Field>
|
|
45
|
+
<FieldLabel htmlFor="holding-name">Name</FieldLabel>
|
|
46
|
+
<Input id="holding-name" defaultValue="Nifty Next 50 index fund" />
|
|
47
|
+
<FieldDescription>As it appears on the statement</FieldDescription>
|
|
48
|
+
</Field>
|
|
49
|
+
<Field>
|
|
50
|
+
<FieldLabel htmlFor="holding-kind">Kind</FieldLabel>
|
|
51
|
+
<Select items={kinds} defaultValue="equity">
|
|
52
|
+
<SelectTrigger id="holding-kind" className="w-full">
|
|
53
|
+
<SelectValue />
|
|
54
|
+
</SelectTrigger>
|
|
55
|
+
<SelectContent>
|
|
56
|
+
<SelectGroup>
|
|
57
|
+
{kinds.map((kind) => (
|
|
58
|
+
<SelectItem key={kind.value} value={kind.value}>
|
|
59
|
+
{kind.label}
|
|
60
|
+
</SelectItem>
|
|
61
|
+
))}
|
|
62
|
+
</SelectGroup>
|
|
63
|
+
</SelectContent>
|
|
64
|
+
</Select>
|
|
65
|
+
</Field>
|
|
66
|
+
<Field>
|
|
67
|
+
<FieldLabel htmlFor="holding-amount">Amount invested</FieldLabel>
|
|
68
|
+
<InputGroup>
|
|
69
|
+
<InputGroupAddon>
|
|
70
|
+
<IndianRupeeIcon />
|
|
71
|
+
</InputGroupAddon>
|
|
72
|
+
<InputGroupInput id="holding-amount" defaultValue="2,50,000" inputMode="numeric" />
|
|
73
|
+
</InputGroup>
|
|
74
|
+
<FieldDescription>In rupees, before charges</FieldDescription>
|
|
75
|
+
</Field>
|
|
76
|
+
<Field data-invalid>
|
|
77
|
+
<FieldLabel htmlFor="holding-folio">Folio number</FieldLabel>
|
|
78
|
+
<Input id="holding-folio" defaultValue="9103-44" aria-invalid aria-describedby="holding-folio-error" />
|
|
79
|
+
<FieldError id="holding-folio-error">A folio number is 8 to 12 digits, such as 91034455</FieldError>
|
|
80
|
+
</Field>
|
|
81
|
+
<Field>
|
|
82
|
+
<FieldLabel id="holding-review">Review</FieldLabel>
|
|
83
|
+
<ToggleGroup defaultValue={["quarterly"]} variant="outline" aria-labelledby="holding-review">
|
|
84
|
+
<ToggleGroupItem value="monthly">Monthly</ToggleGroupItem>
|
|
85
|
+
<ToggleGroupItem value="quarterly">Quarterly</ToggleGroupItem>
|
|
86
|
+
<ToggleGroupItem value="yearly">Yearly</ToggleGroupItem>
|
|
87
|
+
</ToggleGroup>
|
|
88
|
+
</Field>
|
|
89
|
+
<Field data-disabled>
|
|
90
|
+
<FieldLabel htmlFor="holding-account">Account</FieldLabel>
|
|
91
|
+
<Input id="holding-account" defaultValue="Demat, joint" disabled />
|
|
92
|
+
<FieldDescription>Set by the statement you imported</FieldDescription>
|
|
93
|
+
</Field>
|
|
94
|
+
<Field className="sm:col-span-2">
|
|
95
|
+
<FieldLabel htmlFor="holding-note">Note</FieldLabel>
|
|
96
|
+
<Textarea id="holding-note" placeholder="Why you bought it, and what would make you sell" />
|
|
97
|
+
</Field>
|
|
98
|
+
<div className="flex gap-2 sm:col-span-2">
|
|
99
|
+
<Button type="submit">Save holding</Button>
|
|
100
|
+
<Button type="button" variant="outline">
|
|
101
|
+
Cancel
|
|
102
|
+
</Button>
|
|
103
|
+
</div>
|
|
104
|
+
</form>
|
|
105
|
+
</CardContent>
|
|
106
|
+
</Card>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
@@ -5,13 +5,13 @@ function Row({ label }: { label: string }) {
|
|
|
5
5
|
return (
|
|
6
6
|
<TableRow>
|
|
7
7
|
<TableCell>{label}</TableCell>
|
|
8
|
-
<TableCell
|
|
9
|
-
<TableCell
|
|
10
|
-
<TableCell
|
|
11
|
-
<TableCell
|
|
12
|
-
<TableCell
|
|
13
|
-
<TableCell
|
|
14
|
-
<TableCell
|
|
8
|
+
<TableCell data-numeric>{count(153110)}</TableCell>
|
|
9
|
+
<TableCell data-numeric>{money(153110)}</TableCell>
|
|
10
|
+
<TableCell data-numeric>{moneyCompact(99999)}</TableCell>
|
|
11
|
+
<TableCell data-numeric>{moneyCompact(240000)}</TableCell>
|
|
12
|
+
<TableCell data-numeric>{moneyCompact(400000000)}</TableCell>
|
|
13
|
+
<TableCell data-numeric>{pct(0.1234)}</TableCell>
|
|
14
|
+
<TableCell data-numeric>{time("2026-10-20T09:00:00Z")}</TableCell>
|
|
15
15
|
</TableRow>
|
|
16
16
|
);
|
|
17
17
|
}
|
|
@@ -22,13 +22,13 @@ export default function FormattersExample() {
|
|
|
22
22
|
<TableHeader>
|
|
23
23
|
<TableRow>
|
|
24
24
|
<TableHead>Locale</TableHead>
|
|
25
|
-
<TableHead
|
|
26
|
-
<TableHead
|
|
27
|
-
<TableHead
|
|
28
|
-
<TableHead
|
|
29
|
-
<TableHead
|
|
30
|
-
<TableHead
|
|
31
|
-
<TableHead
|
|
25
|
+
<TableHead data-numeric>count</TableHead>
|
|
26
|
+
<TableHead data-numeric>money</TableHead>
|
|
27
|
+
<TableHead data-numeric>moneyCompact</TableHead>
|
|
28
|
+
<TableHead data-numeric>moneyCompact</TableHead>
|
|
29
|
+
<TableHead data-numeric>moneyCompact</TableHead>
|
|
30
|
+
<TableHead data-numeric>pct</TableHead>
|
|
31
|
+
<TableHead data-numeric>time</TableHead>
|
|
32
32
|
</TableRow>
|
|
33
33
|
</TableHeader>
|
|
34
34
|
<TableBody>
|
|
@@ -1,33 +1,23 @@
|
|
|
1
|
-
import { Input } from "@siyahi/ui";
|
|
1
|
+
import { Field, FieldDescription, FieldError, FieldLabel, Input } from "@siyahi/ui";
|
|
2
2
|
|
|
3
3
|
// A field is its label, the input and one line under it: a hint, or the error that replaces it.
|
|
4
4
|
export default function InputStatesExample() {
|
|
5
5
|
return (
|
|
6
6
|
<div className="grid max-w-sm gap-5">
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
Monthly budget
|
|
10
|
-
</label>
|
|
7
|
+
<Field>
|
|
8
|
+
<FieldLabel htmlFor="budget">Monthly budget</FieldLabel>
|
|
11
9
|
<Input id="budget" inputMode="numeric" defaultValue="25,000" aria-describedby="budget-hint" />
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<div className="grid gap-1.5">
|
|
17
|
-
<label htmlFor="pin" className="text-sm font-medium">
|
|
18
|
-
PIN code
|
|
19
|
-
</label>
|
|
10
|
+
<FieldDescription id="budget-hint">In rupees, before tax</FieldDescription>
|
|
11
|
+
</Field>
|
|
12
|
+
<Field data-invalid>
|
|
13
|
+
<FieldLabel htmlFor="pin">PIN code</FieldLabel>
|
|
20
14
|
<Input id="pin" defaultValue="56/001" aria-invalid aria-describedby="pin-error" />
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<div className="grid gap-1.5">
|
|
26
|
-
<label htmlFor="team" className="text-sm font-medium text-muted-foreground">
|
|
27
|
-
Team
|
|
28
|
-
</label>
|
|
15
|
+
<FieldError id="pin-error">A PIN code is six digits, such as 560001</FieldError>
|
|
16
|
+
</Field>
|
|
17
|
+
<Field data-disabled>
|
|
18
|
+
<FieldLabel htmlFor="team">Team</FieldLabel>
|
|
29
19
|
<Input id="team" defaultValue="Finance" disabled />
|
|
30
|
-
</
|
|
20
|
+
</Field>
|
|
31
21
|
</div>
|
|
32
22
|
);
|
|
33
23
|
}
|
|
@@ -75,8 +75,8 @@ function Holdings({ rows }: { rows: Holding[] }) {
|
|
|
75
75
|
<TableRow>
|
|
76
76
|
<TableHead>Holding</TableHead>
|
|
77
77
|
<TableHead>Status</TableHead>
|
|
78
|
-
<TableHead
|
|
79
|
-
<TableHead
|
|
78
|
+
<TableHead data-numeric>Value</TableHead>
|
|
79
|
+
<TableHead data-numeric>12 months</TableHead>
|
|
80
80
|
</TableRow>
|
|
81
81
|
</TableHeader>
|
|
82
82
|
<TableBody>
|
|
@@ -99,8 +99,8 @@ function Holdings({ rows }: { rows: Holding[] }) {
|
|
|
99
99
|
<TableCell>
|
|
100
100
|
<StatusBadge tone={row.tone}>{row.status}</StatusBadge>
|
|
101
101
|
</TableCell>
|
|
102
|
-
<TableCell
|
|
103
|
-
<TableCell
|
|
102
|
+
<TableCell data-numeric>{money(row.value)}</TableCell>
|
|
103
|
+
<TableCell data-numeric>
|
|
104
104
|
<Delta value={row.change} />
|
|
105
105
|
</TableCell>
|
|
106
106
|
</TableRow>
|
|
@@ -109,8 +109,8 @@ function Holdings({ rows }: { rows: Holding[] }) {
|
|
|
109
109
|
<TableFooter>
|
|
110
110
|
<TableRow>
|
|
111
111
|
<TableCell colSpan={2}>Total</TableCell>
|
|
112
|
-
<TableCell
|
|
113
|
-
<TableCell
|
|
112
|
+
<TableCell data-numeric>{money(total)}</TableCell>
|
|
113
|
+
<TableCell data-numeric>{yearAgo > 0 && pct(total / yearAgo - 1)}</TableCell>
|
|
114
114
|
</TableRow>
|
|
115
115
|
</TableFooter>
|
|
116
116
|
</Table>
|