@squadbase/vantage-template 0.1.1 → 0.2.0-dev1.0c136ab

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 (58) hide show
  1. package/README.md +19 -9
  2. package/base-template/.squadbase/skills/vantage-add-feature/SKILL.md +14 -7
  3. package/base-template/.squadbase/skills/vantage-app/SKILL.md +4 -0
  4. package/base-template/.squadbase/skills/vantage-design/SKILL.md +62 -52
  5. package/base-template/.squadbase/skills/vantage-design/references/extract.md +26 -27
  6. package/base-template/.squadbase/skills/vantage-design/references/format.md +12 -172
  7. package/base-template/.squadbase/skills/vantage-design/references/presets.md +50 -110
  8. package/base-template/.squadbase/skills/vantage-pitfalls/SKILL.md +50 -1
  9. package/base-template/.squadbase/skills/vantage-slide/SKILL.md +299 -0
  10. package/base-template/.squadbase/skills/vantage-slide/references/morph.md +102 -0
  11. package/base-template/.squadbase/skills/vantage-slide/references/steps.md +57 -0
  12. package/base-template/.squadbase/skills/vantage-slide/references/tokens.md +87 -0
  13. package/base-template/.squadbase/skills/vantage-slide/references/transitions.md +196 -0
  14. package/base-template/AGENTS.md +225 -18
  15. package/base-template/agents/api.md +36 -0
  16. package/base-template/agents/csv.md +2 -1
  17. package/base-template/agents/doc.md +52 -3
  18. package/base-template/agents/page.md +92 -10
  19. package/base-template/agents/slide.md +90 -4
  20. package/base-template/agents/xlsx.md +2 -1
  21. package/base-template/bun.lock +917 -0
  22. package/base-template/bunfig.toml +5 -0
  23. package/base-template/package.json +6 -6
  24. package/base-template/squadbase.yml +1 -0
  25. package/base-template/src/_layout.tsx +16 -7
  26. package/base-template/src/components/build-recovery.tsx +37 -1
  27. package/base-template/src/components/user-card.tsx +11 -11
  28. package/base-template/src/index.tsx +8 -3
  29. package/base-template/src/styles.css +108 -12
  30. package/dist/index.js +971 -6
  31. package/package.json +20 -17
  32. package/ui-templates/CLAUDE.md +14 -11
  33. package/ui-templates/chart-grid/lib/mock-data.ts +0 -3
  34. package/ui-templates/chart-grid/lib/types.ts +6 -6
  35. package/ui-templates/chart-grid/pages/index.tsx +11 -161
  36. package/ui-templates/chart-grid-ja/lib/mock-data.ts +0 -3
  37. package/ui-templates/chart-grid-ja/lib/types.ts +6 -6
  38. package/ui-templates/chart-grid-ja/pages/index.tsx +11 -161
  39. package/ui-templates/funnel/lib/types.ts +2 -2
  40. package/ui-templates/funnel/pages/index.tsx +10 -88
  41. package/ui-templates/funnel-ja/lib/types.ts +2 -2
  42. package/ui-templates/funnel-ja/pages/index.tsx +10 -87
  43. package/ui-templates/kpi-chart-advanced/lib/mock-data.ts +6 -6
  44. package/ui-templates/kpi-chart-advanced/lib/types.ts +6 -7
  45. package/ui-templates/kpi-chart-advanced/pages/index.tsx +6 -117
  46. package/ui-templates/kpi-chart-advanced-ja/lib/mock-data.ts +6 -6
  47. package/ui-templates/kpi-chart-advanced-ja/lib/types.ts +6 -7
  48. package/ui-templates/kpi-chart-advanced-ja/pages/index.tsx +6 -117
  49. package/ui-templates/kpi-chart-simple/lib/types.ts +4 -4
  50. package/ui-templates/kpi-chart-simple/pages/index.tsx +51 -89
  51. package/ui-templates/kpi-chart-simple-ja/lib/types.ts +4 -4
  52. package/ui-templates/kpi-chart-simple-ja/pages/index.tsx +51 -87
  53. package/ui-templates/table-focus/lib/types.ts +3 -3
  54. package/ui-templates/table-focus/pages/index.tsx +3 -45
  55. package/ui-templates/table-focus-ja/lib/types.ts +3 -3
  56. package/ui-templates/table-focus-ja/pages/index.tsx +3 -45
  57. package/base-template/DESIGN.md +0 -108
  58. package/base-template/package-lock.json +0 -5841
