@squadbase/vantage-template 0.2.0-dev1.d2f1bf0 → 0.2.0-dev1.d8420c4
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/base-template/AGENTS.md +3 -3
- package/base-template/agents/page.md +5 -4
- package/base-template/bun.lock +4 -4
- package/base-template/package.json +2 -2
- package/package.json +2 -2
- package/ui-templates/CLAUDE.md +13 -12
- package/ui-templates/chart-grid/lib/mock-data.ts +0 -3
- package/ui-templates/chart-grid/lib/types.ts +6 -6
- package/ui-templates/chart-grid/pages/index.tsx +11 -161
- package/ui-templates/chart-grid-ja/lib/mock-data.ts +0 -3
- package/ui-templates/chart-grid-ja/lib/types.ts +6 -6
- package/ui-templates/chart-grid-ja/pages/index.tsx +11 -161
- package/ui-templates/funnel/lib/types.ts +2 -2
- package/ui-templates/funnel/pages/index.tsx +10 -88
- package/ui-templates/funnel-ja/lib/types.ts +2 -2
- package/ui-templates/funnel-ja/pages/index.tsx +10 -87
- package/ui-templates/kpi-chart-advanced/lib/mock-data.ts +6 -6
- package/ui-templates/kpi-chart-advanced/lib/types.ts +6 -7
- package/ui-templates/kpi-chart-advanced/pages/index.tsx +6 -117
- package/ui-templates/kpi-chart-advanced-ja/lib/mock-data.ts +6 -6
- package/ui-templates/kpi-chart-advanced-ja/lib/types.ts +6 -7
- package/ui-templates/kpi-chart-advanced-ja/pages/index.tsx +6 -117
- package/ui-templates/kpi-chart-simple/lib/types.ts +4 -4
- package/ui-templates/kpi-chart-simple/pages/index.tsx +4 -42
- package/ui-templates/kpi-chart-simple-ja/lib/types.ts +4 -4
- package/ui-templates/kpi-chart-simple-ja/pages/index.tsx +4 -40
- package/ui-templates/table-focus/lib/types.ts +3 -3
- package/ui-templates/table-focus/pages/index.tsx +3 -45
- package/ui-templates/table-focus-ja/lib/types.ts +3 -3
- package/ui-templates/table-focus-ja/pages/index.tsx +3 -45
package/base-template/AGENTS.md
CHANGED
|
@@ -96,7 +96,7 @@ root/
|
|
|
96
96
|
| `@squadbase/vantage/router` | `Link`・`Outlet`・`useParams`・`useSearch`・`useNavigate`・`redirect`・`notFound`・`useRoutes`・`useCurrentRoute`・`useSearchParam`・`useSearchState` |
|
|
97
97
|
| `@squadbase/vantage/query` | `useApiQuery`・`useApiMutation`・`apiJson`・`apiFetch`・`apiUrl`・`ApiError`、ほか `useQuery`/`useMutation` など TanStack Query の再エクスポート |
|
|
98
98
|
| `@squadbase/vantage/ui` | shadcn/ui(Base UI バリアント)プリミティブ(`Button`・`Loading`・`ErrorState`・`Empty` ほか) |
|
|
99
|
-
| `@squadbase/vantage/components` | 複合パーツ(`PageShell`・`DashboardCardPreset`・`DataTablePreset`、KPI の `KpiCard`・`Delta`、型付きチャート `LineChart`・`BarChart`・`AreaChart`・`DonutChart`・`BarList`
|
|
99
|
+
| `@squadbase/vantage/components` | 複合パーツ(`PageShell`・`DashboardCardPreset`・`DataTablePreset`、KPI の `KpiCard`・`Delta`、型付きチャート `LineChart`・`BarChart`・`AreaChart`・`ScatterChart`・`Heatmap`・`DonutChart`・`FunnelSteps`・`BarList` ほか、表せないときだけ `EChart`、書式の `formatValue`) |
|
|
100
100
|
| `@squadbase/vantage/table` | `FilePageView`・`TableViewer`(データファイルページの表ビューア) |
|
|
101
101
|
| `@squadbase/vantage/slide` | `SlideDeck`・`Slide`・`Steps`・`Step`・`MorphElement`・`useSlideNumber`・`useIsActiveSlide`、1 枚分の block `SlideCover`・`SlideExecSummary`・`SlideKpiHero`・`SlideKpiGrid`・`SlideChartInsight`・`SlideScorecardTable`・`SlideNextActions`・`SlideSection`・`SlideComparison`・`SlideChartFull`、手書きの 1 枚に使う部品 `SlideHeading`・`SlideSourceLine`・`SlideColumns`・`SlideColumn`・`DeltaText`(スライド専用。1920×1080 の固定キャンバス) |
|
|
102
102
|
| `@squadbase/vantage/doc` | `Document`、ドキュメント用の block `DocReportHeader`・`DocExecutiveSummary`・`DocKpiScorecard`・`DocFigure`・`DocDataTable`・`DocCallout`・`DocKeyFindings`・`DocActionItems`・`DocNotesAndSources`、部品 `DeltaText`(ドキュメント専用。中の素の HTML 要素に見出し・表などのスタイルが当たる) |
|
|
@@ -137,7 +137,7 @@ import { KpiCard, Delta } from "@squadbase/vantage/components";
|
|
|
137
137
|
まとめる)。増減の良否は指標の性質(コスト減・解約率減は良い)で決めて
|
|
138
138
|
positive / negative に分け(`KpiCard` / `Delta` の `betterWhen`。下がって良い指標は `betterWhen="down"`)、向きは ▲▼ や符号で表す。
|
|
139
139
|
- **レイアウト:** 内容はカードで包む(ページのチャートはタイトル付きの `DashboardCardPreset` に入れる。
|
|
140
|
-
|
|
140
|
+
チャートは親の幅に追従する)。順序は KPI → チャート → 表。値が 1 つなら KPI にする
|
|
141
141
|
(1 本の棒グラフにしない)。強調は 1 画面(スライドは 1 枚)に 1 か所。数値には単位と比較対象を添える。
|
|
142
142
|
- **Do:** トークンで色を指定する / 色の意味をアプリ全体でそろえる / チャートのタイトルに結論を書く。
|
|
143
143
|
- **Don't:** 色コードや素のパレットクラスを書く / `dark:` を並べる / 3D・装飾目的のグラデーション・
|
|
@@ -242,7 +242,7 @@ vantage add skill # 同梱 skill の一覧と、それぞれの配置
|
|
|
242
242
|
|
|
243
243
|
```bash
|
|
244
244
|
vantage add skill --all # 配置済みはスキップ(場所を報告するだけ)
|
|
245
|
-
vantage add skill --all --dir .
|
|
245
|
+
vantage add skill --all --dir .squadbase/skills # 置き場所を指定(既定は `.squadbase/` があれば `.squadbase/skills`、無ければ配置済みの Skill と同じ場所、それも無ければルート直下)
|
|
246
246
|
```
|
|
247
247
|
|
|
248
248
|
`add skill` はプロジェクト内を走査してから動くので、**再実行しても二重に配置されない**。
|
|
@@ -224,7 +224,7 @@ refetchOnWindowFocus false・networkMode "always")。挙動を変えたいとき
|
|
|
224
224
|
`ErrorState`・`Empty`・`Select`・`Checkbox`・`RadioGroup`・`Field`・`Combobox`・`Pagination`・
|
|
225
225
|
`Avatar`・`Kbd`・`HoverCard`・`AlertDialog`・`Drawer`・`Toaster` + `toast.add()` ほか)。
|
|
226
226
|
- **複合パーツ**は `@squadbase/vantage/components` から(`PageShell`・`DashboardCardPreset`・
|
|
227
|
-
`DataTablePreset`・型付きチャート(下の「グラフ」)
|
|
227
|
+
`DataTablePreset`・型付きチャート(下の「グラフ」)ほか)。
|
|
228
228
|
- **どの名前が import 可能か / props の詳細は `vantage docs` で引く。** ガイドとコンポーネント
|
|
229
229
|
リファレンスはパッケージに同梱されていて、オフラインでも読める(→ `AGENTS.md` の
|
|
230
230
|
「ドキュメントを引く」)。**名前が分からないとき**はやりたいことで `vantage search` する
|
|
@@ -246,13 +246,14 @@ refetchOnWindowFocus false・networkMode "always")。挙動を変えたいとき
|
|
|
246
246
|
|
|
247
247
|
### グラフはまず型付きチャートで描く
|
|
248
248
|
|
|
249
|
-
- 推移は `LineChart` / `AreaChart`、比較は `BarChart
|
|
249
|
+
- 推移は `LineChart` / `AreaChart`、比較は `BarChart`、相関は `ScatterChart`、2 軸の濃淡は `Heatmap`、
|
|
250
|
+
構成比は `DonutChart`、段階ごとの減少は `FunnelSteps`。`data`(行の配列)・
|
|
250
251
|
`index`(x 軸の列)・`categories`(系列の列)を渡すだけで、option は書かない
|
|
251
252
|
(`DonutChart` は `category` / `value`)。
|
|
252
253
|
- 上位 N 件は `BarList`、判定帯や予算消化は `CategoryBar`、達成率は `ProgressCircle`、
|
|
253
254
|
日ごとの状態は `Tracker`。
|
|
254
|
-
- `EChart` + `
|
|
255
|
-
|
|
255
|
+
- `EChart` + option 関数は、レーダーなど型付きチャートで表せないときだけ使う。`EChart` で組んだ
|
|
256
|
+
グラフは、あとから種類もデータも編集で変えられない。
|
|
256
257
|
- 色は省略してテーマトークンに任せる。指定するなら `"chart-1"`〜`"chart-5"` か
|
|
257
258
|
`"var(--destructive)"` などの CSS 色。hex の直書きや Tailwind クラスは使わない。
|
|
258
259
|
- 数値の書式(`¥`・`%`・桁区切り)は `valueFormatter` に渡す。
|
package/base-template/bun.lock
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"name": "vibe-app",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@squadbase/react": "^0.1.0",
|
|
9
|
-
"@squadbase/vantage": "0.7.
|
|
10
|
-
"@squadbase/vantage-sdk": "0.1.2-dev1.
|
|
9
|
+
"@squadbase/vantage": "0.7.1-dev1.cee9cbf",
|
|
10
|
+
"@squadbase/vantage-sdk": "0.1.2-dev1.cbfdf19",
|
|
11
11
|
"date-fns": "^4.1.0",
|
|
12
12
|
"lucide-react": "^0.468.0",
|
|
13
13
|
"react": "^19.3.1",
|
|
@@ -196,9 +196,9 @@
|
|
|
196
196
|
|
|
197
197
|
"@squadbase/react": ["@squadbase/react@0.1.0", "", { "dependencies": { "zod": "^4.3.6" }, "peerDependencies": { "@types/react": "17.x || 18.x || 19.x", "react": "17.x || 18.x || 19.x" }, "optionalPeers": ["@types/react"] }, "sha512-k+Dpyj7eH+Yjydw54iEluCjYDae086d12hWgBjNMpw4wLbQGz3CrJ6Yipodg8n1cKUt7zvwddlcTHd79bgKsXg=="],
|
|
198
198
|
|
|
199
|
-
"@squadbase/vantage": ["@squadbase/vantage@0.7.
|
|
199
|
+
"@squadbase/vantage": ["@squadbase/vantage@0.7.1-dev1.cee9cbf", "", { "dependencies": { "@base-ui/react": "^1.6.0", "@hono/node-server": "^2.1.5", "@streamdown/code": "^1.1.1", "@tailwindcss/vite": "^4.3.3", "@tanstack/react-query": "^5.101.2", "@tanstack/react-router": "^1.170.17", "@tanstack/react-table": "^8.21.3", "@vitejs/plugin-react": "^6.1.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", "echarts": "^6.0.0", "esbuild": "0.28.1", "fflate": "^0.8.3", "hono": "^4.13.13", "html-to-image": "^1.11.13", "lucide-react": "^0.468.0", "papaparse": "^5.7.0", "picocolors": "^1.1.1", "react-day-picker": "^10.0.1", "read-excel-file": "^9.3.10", "shiki": "3.23.0", "streamdown": "^2.5.0", "tailwind-merge": "3.6.0", "tailwindcss": "^4.3.3", "tw-animate-css": "^1.0.0", "vite": "^8.3.4" }, "peerDependencies": { "react": ">=18.2.0", "react-dom": ">=18.2.0", "typescript": ">=5.0.0" }, "optionalPeers": ["typescript"], "bin": { "vantage": "dist/cli.js" } }, "sha512-Ppv+cNd/gYr7W5W54tInGAK6xiMsJCooKSL8ZICjpXgA4bNDGdAoyUFaDYJEwW5cSSSp9oG0SCqKqhDAQFsLtg=="],
|
|
200
200
|
|
|
201
|
-
"@squadbase/vantage-sdk": ["@squadbase/vantage-sdk@0.1.2-dev1.
|
|
201
|
+
"@squadbase/vantage-sdk": ["@squadbase/vantage-sdk@0.1.2-dev1.cbfdf19", "", {}, "sha512-4MIM7HfbzAX/ra2JZ5BFrWQ2ipLagax6uh6Ca+/qLn5W0UlSMyRY8Fthzz4QLRah4j0G8AhdXC9B71cWCbJoag=="],
|
|
202
202
|
|
|
203
203
|
"@streamdown/code": ["@streamdown/code@1.1.1", "", { "dependencies": { "shiki": "^3.19.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-i7HTNuDgZWb+VdrNVOam9gQhIc5MSSDXKWXgbUrn/4vSRaSMM+Rtl10MQj4wLWPNpF7p80waJsAqFP8HZfb0Jg=="],
|
|
204
204
|
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@squadbase/react": "^0.1.0",
|
|
15
|
-
"@squadbase/vantage": "0.7.
|
|
16
|
-
"@squadbase/vantage-sdk": "0.1.2-dev1.
|
|
15
|
+
"@squadbase/vantage": "0.7.1-dev1.cee9cbf",
|
|
16
|
+
"@squadbase/vantage-sdk": "0.1.2-dev1.cbfdf19",
|
|
17
17
|
"date-fns": "^4.1.0",
|
|
18
18
|
"lucide-react": "^0.468.0",
|
|
19
19
|
"react": "^19.3.1",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squadbase/vantage-template",
|
|
3
|
-
"version": "0.2.0-dev1.
|
|
3
|
+
"version": "0.2.0-dev1.d8420c4",
|
|
4
4
|
"description": "CLI tool for initializing and customizing Squadbase Vantage projects.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"squadbase",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@ai-sdk/openai": "2.0.122",
|
|
51
51
|
"ai": "^5.0.52"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "d8420c42a10798dd9a714385c64a4aa07f7c724e",
|
|
54
54
|
"scripts": {
|
|
55
55
|
"sync-base": "rsync -a --delete --exclude='node_modules' --exclude='dist' --exclude='.vantage' --exclude='*.tsbuildinfo' --exclude='*.log' template/ base-template/ && mv base-template/.gitignore base-template/_gitignore",
|
|
56
56
|
"build": "pnpm run sync-base && tsup",
|
package/ui-templates/CLAUDE.md
CHANGED
|
@@ -40,22 +40,23 @@ src/components/<slug>/
|
|
|
40
40
|
|
|
41
41
|
**`components/` を使う理由(重要)**: Vantage は**ファイルベースルーティング**で、`.tsx` ファイルは原則すべてページ扱いになる。`components/` / `hooks/` / `lib/` / `server/` / `public/` だけがルート走査から除外される(`NON_ROUTE_DIRS`)ため、`src/templates/<slug>/` のようなディレクトリに `.tsx` を置くと **`/templates/<slug>/...` という意図しないルートが生え、`vantage check` が `MISSING_DEFAULT_EXPORT` で落ちる**(`SUSPICIOUS_ROUTE_DIR` 警告も出る)。データファイル(`.ts`)も同じディレクトリに置いてコロケーションを保つ。
|
|
42
42
|
|
|
43
|
-
### 2.
|
|
43
|
+
### 2. チャートは型付き部品で書く — EChart + option 関数は作らない
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
**折れ線 / 面 / 棒 / 散布図 / ヒートマップ / ドーナツ / ファネルは、カタログ部品(`LineChart` / `AreaChart` / `BarChart` / `ScatterChart` / `Heatmap` / `DonutChart` / `FunnelSteps`)に行配列とキー名を渡して書く。** 行配列は識別子(`mock-data.ts` の配列、または `index.tsx` 内で一度だけ作る `const xxxRows`)で渡す。JSX の prop に `.map(...)` や option 関数の呼び出しを書かない(Bluetree がチャートを部品として読めなくなる)。
|
|
46
46
|
|
|
47
47
|
```tsx
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
<AreaChart
|
|
49
|
+
data={timeSeries}
|
|
50
|
+
index="date"
|
|
51
|
+
categories={["series1", "series2"]}
|
|
52
|
+
labels={{ series1: "Series A", series2: "Series B" }}
|
|
53
|
+
height="280px"
|
|
54
|
+
/>
|
|
54
55
|
```
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
- データ型は `interface` ではなく `type` で宣言する(部品の `data` は `Record<string, unknown>[]` を要求し、`interface` は代入できない)。
|
|
58
|
+
- 部品が表せない表現(第2軸の折れ線の重ね描き、`visualMap` など)のために `EChart` + option 関数へ戻さない。**カタログに部品が無いチャート(現状はレーダーだけ)に限り**、`index.tsx` 内のオプションビルダ関数 + `<EChart option={...} />` で書く。
|
|
59
|
+
- 色は書かない。部品も `EChart` も `--chart-1..5` に追従するので、`option.color` / `itemStyle.color` / ラベルの `color` / `theme` プロップは使わない。意味色(成功=緑・失敗=赤)が要る series だけ例外。
|
|
59
60
|
|
|
60
61
|
### 3. データ層(mock-data / types)は分離する
|
|
61
62
|
|
|
@@ -97,7 +98,7 @@ server/api/<endpoint>.ts # ★ サンプルデータ + GET ハ
|
|
|
97
98
|
| `PageShell*` / `DashboardCard*` / `EChart` / `EChartsOption` / `DataTable*` / `ColumnDef` / `DateRangePicker` / `FilterBar*` / `FunnelSteps` / `MetricValue` / `TrendIndicator` / `StatusBadge` / `SegmentedControl` / `MultiSelect` / `SearchableSelect` / `SectionHeader` / `AppShell` / `Placeholder` / `Sparkline` | `@squadbase/vantage/components` |
|
|
98
99
|
| `Button` / `Input` / `Badge` / `Tabs*` / `ToggleGroup*` / `Table*` / `Select*` / `Dialog*` / `cn` ほか shadcn プリミティブ | `@squadbase/vantage/ui` |
|
|
99
100
|
|
|
100
|
-
型付きチャート(`LineChart` / `AreaChart` / `BarChart` / `DonutChart` / `BarList` / `CategoryBar` / `ProgressCircle` / `Tracker`、`@squadbase/vantage/components`)
|
|
101
|
+
型付きチャート(`LineChart` / `AreaChart` / `BarChart` / `ScatterChart` / `Heatmap` / `DonutChart` / `FunnelSteps` / `BarList` / `CategoryBar` / `ProgressCircle` / `Tracker`、`@squadbase/vantage/components`)は 0.6.3 以降の部品。雛形の依存は `^0.7.0` なので使ってよい。`Avatar` / `Pagination` / `RadioGroup` / `AlertDialog` / `Drawer` / `Toaster` / `Field` / `Combobox` / `HoverCard` / `Kbd`(`@squadbase/vantage/ui`)も同じ。
|
|
101
102
|
| `definePage` | `@squadbase/vantage` |
|
|
102
103
|
| `Link` / `Outlet` / `useParams` / `useSearch` / `useNavigate` / `useRoutes` / `useCurrentRoute` / `useSearchParam` / `useSearchState` | `@squadbase/vantage/router` |
|
|
103
104
|
| `useApiQuery` / `useApiMutation` / `useQuery` / `useMutation` / `apiFetch` | `@squadbase/vantage/query` |
|
|
@@ -90,9 +90,6 @@ export const radarAxes: RadarPoint[] = [
|
|
|
90
90
|
{ current: 79, benchmark: 70 },
|
|
91
91
|
]
|
|
92
92
|
|
|
93
|
-
export const HEATMAP_X_AXIS = ["0", "1", "2", "3", "4", "5"]
|
|
94
|
-
export const HEATMAP_Y_AXIS = ["Row 1", "Row 2", "Row 3", "Row 4", "Row 5", "Row 6", "Row 7"]
|
|
95
|
-
|
|
96
93
|
export const heatmapCells: HeatmapCell[] = [
|
|
97
94
|
{ x: "0", y: "Row 1", value: 57 },
|
|
98
95
|
{ x: "1", y: "Row 1", value: 25 },
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type TimePoint = {
|
|
2
2
|
date: string
|
|
3
3
|
series1: number
|
|
4
4
|
series2: number
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export
|
|
7
|
+
export type BarPoint = {
|
|
8
8
|
value: number
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export
|
|
11
|
+
export type ScatterPoint = {
|
|
12
12
|
x: number
|
|
13
13
|
y: number
|
|
14
14
|
size: number
|
|
15
15
|
label: string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export
|
|
18
|
+
export type RadarPoint = {
|
|
19
19
|
current: number
|
|
20
20
|
benchmark: number
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export
|
|
23
|
+
export type HeatmapCell = {
|
|
24
24
|
x: string
|
|
25
25
|
y: string
|
|
26
26
|
value: number
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export
|
|
29
|
+
export type DashboardFilters = {
|
|
30
30
|
dateRange: { from: Date | undefined; to: Date | undefined }
|
|
31
31
|
}
|
|
@@ -3,6 +3,11 @@ import { subDays } from "date-fns"
|
|
|
3
3
|
import { definePage } from "@squadbase/vantage"
|
|
4
4
|
import {
|
|
5
5
|
DashboardCardPreset,
|
|
6
|
+
AreaChart,
|
|
7
|
+
BarChart,
|
|
8
|
+
Heatmap,
|
|
9
|
+
LineChart,
|
|
10
|
+
ScatterChart,
|
|
6
11
|
DateRangePicker,
|
|
7
12
|
EChart,
|
|
8
13
|
PageShell,
|
|
@@ -22,15 +27,9 @@ import {
|
|
|
22
27
|
scatterPoints,
|
|
23
28
|
radarAxes,
|
|
24
29
|
heatmapCells,
|
|
25
|
-
HEATMAP_X_AXIS,
|
|
26
|
-
HEATMAP_Y_AXIS,
|
|
27
30
|
} from "./components/chart-grid/mock-data"
|
|
28
31
|
import type {
|
|
29
|
-
TimePoint,
|
|
30
|
-
BarPoint,
|
|
31
|
-
ScatterPoint,
|
|
32
32
|
RadarPoint,
|
|
33
|
-
HeatmapCell,
|
|
34
33
|
DashboardFilters,
|
|
35
34
|
} from "./components/chart-grid/types"
|
|
36
35
|
|
|
@@ -40,86 +39,6 @@ export const page = definePage({
|
|
|
40
39
|
"Six-chart grid (area, line, bar, scatter, radar, heatmap) with category filter chips in the header.",
|
|
41
40
|
})
|
|
42
41
|
|
|
43
|
-
// ── chart helpers ───────────────────────────────────────────────────────────
|
|
44
|
-
|
|
45
|
-
function getBaseGrid() {
|
|
46
|
-
return { left: "3%", right: "4%", bottom: "10%", containLabel: true }
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function formatNumber(n: number): string {
|
|
50
|
-
const sign = n < 0 ? "-" : ""
|
|
51
|
-
const abs = Math.abs(n)
|
|
52
|
-
if (abs >= 1_000_000) return `${sign}${(abs / 1_000_000).toFixed(1)}M`
|
|
53
|
-
if (abs >= 1_000) return `${sign}${(abs / 1_000).toFixed(1)}K`
|
|
54
|
-
return n.toLocaleString("en-US")
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// ── chart options ────────────────────────────────────────────────────────────
|
|
58
|
-
|
|
59
|
-
function areaOption(data: TimePoint[]): EChartsOption {
|
|
60
|
-
return {
|
|
61
|
-
tooltip: { trigger: "axis" },
|
|
62
|
-
legend: { bottom: 0 },
|
|
63
|
-
grid: getBaseGrid(),
|
|
64
|
-
xAxis: {
|
|
65
|
-
type: "category",
|
|
66
|
-
data: data.map((d) => d.date),
|
|
67
|
-
boundaryGap: false,
|
|
68
|
-
axisLabel: { formatter: (v: string) => v.slice(5) },
|
|
69
|
-
},
|
|
70
|
-
yAxis: { type: "value", axisLabel: { formatter: (v: number) => formatNumber(v) } },
|
|
71
|
-
series: [
|
|
72
|
-
{
|
|
73
|
-
name: "Series A",
|
|
74
|
-
type: "line",
|
|
75
|
-
smooth: true,
|
|
76
|
-
showSymbol: false,
|
|
77
|
-
data: data.map((d) => d.series1),
|
|
78
|
-
areaStyle: { opacity: 0.22 },
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
name: "Series B",
|
|
82
|
-
type: "line",
|
|
83
|
-
smooth: true,
|
|
84
|
-
showSymbol: false,
|
|
85
|
-
data: data.map((d) => d.series2),
|
|
86
|
-
areaStyle: { opacity: 0.14 },
|
|
87
|
-
},
|
|
88
|
-
],
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function lineOption(data: TimePoint[]): EChartsOption {
|
|
93
|
-
return {
|
|
94
|
-
tooltip: { trigger: "axis" },
|
|
95
|
-
legend: { bottom: 0 },
|
|
96
|
-
grid: getBaseGrid(),
|
|
97
|
-
xAxis: {
|
|
98
|
-
type: "category",
|
|
99
|
-
data: data.map((d) => d.date),
|
|
100
|
-
boundaryGap: false,
|
|
101
|
-
axisLabel: { formatter: (v: string) => v.slice(5) },
|
|
102
|
-
},
|
|
103
|
-
yAxis: { type: "value", axisLabel: { formatter: (v: number) => formatNumber(v) } },
|
|
104
|
-
series: [
|
|
105
|
-
{
|
|
106
|
-
name: "Series A",
|
|
107
|
-
type: "line",
|
|
108
|
-
smooth: true,
|
|
109
|
-
showSymbol: false,
|
|
110
|
-
data: data.map((d) => d.series1),
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
name: "Series B",
|
|
114
|
-
type: "line",
|
|
115
|
-
smooth: true,
|
|
116
|
-
showSymbol: false,
|
|
117
|
-
data: data.map((d) => d.series2),
|
|
118
|
-
},
|
|
119
|
-
],
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
42
|
const BAR_CATEGORIES = [
|
|
124
43
|
"Item 1",
|
|
125
44
|
"Item 2",
|
|
@@ -131,45 +50,6 @@ const BAR_CATEGORIES = [
|
|
|
131
50
|
"Item 8",
|
|
132
51
|
]
|
|
133
52
|
|
|
134
|
-
function barOption(data: BarPoint[]): EChartsOption {
|
|
135
|
-
return {
|
|
136
|
-
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
|
|
137
|
-
grid: getBaseGrid(),
|
|
138
|
-
xAxis: { type: "category", data: BAR_CATEGORIES },
|
|
139
|
-
yAxis: { type: "value", axisLabel: { formatter: (v: number) => formatNumber(v) } },
|
|
140
|
-
series: [
|
|
141
|
-
{
|
|
142
|
-
name: "Series A",
|
|
143
|
-
type: "bar",
|
|
144
|
-
data: data.map((d) => d.value),
|
|
145
|
-
barMaxWidth: 28,
|
|
146
|
-
},
|
|
147
|
-
],
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function scatterOption(data: ScatterPoint[]): EChartsOption {
|
|
152
|
-
return {
|
|
153
|
-
tooltip: { trigger: "item" },
|
|
154
|
-
grid: getBaseGrid(),
|
|
155
|
-
xAxis: { type: "value" },
|
|
156
|
-
yAxis: { type: "value" },
|
|
157
|
-
series: [
|
|
158
|
-
{
|
|
159
|
-
type: "scatter",
|
|
160
|
-
data: data.map((p) => ({
|
|
161
|
-
value: [p.x, p.y, p.size] as [number, number, number],
|
|
162
|
-
label: p.label,
|
|
163
|
-
})),
|
|
164
|
-
symbolSize: (val: unknown) => {
|
|
165
|
-
const arr = val as [number, number, number]
|
|
166
|
-
return arr[2]
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
] as EChartsOption["series"],
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
53
|
const RADAR_AXES = ["Axis 1", "Axis 2", "Axis 3", "Axis 4", "Axis 5", "Axis 6"]
|
|
174
54
|
|
|
175
55
|
function radarOption(data: RadarPoint[]): EChartsOption {
|
|
@@ -200,34 +80,7 @@ function radarOption(data: RadarPoint[]): EChartsOption {
|
|
|
200
80
|
}
|
|
201
81
|
}
|
|
202
82
|
|
|
203
|
-
|
|
204
|
-
data: HeatmapCell[],
|
|
205
|
-
xAxis: string[],
|
|
206
|
-
yAxis: string[],
|
|
207
|
-
): EChartsOption {
|
|
208
|
-
const max = Math.max(...data.map((c) => c.value))
|
|
209
|
-
return {
|
|
210
|
-
tooltip: { position: "top" },
|
|
211
|
-
grid: { height: "70%", top: "8%", left: "10%", right: "8%" },
|
|
212
|
-
xAxis: { type: "category", data: xAxis, splitArea: { show: true } },
|
|
213
|
-
yAxis: { type: "category", data: yAxis, splitArea: { show: true } },
|
|
214
|
-
visualMap: {
|
|
215
|
-
min: 0,
|
|
216
|
-
max,
|
|
217
|
-
calculable: true,
|
|
218
|
-
orient: "horizontal",
|
|
219
|
-
bottom: 0,
|
|
220
|
-
},
|
|
221
|
-
series: [
|
|
222
|
-
{
|
|
223
|
-
type: "heatmap",
|
|
224
|
-
data: data.map((c) => [xAxis.indexOf(c.x), yAxis.indexOf(c.y), c.value]),
|
|
225
|
-
label: { show: false },
|
|
226
|
-
emphasis: { itemStyle: { shadowBlur: 8 } },
|
|
227
|
-
},
|
|
228
|
-
],
|
|
229
|
-
}
|
|
230
|
-
}
|
|
83
|
+
const barRows = barSeries.map((d, i) => ({ item: BAR_CATEGORIES[i], value: d.value }))
|
|
231
84
|
|
|
232
85
|
// ── page ─────────────────────────────────────────────────────────────────────
|
|
233
86
|
|
|
@@ -290,7 +143,7 @@ export default function HomePage() {
|
|
|
290
143
|
title="Trend (area)"
|
|
291
144
|
description="Two series over the selected period"
|
|
292
145
|
>
|
|
293
|
-
<
|
|
146
|
+
<AreaChart data={timeSeries} index="date" categories={["series1", "series2"]} labels={{ series1: "Series A", series2: "Series B" }} height="280px" />
|
|
294
147
|
</DashboardCardPreset>
|
|
295
148
|
)}
|
|
296
149
|
{show("trend") && (
|
|
@@ -298,17 +151,17 @@ export default function HomePage() {
|
|
|
298
151
|
title="Trend (line)"
|
|
299
152
|
description="Two series over the selected period"
|
|
300
153
|
>
|
|
301
|
-
<
|
|
154
|
+
<LineChart data={timeSeries} index="date" categories={["series1", "series2"]} labels={{ series1: "Series A", series2: "Series B" }} height="280px" />
|
|
302
155
|
</DashboardCardPreset>
|
|
303
156
|
)}
|
|
304
157
|
{show("ranking") && (
|
|
305
158
|
<DashboardCardPreset title="Top categories" description="Ranked by value">
|
|
306
|
-
<
|
|
159
|
+
<BarChart data={barRows} index="item" categories={["value"]} labels={{ value: "Series A" }} showLegend={false} height="280px" />
|
|
307
160
|
</DashboardCardPreset>
|
|
308
161
|
)}
|
|
309
162
|
{show("distribution") && (
|
|
310
163
|
<DashboardCardPreset title="Correlation" description="Each point is an item">
|
|
311
|
-
<
|
|
164
|
+
<ScatterChart data={scatterPoints} x="x" y="y" size="size" index="label" height="280px" />
|
|
312
165
|
</DashboardCardPreset>
|
|
313
166
|
)}
|
|
314
167
|
{show("distribution") && (
|
|
@@ -318,10 +171,7 @@ export default function HomePage() {
|
|
|
318
171
|
)}
|
|
319
172
|
{show("distribution") && (
|
|
320
173
|
<DashboardCardPreset title="Activity" description="Intensity by cell">
|
|
321
|
-
<
|
|
322
|
-
option={heatmapOption(heatmapCells, HEATMAP_X_AXIS, HEATMAP_Y_AXIS)}
|
|
323
|
-
height="280px"
|
|
324
|
-
/>
|
|
174
|
+
<Heatmap data={heatmapCells} x="x" y="y" value="value" xLabels={["0", "1", "2", "3", "4", "5"]} yLabels={["Row 7", "Row 6", "Row 5", "Row 4", "Row 3", "Row 2", "Row 1"]} height={280} />
|
|
325
175
|
</DashboardCardPreset>
|
|
326
176
|
)}
|
|
327
177
|
</div>
|
|
@@ -90,9 +90,6 @@ export const radarAxes: RadarPoint[] = [
|
|
|
90
90
|
{ current: 79, benchmark: 70 },
|
|
91
91
|
]
|
|
92
92
|
|
|
93
|
-
export const HEATMAP_X_AXIS = ["0", "1", "2", "3", "4", "5"]
|
|
94
|
-
export const HEATMAP_Y_AXIS = ["行1", "行2", "行3", "行4", "行5", "行6", "行7"]
|
|
95
|
-
|
|
96
93
|
export const heatmapCells: HeatmapCell[] = [
|
|
97
94
|
{ x: "0", y: "行1", value: 57 },
|
|
98
95
|
{ x: "1", y: "行1", value: 25 },
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type TimePoint = {
|
|
2
2
|
date: string
|
|
3
3
|
series1: number
|
|
4
4
|
series2: number
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export
|
|
7
|
+
export type BarPoint = {
|
|
8
8
|
value: number
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export
|
|
11
|
+
export type ScatterPoint = {
|
|
12
12
|
x: number
|
|
13
13
|
y: number
|
|
14
14
|
size: number
|
|
15
15
|
label: string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export
|
|
18
|
+
export type RadarPoint = {
|
|
19
19
|
current: number
|
|
20
20
|
benchmark: number
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export
|
|
23
|
+
export type HeatmapCell = {
|
|
24
24
|
x: string
|
|
25
25
|
y: string
|
|
26
26
|
value: number
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export
|
|
29
|
+
export type DashboardFilters = {
|
|
30
30
|
dateRange: { from: Date | undefined; to: Date | undefined }
|
|
31
31
|
}
|