@squadbase/vantage 0.6.1 → 0.6.2-dev1.31accb1
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/dist/add-DY4AXANK.js +6 -0
- package/dist/add-DY4AXANK.js.map +1 -0
- package/dist/{build-O5TVNH4E.js → build-TVKFIVFQ.js} +8 -8
- package/dist/{build-O5TVNH4E.js.map → build-TVKFIVFQ.js.map} +1 -1
- package/dist/{check-WFBEDHDR.js → check-3KHZXZMQ.js} +6 -6
- package/dist/{check-WFBEDHDR.js.map → check-3KHZXZMQ.js.map} +1 -1
- package/dist/{chunk-PLST5Q7T.js → chunk-AG6RZ2RR.js} +1010 -23
- package/dist/chunk-AG6RZ2RR.js.map +1 -0
- package/dist/{chunk-KLEIVDUV.js → chunk-CEXAQQ5W.js} +150 -11
- package/dist/chunk-CEXAQQ5W.js.map +1 -0
- package/dist/{chunk-JGRMRXXZ.js → chunk-JKLLFVEU.js} +3 -3
- package/dist/{chunk-JGRMRXXZ.js.map → chunk-JKLLFVEU.js.map} +1 -1
- package/dist/{chunk-EP6JHXSR.js → chunk-LMUACBMA.js} +3 -3
- package/dist/{chunk-EP6JHXSR.js.map → chunk-LMUACBMA.js.map} +1 -1
- package/dist/{chunk-MXI3PZFT.js → chunk-OB6UBJXF.js} +156 -200
- package/dist/chunk-OB6UBJXF.js.map +1 -0
- package/dist/{chunk-BCE22JSM.js → chunk-P7W4LR3Z.js} +32 -13
- package/dist/chunk-P7W4LR3Z.js.map +1 -0
- package/dist/chunk-PXRX5PEC.js +54 -0
- package/dist/chunk-PXRX5PEC.js.map +1 -0
- package/dist/{chunk-3G43C6OL.js → chunk-QI3XQKHS.js} +39 -3
- package/dist/chunk-QI3XQKHS.js.map +1 -0
- package/dist/{chunk-QDZA5JSL.js → chunk-U2M6HGKQ.js} +3 -3
- package/dist/{chunk-QDZA5JSL.js.map → chunk-U2M6HGKQ.js.map} +1 -1
- package/dist/{chunk-T3FLAGI6.js → chunk-VA776YE5.js} +3 -3
- package/dist/{chunk-T3FLAGI6.js.map → chunk-VA776YE5.js.map} +1 -1
- package/dist/cli.js +14 -11
- package/dist/cli.js.map +1 -1
- package/dist/components/index.d.ts +223 -1
- package/dist/components/index.js +3 -2
- package/dist/{dev-NZRLOQCL.js → dev-GDKATCC7.js} +22 -11
- package/dist/dev-GDKATCC7.js.map +1 -0
- package/dist/doc/index.d.ts +4 -0
- package/dist/doc/index.js +107 -11
- package/dist/doc/index.js.map +1 -1
- package/dist/{docs-ZGDJUHJI.js → docs-EJJ3BECT.js} +3 -3
- package/dist/{docs-ZGDJUHJI.js.map → docs-EJJ3BECT.js.map} +1 -1
- package/dist/{doctor-VFKEMR54.js → doctor-WQXPXP6K.js} +7 -7
- package/dist/doctor-WQXPXP6K.js.map +1 -0
- package/dist/{preview-QDCIVVSR.js → preview-OGMCNQUO.js} +12 -4
- package/dist/preview-OGMCNQUO.js.map +1 -0
- package/dist/{routes-RHP5FVGD.js → routes-MWBWWOJ2.js} +5 -5
- package/dist/{routes-RHP5FVGD.js.map → routes-MWBWWOJ2.js.map} +1 -1
- package/dist/{search-RFBELGY7.js → search-6Y422SV6.js} +3 -3
- package/dist/{search-RFBELGY7.js.map → search-6Y422SV6.js.map} +1 -1
- package/dist/slide/index.js +61 -15
- package/dist/slide/index.js.map +1 -1
- package/dist/table/index.js +7 -5
- package/dist/table/index.js.map +1 -1
- package/dist/ui/index.d.ts +140 -10
- package/dist/ui/index.js +1406 -63
- package/dist/ui/index.js.map +1 -1
- package/dist/{upgrade-GF2P67M6.js → upgrade-HCANX4GQ.js} +6 -6
- package/dist/{upgrade-GF2P67M6.js.map → upgrade-HCANX4GQ.js.map} +1 -1
- package/dist/vite/index.js +3 -3
- package/docs/en/changelog.md +24 -0
- package/docs/en/cli-reference.md +30 -0
- package/docs/en/parts/page-shell.md +1 -1
- package/docs/en/routing.md +4 -2
- package/docs/index.json +291 -61
- package/docs/ja/changelog.md +50 -0
- package/docs/ja/cli-reference.md +29 -0
- package/docs/ja/components.md +33 -89
- package/docs/ja/page-types/csv.md +83 -0
- package/docs/ja/page-types/doc.md +83 -0
- package/docs/ja/page-types/excel.md +82 -0
- package/docs/ja/page-types/slide.md +132 -0
- package/docs/ja/page-types.md +47 -0
- package/docs/ja/parts/area-chart.md +61 -0
- package/docs/ja/parts/bar-chart.md +69 -0
- package/docs/ja/parts/bar-list.md +35 -0
- package/docs/ja/parts/category-bar.md +36 -0
- package/docs/ja/parts/donut-chart.md +47 -0
- package/docs/ja/parts/echart.md +3 -0
- package/docs/ja/parts/line-chart.md +58 -0
- package/docs/ja/parts/page-shell.md +1 -1
- package/docs/ja/parts/progress-circle.md +34 -0
- package/docs/ja/parts/sparkline.md +1 -1
- package/docs/ja/parts/tracker.md +32 -0
- package/docs/ja/routing.md +8 -84
- package/docs/ja/ui/alert-dialog.md +41 -0
- package/docs/ja/ui/avatar.md +31 -0
- package/docs/ja/ui/combobox.md +74 -0
- package/docs/ja/ui/drawer.md +41 -0
- package/docs/ja/ui/field.md +42 -0
- package/docs/ja/ui/hover-card.md +21 -0
- package/docs/ja/ui/kbd.md +16 -0
- package/docs/ja/ui/pagination.md +36 -0
- package/docs/ja/ui/radio-group.md +21 -0
- package/docs/ja/ui/toast.md +46 -0
- package/docs/ja/ui-and-theming.md +14 -7
- package/package.json +18 -12
- package/registry/ui/accordion.tsx +74 -0
- package/registry/ui/alert-dialog.tsx +189 -0
- package/registry/ui/alert.tsx +78 -0
- package/registry/ui/app-shell.tsx +281 -0
- package/registry/ui/area-chart.tsx +1015 -0
- package/registry/ui/avatar.tsx +110 -0
- package/registry/ui/badge.tsx +54 -0
- package/registry/ui/bar-chart.tsx +1013 -0
- package/registry/ui/bar-list.tsx +302 -0
- package/registry/ui/breadcrumb.tsx +126 -0
- package/registry/ui/button.tsx +60 -0
- package/registry/ui/calendar.tsx +221 -0
- package/registry/ui/card.tsx +105 -0
- package/registry/ui/category-bar.tsx +281 -0
- package/registry/ui/checkbox.tsx +28 -0
- package/registry/ui/collapsible.tsx +21 -0
- package/registry/ui/combobox.tsx +310 -0
- package/registry/ui/command.tsx +196 -0
- package/registry/ui/dashboard-card.tsx +174 -0
- package/registry/ui/data-table.tsx +16 -91
- package/registry/ui/date-range-picker.tsx +209 -0
- package/registry/ui/dialog.tsx +159 -0
- package/registry/ui/donut-chart.tsx +1004 -0
- package/registry/ui/drawer.tsx +229 -0
- package/registry/ui/dropdown-menu.tsx +272 -0
- package/registry/ui/echart.tsx +486 -0
- package/registry/ui/field.tsx +240 -0
- package/registry/ui/filter-bar.tsx +365 -0
- package/registry/ui/funnel-steps.tsx +274 -0
- package/registry/ui/hover-card.tsx +52 -0
- package/registry/ui/input-group.tsx +158 -0
- package/registry/ui/input.tsx +22 -0
- package/registry/ui/kbd.tsx +28 -0
- package/registry/ui/label.tsx +20 -0
- package/registry/ui/line-chart.tsx +1007 -0
- package/registry/ui/metric-value.tsx +54 -0
- package/registry/ui/multi-select.tsx +226 -0
- package/registry/ui/page-shell.tsx +227 -0
- package/registry/ui/pagination.tsx +138 -0
- package/registry/ui/placeholder.tsx +30 -0
- package/registry/ui/popover.tsx +90 -0
- package/registry/ui/progress-circle.tsx +272 -0
- package/registry/ui/progress.tsx +83 -0
- package/registry/ui/radio-group.tsx +39 -0
- package/registry/ui/scroll-area.tsx +55 -0
- package/registry/ui/searchable-select.tsx +209 -0
- package/registry/ui/section-header.tsx +41 -0
- package/registry/ui/segmented-control.tsx +71 -0
- package/registry/ui/select.tsx +253 -0
- package/registry/ui/separator.tsx +25 -0
- package/registry/ui/sheet.tsx +137 -0
- package/registry/ui/sidebar.tsx +723 -0
- package/registry/ui/skeleton.tsx +15 -0
- package/registry/ui/slider.tsx +54 -0
- package/registry/ui/sparkline.tsx +155 -0
- package/registry/ui/spinner.tsx +12 -0
- package/registry/ui/states.tsx +61 -0
- package/registry/ui/status-badge.tsx +79 -0
- package/registry/ui/switch.tsx +32 -0
- package/registry/ui/table.tsx +116 -0
- package/registry/ui/tabs.tsx +82 -0
- package/registry/ui/textarea.tsx +20 -0
- package/registry/ui/toast.tsx +250 -0
- package/registry/ui/toggle-group.tsx +89 -0
- package/registry/ui/toggle.tsx +45 -0
- package/registry/ui/tooltip.tsx +66 -0
- package/registry/ui/tracker.tsx +236 -0
- package/registry/ui/trend-indicator.tsx +62 -0
- package/skills/vantage-add-feature/SKILL.md +9 -7
- package/skills/vantage-design/SKILL.md +3 -1
- package/skills/vantage-design/references/format.md +1 -1
- package/skills/vantage-pitfalls/SKILL.md +5 -1
- package/skills/vantage-slide/SKILL.md +17 -0
- package/templates/AGENTS.md +10 -1
- package/templates/agents/api.md +29 -0
- package/templates/agents/csv.md +2 -1
- package/templates/agents/doc.md +6 -3
- package/templates/agents/page.md +22 -8
- package/templates/agents/slide.md +13 -1
- package/templates/agents/xlsx.md +2 -1
- package/theme.css +51 -1
- package/dist/add-EISGSZAH.js +0 -6
- package/dist/add-EISGSZAH.js.map +0 -1
- package/dist/chunk-3G43C6OL.js.map +0 -1
- package/dist/chunk-BCE22JSM.js.map +0 -1
- package/dist/chunk-KLEIVDUV.js.map +0 -1
- package/dist/chunk-MXI3PZFT.js.map +0 -1
- package/dist/chunk-PLST5Q7T.js.map +0 -1
- package/dist/dev-NZRLOQCL.js.map +0 -1
- package/dist/doctor-VFKEMR54.js.map +0 -1
- package/dist/preview-QDCIVVSR.js.map +0 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copied by `vantage add ui trend-indicator`. This file is yours to edit.
|
|
2
|
+
// Generated from @squadbase/vantage src/components/trend-indicator.tsx by `npm run registry` (in Vantage, edit src/, not registry/).
|
|
3
|
+
/**
|
|
4
|
+
* TrendIndicator — an arrow plus percentage change. Colour tracks *sentiment*,
|
|
5
|
+
* not direction: set `positiveIsGood={false}` for metrics where going up is bad
|
|
6
|
+
* (churn, error rate) and a rise renders as negative.
|
|
7
|
+
*/
|
|
8
|
+
import { forwardRef } from "react"
|
|
9
|
+
import { ArrowDown, ArrowUp, Minus } from "lucide-react"
|
|
10
|
+
import { cva } from "class-variance-authority"
|
|
11
|
+
|
|
12
|
+
import { cn } from "@squadbase/vantage/ui"
|
|
13
|
+
import type { TrendDirection } from "@squadbase/vantage/components"
|
|
14
|
+
|
|
15
|
+
const trendIndicatorVariants = cva("inline-flex items-center gap-0.5 text-sm font-medium", {
|
|
16
|
+
variants: {
|
|
17
|
+
sentiment: {
|
|
18
|
+
positive: "text-chart-1",
|
|
19
|
+
negative: "text-primary",
|
|
20
|
+
neutral: "text-muted-foreground",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
sentiment: "neutral",
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
export interface TrendIndicatorProps {
|
|
29
|
+
value: number
|
|
30
|
+
direction: TrendDirection
|
|
31
|
+
positiveIsGood?: boolean
|
|
32
|
+
className?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const TrendIndicator = forwardRef<HTMLSpanElement, TrendIndicatorProps>(
|
|
36
|
+
({ value, direction, positiveIsGood = true, className }, ref) => {
|
|
37
|
+
const isGood = direction === "neutral" ? null : (direction === "up") === positiveIsGood
|
|
38
|
+
const sentiment = isGood === null ? "neutral" : isGood ? "positive" : "negative"
|
|
39
|
+
|
|
40
|
+
const Icon = direction === "up" ? ArrowUp : direction === "down" ? ArrowDown : Minus
|
|
41
|
+
|
|
42
|
+
const ariaLabel =
|
|
43
|
+
direction === "neutral"
|
|
44
|
+
? `変化なし ${value}%`
|
|
45
|
+
: direction === "up"
|
|
46
|
+
? `${value}% 増加`
|
|
47
|
+
: `${value}% 減少`
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<span
|
|
51
|
+
ref={ref}
|
|
52
|
+
data-slot="trend-indicator"
|
|
53
|
+
className={cn(trendIndicatorVariants({ sentiment }), className)}
|
|
54
|
+
aria-label={ariaLabel}
|
|
55
|
+
>
|
|
56
|
+
<Icon className="size-3.5" aria-hidden="true" />
|
|
57
|
+
<span>{value}%</span>
|
|
58
|
+
</span>
|
|
59
|
+
)
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
TrendIndicator.displayName = "TrendIndicator"
|
|
@@ -16,7 +16,7 @@ CLI は雛形を出すだけで、規約の遵守はこちらの責任。**追
|
|
|
16
16
|
```bash
|
|
17
17
|
vantage add page <name> # ルートページ(.tsx)
|
|
18
18
|
vantage add api <name> # server/api/**.ts の API モジュール
|
|
19
|
-
vantage add ui <name> #
|
|
19
|
+
vantage add ui <name> # /ui・/components の部品ソースを components/ui/ にコピー(src/ があればその中)
|
|
20
20
|
vantage add block <name> # registry からブロックを components/blocks/ にコピー(同上)
|
|
21
21
|
```
|
|
22
22
|
|
|
@@ -121,15 +121,17 @@ vantage add ui data-table # → components/ui/data-table.tsx(編集可能
|
|
|
121
121
|
vantage add block sales-overview # → components/blocks/sales-overview.tsx
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
未知の名前を渡すと利用可能な名前一覧を出して失敗する。
|
|
127
|
-
- コピーが要らない大半のプリミティブは `@squadbase/vantage/ui` から、複合パーツは
|
|
128
|
-
`@squadbase/vantage/components` から**そのまま import**するのが基本(コピー不要)。
|
|
124
|
+
- **基本はコピーせず import する。** プリミティブは `@squadbase/vantage/ui` から、複合パーツと
|
|
125
|
+
チャートは `@squadbase/vantage/components` から**そのまま import**する。
|
|
129
126
|
```tsx
|
|
130
127
|
import { Button, Loading, ErrorState } from "@squadbase/vantage/ui"
|
|
131
|
-
import { DashboardCardPreset, DataTablePreset,
|
|
128
|
+
import { DashboardCardPreset, DataTablePreset, LineChart } from "@squadbase/vantage/components"
|
|
132
129
|
```
|
|
130
|
+
- `add ui` は**改造したいときだけ**使う。`/ui` と `/components` の部品はすべて kebab-case 名で
|
|
131
|
+
コピーできる(`add ui bar-chart`・`add ui combobox`)。未知の名前を渡すと利用可能な名前一覧を
|
|
132
|
+
出して失敗する。
|
|
133
|
+
- グラフは型付きチャート(`LineChart`・`BarChart` など)から選ぶ。選び方は `agents/page.md` の
|
|
134
|
+
「グラフはまず型付きチャートで描く」。
|
|
133
135
|
- **props は `vantage docs <name>` で確認してから書く**(`vantage docs button`・
|
|
134
136
|
`vantage docs parts/data-table`。名前が分からなければ `vantage search <やりたいこと>` で
|
|
135
137
|
探してから `vantage docs` に渡す)。
|
|
@@ -77,7 +77,7 @@ Vantage アプリの見た目は 2 つのファイルで決まる。
|
|
|
77
77
|
|
|
78
78
|
```css
|
|
79
79
|
body {
|
|
80
|
-
font-family: "<Font>", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
80
|
+
font-family: "<Font>", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
|
|
81
81
|
}
|
|
82
82
|
:root {
|
|
83
83
|
--slide-font-display: "<Font>", system-ui, -apple-system, "Hiragino Kaku Gothic ProN", "Hiragino Sans", "Yu Gothic", Meiryo, sans-serif;
|
|
@@ -85,6 +85,8 @@ Vantage アプリの見た目は 2 つのファイルで決まる。
|
|
|
85
85
|
}
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
欧文の Web フォントだけを先頭に足すときも、日本語の system face(`"Hiragino Sans"` 〜 `Meiryo`)は
|
|
89
|
+
必ず残す。消すとカナ・漢字がブラウザ任せのフォールバックになり、細く表示される。
|
|
88
90
|
日本語の Web フォントは face が 100 を超えるので原則使わない(pptx 書き出しも壊れる。
|
|
89
91
|
`vantage-slide` の `references/tokens.md` 参照)。
|
|
90
92
|
|
|
@@ -119,7 +119,7 @@ DESIGN.md — このアプリの「見た目の意図」を書くファイルで
|
|
|
119
119
|
|
|
120
120
|
| 用途 | 指定 | 備考 |
|
|
121
121
|
| --- | --- | --- |
|
|
122
|
-
| 見出し・本文 |
|
|
122
|
+
| 見出し・本文 | 日本語を含むシステムフォント(`body` の `font-family`) | Web フォントは使わない |
|
|
123
123
|
| 数字 | 同上 + `tabular-nums` | 桁がそろうように必ず付ける |
|
|
124
124
|
| スライドの見出し | `--slide-font-display` | 既定は日本語を含むシステムフォント |
|
|
125
125
|
| スライドの本文 | `--slide-font-body` | 既定は見出しと同じ |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vantage-pitfalls
|
|
3
|
-
description: Vantage(@squadbase/vantage)アプリを書くときに静かに壊れる落とし穴のリファレンス。Base UI は Radix ではない(asChild 無し・render プロップ)、Select の value/label、クライアントから server/ を import
|
|
3
|
+
description: Vantage(@squadbase/vantage)アプリを書くときに静かに壊れる落とし穴のリファレンス。Base UI は Radix ではない(asChild 無し・render プロップ)、Select の value/label、クライアントから server/ を import しない、チャートの色指定と EChart の配色・高さ、動的パラメータの3綴り同期、PUBLIC_ env、HttpError、csv/xlsx ページの URL 衝突とサイズ上限、スライドの data-waitfor など。Vantage の UI コンポーネントやルーティングが思った通りに動かないとき、ビルドやスタイルが静かに欠落するときに参照する。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Vantage アプリの落とし穴リファレンス
|
|
@@ -59,6 +59,10 @@ Base UI の `SelectValue` は選択中の **value をそのまま描き**、`Sel
|
|
|
59
59
|
|
|
60
60
|
## チャート:`EChart` の配色はトークン追従。上書きは `option.color`
|
|
61
61
|
|
|
62
|
+
ふつうの推移・比較・構成比は型付きチャート(`LineChart`・`BarChart` など。→ `agents/page.md`)で
|
|
63
|
+
描く。その `colors` に渡すのはトークン名 `"chart-1"`〜`"chart-5"` か CSS 色で、Tailwind クラス
|
|
64
|
+
(`"bg-blue-500"` など)は効かない。以下は `EChart` を直接使うときの話。
|
|
65
|
+
|
|
62
66
|
系列色は `--chart-1..5`、軸・凡例・ツールチップは文字色/境界色のトークンから組まれる
|
|
63
67
|
(init 時にトークンの実値を解決している)。ライト / ダークの切り替えにも、`styles.css` の
|
|
64
68
|
書き換えやテーマプリセットの適用にも追従する。
|
|
@@ -49,6 +49,9 @@ export default function JuneDeck() {
|
|
|
49
49
|
- **`.slide` を付けられるのはルートになるページモジュールだけ。** `_layout.slide.tsx` や
|
|
50
50
|
`deck.slide.ts` は `INVALID_PAGE_VARIANT` エラーになります。
|
|
51
51
|
- **`june.slide.tsx` と `june.tsx` は同じ URL** になるので `ROUTE_CONFLICT` です。どちらかを消すこと。
|
|
52
|
+
- **ルート `/` がすでに他のページ(`index.tsx` など)で使われている場合、スライドは `index.slide.tsx` ではなく、タイトルから作った slug でファイル名を付ける。** `index.slide.tsx` と `index.tsx` は同じ `/` に解決して `ROUTE_CONFLICT` になる。
|
|
53
|
+
- 例: "Label check" → `src/label-check.slide.tsx` → `/label-check`
|
|
54
|
+
- 例: "Monthly Report" → `src/monthly-report.slide.tsx` → `/monthly-report`
|
|
52
55
|
- **デッキファイル以外を作らない。** ヘルパーコンポーネントも定数も同じ `.slide.tsx` の中に書く。
|
|
53
56
|
スライド専用のコンポーネントを `components/` に切り出すと、デッキ 1 本を読むのに 2 ファイル
|
|
54
57
|
追わせることになります。
|
|
@@ -194,6 +197,17 @@ pptx 書き出しのために描き終わりを待たせる必要があります
|
|
|
194
197
|
チャートに色をハードコードしないこと(`option.color` / `itemStyle.color` / `theme`)。
|
|
195
198
|
`EChart` はテーマトークンに追従します。
|
|
196
199
|
|
|
200
|
+
## 説明と図表を同じデータ時点へ揃える
|
|
201
|
+
|
|
202
|
+
分析を共有するデッキでは、本文・数値・図表が**同じ対象期間と同じ取得時点の結果**を参照していることを
|
|
203
|
+
確かめます。
|
|
204
|
+
|
|
205
|
+
- 対象期間とデータ取得時点を、該当ページかフッターに短く表示する(例: 「2026年6月 / 7月1日 9:00 取得」)
|
|
206
|
+
- **固定した説明文に対して図表だけが最新値へ変わる構成を避ける。** ライブ更新を意図するなら、本文の
|
|
207
|
+
数値・結論も同じ取得結果から導いて、図表と一緒に変わる構成にする
|
|
208
|
+
- 同一時点の結果を保持・参照できない場合は、スナップショットとして保存できたとは報告しない。
|
|
209
|
+
必要な保持の仕組みと、現在保証できない範囲(例: 再表示すると図表だけ最新値になる)を伝える
|
|
210
|
+
|
|
197
211
|
## 実行時に無料で付いてくるもの
|
|
198
212
|
|
|
199
213
|
- `src/june.slide.tsx` → `/june`。ナビ(`useRoutes()`)に通常のページと同格で並ぶ
|
|
@@ -244,6 +258,7 @@ pptx 書き出しのために描き終わりを待たせる必要があります
|
|
|
244
258
|
- [ ] 繰り返す視覚要素が `array.map` ではなく明示的な `<Component />` になっている
|
|
245
259
|
- [ ] ページ番号が `useSlideNumber()` から来ている(ハードコードしていない)
|
|
246
260
|
- [ ] チャートが `data-waitfor="canvas"` で包まれている
|
|
261
|
+
- [ ] 本文・数値・図表が同じ対象期間と取得時点の結果を参照し、その期間と時点が表示されている
|
|
247
262
|
- [ ] `<Steps>` を使ったページが、`?p=` で直接開いても完成した絵として読める
|
|
248
263
|
- [ ] トランジションを宣言したなら、全ページが 1 つの family に収まっている(→ `references/transitions.md`)
|
|
249
264
|
- [ ] `definePage` の値がリテラルである
|
|
@@ -262,3 +277,5 @@ pptx 書き出しのために描き終わりを待たせる必要があります
|
|
|
262
277
|
- ❌ スライド用のコンポーネントを別ファイルに切り出す
|
|
263
278
|
- ❌ チャートに `data-waitfor="canvas"` を付け忘れる(pptx が白紙になる)
|
|
264
279
|
- ❌ プリミティブを `references/*.md` を読まずに使う
|
|
280
|
+
- ❌ 説明文を固定したまま図表だけライブデータで描く(再表示すると本文と図表の時点がずれる)
|
|
281
|
+
- ❌ 同一時点の結果を保持できていないのに「スナップショットとして保存した」と報告する
|
package/templates/AGENTS.md
CHANGED
|
@@ -93,7 +93,7 @@ root/
|
|
|
93
93
|
| `@squadbase/vantage/router` | `Link`・`Outlet`・`useParams`・`useSearch`・`useNavigate`・`redirect`・`notFound`・`useRoutes`・`useCurrentRoute`・`useSearchParam`・`useSearchState` |
|
|
94
94
|
| `@squadbase/vantage/query` | `useApiQuery`・`useApiMutation`・`apiJson`・`apiFetch`・`apiUrl`・`ApiError`、ほか `useQuery`/`useMutation` など TanStack Query の再エクスポート |
|
|
95
95
|
| `@squadbase/vantage/ui` | shadcn/ui(Base UI バリアント)プリミティブ(`Button`・`Loading`・`ErrorState`・`Empty` ほか) |
|
|
96
|
-
| `@squadbase/vantage/components` | 複合パーツ(`PageShell`・`DashboardCardPreset`・`DataTablePreset`・`EChart`
|
|
96
|
+
| `@squadbase/vantage/components` | 複合パーツ(`PageShell`・`DashboardCardPreset`・`DataTablePreset`、型付きチャート `LineChart`・`BarChart`・`AreaChart`・`DonutChart`・`BarList` ほか、`EChart`) |
|
|
97
97
|
| `@squadbase/vantage/table` | `FilePageView`・`TableViewer`(データファイルページの表ビューア) |
|
|
98
98
|
| `@squadbase/vantage/slide` | `SlideDeck`・`Slide`・`Steps`・`Step`・`MorphElement`・`useSlideNumber`・`useIsActiveSlide`(スライド専用。1920×1080 の固定キャンバス) |
|
|
99
99
|
| `@squadbase/vantage/doc` | `Document`(ドキュメント専用。中の素の HTML 要素に見出し・表などのスタイルが当たる) |
|
|
@@ -137,6 +137,15 @@ root/
|
|
|
137
137
|
| `.xlsx` ページ | `agents/xlsx.md` |
|
|
138
138
|
| `.csv` ページ | `agents/csv.md` |
|
|
139
139
|
|
|
140
|
+
**ページになるのは `.tsx` / `.jsx`(`.slide.tsx`・`.doc.tsx` を含む)・`.csv`・`.xlsx` だけ。**
|
|
141
|
+
|
|
142
|
+
- `.xls`・`.xlsm`・`.xlsb`・`.ods`・`.tsv`・`.numbers`・`.parquet` はルートにならず、404 にもならない。
|
|
143
|
+
`vantage check` の `UNSUPPORTED_PAGE_FILE` 警告だけが知らせる。`.xlsx` / `.csv` に変換して置く
|
|
144
|
+
- `.md`・`.json`・`.txt` は何も言わずに無視される。Markdown を見せたいときは `.tsx` のページで
|
|
145
|
+
`MarkdownRenderer`(`@squadbase/vantage/markdown`)に渡す
|
|
146
|
+
- `.csv` / `.xlsx` はブラウザでパースする。25MB を超えるとそのページにエラーが出る
|
|
147
|
+
(`FILE_PAGE_TOO_LARGE` 警告)。20 万行を超えるシートは先頭 20 万行だけが表示される
|
|
148
|
+
|
|
140
149
|
## 環境変数
|
|
141
150
|
|
|
142
151
|
- **クライアントで読めるのは `import.meta.env.PUBLIC_*` と `MODE`/`DEV`/`PROD`/`SSR`/`BASE_URL`
|
package/templates/agents/api.md
CHANGED
|
@@ -25,6 +25,11 @@ export async function GET({ params, env }: ApiContext) {
|
|
|
25
25
|
エクスポートする。それ以外の名前は `INVALID_API_EXPORT` エラー。
|
|
26
26
|
- 動的 API も `[id].ts` 記法: `server/api/customers/[id].ts` → `GET /api/customers/:id`。
|
|
27
27
|
`params.id` で取り出す(`noUncheckedIndexedAccess` が効くので narrowing が要る)。
|
|
28
|
+
- **`noUncheckedIndexedAccess` は配列・レコードの添字すべてに効く。** `arr[0]` も `obj[key]` も
|
|
29
|
+
`T | undefined` になる。最初に書く前に、添字アクセスと `useApiQuery` の `data` が
|
|
30
|
+
undefined を扱っているかを頭の中で型検査してから書く。上流の生の応答の値は
|
|
31
|
+
`Number(row.metricValues?.[0]?.value ?? "0")` のように `?.` と `??` で取り出す
|
|
32
|
+
(`!` で黙らせない)。
|
|
28
33
|
- **クライアントに見せたいエラーは `HttpError(status, msg)` を throw する。** それ以外の throw は
|
|
29
34
|
ログに記録され汎用の 500 に丸められる。
|
|
30
35
|
- **シークレットは `ApiContext.env` にだけ届く**(クライアントには決して届かない)。
|
|
@@ -34,9 +39,12 @@ export async function GET({ params, env }: ApiContext) {
|
|
|
34
39
|
|
|
35
40
|
```tsx
|
|
36
41
|
import { useApiQuery, useApiMutation } from "@squadbase/vantage/query"
|
|
42
|
+
import { Loading, ErrorState } from "@squadbase/vantage/ui"
|
|
37
43
|
|
|
38
44
|
const q = useApiQuery<Customer>(`/api/customers/${customerId}`)
|
|
45
|
+
if (q.isPending) return <Loading />
|
|
39
46
|
if (q.isError) return <ErrorState message={q.error.message} /> // HttpError のメッセージ
|
|
47
|
+
q.data // ここで初めて Customer(undefined ではない)
|
|
40
48
|
|
|
41
49
|
// クエリ文字列は search で。undefined の項目は落ちる
|
|
42
50
|
const rows = useApiQuery<Row[]>("/api/customers", { search: { segment } })
|
|
@@ -45,5 +53,26 @@ const rows = useApiQuery<Row[]>("/api/customers", { search: { segment } })
|
|
|
45
53
|
const save = useApiMutation<Customer, Payload>("/api/customers", { method: "POST" })
|
|
46
54
|
```
|
|
47
55
|
|
|
56
|
+
**`data` は、同じ結果オブジェクトで `isPending` と `isError` を判定したあとでしか
|
|
57
|
+
narrowing されない。** 判定前や、配列の `.find` などでまとめた判定のあとでは `T | undefined` のまま。
|
|
58
|
+
複数のクエリは 1 本ずつ判定してから `data` を使う(`data!` で黙らせない):
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
const sessions = useApiQuery<SessionsDaily[]>("/api/sessions-daily")
|
|
62
|
+
const metrics = useApiQuery<MetricsDaily[]>("/api/metrics-daily")
|
|
63
|
+
|
|
64
|
+
if (sessions.isPending || metrics.isPending) return <Loading />
|
|
65
|
+
if (sessions.isError) return <ErrorState message={sessions.error.message} />
|
|
66
|
+
if (metrics.isError) return <ErrorState message={metrics.error.message} />
|
|
67
|
+
// ここから sessions.data: SessionsDaily[] / metrics.data: MetricsDaily[]
|
|
68
|
+
return <Chart sessions={sessions.data} metrics={metrics.data} />
|
|
69
|
+
|
|
70
|
+
// NG: const failed = [sessions, metrics].find((q) => q.isError) のように配列でまとめて判定すると
|
|
71
|
+
// 各 q.data は narrowing されず、`T[] | undefined` を T[] の props に渡して型エラーになる
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
カードごとに別々に読み込み中・エラーを出すなら、`data` を渡す側で `q.data ?? []` にするか、
|
|
75
|
+
カードのコンポーネントの中で上と同じ判定をする。
|
|
76
|
+
|
|
48
77
|
`ApiError` は `message`・`status`・`body`・`requestId` を持つ。hook が使えない場所では
|
|
49
78
|
`apiJson(path, init)`、生の `Response` が要るときは `apiFetch`。
|
package/templates/agents/csv.md
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
```
|
|
28
28
|
- 数式・グラフ・セル書式といった概念は csv には無いので、値がそのまま読めます。ブラウザで
|
|
29
29
|
パースするので 25MB を超えるファイルはそのページにエラーが出ます —— 大きいデータは
|
|
30
|
-
`server/api/` から配って `DataTable`
|
|
30
|
+
`server/api/` から配って `DataTable` で描いてください。20 万行を超えると先頭
|
|
31
|
+
20 万行だけが表示されます(残りはダウンロードして見る)
|
|
31
32
|
- **ビューアの無い拡張子(`.tsv` など)はルートになりません。** `vantage check` の
|
|
32
33
|
`UNSUPPORTED_PAGE_FILE` 警告が知らせます
|
package/templates/agents/doc.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
```tsx
|
|
14
14
|
import { definePage } from "@squadbase/vantage"
|
|
15
|
-
import {
|
|
15
|
+
import { BarChart } from "@squadbase/vantage/components"
|
|
16
16
|
import { Document } from "@squadbase/vantage/doc"
|
|
17
17
|
|
|
18
18
|
export const page = definePage({ title: "6月度サマリー", navLabel: "6月度サマリー" })
|
|
@@ -23,7 +23,7 @@ export default function JuneSummary() {
|
|
|
23
23
|
<p>6月の売上は <strong>5,250 万円</strong>で、目標を 5% 上回りました。</p>
|
|
24
24
|
<h2>週次の売上</h2>
|
|
25
25
|
<figure>
|
|
26
|
-
<
|
|
26
|
+
<BarChart data={weekly} index="week" categories={["売上"]} height={280} ariaLabel="6月の週次売上" />
|
|
27
27
|
<figcaption>第4週はキャンペーン初週</figcaption>
|
|
28
28
|
</figure>
|
|
29
29
|
<table>…</table>
|
|
@@ -42,8 +42,11 @@ export default function JuneSummary() {
|
|
|
42
42
|
見た目を変えたいときはユーティリティを並べず、下の `--doc-*` を変えます。
|
|
43
43
|
- **数値はコードに直接書く。** ドキュメントは書いた時点の内容を残すページです。
|
|
44
44
|
`useApiQuery` などで読み込むと、開くたびに値が変わります。
|
|
45
|
-
-
|
|
45
|
+
- **チャートは型付きチャート(`BarChart`・`LineChart` など。`@squadbase/vantage/components`)を
|
|
46
|
+
文中に置く**(選び方は `agents/page.md` の「グラフはまず型付きチャートで描く」)。`figure` で囲めば
|
|
46
47
|
`figcaption` がキャプションになります。
|
|
48
|
+
- **PDF の保存ボタンは作らない。** `<Document>` が右下に PDF 保存のボタンを出し、印刷時は
|
|
49
|
+
本文だけをライトの配色で出します。
|
|
47
50
|
- **ページ全体を包むのは `<Document>` だけ。** `PageShell` などのダッシュボード用の枠で包まない
|
|
48
51
|
(本文の幅と余白は `<Document>` が決めます)。
|
|
49
52
|
|
package/templates/agents/page.md
CHANGED
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@squadbase/vantage": "^0.5.0",
|
|
29
|
-
"react": "^19.
|
|
30
|
-
"react-dom": "^19.
|
|
29
|
+
"react": "^19.3.1",
|
|
30
|
+
"react-dom": "^19.3.1"
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
```
|
|
@@ -164,17 +164,31 @@ refetchOnWindowFocus false・networkMode "always")。挙動を変えたいとき
|
|
|
164
164
|
## 組み込み UI / コンポーネントの入口
|
|
165
165
|
|
|
166
166
|
- **プリミティブ**は `@squadbase/vantage/ui` から import する(`Button`・`Loading`・
|
|
167
|
-
`ErrorState`・`Empty`・`Select`・`Checkbox
|
|
167
|
+
`ErrorState`・`Empty`・`Select`・`Checkbox`・`RadioGroup`・`Field`・`Combobox`・`Pagination`・
|
|
168
|
+
`Avatar`・`Kbd`・`HoverCard`・`AlertDialog`・`Drawer`・`Toaster` + `toast.add()` ほか)。
|
|
168
169
|
- **複合パーツ**は `@squadbase/vantage/components` から(`PageShell`・`DashboardCardPreset`・
|
|
169
|
-
`DataTablePreset
|
|
170
|
+
`DataTablePreset`・型付きチャート(下の「グラフ」)・`EChart` ほか)。
|
|
170
171
|
- **どの名前が import 可能か / props の詳細は `vantage docs` で引く。** ガイドとコンポーネント
|
|
171
172
|
リファレンスはパッケージに同梱されていて、オフラインでも読める(→ `AGENTS.md` の
|
|
172
173
|
「ドキュメントを引く」)。**名前が分からないとき**はやりたいことで `vantage search` する
|
|
173
174
|
(→ 同節)。
|
|
174
|
-
- **UI は import して使うのが既定。取り出す(eject)必要はない。** `vantage add ui
|
|
175
|
-
|
|
176
|
-
`
|
|
177
|
-
`add
|
|
175
|
+
- **UI は import して使うのが既定。取り出す(eject)必要はない。** `vantage add ui <name>` は
|
|
176
|
+
ソースを手元にコピーして**改造したいとき専用**のコマンド。`/ui` のプリミティブも
|
|
177
|
+
`/components` の複合パーツも全部取り出せる(名前は kebab-case: `add ui bar-chart`。
|
|
178
|
+
ブロックは `add block sales-overview`。未知名で実行すると候補が一覧表示される)。
|
|
179
|
+
|
|
180
|
+
### グラフはまず型付きチャートで描く
|
|
181
|
+
|
|
182
|
+
- 推移は `LineChart` / `AreaChart`、比較は `BarChart`、構成比は `DonutChart`。`data`(行の配列)・
|
|
183
|
+
`index`(x 軸の列)・`categories`(系列の列)を渡すだけで、option は書かない
|
|
184
|
+
(`DonutChart` は `category` / `value`)。
|
|
185
|
+
- 上位 N 件は `BarList`、判定帯や予算消化は `CategoryBar`、達成率は `ProgressCircle`、
|
|
186
|
+
日ごとの状態は `Tracker`。
|
|
187
|
+
- `EChart` + `EChartsOption` は、二軸・散布図・ヒートマップ・注釈線など型付きチャートの props で
|
|
188
|
+
表せないときだけ使う。
|
|
189
|
+
- 色は省略してテーマトークンに任せる。指定するなら `"chart-1"`〜`"chart-5"` か
|
|
190
|
+
`"var(--destructive)"` などの CSS 色。hex の直書きや Tailwind クラスは使わない。
|
|
191
|
+
- 数値の書式(`¥`・`%`・桁区切り)は `valueFormatter` に渡す。
|
|
178
192
|
|
|
179
193
|
### ダークモードは opt-in
|
|
180
194
|
|
|
@@ -11,6 +11,13 @@
|
|
|
11
11
|
`src/monthly-report.slide.tsx` → `/monthly-report`。中身は `<SlideDeck>` を返す普通の React
|
|
12
12
|
コンポーネントで、`definePage` もナビも通常のページと同じように効きます。
|
|
13
13
|
|
|
14
|
+
**ファイル名の決め方:**
|
|
15
|
+
|
|
16
|
+
- **ルート `/` がすでに他のページ(`index.tsx`など)で使われている場合は、スライドのタイトルから slug を作ってファイル名にする。** `index.slide.tsx` は `index.tsx` と同じ `/` に解決するので `ROUTE_CONFLICT` になる。
|
|
17
|
+
- 例: "Label check" というスライド → `src/label-check.slide.tsx` → `/label-check`
|
|
18
|
+
- 例: "Monthly Report" というスライド → `src/monthly-report.slide.tsx` → `/monthly-report`
|
|
19
|
+
- 新規プロジェクトでまだ `/` が空いている場合のみ、`index.slide.tsx` を使ってよい。
|
|
20
|
+
|
|
14
21
|
```tsx
|
|
15
22
|
import { Slide, SlideDeck } from "@squadbase/vantage/slide"
|
|
16
23
|
|
|
@@ -34,7 +41,12 @@ export default function Deck() {
|
|
|
34
41
|
送れ、左のスライド一覧(サムネイル列)は `L` で開閉、`F` で全画面、ツールバーから pptx を
|
|
35
42
|
書き出せます。**書き方の作法は同梱 Skill の
|
|
36
43
|
`vantage-slide`** にあります(キャンバスの縦方向の予算、段階表示、トランジション、モーフ、
|
|
37
|
-
pptx
|
|
44
|
+
pptx が壊れる条件、説明と図表のデータ時点の揃え方)。
|
|
45
|
+
|
|
46
|
+
**分析を共有するデッキでは、本文・数値・図表を同じ対象期間と同じ取得時点の結果に揃え、その期間と
|
|
47
|
+
時点を短く表示する。** 説明文を固定したまま図表だけが最新値へ変わる構成にしない(ライブ更新を
|
|
48
|
+
意図するなら本文も同じ取得結果から導く)。同一時点の結果を保持できない場合は、スナップショットとして
|
|
49
|
+
保存できたとは報告せず、必要な保持の仕組みと保証できない範囲を伝える。
|
|
38
50
|
|
|
39
51
|
`.slide` を付けられるのはルートになるページモジュールだけで、`_layout.slide.tsx` などは
|
|
40
52
|
`INVALID_PAGE_VARIANT` エラーになります。`june.slide.tsx` と `june.tsx` は同じ URL に解決するので
|
package/templates/agents/xlsx.md
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
- **複数シートに対応**しています。シートのタブは下端に並び、切り替えて閲覧できます。
|
|
29
29
|
- 数式・グラフ・セル書式は再現されません(値として読めれば十分、という設計)。ブラウザでパースするので
|
|
30
30
|
25MB を超えるファイルはそのページにエラーが出ます —— 大きいデータは `server/api/` から配って
|
|
31
|
-
`DataTable`
|
|
31
|
+
`DataTable` で描いてください。20 万行を超えると先頭
|
|
32
|
+
20 万行だけが表示されます(残りはダウンロードして見る)
|
|
32
33
|
- **ビューアの無い拡張子(`.xls`・`.ods` など)はルートになりません。** `vantage check` の
|
|
33
34
|
`UNSUPPORTED_PAGE_FILE` 警告が知らせます
|
package/theme.css
CHANGED
|
@@ -397,6 +397,50 @@
|
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
+
/* Printing a document (its "Save as PDF"): only the document reaches paper.
|
|
401
|
+
Scoped with `:has()` so a dashboard prints as it did. Unlayered on purpose —
|
|
402
|
+
these must beat the app frame's Tailwind utilities (`overflow-auto`,
|
|
403
|
+
`h-svh`, `fixed`). The dark theme is dropped by `doc/print.ts`, not here. */
|
|
404
|
+
@media print {
|
|
405
|
+
:root:has([data-slot="document"]) {
|
|
406
|
+
[data-slot="document-print"],
|
|
407
|
+
[data-slot="app-shell"] > header,
|
|
408
|
+
[data-slot="sidebar"],
|
|
409
|
+
[data-slot="sidebar-gap"],
|
|
410
|
+
[data-slot="sidebar-container"] {
|
|
411
|
+
display: none;
|
|
412
|
+
}
|
|
413
|
+
body,
|
|
414
|
+
#root,
|
|
415
|
+
[data-slot="sidebar-wrapper"],
|
|
416
|
+
[data-slot="app-shell"],
|
|
417
|
+
[data-slot="app-shell"] > main {
|
|
418
|
+
height: auto;
|
|
419
|
+
min-height: 0;
|
|
420
|
+
overflow: visible;
|
|
421
|
+
background: none;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/* The page margin is zeroed by `<Document>` (an `@page` rule cannot be
|
|
425
|
+
scoped to it here), which drops the browser's date / URL header and
|
|
426
|
+
footer; this padding is the margin instead, repeated on every page. */
|
|
427
|
+
[data-slot="document"] {
|
|
428
|
+
padding: 16mm 18mm;
|
|
429
|
+
-webkit-box-decoration-break: clone;
|
|
430
|
+
box-decoration-break: clone;
|
|
431
|
+
}
|
|
432
|
+
[data-slot="document"] :where(h1, h2, h3, h4) {
|
|
433
|
+
break-after: avoid;
|
|
434
|
+
}
|
|
435
|
+
[data-slot="document"] :where(figure, img, pre, blockquote, tr) {
|
|
436
|
+
break-inside: avoid;
|
|
437
|
+
}
|
|
438
|
+
[data-slot="document"] :where(table) {
|
|
439
|
+
display: table;
|
|
440
|
+
overflow: visible;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
400
444
|
/* ------------------------------------------------------------ utilities */
|
|
401
445
|
|
|
402
446
|
@utility no-scrollbar {
|
|
@@ -418,7 +462,13 @@
|
|
|
418
462
|
body {
|
|
419
463
|
background-color: var(--background);
|
|
420
464
|
color: var(--foreground);
|
|
421
|
-
|
|
465
|
+
/* Latin system faces carry no kana/kanji, so without Japanese families here the
|
|
466
|
+
browser picks a per-locale fallback (lang="en" → e.g. thin "Yu Gothic" Regular
|
|
467
|
+
on Windows, or a face without a 500 weight on macOS) and kana render thin.
|
|
468
|
+
List the Japanese system faces explicitly, after the Latin ones. */
|
|
469
|
+
font-family:
|
|
470
|
+
ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", "Yu Gothic UI", Meiryo,
|
|
471
|
+
sans-serif;
|
|
422
472
|
-webkit-font-smoothing: antialiased;
|
|
423
473
|
}
|
|
424
474
|
|
package/dist/add-EISGSZAH.js
DELETED
package/dist/add-EISGSZAH.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"add-EISGSZAH.js"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/util.ts"],"names":[],"mappings":"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","file":"chunk-3G43C6OL.js","sourcesContent":["import fs from \"node:fs\"\nimport path from \"node:path\"\nimport pc from \"picocolors\"\nimport { PAGE_EXTENSIONS } from \"../core/constants\"\nimport type { Diagnostic } from \"../core/types\"\n\n/** Parsed CLI arguments. */\nexport interface ParsedArgs {\n positionals: string[]\n flags: Record<string, string | boolean>\n}\n\n/** Flags that never take a value, so they don't swallow the next token. */\nconst BOOLEAN_FLAGS = new Set([\n \"json\",\n \"help\",\n \"force\",\n \"verbose\",\n \"version\",\n \"all\",\n \"list\",\n \"regex\",\n \"pages\",\n \"apis\",\n \"detail\",\n \"strict-port\",\n \"no-strict-port\",\n \"overlay\",\n \"no-overlay\",\n \"h\",\n \"v\",\n])\n\n/** Minimal argv parser: `--json`, `--port 3000`, `--port=3000`, `-v`, positionals. */\nexport function parseArgs(argv: string[]): ParsedArgs {\n const positionals: string[] = []\n const flags: Record<string, string | boolean> = {}\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]!\n if (arg.startsWith(\"--\")) {\n const eq = arg.indexOf(\"=\")\n if (eq !== -1) {\n flags[arg.slice(2, eq)] = arg.slice(eq + 1)\n continue\n }\n const key = arg.slice(2)\n if (BOOLEAN_FLAGS.has(key)) {\n flags[key] = true\n continue\n }\n const next = argv[i + 1]\n if (next !== undefined && !next.startsWith(\"-\")) {\n flags[key] = next\n i++\n } else {\n flags[key] = true\n }\n } else if (arg.length > 1 && arg.startsWith(\"-\") && !/^-\\d/.test(arg)) {\n // Single-dash short flags, e.g. `-v`, `-h` (each char is a boolean).\n for (const ch of arg.slice(1)) flags[ch] = true\n } else {\n positionals.push(arg)\n }\n }\n return { positionals, flags }\n}\n\n/**\n * Apply a `--api-base-url <url>` flag by setting `process.env.PUBLIC_API_BASE_URL`\n * so Vite inlines it into the client bundle (via envPrefix). Setting it on\n * process.env gives the flag precedence over any `.env` file value. No-op when\n * the flag is absent, leaving any `.env` value in effect.\n */\nexport function applyApiBaseUrlFlag(args: ParsedArgs): void {\n const value = args.flags[\"api-base-url\"]\n if (typeof value === \"string\" && value.length) {\n process.env.PUBLIC_API_BASE_URL = value\n }\n}\n\n/** A resolved `--port`, or the reason it could not be resolved. */\nexport type PortResolution =\n | { ok: true; port: number; strictPort: boolean }\n | { ok: false; error: string }\n\n/**\n * Resolve `--port` / `--strict-port` / `--no-strict-port` into Vite's server\n * options.\n *\n * An explicit `--port` is strict by default: writing `--port 3000` means the\n * port is a contract with something outside this process — a reverse proxy, a\n * container port mapping, an OAuth redirect URI — so binding 3001 instead is a\n * silent failure, not a recovery (a supervisor that only checks \"is anything\n * listening on 3000\" will happily report a server that nobody can reach).\n * Without the flag the default is merely \"some free port\", so Vite keeps\n * walking to the next one as it always has, and running two projects at once\n * needs no ceremony. `--strict-port` / `--no-strict-port` override either way.\n *\n * A bad value is an error rather than a silent fallback, for the same reason:\n * a typo'd `--port` that quietly became 5173 is exactly the failure strictness\n * exists to prevent.\n */\nexport function resolvePortOptions(\n flags: Record<string, string | boolean>,\n fallback: number,\n): PortResolution {\n const raw = flags.port\n let port = fallback\n if (raw !== undefined) {\n if (typeof raw !== \"string\") return { ok: false, error: \"--port needs a number, e.g. --port 3000\" }\n const n = Number(raw)\n if (!Number.isInteger(n) || n < 1 || n > 65535) {\n return { ok: false, error: `Invalid --port \"${raw}\" — use an integer between 1 and 65535.` }\n }\n port = n\n }\n const strictPort = flags[\"no-strict-port\"]\n ? false\n : Boolean(flags[\"strict-port\"]) || raw !== undefined\n return { ok: true, port, strictPort }\n}\n\n/**\n * Resolve `--overlay` / `--no-overlay` into Vite's `server.hmr.overlay`.\n *\n * The overlay stays on by default — it is the fastest way for a human to see a\n * runtime error. `--no-overlay` is for the cases where a full-screen error card\n * is in the way rather than helpful: screenshots and demos, and agent-driven\n * sessions where the error already arrives in the terminal through console\n * forwarding and the overlay only obscures the page being inspected.\n */\nexport function resolveHmrOverlay(flags: Record<string, string | boolean>): boolean {\n if (flags.overlay) return true\n return !flags[\"no-overlay\"]\n}\n\n/**\n * Report a strict bind that lost the port, in the one shape dev and preview\n * share. Returns false when `err` is anything else, so the caller rethrows.\n * Vite throws a plain Error (no `code`) for this, hence the message match — a\n * reworded Vite message degrades to the generic handler, not to a wrong one.\n */\nexport function reportPortInUse(err: unknown, port: number, strictPort: boolean): boolean {\n if (!strictPort || !(err instanceof Error) || !/already in use/.test(err.message)) return false\n log.error(`Port ${port} is already in use.`)\n log.info(\" free that port, pass a different --port, or --no-strict-port to take the next one\")\n return true\n}\n\n/** Resolve the project root, honoring `--root`, defaulting to cwd. */\nexport function resolveRoot(flags: Record<string, string | boolean>): string {\n const raw = typeof flags.root === \"string\" ? flags.root : process.cwd()\n return path.resolve(raw)\n}\n\n/** How far up from a page file to look for the package root. */\nconst QUICK_ROOT_MAX_DEPTH = 5\n\n/**\n * Resolve a positional path to a quick-run project root.\n * A directory → itself; a page file (.tsx/.jsx) → its project; else null.\n */\nexport function resolveQuickRoot(target: string): string | null {\n try {\n const abs = path.resolve(target)\n const stat = fs.statSync(abs)\n if (stat.isDirectory()) return abs\n if (stat.isFile() && PAGE_EXTENSIONS.some((ext) => abs.endsWith(ext))) {\n // Walk up to the nearest package.json so `vantage ./demo/src/index.tsx`\n // starts in ./demo — the directory holding the page is not the project\n // root once pages live under src/ (or in any nested route directory).\n let dir = path.dirname(abs)\n for (let i = 0; i <= QUICK_ROOT_MAX_DEPTH; i++) {\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir\n const parent = path.dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n return path.dirname(abs)\n }\n } catch {\n // statSync throws when the path does not exist → null (not a quick target)\n }\n return null\n}\n\nexport const log = {\n info: (msg: string) => console.log(msg),\n step: (msg: string) => console.log(pc.cyan(\"→ \") + msg),\n ok: (msg: string) => console.log(pc.green(\"✓ \") + msg),\n warn: (msg: string) => console.log(pc.yellow(\"! \") + msg),\n error: (msg: string) => console.error(pc.red(\"✗ \") + msg),\n brand: (msg: string) => console.log(pc.bold(pc.magenta(\"vantage \")) + msg),\n}\n\n/** Print diagnostics as human-readable text. */\nexport function printDiagnostics(diags: Diagnostic[]): void {\n for (const d of diags) {\n const badge =\n d.severity === \"error\" ? pc.red(pc.bold(\" ERROR \")) : pc.yellow(pc.bold(\" WARN \"))\n console.log(`${badge} ${pc.dim(d.code)} ${d.message}`)\n if (d.files?.length) console.log(` ${pc.dim(\"files:\")} ${d.files.join(\", \")}`)\n if (d.fix) console.log(` ${pc.dim(\"fix:\")} ${d.fix}`)\n }\n}\n\n/** Emit a JSON payload to stdout (for agent consumption). */\nexport function printJson(payload: unknown): void {\n process.stdout.write(JSON.stringify(payload, null, 2) + \"\\n\")\n}\n\n/** Read the vantage package version. */\nexport function frameworkVersion(): string {\n try {\n // dist/cli.js (and shared chunks) live in dist/, so package.json is one up.\n const url = new URL(\"../package.json\", import.meta.url)\n const pkg = JSON.parse(fs.readFileSync(url, \"utf8\")) as { version: string }\n return pkg.version\n } catch {\n return \"0.0.0\"\n }\n}\n\nexport function fileExists(p: string): boolean {\n try {\n return fs.existsSync(p)\n } catch {\n return false\n }\n}\n"]}
|