@squadbase/vantage-template 0.2.0-dev1.3cd91d9 → 0.2.0-dev1.54651d3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/base-template/AGENTS.md +2 -2
  2. package/base-template/agents/page.md +5 -4
  3. package/base-template/bun.lock +2 -2
  4. package/base-template/package.json +1 -1
  5. package/package.json +2 -2
  6. package/ui-templates/CLAUDE.md +13 -12
  7. package/ui-templates/chart-grid/lib/mock-data.ts +0 -3
  8. package/ui-templates/chart-grid/lib/types.ts +6 -6
  9. package/ui-templates/chart-grid/pages/index.tsx +11 -161
  10. package/ui-templates/chart-grid-ja/lib/mock-data.ts +0 -3
  11. package/ui-templates/chart-grid-ja/lib/types.ts +6 -6
  12. package/ui-templates/chart-grid-ja/pages/index.tsx +11 -161
  13. package/ui-templates/funnel/lib/types.ts +2 -2
  14. package/ui-templates/funnel/pages/index.tsx +10 -88
  15. package/ui-templates/funnel-ja/lib/types.ts +2 -2
  16. package/ui-templates/funnel-ja/pages/index.tsx +10 -87
  17. package/ui-templates/kpi-chart-advanced/lib/mock-data.ts +6 -6
  18. package/ui-templates/kpi-chart-advanced/lib/types.ts +6 -7
  19. package/ui-templates/kpi-chart-advanced/pages/index.tsx +6 -117
  20. package/ui-templates/kpi-chart-advanced-ja/lib/mock-data.ts +6 -6
  21. package/ui-templates/kpi-chart-advanced-ja/lib/types.ts +6 -7
  22. package/ui-templates/kpi-chart-advanced-ja/pages/index.tsx +6 -117
  23. package/ui-templates/kpi-chart-simple/lib/types.ts +4 -4
  24. package/ui-templates/kpi-chart-simple/pages/index.tsx +4 -42
  25. package/ui-templates/kpi-chart-simple-ja/lib/types.ts +4 -4
  26. package/ui-templates/kpi-chart-simple-ja/pages/index.tsx +4 -40
  27. package/ui-templates/table-focus/lib/types.ts +3 -3
  28. package/ui-templates/table-focus/pages/index.tsx +3 -45
  29. package/ui-templates/table-focus-ja/lib/types.ts +3 -3
  30. package/ui-templates/table-focus-ja/pages/index.tsx +3 -45
@@ -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` ほか、`EChart`、書式の `formatValue`) |
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
- `EChart` は親の幅に追従する)。順序は KPI → チャート → 表。値が 1 つなら KPI にする
140
+ チャートは親の幅に追従する)。順序は KPI → チャート → 表。値が 1 つなら KPI にする
141
141
  (1 本の棒グラフにしない)。強調は 1 画面(スライドは 1 枚)に 1 か所。数値には単位と比較対象を添える。
142
142
  - **Do:** トークンで色を指定する / 色の意味をアプリ全体でそろえる / チャートのタイトルに結論を書く。
143
143
  - **Don't:** 色コードや素のパレットクラスを書く / `dark:` を並べる / 3D・装飾目的のグラデーション・
@@ -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`・型付きチャート(下の「グラフ」)・`EChart` ほか)。
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`、構成比は `DonutChart`。`data`(行の配列)・
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` + `EChartsOption` は、二軸・散布図・ヒートマップ・注釈線など型付きチャートの props で
255
- 表せないときだけ使う。
255
+ - `EChart` + option 関数は、レーダーなど型付きチャートで表せないときだけ使う。`EChart` で組んだ
256
+ グラフは、あとから種類もデータも編集で変えられない。
256
257
  - 色は省略してテーマトークンに任せる。指定するなら `"chart-1"`〜`"chart-5"` か
257
258
  `"var(--destructive)"` などの CSS 色。hex の直書きや Tailwind クラスは使わない。
258
259
  - 数値の書式(`¥`・`%`・桁区切り)は `valueFormatter` に渡す。
@@ -6,7 +6,7 @@
6
6
  "name": "vibe-app",
