@squadbase/vantage-template 0.0.2 → 0.1.0-dev.3f759a0
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 +9 -7
- package/base-template/.squadbase/skills/project-storage/SKILL.md +157 -0
- package/base-template/.squadbase/skills/vantage-app/SKILL.md +6 -6
- package/base-template/.squadbase/skills/vantage-design/SKILL.md +137 -0
- package/base-template/.squadbase/skills/vantage-design/references/extract.md +110 -0
- package/base-template/.squadbase/skills/vantage-design/references/format.md +172 -0
- package/base-template/.squadbase/skills/vantage-design/references/presets.md +110 -0
- package/base-template/.squadbase/skills/vantage-design/scripts/contrast.mjs +166 -0
- package/base-template/.squadbase/skills/vantage-pitfalls/SKILL.md +22 -0
- package/base-template/AGENTS.md +98 -218
- package/base-template/DESIGN.md +108 -0
- package/base-template/agents/api.md +49 -0
- package/base-template/agents/csv.md +32 -0
- package/base-template/agents/doc.md +73 -0
- package/base-template/agents/page.md +187 -0
- package/base-template/agents/slide.md +41 -0
- package/base-template/agents/xlsx.md +33 -0
- package/base-template/automations/.gitkeep +0 -0
- package/base-template/bun.lock +907 -0
- package/base-template/package.json +3 -3
- package/base-template/pipelines/pyproject.toml +5 -0
- package/base-template/squadbase.yml +1 -0
- package/base-template/src/_error.tsx +7 -11
- package/base-template/src/_layout.tsx +8 -1
- package/base-template/src/components/build-recovery.tsx +219 -0
- package/base-template/src/index.tsx +53 -8
- package/base-template/src/styles.css +19 -0
- package/dist/index.js +16 -7
- package/package.json +18 -12
- package/ui-templates/chart-grid/pages/index.tsx +1 -1
- package/ui-templates/chart-grid/preview-square.png +0 -0
- package/ui-templates/chart-grid/preview-wide.png +0 -0
- package/ui-templates/chart-grid-ja/pages/index.tsx +1 -1
- package/ui-templates/chart-grid-ja/preview-square.png +0 -0
- package/ui-templates/chart-grid-ja/preview-wide.png +0 -0
- package/ui-templates/funnel/pages/index.tsx +2 -2
- package/ui-templates/funnel/preview-square.png +0 -0
- package/ui-templates/funnel/preview-wide.png +0 -0
- package/ui-templates/funnel-ja/pages/index.tsx +2 -2
- package/ui-templates/funnel-ja/preview-square.png +0 -0
- package/ui-templates/funnel-ja/preview-wide.png +0 -0
- package/ui-templates/kpi-chart-advanced/preview-square.png +0 -0
- package/ui-templates/kpi-chart-advanced/preview-wide.png +0 -0
- package/ui-templates/kpi-chart-advanced-ja/preview-square.png +0 -0
- package/ui-templates/kpi-chart-advanced-ja/preview-wide.png +0 -0
- package/ui-templates/kpi-chart-simple/preview-square.png +0 -0
- package/ui-templates/kpi-chart-simple/preview-wide.png +0 -0
- package/ui-templates/kpi-chart-simple-ja/preview-square.png +0 -0
- package/ui-templates/kpi-chart-simple-ja/preview-wide.png +0 -0
- package/ui-templates/table-focus/preview-square.png +0 -0
- package/ui-templates/table-focus/preview-wide.png +0 -0
- package/ui-templates/table-focus-ja/preview-square.png +0 -0
- package/ui-templates/table-focus-ja/preview-wide.png +0 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# ダッシュボード / 通常ページ(.tsx)
|
|
2
|
+
|
|
3
|
+
フレームワーク所有の知識ファイルで、`vantage upgrade` で再同期されます。`.tsx` の通常ページ
|
|
4
|
+
(ダッシュボード)を書くときに読んでください。前提となる不変条件・ディレクトリ構造は
|
|
5
|
+
`AGENTS.md` を先に読んでいる想定です。
|
|
6
|
+
|
|
7
|
+
プロジェクトルートに `DESIGN.md` があれば、書き始める前に読んで配色・書体・レイアウトの規則に従う。
|
|
8
|
+
|
|
9
|
+
## 最小アプリ(2 ファイル)
|
|
10
|
+
|
|
11
|
+
`package.json` と `index.tsx` の 2 ファイルだけで動く。
|
|
12
|
+
|
|
13
|
+
`package.json`:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"name": "my-dashboard",
|
|
18
|
+
"private": true,
|
|
19
|
+
"type": "module",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"dev": "vantage dev",
|
|
22
|
+
"build": "vantage build",
|
|
23
|
+
"preview": "vantage preview",
|
|
24
|
+
"check": "vantage check",
|
|
25
|
+
"routes": "vantage routes"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@squadbase/vantage": "^0.5.0",
|
|
29
|
+
"react": "^19.2.7",
|
|
30
|
+
"react-dom": "^19.2.7"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`index.tsx`(ルートのデフォルトエクスポートが `/` ページになる):
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
export default function Dashboard() {
|
|
39
|
+
return (
|
|
40
|
+
<main className="p-6">
|
|
41
|
+
<h1 className="text-2xl font-semibold">Dashboard</h1>
|
|
42
|
+
</main>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pnpm install
|
|
49
|
+
pnpm dev # → http://localhost:5173(HMR)
|
|
50
|
+
pnpm check # 静的診断(エラーがあれば exit 1)
|
|
51
|
+
pnpm routes # ページ/API の URL マップ
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`server/` ディレクトリが無いので、この構成は **SPA モード**。ページを直下に置く形だが、
|
|
55
|
+
`src/` を作ってその中に集めてもよい(テンプレートから始めた場合は最初から `src/` がある)。
|
|
56
|
+
どちらか一方に寄せること(→ `AGENTS.md` の「ディレクトリ構造」)。
|
|
57
|
+
|
|
58
|
+
## ルーティング規約(ファイル名 → ルート)
|
|
59
|
+
|
|
60
|
+
ページルート(`src/` があればその中、無ければプロジェクトルート)からの相対パスが、そのまま
|
|
61
|
+
URL になる。各ページは**デフォルトエクスポートの React コンポーネントが必須**(無いと
|
|
62
|
+
`MISSING_DEFAULT_EXPORT`)。以下の「ファイル」列はページルートからの相対パス。
|
|
63
|
+
|
|
64
|
+
| ファイル | ルート |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `index.tsx` | `/` |
|
|
67
|
+
| `monthly-analysis.tsx` | `/monthly-analysis` |
|
|
68
|
+
| `sales/index.tsx` | `/sales` |
|
|
69
|
+
| `sales/[customerId].tsx` | `/sales/:customerId`(動的パラメータ) |
|
|
70
|
+
| `_layout.tsx` | そのディレクトリ配下を包むネストレイアウト(`Outlet` で子を描く) |
|
|
71
|
+
| `_404.tsx` | Not Found ページ |
|
|
72
|
+
| `_error.tsx` | ルートが throw したときのエラーページ |
|
|
73
|
+
| `monthly-report.slide.tsx` | `/monthly-report`(スライドデッキ。詳しくは `agents/slide.md`) |
|
|
74
|
+
| `sales-export.csv` | `/sales-export`(詳しくは `agents/csv.md`) |
|
|
75
|
+
| `data/june.xlsx` | `/data/june`(詳しくは `agents/xlsx.md`) |
|
|
76
|
+
|
|
77
|
+
`components/`・`hooks/`・`lib/`・`server/`・`public/` はどの階層でもルート走査の対象外
|
|
78
|
+
(ページにならない)。それ以外のディレクトリ名は URL のセグメントになる(→ `AGENTS.md` の
|
|
79
|
+
「ディレクトリ構造」)。
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { definePage } from "@squadbase/vantage"
|
|
83
|
+
|
|
84
|
+
// title は document.title、navLabel は useRoutes() で組むナビの表示名(既定は title)
|
|
85
|
+
export const page = definePage({ title: "Monthly Analysis · Acme", navLabel: "Monthly" })
|
|
86
|
+
|
|
87
|
+
export default function MonthlyAnalysis() {
|
|
88
|
+
return <main className="p-6">…</main>
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### ナビはルート一覧から組む
|
|
93
|
+
|
|
94
|
+
`useRoutes()` がページルート一覧(スキャン順)を返すので、リンク配列を手で持たない。
|
|
95
|
+
`useCurrentRoute()` は現在のルート(404 なら `undefined`)。
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { Link, useCurrentRoute, useRoutes } from "@squadbase/vantage/router"
|
|
99
|
+
|
|
100
|
+
// 動的ルートは URL が定まらないので外す。label は navLabel → title → path の順
|
|
101
|
+
const routes = useRoutes().filter((r) => !r.dynamic)
|
|
102
|
+
const current = useCurrentRoute()
|
|
103
|
+
|
|
104
|
+
routes.map((r) => (
|
|
105
|
+
<Link key={r.path} to={r.to} activeClassName="font-semibold">
|
|
106
|
+
{r.label}
|
|
107
|
+
</Link>
|
|
108
|
+
))
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`RouteInfo`: `path`(`/sales/:id`)・`to`(`/sales/$id`)・`params`・`dynamic`・`index`・`label`・
|
|
112
|
+
`title`・`description`・`navLabel`・`kind`(`"module"` | `"file"`)・`variant`(`"slide"`)。
|
|
113
|
+
後ろの 2 つで、ナビをダッシュボード / スライド / データに分けたりアイコンを変えたりできます。
|
|
114
|
+
|
|
115
|
+
### フィルタ状態は URL に置く
|
|
116
|
+
|
|
117
|
+
リロードで消えず、URL をそのまま共有できる。`useState` と同じ形。
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { useSearchParam, useSearchState } from "@squadbase/vantage/router"
|
|
121
|
+
|
|
122
|
+
const [region, setRegion] = useSearchParam("region", "all") // 常に string
|
|
123
|
+
const [segments, setSegments] = useSearchState<string[]>("segments", []) // JSON になる値
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
デフォルト値(または `null`)を書くとキーは URL から消える。履歴は既定で `replace`
|
|
127
|
+
(`{ replace: false }` で push)。
|
|
128
|
+
|
|
129
|
+
### 動的パラメータの「3 つの綴り」を同期させる
|
|
130
|
+
|
|
131
|
+
崩すと静かにマッチしなくなる不変条件:
|
|
132
|
+
|
|
133
|
+
- ファイル名 `sales/[customerId].tsx`
|
|
134
|
+
- 表示ルート `/sales/:customerId`
|
|
135
|
+
- リンクトークン `to="/sales/$customerId"` + `params={{ customerId }}`
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
import { Link, useParams } from "@squadbase/vantage/router"
|
|
139
|
+
|
|
140
|
+
<Link to="/sales/$customerId" params={{ customerId: row.id }}>{row.name}</Link>
|
|
141
|
+
|
|
142
|
+
// 詳細ページ側で取り出す
|
|
143
|
+
const { customerId } = useParams()
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## データ取得(server を持たない fetch)
|
|
147
|
+
|
|
148
|
+
外部 API を叩くだけなら `server/` は不要。`@squadbase/vantage/query` の `useQuery` を使う:
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import { useQuery } from "@squadbase/vantage/query"
|
|
152
|
+
import { Loading, ErrorState } from "@squadbase/vantage/ui"
|
|
153
|
+
|
|
154
|
+
const q = useQuery({ queryKey: ["stats"], queryFn: () => fetch("/…").then((r) => r.json()) })
|
|
155
|
+
if (q.isPending) return <Loading />
|
|
156
|
+
if (q.isError) return <ErrorState message={(q.error as Error).message} />
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`QueryClient` は Vantage が 1 つだけ管理する(staleTime 30s・retry 1・
|
|
160
|
+
refetchOnWindowFocus false・networkMode "always")。挙動を変えたいときはクエリ側のオプションで
|
|
161
|
+
上書きする。
|
|
162
|
+
自分の `server/api` を叩くときは `useQuery` ではなく `useApiQuery`(→ `agents/api.md`)。
|
|
163
|
+
|
|
164
|
+
## 組み込み UI / コンポーネントの入口
|
|
165
|
+
|
|
166
|
+
- **プリミティブ**は `@squadbase/vantage/ui` から import する(`Button`・`Loading`・
|
|
167
|
+
`ErrorState`・`Empty`・`Select`・`Checkbox` ほか)。
|
|
168
|
+
- **複合パーツ**は `@squadbase/vantage/components` から(`PageShell`・`DashboardCardPreset`・
|
|
169
|
+
`DataTablePreset`・`EChart` ほか)。
|
|
170
|
+
- **どの名前が import 可能か / props の詳細は `vantage docs` で引く。** ガイドとコンポーネント
|
|
171
|
+
リファレンスはパッケージに同梱されていて、オフラインでも読める(→ `AGENTS.md` の
|
|
172
|
+
「ドキュメントを引く」)。**名前が分からないとき**はやりたいことで `vantage search` する
|
|
173
|
+
(→ 同節)。
|
|
174
|
+
- **UI は import して使うのが既定。取り出す(eject)必要はない。** `vantage add ui|block` は
|
|
175
|
+
ソースを手元にコピーして**改造したいとき専用**のコマンドで、取り出せるのは
|
|
176
|
+
`ui: data-table` と `block: sales-overview` の 2 つだけ。それ以外の名前は import 専用で
|
|
177
|
+
`add` の対象ではない(未知名で実行すると候補が一覧表示される)。
|
|
178
|
+
|
|
179
|
+
### ダークモードは opt-in
|
|
180
|
+
|
|
181
|
+
ダークのトークンが効くのは、祖先に `.dark` か `[data-theme="dark"]` が付いているときだけ。
|
|
182
|
+
**OS / ブラウザの設定(`prefers-color-scheme`)は見ない。** `dark:` ユーティリティも同じ
|
|
183
|
+
スイッチに繋いであるので(`theme.css` の `@custom-variant dark`)、自分でクラスを付けない限り
|
|
184
|
+
アプリは常にライトで描かれる ― `dark:` を書いてもそこだけダークになることはない。
|
|
185
|
+
|
|
186
|
+
明暗を切り替えたいときは、レイアウトのルート要素などに `.dark` / `data-theme="dark"` を
|
|
187
|
+
自分で付ける。
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# スライド(.slide.tsx)
|
|
2
|
+
|
|
3
|
+
フレームワーク所有の知識ファイルで、`vantage upgrade` で再同期されます。`.slide.tsx` で
|
|
4
|
+
スライドデッキを書くときに読んでください。不変条件・ディレクトリ構造は `AGENTS.md` を
|
|
5
|
+
先に読んでいる想定です。
|
|
6
|
+
|
|
7
|
+
プロジェクトルートに `DESIGN.md` があれば、書き始める前に読んで「スライド」の節と配色・書体の規則に従う。
|
|
8
|
+
|
|
9
|
+
## スライドは `.slide.tsx` で書く
|
|
10
|
+
|
|
11
|
+
`src/monthly-report.slide.tsx` → `/monthly-report`。中身は `<SlideDeck>` を返す普通の React
|
|
12
|
+
コンポーネントで、`definePage` もナビも通常のページと同じように効きます。
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Slide, SlideDeck } from "@squadbase/vantage/slide"
|
|
16
|
+
|
|
17
|
+
export const page = definePage({ title: "6月度レビュー", navLabel: "6月度" })
|
|
18
|
+
export default function Deck() {
|
|
19
|
+
return (
|
|
20
|
+
<SlideDeck>
|
|
21
|
+
<Slide>…</Slide>
|
|
22
|
+
<Slide>…</Slide>
|
|
23
|
+
</SlideDeck>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**`<Slide>` は `<SlideDeck>` の直接の子に書く。** `SlideDeck` は直下の `<Slide>` 要素だけを数えるので、
|
|
29
|
+
`<Slide>` を自作コンポーネント(`<Slide1 />` など)や Fragment で包むと 1 枚も数えられず「1 / 0」に
|
|
30
|
+
なります(`{items.map((x) => <Slide key={x.id}>…</Slide>)}` のような配列は可)。共通の部品は
|
|
31
|
+
`<Slide>` の**中**に置くコンポーネントとして切り出します(`<Slide><CoverPage /></Slide>`)。
|
|
32
|
+
|
|
33
|
+
1920×1080 の固定キャンバスに絶対 px で書き、画面サイズに合わせて縮小されます。キー / クリックで
|
|
34
|
+
送れ、左のスライド一覧(サムネイル列)は `L` で開閉、`F` で全画面、ツールバーから pptx を
|
|
35
|
+
書き出せます。**書き方の作法は同梱 Skill の
|
|
36
|
+
`vantage-slide`** にあります(キャンバスの縦方向の予算、段階表示、トランジション、モーフ、
|
|
37
|
+
pptx が壊れる条件)。
|
|
38
|
+
|
|
39
|
+
`.slide` を付けられるのはルートになるページモジュールだけで、`_layout.slide.tsx` などは
|
|
40
|
+
`INVALID_PAGE_VARIANT` エラーになります。`june.slide.tsx` と `june.tsx` は同じ URL に解決するので
|
|
41
|
+
`ROUTE_CONFLICT` です。
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# xlsx ページ
|
|
2
|
+
|
|
3
|
+
フレームワーク所有の知識ファイルで、`vantage upgrade` で再同期されます。`.xlsx` を
|
|
4
|
+
ページとして置くときに読んでください。不変条件・ディレクトリ構造は `AGENTS.md` を
|
|
5
|
+
先に読んでいる想定です。
|
|
6
|
+
|
|
7
|
+
## `.xlsx` を置くだけでページになる
|
|
8
|
+
|
|
9
|
+
**`.xlsx` を `src/` に置くだけで、他のページと同格のルートになります。** URL の作り方は
|
|
10
|
+
`.tsx` と同じ(`src/data/june.xlsx` → `/data/june`、`index.xlsx` はそのディレクトリ)で、
|
|
11
|
+
ナビにも `vantage routes` にも並びます。開くとフレームワーク同梱の表ビューアが描き、複数シートを
|
|
12
|
+
切り替えられ、元ファイルをダウンロードできます。ビューアは**表計算ソフトの見た目**です ——
|
|
13
|
+
列は A / B / C、左に行番号、ファイルの 1 行目はヘッダとして固定、シートのタブは下端。
|
|
14
|
+
読み取り専用で、編集もソートもできません(セルを選んで `Cmd/Ctrl+C` でコピーは可)。
|
|
15
|
+
|
|
16
|
+
- **タイトルはファイル名から導かれる**(`june.xlsx` → 「June」)。データファイルに `definePage` は
|
|
17
|
+
書けません。名前を変えたいときはファイルをリネームします
|
|
18
|
+
- **ページにしたくないファイルは `_` を前置する**(`_june.xlsx`)。`components/`・`hooks/`・`lib/` に
|
|
19
|
+
置いたものも同じくページになりません
|
|
20
|
+
- **既定はファイルをそのまま置く(tsx を書かない)。** 自分でタイトルや説明を付けたいときだけ、`_` を
|
|
21
|
+
前置してルート化を止め、tsx から描きます:
|
|
22
|
+
```tsx
|
|
23
|
+
import { FilePageView } from "@squadbase/vantage/table"
|
|
24
|
+
import src from "./_june.xlsx?url&no-inline"
|
|
25
|
+
export const page = definePage({ title: "6月度 売上レポート" })
|
|
26
|
+
export default () => <FilePageView src={src} kind="xlsx" fileName="june.xlsx" />
|
|
27
|
+
```
|
|
28
|
+
- **複数シートに対応**しています。シートのタブは下端に並び、切り替えて閲覧できます。
|
|
29
|
+
- 数式・グラフ・セル書式は再現されません(値として読めれば十分、という設計)。ブラウザでパースするので
|
|
30
|
+
25MB を超えるファイルはそのページにエラーが出ます —— 大きいデータは `server/api/` から配って
|
|
31
|
+
`DataTable` で描いてください
|
|
32
|
+
- **ビューアの無い拡張子(`.xls`・`.ods` など)はルートになりません。** `vantage check` の
|
|
33
|
+
`UNSUPPORTED_PAGE_FILE` 警告が知らせます
|
|
File without changes
|