@alpic-ai/ui 1.160.0 → 1.162.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/dist/components/accordion-card.d.mts +1 -5
- package/dist/components/accordion-card.mjs +1 -5
- package/dist/components/accordion.d.mts +1 -5
- package/dist/components/accordion.mjs +1 -5
- package/dist/components/attachment-tile.d.mts +0 -5
- package/dist/components/chart-legend.d.mts +4 -1
- package/dist/components/chart-legend.mjs +21 -7
- package/dist/components/chart-primitives.d.mts +3 -8
- package/dist/components/chart-primitives.mjs +3 -8
- package/dist/components/combobox.d.mts +0 -1
- package/dist/components/line-chart.d.mts +3 -1
- package/dist/components/line-chart.mjs +7 -4
- package/dist/components/select-trigger-variants.d.mts +1 -5
- package/dist/components/select-trigger-variants.mjs +1 -5
- package/dist/components/table.d.mts +1 -5
- package/dist/components/task-progress.d.mts +1 -4
- package/dist/lib/chart-palette.d.mts +1 -20
- package/dist/lib/chart-palette.mjs +1 -20
- package/dist/lib/chart.d.mts +1 -4
- package/dist/lib/chart.mjs +2 -11
- package/package.json +5 -5
- package/src/components/accordion-card.tsx +1 -5
- package/src/components/accordion.tsx +1 -5
- package/src/components/attachment-tile.tsx +0 -5
- package/src/components/avatar.tsx +0 -2
- package/src/components/bar-chart.tsx +1 -2
- package/src/components/bar-list.tsx +1 -2
- package/src/components/chart-legend.tsx +47 -10
- package/src/components/chart-primitives.tsx +3 -9
- package/src/components/combobox.tsx +1 -29
- package/src/components/dropdown-menu.tsx +0 -12
- package/src/components/form.tsx +0 -4
- package/src/components/heatmap-chart.tsx +4 -10
- package/src/components/line-chart.tsx +16 -3
- package/src/components/select-trigger-variants.ts +1 -5
- package/src/components/select.tsx +0 -10
- package/src/components/sidebar.tsx +0 -2
- package/src/components/table.tsx +1 -5
- package/src/components/tabs.tsx +1 -18
- package/src/components/tag.tsx +0 -6
- package/src/components/task-progress.tsx +2 -14
- package/src/components/wizard.tsx +0 -6
- package/src/lib/chart-palette.ts +3 -22
- package/src/lib/chart.ts +3 -15
- package/src/stories/button.stories.tsx +1 -15
- package/src/stories/combobox.stories.tsx +0 -12
- package/src/stories/dropdown-menu.stories.tsx +0 -4
- package/src/stories/form.stories.tsx +0 -6
- package/src/stories/heatmap-chart.stories.tsx +0 -1
- package/src/stories/input-group.stories.tsx +0 -4
- package/src/stories/input.stories.tsx +0 -8
- package/src/stories/line-chart.stories.tsx +120 -80
- package/src/stories/sidebar.stories.tsx +1 -4
- package/src/stories/skeleton.stories.tsx +0 -2
- package/src/stories/table.stories.tsx +0 -5
- package/src/stories/tabs.stories.tsx +0 -11
- package/src/stories/toggle-group.stories.tsx +0 -5
- package/src/stories/wizard.stories.tsx +0 -4
|
@@ -2,8 +2,7 @@ import { ArrowRight, Plus, Sparkles } from "lucide-react";
|
|
|
2
2
|
|
|
3
3
|
import { Button } from "../components/button";
|
|
4
4
|
|
|
5
|
-
//
|
|
6
|
-
// variants stacked top-to-bottom, states left-to-right.
|
|
5
|
+
// Hover states are simulated via className; layout matches the Figma page (variants top-to-bottom, states left-to-right).
|
|
7
6
|
|
|
8
7
|
const VARIANT_LABEL = "type-text-xs text-muted-foreground w-20 shrink-0";
|
|
9
8
|
const STATE_HEADER = "type-text-xs text-muted-foreground font-medium w-32 text-center";
|
|
@@ -16,7 +15,6 @@ const ICON_STATE_HEADER = "type-text-xs text-muted-foreground font-medium w-16 t
|
|
|
16
15
|
export const AllVariants = () => {
|
|
17
16
|
return (
|
|
18
17
|
<div className="flex flex-col gap-3 p-8">
|
|
19
|
-
{/* ── Text buttons ────────────────────────────────────────────────── */}
|
|
20
18
|
<span className={SECTION_HEADER}>Text</span>
|
|
21
19
|
|
|
22
20
|
<div className={ROW}>
|
|
@@ -26,7 +24,6 @@ export const AllVariants = () => {
|
|
|
26
24
|
<div className={STATE_HEADER}>Loading</div>
|
|
27
25
|
</div>
|
|
28
26
|
|
|
29
|
-
{/* Primary */}
|
|
30
27
|
<div className={ROW}>
|
|
31
28
|
<span className={VARIANT_LABEL}>Primary</span>
|
|
32
29
|
<div className={CELL}>
|
|
@@ -46,7 +43,6 @@ export const AllVariants = () => {
|
|
|
46
43
|
</div>
|
|
47
44
|
</div>
|
|
48
45
|
|
|
49
|
-
{/* Secondary */}
|
|
50
46
|
<div className={ROW}>
|
|
51
47
|
<span className={VARIANT_LABEL}>Secondary</span>
|
|
52
48
|
<div className={CELL}>
|
|
@@ -66,7 +62,6 @@ export const AllVariants = () => {
|
|
|
66
62
|
</div>
|
|
67
63
|
</div>
|
|
68
64
|
|
|
69
|
-
{/* Tertiary */}
|
|
70
65
|
<div className={ROW}>
|
|
71
66
|
<span className={VARIANT_LABEL}>Tertiary</span>
|
|
72
67
|
<div className={CELL}>
|
|
@@ -86,7 +81,6 @@ export const AllVariants = () => {
|
|
|
86
81
|
</div>
|
|
87
82
|
</div>
|
|
88
83
|
|
|
89
|
-
{/* Link color */}
|
|
90
84
|
<div className={ROW}>
|
|
91
85
|
<span className={VARIANT_LABEL}>Link</span>
|
|
92
86
|
<div className={CELL}>
|
|
@@ -104,7 +98,6 @@ export const AllVariants = () => {
|
|
|
104
98
|
</div>
|
|
105
99
|
</div>
|
|
106
100
|
|
|
107
|
-
{/* Link gray */}
|
|
108
101
|
<div className={ROW}>
|
|
109
102
|
<span className={VARIANT_LABEL}>Link muted</span>
|
|
110
103
|
<div className={CELL}>
|
|
@@ -122,7 +115,6 @@ export const AllVariants = () => {
|
|
|
122
115
|
</div>
|
|
123
116
|
</div>
|
|
124
117
|
|
|
125
|
-
{/* Destructive */}
|
|
126
118
|
<div className={ROW}>
|
|
127
119
|
<span className={VARIANT_LABEL}>Destructive</span>
|
|
128
120
|
<div className={CELL}>
|
|
@@ -142,7 +134,6 @@ export const AllVariants = () => {
|
|
|
142
134
|
</div>
|
|
143
135
|
</div>
|
|
144
136
|
|
|
145
|
-
{/* ── Icon only ───────────────────────────────────────────────────── */}
|
|
146
137
|
<span className={SECTION_HEADER}>Icon only</span>
|
|
147
138
|
|
|
148
139
|
<div className={ROW}>
|
|
@@ -213,7 +204,6 @@ export const AllVariants = () => {
|
|
|
213
204
|
</div>
|
|
214
205
|
</div>
|
|
215
206
|
|
|
216
|
-
{/* ── Icon rounded ────────────────────────────────────────────────── */}
|
|
217
207
|
<span className={SECTION_HEADER}>Icon rounded</span>
|
|
218
208
|
|
|
219
209
|
<div className={ROW}>
|
|
@@ -284,7 +274,6 @@ export const AllVariants = () => {
|
|
|
284
274
|
</div>
|
|
285
275
|
</div>
|
|
286
276
|
|
|
287
|
-
{/* ── Pill ──────────────────────────────────────────────────────────── */}
|
|
288
277
|
<span className={SECTION_HEADER}>Pill</span>
|
|
289
278
|
|
|
290
279
|
<div className="flex items-center gap-3">
|
|
@@ -302,7 +291,6 @@ export const AllVariants = () => {
|
|
|
302
291
|
</Button>
|
|
303
292
|
</div>
|
|
304
293
|
|
|
305
|
-
{/* ── With icon (leading) ──────────────────────────────────────────── */}
|
|
306
294
|
<span className={SECTION_HEADER}>With icon</span>
|
|
307
295
|
|
|
308
296
|
<div className="flex items-center gap-3">
|
|
@@ -323,7 +311,6 @@ export const AllVariants = () => {
|
|
|
323
311
|
</Button>
|
|
324
312
|
</div>
|
|
325
313
|
|
|
326
|
-
{/* ── CTA (animated gradient ring) ────────────────────────────────── */}
|
|
327
314
|
<span className={SECTION_HEADER}>CTA — animated</span>
|
|
328
315
|
<p className="type-text-xs text-muted-foreground -mt-2 max-w-md">
|
|
329
316
|
Hover to rotate the conic gradient around the border and ignite the soft halo.
|
|
@@ -345,7 +332,6 @@ export const AllVariants = () => {
|
|
|
345
332
|
</Button>
|
|
346
333
|
</div>
|
|
347
334
|
|
|
348
|
-
{/* ── asChild ─────────────────────────────────────────────────────── */}
|
|
349
335
|
<span className={SECTION_HEADER}>asChild</span>
|
|
350
336
|
|
|
351
337
|
<div className="flex items-center gap-3">
|
|
@@ -15,8 +15,6 @@ import {
|
|
|
15
15
|
} from "../components/combobox";
|
|
16
16
|
import { CommandItem } from "../components/command";
|
|
17
17
|
|
|
18
|
-
/* ── With search ──────────────────────────────────────────────────────────── */
|
|
19
|
-
|
|
20
18
|
const branches = ["main", "develop", "feature/auth", "feature/dashboard", "fix/login-bug", "release/v2.0"];
|
|
21
19
|
|
|
22
20
|
function SearchCombobox() {
|
|
@@ -44,8 +42,6 @@ function SearchCombobox() {
|
|
|
44
42
|
);
|
|
45
43
|
}
|
|
46
44
|
|
|
47
|
-
/* ── Custom trigger content (avatars + supporting text) ──────────────────── */
|
|
48
|
-
|
|
49
45
|
const people = [
|
|
50
46
|
{ id: "olivia", name: "Olivia Rhye", handle: "@olivia" },
|
|
51
47
|
{ id: "phoenix", name: "Phoenix Baker", handle: "@phoenix" },
|
|
@@ -90,8 +86,6 @@ function AvatarCombobox() {
|
|
|
90
86
|
);
|
|
91
87
|
}
|
|
92
88
|
|
|
93
|
-
/* ── With CommandItem action ─────────────────────────────────────────────── */
|
|
94
|
-
|
|
95
89
|
const namespaces = [
|
|
96
90
|
{ id: "acme", name: "acme-corp" },
|
|
97
91
|
{ id: "personal", name: "johndoe" },
|
|
@@ -127,8 +121,6 @@ function CommandActionCombobox() {
|
|
|
127
121
|
);
|
|
128
122
|
}
|
|
129
123
|
|
|
130
|
-
/* ── Grouped with headings ───────────────────────────────────────────────── */
|
|
131
|
-
|
|
132
124
|
function GroupedCombobox() {
|
|
133
125
|
const [value, setValue] = useState<string | null>(null);
|
|
134
126
|
return (
|
|
@@ -154,8 +146,6 @@ function GroupedCombobox() {
|
|
|
154
146
|
);
|
|
155
147
|
}
|
|
156
148
|
|
|
157
|
-
/* ── Multi-select with tags ───────────────────────────────────────────────── */
|
|
158
|
-
|
|
159
149
|
function MultiCombobox() {
|
|
160
150
|
const [values, setValues] = useState<string[]>(["phoenix", "olivia"]);
|
|
161
151
|
return (
|
|
@@ -182,8 +172,6 @@ function MultiCombobox() {
|
|
|
182
172
|
);
|
|
183
173
|
}
|
|
184
174
|
|
|
185
|
-
/* ── Story ────────────────────────────────────────────────────────────────── */
|
|
186
|
-
|
|
187
175
|
export const AllVariants: Story = () => (
|
|
188
176
|
<div className="grid grid-cols-1 gap-10 p-10 md:grid-cols-2">
|
|
189
177
|
<div className="flex flex-col gap-1.5">
|
|
@@ -34,7 +34,6 @@ import {
|
|
|
34
34
|
|
|
35
35
|
export const AllVariants: Story = () => (
|
|
36
36
|
<div className="flex flex-col gap-10 p-10">
|
|
37
|
-
{/* Basic with icons & shortcuts */}
|
|
38
37
|
<div className="flex flex-col gap-1.5">
|
|
39
38
|
<p className="type-text-xs font-medium text-subtle-foreground">Default with icons & shortcuts</p>
|
|
40
39
|
<DropdownMenu>
|
|
@@ -122,7 +121,6 @@ export const AllVariants: Story = () => (
|
|
|
122
121
|
</DropdownMenu>
|
|
123
122
|
</div>
|
|
124
123
|
|
|
125
|
-
{/* Destructive variant */}
|
|
126
124
|
<div className="flex flex-col gap-1.5">
|
|
127
125
|
<p className="type-text-xs font-medium text-subtle-foreground">Destructive item</p>
|
|
128
126
|
<DropdownMenu>
|
|
@@ -143,7 +141,6 @@ export const AllVariants: Story = () => (
|
|
|
143
141
|
</DropdownMenu>
|
|
144
142
|
</div>
|
|
145
143
|
|
|
146
|
-
{/* Header with avatar */}
|
|
147
144
|
<div className="flex flex-col gap-1.5">
|
|
148
145
|
<p className="type-text-xs font-medium text-subtle-foreground">With header (avatar group)</p>
|
|
149
146
|
<DropdownMenu>
|
|
@@ -173,7 +170,6 @@ export const AllVariants: Story = () => (
|
|
|
173
170
|
</DropdownMenu>
|
|
174
171
|
</div>
|
|
175
172
|
|
|
176
|
-
{/* Disabled items */}
|
|
177
173
|
<div className="flex flex-col gap-1.5">
|
|
178
174
|
<p className="type-text-xs font-medium text-subtle-foreground">Disabled items</p>
|
|
179
175
|
<DropdownMenu>
|
|
@@ -13,8 +13,6 @@ import {
|
|
|
13
13
|
TextareaField,
|
|
14
14
|
} from "../components/form";
|
|
15
15
|
|
|
16
|
-
/* ── Types ───────────────────────────────────────────────────────────────── */
|
|
17
|
-
|
|
18
16
|
interface CreateProjectForm {
|
|
19
17
|
email: string;
|
|
20
18
|
role: string;
|
|
@@ -43,8 +41,6 @@ const capabilities = [
|
|
|
43
41
|
{ value: "admin", label: "Admin" },
|
|
44
42
|
];
|
|
45
43
|
|
|
46
|
-
/* ── Composed Form ───────────────────────────────────────────────────────── */
|
|
47
|
-
|
|
48
44
|
function ComposedForm() {
|
|
49
45
|
const form = useForm<CreateProjectForm>({
|
|
50
46
|
defaultValues: {
|
|
@@ -141,8 +137,6 @@ function ComposedForm() {
|
|
|
141
137
|
);
|
|
142
138
|
}
|
|
143
139
|
|
|
144
|
-
/* ── Story ────────────────────────────────────────────────────────────────── */
|
|
145
|
-
|
|
146
140
|
export const AllVariants: Story = () => (
|
|
147
141
|
<div className="flex flex-col gap-3">
|
|
148
142
|
<p className="type-text-xs font-medium text-subtle-foreground uppercase tracking-wide">
|
|
@@ -18,7 +18,6 @@ function mulberry32(seed: number) {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
// Long-format activity rows: one record per (day, hour) with a working-hours hump.
|
|
22
21
|
const ACTIVITY = (() => {
|
|
23
22
|
const random = mulberry32(99);
|
|
24
23
|
const rows: Array<{ day: string; hour: string; sessions: number }> = [];
|
|
@@ -7,7 +7,6 @@ const SECTION_HEADER = "type-text-xs font-medium text-muted-foreground uppercase
|
|
|
7
7
|
|
|
8
8
|
export const AllVariants: Story = () => (
|
|
9
9
|
<div className="flex flex-col gap-6 p-8 max-w-lg">
|
|
10
|
-
{/* Textarea with block-end addon */}
|
|
11
10
|
<span className={SECTION_HEADER}>Textarea + block-end footer</span>
|
|
12
11
|
<InputGroup>
|
|
13
12
|
<InputGroupTextarea placeholder="Type a message…" />
|
|
@@ -21,7 +20,6 @@ export const AllVariants: Story = () => (
|
|
|
21
20
|
</InputGroupAddon>
|
|
22
21
|
</InputGroup>
|
|
23
22
|
|
|
24
|
-
{/* Inline-start addon */}
|
|
25
23
|
<span className={SECTION_HEADER}>Inline-start addon (icon)</span>
|
|
26
24
|
<InputGroup>
|
|
27
25
|
<InputGroupAddon align="inline-start">
|
|
@@ -34,7 +32,6 @@ export const AllVariants: Story = () => (
|
|
|
34
32
|
/>
|
|
35
33
|
</InputGroup>
|
|
36
34
|
|
|
37
|
-
{/* Inline-end addon */}
|
|
38
35
|
<span className={SECTION_HEADER}>Inline-end addon (button)</span>
|
|
39
36
|
<InputGroup>
|
|
40
37
|
<input
|
|
@@ -49,7 +46,6 @@ export const AllVariants: Story = () => (
|
|
|
49
46
|
</InputGroupAddon>
|
|
50
47
|
</InputGroup>
|
|
51
48
|
|
|
52
|
-
{/* Disabled state */}
|
|
53
49
|
<span className={SECTION_HEADER}>Disabled</span>
|
|
54
50
|
<InputGroup>
|
|
55
51
|
<InputGroupTextarea placeholder="Cannot type here…" disabled />
|
|
@@ -7,11 +7,9 @@ const SECTION_HEADER = "type-text-xs font-medium text-muted-foreground uppercase
|
|
|
7
7
|
|
|
8
8
|
export const AllVariants: Story = () => (
|
|
9
9
|
<div className="flex flex-col gap-6 p-8 max-w-sm">
|
|
10
|
-
{/* Default */}
|
|
11
10
|
<span className={SECTION_HEADER}>Default</span>
|
|
12
11
|
<Input id="default" placeholder="alice@example.com" />
|
|
13
12
|
|
|
14
|
-
{/* With label + hint */}
|
|
15
13
|
<span className={SECTION_HEADER}>With label + hint</span>
|
|
16
14
|
<Input
|
|
17
15
|
id="with-label"
|
|
@@ -21,7 +19,6 @@ export const AllVariants: Story = () => (
|
|
|
21
19
|
hint="This is a hint text to help user."
|
|
22
20
|
/>
|
|
23
21
|
|
|
24
|
-
{/* With tooltip */}
|
|
25
22
|
<span className={SECTION_HEADER}>With tooltip</span>
|
|
26
23
|
<Input
|
|
27
24
|
id="with-tooltip"
|
|
@@ -31,7 +28,6 @@ export const AllVariants: Story = () => (
|
|
|
31
28
|
placeholder="alice@example.com"
|
|
32
29
|
/>
|
|
33
30
|
|
|
34
|
-
{/* Error */}
|
|
35
31
|
<span className={SECTION_HEADER}>Error</span>
|
|
36
32
|
<Input
|
|
37
33
|
id="error"
|
|
@@ -41,7 +37,6 @@ export const AllVariants: Story = () => (
|
|
|
41
37
|
error="Please enter a valid email address."
|
|
42
38
|
/>
|
|
43
39
|
|
|
44
|
-
{/* Disabled */}
|
|
45
40
|
<span className={SECTION_HEADER}>Disabled</span>
|
|
46
41
|
<Input
|
|
47
42
|
id="disabled"
|
|
@@ -51,15 +46,12 @@ export const AllVariants: Story = () => (
|
|
|
51
46
|
disabled
|
|
52
47
|
/>
|
|
53
48
|
|
|
54
|
-
{/* Leading icon */}
|
|
55
49
|
<span className={SECTION_HEADER}>Leading icon (email)</span>
|
|
56
50
|
<Input id="leading-icon" label="Email" required placeholder="alice@example.com" leadingIcon={<Mail />} />
|
|
57
51
|
|
|
58
|
-
{/* Leading text (website) */}
|
|
59
52
|
<span className={SECTION_HEADER}>Leading text</span>
|
|
60
53
|
<Input id="leading-text" label="Website" required placeholder="www.example.com" leadingText="http://" />
|
|
61
54
|
|
|
62
|
-
{/* Small size */}
|
|
63
55
|
<span className={SECTION_HEADER}>Small size</span>
|
|
64
56
|
<Input id="sm-default" size="sm" placeholder="alice@example.com" label="Email" />
|
|
65
57
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Story } from "@ladle/react";
|
|
2
|
+
import { useState } from "react";
|
|
2
3
|
|
|
3
4
|
import { ChartCard } from "../components/chart-card";
|
|
4
5
|
import { LineChart } from "../components/line-chart";
|
|
@@ -37,7 +38,8 @@ const genLatency = (seed: number) => {
|
|
|
37
38
|
return Array.from({ length }, (_, index) => {
|
|
38
39
|
p50 = Math.max(120, p50 + (rnd() - 0.48) * 40);
|
|
39
40
|
p95 = Math.max(p50 + 200, p95 + (rnd() - 0.46) * 120);
|
|
40
|
-
|
|
41
|
+
const spiked = Math.round(p95 * (index === 19 ? 1.7 : 1));
|
|
42
|
+
return { t: hourLabel(index, length), p50: Math.round(p50), p95: spiked, p99: Math.round(spiked * 1.6) };
|
|
41
43
|
});
|
|
42
44
|
};
|
|
43
45
|
|
|
@@ -64,83 +66,121 @@ const ms = (value: number) => `${value}ms`;
|
|
|
64
66
|
const tokensSpark = tokens.map((row) => row.v);
|
|
65
67
|
const latencyPeak = latency.reduce((best, row) => (row.p95 > best.p95 ? row : best));
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
69
|
+
const percentileSeries = [
|
|
70
|
+
{ key: "p95", name: "p95" },
|
|
71
|
+
{ key: "p50", name: "p50" },
|
|
72
|
+
{ key: "p99", name: "p99", dashed: true },
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
export const AllVariants: Story = () => {
|
|
76
|
+
const [isolated, setIsolated] = useState<string | null>(null);
|
|
77
|
+
const hiddenPercentiles = new Set(
|
|
78
|
+
isolated == null ? [] : percentileSeries.map((entry) => entry.key).filter((key) => key !== isolated),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className="mx-auto max-w-[1600px] p-8">
|
|
83
|
+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3">
|
|
84
|
+
<ChartCard
|
|
85
|
+
palette="cyan"
|
|
86
|
+
accent="left"
|
|
87
|
+
kicker="Last 24h"
|
|
88
|
+
title="Sessions"
|
|
89
|
+
description="Full-width · left accent"
|
|
90
|
+
className="md:col-span-2 xl:col-span-3"
|
|
91
|
+
>
|
|
92
|
+
<LineChart
|
|
93
|
+
data={compare}
|
|
94
|
+
index="t"
|
|
95
|
+
series={[
|
|
96
|
+
{ key: "claude", name: "Claude" },
|
|
97
|
+
{ key: "chatgpt", name: "ChatGPT" },
|
|
98
|
+
]}
|
|
99
|
+
lastValueLabel
|
|
100
|
+
legend
|
|
101
|
+
valueFormatter={nf}
|
|
102
|
+
/>
|
|
103
|
+
</ChartCard>
|
|
104
|
+
|
|
105
|
+
<ChartCard palette="magenta" kicker="Last 24h" title="Output tokens" description="Single series · value flags">
|
|
106
|
+
<Stat value="1.4M" unit="tokens" delta={{ value: 8.1, direction: "up" }} sparkline={tokensSpark} />
|
|
107
|
+
<LineChart data={tokens} index="t" series={[{ key: "v", name: "tokens" }]} valueFlags valueFormatter={fmtK} />
|
|
108
|
+
</ChartCard>
|
|
109
|
+
|
|
110
|
+
<ChartCard
|
|
111
|
+
palette="magenta"
|
|
112
|
+
kicker="Last 24h"
|
|
113
|
+
title="Request latency"
|
|
114
|
+
description="p50 vs p95 · SLA band + peak"
|
|
115
|
+
>
|
|
116
|
+
<Stat value="240ms" unit="p50 · current" delta={{ value: 4.2, direction: "down", invert: true }} />
|
|
117
|
+
<LineChart
|
|
118
|
+
data={latency}
|
|
119
|
+
index="t"
|
|
120
|
+
series={[
|
|
121
|
+
{ key: "p50", name: "p50" },
|
|
122
|
+
{ key: "p95", name: "p95", dashed: true, color: "#9b5de5" },
|
|
123
|
+
]}
|
|
124
|
+
referenceLine={{ y: 1000, label: "SLA 1s", band: true }}
|
|
125
|
+
markers={[{ x: latencyPeak.t, y: latencyPeak.p95, label: "peak", color: "#9b5de5" }]}
|
|
126
|
+
legend
|
|
127
|
+
valueFormatter={ms}
|
|
128
|
+
/>
|
|
129
|
+
</ChartCard>
|
|
130
|
+
|
|
131
|
+
<ChartCard
|
|
132
|
+
palette="magenta"
|
|
133
|
+
kicker="Last 24h"
|
|
134
|
+
title="Percentiles"
|
|
135
|
+
description="Interactive legend · click to isolate"
|
|
136
|
+
>
|
|
137
|
+
<LineChart
|
|
138
|
+
data={latency}
|
|
139
|
+
index="t"
|
|
140
|
+
series={percentileSeries}
|
|
141
|
+
dots
|
|
142
|
+
legend
|
|
143
|
+
legendAlign="center"
|
|
144
|
+
lastValueLabel
|
|
145
|
+
hiddenSeries={hiddenPercentiles}
|
|
146
|
+
onLegendItemClick={(key) => setIsolated((current) => (current === key ? null : key))}
|
|
147
|
+
valueFormatter={ms}
|
|
148
|
+
/>
|
|
149
|
+
</ChartCard>
|
|
150
|
+
|
|
151
|
+
<ChartCard palette="cyan" kicker="Last 24h" title="Sessions" description="Claude vs ChatGPT · last values">
|
|
152
|
+
<LineChart
|
|
153
|
+
data={compare}
|
|
154
|
+
index="t"
|
|
155
|
+
series={[
|
|
156
|
+
{ key: "claude", name: "Claude" },
|
|
157
|
+
{ key: "chatgpt", name: "ChatGPT" },
|
|
158
|
+
]}
|
|
159
|
+
lastValueLabel
|
|
160
|
+
legend
|
|
161
|
+
valueFormatter={nf}
|
|
162
|
+
/>
|
|
163
|
+
</ChartCard>
|
|
164
|
+
|
|
165
|
+
<ChartCard palette="cyan" kicker="Last 24h" title="Throughput" description="Dots · stepped curve">
|
|
166
|
+
<LineChart
|
|
167
|
+
data={tokens}
|
|
168
|
+
index="t"
|
|
169
|
+
series={[{ key: "v", name: "tokens" }]}
|
|
170
|
+
curve="step"
|
|
171
|
+
dots
|
|
172
|
+
valueFormatter={fmtK}
|
|
173
|
+
/>
|
|
174
|
+
</ChartCard>
|
|
175
|
+
|
|
176
|
+
<ChartCard palette="magenta" kicker="State" title="Loading" description="Mono spinner placeholder">
|
|
177
|
+
<LineChart data={[]} index="t" series={[{ key: "v", name: "tokens" }]} loading />
|
|
178
|
+
</ChartCard>
|
|
179
|
+
|
|
180
|
+
<ChartCard palette="magenta" kicker="State" title="Empty" description="No data in range">
|
|
181
|
+
<LineChart data={[]} index="t" series={[{ key: "v", name: "tokens" }]} />
|
|
182
|
+
</ChartCard>
|
|
183
|
+
</div>
|
|
144
184
|
</div>
|
|
145
|
-
|
|
146
|
-
|
|
185
|
+
);
|
|
186
|
+
};
|
|
@@ -23,10 +23,7 @@ import {
|
|
|
23
23
|
SidebarTrigger,
|
|
24
24
|
} from "../components/sidebar";
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
* Wraps stories so `fixed` inside SidebarProvider becomes `absolute`
|
|
28
|
-
* relative to this container (via `transform: scale(1)` trick).
|
|
29
|
-
*/
|
|
26
|
+
/** `transform: scale(1)` makes the SidebarProvider's `fixed` elements position relative to this frame. */
|
|
30
27
|
function StoryFrame({ children, height = 600 }: { children: ReactNode; height?: number }) {
|
|
31
28
|
return (
|
|
32
29
|
<div
|
|
@@ -4,7 +4,6 @@ import { Skeleton } from "../components/skeleton";
|
|
|
4
4
|
|
|
5
5
|
export const AllVariants: Story = () => (
|
|
6
6
|
<div className="flex flex-col gap-8">
|
|
7
|
-
{/* Shape variants */}
|
|
8
7
|
<div className="flex flex-col gap-1.5">
|
|
9
8
|
<p className="type-text-xs font-medium text-subtle-foreground">Rectangle (default)</p>
|
|
10
9
|
<div className="flex flex-col gap-2">
|
|
@@ -23,7 +22,6 @@ export const AllVariants: Story = () => (
|
|
|
23
22
|
</div>
|
|
24
23
|
</div>
|
|
25
24
|
|
|
26
|
-
{/* Common compositions */}
|
|
27
25
|
<div className="flex flex-col gap-1.5">
|
|
28
26
|
<p className="type-text-xs font-medium text-subtle-foreground">Card placeholder</p>
|
|
29
27
|
<div className="flex flex-col gap-3 rounded-lg border border-border p-4">
|
|
@@ -88,7 +88,6 @@ const PAGE_SIZE = 3;
|
|
|
88
88
|
|
|
89
89
|
export const AllVariants: Story = () => (
|
|
90
90
|
<div className="flex flex-col gap-8 p-6 bg-background max-w-4xl">
|
|
91
|
-
{/* Text-only table */}
|
|
92
91
|
<div className="flex flex-col gap-1.5">
|
|
93
92
|
<p className="type-text-xs font-medium text-subtle-foreground">Text cells</p>
|
|
94
93
|
<Table>
|
|
@@ -115,7 +114,6 @@ export const AllVariants: Story = () => (
|
|
|
115
114
|
</Table>
|
|
116
115
|
</div>
|
|
117
116
|
|
|
118
|
-
{/* Avatar cells + checkbox */}
|
|
119
117
|
<div className="flex flex-col gap-1.5">
|
|
120
118
|
<p className="type-text-xs font-medium text-subtle-foreground">Avatar cells + checkbox</p>
|
|
121
119
|
<Table>
|
|
@@ -148,7 +146,6 @@ export const AllVariants: Story = () => (
|
|
|
148
146
|
</Table>
|
|
149
147
|
</div>
|
|
150
148
|
|
|
151
|
-
{/* With footer */}
|
|
152
149
|
<div className="flex flex-col gap-1.5">
|
|
153
150
|
<p className="type-text-xs font-medium text-subtle-foreground">With caption + footer</p>
|
|
154
151
|
<Table>
|
|
@@ -178,7 +175,6 @@ export const AllVariants: Story = () => (
|
|
|
178
175
|
</Table>
|
|
179
176
|
</div>
|
|
180
177
|
|
|
181
|
-
{/* Selected row state */}
|
|
182
178
|
<div className="flex flex-col gap-1.5">
|
|
183
179
|
<p className="type-text-xs font-medium text-subtle-foreground">Selected row state</p>
|
|
184
180
|
<Table>
|
|
@@ -201,7 +197,6 @@ export const AllVariants: Story = () => (
|
|
|
201
197
|
</Table>
|
|
202
198
|
</div>
|
|
203
199
|
|
|
204
|
-
{/* Paginated table */}
|
|
205
200
|
<PaginatedTableExample />
|
|
206
201
|
</div>
|
|
207
202
|
);
|
|
@@ -42,9 +42,6 @@ export const AllVariants: Story = () => {
|
|
|
42
42
|
|
|
43
43
|
return (
|
|
44
44
|
<div className="flex flex-col gap-10 p-8">
|
|
45
|
-
{/* ─── Navigation tabs ─────────────────────────────────────── */}
|
|
46
|
-
|
|
47
|
-
{/* Horizontal + line (default) */}
|
|
48
45
|
<div>
|
|
49
46
|
<p className={SECTION_HEADER}>Nav — horizontal, variant="line" (default)</p>
|
|
50
47
|
<div className="mt-4">
|
|
@@ -61,7 +58,6 @@ export const AllVariants: Story = () => {
|
|
|
61
58
|
</div>
|
|
62
59
|
</div>
|
|
63
60
|
|
|
64
|
-
{/* Horizontal + pill */}
|
|
65
61
|
<div>
|
|
66
62
|
<p className={SECTION_HEADER}>Nav — horizontal, variant="pill"</p>
|
|
67
63
|
<div className="mt-4">
|
|
@@ -78,7 +74,6 @@ export const AllVariants: Story = () => {
|
|
|
78
74
|
</div>
|
|
79
75
|
</div>
|
|
80
76
|
|
|
81
|
-
{/* Vertical + pill (default) */}
|
|
82
77
|
<div>
|
|
83
78
|
<p className={SECTION_HEADER}>Nav — vertical, variant="pill" (default)</p>
|
|
84
79
|
<div className="mt-4 flex gap-6">
|
|
@@ -99,9 +94,6 @@ export const AllVariants: Story = () => {
|
|
|
99
94
|
</div>
|
|
100
95
|
</div>
|
|
101
96
|
|
|
102
|
-
{/* ─── Tabs (state-based) ────────────────────────────── */}
|
|
103
|
-
|
|
104
|
-
{/* Tabs — line */}
|
|
105
97
|
<div>
|
|
106
98
|
<p className={SECTION_HEADER}>Tabs — line variant</p>
|
|
107
99
|
<Tabs defaultValue="all" className="mt-4">
|
|
@@ -118,7 +110,6 @@ export const AllVariants: Story = () => {
|
|
|
118
110
|
</Tabs>
|
|
119
111
|
</div>
|
|
120
112
|
|
|
121
|
-
{/* Tabs — default (horizontal) */}
|
|
122
113
|
<div>
|
|
123
114
|
<p className={SECTION_HEADER}>Tabs — default variant (horizontal)</p>
|
|
124
115
|
<Tabs defaultValue="all" className="mt-4">
|
|
@@ -135,7 +126,6 @@ export const AllVariants: Story = () => {
|
|
|
135
126
|
</Tabs>
|
|
136
127
|
</div>
|
|
137
128
|
|
|
138
|
-
{/* Tabs — default (vertical) */}
|
|
139
129
|
<div>
|
|
140
130
|
<p className={SECTION_HEADER}>Tabs — default variant (vertical)</p>
|
|
141
131
|
<Tabs defaultValue="overview" orientation="vertical" className="mt-4">
|
|
@@ -150,7 +140,6 @@ export const AllVariants: Story = () => {
|
|
|
150
140
|
</Tabs>
|
|
151
141
|
</div>
|
|
152
142
|
|
|
153
|
-
{/* Tabs — disabled */}
|
|
154
143
|
<div>
|
|
155
144
|
<p className={SECTION_HEADER}>Tabs — disabled trigger</p>
|
|
156
145
|
<Tabs defaultValue="one" className="mt-4">
|