@siyahi/ui 0.1.9-next.17 → 0.1.9-next.18
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/README.md +77 -207
- package/agents/examples/accordion.tsx +39 -0
- package/agents/examples/alert.tsx +25 -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 +30 -0
- package/agents/examples/bar-list.tsx +24 -0
- package/agents/examples/breadcrumb.tsx +28 -0
- package/agents/examples/button.tsx +21 -0
- package/agents/examples/calendar.tsx +15 -0
- package/agents/examples/card.tsx +34 -0
- package/agents/examples/chart-area.tsx +38 -0
- package/agents/examples/chart-bar-flows.tsx +31 -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 +70 -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-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 +50 -0
- package/agents/examples/heatmap-status.tsx +51 -0
- package/agents/examples/heatmap-weekday.tsx +53 -0
- package/agents/examples/input.tsx +17 -0
- package/agents/examples/local-time.tsx +14 -0
- package/agents/examples/metric-strip.tsx +40 -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/scroll-area.tsx +20 -0
- package/agents/examples/section-cards-select.tsx +27 -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 +115 -0
- package/agents/examples/table.tsx +50 -0
- package/agents/examples/tabs.tsx +16 -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 +87 -0
- package/agents/manifest.json +931 -0
- package/agents/report-rules.json +7 -0
- package/dist/components/registry/charts/bar-chart-card.js +1 -0
- package/dist/components/registry/dashboardcn/bar-list.js +8 -7
- package/dist/components/registry/heatmap/calendar-heatmap.js +8 -1
- package/dist/components/registry/heatmap/status-heatmap.js +8 -1
- package/dist/components/registry/heatmap/weekday-heatmap.d.ts +6 -2
- package/dist/components/registry/heatmap/weekday-heatmap.js +56 -37
- package/dist/components/registry/niko-table/core/data-table-context.d.ts +2 -0
- package/dist/components/registry/niko-table/core/data-table-context.js +21 -0
- package/dist/components/registry/niko-table/core/data-table-grouped-row.js +3 -1
- package/dist/components/registry/niko-table/core/data-table-structure.js +15 -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-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 +2 -2
- package/dist/components/registry/sidebar-07/nav-main.js +7 -1
- package/dist/components/siyahi/treemap.js +46 -4
- package/dist/lib/chart-frame.js +180 -124
- package/dist/lib/chart-series.d.ts +1 -1
- package/dist/lib/format.js +32 -13
- package/dist/lib/heatmap-navigation.d.ts +8 -0
- package/dist/lib/heatmap-navigation.js +49 -0
- package/package.json +3 -1
- package/styles/siyahi.css +24 -0
package/README.md
CHANGED
|
@@ -2,20 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Siyahi
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
light and dark, a few finance components, locale-aware formatters, a lint that
|
|
10
|
-
keeps pages on the theme, and a catalogue site that is the documentation.
|
|
5
|
+
A design system for data-heavy React apps: [shadcn/ui](https://ui.shadcn.com)
|
|
6
|
+
on [Base UI](https://base-ui.com) and Tailwind CSS v4, with a shared theme,
|
|
7
|
+
charts, tables and locale-aware formatters. Components ship in `@siyahi/ui`;
|
|
8
|
+
checks and build helpers ship in `@siyahi/tools`.
|
|
11
9
|
|
|
12
|
-
**
|
|
10
|
+
**[Browse the catalogue](https://siyahi.jatinbansal.com)** for components and live examples.
|
|
11
|
+
|
|
12
|
+
## For agents
|
|
13
|
+
|
|
14
|
+
Install the public [Siyahi skill](https://github.com/jatinbansal1998/siyahi/blob/main/skills/siyahi/SKILL.md):
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npx skills add jatinbansal1998/siyahi --skill siyahi --agent claude-code --agent codex
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Read the installed package's `agents/manifest.json` to select components and
|
|
21
|
+
recipes, then only the matching `agents/examples/*.tsx`. Exact prop types are in
|
|
22
|
+
`dist/index.d.ts`. The skill guides reuse and verification; page structure and
|
|
23
|
+
interactions remain yours. No other skill or local Siyahi checkout is required.
|
|
13
24
|
|
|
14
25
|
## Install
|
|
15
26
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
Releases use the `next` tag until 1.0. Siyahi needs React 19 and Tailwind CSS v4.
|
|
28
|
+
Compile its stylesheet with the Tailwind Vite plugin; a plain CSS import leaves
|
|
29
|
+
components unstyled.
|
|
19
30
|
|
|
20
31
|
```sh
|
|
21
32
|
npm install @siyahi/ui@next tailwindcss @tailwindcss/vite
|
|
@@ -23,7 +34,7 @@ npm install --save-dev @siyahi/tools@next
|
|
|
23
34
|
```
|
|
24
35
|
|
|
25
36
|
```ts
|
|
26
|
-
// vite.config.ts
|
|
37
|
+
// vite.config.ts: add to your existing plugins
|
|
27
38
|
import tailwindcss from "@tailwindcss/vite";
|
|
28
39
|
import { preloadFonts } from "@siyahi/tools/vite";
|
|
29
40
|
export default defineConfig({ plugins: [react(), tailwindcss(), preloadFonts()] });
|
|
@@ -45,234 +56,93 @@ createRoot(root).render(
|
|
|
45
56
|
);
|
|
46
57
|
```
|
|
47
58
|
|
|
48
|
-
`preloadFonts()`
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Geist swaps in. An app that renders its own HTML adds the tags itself, with
|
|
53
|
-
the hashed URLs of `geist-latin-wght-normal.woff2`,
|
|
54
|
-
`geist-latin-ext-wght-normal.woff2` and `geist-mono-latin-wght-normal.woff2`.
|
|
55
|
-
|
|
56
|
-
Everything comes from `@siyahi/ui`: the shadcn components, the registry
|
|
57
|
-
add-ons (chart cards, data table, heatmaps, stat tiles, sidebar) and Siyahi's
|
|
58
|
-
own components. Add `lucide-react` only if your
|
|
59
|
-
own code imports icons. A Next.js app compiles the same stylesheet through
|
|
60
|
-
`@tailwindcss/postcss` instead of the Vite plugin.
|
|
61
|
-
|
|
62
|
-
### Also on GitHub releases
|
|
63
|
-
|
|
64
|
-
Each explicit release from `main` also attaches both tarballs to a GitHub release
|
|
65
|
-
(`v<version>`, plus a rolling `next`). They are a fallback if npm is unreachable:
|
|
66
|
-
`npm install --allow-remote=root https://github.com/jatinbansal1998/siyahi/releases/download/v<version>/siyahi-ui-<version>.tgz`.
|
|
67
|
-
|
|
68
|
-
## What is in it
|
|
69
|
-
|
|
70
|
-
- **shadcn/ui components** in the `base-nova` style, shadcn's flat and compact
|
|
71
|
-
one, installed with the shadcn CLI and never edited.
|
|
72
|
-
- **Registry add-ons**, copied once with their origin and licence recorded:
|
|
73
|
-
bar, area and line chart cards from shadcn's chart blocks, a data table on
|
|
74
|
-
TanStack Table, calendar, weekday and status heatmaps, a ranked
|
|
75
|
-
bar list, a `Sparkline`, the `MetricStrip` row of figures, the
|
|
76
|
-
`SectionCards` stat tile and the `sidebar-07` app shell.
|
|
77
|
-
- **Siyahi components**: `Delta` (a signed figure with ▲ ▼), `PriceChart`
|
|
78
|
-
(TradingView Lightweight Charts in theme colours), `Treemap` (holdings heat
|
|
79
|
-
map; hover or tap a tile for its figures) with `TreemapLegend` (its colour
|
|
80
|
-
scale), `LocalTime` (a time in the configured zone with the viewer's own clock
|
|
81
|
-
in a tooltip), `ToneProgress` (Progress in a meaning colour), the page parts
|
|
82
|
-
`PageSection`, `PageSubheading`, `DataList` and `InlineCode`, the data table
|
|
83
|
-
parts `DataTableSortHeader` (sorts on one click) and `DataTableRowCount`
|
|
84
|
-
("12 of 48"), `DataBar` (a figure in a table cell with a bar giving its size
|
|
85
|
-
against the column's largest), `PanelGrid` (data blocks side by side, with
|
|
86
|
-
hairlines between them on a ruled page), and `SiyahiProvider`.
|
|
87
|
-
- **Surfaces**: by default a data block has no box. Every `Card` on a ruled
|
|
88
|
-
page, chart cards and stat tiles included, loses its fill, corner and ring,
|
|
89
|
-
and a `PanelGrid` draws hairlines between blocks; see Surfaces below. A
|
|
90
|
-
category (a sector, a
|
|
91
|
-
broker, a unit's kind) is an outline `Badge`: categories stay neutral, and
|
|
92
|
-
colour is left to the four meaning colours and the charts. On a narrow card
|
|
93
|
-
(header under 24rem, so any phone) a header action such as a toggle drops
|
|
94
|
-
under the title and description, left-aligned; a stat tile's badge stays
|
|
95
|
-
top right.
|
|
96
|
-
- **Formatters**: `count`, `money`, `moneyCompact`, `pct` and `time`, or `useFormat()`
|
|
97
|
-
for the same bound to the provider's locale.
|
|
98
|
-
`useFormat().time(value, { withDate: true })` (or
|
|
99
|
-
`time(value, locale, { withDate: true })`) and `<LocalTime withDate>` write
|
|
100
|
-
the date first: `20 Oct 2026, 14:30 IST`.
|
|
101
|
-
- **`report.css`** for static HTML reports that do not use React: the theme as
|
|
102
|
-
plain CSS variables plus base body styles, with no network requests.
|
|
103
|
-
|
|
104
|
-
## Which component
|
|
105
|
-
|
|
106
|
-
| Need | Component |
|
|
107
|
-
| ----------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
108
|
-
| Values over time or another ordered axis (months, hours, price buckets) | `BarChartCard`, `AreaChartCard` or `LineChartCard` |
|
|
109
|
-
| Counts or amounts per period, one series or several | `BarChartCard`; `stacked` when the series add up to a total |
|
|
110
|
-
| A running level, such as a portfolio's value against money put in | `AreaChartCard` |
|
|
111
|
-
| Series compared point by point, such as a return against an index | `LineChartCard` |
|
|
112
|
-
| Samples in time with limits and events marked | `LineChartCard` with `xDomain`, `xTicks` and `referenceLines` |
|
|
113
|
-
| Long category names, such as sectors | `BarChartCard` with `horizontal` |
|
|
114
|
-
| A gain above zero and a loss below it | a series with `color` and `negativeColor` |
|
|
115
|
-
| Ranked counts or amounts by category (a name, a bar and a figure) | `BarList`; give two lists one `max` to share a scale |
|
|
116
|
-
| Where a budget sits, a split of a whole, or losses against gains | `DistributionBar` |
|
|
117
|
-
| Headline figures with their change | `SectionCards`, with a `Delta` in each badge |
|
|
118
|
-
| Many figures of equal weight, each with its change and recent run | `MetricStrip` |
|
|
119
|
-
| A run of values beside a figure, in a tile, a strip or a table cell | `Sparkline`; in a tile, `SectionCards`' `trend` |
|
|
120
|
-
| A table column that should read as a bar chart | `DataBar` in the column's cell |
|
|
121
|
-
| One instrument's price history | `PriceChart` |
|
|
122
|
-
| Holdings sized by weight and coloured by change | `Treemap` |
|
|
123
|
-
| Activity by day, by weekday and hour, or a status over time | `CalendarHeatmap`, `WeekdayHeatmap`, `StatusHeatmap` |
|
|
124
|
-
| Rows to sort and filter | `DataTable`, inside a `Card` |
|
|
125
|
-
| A column that sorts on one click; a search and an "n of m" count | `DataTableSortHeader`; `DataTableSearchFilter`, `DataTableRowCount` |
|
|
126
|
-
| Stat tiles that pick a scope for the page | `SectionCards` with `selected` and `onSelect` |
|
|
127
|
-
| A share or a part of a whole, coloured as a gain or a loss | `ToneProgress` |
|
|
128
|
-
| The colour scale under a `Treemap` | `TreemapLegend`, with the map's `range` |
|
|
129
|
-
| One part of a long page: rule, eyebrow, heading, lead, action | `PageSection`, with `PageSubheading` inside |
|
|
130
|
-
| Label and value pairs, such as a record's fields | `DataList` and `DataListItem` |
|
|
131
|
-
| A command or file to copy, wrapped or scrolling | `CodeBlock` with `CodeBlockCopyButton` |
|
|
132
|
-
| A labelled copy action, such as "Copy all" for a section | `CopyButton` |
|
|
133
|
-
| Data blocks side by side: charts, tables, a strip of figures | `PanelGrid` |
|
|
134
|
-
| Boxes back, or no lines at all, for a page or a part of one | `SiyahiProvider` with `surface="card"` or `surface="open"` |
|
|
135
|
-
| A command, file or identifier inside prose | `InlineCode` |
|
|
136
|
-
| A signed figure (a gain, a loss, a change) | `Delta` |
|
|
137
|
-
| A time, with the viewer's own clock on hover | `LocalTime` |
|
|
138
|
-
|
|
139
|
-
The three chart cards take the rows, the field the x axis reads and the series,
|
|
140
|
-
and own everything else: the card and its header action (a range or mode
|
|
141
|
-
toggle), the axes, the dashed horizontal grid, Geist Mono ticks, a tooltip that
|
|
142
|
-
names the hovered point and gives each series' formatted value, and the legend
|
|
143
|
-
below. Props cover the rest: a footer, a placeholder while data loads,
|
|
144
|
-
reference lines, a numeric x axis, a fixed value axis, axis titles, a second
|
|
145
|
-
line under each tick, a picked category, sideways bars and straight segments.
|
|
146
|
-
A page never puts Recharts axes, grids or tooltips together itself.
|
|
59
|
+
`preloadFonts()` loads Geist and Geist Mono with the scripts. Add `lucide-react`
|
|
60
|
+
only when your own code imports icons. Next.js compiles the stylesheet through
|
|
61
|
+
`@tailwindcss/postcss` instead of the Vite plugin. Static HTML reports inline the
|
|
62
|
+
package's `report.css` and follow `agents/report-rules.json`.
|
|
147
63
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
title="Orders by hour"
|
|
151
|
-
data={[
|
|
152
|
-
{ hour: 9, orders: 42 },
|
|
153
|
-
{ hour: 10, orders: 31 },
|
|
154
|
-
]}
|
|
155
|
-
xKey="hour"
|
|
156
|
-
xFormatter={(hour) => `${String(hour).padStart(2, "0")}:00`}
|
|
157
|
-
series={[{ key: "orders", label: "Orders", color: "var(--chart-1)" }]}
|
|
158
|
-
height={256}
|
|
159
|
-
/>
|
|
160
|
-
```
|
|
64
|
+
If npm is unreachable, both package tarballs are attached to
|
|
65
|
+
[GitHub releases](https://github.com/jatinbansal1998/siyahi/releases).
|
|
161
66
|
|
|
162
67
|
## Locale
|
|
163
68
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
follows:
|
|
69
|
+
`useFormat()` provides `count`, `money`, `moneyCompact`, `pct` and `time`,
|
|
70
|
+
bound to the provider's locale. Defaults are Indian English, rupees and India
|
|
71
|
+
Standard Time: `₹1,53,110`, `₹2.4L`, `14:30 IST`. Use `Delta` for signed changes.
|
|
72
|
+
Override the locale for a whole app or a nested section:
|
|
169
73
|
|
|
170
74
|
```tsx
|
|
171
75
|
<SiyahiProvider locale={{ numberLocale: "en-US", currency: "USD", timeZone: "America/New_York" }}>
|
|
172
76
|
```
|
|
173
77
|
|
|
174
|
-
|
|
175
|
-
loss, a change) goes through `<Delta>`, which adds ▲ or ▼ and the meaning
|
|
176
|
-
colour. Time zone names come from the runtime's ICU data; a slim Node or
|
|
177
|
-
browser build may print `GMT+5:30` where a full one prints `IST`.
|
|
78
|
+
## Responsive behavior
|
|
178
79
|
|
|
179
|
-
|
|
80
|
+
Data tables suspend horizontal freezing below 40rem of their own available
|
|
81
|
+
space, including narrow panels on a laptop. Pinning preferences, search, sort,
|
|
82
|
+
selection and expansion stay intact. All columns remain reachable by scrolling;
|
|
83
|
+
the scrolling region also accepts keyboard focus. For page-specific compact
|
|
84
|
+
records, choose essential columns and keep every other field in accessible
|
|
85
|
+
details or an explicit full-table view.
|
|
180
86
|
|
|
181
|
-
|
|
182
|
-
`
|
|
87
|
+
The shipped `data-table-filters` recipe moves secondary filters into a `Sheet`
|
|
88
|
+
using `useDataTable().isCompact`. Configure filtering explicitly when its
|
|
89
|
+
controls render conditionally. Keep search and the active-filter count visible.
|
|
90
|
+
Use container queries for layout and pointer capability for touch targets;
|
|
91
|
+
a touch laptop needs the same reachable controls as a phone.
|
|
183
92
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
- `"card"`: shadcn's own Nova card, a filled box with a 1px ring.
|
|
93
|
+
Ranked lists wrap long labels in narrow panels. Horizontal charts reserve space
|
|
94
|
+
for bars and wrap their category labels; exact axis ticks keep their normal
|
|
95
|
+
text size and scroll when necessary. Heatmap examples expose values on selection
|
|
96
|
+
and support one keyboard entry with arrow navigation. `WeekdayHeatmap` accepts
|
|
97
|
+
`hours` and `weekdays` to show a relevant domain without changing data labels.
|
|
190
98
|
|
|
191
|
-
|
|
192
|
-
for one part of a page. A picked `SectionCards` tile keeps its ring on every
|
|
193
|
-
surface.
|
|
99
|
+
## Surfaces
|
|
194
100
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
101
|
+
`SiyahiProvider` sets how data blocks sit on the page:
|
|
102
|
+
|
|
103
|
+
- `surface="ruled"` (default, even outside a provider): unboxed blocks;
|
|
104
|
+
`PanelGrid` draws hairlines between them.
|
|
105
|
+
- `surface="open"`: no boxes or rules; card padding is removed.
|
|
106
|
+
- `surface="card"`: shadcn's filled Nova cards with a ring.
|
|
200
107
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
108
|
+
Nest a provider to change one section. Stack `PageSection` blocks with
|
|
109
|
+
`flex flex-col gap-6`; use `PanelGrid` for blocks side by side. Categories use
|
|
110
|
+
neutral outline badges, leaving colour for meaning and chart series.
|
|
204
111
|
|
|
205
112
|
## Dark mode
|
|
206
113
|
|
|
207
|
-
The
|
|
208
|
-
toggle
|
|
209
|
-
|
|
210
|
-
line after the import and sets the `dark` class on `<html>`:
|
|
114
|
+
The theme follows the device through `prefers-color-scheme`. For an app-owned
|
|
115
|
+
toggle, override the variant after the stylesheet import and set the `dark`
|
|
116
|
+
class on `<html>`:
|
|
211
117
|
|
|
212
118
|
```css
|
|
213
119
|
@import "@siyahi/ui/styles.css";
|
|
214
120
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
215
121
|
```
|
|
216
122
|
|
|
217
|
-
|
|
218
|
-
`<html>` yourself as well, so scrollbars and form controls match.
|
|
219
|
-
|
|
220
|
-
## Lint
|
|
221
|
-
|
|
222
|
-
`@siyahi/tools` ships an [oxlint](https://oxc.rs) plugin. Its rules run only in
|
|
223
|
-
files that import `@siyahi/ui`, so older pages are left alone. They reject
|
|
224
|
-
colour literals (hex, `rgb()`, `oklch()`), Tailwind palette colours, Tailwind
|
|
225
|
-
arbitrary values such as `text-[13px]`, `dark:` and `light:` variants,
|
|
226
|
-
numeric font sizes, and chart configs with a per-scheme `theme` map (shadcn's
|
|
227
|
-
chart applies its dark half under a `.dark` class Siyahi never sets; name a
|
|
228
|
-
chart token with `color: "var(--chart-1)"` instead). Two of the rules are
|
|
229
|
-
[`@shadcn/lint`](https://github.com/shadcn-ui/lint)'s, scoped the same way.
|
|
230
|
-
|
|
231
|
-
```sh
|
|
232
|
-
npm install --save-dev @siyahi/tools@next oxlint
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
```json
|
|
236
|
-
{
|
|
237
|
-
"jsPlugins": ["@siyahi/tools/lint"],
|
|
238
|
-
"settings": { "shadcn": { "ui": "@siyahi/ui", "themeImports": ["^@siyahi/ui/"] } },
|
|
239
|
-
"rules": {
|
|
240
|
-
"siyahi/no-color-literal": "error",
|
|
241
|
-
"siyahi/no-scheme-variant": "error",
|
|
242
|
-
"siyahi/no-numeric-font-size": "error",
|
|
243
|
-
"siyahi/no-chart-theme-map": "error",
|
|
244
|
-
"siyahi/no-raw-colors": "error",
|
|
245
|
-
"siyahi/no-arbitrary-values": "error"
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
`@siyahi/tools` also has `siyahi-shots` (screenshots of a page at 1920 and 390
|
|
251
|
-
pixels wide in both schemes, with layout checks), `siyahi-cls` (how far a page
|
|
252
|
-
moves after its first paint on a slow network) and `siyahi-contrast` (the
|
|
253
|
-
theme contrast check). See [packages/tools](packages/tools/README.md).
|
|
123
|
+
Set `color-scheme` on `<html>` as well so native controls match.
|
|
254
124
|
|
|
255
|
-
##
|
|
125
|
+
## Tools
|
|
256
126
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
| `assets/icon.svg` | The mark. |
|
|
127
|
+
`@siyahi/tools` provides theme lint rules, font preload, layout screenshots
|
|
128
|
+
(`siyahi-shots`), loading-shift checks (`siyahi-cls`) and contrast checks
|
|
129
|
+
(`siyahi-contrast`). See the
|
|
130
|
+
[tools guide](https://github.com/jatinbansal1998/siyahi/blob/main/packages/tools/README.md)
|
|
131
|
+
for configuration and commands.
|
|
263
132
|
|
|
264
|
-
Development
|
|
133
|
+
## Development
|
|
265
134
|
|
|
266
135
|
```sh
|
|
267
136
|
pnpm install
|
|
268
|
-
pnpm --filter @siyahi/tools exec playwright install chromium
|
|
269
|
-
pnpm check
|
|
270
|
-
pnpm dev
|
|
137
|
+
pnpm --filter @siyahi/tools exec playwright install chromium
|
|
138
|
+
pnpm check
|
|
139
|
+
pnpm dev
|
|
271
140
|
```
|
|
272
141
|
|
|
273
|
-
|
|
142
|
+
Read [CONTRIBUTING.md](https://github.com/jatinbansal1998/siyahi/blob/main/CONTRIBUTING.md)
|
|
143
|
+
before adding components. Source lives in `packages/ui`, `packages/tools` and
|
|
144
|
+
`apps/catalogue`; the catalogue is the visual documentation.
|
|
274
145
|
|
|
275
146
|
## Licence
|
|
276
147
|
|
|
277
|
-
MIT
|
|
278
|
-
notice; see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
|
148
|
+
MIT. See [LICENSE](LICENSE) and [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
const questions = [
|
|
4
|
+
[
|
|
5
|
+
"prices",
|
|
6
|
+
"When are prices updated?",
|
|
7
|
+
"At the exchange close each trading day, and every minute while markets are open.",
|
|
8
|
+
],
|
|
9
|
+
["lots", "How are lots matched?", "Sells are matched to the oldest buy first, as the tax rules require."],
|
|
10
|
+
["brokers", "Can I add a second broker?", "Yes. Each broker is its own account, and the totals add them up."],
|
|
11
|
+
] as const;
|
|
12
|
+
|
|
13
|
+
function Questions() {
|
|
14
|
+
return questions.map(([value, question, answer]) => (
|
|
15
|
+
<AccordionItem key={value} value={value}>
|
|
16
|
+
<AccordionTrigger>{question}</AccordionTrigger>
|
|
17
|
+
<AccordionContent>{answer}</AccordionContent>
|
|
18
|
+
</AccordionItem>
|
|
19
|
+
));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default function AccordionExample() {
|
|
23
|
+
return (
|
|
24
|
+
<div className="grid gap-6 md:grid-cols-2">
|
|
25
|
+
<div className="flex flex-col gap-2">
|
|
26
|
+
<p className="text-sm text-muted-foreground">One open at a time</p>
|
|
27
|
+
<Accordion aria-label="One open at a time" defaultValue={["prices"]}>
|
|
28
|
+
<Questions />
|
|
29
|
+
</Accordion>
|
|
30
|
+
</div>
|
|
31
|
+
<div className="flex flex-col gap-2">
|
|
32
|
+
<p className="text-sm text-muted-foreground">Several open</p>
|
|
33
|
+
<Accordion aria-label="Several open" multiple defaultValue={["prices", "lots"]}>
|
|
34
|
+
<Questions />
|
|
35
|
+
</Accordion>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Alert, AlertDescription, AlertTitle } from "@siyahi/ui";
|
|
2
|
+
import { CircleAlertIcon, InfoIcon, TriangleAlertIcon } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
export default function AlertExample() {
|
|
5
|
+
return (
|
|
6
|
+
<div className="flex flex-col gap-3">
|
|
7
|
+
<Alert>
|
|
8
|
+
<InfoIcon />
|
|
9
|
+
<AlertTitle>Prices are delayed</AlertTitle>
|
|
10
|
+
<AlertDescription>Quotes refresh every fifteen minutes during market hours.</AlertDescription>
|
|
11
|
+
</Alert>
|
|
12
|
+
<Alert>
|
|
13
|
+
{/* Alert sets its icons to the text colour with a stronger selector; the ! lets the icon's colour win. */}
|
|
14
|
+
<TriangleAlertIcon className="text-warning!" />
|
|
15
|
+
<AlertTitle>Two trades are unmatched</AlertTitle>
|
|
16
|
+
<AlertDescription>The contract notes list trades the ledger does not have yet.</AlertDescription>
|
|
17
|
+
</Alert>
|
|
18
|
+
<Alert variant="destructive">
|
|
19
|
+
<CircleAlertIcon />
|
|
20
|
+
<AlertTitle>Import failed</AlertTitle>
|
|
21
|
+
<AlertDescription>The statement could not be read. Download it again and retry.</AlertDescription>
|
|
22
|
+
</Alert>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AppSidebar, SidebarProvider } from "@siyahi/ui";
|
|
2
|
+
import {
|
|
3
|
+
BlocksIcon,
|
|
4
|
+
ChartAreaIcon,
|
|
5
|
+
CodeIcon,
|
|
6
|
+
FileTextIcon,
|
|
7
|
+
HouseIcon,
|
|
8
|
+
LayersIcon,
|
|
9
|
+
PaletteIcon,
|
|
10
|
+
SlidersHorizontalIcon,
|
|
11
|
+
} from "lucide-react";
|
|
12
|
+
|
|
13
|
+
// No `items` on a view, so each one is a plain link.
|
|
14
|
+
const views = [
|
|
15
|
+
{ title: "Overview", url: "#/overview", icon: <HouseIcon /> },
|
|
16
|
+
{ title: "Foundations", url: "#/foundations", icon: <PaletteIcon /> },
|
|
17
|
+
{ title: "Components", url: "#/components", icon: <LayersIcon /> },
|
|
18
|
+
{ title: "Inputs and overlays", url: "#/inputs", icon: <SlidersHorizontalIcon /> },
|
|
19
|
+
{ title: "Data", url: "#/data", icon: <ChartAreaIcon /> },
|
|
20
|
+
{ title: "Blocks", url: "#/blocks", icon: <BlocksIcon />, isActive: true },
|
|
21
|
+
{ title: "Reports", url: "#/reports", icon: <FileTextIcon /> },
|
|
22
|
+
// linkProps go onto the anchor: here a new tab, in an app often onMouseEnter to prefetch the view's data.
|
|
23
|
+
{
|
|
24
|
+
title: "Source",
|
|
25
|
+
url: "https://github.com/jatinbansal1998/siyahi",
|
|
26
|
+
icon: <CodeIcon />,
|
|
27
|
+
linkProps: { target: "_blank", rel: "noreferrer" },
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export default function AppSidebarExample() {
|
|
32
|
+
return (
|
|
33
|
+
// In an app, AppSidebar sits fixed at the edge; collapsible="none" draws it in place here.
|
|
34
|
+
<SidebarProvider className="min-h-0">
|
|
35
|
+
<AppSidebar collapsible="none" navMain={views} navLabel="Views" className="rounded-lg border" />
|
|
36
|
+
</SidebarProvider>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Avatar, AvatarFallback } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function AvatarExample() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="flex gap-2">
|
|
6
|
+
<Avatar>
|
|
7
|
+
<AvatarFallback>JB</AvatarFallback>
|
|
8
|
+
</Avatar>
|
|
9
|
+
<Avatar>
|
|
10
|
+
<AvatarFallback>HU</AvatarFallback>
|
|
11
|
+
</Avatar>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Badge, Delta } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
export default function BadgeExample() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
6
|
+
<Badge>Equity</Badge>
|
|
7
|
+
<Badge variant="secondary">Mutual fund</Badge>
|
|
8
|
+
<Badge variant="outline">Zerodha</Badge>
|
|
9
|
+
<Badge variant="destructive">Failed</Badge>
|
|
10
|
+
<Badge variant="outline">
|
|
11
|
+
<Delta value={0.042} />
|
|
12
|
+
</Badge>
|
|
13
|
+
<Badge variant="outline">
|
|
14
|
+
<Delta value={-0.013} />
|
|
15
|
+
</Badge>
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BarList, Card, CardContent, CardDescription, CardHeader, CardTitle, useFormat } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
const sectors = [
|
|
4
|
+
{ name: "Information Technology and Services", value: 100 },
|
|
5
|
+
{ name: "Fast Moving Consumer Goods", value: 70 },
|
|
6
|
+
{ name: "Automobile and Auto Components", value: 50 },
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
export default function BarListLabelsExample() {
|
|
10
|
+
const { count } = useFormat();
|
|
11
|
+
return (
|
|
12
|
+
<Card>
|
|
13
|
+
<CardHeader>
|
|
14
|
+
<CardTitle>Orders by sector, ranked</CardTitle>
|
|
15
|
+
<CardDescription>Full labels and order counts stay readable in narrow panels</CardDescription>
|
|
16
|
+
</CardHeader>
|
|
17
|
+
<CardContent>
|
|
18
|
+
<BarList data={sectors} valueFormatter={count} />
|
|
19
|
+
</CardContent>
|
|
20
|
+
</Card>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BarList, Card, CardContent, CardDescription, CardHeader, CardTitle, useFormat } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
// The biggest unrealised gains and losses; made-up figures.
|
|
4
|
+
const gains = [
|
|
5
|
+
{ name: "INFY", value: 84000 },
|
|
6
|
+
{ name: "TCS", value: 52000 },
|
|
7
|
+
{ name: "HDFCBANK", value: 31000 },
|
|
8
|
+
];
|
|
9
|
+
const losses = [
|
|
10
|
+
{ name: "ITC", value: 18400 },
|
|
11
|
+
{ name: "WIPRO", value: 7600 },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export default function BarListSidesExample() {
|
|
15
|
+
const { money } = useFormat();
|
|
16
|
+
// One scale for both lists, so a small loss draws a short bar beside a large gain.
|
|
17
|
+
const max = Math.max(...[...gains, ...losses].map((row) => row.value));
|
|
18
|
+
return (
|
|
19
|
+
<Card>
|
|
20
|
+
<CardHeader>
|
|
21
|
+
<CardTitle>What drives the P&L</CardTitle>
|
|
22
|
+
<CardDescription>The biggest ₹ gains and losses, on one scale</CardDescription>
|
|
23
|
+
</CardHeader>
|
|
24
|
+
<CardContent className="grid gap-6 md:grid-cols-2">
|
|
25
|
+
<BarList data={gains} max={max} color="var(--positive)" valueFormatter={(v) => money(v)} />
|
|
26
|
+
<BarList data={losses} max={max} color="var(--negative)" valueFormatter={(v) => money(v)} />
|
|
27
|
+
</CardContent>
|
|
28
|
+
</Card>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BarList, Card, CardContent, CardDescription, CardHeader, CardTitle, Delta, useFormat } from "@siyahi/ui";
|
|
2
|
+
|
|
3
|
+
// detail is the loss as a share of what the holding cost.
|
|
4
|
+
const largestLosses = [
|
|
5
|
+
{ name: "ITC", value: 18400, detail: <Delta value={-0.062} /> },
|
|
6
|
+
{ name: "HDFCBANK", value: 12900, detail: <Delta value={-0.047} /> },
|
|
7
|
+
{ name: "WIPRO", value: 7600, detail: <Delta value={-0.072} /> },
|
|
8
|
+
{ name: "Asian Paints (India)", value: 4100, detail: <Delta value={-0.06} /> },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export default function BarListExample() {
|
|
12
|
+
const { money } = useFormat();
|
|
13
|
+
return (
|
|
14
|
+
<Card>
|
|
15
|
+
<CardHeader>
|
|
16
|
+
<CardTitle>Needs attention</CardTitle>
|
|
17
|
+
<CardDescription>Largest unrealised losses</CardDescription>
|
|
18
|
+
</CardHeader>
|
|
19
|
+
<CardContent>
|
|
20
|
+
<BarList data={largestLosses} valueFormatter={(v) => money(v)} showPercentage />
|
|
21
|
+
</CardContent>
|
|
22
|
+
</Card>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Breadcrumb,
|
|
3
|
+
BreadcrumbItem,
|
|
4
|
+
BreadcrumbLink,
|
|
5
|
+
BreadcrumbList,
|
|
6
|
+
BreadcrumbPage,
|
|
7
|
+
BreadcrumbSeparator,
|
|
8
|
+
} from "@siyahi/ui";
|
|
9
|
+
|
|
10
|
+
export default function BreadcrumbExample() {
|
|
11
|
+
return (
|
|
12
|
+
<Breadcrumb>
|
|
13
|
+
<BreadcrumbList>
|
|
14
|
+
<BreadcrumbItem>
|
|
15
|
+
<BreadcrumbLink href="#/components">Portfolio</BreadcrumbLink>
|
|
16
|
+
</BreadcrumbItem>
|
|
17
|
+
<BreadcrumbSeparator />
|
|
18
|
+
<BreadcrumbItem>
|
|
19
|
+
<BreadcrumbLink href="#/components">Equity</BreadcrumbLink>
|
|
20
|
+
</BreadcrumbItem>
|
|
21
|
+
<BreadcrumbSeparator />
|
|
22
|
+
<BreadcrumbItem>
|
|
23
|
+
<BreadcrumbPage>INFY</BreadcrumbPage>
|
|
24
|
+
</BreadcrumbItem>
|
|
25
|
+
</BreadcrumbList>
|
|
26
|
+
</Breadcrumb>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Button } from "@siyahi/ui";
|
|
2
|
+
import { DownloadIcon, RefreshCwIcon } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
export default function ButtonExample() {
|
|
5
|
+
return (
|
|
6
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
7
|
+
<Button>Save</Button>
|
|
8
|
+
<Button variant="outline">
|
|
9
|
+
<DownloadIcon />
|
|
10
|
+
Export
|
|
11
|
+
</Button>
|
|
12
|
+
<Button variant="secondary">Secondary</Button>
|
|
13
|
+
<Button variant="ghost">Ghost</Button>
|
|
14
|
+
<Button variant="destructive">Delete</Button>
|
|
15
|
+
<Button variant="link">Link</Button>
|
|
16
|
+
<Button variant="outline" size="icon" aria-label="Refresh">
|
|
17
|
+
<RefreshCwIcon />
|
|
18
|
+
</Button>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Calendar } from "@siyahi/ui";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
|
|
4
|
+
export default function CalendarExample() {
|
|
5
|
+
const [date, setDate] = useState<Date | undefined>(new Date(2026, 9, 20));
|
|
6
|
+
return (
|
|
7
|
+
<Calendar
|
|
8
|
+
mode="single"
|
|
9
|
+
selected={date}
|
|
10
|
+
onSelect={setDate}
|
|
11
|
+
defaultMonth={new Date(2026, 9, 1)}
|
|
12
|
+
className="w-fit rounded-lg border"
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
}
|