@squadbase/vantage 0.6.2-dev1.d594c56 → 0.6.2-dev1.e85faec
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/dist/chunk-2IAPIOPS.js +152 -0
- package/dist/chunk-2IAPIOPS.js.map +1 -0
- package/dist/chunk-57GHR5LN.js +163 -0
- package/dist/chunk-57GHR5LN.js.map +1 -0
- package/dist/chunk-6OTTGAPO.js +44 -0
- package/dist/chunk-6OTTGAPO.js.map +1 -0
- package/dist/{chunk-XPQSTZUU.js → chunk-7S52M2SL.js} +4 -3
- package/dist/chunk-7S52M2SL.js.map +1 -0
- package/dist/chunk-JXFCSF3K.js +673 -0
- package/dist/chunk-JXFCSF3K.js.map +1 -0
- package/dist/{chunk-HKSVYMYJ.js → chunk-QOXXOFGL.js} +61 -929
- package/dist/chunk-QOXXOFGL.js.map +1 -0
- package/dist/components/index.d.ts +11 -247
- package/dist/components/index.js +5 -2
- package/dist/delta-text-CvwBGJ95.d.ts +15 -0
- package/dist/doc/index.d.ts +215 -2
- package/dist/doc/index.js +300 -3
- package/dist/doc/index.js.map +1 -1
- package/dist/format-U0cQl069.d.ts +243 -0
- package/dist/slide/index.d.ts +272 -1
- package/dist/slide/index.js +966 -1
- package/dist/slide/index.js.map +1 -1
- package/dist/table/index.js +5 -2
- package/dist/table/index.js.map +1 -1
- package/dist/ui/index.d.ts +4 -1
- package/dist/ui/index.js +3 -3
- package/dist/ui/index.js.map +1 -1
- package/docs/en/components.md +13 -2
- package/docs/en/doc/delta-text.md +40 -0
- package/docs/en/doc/doc-action-items.md +49 -0
- package/docs/en/doc/doc-callout.md +38 -0
- package/docs/en/doc/doc-data-table.md +60 -0
- package/docs/en/doc/doc-executive-summary.md +64 -0
- package/docs/en/doc/doc-figure.md +56 -0
- package/docs/en/doc/doc-key-findings.md +61 -0
- package/docs/en/doc/doc-kpi-scorecard.md +80 -0
- package/docs/en/doc/doc-notes-and-sources.md +43 -0
- package/docs/en/doc/doc-report-header.md +46 -0
- package/docs/en/parts/area-chart.md +99 -0
- package/docs/en/parts/bar-chart.md +91 -0
- package/docs/en/parts/bar-list.md +50 -0
- package/docs/en/parts/category-bar.md +37 -0
- package/docs/en/parts/chart-frame.md +39 -0
- package/docs/en/parts/delta.md +4 -3
- package/docs/en/parts/donut-chart.md +72 -0
- package/docs/en/parts/funnel-steps.md +2 -1
- package/docs/en/parts/heatmap.md +53 -0
- package/docs/en/parts/kpi-card.md +2 -1
- package/docs/en/parts/legend.md +35 -0
- package/docs/en/parts/line-chart.md +94 -0
- package/docs/en/parts/progress-circle.md +33 -0
- package/docs/en/parts/sample-data.md +39 -0
- package/docs/en/parts/scatter-chart.md +56 -0
- package/docs/en/parts/tracker.md +36 -0
- package/docs/en/parts/updated-at.md +30 -0
- package/docs/en/parts/waterfall-chart.md +56 -0
- package/docs/en/slide/slide-chart-full.md +48 -0
- package/docs/en/slide/slide-chart-insight.md +52 -0
- package/docs/en/slide/slide-columns.md +46 -0
- package/docs/en/slide/slide-comparison.md +68 -0
- package/docs/en/slide/slide-cover.md +39 -0
- package/docs/en/slide/slide-exec-summary.md +47 -0
- package/docs/en/slide/slide-heading.md +38 -0
- package/docs/en/slide/slide-kpi-grid.md +55 -0
- package/docs/en/slide/slide-kpi-hero.md +58 -0
- package/docs/en/slide/slide-next-actions.md +49 -0
- package/docs/en/slide/slide-scorecard-table.md +54 -0
- package/docs/en/slide/slide-section.md +44 -0
- package/docs/en/slide/slide-source-line.md +34 -0
- package/docs/en/ui/alert-dialog.md +42 -0
- package/docs/en/ui/avatar.md +31 -0
- package/docs/en/ui/combobox.md +74 -0
- package/docs/en/ui/drawer.md +41 -0
- package/docs/en/ui/empty.md +1 -1
- package/docs/en/ui/error-state.md +4 -3
- package/docs/en/ui/field.md +42 -0
- package/docs/en/ui/hover-card.md +21 -0
- package/docs/en/ui/kbd.md +17 -0
- package/docs/en/ui/loading.md +1 -1
- package/docs/en/ui/pagination.md +36 -0
- package/docs/en/ui/radio-group.md +21 -0
- package/docs/en/ui/toast.md +44 -0
- package/docs/en/ui/toggle-group.md +4 -3
- package/docs/index.json +857 -77
- package/docs/ja/components.md +12 -1
- package/docs/ja/doc/delta-text.md +40 -0
- package/docs/ja/doc/doc-action-items.md +49 -0
- package/docs/ja/doc/doc-callout.md +38 -0
- package/docs/ja/doc/doc-data-table.md +60 -0
- package/docs/ja/doc/doc-executive-summary.md +64 -0
- package/docs/ja/doc/doc-figure.md +56 -0
- package/docs/ja/doc/doc-key-findings.md +61 -0
- package/docs/ja/doc/doc-kpi-scorecard.md +80 -0
- package/docs/ja/doc/doc-notes-and-sources.md +43 -0
- package/docs/ja/doc/doc-report-header.md +46 -0
- package/docs/ja/parts/area-chart.md +49 -25
- package/docs/ja/parts/bar-chart.md +50 -24
- package/docs/ja/parts/bar-list.md +31 -8
- package/docs/ja/parts/chart-frame.md +36 -0
- package/docs/ja/parts/delta.md +5 -4
- package/docs/ja/parts/donut-chart.md +45 -26
- package/docs/ja/parts/funnel-steps.md +27 -8
- package/docs/ja/parts/heatmap.md +45 -0
- package/docs/ja/parts/kpi-card.md +2 -1
- package/docs/ja/parts/legend.md +36 -0
- package/docs/ja/parts/line-chart.md +48 -22
- package/docs/ja/parts/sample-data.md +61 -0
- package/docs/ja/parts/scatter-chart.md +69 -0
- package/docs/ja/parts/updated-at.md +27 -0
- package/docs/ja/parts/waterfall-chart.md +61 -0
- package/docs/ja/slide/slide-chart-full.md +48 -0
- package/docs/ja/slide/slide-chart-insight.md +52 -0
- package/docs/ja/slide/slide-columns.md +46 -0
- package/docs/ja/slide/slide-comparison.md +68 -0
- package/docs/ja/slide/slide-cover.md +39 -0
- package/docs/ja/slide/slide-exec-summary.md +47 -0
- package/docs/ja/slide/slide-heading.md +38 -0
- package/docs/ja/slide/slide-kpi-grid.md +55 -0
- package/docs/ja/slide/slide-kpi-hero.md +58 -0
- package/docs/ja/slide/slide-next-actions.md +49 -0
- package/docs/ja/slide/slide-scorecard-table.md +54 -0
- package/docs/ja/slide/slide-section.md +44 -0
- package/docs/ja/slide/slide-source-line.md +34 -0
- package/docs/ja/ui/empty.md +1 -1
- package/docs/ja/ui/error-state.md +4 -3
- package/docs/ja/ui/loading.md +1 -1
- package/docs/ja/ui/toggle-group.md +4 -3
- package/package.json +2 -2
- package/registry/ui/area-chart.tsx +88 -26
- package/registry/ui/attention-list.tsx +303 -0
- package/registry/ui/bar-chart.tsx +88 -26
- package/registry/ui/bar-list.tsx +87 -24
- package/registry/ui/box-plot-chart.tsx +3906 -0
- package/registry/ui/category-bar.tsx +54 -19
- package/registry/ui/chart-frame.tsx +56 -21
- package/registry/ui/dashboard-card.tsx +2 -2
- package/registry/ui/delta.tsx +11 -8
- package/registry/ui/donut-chart.tsx +89 -26
- package/registry/ui/echart.tsx +194 -44
- package/registry/ui/funnel-steps.tsx +33 -5
- package/registry/ui/heatmap.tsx +55 -21
- package/registry/ui/histogram-chart.tsx +3986 -0
- package/registry/ui/kpi-card.tsx +41 -14
- package/registry/ui/legend.tsx +87 -24
- package/registry/ui/line-chart.tsx +88 -26
- package/registry/ui/page-shell.tsx +9 -9
- package/registry/ui/paired-chart.tsx +3827 -0
- package/registry/ui/sample-data.tsx +1 -1
- package/registry/ui/scatter-chart.tsx +88 -26
- package/registry/ui/section-header.tsx +2 -2
- package/registry/ui/slider.tsx +1 -1
- package/registry/ui/status-badge.tsx +8 -8
- package/registry/ui/tooltip.tsx +6 -2
- package/registry/ui/tracker.tsx +9 -3
- package/registry/ui/trend-indicator.tsx +2 -2
- package/registry/ui/waterfall-chart.tsx +88 -26
- package/skills/vantage-design/SKILL.md +27 -25
- package/skills/vantage-design/references/extract.md +16 -14
- package/skills/vantage-design/references/format.md +6 -5
- package/skills/vantage-design/references/presets.md +60 -110
- package/skills/vantage-slide/SKILL.md +54 -36
- package/templates/AGENTS.md +2 -2
- package/templates/agents/doc.md +48 -0
- package/templates/agents/page.md +22 -1
- package/templates/agents/slide.md +70 -2
- package/theme.css +16 -15
- package/dist/chunk-HKSVYMYJ.js.map +0 -1
- package/dist/chunk-XPQSTZUU.js.map +0 -1
|
@@ -32,7 +32,7 @@ import { EChart } from "@squadbase/vantage/components"
|
|
|
32
32
|
import type { Polarity } from "@squadbase/vantage/components"
|
|
33
33
|
import { EMPTY_VALUE, MINUS_SIGN } from "@squadbase/vantage/components"
|
|
34
34
|
import type { ChartCommonProps, NumericKeys, ValueFormatter } from "@squadbase/vantage/components"
|
|
35
|
-
import { createContext, useCallback, useEffect, useRef, useState } from "react"
|
|
35
|
+
import { createContext, useCallback, useEffect, useRef, useState, type RefObject } from "react"
|
|
36
36
|
import type { ChartTone } from "@squadbase/vantage/components"
|
|
37
37
|
import { type ReactNode } from "react"
|
|
38
38
|
import { computeComparison, defaultChangeDisplay, formatChange, toneForValue, type ComparisonKind, type PeriodGrain } from "@squadbase/vantage/components"
|
|
@@ -65,6 +65,8 @@ const SERIES_TOKENS = ["--chart-1", "--chart-2", "--chart-3", "--chart-4", "--ch
|
|
|
65
65
|
interface ChartTokens {
|
|
66
66
|
/** Resolved `--chart-1..5`, in order. */
|
|
67
67
|
series: string[]
|
|
68
|
+
/** Computed `font-family` of the container, so canvas text matches the DOM. Optional. */
|
|
69
|
+
fontFamily?: string
|
|
68
70
|
/** Body text: titles and the default `textStyle`. */
|
|
69
71
|
foreground: string | null
|
|
70
72
|
/** Secondary text: axis labels, legend, subtitles. */
|
|
@@ -73,10 +75,23 @@ interface ChartTokens {
|
|
|
73
75
|
border: string | null
|
|
74
76
|
/** Tooltip surface. */
|
|
75
77
|
popover: string | null
|
|
78
|
+
/** Semantic and surface dependencies used by typed chart options. Optional for hand-built tokens. */
|
|
79
|
+
colors?: Record<string, string>
|
|
80
|
+
/** Actual inherited painting surface (may change without a token changing). */
|
|
81
|
+
surface?: string | null
|
|
76
82
|
/** Tooltip text. */
|
|
77
83
|
popoverForeground: string | null
|
|
78
84
|
}
|
|
79
85
|
|
|
86
|
+
// Keep scope out of the public token shape. A resolved snapshot remembers where arbitrary
|
|
87
|
+
// var(--token) expressions must be read, without retaining unmounted charts globally.
|
|
88
|
+
const tokenScopes = new WeakMap<ChartTokens, Element>()
|
|
89
|
+
const OPTION_COLOR_TOKENS = [
|
|
90
|
+
"--background", "--card", "--muted", "--primary", "--destructive",
|
|
91
|
+
...["positive", "negative", "warning", "neutral", "info"].flatMap((tone) =>
|
|
92
|
+
["", "-fill", "-subtle"].map((suffix) => `--${tone}${suffix}`)),
|
|
93
|
+
]
|
|
94
|
+
|
|
80
95
|
let normalizeContext: CanvasRenderingContext2D | null | undefined
|
|
81
96
|
|
|
82
97
|
/** The forms `fillStyle` serializes legacy colours to, and zrender can parse. */
|
|
@@ -132,14 +147,19 @@ function readChartTokens(el?: Element | null): ChartTokens | null {
|
|
|
132
147
|
const color = read(token)
|
|
133
148
|
if (color) series.push(color)
|
|
134
149
|
}
|
|
135
|
-
|
|
150
|
+
const tokens: ChartTokens = {
|
|
136
151
|
series,
|
|
152
|
+
colors: Object.fromEntries(OPTION_COLOR_TOKENS.map((name) => [name, styles.getPropertyValue(name).trim()])),
|
|
153
|
+
surface: readChartSurface(target),
|
|
154
|
+
...(styles.fontFamily ? { fontFamily: styles.fontFamily } : {}),
|
|
137
155
|
foreground: read("--foreground"),
|
|
138
156
|
mutedForeground: read("--muted-foreground"),
|
|
139
157
|
border: read("--border"),
|
|
140
158
|
popover: read("--popover"),
|
|
141
159
|
popoverForeground: read("--popover-foreground"),
|
|
142
160
|
}
|
|
161
|
+
tokenScopes.set(tokens, target)
|
|
162
|
+
return tokens
|
|
143
163
|
}
|
|
144
164
|
|
|
145
165
|
/** Structural equality, so a theme toggle that changes nothing doesn't re-init. */
|
|
@@ -147,8 +167,13 @@ function sameChartTokens(a: ChartTokens | null, b: ChartTokens | null): boolean
|
|
|
147
167
|
if (a === b) return true
|
|
148
168
|
if (!a || !b) return false
|
|
149
169
|
return (
|
|
170
|
+
tokenScopes.get(a) === tokenScopes.get(b) &&
|
|
171
|
+
a.surface === b.surface &&
|
|
172
|
+
Object.keys(a.colors ?? {}).length === Object.keys(b.colors ?? {}).length &&
|
|
173
|
+
Object.entries(a.colors ?? {}).every(([name, value]) => b.colors?.[name] === value) &&
|
|
150
174
|
a.series.length === b.series.length &&
|
|
151
175
|
a.series.every((color, i) => color === b.series[i]) &&
|
|
176
|
+
a.fontFamily === b.fontFamily &&
|
|
152
177
|
a.foreground === b.foreground &&
|
|
153
178
|
a.mutedForeground === b.mutedForeground &&
|
|
154
179
|
a.border === b.border &&
|
|
@@ -171,7 +196,7 @@ function sameChartTokens(a: ChartTokens | null, b: ChartTokens | null): boolean
|
|
|
171
196
|
* attributes alone leaves the chart painted in the previous palette until a
|
|
172
197
|
* reload — the tokens in the DOM are new, the canvas is not.
|
|
173
198
|
*/
|
|
174
|
-
function watchChartTokens(onChange: () => void): () => void {
|
|
199
|
+
function watchChartTokens(onChange: () => void, scope?: Element | null): () => void {
|
|
175
200
|
if (typeof document === "undefined") return () => {}
|
|
176
201
|
// Style edits arrive as bursts of mutations; coalesce them into one read, and
|
|
177
202
|
// take it after the next frame so a swapped stylesheet has been applied.
|
|
@@ -186,8 +211,11 @@ function watchChartTokens(onChange: () => void): () => void {
|
|
|
186
211
|
|
|
187
212
|
const themeObserver = new MutationObserver(schedule)
|
|
188
213
|
const attributeFilter = ["class", "style", "data-theme"]
|
|
189
|
-
|
|
190
|
-
|
|
214
|
+
// Only the chart and its ancestors can change its inherited theme. Never observe
|
|
215
|
+
// the document subtree: canvas/tooltip/rendering mutations would trigger every chart.
|
|
216
|
+
for (let node: Element | null = scope ?? document.body ?? document.documentElement; node; node = node.parentElement) {
|
|
217
|
+
themeObserver.observe(node, { attributes: true, attributeFilter })
|
|
218
|
+
}
|
|
191
219
|
|
|
192
220
|
const styleObserver = new MutationObserver(schedule)
|
|
193
221
|
if (document.head) {
|
|
@@ -243,7 +271,7 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
|
|
|
243
271
|
// Let the page background show through: charts sit on cards, not on a canvas.
|
|
244
272
|
backgroundColor: "transparent",
|
|
245
273
|
...(tokens.series.length > 0 ? { color: tokens.series } : {}),
|
|
246
|
-
textStyle: { color: text },
|
|
274
|
+
textStyle: { color: text, ...(tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {}) },
|
|
247
275
|
title: { textStyle: { color: text }, subtextStyle: { color: muted } },
|
|
248
276
|
legend: { textStyle: { color: muted } },
|
|
249
277
|
categoryAxis: axisTheme(tokens, false),
|
|
@@ -259,7 +287,11 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
|
|
|
259
287
|
padding: [8, 12],
|
|
260
288
|
// Rounded card with a soft shadow; in dark mode the shadow barely shows, so the border carries the edge.
|
|
261
289
|
extraCssText: "border-radius:8px;box-shadow:var(--shadow-card, 0 4px 12px rgb(0 0 0 / 0.08));",
|
|
262
|
-
textStyle: {
|
|
290
|
+
textStyle: {
|
|
291
|
+
color: tokens.popoverForeground ?? undefined,
|
|
292
|
+
fontSize: 12,
|
|
293
|
+
...(tokens.fontFamily ? { fontFamily: tokens.fontFamily } : {}),
|
|
294
|
+
},
|
|
263
295
|
axisPointer: { lineStyle: { color: line }, crossStyle: { color: line } },
|
|
264
296
|
},
|
|
265
297
|
}
|
|
@@ -271,22 +303,23 @@ function buildChartTheme(tokens: ChartTokens): Record<string, unknown> {
|
|
|
271
303
|
* components that build an ECharts option from token colours themselves (the
|
|
272
304
|
* typed charts), so their palette follows light/dark like `EChart`'s theme.
|
|
273
305
|
*/
|
|
274
|
-
function useChartTokens(): ChartTokens | null {
|
|
306
|
+
function useChartTokens(scope?: Element | null | RefObject<Element | null>): ChartTokens | null {
|
|
275
307
|
const [tokens, setTokens] = useState<ChartTokens | null>(() => readChartTokens())
|
|
276
308
|
// Compared here, not inside a `setTokens` updater: an updater that reads the DOM is
|
|
277
309
|
// replayed by React on every rebase and returns a fresh object each time, so the state
|
|
278
310
|
// never settles ("Maximum update depth exceeded" once the tokens change after mount).
|
|
279
311
|
const tokensRef = useRef(tokens)
|
|
280
312
|
useEffect(() => {
|
|
313
|
+
const target = scope && "current" in scope ? scope.current : scope
|
|
281
314
|
const sync = () => {
|
|
282
|
-
const next = readChartTokens()
|
|
315
|
+
const next = readChartTokens(target)
|
|
283
316
|
if (sameChartTokens(tokensRef.current, next)) return
|
|
284
317
|
tokensRef.current = next
|
|
285
318
|
setTokens(next)
|
|
286
319
|
}
|
|
287
320
|
sync()
|
|
288
|
-
return watchChartTokens(sync)
|
|
289
|
-
}, [])
|
|
321
|
+
return watchChartTokens(sync, target)
|
|
322
|
+
}, [scope])
|
|
290
323
|
return tokens
|
|
291
324
|
}
|
|
292
325
|
|
|
@@ -298,7 +331,7 @@ const EMBEDDED_VAR_RE = /var\(\s*(--[\w-]+)\s*\)/g
|
|
|
298
331
|
/**
|
|
299
332
|
* Turn chart colours into canvas-safe strings. `"chart-1"`〜`"chart-5"` come from
|
|
300
333
|
* the resolved series tokens; `"positive"` / `"warning"` / `"negative"` / `"neutral"` (and the area
|
|
301
|
-
* variants `"positive-fill"`, …) are read
|
|
334
|
+
* variants `"positive-fill"`, …) are read in the snapshot's inherited scope (`--positive`, …); `var(--token)` uses the same scope; any
|
|
302
335
|
* other CSS colour is normalized like the tokens are. A colour that can't be
|
|
303
336
|
* resolved comes back as `""`, which ECharts treats as "use the palette".
|
|
304
337
|
*/
|
|
@@ -309,12 +342,13 @@ function resolveChartColors(colors: readonly string[], tokens: ChartTokens | nul
|
|
|
309
342
|
// Meaning colours are the theme tokens of the same name: same path as `var(--positive)`.
|
|
310
343
|
if (TONE_NAME_RE.test(color.trim())) {
|
|
311
344
|
if (typeof document === "undefined") return ""
|
|
312
|
-
|
|
345
|
+
const target = (tokens && tokenScopes.get(tokens)) ?? document.documentElement
|
|
346
|
+
return toCanvasColor(getComputedStyle(target).getPropertyValue(`--${color.trim()}`)) ?? ""
|
|
313
347
|
}
|
|
314
348
|
if (typeof document === "undefined") return color
|
|
315
349
|
let value = color.trim()
|
|
316
350
|
const cssVar = CSS_VAR_RE.exec(value)
|
|
317
|
-
const styles = getComputedStyle(document.documentElement)
|
|
351
|
+
const styles = getComputedStyle((tokens && tokenScopes.get(tokens)) ?? document.documentElement)
|
|
318
352
|
if (cssVar) {
|
|
319
353
|
value = styles.getPropertyValue(cssVar[1]!).trim() || (cssVar[2] ?? "").trim()
|
|
320
354
|
} else if (value.includes("var(")) {
|
|
@@ -360,7 +394,7 @@ function readChartSurface(el: Element | null): string | null {
|
|
|
360
394
|
if (color) return color
|
|
361
395
|
}
|
|
362
396
|
}
|
|
363
|
-
return toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue("--background"))
|
|
397
|
+
return toCanvasColor(getComputedStyle(el ?? document.documentElement).getPropertyValue("--background"))
|
|
364
398
|
}
|
|
365
399
|
|
|
366
400
|
/** Widths are bucketed so a resize only rebuilds the option when the label budget can change. */
|
|
@@ -374,9 +408,10 @@ const WIDTH_BUCKET = 40
|
|
|
374
408
|
*/
|
|
375
409
|
function useChartSurface<E extends Element>(
|
|
376
410
|
forwarded: ForwardedRef<E>,
|
|
377
|
-
tokens
|
|
378
|
-
): { ref: (el: E | null) => void; surface: string | undefined; width: number | undefined } {
|
|
411
|
+
tokens?: ChartTokens | null,
|
|
412
|
+
): { ref: (el: E | null) => void; surface: string | undefined; width: number | undefined; tokens: ChartTokens | null } {
|
|
379
413
|
const [node, setNode] = useState<E | null>(null)
|
|
414
|
+
const scopedTokens = useChartTokens(node)
|
|
380
415
|
const [surface, setSurface] = useState<string | undefined>(undefined)
|
|
381
416
|
const [width, setWidth] = useState<number | undefined>(undefined)
|
|
382
417
|
const ref = useCallback(
|
|
@@ -390,7 +425,7 @@ function useChartSurface<E extends Element>(
|
|
|
390
425
|
useEffect(() => {
|
|
391
426
|
if (!node) return
|
|
392
427
|
setSurface(readChartSurface(node) ?? undefined)
|
|
393
|
-
}, [node, tokens])
|
|
428
|
+
}, [node, tokens, scopedTokens])
|
|
394
429
|
useEffect(() => {
|
|
395
430
|
if (!node || typeof ResizeObserver === "undefined") return
|
|
396
431
|
const update = (w: number) => setWidth(Math.floor(w / WIDTH_BUCKET) * WIDTH_BUCKET)
|
|
@@ -399,7 +434,7 @@ function useChartSurface<E extends Element>(
|
|
|
399
434
|
observer.observe(node)
|
|
400
435
|
return () => observer.disconnect()
|
|
401
436
|
}, [node])
|
|
402
|
-
return { ref, surface, width }
|
|
437
|
+
return { ref, surface, width, tokens: scopedTokens }
|
|
403
438
|
}
|
|
404
439
|
|
|
405
440
|
/* ---------- inlined from @squadbase/squadkit registry/lib/chart-options.ts (internal to @squadbase/vantage) ---------- */
|
|
@@ -789,6 +824,10 @@ const toDate = (t: ParsedTime) => new Date(t.year, t.month - 1, t.day)
|
|
|
789
824
|
|
|
790
825
|
/** How many x labels a time axis shows at most (the step is picked so the labels never crowd). */
|
|
791
826
|
const TIME_AXIS_MAX_LABELS = 6
|
|
827
|
+
/** Under this plot width (px) the axis, legend and labels switch to their compact form. */
|
|
828
|
+
const NARROW_PLOT_WIDTH = 400
|
|
829
|
+
/** The most x labels a narrow plot shows (a 262px plot reads 4 at most). */
|
|
830
|
+
const NARROW_TIME_AXIS_MAX_LABELS = 4
|
|
792
831
|
|
|
793
832
|
/** Calendar-friendly label steps per granularity (every 3 months, every week …). */
|
|
794
833
|
const TIME_AXIS_STEPS: Record<TimeGranularity, readonly number[]> = {
|
|
@@ -1234,7 +1273,9 @@ const LEGEND_LINE_BUDGET = 320
|
|
|
1234
1273
|
/** How many lines the plain legend takes, estimated from its labels (12px text + 8px dot + gaps). */
|
|
1235
1274
|
function legendLines(items: readonly string[], plotWidth?: number, reserve = 0): number {
|
|
1236
1275
|
const width = items.reduce((sum, name) => sum + [...name].length * 12 + 8 + 5 + 16, 0)
|
|
1237
|
-
|
|
1276
|
+
// A narrow plot has no room for the PNG buttons beside the legend: they move off its line, so no reserve.
|
|
1277
|
+
const narrow = plotWidth !== undefined && plotWidth < NARROW_PLOT_WIDTH
|
|
1278
|
+
const budget = Math.max(80, (plotWidth ? (narrow ? plotWidth : Math.min(LEGEND_LINE_BUDGET, plotWidth)) : LEGEND_LINE_BUDGET) - (narrow ? 0 : reserve))
|
|
1238
1279
|
return Math.min(3, Math.max(1, Math.ceil(width / budget)))
|
|
1239
1280
|
}
|
|
1240
1281
|
|
|
@@ -1489,7 +1530,15 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
|
|
|
1489
1530
|
? null
|
|
1490
1531
|
: timeAxisLabelStep(
|
|
1491
1532
|
rawIndex,
|
|
1492
|
-
plotWidth
|
|
1533
|
+
plotWidth
|
|
1534
|
+
? Math.max(
|
|
1535
|
+
2,
|
|
1536
|
+
Math.min(
|
|
1537
|
+
plotWidth < NARROW_PLOT_WIDTH ? NARROW_TIME_AXIS_MAX_LABELS : TIME_AXIS_MAX_LABELS,
|
|
1538
|
+
Math.floor(plotWidth / TIME_LABEL_WIDTH),
|
|
1539
|
+
),
|
|
1540
|
+
)
|
|
1541
|
+
: undefined,
|
|
1493
1542
|
)
|
|
1494
1543
|
// Plain (non-date) x labels of a line chart: thinned to every n-th so they never touch, never rotated.
|
|
1495
1544
|
const plainStep = (() => {
|
|
@@ -1535,8 +1584,12 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
|
|
|
1535
1584
|
: []
|
|
1536
1585
|
// On a narrow plot the max and the latest label would print over each other: keep the latest.
|
|
1537
1586
|
const pointGap = plotWidth && labels.length > 1 ? plotWidth / (kind === "bar" ? labels.length : labels.length - 1) : null
|
|
1587
|
+
// By default only the latest value is labelled; an explicit `highlight` keeps its max + latest.
|
|
1588
|
+
const latestOnly = cfg.highlight === undefined && !shareHighlight && picked.length === 2
|
|
1538
1589
|
const highlightPoints =
|
|
1539
|
-
|
|
1590
|
+
latestOnly
|
|
1591
|
+
? [picked[1]!]
|
|
1592
|
+
: picked.length === 2 && pointGap !== null && Math.abs(picked[1]!.index - picked[0]!.index) * pointGap < HIGHLIGHT_LABEL_WIDTH
|
|
1540
1593
|
? [picked[1]!]
|
|
1541
1594
|
: picked
|
|
1542
1595
|
|
|
@@ -1747,6 +1800,8 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
|
|
|
1747
1800
|
? { width: 0, color, opacity: 0 }
|
|
1748
1801
|
: { width: 2, color, opacity: dimSeries ? DIMMED : 1 },
|
|
1749
1802
|
itemStyle: { color, opacity: dimSeries ? DIMMED : 1 },
|
|
1803
|
+
// Hovering a series fades the others (not for a stack, where the bands read together).
|
|
1804
|
+
emphasis: stacked ? undefined : { focus: "series" as const },
|
|
1750
1805
|
areaStyle: areaStyle && dimSeries ? { ...areaStyle, opacity: DIMMED * 0.3 } : areaStyle,
|
|
1751
1806
|
markPoint: markPointFor(c, color),
|
|
1752
1807
|
markLine: undefined,
|
|
@@ -2193,7 +2248,10 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
|
|
|
2193
2248
|
legend: {
|
|
2194
2249
|
show: showLegend,
|
|
2195
2250
|
top: 0,
|
|
2196
|
-
|
|
2251
|
+
// Narrow: left-aligned and wrapping above the plot, so nothing is cut off at the right edge.
|
|
2252
|
+
...(plotWidth !== undefined && plotWidth < NARROW_PLOT_WIDTH
|
|
2253
|
+
? { left: 0, right: 0 }
|
|
2254
|
+
: { right: reserveActions ? ACTIONS_RESERVE : 0 }),
|
|
2197
2255
|
// Plain wraps onto a second line at narrow widths instead of hiding items behind arrows.
|
|
2198
2256
|
type: "plain",
|
|
2199
2257
|
icon: "circle",
|
|
@@ -2254,7 +2312,12 @@ function buildCartesianOption(cfg: CartesianChartConfig): EChartsOption {
|
|
|
2254
2312
|
}
|
|
2255
2313
|
}
|
|
2256
2314
|
const shares = percent ? cartesianSeriesValues(i <= lastActual ? [row] : [], categories, "percent") : null
|
|
2257
|
-
|
|
2315
|
+
// Rows follow the legend order (categories first), not ECharts' own series order.
|
|
2316
|
+
const legendRank = (p: AxisTooltipParam) => {
|
|
2317
|
+
const at = categories.indexOf(p.seriesName ?? "")
|
|
2318
|
+
return at === -1 ? categories.length : at
|
|
2319
|
+
}
|
|
2320
|
+
for (const p of [...list].sort((a, b) => legendRank(a) - legendRank(b))) {
|
|
2258
2321
|
const color = typeof p.color === "string" ? p.color : "currentColor"
|
|
2259
2322
|
if (p.seriesId === FORECAST_SERIES_ID) {
|
|
2260
2323
|
// At and before the boundary the forecast repeats the actual value.
|
|
@@ -4105,8 +4168,7 @@ function WaterfallChartImpl<T extends Record<string, unknown>>(
|
|
|
4105
4168
|
ref: ForwardedRef<HTMLDivElement>,
|
|
4106
4169
|
) {
|
|
4107
4170
|
const valueKey: string = categories[0] ?? ""
|
|
4108
|
-
const tokens =
|
|
4109
|
-
const { ref: frameRef, width: plotWidth } = useChartSurface(ref, tokens)
|
|
4171
|
+
const { ref: frameRef, width: plotWidth, tokens } = useChartSurface(ref)
|
|
4110
4172
|
// Value labels and the tooltip read in full (as `format` says); ticks read short.
|
|
4111
4173
|
const valueFormatter = useMemo(() => resolveValueFormatter(valueFormatterProp, format), [valueFormatterProp, format])
|
|
4112
4174
|
const axisFormatter = useMemo(() => resolveAxisFormatter(valueFormatterProp, format), [valueFormatterProp, format])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vantage-design
|
|
3
|
-
description: Vantage(@squadbase/vantage)アプリの見た目の意図 `DESIGN.md` と、実際の値を持つ `styles.css` をまとめて作る / 更新する手順。配色・ブランドカラー・テーマ・チャートの色・フォント・角丸・トーンを変えたいとき、既存サイトやロゴ・資料・外部の DESIGN.md に合わせたいとき、プロジェクト作成時の初期デザイン(
|
|
3
|
+
description: Vantage(@squadbase/vantage)アプリの見た目の意図 `DESIGN.md` と、実際の値を持つ `styles.css` をまとめて作る / 更新する手順。配色・ブランドカラー・テーマ・チャートの色・フォント・角丸・トーンを変えたいとき、既存サイトやロゴ・資料・外部の DESIGN.md に合わせたいとき、プロジェクト作成時の初期デザイン(テーマ neutral / ocean / forest / sunset / violet / rose / mono)を決めるときに使う。「色を変えて」「ブランドに合わせて」「このサイトに合わせて」「落ち着いた感じに」「フォントを変えて」「テーマを作って」「DESIGN.md を作って」、"change the colors", "match our brand", "match this website", "theme", "color palette", "font", "design system", "DESIGN.md" で起動。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# DESIGN.md と styles.css をまとめて更新する
|
|
@@ -23,7 +23,7 @@ Vantage アプリの見た目は 2 つのファイルで決まる。
|
|
|
23
23
|
| --- | --- |
|
|
24
24
|
| `references/format.md` | `DESIGN.md` を書く / 直すとき(書式・節の順番・雛形) |
|
|
25
25
|
| `references/extract.md` | URL・画像・pptx/pdf・言葉・外部 DESIGN.md から色と書体を取り出すとき |
|
|
26
|
-
| `references/presets.md` |
|
|
26
|
+
| `references/presets.md` | テーマ(`neutral` / `ocean` / `forest` / `sunset` / `violet` / `rose` / `mono`)の選び方と `theme` コマンド。旧プリセット id の読み替え |
|
|
27
27
|
| `scripts/contrast.mjs` | 文字色と背景色のコントラスト比を確かめるとき |
|
|
28
28
|
|
|
29
29
|
## 手順
|
|
@@ -43,29 +43,32 @@ Vantage アプリの見た目は 2 つのファイルで決まる。
|
|
|
43
43
|
各行に「何に合わせてその色にしたか」を 1 語添える。
|
|
44
44
|
- **トーンの説明**(2〜3 行。`DESIGN.md` の「全体のトーン」にそのまま入る文)。
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
テーマで足りる場合はテーマ id(`references/presets.md`)で提案してよい。旧プリセット id(`default` / `calm` / `vivid` / `mono`)で頼まれたら新 id に読み替える。
|
|
47
47
|
|
|
48
48
|
### 3. styles.css と DESIGN.md を同じステップで書く
|
|
49
49
|
|
|
50
50
|
`styles.css`:
|
|
51
51
|
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
(`
|
|
58
|
-
|
|
59
|
-
-
|
|
52
|
+
- **テーマ範囲・チャート範囲のマーカーの中は手で編集しない。** 色・角丸・書体の出発点は 7 テーマ
|
|
53
|
+
(`neutral` / `ocean` / `forest` / `sunset` / `violet` / `rose` / `mono`)から選び、コマンドで当てる:
|
|
54
|
+
`npx @squadbase/vantage-template theme <id>`(プロジェクトルートで実行。`--dry-run` で書き込まずに
|
|
55
|
+
結果を見られる)。``/* squadkit-theme — regenerated by `theme`; edits here are lost */`` 〜
|
|
56
|
+
`/* squadkit-theme:end */` の間はコマンドが丸ごと書き換える生成物で、手で直した値は次の適用で消える。
|
|
57
|
+
旧プリセット id(`default` → `neutral` / `calm` → `ocean` / `vivid` → `sunset` / `mono`)もコマンドが受ける。
|
|
58
|
+
- チャートの 5 色はテーマが持つ。テーマと別の配色にしたいときだけ
|
|
59
|
+
`npx @squadbase/vantage-template chart <preset>`(`blue` / `ocean` / `sunset` / `forest` / `berry` / `mono`)を使う。
|
|
60
|
+
``/* vantage-template:chart-preset … */`` 〜 `/* vantage-template:chart-preset:end */` の間が置き換わり、
|
|
61
|
+
テーマのチャート色より優先される。テーマに揃え直すには `theme <id> --reset-chart`。
|
|
62
|
+
- プリセットに無いチャート色(ブランド色を `--chart-1` にしたいなど)は、**マーカーブロックの後ろ**に
|
|
60
63
|
別の `:root { --chart-1: …; }` と `.dark, [data-theme="dark"] { --chart-1: …; }` を足して上書きする
|
|
61
|
-
(後に書いた方が勝つ)
|
|
62
|
-
- `--primary` / `--primary-foreground` / `--radius`
|
|
63
|
-
(
|
|
64
|
-
|
|
65
|
-
(`var(--color-sky-600)`)で書く。
|
|
66
|
-
-
|
|
67
|
-
(
|
|
68
|
-
|
|
64
|
+
(後に書いた方が勝つ)。上書きするのは変えたい番号だけにし、残りはテーマに任せる。
|
|
65
|
+
- `--primary` / `--primary-foreground` / `--radius` などテーマに無い値・ブランド色の上書きも、
|
|
66
|
+
**マーカーブロックの後ろ**(ファイル末尾)に書く。マーカーより前に書いた値はテーマに負ける。
|
|
67
|
+
色は `:root` と `.dark, [data-theme="dark"]` の**両方**に書く。片方だけだとダークモードでテーマの値に
|
|
68
|
+
戻る。値は `oklch()` か Tailwind のパレット変数(`var(--color-sky-600)`)で書く。
|
|
69
|
+
- 書体は既定でシステムフォント。**ページの書体は `--font-sans`**(`styles.css` の `body` が
|
|
70
|
+
`font-family: var(--font-sans)` で参照する。テーマ範囲も `--font-sans` を持つので、書体を変えるには
|
|
71
|
+
マーカーブロックの後ろで `:root { --font-sans: …; }` を上書きする)。スライドの書体は `:root` の
|
|
69
72
|
`--slide-font-display`(見出し)/ `--slide-font-body`(本文)で決まる。Web フォントを使うときの
|
|
70
73
|
レシピ:
|
|
71
74
|
1. Google Fonts の CSS
|
|
@@ -73,13 +76,11 @@ Vantage アプリの見た目は 2 つのファイルで決まる。
|
|
|
73
76
|
から使う subset の `@font-face` ブロックだけを `styles.css` の先頭に貼る。
|
|
74
77
|
**`@import url(...)` は使わない** ― `styles.css` はテーマの後ろに連結されるので
|
|
75
78
|
「@import rules must precede all rules」の警告とともにビルドで捨てられる。
|
|
76
|
-
2.
|
|
79
|
+
2. マーカーブロックの後ろに次を書く(フォールバックは `theme.css` の既定と同じ並び):
|
|
77
80
|
|
|
78
81
|
```css
|
|
79
|
-
body {
|
|
80
|
-
font-family: "<Font>", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", Meiryo, ui-sans-serif, system-ui, sans-serif;
|
|
81
|
-
}
|
|
82
82
|
:root {
|
|
83
|
+
--font-sans: "<Font>", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", Meiryo, ui-sans-serif, system-ui, sans-serif;
|
|
83
84
|
--slide-font-display: "<Font>", -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Kaku Gothic ProN", "Hiragino Sans", "Yu Gothic", Meiryo, system-ui, sans-serif;
|
|
84
85
|
--slide-font-body: var(--slide-font-display);
|
|
85
86
|
}
|
|
@@ -90,8 +91,9 @@ Vantage アプリの見た目は 2 つのファイルで決まる。
|
|
|
90
91
|
`ui-sans-serif` / `system-ui` は日本語の face より**後ろ**に置く。日本語の Windows ではどちらも
|
|
91
92
|
Yu Gothic UI(UI のリサイズを避けるために字幅を詰めた書体)に解決され、カナがここで決まって
|
|
92
93
|
半角風に見える。macOS の Chrome は `-apple-system` を解釈しないので `BlinkMacSystemFont` も並べる。
|
|
93
|
-
既存アプリの `styles.css` に `
|
|
94
|
-
|
|
94
|
+
既存アプリの `styles.css` の `body` に `font-family` が直書きされている(`var(--font-sans)` ではない)、
|
|
95
|
+
または `ui-sans-serif, system-ui, …` が先頭にある、`"Yu Gothic UI"` が残っているときは、
|
|
96
|
+
`body { font-family: var(--font-sans); }` に直し、書体は `--font-sans` に上の並びで書く。
|
|
95
97
|
日本語の Web フォントは face が 100 を超えるので原則使わない(pptx 書き出しも壊れる。
|
|
96
98
|
`vantage-slide` の `references/tokens.md` 参照)。
|
|
97
99
|
|
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
3. **書体**(見出しと本文の `font-family`。システムフォントで足りるか)
|
|
8
8
|
4. **トーン**(2〜3 語: 「落ち着いた」「明るい」「堅い」…)
|
|
9
9
|
|
|
10
|
-
チャートの 5
|
|
11
|
-
`npx @squadbase/vantage-template
|
|
12
|
-
配慮が済んでいる)
|
|
10
|
+
チャートの 5 色は、主色から直接作るより**主色に最も近いテーマ**を選び、
|
|
11
|
+
`npx @squadbase/vantage-template theme <id>` で適用する方が安全(5 色の明度差・色覚多様性への
|
|
12
|
+
配慮が済んでいる)。テーマと別のチャート配色が要るときは `chart <preset>`。`styles.css` の
|
|
13
|
+
`squadkit-theme` / `vantage-template:chart-preset` のマーカーブロックの中は
|
|
13
14
|
**手で編集しない**(次の適用で消える)。主色を `--chart-1` に入れたいときだけ、マーカーブロックの
|
|
14
15
|
**後ろ**に `:root` と `.dark, [data-theme="dark"]` の `--chart-1` 上書きを足し、残り 4 色は
|
|
15
|
-
プリセットに任せる。`--primary` や `--radius`
|
|
16
|
+
プリセットに任せる。`--primary` や `--radius` はマーカーブロックの後ろに書く。
|
|
16
17
|
|
|
17
18
|
## URL(既存サイトに合わせる)
|
|
18
19
|
|
|
@@ -36,7 +37,7 @@ grep -oE 'font-family:[^;]+' /tmp/site.css | sort | uniq -c | sort -rn | head
|
|
|
36
37
|
3. **ボタン・リンクの色**: `a {` `.btn` `button` `[class*=primary]` のセレクタの `color` /
|
|
37
38
|
`background-color`。出現回数の多い有彩色が主色。
|
|
38
39
|
4. **背景**: `body` / `html` の `background`。暗ければ「暗い基調」。
|
|
39
|
-
5. **書体**: `body` の `font-family
|
|
40
|
+
5. **書体**: `body` の `font-family`(書き込み先は `--font-sans`)。Google Fonts の `<link>` があればその family 名。
|
|
40
41
|
|
|
41
42
|
注意:
|
|
42
43
|
|
|
@@ -66,18 +67,19 @@ grep -oE 'font-family:[^;]+' /tmp/site.css | sort | uniq -c | sort -rn | head
|
|
|
66
67
|
|
|
67
68
|
## 言葉だけ(「落ち着いた感じに」)
|
|
68
69
|
|
|
69
|
-
形容詞を `presets.md` の
|
|
70
|
+
形容詞を `presets.md` の 7 テーマに寄せ、そのうえで主色だけを調整する。
|
|
70
71
|
|
|
71
72
|
| 言われたこと | 出発点 |
|
|
72
73
|
| --- | --- |
|
|
73
|
-
| 落ち着いた・信頼感・堅い・経営向け・青系 | `
|
|
74
|
-
| 明るい・元気・勢い・暖かい・営業向け | `
|
|
74
|
+
| 落ち着いた・信頼感・堅い・経営向け・青系 | `ocean` |
|
|
75
|
+
| 明るい・元気・勢い・暖かい・営業向け | `sunset` |
|
|
75
76
|
| シンプル・モノクロ・印刷する・資料に貼る | `mono` |
|
|
76
|
-
| 特に無し・標準・おまかせ | `
|
|
77
|
-
| 自然・環境・緑 | `
|
|
78
|
-
|
|
|
77
|
+
| 特に無し・標準・おまかせ | `neutral` |
|
|
78
|
+
| 自然・環境・緑 | `forest` |
|
|
79
|
+
| 華やか・ポップ・紫 | `violet` |
|
|
80
|
+
| 華やか・ポップ・ピンク | `rose` |
|
|
79
81
|
|
|
80
|
-
当てはまらない言葉は、2 案(例: `
|
|
82
|
+
当てはまらない言葉は、2 案(例: `ocean` と `neutral`)を並べて選んでもらう。
|
|
81
83
|
|
|
82
84
|
## 外部の DESIGN.md(Stitch などが書いたもの)
|
|
83
85
|
|
|
@@ -99,8 +101,8 @@ Vantage の `DESIGN.md` は値を持たないので、**値を `styles.css` へ
|
|
|
99
101
|
| error | `--destructive` |
|
|
100
102
|
| success / warning | 専用トークンなし → `--chart-*` のどれかに割り当てて `DESIGN.md` に書く |
|
|
101
103
|
| radius / corner | `--radius` |
|
|
102
|
-
| display / headline font | `--slide-font-display`(+ ページの見出しなら
|
|
103
|
-
| body font |
|
|
104
|
+
| display / headline font | `--slide-font-display`(+ ページの見出しなら `--font-sans`) |
|
|
105
|
+
| body font | `--font-sans`(ページ本文)と `--slide-font-body` |
|
|
104
106
|
|
|
105
107
|
3. `styles.css` のマーカーブロックの外に、`:root` と `.dark, [data-theme="dark"]` の両方で書く
|
|
106
108
|
(チャート色・書体の書き方は SKILL.md の手順 3)。外部の DESIGN.md に
|
|
@@ -50,8 +50,8 @@ Components → 「成果物の種類ごとの規則」/ Do's and Don'ts。値は
|
|
|
50
50
|
|
|
51
51
|
- `--muted` `--accent` `--secondary` `--border` は背景・境界用。文字色の役割に割り当てない。
|
|
52
52
|
- 良い / 注意の専用トークンは無い。`--chart-*` の中から割り当てるか、「専用トークンなし」と書く。
|
|
53
|
-
-
|
|
54
|
-
|
|
53
|
+
- ページ本文の書体は `--font-sans`(`styles.css` の `body` が `font-family: var(--font-sans)` で参照する。
|
|
54
|
+
テーマを当てると `--font-sans` もテーマの値になる。変えるときはテーマ範囲のマーカーの後ろで上書きする)。
|
|
55
55
|
- `--slide-bg` などは既定で `--background` などの別名。`.dark` に書き直す必要は無い。
|
|
56
56
|
|
|
57
57
|
## 雛形(中立の既定テーマ)
|
|
@@ -112,14 +112,15 @@ DESIGN.md — このアプリの「見た目の意図」を書くファイルで
|
|
|
112
112
|
- 系列は 5 つまで。それ以上はグループ化するか「その他」にまとめる。
|
|
113
113
|
- 禁止: 同じチャートで `--destructive` を普通の系列色として使う(悪い値に見える)。
|
|
114
114
|
- 禁止: 隣り合う系列に `--chart-3` と `--chart-4` を並べて細い線で描く(見分けにくい)。
|
|
115
|
-
- 配色を丸ごと変えるときは `npx @squadbase/vantage-template
|
|
116
|
-
(`
|
|
115
|
+
- 配色を丸ごと変えるときは `npx @squadbase/vantage-template theme <id>` を使う
|
|
116
|
+
(`neutral` / `ocean` / `forest` / `sunset` / `violet` / `rose` / `mono`)。チャートだけ別の配色にするときは
|
|
117
|
+
`chart <preset>`(`blue` / `ocean` / `sunset` / `forest` / `berry` / `mono`)。
|
|
117
118
|
|
|
118
119
|
## 書体 (Typography)
|
|
119
120
|
|
|
120
121
|
| 用途 | 指定 | 備考 |
|
|
121
122
|
| --- | --- | --- |
|
|
122
|
-
| 見出し・本文 | 日本語を含むシステムフォント(
|
|
123
|
+
| 見出し・本文 | 日本語を含むシステムフォント(`--font-sans`) | Web フォントは使わない |
|
|
123
124
|
| 数字 | 同上 + `tabular-nums` | 桁がそろうように必ず付ける |
|
|
124
125
|
| スライドの見出し | `--slide-font-display` | 既定は日本語を含むシステムフォント |
|
|
125
126
|
| スライドの本文 | `--slide-font-body` | 既定は見出しと同じ |
|