@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.
Files changed (187) hide show
  1. package/README.md +24 -4
  2. package/dist/{chunk-ZGDU5YLH.js → chunk-5L2MH2NG.js} +16 -7
  3. package/dist/chunk-5L2MH2NG.js.map +1 -0
  4. package/dist/chunk-7IPAXPPY.js +51 -0
  5. package/dist/chunk-7IPAXPPY.js.map +1 -0
  6. package/dist/chunk-A2UUGASH.js +12 -0
  7. package/dist/chunk-A2UUGASH.js.map +1 -0
  8. package/dist/chunk-DTDVSFRY.js +29 -0
  9. package/dist/chunk-DTDVSFRY.js.map +1 -0
  10. package/dist/chunk-WQZYXXQW.js +2249 -0
  11. package/dist/chunk-WQZYXXQW.js.map +1 -0
  12. package/dist/{chunk-73J5ZD4C.js → chunk-YLAB6UQS.js} +17 -3
  13. package/dist/chunk-YLAB6UQS.js.map +1 -0
  14. package/dist/cli.js +607 -36
  15. package/dist/cli.js.map +1 -1
  16. package/dist/client/index.d.ts +2 -1
  17. package/dist/client/index.js +3 -1
  18. package/dist/client/index.js.map +1 -1
  19. package/dist/components/index.d.ts +575 -0
  20. package/dist/components/index.js +2097 -0
  21. package/dist/components/index.js.map +1 -0
  22. package/dist/{define-page-B6y9TOfZ.d.ts → define-page-BfhrK99G.d.ts} +5 -0
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.js +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/markdown/index.d.ts +9 -0
  27. package/dist/markdown/index.js +26 -0
  28. package/dist/markdown/index.js.map +1 -0
  29. package/dist/query/index.d.ts +95 -2
  30. package/dist/query/index.js +102 -1
  31. package/dist/query/index.js.map +1 -1
  32. package/dist/router/index.d.ts +86 -1
  33. package/dist/router/index.js +71 -7
  34. package/dist/router/index.js.map +1 -1
  35. package/dist/server/node.js +6 -1
  36. package/dist/server/node.js.map +1 -1
  37. package/dist/ui/index.d.ts +316 -200
  38. package/dist/ui/index.js +566 -511
  39. package/dist/ui/index.js.map +1 -1
  40. package/dist/vite/index.js +2 -2
  41. package/docs/en/agent-skills.md +89 -0
  42. package/docs/en/api-and-server.md +84 -0
  43. package/docs/en/build-and-deploy.md +280 -0
  44. package/docs/en/cli-reference.md +311 -0
  45. package/docs/en/components.md +235 -0
  46. package/docs/en/data-fetching.md +142 -0
  47. package/docs/en/environment-variables.md +69 -0
  48. package/docs/en/getting-started.md +95 -0
  49. package/docs/en/index.md +65 -0
  50. package/docs/en/markdown/markdown-renderer.md +44 -0
  51. package/docs/en/pages-and-metadata.md +59 -0
  52. package/docs/en/parts/app-shell.md +54 -0
  53. package/docs/en/parts/dashboard-card.md +64 -0
  54. package/docs/en/parts/data-table.md +86 -0
  55. package/docs/en/parts/date-range-picker.md +41 -0
  56. package/docs/en/parts/echart.md +53 -0
  57. package/docs/en/parts/filter-bar.md +66 -0
  58. package/docs/en/parts/funnel-steps.md +33 -0
  59. package/docs/en/parts/metric-value.md +23 -0
  60. package/docs/en/parts/multi-select.md +27 -0
  61. package/docs/en/parts/page-shell.md +45 -0
  62. package/docs/en/parts/placeholder.md +38 -0
  63. package/docs/en/parts/searchable-select.md +47 -0
  64. package/docs/en/parts/section-header.md +20 -0
  65. package/docs/en/parts/segmented-control.md +25 -0
  66. package/docs/en/parts/sparkline.md +47 -0
  67. package/docs/en/parts/status-badge.md +44 -0
  68. package/docs/en/parts/trend-indicator.md +26 -0
  69. package/docs/en/routing.md +177 -0
  70. package/docs/en/ui/accordion.md +36 -0
  71. package/docs/en/ui/alert.md +31 -0
  72. package/docs/en/ui/badge.md +23 -0
  73. package/docs/en/ui/breadcrumb.md +38 -0
  74. package/docs/en/ui/button.md +39 -0
  75. package/docs/en/ui/calendar.md +28 -0
  76. package/docs/en/ui/card.md +35 -0
  77. package/docs/en/ui/checkbox.md +34 -0
  78. package/docs/en/ui/cn.md +34 -0
  79. package/docs/en/ui/collapsible.md +21 -0
  80. package/docs/en/ui/command.md +37 -0
  81. package/docs/en/ui/dialog.md +52 -0
  82. package/docs/en/ui/dropdown-menu.md +50 -0
  83. package/docs/en/ui/empty.md +22 -0
  84. package/docs/en/ui/error-state.md +50 -0
  85. package/docs/en/ui/input-group.md +30 -0
  86. package/docs/en/ui/input.md +28 -0
  87. package/docs/en/ui/label.md +19 -0
  88. package/docs/en/ui/loading.md +19 -0
  89. package/docs/en/ui/popover.md +34 -0
  90. package/docs/en/ui/progress.md +28 -0
  91. package/docs/en/ui/scroll-area.md +23 -0
  92. package/docs/en/ui/select.md +63 -0
  93. package/docs/en/ui/separator.md +15 -0
  94. package/docs/en/ui/sheet.md +28 -0
  95. package/docs/en/ui/sidebar.md +92 -0
  96. package/docs/en/ui/skeleton.md +16 -0
  97. package/docs/en/ui/slider.md +21 -0
  98. package/docs/en/ui/spinner.md +14 -0
  99. package/docs/en/ui/switch.md +19 -0
  100. package/docs/en/ui/table.md +24 -0
  101. package/docs/en/ui/tabs.md +23 -0
  102. package/docs/en/ui/textarea.md +15 -0
  103. package/docs/en/ui/toggle-group.md +26 -0
  104. package/docs/en/ui/toggle.md +19 -0
  105. package/docs/en/ui/tooltip.md +22 -0
  106. package/docs/en/ui/use-is-mobile.md +18 -0
  107. package/docs/en/ui-and-theming.md +95 -0
  108. package/docs/index.json +1346 -0
  109. package/docs/ja/agent-skills.md +87 -0
  110. package/docs/ja/api-and-server.md +84 -0
  111. package/docs/ja/build-and-deploy.md +279 -0
  112. package/docs/ja/cli-reference.md +305 -0
  113. package/docs/ja/components.md +231 -0
  114. package/docs/ja/data-fetching.md +142 -0
  115. package/docs/ja/environment-variables.md +68 -0
  116. package/docs/ja/getting-started.md +95 -0
  117. package/docs/ja/index.md +65 -0
  118. package/docs/ja/markdown/markdown-renderer.md +43 -0
  119. package/docs/ja/pages-and-metadata.md +59 -0
  120. package/docs/ja/parts/app-shell.md +54 -0
  121. package/docs/ja/parts/dashboard-card.md +64 -0
  122. package/docs/ja/parts/data-table.md +85 -0
  123. package/docs/ja/parts/date-range-picker.md +41 -0
  124. package/docs/ja/parts/echart.md +52 -0
  125. package/docs/ja/parts/filter-bar.md +64 -0
  126. package/docs/ja/parts/funnel-steps.md +33 -0
  127. package/docs/ja/parts/metric-value.md +25 -0
  128. package/docs/ja/parts/multi-select.md +27 -0
  129. package/docs/ja/parts/page-shell.md +45 -0
  130. package/docs/ja/parts/placeholder.md +37 -0
  131. package/docs/ja/parts/searchable-select.md +47 -0
  132. package/docs/ja/parts/section-header.md +20 -0
  133. package/docs/ja/parts/segmented-control.md +26 -0
  134. package/docs/ja/parts/sparkline.md +47 -0
  135. package/docs/ja/parts/status-badge.md +44 -0
  136. package/docs/ja/parts/trend-indicator.md +26 -0
  137. package/docs/ja/routing.md +175 -0
  138. package/docs/ja/ui/accordion.md +37 -0
  139. package/docs/ja/ui/alert.md +31 -0
  140. package/docs/ja/ui/badge.md +23 -0
  141. package/docs/ja/ui/breadcrumb.md +38 -0
  142. package/docs/ja/ui/button.md +39 -0
  143. package/docs/ja/ui/calendar.md +28 -0
  144. package/docs/ja/ui/card.md +35 -0
  145. package/docs/ja/ui/checkbox.md +34 -0
  146. package/docs/ja/ui/cn.md +34 -0
  147. package/docs/ja/ui/collapsible.md +21 -0
  148. package/docs/ja/ui/command.md +36 -0
  149. package/docs/ja/ui/dialog.md +51 -0
  150. package/docs/ja/ui/dropdown-menu.md +50 -0
  151. package/docs/ja/ui/empty.md +22 -0
  152. package/docs/ja/ui/error-state.md +50 -0
  153. package/docs/ja/ui/input-group.md +30 -0
  154. package/docs/ja/ui/input.md +28 -0
  155. package/docs/ja/ui/label.md +19 -0
  156. package/docs/ja/ui/loading.md +19 -0
  157. package/docs/ja/ui/popover.md +34 -0
  158. package/docs/ja/ui/progress.md +28 -0
  159. package/docs/ja/ui/scroll-area.md +24 -0
  160. package/docs/ja/ui/select.md +64 -0
  161. package/docs/ja/ui/separator.md +15 -0
  162. package/docs/ja/ui/sheet.md +28 -0
  163. package/docs/ja/ui/sidebar.md +92 -0
  164. package/docs/ja/ui/skeleton.md +16 -0
  165. package/docs/ja/ui/slider.md +21 -0
  166. package/docs/ja/ui/spinner.md +14 -0
  167. package/docs/ja/ui/switch.md +19 -0
  168. package/docs/ja/ui/table.md +24 -0
  169. package/docs/ja/ui/tabs.md +24 -0
  170. package/docs/ja/ui/textarea.md +15 -0
  171. package/docs/ja/ui/toggle-group.md +27 -0
  172. package/docs/ja/ui/toggle.md +19 -0
  173. package/docs/ja/ui/tooltip.md +22 -0
  174. package/docs/ja/ui/use-is-mobile.md +18 -0
  175. package/docs/ja/ui-and-theming.md +95 -0
  176. package/package.json +29 -4
  177. package/registry/blocks/sales-overview.tsx +43 -19
  178. package/registry/ui/data-table.tsx +702 -102
  179. package/skills/vantage-add-feature/SKILL.md +153 -0
  180. package/skills/vantage-app/SKILL.md +291 -0
  181. package/skills/vantage-pitfalls/SKILL.md +139 -0
  182. package/templates/AGENTS.md +313 -0
  183. package/theme.css +178 -40
  184. package/dist/chunk-73J5ZD4C.js.map +0 -1
  185. package/dist/chunk-ATYZ45XL.js +0 -19
  186. package/dist/chunk-ATYZ45XL.js.map +0 -1
  187. 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
@@ -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
+ ```