@cboxdk/cbox-ui 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -2
- package/dist/charts.d.ts +82 -0
- package/dist/charts.js +189 -0
- package/dist/charts.js.map +1 -0
- package/dist/chunk-OFTNLF7H.js +55 -0
- package/dist/chunk-OFTNLF7H.js.map +1 -0
- package/dist/engine-4DRZ3POZ.js +10 -0
- package/dist/engine-4DRZ3POZ.js.map +1 -0
- package/dist/index.d.ts +207 -7
- package/dist/index.js +573 -152
- package/dist/index.js.map +1 -1
- package/dist/scale-BaaY5qJs.d.ts +24 -0
- package/package.json +10 -1
- package/tokens/cbox.css +99 -88
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ The package is published on npm as `@cboxdk/cbox-ui` under the MIT License. The
|
|
|
27
27
|
@import '@cboxdk/cbox-ui/tokens';
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
That's it — every `text-foreground`, `bg-card`, `border-border`, `text-mono`, etc. utility now resolves against the Cbox palette. Light + dark variants come bundled.
|
|
30
|
+
That's it — every `text-foreground`, `bg-card`, `border-border`, `text-mono`, etc. utility now resolves against the Cbox palette. Light + dark variants come bundled: dark applies under `.dark` or `data-theme="dark"` on the root, whichever the host writes. Add `@source '../../node_modules/@cboxdk/cbox-ui/dist';` so Tailwind generates the utilities the components use, and when the host stores its theme choice as an attribute, point Tailwind's `dark:` variant at it (`@custom-variant dark (&:where([data-theme='dark'], [data-theme='dark'] *));`).
|
|
31
31
|
|
|
32
32
|
### 2. Wrap the app root with `<CboxIdProvider>`
|
|
33
33
|
|
|
@@ -113,7 +113,8 @@ Match id's existing patterns — see id/resources/js/pages/* for examples.
|
|
|
113
113
|
| `TopBar` | Standard 56px-tall app bar. Slot for brand + centre + right cluster. |
|
|
114
114
|
| `OrgSwitcher` | Dropdown listing the user's orgs. Calls `onSwitchOrganization` (or POSTs to `urls.switchOrgUrl`) on pick. |
|
|
115
115
|
| `AppLauncher` | 9-dot grid showing sister Cbox apps the user can jump into. |
|
|
116
|
-
| `UserMenu` | Avatar dropdown with "Manage account ↗" + "Team & billing ↗" (deep-links into id) + Sign out. |
|
|
116
|
+
| `UserMenu` | Avatar dropdown with "Manage account ↗" + "Team & billing ↗" (deep-links into id) + Sign out. Pass `LinkComponent` when those rows are pages of the host app, so the visit stays client-side. |
|
|
117
|
+
| `CboxAppCatalog` | The Switch-app control fed live from the host's catalog endpoint (see "App catalog" below). |
|
|
117
118
|
| `NotificationsBell` | Bell icon with unread badge, links to id's unified inbox. Renders nothing if context lacks `notifications`. |
|
|
118
119
|
|
|
119
120
|
### Page primitives
|
|
@@ -130,6 +131,17 @@ Match id's existing patterns — see id/resources/js/pages/* for examples.
|
|
|
130
131
|
| `KeyValue` / `KeyValueList` | Definition-list style "label → value" for detail panels. |
|
|
131
132
|
| `Heading` | Section heading without the panel chrome. |
|
|
132
133
|
|
|
134
|
+
### Charts
|
|
135
|
+
|
|
136
|
+
Time series use ECharts, from the `@cboxdk/cbox-ui/charts` entry so apps without charts never load it. Install `echarts` (^6) next to cbox-ui to use it; ECharts itself is fetched on the first chart's mount.
|
|
137
|
+
|
|
138
|
+
| Export | What it does |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `TimeChart` (`/charts`) | Lines over a time window drawn to scale from zero with round ticks, a faint area under the primary series, thin lines for the rest (one per pod, say), labelled vertical lines for `events` (deploys, scaling), gaps for missing samples, an axis tooltip, and zoom by slider, pinch or Ctrl/⌘ + scroll. Colours come from `--chart-1…5` and follow dark mode. Times are milliseconds. Keep a table of the same numbers beside it. |
|
|
141
|
+
| `Chart` (`/charts`) | The ECharts wrapper under it: SVG renderer, token colours, theme and reduced-motion aware. Build other chart types on it. |
|
|
142
|
+
| `Sparkline` | A small decorative SVG line for table rows. No ECharts. |
|
|
143
|
+
| `niceTicks` / `timeTicks` / `seriesData` | The axis and gap arithmetic. |
|
|
144
|
+
|
|
133
145
|
## Versioning
|
|
134
146
|
|
|
135
147
|
This package follows semver. **Breaking changes get a major bump** — every Cbox app pinning a major version stays safe. New components, new optional props, new tokens → minor. Token tweaks that don't change the visual contract → patch.
|
|
@@ -154,3 +166,89 @@ Switch back to the published version with `bun unlink @cboxdk/cbox-ui && bun ins
|
|
|
154
166
|
## Brand
|
|
155
167
|
|
|
156
168
|
Brand guidelines, logo files, and the canonical asset set live in [`BRAND.md`](./BRAND.md) and `assets/`.
|
|
169
|
+
|
|
170
|
+
## Localization
|
|
171
|
+
|
|
172
|
+
Wrap the app shell in `CboxLocalizationProvider` to translate shared navigation,
|
|
173
|
+
menus, placeholders and accessible labels. Existing consumers keep English when
|
|
174
|
+
no provider is present. The host owns the selected language and its catalogs:
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
<CboxLocalizationProvider locale={language} translate={t}>
|
|
178
|
+
<CboxAppShell {...shellProps}>{children}</CboxAppShell>
|
|
179
|
+
</CboxLocalizationProvider>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`translate(message, values?)` returns plain text. Messages use English source
|
|
183
|
+
keys and named placeholders, such as `Settings for {name}`. Preserve placeholders
|
|
184
|
+
when translating. React escapes the returned text; do not return HTML. Consumer
|
|
185
|
+
labels, notification content, organization names and other user data remain the
|
|
186
|
+
host's responsibility. The provider does not persist settings or infer regional
|
|
187
|
+
number/date formats from interface language. Cbox apps read those preferences
|
|
188
|
+
from Cbox ID's versioned `preferences` namespace.
|
|
189
|
+
|
|
190
|
+
Pass an optional `formatDate(isoTimestamp)` callback when the host manages date
|
|
191
|
+
format and timezone preferences separately. Notification timestamps use that
|
|
192
|
+
callback; without it, existing browser formatting is preserved.
|
|
193
|
+
|
|
194
|
+
### App catalog (Switch app)
|
|
195
|
+
|
|
196
|
+
`AppSwitcher` and `AppLauncher` render the static `apps` list from `CboxIdProvider`. Apps
|
|
197
|
+
that read the person's catalog live from Cbox ID use `CboxAppCatalog` instead: the host
|
|
198
|
+
serves a same-origin endpoint (a proxy of Cbox ID's catalog under the signed-in person's
|
|
199
|
+
grant) and the component renders its answer, refreshes it when `refresh_after` expires
|
|
200
|
+
while the panel is open, and offers the way back to Cbox ID when the grant is missing.
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
<CboxAppCatalog endpoint={appCatalogUrl} currentAppKey="infra" />
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The endpoint contract (`parseAppCatalog` is exported, so a host can test its own answer):
|
|
207
|
+
|
|
208
|
+
- `200 { apps: [{ key, name, launch_url, icon_url?, icon_dark_url?, description? }], refresh_after?: seconds }`
|
|
209
|
+
— `refresh_after` is clamped to 1–60 s; apps without an `http(s)` launch URL are dropped.
|
|
210
|
+
- `401`/`403` with `{ authorize_url }` or `{ state: 'authorization_required' }` — the panel
|
|
211
|
+
says the apps could not be loaded and links "Reconnect to Cbox ID" to `authorize_url` with
|
|
212
|
+
`return_to` set to the current path (same-origin URLs only).
|
|
213
|
+
- Anything else — "Apps could not be loaded." with a retry.
|
|
214
|
+
|
|
215
|
+
`endpoint={null}` renders the control disabled, so the chrome keeps its shape on pages
|
|
216
|
+
without an organization.
|
|
217
|
+
|
|
218
|
+
App icons come from Cbox ID's catalog: `icon_url` for light surfaces and `icon_dark_url` for
|
|
219
|
+
dark ones. The tiles render both and the token stylesheet shows the one for the current theme
|
|
220
|
+
(`.dark` or `[data-theme="dark"]` on the root); an app without an icon shows its initials. Apps
|
|
221
|
+
keep no local copy of the marks. Each answer is kept in this browser (`cbox-app-catalog`), so
|
|
222
|
+
`<CboxServiceMark appKey="infra" />` and the collapsed `CboxBrand` in the rail paint the app's
|
|
223
|
+
own icon at once on the next page. A host that loads the catalog itself calls
|
|
224
|
+
`rememberAppCatalog(apps)`; `CboxAppIcon` renders any single app's icon.
|
|
225
|
+
|
|
226
|
+
### Workspace navigation (current design contract)
|
|
227
|
+
|
|
228
|
+
`CboxWorkspaceShell` is the two-tier product shell. Pass `areas` (each has a
|
|
229
|
+
label, href, icon and optional child `items`), the router's `currentPath` and
|
|
230
|
+
`LinkComponent`, plus `context`, `tools` and `account` slots. Include the real
|
|
231
|
+
organization context, search, notifications and Switch app in these slots;
|
|
232
|
+
render `UserMenu placement="top-start"` in `account`. The account stays at the
|
|
233
|
+
bottom of the main rail. Existing `CboxAppShell` consumers retain their API.
|
|
234
|
+
|
|
235
|
+
The rail reserves 64px, expands on hover/focus without moving content, and
|
|
236
|
+
reserves 222px when pinned. Context navigation only appears for multi-page
|
|
237
|
+
areas; its panel button and Command/Control-period collapse it to a 26px strip.
|
|
238
|
+
Mobile uses a modal navigation sheet and retains the header app switcher.
|
|
239
|
+
Query strings do not change active navigation, and the **most specific href wins**: an
|
|
240
|
+
area at the organization root (`/acme`) does not claim `/acme/projects/...` when a
|
|
241
|
+
Projects area exists, and inside a subnav only the deepest matching item is active. Active
|
|
242
|
+
links carry `aria-current="page"`.
|
|
243
|
+
|
|
244
|
+
Hosts own route construction, organization switching, search and preference persistence.
|
|
245
|
+
For the two shell preferences the host persists, pass them in: `pinned` + `onPinnedChange`
|
|
246
|
+
and `collapsed` + `onCollapsedChange` (controlled), or `defaultPinned` / `defaultCollapsed`
|
|
247
|
+
to seed the shell's own state. `brandHref` points the brand row somewhere other than `/`
|
|
248
|
+
(the current organization's overview), and `mainId` names the `<main>` landmark for the
|
|
249
|
+
host's skip link (default `main-content`).
|
|
250
|
+
|
|
251
|
+
Core tokens now match the warm cream/ink design-system colors. Body text uses
|
|
252
|
+
the system stack; hosts self-host Plus Jakarta Sans for headings and JetBrains
|
|
253
|
+
Mono for technical values. Card/control/badge radii are 12/8/6px. The main canvas
|
|
254
|
+
uses the approved single radial wash at 30% 0 in both themes.
|
package/dist/charts.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { EChartsCoreOption } from 'echarts/core';
|
|
3
|
+
import { T as TimePoint } from './scale-BaaY5qJs.js';
|
|
4
|
+
export { S as SeriesDatum, n as niceTicks, s as seriesData, t as timeTicks } from './scale-BaaY5qJs.js';
|
|
5
|
+
|
|
6
|
+
/** The chart colours of the mode on screen, read from the design tokens. */
|
|
7
|
+
type ChartColors = {
|
|
8
|
+
series: string[];
|
|
9
|
+
text: string;
|
|
10
|
+
muted: string;
|
|
11
|
+
grid: string;
|
|
12
|
+
surface: string;
|
|
13
|
+
border: string;
|
|
14
|
+
font: string;
|
|
15
|
+
mono: string;
|
|
16
|
+
};
|
|
17
|
+
declare function readChartColors(): ChartColors;
|
|
18
|
+
/** Follows the theme switch: the `dark` class and `data-theme` on <html>, and the OS setting. */
|
|
19
|
+
declare function useChartColors(): ChartColors;
|
|
20
|
+
/**
|
|
21
|
+
* One ECharts chart, the Cbox convention: SVG renderer, sized by its box, ECharts imported on
|
|
22
|
+
* first mount. The option is built from the colours on screen, so light and dark follow, and
|
|
23
|
+
* animation is off under reduced motion. `label` is what a screen reader hears; keep a table
|
|
24
|
+
* of the same numbers beside the chart. Keep `option` stable (useCallback) to avoid redraws.
|
|
25
|
+
*/
|
|
26
|
+
declare function Chart({ option, label, height, className }: {
|
|
27
|
+
option: (colors: ChartColors) => EChartsCoreOption;
|
|
28
|
+
label: string;
|
|
29
|
+
height?: number;
|
|
30
|
+
className?: string;
|
|
31
|
+
}): react_jsx_runtime.JSX.Element;
|
|
32
|
+
|
|
33
|
+
type TimeSeries = {
|
|
34
|
+
key: string;
|
|
35
|
+
label: string;
|
|
36
|
+
/** Contiguous runs of samples; a new run starts after a gap, which is drawn as a gap. */
|
|
37
|
+
segments: TimePoint[][];
|
|
38
|
+
/** The headline series: drawn with a faint area. Defaults to the first series. */
|
|
39
|
+
primary?: boolean;
|
|
40
|
+
/** A reference to read the others against (last week, a limit): dashed, no area. */
|
|
41
|
+
dashed?: boolean;
|
|
42
|
+
};
|
|
43
|
+
/** A moment worth explaining (a deploy, a scale step): a labelled vertical line, never a cause claim. */
|
|
44
|
+
type ChartEvent = {
|
|
45
|
+
/** Milliseconds since the epoch. */
|
|
46
|
+
at: number;
|
|
47
|
+
label: string;
|
|
48
|
+
/** Index into the chart tokens; deploys use 1 and scaling 2 by convention. */
|
|
49
|
+
tone?: number;
|
|
50
|
+
/** Extra tooltip line, such as the end time and outcome. Plain text. */
|
|
51
|
+
detail?: string;
|
|
52
|
+
};
|
|
53
|
+
type TimeChartProps = {
|
|
54
|
+
series: TimeSeries[];
|
|
55
|
+
/** The window, in milliseconds. */
|
|
56
|
+
from: number;
|
|
57
|
+
to: number;
|
|
58
|
+
/** Accessible name; keep a table of the same numbers next to the chart. */
|
|
59
|
+
label: string;
|
|
60
|
+
formatValue: (value: number) => string;
|
|
61
|
+
/** Axis and tooltip time. Say the zone once beside the chart. */
|
|
62
|
+
formatTime?: (t: number) => string;
|
|
63
|
+
/** Appended to values in the tooltip. */
|
|
64
|
+
unit?: string;
|
|
65
|
+
/** Lowest top of the y axis, so a flat near-zero line does not fill the plot. */
|
|
66
|
+
minimumTop?: number;
|
|
67
|
+
events?: ChartEvent[];
|
|
68
|
+
/** A moment marked with a dashed line, such as a selected request. */
|
|
69
|
+
marker?: number | null;
|
|
70
|
+
/** Zoom by slider, pinch or Ctrl/⌘ + scroll. On by default. */
|
|
71
|
+
zoom?: boolean;
|
|
72
|
+
height?: number;
|
|
73
|
+
className?: string;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* THE CBOX TIME CHART (ECharts): drawn to scale from zero with round ticks, a line with a
|
|
77
|
+
* faint area for the headline series, thin lines for the rest, labelled vertical lines for
|
|
78
|
+
* events, gaps for missing samples, an axis tooltip with every series, and zoom.
|
|
79
|
+
*/
|
|
80
|
+
declare function TimeChart({ series, from, to, label, formatValue, formatTime, unit, minimumTop, events, marker, zoom, height, className }: TimeChartProps): react_jsx_runtime.JSX.Element;
|
|
81
|
+
|
|
82
|
+
export { Chart, type ChartColors, type ChartEvent, TimeChart, type TimeChartProps, TimePoint, type TimeSeries, readChartColors, useChartColors };
|
package/dist/charts.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { cn, niceTicks, seriesData } from './chunk-OFTNLF7H.js';
|
|
2
|
+
export { niceTicks, seriesData, timeTicks } from './chunk-OFTNLF7H.js';
|
|
3
|
+
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
function readChartColors() {
|
|
7
|
+
const style = getComputedStyle(document.documentElement);
|
|
8
|
+
const token = (name, fallback) => style.getPropertyValue(name).trim() || fallback;
|
|
9
|
+
return {
|
|
10
|
+
series: [1, 2, 3, 4, 5].map((index) => token(`--chart-${index}`, "#2a78d6")),
|
|
11
|
+
text: token("--foreground", "#1f1a13"),
|
|
12
|
+
muted: token("--muted-foreground", "#6a6257"),
|
|
13
|
+
grid: token("--border", "#e2ded5"),
|
|
14
|
+
surface: token("--popover", "#fffefc"),
|
|
15
|
+
border: token("--border", "#e2ded5"),
|
|
16
|
+
font: getComputedStyle(document.body).fontFamily,
|
|
17
|
+
mono: token("--font-mono", "") || "ui-monospace, SFMono-Regular, Menlo, Monaco, monospace"
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function useChartColors() {
|
|
21
|
+
const [colors, setColors] = useState(readChartColors);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const update = () => setColors(readChartColors());
|
|
24
|
+
const observer = new MutationObserver(update);
|
|
25
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class", "data-theme"] });
|
|
26
|
+
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
27
|
+
media.addEventListener("change", update);
|
|
28
|
+
return () => {
|
|
29
|
+
observer.disconnect();
|
|
30
|
+
media.removeEventListener("change", update);
|
|
31
|
+
};
|
|
32
|
+
}, []);
|
|
33
|
+
return colors;
|
|
34
|
+
}
|
|
35
|
+
function Chart({ option, label, height = 220, className }) {
|
|
36
|
+
const box = useRef(null);
|
|
37
|
+
const [chart, setChart] = useState(null);
|
|
38
|
+
const colors = useChartColors();
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
let disposed = false;
|
|
41
|
+
let instance = null;
|
|
42
|
+
let resize = null;
|
|
43
|
+
void import('./engine-4DRZ3POZ.js').then(({ echarts }) => {
|
|
44
|
+
const element = box.current;
|
|
45
|
+
if (disposed || !element) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
instance = echarts.init(element, null, { renderer: "svg" });
|
|
49
|
+
resize = new ResizeObserver(() => instance?.resize());
|
|
50
|
+
resize.observe(element);
|
|
51
|
+
setChart(instance);
|
|
52
|
+
});
|
|
53
|
+
return () => {
|
|
54
|
+
disposed = true;
|
|
55
|
+
resize?.disconnect();
|
|
56
|
+
instance?.dispose();
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (!chart) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
64
|
+
chart.setOption({ animation: !reduce, aria: { enabled: true, label: { description: label } }, ...option(colors) }, true);
|
|
65
|
+
}, [chart, option, colors, label]);
|
|
66
|
+
return /* @__PURE__ */ jsx("div", { ref: box, style: { height }, role: "img", "aria-label": label, className: cn("w-full", className) });
|
|
67
|
+
}
|
|
68
|
+
var defaultTime = (t) => new Intl.DateTimeFormat(void 0, { hour: "2-digit", minute: "2-digit", hour12: false }).format(t);
|
|
69
|
+
var escape = (text) => text.replace(/[&<>"']/g, (character) => `&#${character.charCodeAt(0)};`);
|
|
70
|
+
function TimeChart({ series, from, to, label, formatValue, formatTime = defaultTime, unit = "", minimumTop = 0, events = [], marker = null, zoom = true, height = 260, className }) {
|
|
71
|
+
const option = useCallback(
|
|
72
|
+
(colors) => {
|
|
73
|
+
const ticks = niceTicks(Math.max(minimumTop, ...series.flatMap((item) => item.segments.flat().map((point) => point.value))));
|
|
74
|
+
const top = ticks[ticks.length - 1] ?? 1;
|
|
75
|
+
const axisLabel = { color: colors.muted, fontFamily: colors.mono, fontSize: 11 };
|
|
76
|
+
const primary = Math.max(0, series.findIndex((item) => item.primary));
|
|
77
|
+
const tone = (index) => colors.series[index % colors.series.length] ?? colors.text;
|
|
78
|
+
const value = (number) => `${formatValue(number)}${unit ? ` ${unit}` : ""}`;
|
|
79
|
+
const lines = [
|
|
80
|
+
...events.filter((event) => event.at >= from && event.at <= to).map((event) => ({
|
|
81
|
+
xAxis: event.at,
|
|
82
|
+
name: event.label,
|
|
83
|
+
event,
|
|
84
|
+
lineStyle: { color: tone(event.tone ?? 1), type: "solid", width: 1, opacity: 0.8 },
|
|
85
|
+
label: { show: true, formatter: event.label, position: "insideEndTop", color: tone(event.tone ?? 1), fontFamily: colors.mono, fontSize: 10 }
|
|
86
|
+
})),
|
|
87
|
+
...marker !== null && marker >= from && marker <= to ? [{ xAxis: marker, name: "", lineStyle: { color: colors.text, type: "dashed", width: 1 }, label: { show: false } }] : []
|
|
88
|
+
];
|
|
89
|
+
return {
|
|
90
|
+
color: colors.series,
|
|
91
|
+
textStyle: { fontFamily: colors.font, color: colors.text },
|
|
92
|
+
grid: { top: 16, right: 16, bottom: zoom ? 56 : 24, left: 56 },
|
|
93
|
+
xAxis: {
|
|
94
|
+
type: "time",
|
|
95
|
+
min: from,
|
|
96
|
+
max: to,
|
|
97
|
+
axisLine: { lineStyle: { color: colors.grid } },
|
|
98
|
+
axisTick: { show: false },
|
|
99
|
+
splitLine: { show: false },
|
|
100
|
+
axisLabel: { ...axisLabel, hideOverlap: true, formatter: (t) => formatTime(t) }
|
|
101
|
+
},
|
|
102
|
+
yAxis: {
|
|
103
|
+
type: "value",
|
|
104
|
+
min: 0,
|
|
105
|
+
max: top,
|
|
106
|
+
interval: top / Math.max(1, ticks.length - 1),
|
|
107
|
+
axisLabel: { ...axisLabel, formatter: (number) => formatValue(number) },
|
|
108
|
+
splitLine: { lineStyle: { color: colors.grid, type: "dashed" } }
|
|
109
|
+
},
|
|
110
|
+
dataZoom: zoom ? [
|
|
111
|
+
{ type: "inside", xAxisIndex: 0, filterMode: "none", zoomOnMouseWheel: "ctrl", moveOnMouseWheel: false, moveOnMouseMove: true },
|
|
112
|
+
{
|
|
113
|
+
type: "slider",
|
|
114
|
+
xAxisIndex: 0,
|
|
115
|
+
filterMode: "none",
|
|
116
|
+
height: 18,
|
|
117
|
+
bottom: 8,
|
|
118
|
+
borderColor: colors.grid,
|
|
119
|
+
fillerColor: "rgba(127,127,127,0.12)",
|
|
120
|
+
handleStyle: { color: colors.surface, borderColor: colors.muted },
|
|
121
|
+
moveHandleSize: 0,
|
|
122
|
+
showDetail: false,
|
|
123
|
+
dataBackground: { lineStyle: { color: colors.muted, opacity: 0.4 }, areaStyle: { opacity: 0 } },
|
|
124
|
+
selectedDataBackground: { lineStyle: { color: tone(0) }, areaStyle: { opacity: 0 } },
|
|
125
|
+
textStyle: axisLabel
|
|
126
|
+
}
|
|
127
|
+
] : [],
|
|
128
|
+
tooltip: {
|
|
129
|
+
trigger: "axis",
|
|
130
|
+
confine: true,
|
|
131
|
+
backgroundColor: colors.surface,
|
|
132
|
+
borderColor: colors.border,
|
|
133
|
+
borderWidth: 1,
|
|
134
|
+
padding: [6, 10],
|
|
135
|
+
textStyle: { color: colors.text, fontFamily: colors.mono, fontSize: 12 },
|
|
136
|
+
axisPointer: { type: "line", lineStyle: { color: colors.muted, opacity: 0.5 } },
|
|
137
|
+
formatter: (items) => {
|
|
138
|
+
const present = items.filter((item) => item.value[1] !== null);
|
|
139
|
+
const first = present[0];
|
|
140
|
+
if (!first) {
|
|
141
|
+
return "";
|
|
142
|
+
}
|
|
143
|
+
const rows = present.map(
|
|
144
|
+
(item) => series.length > 1 ? `<span style="color:${item.color}">\u25CF</span> ${escape(item.seriesName)} <b>${escape(value(item.value[1] ?? 0))}</b>` : `<b>${escape(value(item.value[1] ?? 0))}</b>`
|
|
145
|
+
);
|
|
146
|
+
return `${escape(formatTime(first.value[0]))}<br/>${rows.join("<br/>")}`;
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
series: series.map((item, index) => {
|
|
150
|
+
const color = tone(index);
|
|
151
|
+
const isPrimary = index === primary;
|
|
152
|
+
return {
|
|
153
|
+
type: "line",
|
|
154
|
+
name: item.label,
|
|
155
|
+
data: seriesData(item.segments),
|
|
156
|
+
connectNulls: false,
|
|
157
|
+
symbol: "circle",
|
|
158
|
+
symbolSize: 0,
|
|
159
|
+
lineStyle: { width: isPrimary ? 1.5 : 1, color, type: item.dashed ? "dashed" : "solid" },
|
|
160
|
+
itemStyle: { color },
|
|
161
|
+
areaStyle: isPrimary && !item.dashed ? { opacity: 0.14, color } : void 0,
|
|
162
|
+
emphasis: { disabled: true },
|
|
163
|
+
z: isPrimary ? 3 : 2,
|
|
164
|
+
markLine: isPrimary && lines.length > 0 ? {
|
|
165
|
+
silent: false,
|
|
166
|
+
symbol: "none",
|
|
167
|
+
data: lines,
|
|
168
|
+
tooltip: {
|
|
169
|
+
formatter: (entry) => {
|
|
170
|
+
const event = entry.data.event;
|
|
171
|
+
if (!event) {
|
|
172
|
+
return escape(entry.data.name);
|
|
173
|
+
}
|
|
174
|
+
return `${escape(event.label)}<br/>${escape(formatTime(event.at))}${event.detail ? ` \xB7 ${escape(event.detail)}` : ""}`;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} : void 0
|
|
178
|
+
};
|
|
179
|
+
})
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
[series, from, to, formatValue, formatTime, unit, minimumTop, events, marker, zoom]
|
|
183
|
+
);
|
|
184
|
+
return /* @__PURE__ */ jsx(Chart, { option, label, height, className });
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export { Chart, TimeChart, readChartColors, useChartColors };
|
|
188
|
+
//# sourceMappingURL=charts.js.map
|
|
189
|
+
//# sourceMappingURL=charts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/charts/chart.tsx","../src/charts/time-chart.tsx"],"names":["jsx"],"mappings":"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","file":"charts.js","sourcesContent":["import type { ECharts, EChartsCoreOption } from 'echarts/core';\nimport { useEffect, useRef, useState } from 'react';\nimport { cn } from '../utils/cn';\n\n/** The chart colours of the mode on screen, read from the design tokens. */\nexport type ChartColors = {\n series: string[];\n text: string;\n muted: string;\n grid: string;\n surface: string;\n border: string;\n font: string;\n mono: string;\n};\n\nexport function readChartColors(): ChartColors {\n const style = getComputedStyle(document.documentElement);\n const token = (name: string, fallback: string) => style.getPropertyValue(name).trim() || fallback;\n\n return {\n series: [1, 2, 3, 4, 5].map((index) => token(`--chart-${index}`, '#2a78d6')),\n text: token('--foreground', '#1f1a13'),\n muted: token('--muted-foreground', '#6a6257'),\n grid: token('--border', '#e2ded5'),\n surface: token('--popover', '#fffefc'),\n border: token('--border', '#e2ded5'),\n font: getComputedStyle(document.body).fontFamily,\n mono: token('--font-mono', '') || 'ui-monospace, SFMono-Regular, Menlo, Monaco, monospace',\n };\n}\n\n/** Follows the theme switch: the `dark` class and `data-theme` on <html>, and the OS setting. */\nexport function useChartColors(): ChartColors {\n const [colors, setColors] = useState(readChartColors);\n\n useEffect(() => {\n const update = () => setColors(readChartColors());\n const observer = new MutationObserver(update);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class', 'data-theme'] });\n const media = window.matchMedia('(prefers-color-scheme: dark)');\n media.addEventListener('change', update);\n\n return () => {\n observer.disconnect();\n media.removeEventListener('change', update);\n };\n }, []);\n\n return colors;\n}\n\n/**\n * One ECharts chart, the Cbox convention: SVG renderer, sized by its box, ECharts imported on\n * first mount. The option is built from the colours on screen, so light and dark follow, and\n * animation is off under reduced motion. `label` is what a screen reader hears; keep a table\n * of the same numbers beside the chart. Keep `option` stable (useCallback) to avoid redraws.\n */\nexport function Chart({ option, label, height = 220, className }: { option: (colors: ChartColors) => EChartsCoreOption; label: string; height?: number; className?: string }) {\n const box = useRef<HTMLDivElement>(null);\n const [chart, setChart] = useState<ECharts | null>(null);\n const colors = useChartColors();\n\n useEffect(() => {\n let disposed = false;\n let instance: ECharts | null = null;\n let resize: ResizeObserver | null = null;\n\n void import('./engine').then(({ echarts }) => {\n const element = box.current;\n\n if (disposed || !element) {\n return;\n }\n\n instance = echarts.init(element, null, { renderer: 'svg' });\n resize = new ResizeObserver(() => instance?.resize());\n resize.observe(element);\n setChart(instance);\n });\n\n return () => {\n disposed = true;\n resize?.disconnect();\n instance?.dispose();\n };\n }, []);\n\n useEffect(() => {\n if (!chart) {\n return;\n }\n\n const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n chart.setOption({ animation: !reduce, aria: { enabled: true, label: { description: label } }, ...option(colors) }, true);\n }, [chart, option, colors, label]);\n\n return <div ref={box} style={{ height }} role=\"img\" aria-label={label} className={cn('w-full', className)} />;\n}\n","import { useCallback } from 'react';\nimport { Chart, type ChartColors } from './chart';\nimport { niceTicks, seriesData, type TimePoint } from './scale';\n\nexport type TimeSeries = {\n key: string;\n label: string;\n /** Contiguous runs of samples; a new run starts after a gap, which is drawn as a gap. */\n segments: TimePoint[][];\n /** The headline series: drawn with a faint area. Defaults to the first series. */\n primary?: boolean;\n /** A reference to read the others against (last week, a limit): dashed, no area. */\n dashed?: boolean;\n};\n\n/** A moment worth explaining (a deploy, a scale step): a labelled vertical line, never a cause claim. */\nexport type ChartEvent = {\n /** Milliseconds since the epoch. */\n at: number;\n label: string;\n /** Index into the chart tokens; deploys use 1 and scaling 2 by convention. */\n tone?: number;\n /** Extra tooltip line, such as the end time and outcome. Plain text. */\n detail?: string;\n};\n\nexport type TimeChartProps = {\n series: TimeSeries[];\n /** The window, in milliseconds. */\n from: number;\n to: number;\n /** Accessible name; keep a table of the same numbers next to the chart. */\n label: string;\n formatValue: (value: number) => string;\n /** Axis and tooltip time. Say the zone once beside the chart. */\n formatTime?: (t: number) => string;\n /** Appended to values in the tooltip. */\n unit?: string;\n /** Lowest top of the y axis, so a flat near-zero line does not fill the plot. */\n minimumTop?: number;\n events?: ChartEvent[];\n /** A moment marked with a dashed line, such as a selected request. */\n marker?: number | null;\n /** Zoom by slider, pinch or Ctrl/⌘ + scroll. On by default. */\n zoom?: boolean;\n height?: number;\n className?: string;\n};\n\nconst defaultTime = (t: number) => new Intl.DateTimeFormat(undefined, { hour: '2-digit', minute: '2-digit', hour12: false }).format(t);\n\nconst escape = (text: string) => text.replace(/[&<>\"']/g, (character) => `&#${character.charCodeAt(0)};`);\n\n/**\n * THE CBOX TIME CHART (ECharts): drawn to scale from zero with round ticks, a line with a\n * faint area for the headline series, thin lines for the rest, labelled vertical lines for\n * events, gaps for missing samples, an axis tooltip with every series, and zoom.\n */\nexport function TimeChart({ series, from, to, label, formatValue, formatTime = defaultTime, unit = '', minimumTop = 0, events = [], marker = null, zoom = true, height = 260, className }: TimeChartProps) {\n const option = useCallback(\n (colors: ChartColors) => {\n const ticks = niceTicks(Math.max(minimumTop, ...series.flatMap((item) => item.segments.flat().map((point) => point.value))));\n const top = ticks[ticks.length - 1] ?? 1;\n const axisLabel = { color: colors.muted, fontFamily: colors.mono, fontSize: 11 };\n const primary = Math.max(0, series.findIndex((item) => item.primary));\n const tone = (index: number) => colors.series[index % colors.series.length] ?? colors.text;\n const value = (number: number) => `${formatValue(number)}${unit ? ` ${unit}` : ''}`;\n const lines = [\n ...events\n .filter((event) => event.at >= from && event.at <= to)\n .map((event) => ({\n xAxis: event.at,\n name: event.label,\n event,\n lineStyle: { color: tone(event.tone ?? 1), type: 'solid', width: 1, opacity: 0.8 },\n label: { show: true, formatter: event.label, position: 'insideEndTop', color: tone(event.tone ?? 1), fontFamily: colors.mono, fontSize: 10 },\n })),\n ...(marker !== null && marker >= from && marker <= to ? [{ xAxis: marker, name: '', lineStyle: { color: colors.text, type: 'dashed', width: 1 }, label: { show: false } }] : []),\n ];\n\n return {\n color: colors.series,\n textStyle: { fontFamily: colors.font, color: colors.text },\n grid: { top: 16, right: 16, bottom: zoom ? 56 : 24, left: 56 },\n xAxis: {\n type: 'time',\n min: from,\n max: to,\n axisLine: { lineStyle: { color: colors.grid } },\n axisTick: { show: false },\n splitLine: { show: false },\n axisLabel: { ...axisLabel, hideOverlap: true, formatter: (t: number) => formatTime(t) },\n },\n yAxis: {\n type: 'value',\n min: 0,\n max: top,\n interval: top / Math.max(1, ticks.length - 1),\n axisLabel: { ...axisLabel, formatter: (number: number) => formatValue(number) },\n splitLine: { lineStyle: { color: colors.grid, type: 'dashed' } },\n },\n dataZoom: zoom\n ? [\n { type: 'inside', xAxisIndex: 0, filterMode: 'none', zoomOnMouseWheel: 'ctrl', moveOnMouseWheel: false, moveOnMouseMove: true },\n {\n type: 'slider',\n xAxisIndex: 0,\n filterMode: 'none',\n height: 18,\n bottom: 8,\n borderColor: colors.grid,\n fillerColor: 'rgba(127,127,127,0.12)',\n handleStyle: { color: colors.surface, borderColor: colors.muted },\n moveHandleSize: 0,\n showDetail: false,\n dataBackground: { lineStyle: { color: colors.muted, opacity: 0.4 }, areaStyle: { opacity: 0 } },\n selectedDataBackground: { lineStyle: { color: tone(0) }, areaStyle: { opacity: 0 } },\n textStyle: axisLabel,\n },\n ]\n : [],\n tooltip: {\n trigger: 'axis',\n confine: true,\n backgroundColor: colors.surface,\n borderColor: colors.border,\n borderWidth: 1,\n padding: [6, 10],\n textStyle: { color: colors.text, fontFamily: colors.mono, fontSize: 12 },\n axisPointer: { type: 'line', lineStyle: { color: colors.muted, opacity: 0.5 } },\n formatter: (items: { seriesName: string; color: string; value: [number, number | null] }[]) => {\n const present = items.filter((item) => item.value[1] !== null);\n const first = present[0];\n\n if (!first) {\n return '';\n }\n\n const rows = present.map((item) =>\n series.length > 1 ? `<span style=\"color:${item.color}\">●</span> ${escape(item.seriesName)} <b>${escape(value(item.value[1] ?? 0))}</b>` : `<b>${escape(value(item.value[1] ?? 0))}</b>`,\n );\n\n return `${escape(formatTime(first.value[0]))}<br/>${rows.join('<br/>')}`;\n },\n },\n series: series.map((item, index) => {\n const color = tone(index);\n const isPrimary = index === primary;\n\n return {\n type: 'line',\n name: item.label,\n data: seriesData(item.segments),\n connectNulls: false,\n symbol: 'circle',\n symbolSize: 0,\n lineStyle: { width: isPrimary ? 1.5 : 1, color, type: item.dashed ? 'dashed' : 'solid' },\n itemStyle: { color },\n areaStyle: isPrimary && !item.dashed ? { opacity: 0.14, color } : undefined,\n emphasis: { disabled: true },\n z: isPrimary ? 3 : 2,\n markLine:\n isPrimary && lines.length > 0\n ? {\n silent: false,\n symbol: 'none',\n data: lines,\n tooltip: {\n formatter: (entry: { data: { event?: ChartEvent; name: string } }) => {\n const event = entry.data.event;\n\n if (!event) {\n return escape(entry.data.name);\n }\n\n return `${escape(event.label)}<br/>${escape(formatTime(event.at))}${event.detail ? ` · ${escape(event.detail)}` : ''}`;\n },\n },\n }\n : undefined,\n };\n }),\n };\n },\n [series, from, to, formatValue, formatTime, unit, minimumTop, events, marker, zoom],\n );\n\n return <Chart option={option} label={label} height={height} className={className} />;\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
// src/utils/cn.ts
|
|
5
|
+
function cn(...inputs) {
|
|
6
|
+
return twMerge(clsx(inputs));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/charts/scale.ts
|
|
10
|
+
function niceTicks(max, count = 4) {
|
|
11
|
+
const top = max > 0 && Number.isFinite(max) ? max : 1;
|
|
12
|
+
const raw = top / count;
|
|
13
|
+
const power = 10 ** Math.floor(Math.log10(raw));
|
|
14
|
+
const fraction = raw / power;
|
|
15
|
+
const step = (fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 2.5 ? 2.5 : fraction <= 5 ? 5 : 10) * power;
|
|
16
|
+
const ticks = [];
|
|
17
|
+
for (let value = 0; value < top + step * 0.999; value += step) {
|
|
18
|
+
ticks.push(Number(value.toPrecision(12)));
|
|
19
|
+
}
|
|
20
|
+
if (ticks.length < 2) {
|
|
21
|
+
ticks.push(step);
|
|
22
|
+
}
|
|
23
|
+
return ticks;
|
|
24
|
+
}
|
|
25
|
+
var MINUTE = 6e4;
|
|
26
|
+
var STEPS = [1, 2, 5, 10, 15, 30, 60, 120, 180, 360, 720, 1440, 2880, 10080].map((minutes) => minutes * MINUTE);
|
|
27
|
+
function timeTicks(from, to, width) {
|
|
28
|
+
const most = Math.max(2, Math.floor(width / 84));
|
|
29
|
+
const step = STEPS.find((candidate) => (to - from) / candidate <= most) ?? 7 * 1440 * MINUTE;
|
|
30
|
+
const ticks = [];
|
|
31
|
+
for (let tick = Math.ceil(from / step) * step; tick <= to; tick += step) {
|
|
32
|
+
ticks.push(tick);
|
|
33
|
+
}
|
|
34
|
+
return ticks;
|
|
35
|
+
}
|
|
36
|
+
function seriesData(segments) {
|
|
37
|
+
const data = [];
|
|
38
|
+
segments.forEach((segment, index) => {
|
|
39
|
+
const first = segment[0];
|
|
40
|
+
if (!first) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (index > 0) {
|
|
44
|
+
data.push({ value: [first.t - 1, null] });
|
|
45
|
+
}
|
|
46
|
+
for (const point of segment) {
|
|
47
|
+
data.push(segment.length === 1 ? { value: [point.t, point.value], symbolSize: 5 } : { value: [point.t, point.value] });
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return data;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { cn, niceTicks, seriesData, timeTicks };
|
|
54
|
+
//# sourceMappingURL=chunk-OFTNLF7H.js.map
|
|
55
|
+
//# sourceMappingURL=chunk-OFTNLF7H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/cn.ts","../src/charts/scale.ts"],"names":[],"mappings":"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","file":"chunk-OFTNLF7H.js","sourcesContent":["import clsx, { type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * The arithmetic under the Cbox charts (first written for Cbox Telemetry): round value\n * ticks from zero, and time ticks on whole minutes, hours or days.\n */\n\n/** 0 and round steps up to at least `max`: 0, 250, 500, 750, 1000. */\nexport function niceTicks(max: number, count = 4): number[] {\n const top = max > 0 && Number.isFinite(max) ? max : 1;\n const raw = top / count;\n const power = 10 ** Math.floor(Math.log10(raw));\n const fraction = raw / power;\n const step = (fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 2.5 ? 2.5 : fraction <= 5 ? 5 : 10) * power;\n const ticks: number[] = [];\n\n for (let value = 0; value < top + step * 0.999; value += step) {\n ticks.push(Number(value.toPrecision(12)));\n }\n\n if (ticks.length < 2) {\n ticks.push(step);\n }\n\n return ticks;\n}\n\nconst MINUTE = 60_000;\nconst STEPS = [1, 2, 5, 10, 15, 30, 60, 120, 180, 360, 720, 1440, 2880, 10080].map((minutes) => minutes * MINUTE);\n\n/** Ticks (milliseconds) on whole minutes, hours or days, about one per 84 px of plot. */\nexport function timeTicks(from: number, to: number, width: number): number[] {\n const most = Math.max(2, Math.floor(width / 84));\n const step = STEPS.find((candidate) => (to - from) / candidate <= most) ?? 7 * 1440 * MINUTE;\n const ticks: number[] = [];\n\n for (let tick = Math.ceil(from / step) * step; tick <= to; tick += step) {\n ticks.push(tick);\n }\n\n return ticks;\n}\n\n/** A sample at `t` milliseconds since the epoch. */\nexport type TimePoint = { t: number; value: number };\n\nexport type SeriesDatum = { value: [number, number | null]; symbolSize?: number };\n\n/**\n * Runs of samples as ECharts line data: a null between runs keeps missing samples a gap\n * (never interpolated or drawn as zero), and an isolated sample becomes a visible dot.\n */\nexport function seriesData(segments: TimePoint[][]): SeriesDatum[] {\n const data: SeriesDatum[] = [];\n\n segments.forEach((segment, index) => {\n const first = segment[0];\n\n if (!first) {\n return;\n }\n\n if (index > 0) {\n data.push({ value: [first.t - 1, null] });\n }\n\n for (const point of segment) {\n data.push(segment.length === 1 ? { value: [point.t, point.value], symbolSize: 5 } : { value: [point.t, point.value] });\n }\n });\n\n return data;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { LineChart } from 'echarts/charts';
|
|
2
|
+
import { DataZoomComponent, GridComponent, TooltipComponent, MarkLineComponent, AriaComponent } from 'echarts/components';
|
|
3
|
+
import * as echarts from 'echarts/core';
|
|
4
|
+
export { echarts };
|
|
5
|
+
import { SVGRenderer } from 'echarts/renderers';
|
|
6
|
+
|
|
7
|
+
// src/charts/engine.ts
|
|
8
|
+
echarts.use([LineChart, DataZoomComponent, GridComponent, TooltipComponent, MarkLineComponent, AriaComponent, SVGRenderer]);
|
|
9
|
+
//# sourceMappingURL=engine-4DRZ3POZ.js.map
|
|
10
|
+
//# sourceMappingURL=engine-4DRZ3POZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/charts/engine.ts"],"names":[],"mappings":";;;;;;;AAMQ,OAAA,CAAA,GAAA,CAAI,CAAC,WAAW,iBAAA,EAAmB,aAAA,EAAe,kBAAkB,iBAAA,EAAmB,aAAA,EAAe,WAAW,CAAC,CAAA","file":"engine-4DRZ3POZ.js","sourcesContent":["import { LineChart } from 'echarts/charts';\nimport { AriaComponent, DataZoomComponent, GridComponent, MarkLineComponent, TooltipComponent } from 'echarts/components';\nimport * as echarts from 'echarts/core';\nimport { SVGRenderer } from 'echarts/renderers';\n\n/** Only what the Cbox time chart uses; loaded on first mount so pages without charts never pay for it. */\necharts.use([LineChart, DataZoomComponent, GridComponent, TooltipComponent, MarkLineComponent, AriaComponent, SVGRenderer]);\n\nexport { echarts };\n"]}
|