@cboxdk/cbox-ui 0.6.0 → 0.7.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.
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The arithmetic under the Cbox charts (first written for Cbox Telemetry): round value
3
+ * ticks from zero, and time ticks on whole minutes, hours or days.
4
+ */
5
+ /** 0 and round steps up to at least `max`: 0, 250, 500, 750, 1000. */
6
+ declare function niceTicks(max: number, count?: number): number[];
7
+ /** Ticks (milliseconds) on whole minutes, hours or days, about one per 84 px of plot. */
8
+ declare function timeTicks(from: number, to: number, width: number): number[];
9
+ /** A sample at `t` milliseconds since the epoch. */
10
+ type TimePoint = {
11
+ t: number;
12
+ value: number;
13
+ };
14
+ type SeriesDatum = {
15
+ value: [number, number | null];
16
+ symbolSize?: number;
17
+ };
18
+ /**
19
+ * Runs of samples as ECharts line data: a null between runs keeps missing samples a gap
20
+ * (never interpolated or drawn as zero), and an isolated sample becomes a visible dot.
21
+ */
22
+ declare function seriesData(segments: TimePoint[][]): SeriesDatum[];
23
+
24
+ export { type SeriesDatum as S, type TimePoint as T, niceTicks as n, seriesData as s, timeTicks as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cboxdk/cbox-ui",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "private": false,
5
5
  "description": "Cbox shared UI — layout primitives, design tokens, and brand assets used across every Cbox-family app (id, cortex, atlas, track, …).",
6
6
  "repository": {
@@ -31,6 +31,10 @@
31
31
  "types": "./dist/index.d.ts",
32
32
  "import": "./dist/index.js"
33
33
  },
34
+ "./charts": {
35
+ "types": "./dist/charts.d.ts",
36
+ "import": "./dist/charts.js"
37
+ },
34
38
  "./tokens": "./tokens/cbox.css",
35
39
  "./tailwind": "./tailwind.preset.js",
36
40
  "./assets/*": "./assets/*"
@@ -43,6 +47,7 @@
43
47
  "typecheck": "tsc --noEmit"
44
48
  },