@@ -0,0 +1,5 @@
1
+ # サプライチェーン対策: 公開から 48 時間(172800 秒)未満の版は install で解決しない。
2
+ # 自社パッケージは publish 直後の版を雛形が参照するため除外する。
3
+ [install]
4
+ minimumReleaseAge = 172800
5
+ minimumReleaseAgeExcludes = ["@squadbase/vantage", "@squadbase/vantage-sdk", "@squadbase/react"]
@@ -12,17 +12,17 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@squadbase/react": "^0.1.0",
15
- "@squadbase/vantage": "0.6.2",
16
- "@squadbase/vantage-sdk": "0.1.1",
15
+ "@squadbase/vantage": "0.7.1-dev1.01a6413",
16
+ "@squadbase/vantage-sdk": "0.1.2-dev1.d4039e5",
17
17
  "date-fns": "^4.1.0",
18
18
  "lucide-react": "^0.468.0",
19
- "react": "^19.2.7",
20
- "react-dom": "^19.2.7"
19
+ "react": "^19.3.1",
20
+ "react-dom": "^19.3.1"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^22.15.0",
24
- "@types/react": "^19.2.0",
25
- "@types/react-dom": "^19.2.0",
24
+ "@types/react": "^19.3.0",
25
+ "@types/react-dom": "^19.3.0",
26
26
  "typescript": "~5.7.0"
27
27
  }
28
28
  }
@@ -3,3 +3,4 @@ version: "1"
3
3
  build:
4
4
  framework: squadbase-vantage
5
5
  runtime: node20
6
+ package_manager: bun
@@ -1,6 +1,6 @@
1
1
  import type { ComponentProps } from "react"
2
2
  import { SquadbaseProvider } from "@squadbase/react"
3
- import { Link, Outlet, useCurrentRoute, useRoutes } from "@squadbase/vantage/router"
3
+ import { Link, Outlet, useCurrentRoute, useNavigate, useRoutes } from "@squadbase/vantage/router"
4
4
  import { AppShell } from "@squadbase/vantage/components"
5
5
  import type { NavGroup } from "@squadbase/vantage/components"
6
6
 
@@ -8,13 +8,11 @@ import { BuildRecovery } from "./components/build-recovery"
8
8
  import { UserCard } from "./components/user-card"
9
9
 
10
10
  /**
11
- * `AppShell` is router-agnostic and renders nav entries through whatever
12
- * component it is handed, using an `href` prop. Adapt it to the Vantage router
13
- * so navigation stays client-side.
11
+ * The app's display language, written to `<html lang>` (a BCP 47 literal, e.g.
12
+ * "ja"). Set it to the language of the app's content: it also switches the slide
13
+ * toolbar messages and enables Japanese phrase-aware line breaking in slides.
14
14
  */
15
- function RouterLink({ href, ...props }: { href: string } & ComponentProps<"a">) {
16
- return <Link to={href} {...props} />
17
- }
15
+ export const lang = "en"
18
16
 
19
17
  /**
20
18
  * The nav *is* the route list — adding a page file puts it in the nav, with no
@@ -50,6 +48,7 @@ function useNavGroups(): NavGroup[] {
50
48
  * 「Something went wrong」のままリロードするまで残る。
51
49
  */