7
7
  "dependencies": {
8
8
  "@squadbase/react": "^0.1.0",
9
- "@squadbase/vantage": "0.7.1-dev1.5e06644",
9
+ "@squadbase/vantage": "0.7.1-dev1.618b9b9",
10
10
  "@squadbase/vantage-sdk": "0.1.2-dev1.5f6d2a8",
11
11
  "date-fns": "^4.1.0",
12
12
  "lucide-react": "^0.468.0",
@@ -196,7 +196,7 @@
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.1-dev1.5e06644", "", { "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-3NJpd7No3IGD4/i6ju7iI8BDsiZHf4rYH6WwgjigQd+C2JW9CeYuwzYkXJdVMs2x/ffiFdIPjj6Nk/X3WGH3Kw=="],
199
+ "@squadbase/vantage": ["@squadbase/vantage@0.7.1-dev1.618b9b9", "", { "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-e5mM9x2jLq8Q4uoeIFei1zxNCd25GCffS38vR08ODWebFawK0OAv9gupCJ0FuXJL8R5fdzN644cnxYlSzzhk9A=="],
200
200
 
201
201
  "@squadbase/vantage-sdk": ["@squadbase/vantage-sdk@0.1.2-dev1.5f6d2a8", "", {}, "sha512-XMJ6wHC2aMiqA+IN+jTuPZBIopsI4dTO3dq40e2LfpXcfUeyDASHxYmTxV/klgHUZH97rGNyq4y7Eb3XIixpVA=="],
202
202
 
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@squadbase/react": "^0.1.0",
15
- "@squadbase/vantage": "0.7.1-dev1.5e06644",
15
+ "@squadbase/vantage": "0.7.1-dev1.618b9b9",
16
16
  "@squadbase/vantage-sdk": "0.1.2-dev1.5f6d2a8",
17
17
  "date-fns": "^4.1.0",
18
18
  "lucide-react": "^0.468.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squadbase/vantage-template",
3
- "version": "0.2.0-dev1.3cd91d9",
3
+ "version": "0.2.0-dev1.54651d3",
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": "3cd91d96fe1d617abb0d60b15701407b88b1113a",
53
+ "gitHead": "54651d38a82bf9e6e2bd36615d516a5cae6e02ae",
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",
@@ -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. インライン優先 — 薄いラッパ component を作らない
43
+ ### 2. チャートは型付き部品で書く — EChart + option 関数は作らない
44
44
 
45
- **`data → EChartsOption → <EChart>` だけの薄いチャート component は作らず、`index.tsx` 内のオプションビルダ関数にする。**
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
- // ✅ 推奨: index.tsx 内のオプションビルダ関数 + EChart 直レンダ
49
- function areaOption(data: TimePoint[]): EChartsOption {
50
- return { /* ... */ }
51
- }
52
- // JSX 内:
53
- <EChart option={areaOption(timeSeries)} height="280px" />
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
- チャート整形ヘルパ(`getBaseGrid` / `formatNumber` 等)も同様に `index.tsx` 内へ inline する。
57
-
58
- **チャートに色をハードコードしない。** `@squadbase/vantage` v0.2.1 以降、`EChart` は init 時に `--chart-1..5`(系列色)と文字色/境界色トークン(軸・凡例・ツールチップ)を読み、light / dark の切り替えにも追従する。v0.2.2 からはスタイルシートの差し替え(`chart <preset>` の適用や `styles.css` の HMR)も拾い、トークンの実値が変わった時だけ再描画する。`option.color` / `itemStyle.color` / ラベルの `color` を書くと、その分だけテンプレがテーマ差し替え(`vantage-template chart <preset>` や `styles.css` の override)から外れる。**ui-templates では書かない**のが既定 — 意味色(成功=緑・失敗=赤など)を出したいときだけ、その series に限って指定する。`theme` プロップは使わない(渡した時点でトークン追従が完全に止まる)。
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`)と `Avatar` / `Pagination` / `RadioGroup` / `AlertDialog` / `Drawer` / `Toaster` / `Field` / `Combobox` / `HoverCard` / `Kbd`(`@squadbase/vantage/ui`)は 0.6.3 で入った。雛形の依存が `^0.5.3` の間は使わない(上の EChart の書き方のまま)。
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 interface TimePoint {
1
+ export type TimePoint = {
2
2
  date: string
3
3
  series1: number
4
4
  series2: number
5
5
  }
6
6
 
7
- export interface BarPoint {
7
+ export type BarPoint = {
8
8
  value: number
9
9
  }
10
10
 
11
- export interface ScatterPoint {
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 interface RadarPoint {
18
+ export type RadarPoint = {
19
19
  current: number
20
20
  benchmark: number
21
21
  }
22
22
 
23
- export interface HeatmapCell {
23
+ export type HeatmapCell = {
24
24
  x: string
25
25
  y: string
26
26
  value: number
27
27
  }
28
28
 
29
- export interface DashboardFilters {
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
- function heatmapOption(
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
- <EChart option={areaOption(timeSeries)} height="280px" />
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
- <EChart option={lineOption(timeSeries)} height="280px" />
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
- <EChart option={barOption(barSeries)} height="280px" />
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
- <EChart option={scatterOption(scatterPoints)} height="280px" />
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
- <EChart
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 interface TimePoint {
1
+ export type TimePoint = {
2
2
  date: string
3
3
  series1: number
4
4
  series2: number
5
5
  }
6
6
 
7
- export interface BarPoint {
7
+ export type BarPoint = {
8
8
  value: number
9
9
  }
10
10
 
11
- export interface ScatterPoint {
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 interface RadarPoint {
18
+ export type RadarPoint = {
19
19
  current: number
20
20
  benchmark: number
21
21
  }
22
22
 
23
- export interface HeatmapCell {
23
+ export type HeatmapCell = {
24
24
  x: string
25
25
  y: string
26
26
  value: number
27
27
  }
28
28
 
29
- export interface DashboardFilters {
29
+ export type DashboardFilters = {
30
30
  dateRange: { from: Date | undefined; to: Date | undefined }
31
31
  }