45
49
  "peerDependencies": {
50
+ "echarts": "^6.0.0",
46
51
  "lucide-react": ">=0.400.0",
47
52
  "react": "^19.0.0",
48
53
  "react-dom": "^19.0.0",
@@ -51,6 +56,9 @@
51
56
  "peerDependenciesMeta": {
52
57
  "lucide-react": {
53
58
  "optional": true
59
+ },
60
+ "echarts": {
61
+ "optional": true
54
62
  }
55
63
  },
56
64
  "dependencies": {
@@ -61,6 +69,7 @@
61
69
  "@types/node": "^22.0.0",
62
70
  "@types/react": "^19.0.0",
63
71
  "@types/react-dom": "^19.0.0",
72
+ "echarts": "6.1.0",
64
73
  "lucide-react": "^0.469.0",
65
74
  "tsup": "^8.3.0",
66
75
  "typescript": "^5.6.0",
package/tokens/cbox.css CHANGED
@@ -1,38 +1,26 @@
1
- /*
2
- * Cbox design tokens.
3
- *
4
- * Drop this file into a Cbox-family app's CSS via:
5
- *
6
- * @import '@cboxdk/cbox-ui/tokens';
7
- *
8
- * Then reference the tokens via Tailwind utilities (text-foreground,
9
- * bg-card, border-border, etc.) — the @theme block at the bottom
10
- * registers them as Tailwind v4 utilities.
11
- *
12
- * Cool-neutral palette. Single deep-blue primary. Plus Jakarta Sans
13
- * + JetBrains Mono. Designed for ops + identity surfaces — refined,
14
- * legible, sans editorial drama.
15
- */
16
-
1
+ /* Cbox colour tokens — cbox-ui structure, warmed toward cbox.dk's cream/ink palette
2
+ * so the products share temperature with the brand site (and aren't a Linear clone).
3
+ * Single deep-blue primary (matches the logo). Light default; dark under `.dark` or
4
+ * `[data-theme="dark"]` on the root — the host decides which it writes. */
17
5
  :root {
18
- --background: oklch(0.992 0.003 247);
19
- --canvas: oklch(0.975 0.008 250);
20
- --foreground: oklch(0.18 0.012 250);
6
+ --background: oklch(0.985 0.006 85);
7
+ --canvas: oklch(0.964 0.012 85);
8
+ --foreground: oklch(0.22 0.015 75);
21
9
 
22
- --card: oklch(1 0 0);
23
- --card-foreground: oklch(0.18 0.012 250);
10
+ --card: oklch(0.997 0.003 90);
11
+ --card-foreground: oklch(0.22 0.015 75);
24
12
 
25
- --popover: oklch(1 0 0);
26
- --popover-foreground: oklch(0.18 0.012 250);
13
+ --popover: oklch(0.997 0.003 90);
14
+ --popover-foreground: oklch(0.22 0.015 75);
27
15
 
28
16
  --primary: oklch(0.45 0.16 258);
29
17
  --primary-foreground: oklch(0.99 0.003 247);
30
18
 
31
- --secondary: oklch(0.96 0.006 250);
32
- --secondary-foreground: oklch(0.22 0.012 250);
19
+ --secondary: oklch(0.955 0.010 85);
20
+ --secondary-foreground: oklch(0.26 0.015 75);
33
21
 
34
- --muted: oklch(0.96 0.006 250);
35
- --muted-foreground: oklch(0.5 0.012 250);
22
+ --muted: oklch(0.955 0.010 85);
23
+ --muted-foreground: oklch(0.50 0.020 75);
36
24
 
37
25
  --accent: oklch(0.5 0.17 258);
38
26
  --accent-foreground: oklch(0.99 0.003 247);
@@ -54,9 +42,9 @@
54
42
  --destructive-foreground: oklch(0.99 0.003 247);
55
43
  --destructive-soft: oklch(0.58 0.21 25 / 0.12);
56
44
 
57
- --border: oklch(0.92 0.006 250);
58
- --border-strong: oklch(0.86 0.008 250);
59
- --input: oklch(0.94 0.005 250);
45
+ --border: oklch(0.82 0.020 85);
46
+ --border-strong: oklch(0.71 0.024 85);
47
+ --input: oklch(0.905 0.014 85);
60
48
  --ring: oklch(0.5 0.17 258);
61
49
 
62
50
  --chart-1: oklch(0.5 0.17 258);
@@ -65,34 +53,41 @@
65
53
  --chart-4: oklch(0.58 0.21 25);
66
54
  --chart-5: oklch(0.6 0.16 295);
67
55
 
68
- --sidebar: oklch(0.985 0.005 250);
69
- --sidebar-foreground: oklch(0.22 0.012 250);
70
- --sidebar-muted: oklch(0.55 0.012 250);
71
- --sidebar-accent: oklch(0.94 0.008 250);
72
- --sidebar-accent-foreground: oklch(0.18 0.012 250);
73
- --sidebar-border: oklch(0.92 0.006 250);
56
+ --sidebar: oklch(0.973 0.010 85);
57
+ --sidebar-foreground: oklch(0.26 0.015 75);
58
+ --sidebar-muted: oklch(0.55 0.020 75);
59
+ --sidebar-accent: oklch(0.935 0.014 85);
60
+ --sidebar-accent-foreground: oklch(0.22 0.015 75);
61
+ --sidebar-border: oklch(0.82 0.020 85);
74
62
  --sidebar-ring: oklch(0.5 0.17 258);
63
+
64
+ /* Semantic aliases */
65
+ --surface-card: var(--card);
66
+ --text-body: var(--foreground);
67
+ --text-muted: var(--muted-foreground);
75
68
  }
76
69
 
77
- .dark {
78
- --background: oklch(0.155 0.01 250);
79
- --canvas: oklch(0.18 0.01 250);
80
- --foreground: oklch(0.97 0.005 247);
70
+ /* Dark: the `.dark` class, or `data-theme="dark"` for hosts that store the choice as an attribute. */
71
+ .dark,
72
+ [data-theme='dark'] {
73
+ --background: oklch(0.185 0.008 80);
74
+ --canvas: oklch(0.21 0.009 80);
75
+ --foreground: oklch(0.965 0.006 90);
81
76
 
82
- --card: oklch(0.2 0.01 250);
83
- --card-foreground: oklch(0.97 0.005 247);
77
+ --card: oklch(0.235 0.010 80);
78
+ --card-foreground: oklch(0.965 0.006 90);
84
79
 
85
- --popover: oklch(0.21 0.011 250);
86
- --popover-foreground: oklch(0.97 0.005 247);
80
+ --popover: oklch(0.245 0.011 80);
81
+ --popover-foreground: oklch(0.965 0.006 90);
87
82
 
88
83
  --primary: oklch(0.65 0.18 258);
89
84
  --primary-foreground: oklch(0.16 0.01 250);
90
85
 
91
- --secondary: oklch(0.25 0.012 250);
92
- --secondary-foreground: oklch(0.96 0.005 247);
86
+ --secondary: oklch(0.285 0.012 80);
87
+ --secondary-foreground: oklch(0.955 0.006 90);
93
88
 
94
- --muted: oklch(0.24 0.012 250);
95
- --muted-foreground: oklch(0.7 0.012 250);
89
+ --muted: oklch(0.275 0.012 80);
90
+ --muted-foreground: oklch(0.70 0.016 85);
96
91
 
97
92
  --accent: oklch(0.65 0.18 258);
98
93
  --accent-foreground: oklch(0.16 0.01 250);
@@ -114,9 +109,9 @@
114
109
  --destructive-foreground: oklch(0.16 0.01 250);
115
110
  --destructive-soft: oklch(0.68 0.21 25 / 0.16);
116
111
 
117
- --border: oklch(0.28 0.012 250);
118
- --border-strong: oklch(0.36 0.014 250);
119
- --input: oklch(0.26 0.012 250);
112
+ --border: oklch(0.39 0.016 80);
113
+ --border-strong: oklch(0.50 0.018 80);
114
+ --input: oklch(0.32 0.013 80);
120
115
  --ring: oklch(0.65 0.18 258);
121
116
 
122
117
  --chart-1: oklch(0.65 0.18 258);
@@ -125,12 +120,12 @@
125
120
  --chart-4: oklch(0.68 0.21 25);
126
121
  --chart-5: oklch(0.72 0.16 295);
127
122
 
128
- --sidebar: oklch(0.18 0.01 250);
129
- --sidebar-foreground: oklch(0.96 0.005 247);
130
- --sidebar-muted: oklch(0.65 0.012 250);
131
- --sidebar-accent: oklch(0.24 0.012 250);
132
- --sidebar-accent-foreground: oklch(0.97 0.005 247);
133
- --sidebar-border: oklch(0.28 0.012 250);
123
+ --sidebar: oklch(0.21 0.009 80);
124
+ --sidebar-foreground: oklch(0.955 0.006 90);
125
+ --sidebar-muted: oklch(0.65 0.016 85);
126
+ --sidebar-accent: oklch(0.275 0.012 80);
127
+ --sidebar-accent-foreground: oklch(0.965 0.006 90);
128
+ --sidebar-border: oklch(0.39 0.016 80);
134
129
  --sidebar-ring: oklch(0.65 0.18 258);
135
130
  }
136
131
 
@@ -140,7 +135,7 @@
140
135
  */
141
136
  @theme inline {
142
137
  --font-sans:
143
- 'Plus Jakarta Sans', 'Instrument Sans', ui-sans-serif, system-ui,
138
+ system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
144
139
  sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
145
140
  'Noto Color Emoji';
146
141
  --font-display: 'Plus Jakarta Sans', ui-sans-serif, system-ui, sans-serif;
@@ -148,10 +143,10 @@
148
143
  'JetBrains Mono', ui-monospace, SFMono-Regular, 'Roboto Mono', Menlo,
149
144
  Monaco, monospace;
150
145
 
151
- --radius: 0.625rem;
146
+ --radius: 0.75rem;
152
147
  --radius-lg: var(--radius);
153
- --radius-md: calc(var(--radius) - 2px);
154
- --radius-sm: calc(var(--radius) - 4px);
148
+ --radius-md: 0.5rem;
149
+ --radius-sm: 0.375rem;
155
150
 
156
151
  --color-background: var(--background);
157
152
  --color-foreground: var(--foreground);
@@ -243,32 +238,41 @@
243
238
  * surface feels consistent across id, webhooks, cortex, etc.
244
239
  */
245
240
  .canvas-gradient {
246
- background:
247
- radial-gradient(
248
- ellipse 1200px 600px at 100% 0%,
249
- oklch(0.5 0.17 258 / 0.04) 0%,
250
- transparent 60%
251
- ),
252
- radial-gradient(
253
- ellipse 800px 400px at 0% 100%,
254
- oklch(0.6 0.16 295 / 0.04) 0%,
255
- transparent 60%
256
- ),
257
- var(--canvas);
258
- }
259
-
260
- .dark .canvas-gradient {
261
- background:
262
- radial-gradient(
263
- ellipse 1200px 600px at 100% 0%,
264
- oklch(0.65 0.18 258 / 0.06) 0%,
265
- transparent 60%
266
- ),
267
- radial-gradient(
268
- ellipse 800px 400px at 0% 100%,
269
- oklch(0.7 0.16 295 / 0.05) 0%,
270
- transparent 60%
271
- ),
272
- var(--canvas);
241
+ background: radial-gradient(ellipse at 30% 0, var(--accent-soft), transparent 48%), var(--canvas);
273
242
  }
274
243
  }
244
+
245
+ /* Workspace shell: one geometry for every product, including floating hover expansion. */
246
+ .cbx-workspace{display:flex;height:100svh;overflow:hidden;font-family:var(--font-sans)}
247
+ .cbx-rail-slot{position:relative;flex:0 0 64px;width:64px;z-index:40}
248
+ .cbx-rail-slot[data-pinned=true]{flex-basis:222px;width:222px}
249
+ .cbx-rail{position:absolute;inset:6px auto 6px 6px;width:52px;border:1px solid var(--border);border-radius:12px;background:var(--sidebar);display:flex;flex-direction:column;padding:6px;transition:width 200ms cubic-bezier(.4,0,.2,1)}
250
+ .cbx-rail[data-open=true]{width:210px;box-shadow:0 1px 2px #0001,0 8px 24px #0001}
251
+ .cbx-rail-brand{display:flex;align-items:center;justify-content:space-between;height:44px;flex-shrink:0;gap:4px}
252
+ .cbx-rail-brand button,.cbx-subnav-header button,.cbx-mobile-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:28px;height:28px;border-radius:8px}
253
+ .cbx-rail nav{flex:1;overflow:auto;padding-top:12px}
254
+ .cbx-workspace-link{display:flex;align-items:center;gap:10px;min-height:34px;padding:0 10px;margin-bottom:3px;border-radius:8px;font-size:13px;white-space:nowrap;color:var(--sidebar-foreground);text-decoration:none}
255
+ .cbx-workspace-link span{overflow:hidden;text-overflow:ellipsis}
256
+ .cbx-workspace-link:hover{background:var(--secondary)}
257
+ .cbx-workspace-link.is-active{background:var(--accent-soft);font-weight:600}
258
+ .cbx-workspace-link.is-active svg{color:var(--primary)}
259
+ .cbx-rail-account{padding-top:8px;border-top:1px solid var(--border)}
260
+ .cbx-workspace-column{display:flex;flex:1;min-width:0;flex-direction:column}
261
+ .cbx-workspace-header{height:56px;flex-shrink:0;display:flex;align-items:center;gap:12px;padding:0 20px;background:var(--background);border-bottom:1px solid var(--border)}
262
+ .cbx-workspace-context{min-width:0;flex:1}
263
+ .cbx-workspace-tools{display:flex;align-items:center;gap:8px;flex-shrink:0}
264
+ .cbx-workspace-body{display:flex;flex:1;min-height:0}
265
+ .cbx-workspace-main{flex:1;min-width:0;overflow:auto}
266
+ .cbx-subnav{width:210px;flex-shrink:0;background:var(--background);border-right:1px solid var(--border);overflow:auto;padding:12px 8px}
267
+ .cbx-subnav[data-collapsed=true]{width:26px;padding:0}
268
+ .cbx-subnav-header{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:34px;margin-bottom:12px;padding:0 8px;font-size:13px}
269
+ .cbx-subnav-strip{display:flex;align-items:center;gap:16px;padding:14px 4px;height:100%;width:26px;flex-direction:column;font-size:12px}
270
+ .cbx-subnav-strip span{writing-mode:vertical-rl}
271
+ .cbx-mobile-trigger{display:none}
272
+ .cbx-workspace-mobile{margin:0;height:100svh;max-height:100svh;width:min(320px,90vw);padding:20px 12px;background:var(--background);color:var(--foreground);border-right:1px solid var(--border)}
273
+ .cbx-workspace-mobile::backdrop{background:#0006}
274
+ @media(max-width:1023px){.cbx-rail-slot,.cbx-subnav{display:none}.cbx-mobile-trigger{display:flex}.cbx-workspace-header{padding:0 12px;gap:8px}}
275
+ @media(prefers-reduced-motion:reduce){.cbx-rail{transition:none}}
276
+
277
+ .cbx-workspace-context [data-component=context-bar] button{max-width:100%}
278
+ @media(max-width:639px){.cbx-workspace-header{flex-wrap:wrap;height:auto;min-height:56px;padding-block:8px}.cbx-workspace-context{order:3;flex-basis:100%;width:100%}.cbx-workspace-tools{margin-left:auto}.cbx-workspace-context [data-component=context-bar]>div{flex:1}}