52
50
  export default function RootLayout() {
51
+ const navigate = useNavigate()
53
52
  return (
54
53
  <SquadbaseProvider>
55
54
  <AppShell
@@ -57,6 +56,7 @@ export default function RootLayout() {
57
56
  groups={useNavGroups()}
58
57
  actions={<UserCard />}
59
58
  linkComponent={RouterLink}
59
+ onNavigate={(href) => navigate({ to: href })}
60
60
  >
61
61
  <BuildRecovery>
62
62
  <Outlet />
@@ -65,3 +65,12 @@ export default function RootLayout() {
65
65
  </SquadbaseProvider>
66
66
  )
67
67
  }
68
+
69
+ /**
70
+ * `AppShell` is router-agnostic and renders nav entries through whatever
71
+ * component it is handed, using an `href` prop. Adapt it to the Vantage router
72
+ * so navigation stays client-side.
73
+ */
74
+ function RouterLink({ href, ...props }: { href: string } & ComponentProps<"a">) {
75
+ return <Link to={href} {...props} />
76
+ }
@@ -29,6 +29,12 @@ import { Button, Spinner } from "@squadbase/vantage/ui"
29
29
  */
30
30
  const FRAMEWORK_ERROR_SELECTOR = '[role="alert"] h2'
31
31
 
32
+ /** `import.meta.hot` のうち、ここで使う分だけ。 */
33
+ interface ViteHot {
34
+ on(event: string, cb: () => void): void
35
+ off?(event: string, cb: () => void): void
36
+ }
37
+
32
38
  /** 書き込みの連鎖が落ち着くのを待ってからリロードする。 */
33
39
  const RELOAD_DELAY_MS = 1200
34
40
 
@@ -43,6 +49,21 @@ const SETTLE_MS = 5000
43
49
 
44
50
  const RELOAD_COUNT_KEY = "vantage:build-recovery-reloads"
45
51
 
52
+ /**
53
+ * 書きかけのファイルを下書きとして表示している間、Vantage のクライアントが立てる目印。
54
+ * 下書き中の描画エラーはフレームワークが直前に通った版へ戻すので、ここでは覆わず、
55
+ * リロードもしない(リロードすると下書きの表示ごと消える)。
56
+ */
57
+ declare global {
58
+ interface Window {
59
+ __VANTAGE_DRAFT__?: { active: boolean }
60
+ }
61
+ }
62
+
63
+ function isDraftActive(): boolean {
64
+ return window.__VANTAGE_DRAFT__?.active === true
65
+ }
66
+
46
67
  /** コピーしたことが伝わればいいので、確認表示はすぐ元に戻す。 */
47
68
  const COPIED_FEEDBACK_MS = 2000
48
69
 
@@ -90,6 +111,7 @@ export function RecoveringState({ error }: { error?: unknown }) {
90
111
  const attempts = readReloadCount()
91
112
  if (attempts < MAX_RELOADS) {
92
113
  const timer = setTimeout(() => {
114
+ if (isDraftActive()) return
93
115
  writeReloadCount(attempts + 1)
94
116
  window.location.reload()
95
117
  }, RELOAD_DELAY_MS)
@@ -181,6 +203,11 @@ export function BuildRecovery({ children }: { children: ReactNode }) {
181
203
  const host = hostRef.current
182
204
  if (!host) return
183
205
  const sync = () => {
206
+ // 下書きの表示中は覆わない。終わった時点でエラー画面が残っていれば、次の sync で覆う。
207
+ if (isDraftActive()) {
208
+ setMessage(null)
209
+ return
210
+ }
184
211
  const heading = host.querySelector(FRAMEWORK_ERROR_SELECTOR)
185
212
  // 覆って見えなくする以上、支援技術にも読ませない。`role="alert"` のままだと
186
213
  // 「Something went wrong」がそのまま読み上げられてしまう。属性は observe の
@@ -192,7 +219,16 @@ export function BuildRecovery({ children }: { children: ReactNode }) {
192
219
  sync()
193
220
  const observer = new MutationObserver(sync)
194
221
  observer.observe(host, { childList: true, subtree: true })
195
- return () => observer.disconnect()
222
+ // 下書きの有無が変わったときに見直す(目印の更新を待つため 1 tick 遅らせる)。
223
+ const onDraftState = () => setTimeout(sync, 0)
224
+ // 生成される `ImportMeta` は `env` しか宣言しない(HMR の型を入れるとアプリが vite/client を
225
+ // 入れたときに二重宣言になる)ので、ここだけ局所キャストで読む。
226
+ const hot = (import.meta as unknown as { hot?: ViteHot }).hot
227
+ hot?.on("vantage:draft-state", onDraftState)
228
+ return () => {
229
+ observer.disconnect()
230
+ hot?.off?.("vantage:draft-state", onDraftState)
231
+ }
196
232
  }, [])
197
233
 
198
234
  const crashed = message !== null
@@ -11,6 +11,16 @@ import {
11
11
  cn,
12
12
  } from "@squadbase/vantage/ui"
13
13
 
14
+ export function UserCard() {
15
+ const userState = useUser()
16
+
17
+ if (userState.status === "success") {
18
+ return <UserInfo user={userState.data} />
19
+ }
20
+
21
+ return <UserInfoFallback />
22
+ }
23
+
14
24
  /**
15
25
  * Squadbase-authenticated user chip for the app shell.
16
26
  *
@@ -47,7 +57,7 @@ function DetailRow({ label, children }: { label: string; children: React.ReactNo
47
57
 
48
58
  function UserInfo({ user }: { user: User }) {
49
59
  const fullName = `${user.firstName} ${user.lastName}`
50
- const rolesHref = navigator.language.startsWith("ja")
60
+ const rolesHref = document.documentElement.lang.startsWith("ja")
51
61
  ? "https://www.squadbase.dev/ja/docs/access-control#プロジェクトロール"
52
62
  : "https://www.squadbase.dev/docs/access-control#project-roles"
53
63
 
@@ -120,13 +130,3 @@ function UserInfoFallback() {
120
130
  </div>
121
131
  )
122
132
  }
123
-
124
- export function UserCard() {
125
- const userState = useUser()
126
-
127
- if (userState.status === "success") {
128
- return <UserInfo user={userState.data} />
129
- }
130
-
131
- return <UserInfoFallback />
132
- }
@@ -17,6 +17,7 @@ export const page = definePage({
17
17
  title: "Dashboard",
18
18
  description: "Sample data — replace with your own to get started.",
19
19
  navLabel: "Home",
20
+ placeholder: true,
20
21
  })
21
22
 
22
23
  const METRICS = [
@@ -65,14 +66,18 @@ const CHARTS = [
65
66
  ]
66
67
 
67
68
  export default function HomePage() {
69
+ // `data-vantage-sample` marks this page as the untouched template sample (the coding
70
+ // agent looks for it). Remove it together with the sample content.
71
+ const sampleNote = document.documentElement.lang.startsWith("ja")
72
+ ? "サンプルデータです。お手元のデータに置き換えて始めましょう。"
73
+ : "Sample data — replace with your own to get started."
74
+
68
75
  return (
69
76
  <PageShell>
70
77
  <PageShellHeader>
71
78
  <PageShellHeading>
72
79
  <PageShellTitle>Dashboard</PageShellTitle>
73
- <PageShellDescription>
74
- Sample data — replace with your own to get started.
75
- </PageShellDescription>
80
+ <PageShellDescription data-vantage-sample="home">{sampleNote}</PageShellDescription>
76
81
  </PageShellHeading>
77
82
  </PageShellHeader>
78
83
 
@@ -17,21 +17,117 @@
17
17
  /* --radius: 0.625rem; */
18
18
  }
19
19
 
20
- /* vantage-template:chart-preset — regenerated by `chart`; edits here are lost */
20
+ /* Page typeface. `--font-sans` (Vantage theme.css, overridable by the theme range
21
+ below or here) already lists Latin system faces and then Japanese ones, so kana
22
+ and kanji do not fall back to a thin locale default. Change the typeface by
23
+ overriding `--font-sans`; keep the Japanese families if you put a webfont in
24
+ front. */
25
+ body {
26
+ font-family: var(--font-sans);
27
+ }
28
+
29
+ /* squadkit-theme — regenerated by `theme`; edits here are lost */
30
+ /* theme: neutral */
21
31
  :root {
22
- --chart-1: var(--color-blue-600);
23
- --chart-2: var(--color-teal-500);
24
- --chart-3: var(--color-fuchsia-500);
25
- --chart-4: var(--color-violet-500);
26
- --chart-5: var(--color-gray-400);
32
+ --radius: 0.5rem;
33
+ --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", Meiryo, ui-sans-serif, system-ui, sans-serif;
34
+ --background: oklch(0.975 0.004 255);
35
+ --card: oklch(1 0 0);
36
+ --popover: oklch(1 0 0);
37
+ --secondary: oklch(0.965 0.005 255);
38
+ --muted: oklch(0.965 0.005 255);
39
+ --accent: oklch(0.955 0.01 255);
40
+ --sidebar: oklch(0.985 0.003 255);
41
+ --sidebar-accent: oklch(0.955 0.01 255);
42
+ --border: oklch(0.93 0.006 255);
43
+ --input: oklch(0.9 0.01 255);
44
+ --sidebar-border: oklch(0.915 0.008 255);
45
+ --foreground: oklch(0.21 0.02 260);
46
+ --card-foreground: oklch(0.21 0.02 260);
47
+ --popover-foreground: oklch(0.21 0.02 260);
48
+ --secondary-foreground: oklch(0.25 0.02 260);
49
+ --muted-foreground: oklch(0.5 0.02 258);
50
+ --accent-foreground: oklch(0.25 0.02 260);
51
+ --sidebar-foreground: oklch(0.21 0.02 260);
52
+ --sidebar-accent-foreground: oklch(0.25 0.02 260);
53
+ --primary: oklch(0.55 0.2 262);
54
+ --primary-foreground: oklch(0.985 0 0);
55
+ --ring: oklch(0.7 0.12 262);
56
+ --sidebar-primary: oklch(0.55 0.2 262);
57
+ --sidebar-primary-foreground: oklch(0.985 0 0);
58
+ --sidebar-ring: oklch(0.7 0.12 262);
59
+ --chart-1: oklch(0.55 0.2 262);
60
+ --chart-2: oklch(0.62 0.17 118);
61
+ --chart-3: oklch(0.5 0.19 352);
62
+ --chart-4: oklch(0.62 0.1 195);
63
+ --chart-5: oklch(0.44 0.18 300);
64
+ --positive: oklch(0.52 0.14 150);
65
+ --positive-subtle: oklch(0.96 0.04 150);
66
+ --positive-fill: oklch(0.62 0.15 150);
67
+ --negative: oklch(0.53 0.19 25);
68
+ --negative-subtle: oklch(0.96 0.03 25);
69
+ --negative-fill: oklch(0.62 0.17 25);
70
+ --warning: oklch(0.53 0.12 70);
71
+ --warning-subtle: oklch(0.96 0.05 85);
72
+ --warning-fill: oklch(0.79 0.16 82);
73
+ --info: oklch(0.52 0.16 255);
74
+ --info-subtle: oklch(0.96 0.03 250);
75
+ --info-fill: oklch(0.62 0.15 250);
76
+ --neutral: oklch(0.52 0 0);
77
+ --neutral-subtle: oklch(0.96 0 0);
78
+ --neutral-fill: oklch(0.62 0 0);
79
+ --destructive: oklch(0.53 0.21 27.325);
80
+ --destructive-foreground: oklch(0.985 0 0);
27
81
  }
28
82
 
29
83
  .dark,
30
84
  [data-theme="dark"] {
31
- --chart-1: var(--color-blue-400);
32
- --chart-2: var(--color-teal-400);
33
- --chart-3: var(--color-fuchsia-400);
34
- --chart-4: var(--color-violet-400);
35
- --chart-5: var(--color-gray-500);
85
+ --background: oklch(0.16 0.012 262);
86
+ --card: oklch(0.215 0.015 262);
87
+ --popover: oklch(0.235 0.016 262);
88
+ --secondary: oklch(0.27 0.016 262);
89
+ --muted: oklch(0.27 0.016 262);
90
+ --accent: oklch(0.3 0.02 262);
91
+ --sidebar: oklch(0.2 0.014 262);
92
+ --sidebar-accent: oklch(0.3 0.02 262);
93
+ --border: oklch(1 0 0 / 10%);
94
+ --input: oklch(1 0 0 / 15%);
95
+ --sidebar-border: oklch(1 0 0 / 10%);
96
+ --foreground: oklch(0.96 0.005 255);
97
+ --card-foreground: oklch(0.96 0.005 255);
98
+ --popover-foreground: oklch(0.96 0.005 255);
99
+ --secondary-foreground: oklch(0.96 0.005 255);
100
+ --muted-foreground: oklch(0.72 0.02 258);
101
+ --accent-foreground: oklch(0.96 0.005 255);
102
+ --sidebar-foreground: oklch(0.96 0.005 255);
103
+ --sidebar-accent-foreground: oklch(0.96 0.005 255);
104
+ --primary: oklch(0.68 0.19 262);
105
+ --primary-foreground: oklch(0.145 0.02 262);
106
+ --ring: oklch(0.6 0.15 262);
107
+ --sidebar-primary: oklch(0.68 0.19 262);
108
+ --sidebar-primary-foreground: oklch(0.145 0.02 262);
109
+ --sidebar-ring: oklch(0.6 0.15 262);
110
+ --chart-1: oklch(0.56 0.19 262);
111
+ --chart-2: oklch(0.75 0.17 118);
112
+ --chart-3: oklch(0.64 0.19 352);
113
+ --chart-4: oklch(0.78 0.105 195);
114
+ --chart-5: oklch(0.71 0.17 300);
115
+ --positive: oklch(0.76 0.15 150);
116
+ --positive-subtle: oklch(0.27 0.05 150);
117
+ --positive-fill: oklch(0.56 0.13 150);
118
+ --negative: oklch(0.74 0.15 22);
119
+ --negative-subtle: oklch(0.27 0.06 25);
120
+ --negative-fill: oklch(0.56 0.15 22);
121
+ --warning: oklch(0.8 0.14 80);
122
+ --warning-subtle: oklch(0.27 0.05 75);
123
+ --warning-fill: oklch(0.73 0.145 78);
124
+ --info: oklch(0.75 0.12 250);
125
+ --info-subtle: oklch(0.27 0.06 255);
126
+ --info-fill: oklch(0.56 0.13 250);
127
+ --neutral: oklch(0.85 0 0);
128
+ --neutral-subtle: oklch(0.27 0 0);
129
+ --neutral-fill: oklch(0.56 0 0);
130
+ --destructive: oklch(0.704 0.191 22.216);
131
+ --destructive-foreground: oklch(0.145 0.02 262);
36
132
  }
37
- /* vantage-template:chart-preset:end */
133
+ /* squadkit-theme:end */