@squadbase/vantage 0.0.1 → 0.1.1
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 +24 -4
- package/dist/{chunk-ZGDU5YLH.js → chunk-5L2MH2NG.js} +16 -7
- package/dist/chunk-5L2MH2NG.js.map +1 -0
- package/dist/chunk-7IPAXPPY.js +51 -0
- package/dist/chunk-7IPAXPPY.js.map +1 -0
- package/dist/chunk-A2UUGASH.js +12 -0
- package/dist/chunk-A2UUGASH.js.map +1 -0
- package/dist/chunk-DTDVSFRY.js +29 -0
- package/dist/chunk-DTDVSFRY.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/client/index.d.ts +2 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/components/index.d.ts +575 -0
- package/dist/components/index.js +2097 -0
- package/dist/components/index.js.map +1 -0
- package/dist/{define-page-B6y9TOfZ.d.ts → define-page-BfhrK99G.d.ts} +5 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- 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 +95 -2
- package/dist/query/index.js +102 -1
- package/dist/query/index.js.map +1 -1
- package/dist/router/index.d.ts +86 -1
- package/dist/router/index.js +71 -7
- package/dist/router/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 +235 -0
- package/docs/en/data-fetching.md +142 -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 +59 -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/placeholder.md +38 -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/sparkline.md +47 -0
- package/docs/en/parts/status-badge.md +44 -0
- package/docs/en/parts/trend-indicator.md +26 -0
- package/docs/en/routing.md +177 -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 +1346 -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 +231 -0
- package/docs/ja/data-fetching.md +142 -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 +59 -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/placeholder.md +37 -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/sparkline.md +47 -0
- package/docs/ja/parts/status-badge.md +44 -0
- package/docs/ja/parts/trend-indicator.md +26 -0
- package/docs/ja/routing.md +175 -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 +153 -0
- package/skills/vantage-app/SKILL.md +291 -0
- package/skills/vantage-pitfalls/SKILL.md +139 -0
- package/templates/AGENTS.md +313 -0
- package/theme.css +178 -40
- package/dist/chunk-73J5ZD4C.js.map +0 -1
- package/dist/chunk-ATYZ45XL.js +0 -19
- package/dist/chunk-ATYZ45XL.js.map +0 -1
- package/dist/chunk-ZGDU5YLH.js.map +0 -1
|
@@ -0,0 +1,235 @@
|
|
|
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
|
+
| [`Sparkline`](parts/sparkline) | An inline trend chart for cells and tiles |
|
|
128
|
+
| [`FilterBar`](parts/filter-bar) | A row of filters driven by one value |
|
|
129
|
+
| [`DateRangePicker`](parts/date-range-picker) | Date range with presets |
|
|
130
|
+
| [`SegmentedControl`](parts/segmented-control) | Single-choice segments |
|
|
131
|
+
| [`SearchableSelect`](parts/searchable-select) | Single choice with search |
|
|
132
|
+
| [`MultiSelect`](parts/multi-select) | Multiple choice with search |
|
|
133
|
+
| [`MetricValue`](parts/metric-value) | A KPI's number and unit |
|
|
134
|
+
| [`TrendIndicator`](parts/trend-indicator) | An arrow and a percentage |
|
|
135
|
+
| [`StatusBadge`](parts/status-badge) | A dot-and-label status badge |
|
|
136
|
+
| [`Placeholder`](parts/placeholder) | An inline marker for sample data |
|
|
137
|
+
|
|
138
|
+
## `@squadbase/vantage/markdown`
|
|
139
|
+
|
|
140
|
+
A subpath holding only [`MarkdownRenderer`](markdown/markdown-renderer). Markdown
|
|
141
|
+
rendering carries Shiki with every language grammar; mixed into the `components` barrel it would add
|
|
142
|
+
over 10 MB to every build, so it is deliberately kept apart.
|
|
143
|
+
|
|
144
|
+
## Putting it together
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
import { Button } from "@squadbase/vantage/ui";
|
|
148
|
+
import {
|
|
149
|
+
PageShell,
|
|
150
|
+
PageShellHeader,
|
|
151
|
+
PageShellHeading,
|
|
152
|
+
PageShellTitle,
|
|
153
|
+
PageShellDescription,
|
|
154
|
+
PageShellHeaderEnd,
|
|
155
|
+
PageShellActions,
|
|
156
|
+
PageShellContent,
|
|
157
|
+
DashboardCardPreset,
|
|
158
|
+
MetricValue,
|
|
159
|
+
TrendIndicator,
|
|
160
|
+
EChart,
|
|
161
|
+
type EChartsOption,
|
|
162
|
+
} from "@squadbase/vantage/components";
|
|
163
|
+
|
|
164
|
+
const option: EChartsOption = {
|
|
165
|
+
xAxis: { type: "category", data: monthly.map((m) => m.month) },
|
|
166
|
+
yAxis: { type: "value" },
|
|
167
|
+
series: [{ type: "bar", data: monthly.map((m) => m.revenue) }],
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export default function Overview() {
|
|
171
|
+
return (
|
|
172
|
+
<PageShell>
|
|
173
|
+
<PageShellHeader>
|
|
174
|
+
<PageShellHeading>
|
|
175
|
+
<PageShellTitle>Sales dashboard</PageShellTitle>
|
|
176
|
+
<PageShellDescription>The last six months</PageShellDescription>
|
|
177
|
+
</PageShellHeading>
|
|
178
|
+
<PageShellHeaderEnd>
|
|
179
|
+
<PageShellActions>
|
|
180
|
+
<Button variant="outline">Export</Button>
|
|
181
|
+
</PageShellActions>
|
|
182
|
+
</PageShellHeaderEnd>
|
|
183
|
+
</PageShellHeader>
|
|
184
|
+
|
|
185
|
+
<PageShellContent>
|
|
186
|
+
<div className="grid gap-4 md:grid-cols-3">
|
|
187
|
+
<DashboardCardPreset title="Revenue">
|
|
188
|
+
<MetricValue className="my-0">$12,400</MetricValue>
|
|
189
|
+
<TrendIndicator value={12.4} direction="up" />
|
|
190
|
+
</DashboardCardPreset>
|
|
191
|
+
<DashboardCardPreset title="New customers">
|
|
192
|
+
<MetricValue className="my-0">128</MetricValue>
|
|
193
|
+
<TrendIndicator value={3.1} direction="down" />
|
|
194
|
+
</DashboardCardPreset>
|
|
195
|
+
<DashboardCardPreset title="Churn">
|
|
196
|
+
<MetricValue className="my-0">2.1%</MetricValue>
|
|
197
|
+
</DashboardCardPreset>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<DashboardCardPreset title="Monthly revenue" className="mt-4">
|
|
201
|
+
<EChart option={option} height={320} />
|
|
202
|
+
</DashboardCardPreset>
|
|
203
|
+
</PageShellContent>
|
|
204
|
+
</PageShell>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Theming
|
|
210
|
+
|
|
211
|
+
The look is decided by CSS variables (design tokens). To change colours or radii, override just the
|
|
212
|
+
variables in a `styles.css` at the project root — see [UI & theming](ui-and-theming).
|
|
213
|
+
|
|
214
|
+
## When you want to edit the source
|
|
215
|
+
|
|
216
|
+
To change a component's internals, pull an editable copy.
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
vantage add ui data-table # an editable DataTable into components/
|
|
220
|
+
vantage add block sales-overview
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
> [!NOTE]
|
|
224
|
+
> In the current prototype, `vantage add` can copy only `data-table` (ui) and `sales-overview` (block).
|
|
225
|
+
> Everything else is import-only.
|
|
226
|
+
|
|
227
|
+
## How to read these pages
|
|
228
|
+
|
|
229
|
+
Every component page pairs a **live preview** with its **source**, in tabs. The
|
|
230
|
+
`export const client = "only";` at the top of each source is this documentation site's own directive
|
|
231
|
+
— your app doesn't need it.
|
|
232
|
+
|
|
233
|
+
> [!NOTE]
|
|
234
|
+
> The previews are shared between both locales, and their sample data is written in Japanese (the
|
|
235
|
+
> site's default locale). The component APIs are the same either way.
|
|
@@ -0,0 +1,142 @@
|
|
|
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`. To call your own `server/api`,
|
|
7
|
+
[`useApiQuery`](#call-your-own-api--useapiquery) below is the shortcut.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { useQuery } from "@squadbase/vantage/query";
|
|
11
|
+
|
|
12
|
+
export default function Customers() {
|
|
13
|
+
const { data, isLoading, error } = useQuery({
|
|
14
|
+
queryKey: ["customers"],
|
|
15
|
+
queryFn: async () => {
|
|
16
|
+
const res = await fetch("/api/customers");
|
|
17
|
+
if (!res.ok) throw new Error("failed to load");
|
|
18
|
+
return res.json();
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (isLoading) return <p>Loading…</p>;
|
|
23
|
+
if (error) return <p>Something went wrong</p>;
|
|
24
|
+
return (
|
|
25
|
+
<ul>
|
|
26
|
+
{data.map((c: { id: string; name: string }) => (
|
|
27
|
+
<li key={c.id}>{c.name}</li>
|
|
28
|
+
))}
|
|
29
|
+
</ul>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## A single managed QueryClient
|
|
35
|
+
|
|
36
|
+
Vantage provides exactly one `QueryClient` with these defaults:
|
|
37
|
+
|
|
38
|
+
| Option | Value |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `staleTime` | 30 seconds |
|
|
41
|
+
| `retry` | 1 |
|
|
42
|
+
| `refetchOnWindowFocus` | `false` |
|
|
43
|
+
| `networkMode` | `"always"` (queries and mutations) |
|
|
44
|
+
|
|
45
|
+
`networkMode: "always"` requests and retries regardless of the browser's offline heuristic. Under
|
|
46
|
+
the default `"online"`, a failed query is *paused* the moment that heuristic reads offline — no
|
|
47
|
+
error, just a loading state that never resolves. A dashboard talks to its own origin (or the
|
|
48
|
+
configured API base), where that heuristic says nothing useful.
|
|
49
|
+
|
|
50
|
+
Customize by **overriding per query**. Swapping the whole `QueryClient` is intentionally not exposed,
|
|
51
|
+
to keep the stack managed.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
// Change behavior for this query only
|
|
55
|
+
useQuery({
|
|
56
|
+
queryKey: ["metrics"],
|
|
57
|
+
queryFn: fetchMetrics,
|
|
58
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
59
|
+
retry: 3,
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
> [!NOTE]
|
|
64
|
+
> Do not import `@tanstack/react-query` directly. Using the curated re-exports from
|
|
65
|
+
> `@squadbase/vantage/query` lets Vantage evolve the underlying library safely.
|
|
66
|
+
|
|
67
|
+
## Call your own API — useApiQuery
|
|
68
|
+
|
|
69
|
+
For routes under `server/api`, use `useApiQuery`. It is `useQuery` plus the boilerplate every page
|
|
70
|
+
was repeating: base-URL resolution, JSON parsing, non-2xx to an error, and a query key.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { useApiQuery } from "@squadbase/vantage/query";
|
|
74
|
+
|
|
75
|
+
interface Monthly {
|
|
76
|
+
monthly: { month: string; revenue: number }[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default function MonthlyAnalysis() {
|
|
80
|
+
const { data, isPending, error } = useApiQuery<Monthly>("/api/monthly-analysis");
|
|
81
|
+
|
|
82
|
+
if (isPending) return <p>Loading…</p>;
|
|
83
|
+
if (error) return <p>{error.message}</p>;
|
|
84
|
+
return <Chart data={data.monthly} />;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Pass the query string as `search`. `undefined` entries are dropped, so an unset filter appears
|
|
89
|
+
neither in the URL nor in the query key.
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
const query = useApiQuery<Row[]>("/api/customers", {
|
|
93
|
+
search: { segment, from: range.from, to: range.to },
|
|
94
|
+
enabled: Boolean(segment), // any useQuery option still works
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The query key defaults to `["api", <url with query string>]`, so changing `search` refetches, and
|
|
99
|
+
`invalidateQueries({ queryKey: ["api"] })` drops everything that came from the API.
|
|
100
|
+
|
|
101
|
+
### Errors arrive as ApiError
|
|
102
|
+
|
|
103
|
+
A non-2xx response is thrown as an `ApiError`. Its `message` is what the API chose to disclose with
|
|
104
|
+
[`HttpError`](api-and-server); anything else surfaces as generic status text.
|
|
105
|
+
|
|
106
|
+
| Property | Contents |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `message` | The message the server set with `HttpError` |
|
|
109
|
+
| `status` | HTTP status |
|
|
110
|
+
| `body` | Parsed response body |
|
|
111
|
+
| `requestId` | `x-vantage-request-id`, to correlate with the dev terminal log |
|
|
112
|
+
|
|
113
|
+
### Writes with useApiMutation
|
|
114
|
+
|
|
115
|
+
The mutation variables are sent as the JSON body. The path may be a function.
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import { useApiMutation, useQueryClient } from "@squadbase/vantage/query";
|
|
119
|
+
|
|
120
|
+
const queryClient = useQueryClient();
|
|
121
|
+
const save = useApiMutation<Customer, { id: string; name: string }>(
|
|
122
|
+
(vars) => `/api/customers/${vars.id}`,
|
|
123
|
+
{
|
|
124
|
+
method: "PUT",
|
|
125
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["api"] }),
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
save.mutate({ id: "1", name: "Northwind" });
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Where a hook doesn't fit (an event handler, say), call `apiJson(path, init)` directly. For the raw
|
|
133
|
+
`Response`, use `apiFetch`.
|
|
134
|
+
|
|
135
|
+
> [!TIP]
|
|
136
|
+
> For an external API, keep using `useQuery` + `fetch`. `useApiQuery` goes through `apiFetch`, so
|
|
137
|
+
> setting [`PUBLIC_API_BASE_URL`](build-and-deploy) lets you deploy the client and server on
|
|
138
|
+
> different origins without touching page code.
|
|
139
|
+
|
|
140
|
+
## What to read next
|
|
141
|
+
|
|
142
|
+
- [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
|
+
```
|