@squadbase/vantage 0.0.1 → 0.1.0
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 +21 -4
- package/dist/chunk-A2UUGASH.js +12 -0
- package/dist/chunk-A2UUGASH.js.map +1 -0
- package/dist/{chunk-ZGDU5YLH.js → chunk-PRFBSQA4.js} +9 -5
- package/dist/chunk-PRFBSQA4.js.map +1 -0
- package/dist/chunk-WQZYXXQW.js +2249 -0
- package/dist/chunk-WQZYXXQW.js.map +1 -0
- package/dist/{chunk-73J5ZD4C.js → chunk-YLAB6UQS.js} +17 -3
- package/dist/chunk-YLAB6UQS.js.map +1 -0
- package/dist/cli.js +607 -36
- package/dist/cli.js.map +1 -1
- package/dist/components/index.d.ts +554 -0
- package/dist/components/index.js +1983 -0
- package/dist/components/index.js.map +1 -0
- package/dist/markdown/index.d.ts +9 -0
- package/dist/markdown/index.js +26 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/query/index.d.ts +27 -1
- package/dist/query/index.js +18 -0
- package/dist/query/index.js.map +1 -1
- package/dist/server/node.js +6 -1
- package/dist/server/node.js.map +1 -1
- package/dist/ui/index.d.ts +316 -200
- package/dist/ui/index.js +566 -511
- package/dist/ui/index.js.map +1 -1
- package/dist/vite/index.js +2 -2
- package/docs/en/agent-skills.md +89 -0
- package/docs/en/api-and-server.md +84 -0
- package/docs/en/build-and-deploy.md +280 -0
- package/docs/en/cli-reference.md +311 -0
- package/docs/en/components.md +233 -0
- package/docs/en/data-fetching.md +78 -0
- package/docs/en/environment-variables.md +69 -0
- package/docs/en/getting-started.md +95 -0
- package/docs/en/index.md +65 -0
- package/docs/en/markdown/markdown-renderer.md +44 -0
- package/docs/en/pages-and-metadata.md +56 -0
- package/docs/en/parts/app-shell.md +54 -0
- package/docs/en/parts/dashboard-card.md +64 -0
- package/docs/en/parts/data-table.md +86 -0
- package/docs/en/parts/date-range-picker.md +41 -0
- package/docs/en/parts/echart.md +53 -0
- package/docs/en/parts/filter-bar.md +66 -0
- package/docs/en/parts/funnel-steps.md +33 -0
- package/docs/en/parts/metric-value.md +23 -0
- package/docs/en/parts/multi-select.md +27 -0
- package/docs/en/parts/page-shell.md +45 -0
- package/docs/en/parts/searchable-select.md +47 -0
- package/docs/en/parts/section-header.md +20 -0
- package/docs/en/parts/segmented-control.md +25 -0
- package/docs/en/parts/status-badge.md +44 -0
- package/docs/en/parts/trend-indicator.md +26 -0
- package/docs/en/routing.md +95 -0
- package/docs/en/ui/accordion.md +36 -0
- package/docs/en/ui/alert.md +31 -0
- package/docs/en/ui/badge.md +23 -0
- package/docs/en/ui/breadcrumb.md +38 -0
- package/docs/en/ui/button.md +39 -0
- package/docs/en/ui/calendar.md +28 -0
- package/docs/en/ui/card.md +35 -0
- package/docs/en/ui/checkbox.md +34 -0
- package/docs/en/ui/cn.md +34 -0
- package/docs/en/ui/collapsible.md +21 -0
- package/docs/en/ui/command.md +37 -0
- package/docs/en/ui/dialog.md +52 -0
- package/docs/en/ui/dropdown-menu.md +50 -0
- package/docs/en/ui/empty.md +22 -0
- package/docs/en/ui/error-state.md +50 -0
- package/docs/en/ui/input-group.md +30 -0
- package/docs/en/ui/input.md +28 -0
- package/docs/en/ui/label.md +19 -0
- package/docs/en/ui/loading.md +19 -0
- package/docs/en/ui/popover.md +34 -0
- package/docs/en/ui/progress.md +28 -0
- package/docs/en/ui/scroll-area.md +23 -0
- package/docs/en/ui/select.md +63 -0
- package/docs/en/ui/separator.md +15 -0
- package/docs/en/ui/sheet.md +28 -0
- package/docs/en/ui/sidebar.md +92 -0
- package/docs/en/ui/skeleton.md +16 -0
- package/docs/en/ui/slider.md +21 -0
- package/docs/en/ui/spinner.md +14 -0
- package/docs/en/ui/switch.md +19 -0
- package/docs/en/ui/table.md +24 -0
- package/docs/en/ui/tabs.md +23 -0
- package/docs/en/ui/textarea.md +15 -0
- package/docs/en/ui/toggle-group.md +26 -0
- package/docs/en/ui/toggle.md +19 -0
- package/docs/en/ui/tooltip.md +22 -0
- package/docs/en/ui/use-is-mobile.md +18 -0
- package/docs/en/ui-and-theming.md +95 -0
- package/docs/index.json +1306 -0
- package/docs/ja/agent-skills.md +87 -0
- package/docs/ja/api-and-server.md +84 -0
- package/docs/ja/build-and-deploy.md +279 -0
- package/docs/ja/cli-reference.md +305 -0
- package/docs/ja/components.md +229 -0
- package/docs/ja/data-fetching.md +78 -0
- package/docs/ja/environment-variables.md +68 -0
- package/docs/ja/getting-started.md +95 -0
- package/docs/ja/index.md +65 -0
- package/docs/ja/markdown/markdown-renderer.md +43 -0
- package/docs/ja/pages-and-metadata.md +56 -0
- package/docs/ja/parts/app-shell.md +54 -0
- package/docs/ja/parts/dashboard-card.md +64 -0
- package/docs/ja/parts/data-table.md +85 -0
- package/docs/ja/parts/date-range-picker.md +41 -0
- package/docs/ja/parts/echart.md +52 -0
- package/docs/ja/parts/filter-bar.md +64 -0
- package/docs/ja/parts/funnel-steps.md +33 -0
- package/docs/ja/parts/metric-value.md +25 -0
- package/docs/ja/parts/multi-select.md +27 -0
- package/docs/ja/parts/page-shell.md +45 -0
- package/docs/ja/parts/searchable-select.md +47 -0
- package/docs/ja/parts/section-header.md +20 -0
- package/docs/ja/parts/segmented-control.md +26 -0
- package/docs/ja/parts/status-badge.md +44 -0
- package/docs/ja/parts/trend-indicator.md +26 -0
- package/docs/ja/routing.md +95 -0
- package/docs/ja/ui/accordion.md +37 -0
- package/docs/ja/ui/alert.md +31 -0
- package/docs/ja/ui/badge.md +23 -0
- package/docs/ja/ui/breadcrumb.md +38 -0
- package/docs/ja/ui/button.md +39 -0
- package/docs/ja/ui/calendar.md +28 -0
- package/docs/ja/ui/card.md +35 -0
- package/docs/ja/ui/checkbox.md +34 -0
- package/docs/ja/ui/cn.md +34 -0
- package/docs/ja/ui/collapsible.md +21 -0
- package/docs/ja/ui/command.md +36 -0
- package/docs/ja/ui/dialog.md +51 -0
- package/docs/ja/ui/dropdown-menu.md +50 -0
- package/docs/ja/ui/empty.md +22 -0
- package/docs/ja/ui/error-state.md +50 -0
- package/docs/ja/ui/input-group.md +30 -0
- package/docs/ja/ui/input.md +28 -0
- package/docs/ja/ui/label.md +19 -0
- package/docs/ja/ui/loading.md +19 -0
- package/docs/ja/ui/popover.md +34 -0
- package/docs/ja/ui/progress.md +28 -0
- package/docs/ja/ui/scroll-area.md +24 -0
- package/docs/ja/ui/select.md +64 -0
- package/docs/ja/ui/separator.md +15 -0
- package/docs/ja/ui/sheet.md +28 -0
- package/docs/ja/ui/sidebar.md +92 -0
- package/docs/ja/ui/skeleton.md +16 -0
- package/docs/ja/ui/slider.md +21 -0
- package/docs/ja/ui/spinner.md +14 -0
- package/docs/ja/ui/switch.md +19 -0
- package/docs/ja/ui/table.md +24 -0
- package/docs/ja/ui/tabs.md +24 -0
- package/docs/ja/ui/textarea.md +15 -0
- package/docs/ja/ui/toggle-group.md +27 -0
- package/docs/ja/ui/toggle.md +19 -0
- package/docs/ja/ui/tooltip.md +22 -0
- package/docs/ja/ui/use-is-mobile.md +18 -0
- package/docs/ja/ui-and-theming.md +95 -0
- package/package.json +29 -4
- package/registry/blocks/sales-overview.tsx +43 -19
- package/registry/ui/data-table.tsx +702 -102
- package/skills/vantage-add-feature/SKILL.md +150 -0
- package/skills/vantage-app/SKILL.md +258 -0
- package/skills/vantage-pitfalls/SKILL.md +115 -0
- package/templates/AGENTS.md +268 -0
- package/theme.css +178 -40
- package/dist/chunk-73J5ZD4C.js.map +0 -1
- package/dist/chunk-ZGDU5YLH.js.map +0 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Components
|
|
2
|
+
|
|
3
|
+
> Reference for the bundled shadcn/ui (Base UI) kit and the composite dashboard components.
|
|
4
|
+
|
|
5
|
+
Vantage ships **shadcn/ui** as-is. Nothing to install, nothing to copy — just import. There are three
|
|
6
|
+
public entry points, and **the sidebar is sectioned by those three**.
|
|
7
|
+
|
|
8
|
+
| Subpath | What's in it | Count |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| [`@squadbase/vantage/ui`](ui/button) | The shadcn/ui primitives (Base UI build) plus utilities like `cn()` | 37 |
|
|
11
|
+
| [`@squadbase/vantage/components`](parts/page-shell) | Dashboard parts composed from them | 15 |
|
|
12
|
+
| [`@squadbase/vantage/markdown`](markdown/markdown-renderer) | Markdown rendering alone (kept apart — it's heavy) | 1 |
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Button, Card, Badge } from "@squadbase/vantage/ui";
|
|
16
|
+
import { PageShell, DashboardCardPreset, EChart } from "@squadbase/vantage/components";
|
|
17
|
+
import { MarkdownRenderer } from "@squadbase/vantage/markdown";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
> [!NOTE]
|
|
21
|
+
> The UI kit is meant to be **imported from the package**, not copied. Pull an editable source with
|
|
22
|
+
> [`vantage add`](cli-reference) only when you need to change a component's internals.
|
|
23
|
+
|
|
24
|
+
## It's the Base UI build
|
|
25
|
+
|
|
26
|
+
What ships is the **Base UI variant** of shadcn/ui. In July 2026 shadcn/ui switched its default
|
|
27
|
+
primitives from Radix UI to [Base UI](https://base-ui.com), and Vantage follows the new one. Coming
|
|
28
|
+
from the Radix build, four differences matter.
|
|
29
|
+
|
|
30
|
+
- **There is no `asChild`.** Pass an element to the `render` prop instead.
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// Radix build
|
|
34
|
+
<PopoverTrigger asChild><Button>Open</Button></PopoverTrigger>
|
|
35
|
+
|
|
36
|
+
// Base UI build (Vantage)
|
|
37
|
+
<PopoverTrigger render={<Button />}>Open</PopoverTrigger>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- **[`Checkbox`](ui/checkbox)'s `checked` is strictly a boolean.** The mixed state is
|
|
41
|
+
the separate `indeterminate` prop.
|
|
42
|
+
- **[`ToggleGroup`](ui/toggle-group)'s `value` is an array.** For single choice, use
|
|
43
|
+
[`SegmentedControl`](parts/segmented-control).
|
|
44
|
+
- **[`Select`](ui/select)'s `onValueChange` gives `string | null`.** You need a
|
|
45
|
+
`null` guard. And `SelectValue` shows the raw value by default — pass the value-to-label map as
|
|
46
|
+
`items` to get labels.
|
|
47
|
+
|
|
48
|
+
State is expressed as `data-open` / `data-checked` rather than `data-state="open"`. Vantage's
|
|
49
|
+
`theme.css` declares custom variants that accept both spellings, so classes like
|
|
50
|
+
`data-open:animate-in` work either way.
|
|
51
|
+
|
|
52
|
+
## `@squadbase/vantage/ui`
|
|
53
|
+
|
|
54
|
+
The shadcn/ui primitives. The names and props are shadcn/ui's own, so
|
|
55
|
+
[their docs](https://ui.shadcn.com/docs/components) apply directly. The sidebar is alphabetical;
|
|
56
|
+
here they're grouped by what they're for.
|
|
57
|
+
|
|
58
|
+
### Forms and input
|
|
59
|
+
|
|
60
|
+
[`Button`](ui/button) ·
|
|
61
|
+
[`Input`](ui/input) ·
|
|
62
|
+
[`InputGroup`](ui/input-group) ·
|
|
63
|
+
[`Textarea`](ui/textarea) ·
|
|
64
|
+
[`Label`](ui/label) ·
|
|
65
|
+
[`Select`](ui/select) ·
|
|
66
|
+
[`Checkbox`](ui/checkbox) ·
|
|
67
|
+
[`Switch`](ui/switch) ·
|
|
68
|
+
[`Slider`](ui/slider) ·
|
|
69
|
+
[`Toggle`](ui/toggle) ·
|
|
70
|
+
[`ToggleGroup`](ui/toggle-group) ·
|
|
71
|
+
[`Calendar`](ui/calendar) ·
|
|
72
|
+
[`Command`](ui/command)
|
|
73
|
+
|
|
74
|
+
### Layout and navigation
|
|
75
|
+
|
|
76
|
+
[`Card`](ui/card) ·
|
|
77
|
+
[`Tabs`](ui/tabs) ·
|
|
78
|
+
[`Separator`](ui/separator) ·
|
|
79
|
+
[`ScrollArea`](ui/scroll-area) ·
|
|
80
|
+
[`Sidebar`](ui/sidebar) ·
|
|
81
|
+
[`Breadcrumb`](ui/breadcrumb) ·
|
|
82
|
+
[`Accordion`](ui/accordion) ·
|
|
83
|
+
[`Collapsible`](ui/collapsible)
|
|
84
|
+
|
|
85
|
+
### Data display
|
|
86
|
+
|
|
87
|
+
[`Table`](ui/table) ·
|
|
88
|
+
[`Badge`](ui/badge) ·
|
|
89
|
+
[`Progress`](ui/progress)
|
|
90
|
+
|
|
91
|
+
### Overlays
|
|
92
|
+
|
|
93
|
+
[`Dialog`](ui/dialog) ·
|
|
94
|
+
[`Sheet`](ui/sheet) ·
|
|
95
|
+
[`Popover`](ui/popover) ·
|
|
96
|
+
[`Tooltip`](ui/tooltip) ·
|
|
97
|
+
[`DropdownMenu`](ui/dropdown-menu)
|
|
98
|
+
|
|
99
|
+
### States
|
|
100
|
+
|
|
101
|
+
[`Alert`](ui/alert) ·
|
|
102
|
+
[`Skeleton`](ui/skeleton) ·
|
|
103
|
+
[`Spinner`](ui/spinner) ·
|
|
104
|
+
[`Loading`](ui/loading) ·
|
|
105
|
+
[`Empty`](ui/empty) ·
|
|
106
|
+
[`ErrorState`](ui/error-state)
|
|
107
|
+
|
|
108
|
+
`Loading` / `Empty` / `ErrorState` are the only three that aren't shadcn/ui — Vantage adds them.
|
|
109
|
+
|
|
110
|
+
### Utilities
|
|
111
|
+
|
|
112
|
+
[`cn()`](ui/cn) · [`useIsMobile()`](ui/use-is-mobile)
|
|
113
|
+
|
|
114
|
+
## `@squadbase/vantage/components`
|
|
115
|
+
|
|
116
|
+
Dashboard parts composed from `ui/`.
|
|
117
|
+
|
|
118
|
+
| Component | What it is |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| [`PageShell`](parts/page-shell) | The page frame: header band, summary, content |
|
|
121
|
+
| [`AppShell`](parts/app-shell) | The app frame — hand it your nav |
|
|
122
|
+
| [`SectionHeader`](parts/section-header) | A section heading with actions |
|
|
123
|
+
| [`DashboardCard`](parts/dashboard-card) | The dashboard tile, with preset and skeleton |
|
|
124
|
+
| [`DataTable`](parts/data-table) | Sorting, search, pagination, selection |
|
|
125
|
+
| [`EChart`](parts/echart) | The Apache ECharts wrapper |
|
|
126
|
+
| [`FunnelSteps`](parts/funnel-steps) | A funnel drawn as bars |
|
|
127
|
+
| [`FilterBar`](parts/filter-bar) | A row of filters driven by one value |
|
|
128
|
+
| [`DateRangePicker`](parts/date-range-picker) | Date range with presets |
|
|
129
|
+
| [`SegmentedControl`](parts/segmented-control) | Single-choice segments |
|
|
130
|
+
| [`SearchableSelect`](parts/searchable-select) | Single choice with search |
|
|
131
|
+
| [`MultiSelect`](parts/multi-select) | Multiple choice with search |
|
|
132
|
+
| [`MetricValue`](parts/metric-value) | A KPI's number and unit |
|
|
133
|
+
| [`TrendIndicator`](parts/trend-indicator) | An arrow and a percentage |
|
|
134
|
+
| [`StatusBadge`](parts/status-badge) | A dot-and-label status badge |
|
|
135
|
+
|
|
136
|
+
## `@squadbase/vantage/markdown`
|
|
137
|
+
|
|
138
|
+
A subpath holding only [`MarkdownRenderer`](markdown/markdown-renderer). Markdown
|
|
139
|
+
rendering carries Shiki with every language grammar; mixed into the `components` barrel it would add
|
|
140
|
+
over 10 MB to every build, so it is deliberately kept apart.
|
|
141
|
+
|
|
142
|
+
## Putting it together
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
import { Button } from "@squadbase/vantage/ui";
|
|
146
|
+
import {
|
|
147
|
+
PageShell,
|
|
148
|
+
PageShellHeader,
|
|
149
|
+
PageShellHeading,
|
|
150
|
+
PageShellTitle,
|
|
151
|
+
PageShellDescription,
|
|
152
|
+
PageShellHeaderEnd,
|
|
153
|
+
PageShellActions,
|
|
154
|
+
PageShellContent,
|
|
155
|
+
DashboardCardPreset,
|
|
156
|
+
MetricValue,
|
|
157
|
+
TrendIndicator,
|
|
158
|
+
EChart,
|
|
159
|
+
type EChartsOption,
|
|
160
|
+
} from "@squadbase/vantage/components";
|
|
161
|
+
|
|
162
|
+
const option: EChartsOption = {
|
|
163
|
+
xAxis: { type: "category", data: monthly.map((m) => m.month) },
|
|
164
|
+
yAxis: { type: "value" },
|
|
165
|
+
series: [{ type: "bar", data: monthly.map((m) => m.revenue) }],
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export default function Overview() {
|
|
169
|
+
return (
|
|
170
|
+
<PageShell>
|
|
171
|
+
<PageShellHeader>
|
|
172
|
+
<PageShellHeading>
|
|
173
|
+
<PageShellTitle>Sales dashboard</PageShellTitle>
|
|
174
|
+
<PageShellDescription>The last six months</PageShellDescription>
|
|
175
|
+
</PageShellHeading>
|
|
176
|
+
<PageShellHeaderEnd>
|
|
177
|
+
<PageShellActions>
|
|
178
|
+
<Button variant="outline">Export</Button>
|
|
179
|
+
</PageShellActions>
|
|
180
|
+
</PageShellHeaderEnd>
|
|
181
|
+
</PageShellHeader>
|
|
182
|
+
|
|
183
|
+
<PageShellContent>
|
|
184
|
+
<div className="grid gap-4 md:grid-cols-3">
|
|
185
|
+
<DashboardCardPreset title="Revenue">
|
|
186
|
+
<MetricValue className="my-0">$12,400</MetricValue>
|
|
187
|
+
<TrendIndicator value={12.4} direction="up" />
|
|
188
|
+
</DashboardCardPreset>
|
|
189
|
+
<DashboardCardPreset title="New customers">
|
|
190
|
+
<MetricValue className="my-0">128</MetricValue>
|
|
191
|
+
<TrendIndicator value={3.1} direction="down" />
|
|
192
|
+
</DashboardCardPreset>
|
|
193
|
+
<DashboardCardPreset title="Churn">
|
|
194
|
+
<MetricValue className="my-0">2.1%</MetricValue>
|
|
195
|
+
</DashboardCardPreset>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<DashboardCardPreset title="Monthly revenue" className="mt-4">
|
|
199
|
+
<EChart option={option} height={320} />
|
|
200
|
+
</DashboardCardPreset>
|
|
201
|
+
</PageShellContent>
|
|
202
|
+
</PageShell>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Theming
|
|
208
|
+
|
|
209
|
+
The look is decided by CSS variables (design tokens). To change colours or radii, override just the
|
|
210
|
+
variables in a `styles.css` at the project root — see [UI & theming](ui-and-theming).
|
|
211
|
+
|
|
212
|
+
## When you want to edit the source
|
|
213
|
+
|
|
214
|
+
To change a component's internals, pull an editable copy.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
vantage add ui data-table # an editable DataTable into components/
|
|
218
|
+
vantage add block sales-overview
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
> [!NOTE]
|
|
222
|
+
> In the current prototype, `vantage add` can copy only `data-table` (ui) and `sales-overview` (block).
|
|
223
|
+
> Everything else is import-only.
|
|
224
|
+
|
|
225
|
+
## How to read these pages
|
|
226
|
+
|
|
227
|
+
Every component page pairs a **live preview** with its **source**, in tabs. The
|
|
228
|
+
`export const client = "only";` at the top of each source is this documentation site's own directive
|
|
229
|
+
— your app doesn't need it.
|
|
230
|
+
|
|
231
|
+
> [!NOTE]
|
|
232
|
+
> The previews are shared between both locales, and their sample data is written in Japanese (the
|
|
233
|
+
> site's default locale). The component APIs are the same either way.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Data fetching
|
|
2
|
+
|
|
3
|
+
> Handle server state with a managed TanStack Query (useQuery).
|
|
4
|
+
|
|
5
|
+
Vantage ships a **managed TanStack Query** for server state. There is no `QueryClient` to set up —
|
|
6
|
+
just import `useQuery` and friends from `@squadbase/vantage/query`.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { useQuery } from "@squadbase/vantage/query";
|
|
10
|
+
|
|
11
|
+
export default function Customers() {
|
|
12
|
+
const { data, isLoading, error } = useQuery({
|
|
13
|
+
queryKey: ["customers"],
|
|
14
|
+
queryFn: async () => {
|
|
15
|
+
const res = await fetch("/api/customers");
|
|
16
|
+
if (!res.ok) throw new Error("failed to load");
|
|
17
|
+
return res.json();
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
if (isLoading) return <p>Loading…</p>;
|
|
22
|
+
if (error) return <p>Something went wrong</p>;
|
|
23
|
+
return (
|
|
24
|
+
<ul>
|
|
25
|
+
{data.map((c: { id: string; name: string }) => (
|
|
26
|
+
<li key={c.id}>{c.name}</li>
|
|
27
|
+
))}
|
|
28
|
+
</ul>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## A single managed QueryClient
|
|
34
|
+
|
|
35
|
+
Vantage provides exactly one `QueryClient` with these defaults:
|
|
36
|
+
|
|
37
|
+
| Option | Value |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `staleTime` | 30 seconds |
|
|
40
|
+
| `retry` | 1 |
|
|
41
|
+
| `refetchOnWindowFocus` | `false` |
|
|
42
|
+
|
|
43
|
+
Customize by **overriding per query**. Swapping the whole `QueryClient` is intentionally not exposed,
|
|
44
|
+
to keep the stack managed.
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
// Change behavior for this query only
|
|
48
|
+
useQuery({
|
|
49
|
+
queryKey: ["metrics"],
|
|
50
|
+
queryFn: fetchMetrics,
|
|
51
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
52
|
+
retry: 3,
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> [!NOTE]
|
|
57
|
+
> Do not import `@tanstack/react-query` directly. Using the curated re-exports from
|
|
58
|
+
> `@squadbase/vantage/query` lets Vantage evolve the underlying library safely.
|
|
59
|
+
|
|
60
|
+
## Pairing with the API
|
|
61
|
+
|
|
62
|
+
Calling `/api/*` inside `queryFn` connects naturally to the [optional server](api-and-server).
|
|
63
|
+
Even a client-only app without `server/` can `fetch` an external API the same way.
|
|
64
|
+
|
|
65
|
+
> [!TIP]
|
|
66
|
+
> When calling the built-in `/api`, use `apiFetch` from `@squadbase/vantage/query` so the base URL can
|
|
67
|
+
> be switched via env (for deploying the client and server on different origins). See
|
|
68
|
+
> [Build & deploy](build-and-deploy) for details.
|
|
69
|
+
>
|
|
70
|
+
> ```tsx
|
|
71
|
+
> import { apiFetch } from "@squadbase/vantage/query";
|
|
72
|
+
>
|
|
73
|
+
> queryFn: () => apiFetch("/api/customers").then((r) => r.json());
|
|
74
|
+
> ```
|
|
75
|
+
|
|
76
|
+
## What to read next
|
|
77
|
+
|
|
78
|
+
- [API & server](api-and-server) — write a backend
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Environment variables
|
|
2
|
+
|
|
3
|
+
> Only PUBLIC_-prefixed env reaches the client. Read secrets from the server's env.
|
|
4
|
+
|
|
5
|
+
Vantage's default is to **never leak** environment variables to the client. The boundary is the prefix.
|
|
6
|
+
|
|
7
|
+
## Only `PUBLIC_` reaches the client
|
|
8
|
+
|
|
9
|
+
Only variables beginning with `PUBLIC_` are included in the client bundle and readable via
|
|
10
|
+
`import.meta.env`.
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
// client code
|
|
14
|
+
const analyticsId = import.meta.env.PUBLIC_ANALYTICS_ID;
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The client can only see:
|
|
18
|
+
|
|
19
|
+
- `PUBLIC_*` (the public values you define)
|
|
20
|
+
- `MODE` / `DEV` / `PROD` / `SSR` / `BASE_URL` (Vite standard)
|
|
21
|
+
|
|
22
|
+
> [!WARNING]
|
|
23
|
+
> Reading an env variable **without** the `PUBLIC_` prefix on the client triggers a `PUBLIC_ENV_MISUSE`
|
|
24
|
+
> warning from `vantage check`. There is no user-facing `VITE_` API.
|
|
25
|
+
|
|
26
|
+
## Secrets come from the server's `env`
|
|
27
|
+
|
|
28
|
+
Read secrets like API keys and tokens from the server's `ApiContext.env` — **never expose them to
|
|
29
|
+
the client**. These carry no prefix.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// server/api/report.ts
|
|
33
|
+
import type { ApiContext } from "@squadbase/vantage/server";
|
|
34
|
+
|
|
35
|
+
export async function GET({ env }: ApiContext) {
|
|
36
|
+
const apiKey = env.SECRET_API_KEY; // never reaches the client
|
|
37
|
+
// …call an external service
|
|
38
|
+
return Response.json({ ok: true });
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## An `.env` example
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# .env
|
|
46
|
+
PUBLIC_ANALYTICS_ID=UA-XXXX # reaches the client
|
|
47
|
+
SECRET_API_KEY=sk_live_xxx # server only (ApiContext.env)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> [!NOTE]
|
|
51
|
+
> The dev server re-reads env on every request. The production Node server snapshots `process.env` once
|
|
52
|
+
> at startup.
|
|
53
|
+
|
|
54
|
+
## Env used at deploy time
|
|
55
|
+
|
|
56
|
+
When you deploy the client and server on different origins, these env vars come into play.
|
|
57
|
+
|
|
58
|
+
| Variable | Side | Role |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `PUBLIC_API_BASE_URL` | Client (public) | Base URL the client uses to call `/api`. Also overridable via `--api-base-url` |
|
|
61
|
+
| `CORS_ORIGIN` | Server | Origin(s) allowed for `/api`. Unset means CORS is off |
|
|
62
|
+
| `CORS_CREDENTIALS` | Server | `true` to allow credentials (cookies, etc.) |
|
|
63
|
+
|
|
64
|
+
See [Build & deploy](build-and-deploy) for how to use them.
|
|
65
|
+
|
|
66
|
+
## What to read next
|
|
67
|
+
|
|
68
|
+
- [Build & deploy](build-and-deploy) — production env and split origins
|
|
69
|
+
- [UI & theming](ui-and-theming) — shape the look
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Getting started
|
|
2
|
+
|
|
3
|
+
> From install to running your first Vantage app.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- **Node.js 20 or newer**
|
|
8
|
+
- A package manager (pnpm, npm, or yarn)
|
|
9
|
+
|
|
10
|
+
## Create the smallest app
|
|
11
|
+
|
|
12
|
+
### Add Vantage
|
|
13
|
+
|
|
14
|
+
Add `@squadbase/vantage` to your project.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @squadbase/vantage
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Write index.tsx
|
|
21
|
+
|
|
22
|
+
Put a single `index.tsx` at the project root. The **default-exported component** becomes the
|
|
23
|
+
route `/`.
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
// index.tsx
|
|
27
|
+
export default function Dashboard() {
|
|
28
|
+
return (
|
|
29
|
+
<main className="p-6">
|
|
30
|
+
<h1 className="text-2xl font-semibold">Dashboard</h1>
|
|
31
|
+
</main>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Start the dev server
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm exec vantage dev
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This starts `http://localhost:5173` with HMR. Editing a page applies via React Fast Refresh
|
|
43
|
+
in place.
|
|
44
|
+
|
|
45
|
+
> [!TIP]
|
|
46
|
+
> Right after a plain `pnpm add`, the `vantage` binary isn't on your `PATH`, so run it via
|
|
47
|
+
> `pnpm exec vantage` (or `npx vantage`). Add `"dev": "vantage dev"` to your `package.json`
|
|
48
|
+
> `scripts` and you can use `pnpm dev` instead.
|
|
49
|
+
|
|
50
|
+
## The development loop
|
|
51
|
+
|
|
52
|
+
| Command | Role |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `vantage dev` | Dev server (HMR + optional API). Default `:5173` |
|
|
55
|
+
| `vantage build` | Production build → `dist/` (client + optional server) |
|
|
56
|
+
| `vantage preview` | Run the production build locally |
|
|
57
|
+
| `vantage check` | Static checks (routes, boundaries, forbidden files). Exit 1 on error |
|
|
58
|
+
| `vantage routes` | Print the page + API URL map |
|
|
59
|
+
|
|
60
|
+
> [!TIP]
|
|
61
|
+
> While `vantage dev` runs, the browser's `console.*` and uncaught errors are forwarded to the dev
|
|
62
|
+
> terminal as `[browser:…]`. Most issues can be diagnosed without opening the browser.
|
|
63
|
+
|
|
64
|
+
## Quick mode (pass a path directly)
|
|
65
|
+
|
|
66
|
+
Instead of `cd`-ing into a project, you can pass its **path directly** to start the dev server.
|
|
67
|
+
Point at a folder or an entry file and `dev` boots on it.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
vantage ./demo # folder → run dev inside it
|
|
71
|
+
vantage ./demo/index.tsx # page file → use its parent folder as the root
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
When the first argument isn't a known command but points at a path, Vantage runs `dev` with that
|
|
75
|
+
path as the root (printing `quick dev → <path>`). See the
|
|
76
|
+
[CLI reference](cli-reference) for the full resolution rules.
|
|
77
|
+
|
|
78
|
+
## You never write config files
|
|
79
|
+
|
|
80
|
+
Vantage takes "convention over configuration" literally. These files are a **hard error**
|
|
81
|
+
(`vantage check` fails) if present in your project:
|
|
82
|
+
|
|
83
|
+
- `vite.config.*`
|
|
84
|
+
- `tailwind.config.*`
|
|
85
|
+
- `postcss.config.*`
|
|
86
|
+
- `components.json`
|
|
87
|
+
- `vantage.config.*`
|
|
88
|
+
|
|
89
|
+
Everything they used to configure is owned by Vantage. When you need to customize, use the
|
|
90
|
+
explicit escape hatches described throughout this guide.
|
|
91
|
+
|
|
92
|
+
## What to read next
|
|
93
|
+
|
|
94
|
+
- [File-based routing](routing) — add more pages
|
|
95
|
+
- [Pages & definePage](pages-and-metadata) — the page contract and metadata
|
package/docs/en/index.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# What is Vantage
|
|
2
|
+
|
|
3
|
+
> A config-free React dashboard framework. You only write index.tsx.
|
|
4
|
+
|
|
5
|
+
A **vantage** point is a place with a clear, commanding view — and that's the idea behind the name:
|
|
6
|
+
give you a dashboard that sees all of your data at a glance, with the least possible effort.
|
|
7
|
+
|
|
8
|
+
**Vantage** is a config-free React dashboard framework for
|
|
9
|
+
[Squadbase Editor](https://squadbase.dev), built on Vite 8. As an app author you write a
|
|
10
|
+
**single `index.tsx`** — routing, React setup, TanStack Query, Tailwind CSS, the UI kit, the dev
|
|
11
|
+
server, an optional API server, and the build are all **owned by Vantage**.
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
// index.tsx → route "/"
|
|
15
|
+
export default function Dashboard() {
|
|
16
|
+
return (
|
|
17
|
+
<main className="p-6">
|
|
18
|
+
<h1 className="text-2xl font-semibold">Dashboard</h1>
|
|
19
|
+
</main>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Those seven lines are a working dashboard app. You never write `vite.config`, `tailwind.config`,
|
|
25
|
+
`postcss.config`, `components.json`, or `vantage.config`.
|
|
26
|
+
|
|
27
|
+
> [!NOTE]
|
|
28
|
+
> This site is a guide for **app authors** — people building dashboards *with* Vantage. For the
|
|
29
|
+
> framework's own internals, see the repository's `README.md` and design document.
|
|
30
|
+
|
|
31
|
+
## Highlights
|
|
32
|
+
|
|
33
|
+
### One-file first
|
|
34
|
+
|
|
35
|
+
A single `index.tsx` is a complete app. Add a `.tsx` file when you want another page.
|
|
36
|
+
|
|
37
|
+
### Convention over configuration
|
|
38
|
+
|
|
39
|
+
Config files aren't just unnecessary — they're forbidden. File and directory conventions drive everything.
|
|
40
|
+
|
|
41
|
+
### Managed stack
|
|
42
|
+
|
|
43
|
+
React, Vite, TanStack Router/Query, Tailwind, and the UI kit are pinned by Vantage.
|
|
44
|
+
|
|
45
|
+
### Server is optional
|
|
46
|
+
|
|
47
|
+
Add `server/` to enable an API. Without it, your app is a client-only SPA.
|
|
48
|
+
|
|
49
|
+
## Next steps
|
|
50
|
+
|
|
51
|
+
### Getting started
|
|
52
|
+
|
|
53
|
+
From install to running your first app.
|
|
54
|
+
|
|
55
|
+
### File-based routing
|
|
56
|
+
|
|
57
|
+
How dropping a file creates a route.
|
|
58
|
+
|
|
59
|
+
### Data fetching
|
|
60
|
+
|
|
61
|
+
Handle server state with a managed TanStack Query.
|
|
62
|
+
|
|
63
|
+
### API & server
|
|
64
|
+
|
|
65
|
+
Write a backend under `server/api`.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# MarkdownRenderer
|
|
2
|
+
|
|
3
|
+
> Renders markdown, syntax highlighting included.
|
|
4
|
+
|
|
5
|
+
Renders a markdown string — tables, code blocks with syntax highlighting, and maths included. Good
|
|
6
|
+
for LLM output, or for prose that lives in your database.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { MarkdownRenderer } from "@squadbase/vantage/markdown";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Description |
|
|
13
|
+
| --- | --- | --- |
|
|
14
|
+
| `content` | `string` | The markdown to render. |
|
|
15
|
+
| `className` | `string` | Classes to add. |
|
|
16
|
+
|
|
17
|
+
## Why it's on its own subpath
|
|
18
|
+
|
|
19
|
+
It is **deliberately not re-exported** from `@squadbase/vantage/components`. Markdown rendering
|
|
20
|
+
carries Shiki with every language grammar, and the import edge alone is something bundlers cannot
|
|
21
|
+
drop. Sitting in the shared barrel, it would add roughly 11 MB and 300 files to the build output of
|
|
22
|
+
apps that never render markdown.
|
|
23
|
+
|
|
24
|
+
Behind its own entry, **only the apps that import it** pay for it.
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
// This one is heavy — and that's fine
|
|
28
|
+
import { MarkdownRenderer } from "@squadbase/vantage/markdown";
|
|
29
|
+
|
|
30
|
+
// This one stays light
|
|
31
|
+
import { DashboardCardPreset } from "@squadbase/vantage/components";
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Streaming LLM output
|
|
35
|
+
|
|
36
|
+
Since only `content` changes, you can hand it a partially-streamed string. Incomplete markdown — an
|
|
37
|
+
unclosed code fence, say — still renders without breaking.
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
const [text, setText] = useState("");
|
|
41
|
+
// …setText((prev) => prev + chunk) as chunks arrive
|
|
42
|
+
|
|
43
|
+
<MarkdownRenderer content={text} />;
|
|
44
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Pages & definePage
|
|
2
|
+
|
|
3
|
+
> A page's only requirement is a default export. Use definePage to attach a static title and description.
|
|
4
|
+
|
|
5
|
+
## The only requirement is a default export
|
|
6
|
+
|
|
7
|
+
A Vantage page needs just one thing: a **default-exported React component**.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
export default function MonthlyAnalysis() {
|
|
11
|
+
return <h1>Monthly analysis</h1>;
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
A page without a default export is flagged by `vantage check` with a `MISSING_DEFAULT_EXPORT` error.
|
|
16
|
+
|
|
17
|
+
## Attach metadata with definePage
|
|
18
|
+
|
|
19
|
+
To add a title or description, use `definePage`. It is optional.
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { definePage } from "@squadbase/vantage";
|
|
23
|
+
|
|
24
|
+
export const page = definePage({
|
|
25
|
+
title: "Monthly analysis",
|
|
26
|
+
description: "A monthly summary of revenue and key metrics",
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export default function MonthlyAnalysis() {
|
|
30
|
+
return <h1>Monthly analysis</h1>;
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- `title` drives `document.title` (the deepest route match's title wins; otherwise it falls back to
|
|
35
|
+
the document's initial `<title>`).
|
|
36
|
+
- `title`/`description` are **read statically at generation time**. Vantage parses the source rather
|
|
37
|
+
than executing your page, so keep the values **literal**.
|
|
38
|
+
|
|
39
|
+
> [!WARNING]
|
|
40
|
+
> The **export name must be `page`** in `export const page = definePage({...})`. A different name means
|
|
41
|
+
> the metadata is not read.
|
|
42
|
+
|
|
43
|
+
## Relationship to Fast Refresh
|
|
44
|
+
|
|
45
|
+
Even with a non-component export like `page`, Vantage handles it internally so React Fast Refresh
|
|
46
|
+
survives. Editing a page body updates in place while preserving state.
|
|
47
|
+
|
|
48
|
+
## Prototype limitations
|
|
49
|
+
|
|
50
|
+
`definePage` also accepts `pendingComponent` / `errorComponent` / `validateSearch` as types, but in
|
|
51
|
+
the current prototype they are **not yet wired into lazy routes**. Per-page pending/error overrides
|
|
52
|
+
are unimplemented — the framework's shared defaults render instead.
|
|
53
|
+
|
|
54
|
+
## What to read next
|
|
55
|
+
|
|
56
|
+
- [Data fetching](data-fetching) — handle server state
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# AppShell
|
|
2
|
+
|
|
3
|
+
> The application frame — hand it your nav and you're done.
|
|
4
|
+
|
|
5
|
+
The frame around the whole app. Hand `groups` an array of nav entries and you get a collapsible
|
|
6
|
+
sidebar — or a header, for narrow screens. Use it instead of assembling
|
|
7
|
+
[`Sidebar`](ui/sidebar) yourself.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { AppShell } from "@squadbase/vantage/components";
|
|
11
|
+
import type { NavGroup, NavItem } from "@squadbase/vantage/components";
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Prop | Type | Default | Description |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| `groups` | `NavGroup[]` | | The navigation: an array of `{ label?, items: NavItem[] }`. |
|
|
17
|
+
| `variant` | `"sidebar" \| "header"` | `"sidebar"` | A sidebar frame, or a header with a select. |
|
|
18
|
+
| `actions` | `ReactNode` | | Rendered at the top right. |
|
|
19
|
+
| `header` | `ReactNode` | | Replaces the default header wholesale. |
|
|
20
|
+
| `defaultOpen` | `boolean` | `true` | With `variant="sidebar"`, whether it starts open. |
|
|
21
|
+
| `linkComponent` | `ElementType` | | The link component used to render items. |
|
|
22
|
+
| `onNavigate` | `(href: string) => void` | | Fired when an item is chosen; defaults to `location.assign`. |
|
|
23
|
+
|
|
24
|
+
## NavItem
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
interface NavItem {
|
|
28
|
+
label: string;
|
|
29
|
+
href: string;
|
|
30
|
+
icon?: ComponentType<{ className?: string }>;
|
|
31
|
+
isActive?: boolean;
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
badge?: string;
|
|
34
|
+
children?: NavItem[]; // collapsible sub-items
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
An item with `children` becomes a disclosure.
|
|
39
|
+
|
|
40
|
+
## Wiring it to the router
|
|
41
|
+
|
|
42
|
+
Pass `onNavigate` for client-side navigation.
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { useNavigate } from "@squadbase/vantage/router";
|
|
46
|
+
|
|
47
|
+
const navigate = useNavigate();
|
|
48
|
+
|
|
49
|
+
<AppShell groups={groups} onNavigate={(href) => navigate({ to: href })}>
|
|
50
|
+
{children}
|
|
51
|
+
</AppShell>;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Highlighting is explicit: set `isActive` by comparing the current route's path with each `href`.
|