@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
package/base-template/AGENTS.md
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
# AGENTS.md — Vantage アプリの地図
|
|
2
2
|
|
|
3
3
|
このファイルは、**Vantage(`@squadbase/vantage`)アプリを作るコーディングエージェント**が
|
|
4
|
-
最初に読むための地図です。アプリ作者(= `index.tsx` を書く側)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
>
|
|
9
|
-
>
|
|
10
|
-
>
|
|
4
|
+
最初に読むための地図です。アプリ作者(= `index.tsx` を書く側)が守るべき規約・不変条件を
|
|
5
|
+
1 ページに集約し、種類ごとの詳しいレシピは `agents/` 配下の知識ファイルに分けています。
|
|
6
|
+
|
|
7
|
+
> このファイルと `agents/*.md` は、いずれも **Vantage フレームワークが所有する正本**の
|
|
8
|
+
> コピーです。手で書き換えても、`vantage upgrade` を実行するとフレームワーク同梱の正本から
|
|
9
|
+
> 再同期されて上書きされます。アプリ固有のメモは別ファイル(例: `README.md`)に書いてください。
|
|
10
|
+
> 例外はプロジェクトルートの `DESIGN.md` で、これは**ユーザーが所有**します(`vantage upgrade` も
|
|
11
|
+
> `vantage add agents` も触らない。→「デザインの意図(DESIGN.md)」)。
|
|
11
12
|
>
|
|
12
13
|
> 手順を伴う踏み込んだワークフローは、同梱の Claude Code Skill に分かれています。このファイルは
|
|
13
|
-
>
|
|
14
|
-
>
|
|
14
|
+
> 「地図」、`agents/*.md` は「種類ごとの静的リファレンス」、Skill は「手順書」という役割分担です。
|
|
15
|
+
> **配置済みの Skill を先に探す**手順は末尾の「さらに詳しく(同梱 Skill)」にあります。
|
|
15
16
|
|
|
16
17
|
## Vantage とは
|
|
17
18
|
|
|
@@ -36,6 +37,11 @@ UI キット・開発サーバー・API サーバー・ビルドはすべて Van
|
|
|
36
37
|
- **クライアントに届く env は `PUBLIC_` 接頭辞のものだけ。** `import.meta.env.PUBLIC_FOO`。
|
|
37
38
|
それ以外を `import.meta.env` で読むと `PUBLIC_ENV_MISUSE` 警告。シークレットは
|
|
38
39
|
`ApiContext.env`(server/ 内)にだけ届く。
|
|
40
|
+
- **色はセマンティックトークンで書く。** `text-foreground`・`text-muted-foreground`・`bg-card`・
|
|
41
|
+
`border-border`。トークンがライト / ダークの両方を持つので `dark:` を並べる必要が無い。
|
|
42
|
+
素のパレット + `dark:`(`text-slate-900 dark:text-slate-100`)を混ぜると、その 1 か所だけ
|
|
43
|
+
手動で 2 モードを管理することになる(→ `agents/page.md` の「ダークモードは opt-in」)。
|
|
44
|
+
`--muted`・`--accent`・`--secondary`・`--border` は背景・境界用で、文字色に使うと読めない。
|
|
39
45
|
- **`.vantage/` と `dist/` は生成物。** 編集しない・読みにいかない(gitignore 済み)。任意の CLI
|
|
40
46
|
コマンド、または `vantage upgrade` で再生成される。
|
|
41
47
|
- **`definePage` の値はリテラルで書く。** title/description/navLabel はビルド時に静的抽出される
|
|
@@ -88,6 +94,9 @@ root/
|
|
|
88
94
|
| `@squadbase/vantage/query` | `useApiQuery`・`useApiMutation`・`apiJson`・`apiFetch`・`apiUrl`・`ApiError`、ほか `useQuery`/`useMutation` など TanStack Query の再エクスポート |
|
|
89
95
|
| `@squadbase/vantage/ui` | shadcn/ui(Base UI バリアント)プリミティブ(`Button`・`Loading`・`ErrorState`・`Empty` ほか) |
|
|
90
96
|
| `@squadbase/vantage/components` | 複合パーツ(`PageShell`・`DashboardCardPreset`・`DataTablePreset`・`EChart` ほか) |
|
|
97
|
+
| `@squadbase/vantage/table` | `FilePageView`・`TableViewer`(データファイルページの表ビューア) |
|
|
98
|
+
| `@squadbase/vantage/slide` | `SlideDeck`・`Slide`・`Steps`・`Step`・`MorphElement`・`useSlideNumber`・`useIsActiveSlide`(スライド専用。1920×1080 の固定キャンバス) |
|
|
99
|
+
| `@squadbase/vantage/doc` | `Document`(ドキュメント専用。中の素の HTML 要素に見出し・表などのスタイルが当たる) |
|
|
91
100
|
| `@squadbase/vantage/markdown` | `MarkdownRenderer`(Shiki を隔離するための専用サブパス) |
|
|
92
101
|
| `@squadbase/vantage/server` | `ApiContext`・`ApiHandler`・`HttpError`・`isHttpError`・`json`(server/ 側でのみ使う) |
|
|
93
102
|
|
|
@@ -96,207 +105,37 @@ root/
|
|
|
96
105
|
`server/` ディレクトリがあれば **fullstack**、無ければ **SPA**。`vantage-manifest.json` の
|
|
97
106
|
`mode` はここから自動で決まり、手で書く設定は無い。**SPA から始めて fullstack へ「昇格」する
|
|
98
107
|
必要はない** ― テンプレートから始めた場合は最初から `server/` があり、その時点で fullstack。
|
|
99
|
-
下の 2
|
|
100
|
-
|
|
101
|
-
- `server/` が**ある** → 「API を持つ(fullstack モード)」を見る。データは自前の `/api/*` から
|
|
102
|
-
`useApiQuery` で取る。
|
|
103
|
-
- `server/` が**無い** → 「最小アプリ(2 ファイル)」の構成。外部 API を直接叩くなら `useQuery`。
|
|
104
|
-
自前の API が要るようになったら `server/api/*.ts` を足すだけでよい(設定変更は不要)。
|
|
105
|
-
|
|
106
|
-
## 最小アプリ(2 ファイル)
|
|
107
|
-
|
|
108
|
-
`package.json` と `index.tsx` の 2 ファイルだけで動く。
|
|
109
|
-
|
|
110
|
-
`package.json`:
|
|
111
|
-
|
|
112
|
-
```json
|
|
113
|
-
{
|
|
114
|
-
"name": "my-dashboard",
|
|
115
|
-
"private": true,
|
|
116
|
-
"type": "module",
|
|
117
|
-
"scripts": {
|
|
118
|
-
"dev": "vantage dev",
|
|
119
|
-
"build": "vantage build",
|
|
120
|
-
"preview": "vantage preview",
|
|
121
|
-
"check": "vantage check",
|
|
122
|
-
"routes": "vantage routes"
|
|
123
|
-
},
|
|
124
|
-
"dependencies": {
|
|
125
|
-
"@squadbase/vantage": "^0.5.0",
|
|
126
|
-
"react": "^19.2.7",
|
|
127
|
-
"react-dom": "^19.2.7"
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
```
|
|
108
|
+
下の 2 つは段階ではなく、いま自分がどちらにいるかを確かめるための地図として読む。
|
|
131
109
|
|
|
132
|
-
`
|
|
110
|
+
- `server/` が**ある** → データは自前の `/api/*` から `useApiQuery` で取る(→ `agents/api.md`)。
|
|
111
|
+
- `server/` が**無い** → 外部 API を直接叩くなら `useQuery`(→ `agents/page.md`)。自前の API が
|
|
112
|
+
要るようになったら `server/api/*.ts` を足すだけでよい(設定変更は不要)。
|
|
133
113
|
|
|
134
|
-
|
|
135
|
-
export default function Dashboard() {
|
|
136
|
-
return (
|
|
137
|
-
<main className="p-6">
|
|
138
|
-
<h1 className="text-2xl font-semibold">Dashboard</h1>
|
|
139
|
-
</main>
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
```
|
|
114
|
+
## デザインの意図(DESIGN.md)
|
|
143
115
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
pnpm check # 静的診断(エラーがあれば exit 1)
|
|
148
|
-
pnpm routes # ページ/API の URL マップ
|
|
149
|
-
```
|
|
116
|
+
プロジェクトルートに `DESIGN.md` があれば、**UI(ページ・スライド・コンポーネント)を書く前に
|
|
117
|
+
読む。** 色・チャート・書体・レイアウトの使い分けがトークン名で書いてあるので、それに従って
|
|
118
|
+
トークンで書く(値は `styles.css` にあり、`DESIGN.md` には色コードを書かない)。
|
|
150
119
|
|
|
151
|
-
`
|
|
152
|
-
|
|
153
|
-
|
|
120
|
+
- **会話中の指示は `DESIGN.md` より優先する。** 同じ指示が繰り返されたら、`DESIGN.md` への
|
|
121
|
+
反映をユーザーに提案する。
|
|
122
|
+
- **「色を変えて」「ブランドに合わせて」などデザイン全体の変更は、ファイルごとに直さない。**
|
|
123
|
+
Skill `vantage-design` の手順で `DESIGN.md` と `styles.css` をまとめて更新する。
|
|
124
|
+
- `DESIGN.md` はユーザーの持ち物。`vantage upgrade` は書き換えない。
|
|
154
125
|
|
|
155
|
-
##
|
|
126
|
+
## 何を書くか → どのファイルを読むか
|
|
156
127
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
`MISSING_DEFAULT_EXPORT`)。以下の「ファイル」列はページルートからの相対パス。
|
|
128
|
+
**書こうとしている種類のファイルだけを開けばよい。** まず該当する 1 ファイルを readFiles で
|
|
129
|
+
読んでから書き始める。
|
|
160
130
|
|
|
161
|
-
|
|
|
131
|
+
| 書こうとしているもの | 読むファイル |
|
|
162
132
|
| --- | --- |
|
|
163
|
-
|
|
|
164
|
-
| `
|
|
165
|
-
|
|
|
166
|
-
|
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
| `_error.tsx` | ルートが throw したときのエラーページ |
|
|
170
|
-
|
|
171
|
-
`components/`・`hooks/`・`lib/`・`server/`・`public/` はどの階層でもルート走査の対象外
|
|
172
|
-
(ページにならない)。それ以外のディレクトリ名は URL のセグメントになる(→「ディレクトリ構造」)。
|
|
173
|
-
|
|
174
|
-
```tsx
|
|
175
|
-
import { definePage } from "@squadbase/vantage"
|
|
176
|
-
|
|
177
|
-
// title は document.title、navLabel は useRoutes() で組むナビの表示名(既定は title)
|
|
178
|
-
export const page = definePage({ title: "Monthly Analysis · Acme", navLabel: "Monthly" })
|
|
179
|
-
|
|
180
|
-
export default function MonthlyAnalysis() {
|
|
181
|
-
return <main className="p-6">…</main>
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
### ナビはルート一覧から組む
|
|
186
|
-
|
|
187
|
-
`useRoutes()` がページルート一覧(スキャン順)を返すので、リンク配列を手で持たない。
|
|
188
|
-
`useCurrentRoute()` は現在のルート(404 なら `undefined`)。
|
|
189
|
-
|
|
190
|
-
```tsx
|
|
191
|
-
import { Link, useCurrentRoute, useRoutes } from "@squadbase/vantage/router"
|
|
192
|
-
|
|
193
|
-
// 動的ルートは URL が定まらないので外す。label は navLabel → title → path の順
|
|
194
|
-
const routes = useRoutes().filter((r) => !r.dynamic)
|
|
195
|
-
const current = useCurrentRoute()
|
|
196
|
-
|
|
197
|
-
routes.map((r) => (
|
|
198
|
-
<Link key={r.path} to={r.to} activeClassName="font-semibold">
|
|
199
|
-
{r.label}
|
|
200
|
-
</Link>
|
|
201
|
-
))
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
`RouteInfo`: `path`(`/sales/:id`)・`to`(`/sales/$id`)・`params`・`dynamic`・`index`・`label`・
|
|
205
|
-
`title`・`description`・`navLabel`。
|
|
206
|
-
|
|
207
|
-
### フィルタ状態は URL に置く
|
|
208
|
-
|
|
209
|
-
リロードで消えず、URL をそのまま共有できる。`useState` と同じ形。
|
|
210
|
-
|
|
211
|
-
```tsx
|
|
212
|
-
import { useSearchParam, useSearchState } from "@squadbase/vantage/router"
|
|
213
|
-
|
|
214
|
-
const [region, setRegion] = useSearchParam("region", "all") // 常に string
|
|
215
|
-
const [segments, setSegments] = useSearchState<string[]>("segments", []) // JSON になる値
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
デフォルト値(または `null`)を書くとキーは URL から消える。履歴は既定で `replace`
|
|
219
|
-
(`{ replace: false }` で push)。
|
|
220
|
-
|
|
221
|
-
### 動的パラメータの「3 つの綴り」を同期させる
|
|
222
|
-
|
|
223
|
-
崩すと静かにマッチしなくなる不変条件:
|
|
224
|
-
|
|
225
|
-
- ファイル名 `sales/[customerId].tsx`
|
|
226
|
-
- 表示ルート `/sales/:customerId`
|
|
227
|
-
- リンクトークン `to="/sales/$customerId"` + `params={{ customerId }}`
|
|
228
|
-
|
|
229
|
-
```tsx
|
|
230
|
-
import { Link, useParams } from "@squadbase/vantage/router"
|
|
231
|
-
|
|
232
|
-
<Link to="/sales/$customerId" params={{ customerId: row.id }}>{row.name}</Link>
|
|
233
|
-
|
|
234
|
-
// 詳細ページ側で取り出す
|
|
235
|
-
const { customerId } = useParams()
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
## データ取得(server を持たない fetch)
|
|
239
|
-
|
|
240
|
-
外部 API を叩くだけなら `server/` は不要。`@squadbase/vantage/query` の `useQuery` を使う:
|
|
241
|
-
|
|
242
|
-
```tsx
|
|
243
|
-
import { useQuery } from "@squadbase/vantage/query"
|
|
244
|
-
import { Loading, ErrorState } from "@squadbase/vantage/ui"
|
|
245
|
-
|
|
246
|
-
const q = useQuery({ queryKey: ["stats"], queryFn: () => fetch("/…").then((r) => r.json()) })
|
|
247
|
-
if (q.isPending) return <Loading />
|
|
248
|
-
if (q.isError) return <ErrorState message={(q.error as Error).message} />
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
`QueryClient` は Vantage が 1 つだけ管理する(staleTime 30s・retry 1・
|
|
252
|
-
refetchOnWindowFocus false・networkMode "always")。挙動を変えたいときはクエリ側のオプションで
|
|
253
|
-
上書きする。
|
|
254
|
-
自分の `server/api` を叩くときは `useQuery` ではなく `useApiQuery`(→「API を持つ(fullstack
|
|
255
|
-
モード)」)。
|
|
256
|
-
|
|
257
|
-
## API を持つ(fullstack モード)
|
|
258
|
-
|
|
259
|
-
**`server/` ディレクトリがあれば fullstack モード**(無いアプリに足せば、その時点で切り替わる)。
|
|
260
|
-
`server/api/**` の各ファイルが API ルートになる。
|
|
261
|
-
|
|
262
|
-
`server/api/monthly-analysis.ts` → `GET /api/monthly-analysis`:
|
|
263
|
-
|
|
264
|
-
```ts
|
|
265
|
-
import type { ApiContext } from "@squadbase/vantage/server"
|
|
266
|
-
import { HttpError } from "@squadbase/vantage/server"
|
|
267
|
-
|
|
268
|
-
export async function GET({ params, env }: ApiContext) {
|
|
269
|
-
if (!env.API_KEY) throw new HttpError(500, "API_KEY missing")
|
|
270
|
-
return Response.json({ ok: true })
|
|
271
|
-
}
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
- API モジュールは**大文字の HTTP メソッド**(`GET`/`POST`/`PUT`/`PATCH`/`DELETE`/`OPTIONS`)を
|
|
275
|
-
エクスポートする。それ以外の名前は `INVALID_API_EXPORT` エラー。
|
|
276
|
-
- 動的 API も `[id].ts` 記法: `server/api/customers/[id].ts` → `GET /api/customers/:id`。
|
|
277
|
-
`params.id` で取り出す(`noUncheckedIndexedAccess` が効くので narrowing が要る)。
|
|
278
|
-
- **クライアントに見せたいエラーは `HttpError(status, msg)` を throw する。** それ以外の throw は
|
|
279
|
-
ログに記録され汎用の 500 に丸められる。
|
|
280
|
-
- **シークレットは `ApiContext.env` にだけ届く**(クライアントには決して届かない)。
|
|
281
|
-
|
|
282
|
-
クライアント側からは `useApiQuery` で `/api/*` を叩く。ベース URL の解決・JSON パース・
|
|
283
|
-
非 2xx の `ApiError` 化・クエリキー(`["api", url]`)が入っている:
|
|
284
|
-
|
|
285
|
-
```tsx
|
|
286
|
-
import { useApiQuery, useApiMutation } from "@squadbase/vantage/query"
|
|
287
|
-
|
|
288
|
-
const q = useApiQuery<Customer>(`/api/customers/${customerId}`)
|
|
289
|
-
if (q.isError) return <ErrorState message={q.error.message} /> // HttpError のメッセージ
|
|
290
|
-
|
|
291
|
-
// クエリ文字列は search で。undefined の項目は落ちる
|
|
292
|
-
const rows = useApiQuery<Row[]>("/api/customers", { search: { segment } })
|
|
293
|
-
|
|
294
|
-
// 書き込み。変数がそのまま JSON ボディになる
|
|
295
|
-
const save = useApiMutation<Customer, Payload>("/api/customers", { method: "POST" })
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
`ApiError` は `message`・`status`・`body`・`requestId` を持つ。hook が使えない場所では
|
|
299
|
-
`apiJson(path, init)`、生の `Response` が要るときは `apiFetch`。
|
|
133
|
+
| ダッシュボード / 通常ページ(`.tsx`) | `agents/page.md` |
|
|
134
|
+
| API(`server/`) | `agents/api.md` |
|
|
135
|
+
| スライド(`.slide.tsx`) | `agents/slide.md` |
|
|
136
|
+
| ドキュメント(`.doc.tsx`) | `agents/doc.md` |
|
|
137
|
+
| `.xlsx` ページ | `agents/xlsx.md` |
|
|
138
|
+
| `.csv` ページ | `agents/csv.md` |
|
|
300
139
|
|
|
301
140
|
## 環境変数
|
|
302
141
|
|
|
@@ -304,20 +143,6 @@ const save = useApiMutation<Customer, Payload>("/api/customers", { method: "POST
|
|
|
304
143
|
のみ。** `VITE_` 系の公開 API は無い。
|
|
305
144
|
- サーバー側のシークレットは `ApiContext.env.MY_SECRET` で読む(`server/` 内のみ)。
|
|
306
145
|
|
|
307
|
-
## 組み込み UI / コンポーネントの入口
|
|
308
|
-
|
|
309
|
-
- **プリミティブ**は `@squadbase/vantage/ui` から import する(`Button`・`Loading`・
|
|
310
|
-
`ErrorState`・`Empty`・`Select`・`Checkbox` ほか)。
|
|
311
|
-
- **複合パーツ**は `@squadbase/vantage/components` から(`PageShell`・`DashboardCardPreset`・
|
|
312
|
-
`DataTablePreset`・`EChart` ほか)。
|
|
313
|
-
- **どの名前が import 可能か / props の詳細は `vantage docs` で引く。** ガイドとコンポーネント
|
|
314
|
-
リファレンスはパッケージに同梱されていて、オフラインでも読める(→「ドキュメントを引く」)。
|
|
315
|
-
**名前が分からないとき**はやりたいことで `vantage search` する(→ 同節)。
|
|
316
|
-
- **UI は import して使うのが既定。取り出す(eject)必要はない。** `vantage add ui|block` は
|
|
317
|
-
ソースを手元にコピーして**改造したいとき専用**のコマンドで、取り出せるのは
|
|
318
|
-
`ui: data-table` と `block: sales-overview` の 2 つだけ。それ以外の名前は import 専用で
|
|
319
|
-
`add` の対象ではない(未知名で実行すると候補が一覧表示される)。
|
|
320
|
-
|
|
321
146
|
## ドキュメントを引く(`vantage docs` / `vantage search`)
|
|
322
147
|
|
|
323
148
|
```bash
|
|
@@ -363,7 +188,10 @@ body・レスポンスの status と形)まで出る。`vantage check --json` /
|
|
|
363
188
|
|
|
364
189
|
- **`vantage-app`** — アプリを一から作る / 構成を広げるときの進め方と検証の順序
|
|
365
190
|
- **`vantage-add-feature`** — 既存アプリに page / api / ui を 1 つ足す定型
|
|
191
|
+
- **`vantage-slide`** — `.slide.tsx` でスライドデッキを書く(キャンバスの予算・段階表示・pptx 書き出し)
|
|
192
|
+
- **`vantage-design`** — `DESIGN.md` と `styles.css` をまとめて作る / 直す(配色・書体・ブランド合わせ)
|
|
366
193
|
- **`vantage-pitfalls`** — Base UI(≠ Radix)の癖など、静かに壊れる落とし穴のリファレンス
|
|
194
|
+
- **`project-storage`** — Squadbase の Project Storage(アップロード済みファイル)をブラウザから読み書きする
|
|
367
195
|
|
|
368
196
|
手順書の本体は `SKILL.md` というファイルで、置き場所はアプリによって違う(ルート直下・
|
|
369
197
|
`.claude/skills/`・`.squadbase/skills/` など)。**探す必要はない ― CLI が探す:**
|
|
@@ -383,6 +211,9 @@ vantage add skill --all --dir .claude/skills # 置き場所を指定(既定は
|
|
|
383
211
|
配置済みのコピーを新しいバージョンに更新したいときだけ `--force` を付ける(見つかった場所を
|
|
384
212
|
そのまま書き換える)。
|
|
385
213
|
|
|
214
|
+
**役割分担:** Skill = 手順書(踏み込んだワークフロー) / `agents/*.md` = 種類ごとの静的
|
|
215
|
+
リファレンス / `AGENTS.md`(このファイル) = 地図。
|
|
216
|
+
|
|
386
217
|
---
|
|
387
218
|
|
|
388
219
|
# テンプレート固有の規約(Squadbase テンプレート)
|
|
@@ -391,8 +222,9 @@ vantage add skill --all --dir .claude/skills # 置き場所を指定(既定は
|
|
|
391
222
|
> フレームワーク規約と矛盾する場合は**こちらが優先**します。
|
|
392
223
|
>
|
|
393
224
|
> `vantage upgrade` はこのファイルをフレームワーク同梱の正本で丸ごと上書きするため、
|
|
394
|
-
> このセクションは消えます。消えたら squadbase-
|
|
395
|
-
>
|
|
225
|
+
> このセクションは消えます。消えたら squadbase-monorepo の
|
|
226
|
+
> `packages/vantage-template/agents/vantage/` から貼り直してください
|
|
227
|
+
> (リポジトリ側では `npm run agents` が正本と結合して再生成します)。
|
|
396
228
|
|
|
397
229
|
## Squadbase の Connection / Query からデータを読む
|
|
398
230
|
|
|
@@ -469,3 +301,51 @@ const res = await fetch(`${baseUrl}/queries/${QUERY_ID}?since=2026-01-01`, {
|
|
|
469
301
|
body: JSON.stringify({ customerId: "c_123" }),
|
|
470
302
|
})
|
|
471
303
|
```
|
|
304
|
+
|
|
305
|
+
## 構築中の一時的なエラーを「進行中」に見せる(`components/build-recovery.tsx`)
|
|
306
|
+
|
|
307
|
+
ページを書いている途中は、ファイルが書き終わる順番の都合で一瞬だけページが throw する
|
|
308
|
+
(まだ存在しないモジュールの import、書きかけのコンポーネント)。これを受け止めるのは
|
|
309
|
+
**Vantage の既定エラー画面**(`Something went wrong`)で、**テンプレートからは差し替えられない** —
|
|
310
|
+
`_error.tsx` はルートルート専用で、ページごとの `errorComponent` は現行プロトタイプでは
|
|
311
|
+
まだ結線されていない。しかも掴んでいるのは TanStack の CatchBoundary なので、HMR で
|
|
312
|
+
ソースが差し替わってもリセットされず、**リロードするまでエラー画面が貼り付く**。
|
|
313
|
+
|
|
314
|
+
`components/build-recovery.tsx` の `BuildRecovery` が、その画面を DOM から検知して
|
|
315
|
+
`Working on it…` 表示を被せ、dev では 1.2 秒待ってから自動でリロードして復帰させる
|
|
316
|
+
(上限 3 回。使い切ったら「再読み込み」の案内に降格し、無事に描けたら残数が戻る)。
|
|
317
|
+
降格した画面にはエラー本文をそのまま出し、`Copy log` でコピーできるようにしてある —
|
|
318
|
+
自力で直らないときに本文をそのまま貼り戻してもらうため。
|
|
319
|
+
`_error.tsx` も同じ `RecoveringState` を描くので、ルートレイアウトが throw したときの
|
|
320
|
+
見た目と復帰の仕方は揃っている。
|
|
321
|
+
|
|
322
|
+
### 追加の不変条件
|
|
323
|
+
|
|
324
|
+
- **`_layout.tsx` の `<BuildRecovery>` を外さない。** `<Outlet />` を包む形で 1 回だけ使う。
|
|
325
|
+
外すと、書き込み途中の一瞬のエラーが `Something went wrong` のまま残る。
|
|
326
|
+
- **`components/build-recovery.tsx` と `_error.tsx` を消さない・作り直さない。** ページ側に
|
|
327
|
+
独自のエラー UI を足す必要はない(足しても既定エラー画面より内側には入れない)。
|
|
328
|
+
- **`role="alert"` の中に `h2` を置かない。** これが既定エラー画面の目印なので、ページが
|
|
329
|
+
同じ形を描くと `BuildRecovery` が誤検知して中身を覆ってしまう。UI キットの `Alert` /
|
|
330
|
+
`ErrorState` は見出しを `div` / `p` で描くのでそのまま使ってよい。
|
|
331
|
+
- **データ取得の失敗は各ページが `ErrorState` で出す。** `BuildRecovery` が拾うのは
|
|
332
|
+
「レンダリングが throw した」場合だけで、`useApiQuery` の `isError` はページの責任
|
|
333
|
+
(→ `agents/page.md` の「データ取得」)。
|
|
334
|
+
|
|
335
|
+
## 依存の追加とスクリプトの実行は bun で
|
|
336
|
+
|
|
337
|
+
このプロジェクトの package manager は **bun** です(`squadbase.yml` の `package_manager: bun`、
|
|
338
|
+
lockfile は `bun.lock`)。Squadbase のサンドボックスは bun と依存のキャッシュを持っており、
|
|
339
|
+
`bun install` はキャッシュだけで終わります。上のフレームワーク規約に出てくる
|
|
340
|
+
`pnpm install` / `pnpm dev` / `pnpm check` は、そのまま `bun install` / `bun run dev` /
|
|
341
|
+
`bun run check` に読み替えてください。
|
|
342
|
+
|
|
343
|
+
### 追加の不変条件
|
|
344
|
+
|
|
345
|
+
- **依存を足すときは `bun add <pkg>`(開発用は `bun add -d <pkg>`)。** `npm install` や
|
|
346
|
+
`pnpm add` を使わない — `package-lock.json` / `pnpm-lock.yaml` が生えて `bun.lock` と別の断面に
|
|
347
|
+
なり、次回起動時の install が lockfile を作り直す。
|
|
348
|
+
- **`bun.lock` を消さない・手で編集しない。** `package.json` の依存を直接書き換えたときは
|
|
349
|
+
`bun install` を一度走らせて `bun.lock` を追従させ、両方を同じコミットに入れる。
|
|
350
|
+
- スクリプトは `bun run <script>`(`bun run dev` / `bun run build` / `bun run check` /
|
|
351
|
+
`bun run routes`)。`npm run <script>` でも動くが、install に npm を使わないこと。
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
DESIGN.md — このアプリの「見た目の意図」を書くファイルです。
|
|
3
|
+
|
|
4
|
+
- 実際の色・角丸・書体の値は src/styles.css にあります。ここにはトークン名(--primary など)と
|
|
5
|
+
使い分けのルールだけを書き、色コードは書きません。
|
|
6
|
+
- エージェントはページ・スライド・コンポーネントを書く前にこのファイルを読みます。
|
|
7
|
+
会話の中での指示はこのファイルより優先されます。
|
|
8
|
+
- 「このサイトに合わせて」「色を落ち着いた感じに」と頼めば、このファイルと styles.css を
|
|
9
|
+
まとめて更新します。
|
|
10
|
+
- このファイルはあなたのものです。`vantage upgrade` が書き換えることはありません。
|
|
11
|
+
-->
|
|
12
|
+
|
|
13
|
+
# デザイン
|
|
14
|
+
|
|
15
|
+
## 全体のトーン (Overview)
|
|
16
|
+
|
|
17
|
+
- 落ち着いた無彩色のベースに、データだけが色を持つ業務ダッシュボード。
|
|
18
|
+
- 装飾より読みやすさを優先する。影・グラデーション・アニメーションは最小限。
|
|
19
|
+
- 数字が主役。1 画面で伝えたいことを 1 つに絞り、補足は小さく添える。
|
|
20
|
+
- ブランド素材: なし(ロゴを使う場合は `public/brand/logo.svg` のように `public/` 配下のパスで書く)
|
|
21
|
+
|
|
22
|
+
## 色 (Colors)
|
|
23
|
+
|
|
24
|
+
色は必ずトークン(Tailwind のセマンティッククラス)で指定する。素のパレット(`bg-blue-600` など)や
|
|
25
|
+
色コードを直接書かない。
|
|
26
|
+
|
|
27
|
+
| 役割 | トークン | 使う場所 |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| 主色 (Primary) | `--primary` / `--primary-foreground` | 主要ボタン、選択中の状態。既定は無彩色 |
|
|
30
|
+
| 強調 (Accent) | `--chart-1` | 1 つだけ目立たせたい数値・系列・リンク的な強調 |
|
|
31
|
+
| 良い (Positive) | `--chart-2` | 前期比のプラスなど、良い変化の小さな印 |
|
|
32
|
+
| 悪い (Negative) | `--destructive` | 前期比のマイナス、エラー、削除操作 |
|
|
33
|
+
| 注意 (Warning) | 専用トークンなし | 文言とアイコンで示し、色は `--muted-foreground` |
|
|
34
|
+
| 背景の段階 | `--background` → `--card` → `--muted` | ページ → カード → カード内の区画・ホバー |
|
|
35
|
+
| 境界 | `--border` / `--input` / `--ring` | 罫線、入力欄、フォーカス |
|
|
36
|
+
| 文字 | `--foreground` / `--muted-foreground` | 本文 / 補足・ラベル・単位 |
|
|
37
|
+
|
|
38
|
+
- `--muted`・`--accent`・`--secondary`・`--border` は背景・境界用。文字色に使わない。
|
|
39
|
+
- 増減(▲▼・前期比)は向きで色を分ける: 増加・プラスは `--chart-2`(または `--primary`)、
|
|
40
|
+
減少・マイナスは `--destructive`。下向きの矢印やマイナスを `--primary` で塗らない。
|
|
41
|
+
- ライトとダークの両方がトークンで決まるので `dark:` を並べない。
|
|
42
|
+
|
|
43
|
+
## チャート (Charts)
|
|
44
|
+
|
|
45
|
+
- 系列の順番は `--chart-1` → `--chart-2` → `--chart-3` → `--chart-4` → `--chart-5`
|
|
46
|
+
(現在はプリセット `blue`: 青 → ティール → フクシア → バイオレット → グレー)。
|
|
47
|
+
- 1 系列だけを目立たせるときは、その系列を `--chart-1`、残りをすべて `--chart-5`(グレー)にする。
|
|
48
|
+
- 良い / 悪いを色で塗り分けるときは `--chart-2` / `--destructive`。色だけに頼らず ▲▼ や符号も添える。
|
|
49
|
+
- 系列は 5 つまで。それ以上はグループ化するか「その他」にまとめる。
|
|
50
|
+
- 禁止: 同じチャートで `--destructive` を普通の系列色として使う(悪い値に見える)。
|
|
51
|
+
- 禁止: 隣り合う系列に `--chart-3` と `--chart-4` を並べて細い線で描く(見分けにくい)。
|
|
52
|
+
- 配色を丸ごと変えるときは `npx @squadbase/vantage-template chart <preset>` を使う
|
|
53
|
+
(`blue` / `ocean` / `sunset` / `forest` / `berry` / `mono`)。
|
|
54
|
+
|
|
55
|
+
## 書体 (Typography)
|
|
56
|
+
|
|
57
|
+
| 用途 | 指定 | 備考 |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| 見出し・本文 | システムフォント(`body` の `font-family`) | Web フォントは使わない |
|
|
60
|
+
| 数字 | 同上 + `tabular-nums` | 桁がそろうように必ず付ける |
|
|
61
|
+
| スライドの見出し | `--slide-font-display` | 既定は日本語を含むシステムフォント |
|
|
62
|
+
| スライドの本文 | `--slide-font-body` | 既定は見出しと同じ |
|
|
63
|
+
|
|
64
|
+
サイズの段階(ダッシュボード):
|
|
65
|
+
|
|
66
|
+
- ページ見出し: `text-2xl font-bold`
|
|
67
|
+
- カード見出し・ラベル: `text-sm font-medium text-muted-foreground`
|
|
68
|
+
- KPI の数値: `text-3xl font-semibold tabular-nums`
|
|
69
|
+
- 本文・表: `text-sm`
|
|
70
|
+
- 注釈・出典: `text-xs text-muted-foreground`
|
|
71
|
+
|
|
72
|
+
スライドのサイズは `--slide-size-hero`(表紙・大きな数字)と `--slide-size-body`(本文)を基準にする。
|
|
73
|
+
|
|
74
|
+
## レイアウトと密度 (Layout)
|
|
75
|
+
|
|
76
|
+
- 情報はカード(`bg-card` + `border-border`)で区切る。角丸は `--radius` に従う(個別に変えない)。
|
|
77
|
+
- グリッドの間隔は `gap-4`。セクション間は `gap-6` 程度。
|
|
78
|
+
- KPI は 1 行に 2〜4 枚。その下にチャート、最後に明細の表。
|
|
79
|
+
- 密度は「中」。余白を削って詰め込むより、ページを分ける。
|
|
80
|
+
|
|
81
|
+
## 成果物の種類ごとの規則 (Per-artifact)
|
|
82
|
+
|
|
83
|
+
### ダッシュボード
|
|
84
|
+
|
|
85
|
+
- 先頭に KPI カード、次にトレンドのチャート、最後に明細の表。
|
|
86
|
+
- 各 KPI には比較対象(前月比・目標比など)を 1 つ添える。
|
|
87
|
+
- チャートのタイトルは結論を書く(「売上推移」より「売上は 3 か月連続で増加」)。
|
|
88
|
+
|
|
89
|
+
### スライド
|
|
90
|
+
|
|
91
|
+
- 1 枚に 1 メッセージ。見出しに結論を書く。
|
|
92
|
+
- 色は `--slide-bg` / `--slide-fg` / `--slide-accent` / `--slide-muted` を使う
|
|
93
|
+
(既定では `--background` / `--foreground` / `--primary` / `--muted-foreground` に連動)。
|
|
94
|
+
- 強調色は 1 枚につき 1 か所まで。
|
|
95
|
+
|
|
96
|
+
## Do / Don't
|
|
97
|
+
|
|
98
|
+
Do:
|
|
99
|
+
|
|
100
|
+
- トークンと Tailwind のセマンティッククラスで色を指定する。
|
|
101
|
+
- 数値には単位と比較対象を付ける。
|
|
102
|
+
- 色の意味(良い / 悪い / 強調)をアプリ全体でそろえる。
|
|
103
|
+
|
|
104
|
+
Don't:
|
|
105
|
+
|
|
106
|
+
- 色コードや素のパレットクラスを直接書く。
|
|
107
|
+
- 1 画面で強調色を何か所にも使う。
|
|
108
|
+
- 3D チャート・円グラフの多用・装飾目的のグラデーション。
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# API(server/)
|
|
2
|
+
|
|
3
|
+
フレームワーク所有の知識ファイルで、`vantage upgrade` で再同期されます。`server/api/**`
|
|
4
|
+
に API ルートを書くときに読んでください。不変条件・ディレクトリ構造は `AGENTS.md` を
|
|
5
|
+
先に読んでいる想定です。
|
|
6
|
+
|
|
7
|
+
## API を持つ(fullstack モード)
|
|
8
|
+
|
|
9
|
+
**`server/` ディレクトリがあれば fullstack モード**(無いアプリに足せば、その時点で切り替わる)。
|
|
10
|
+
`server/api/**` の各ファイルが API ルートになる。
|
|
11
|
+
|
|
12
|
+
`server/api/monthly-analysis.ts` → `GET /api/monthly-analysis`:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import type { ApiContext } from "@squadbase/vantage/server"
|
|
16
|
+
import { HttpError } from "@squadbase/vantage/server"
|
|
17
|
+
|
|
18
|
+
export async function GET({ params, env }: ApiContext) {
|
|
19
|
+
if (!env.API_KEY) throw new HttpError(500, "API_KEY missing")
|
|
20
|
+
return Response.json({ ok: true })
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- API モジュールは**大文字の HTTP メソッド**(`GET`/`POST`/`PUT`/`PATCH`/`DELETE`/`OPTIONS`)を
|
|
25
|
+
エクスポートする。それ以外の名前は `INVALID_API_EXPORT` エラー。
|
|
26
|
+
- 動的 API も `[id].ts` 記法: `server/api/customers/[id].ts` → `GET /api/customers/:id`。
|
|
27
|
+
`params.id` で取り出す(`noUncheckedIndexedAccess` が効くので narrowing が要る)。
|
|
28
|
+
- **クライアントに見せたいエラーは `HttpError(status, msg)` を throw する。** それ以外の throw は
|
|
29
|
+
ログに記録され汎用の 500 に丸められる。
|
|
30
|
+
- **シークレットは `ApiContext.env` にだけ届く**(クライアントには決して届かない)。
|
|
31
|
+
|
|
32
|
+
クライアント側からは `useApiQuery` で `/api/*` を叩く。ベース URL の解決・JSON パース・
|
|
33
|
+
非 2xx の `ApiError` 化・クエリキー(`["api", url]`)が入っている:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { useApiQuery, useApiMutation } from "@squadbase/vantage/query"
|
|
37
|
+
|
|
38
|
+
const q = useApiQuery<Customer>(`/api/customers/${customerId}`)
|
|
39
|
+
if (q.isError) return <ErrorState message={q.error.message} /> // HttpError のメッセージ
|
|
40
|
+
|
|
41
|
+
// クエリ文字列は search で。undefined の項目は落ちる
|
|
42
|
+
const rows = useApiQuery<Row[]>("/api/customers", { search: { segment } })
|
|
43
|
+
|
|
44
|
+
// 書き込み。変数がそのまま JSON ボディになる
|
|
45
|
+
const save = useApiMutation<Customer, Payload>("/api/customers", { method: "POST" })
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`ApiError` は `message`・`status`・`body`・`requestId` を持つ。hook が使えない場所では
|
|
49
|
+
`apiJson(path, init)`、生の `Response` が要るときは `apiFetch`。
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# csv ページ
|
|
2
|
+
|
|
3
|
+
フレームワーク所有の知識ファイルで、`vantage upgrade` で再同期されます。`.csv` を
|
|
4
|
+
ページとして置くときに読んでください。不変条件・ディレクトリ構造は `AGENTS.md` を
|
|
5
|
+
先に読んでいる想定です。
|
|
6
|
+
|
|
7
|
+
## `.csv` を置くだけでページになる
|
|
8
|
+
|
|
9
|
+
**`.csv` を `src/` に置くだけで、他のページと同格のルートになります。** URL の作り方は
|
|
10
|
+
`.tsx` と同じ(`src/sales-export.csv` → `/sales-export`、`index.csv` はそのディレクトリ)で、
|
|
11
|
+
ナビにも `vantage routes` にも並びます。開くとフレームワーク同梱の表ビューアが描き、
|
|
12
|
+
元ファイルをダウンロードできます。ビューアは**表計算ソフトの見た目**です —— 列は A / B / C、
|
|
13
|
+
左に行番号、ファイルの 1 行目はヘッダとして固定。読み取り専用で、編集もソートもできません
|
|
14
|
+
(セルを選んで `Cmd/Ctrl+C` でコピーは可)。
|
|
15
|
+
|
|
16
|
+
- **タイトルはファイル名から導かれる**(`sales-export.csv` → 「Sales Export」)。データファイルに
|
|
17
|
+
`definePage` は書けません。名前を変えたいときはファイルをリネームします
|
|
18
|
+
- **ページにしたくないファイルは `_` を前置する**(`_sales-export.csv`)。`components/`・`hooks/`・
|
|
19
|
+
`lib/` に置いたものも同じくページになりません
|
|
20
|
+
- **既定はファイルをそのまま置く(tsx を書かない)。** 自分でタイトルや説明を付けたいときだけ、`_` を
|
|
21
|
+
前置してルート化を止め、tsx から描きます:
|
|
22
|
+
```tsx
|
|
23
|
+
import { FilePageView } from "@squadbase/vantage/table"
|
|
24
|
+
import src from "./_sales-export.csv?url&no-inline"
|
|
25
|
+
export const page = definePage({ title: "売上エクスポート" })
|
|
26
|
+
export default () => <FilePageView src={src} kind="csv" fileName="sales-export.csv" />
|
|
27
|
+
```
|
|
28
|
+
- 数式・グラフ・セル書式といった概念は csv には無いので、値がそのまま読めます。ブラウザで
|
|
29
|
+
パースするので 25MB を超えるファイルはそのページにエラーが出ます —— 大きいデータは
|
|
30
|
+
`server/api/` から配って `DataTable` で描いてください
|
|
31
|
+
- **ビューアの無い拡張子(`.tsv` など)はルートになりません。** `vantage check` の
|
|
32
|
+
`UNSUPPORTED_PAGE_FILE` 警告が知らせます
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ドキュメント(.doc.tsx)
|
|
2
|
+
|
|
3
|
+
フレームワーク所有の知識ファイルで、`vantage upgrade` で再同期されます。`.doc.tsx` で
|
|
4
|
+
ドキュメントを書くときに読んでください。不変条件・ディレクトリ構造は `AGENTS.md` を
|
|
5
|
+
先に読んでいる想定です。
|
|
6
|
+
|
|
7
|
+
## ドキュメントは `.doc.tsx` で書く
|
|
8
|
+
|
|
9
|
+
`src/june-summary.doc.tsx` → `/june-summary`。上から下へ読む文章のページで、表やチャートを
|
|
10
|
+
文中に置けます。中身は `<Document>` を返す普通の React コンポーネントで、`definePage` もナビも
|
|
11
|
+
通常のページと同じように効きます。
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { definePage } from "@squadbase/vantage"
|
|
15
|
+
import { EChart } from "@squadbase/vantage/components"
|
|
16
|
+
import { Document } from "@squadbase/vantage/doc"
|
|
17
|
+
|
|
18
|
+
export const page = definePage({ title: "6月度サマリー", navLabel: "6月度サマリー" })
|
|
19
|
+
export default function JuneSummary() {
|
|
20
|
+
return (
|
|
21
|
+
<Document>
|
|
22
|
+
<h1>6月度サマリー</h1>
|
|
23
|
+
<p>6月の売上は <strong>5,250 万円</strong>で、目標を 5% 上回りました。</p>
|
|
24
|
+
<h2>週次の売上</h2>
|
|
25
|
+
<figure>
|
|
26
|
+
<EChart option={option} height={280} ariaLabel="6月の週次売上" />
|
|
27
|
+
<figcaption>第4週はキャンペーン初週</figcaption>
|
|
28
|
+
</figure>
|
|
29
|
+
<table>…</table>
|
|
30
|
+
</Document>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 書き方
|
|
36
|
+
|
|
37
|
+
- **素の HTML 要素で書く。** `<Document>` の中の `h1`〜`h4`・`p`・`ul`/`ol`/`li`・`table`・
|
|
38
|
+
`blockquote`・`pre`/`code`・`hr`・`a`・`figure`/`figcaption`・`img` には、見出しの大きさ・余白・
|
|
39
|
+
罫線などが最初から当たっています。クラスは要りません。
|
|
40
|
+
- **Tailwind のユーティリティは、その要素だけ見た目を変えたいときに使う。** 要素の既定の
|
|
41
|
+
スタイルはユーティリティより弱いので、`className` を付ければそちらが勝ちます。ドキュメント全体の
|
|
42
|
+
見た目を変えたいときはユーティリティを並べず、下の `--doc-*` を変えます。
|
|
43
|
+
- **数値はコードに直接書く。** ドキュメントは書いた時点の内容を残すページです。
|
|
44
|
+
`useApiQuery` などで読み込むと、開くたびに値が変わります。
|
|
45
|
+
- **チャートは `EChart`(`@squadbase/vantage/components`)を文中に置く。** `figure` で囲めば
|
|
46
|
+
`figcaption` がキャプションになります。
|
|
47
|
+
- **ページ全体を包むのは `<Document>` だけ。** `PageShell` などのダッシュボード用の枠で包まない
|
|
48
|
+
(本文の幅と余白は `<Document>` が決めます)。
|
|
49
|
+
|
|
50
|
+
## 見た目を変える
|
|
51
|
+
|
|
52
|
+
配色・書体・本文の幅は `--doc-*` の CSS 変数です。既定値はアプリのトークンへの別名なので、
|
|
53
|
+
ダークモードにもそのまま追従します。
|
|
54
|
+
|
|
55
|
+
| 変数 | 既定値 | 何に効くか |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| `--doc-fg` | `var(--foreground)` | 本文の文字色 |
|
|
58
|
+
| `--doc-muted` | `var(--muted-foreground)` | 引用・キャプション |
|
|
59
|
+
| `--doc-accent` | `var(--primary)` | リンク |
|
|
60
|
+
| `--doc-border` | `var(--border)` | 表・`h2` の下線・引用・`hr` |
|
|
61
|
+
| `--doc-subtle` | `var(--muted)` | コード・表の見出し行の背景 |
|
|
62
|
+
| `--doc-font-body` / `--doc-font-heading` / `--doc-font-mono` | アプリの書体 | 本文 / 見出し / コード |
|
|
63
|
+
| `--doc-size-body` | `1rem` | 本文の文字サイズ(見出しはこれに比例) |
|
|
64
|
+
| `--doc-line-height` | `1.8` | 本文の行間 |
|
|
65
|
+
| `--doc-max-width` | `48rem` | 本文の幅 |
|
|
66
|
+
|
|
67
|
+
アプリのすべてのドキュメントに効かせるなら `styles.css` の `:root` で定義し直します。1 つの
|
|
68
|
+
ドキュメントだけなら `<Document theme={{ accent: "#2563eb", maxWidth: "56rem" }}>` のように
|
|
69
|
+
`theme` で渡します(`theme` のキーは変数名から `--doc-` を外してキャメルケースにしたもの)。
|
|
70
|
+
|
|
71
|
+
`.doc` を付けられるのはルートになるページモジュールだけで、`_layout.doc.tsx` などは
|
|
72
|
+
`INVALID_PAGE_VARIANT` エラーになります。`june.doc.tsx` と `june.tsx` は同じ URL に解決するので
|
|
73
|
+
`ROUTE_CONFLICT` です。
|