@a4ui/core 0.32.0 → 0.34.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/charts/BarList.d.ts +33 -0
- package/dist/charts/CategoryBar.d.ts +23 -0
- package/dist/charts/StatusTracker.d.ts +27 -0
- package/dist/charts/index.d.ts +3 -0
- package/dist/charts.js +446 -316
- package/dist/elements.css +278 -0
- package/dist/full.css +278 -0
- package/dist/index.d.ts +25 -1
- package/dist/index.js +6423 -4195
- package/dist/ui/AudioWaveform.d.ts +22 -0
- package/dist/ui/Callout.d.ts +27 -0
- package/dist/ui/Confetti.d.ts +46 -0
- package/dist/ui/CouponField.d.ts +33 -0
- package/dist/ui/CursorTrail.d.ts +25 -0
- package/dist/ui/DiffViewer.d.ts +33 -0
- package/dist/ui/FollowingPointer.d.ts +24 -0
- package/dist/ui/GanttChart.d.ts +37 -0
- package/dist/ui/Globe.d.ts +44 -0
- package/dist/ui/Kanban.d.ts +49 -0
- package/dist/ui/Lamp.d.ts +22 -0
- package/dist/ui/Lightbox.d.ts +41 -0
- package/dist/ui/ModelPicker.d.ts +38 -0
- package/dist/ui/OnboardingChecklist.d.ts +51 -0
- package/dist/ui/PivotTable.d.ts +37 -0
- package/dist/ui/ReasoningTrace.d.ts +28 -0
- package/dist/ui/SheetSnap.d.ts +28 -0
- package/dist/ui/Snippet.d.ts +19 -0
- package/dist/ui/SuggestionChips.d.ts +25 -0
- package/dist/ui/ToolCallTimeline.d.ts +34 -0
- package/dist/ui/TreeTable.d.ts +52 -0
- package/dist/ui/UsageMeter.d.ts +26 -0
- package/dist/ui/VideoPlayerShell.d.ts +19 -0
- package/dist/ui/WorldMap.d.ts +36 -0
- package/package.json +1 -1
- package/src/charts/BarList.tsx +83 -0
- package/src/charts/CategoryBar.tsx +95 -0
- package/src/charts/StatusTracker.tsx +81 -0
- package/src/charts/index.ts +3 -0
- package/src/index.ts +48 -1
- package/src/ui/AudioWaveform.tsx +190 -0
- package/src/ui/Callout.tsx +66 -0
- package/src/ui/Confetti.tsx +131 -0
- package/src/ui/CouponField.tsx +120 -0
- package/src/ui/CursorTrail.tsx +88 -0
- package/src/ui/DiffViewer.tsx +166 -0
- package/src/ui/FollowingPointer.tsx +112 -0
- package/src/ui/GanttChart.tsx +283 -0
- package/src/ui/Globe.tsx +317 -0
- package/src/ui/Kanban.tsx +250 -0
- package/src/ui/Lamp.tsx +88 -0
- package/src/ui/Lightbox.tsx +261 -0
- package/src/ui/ModelPicker.tsx +119 -0
- package/src/ui/OnboardingChecklist.tsx +163 -0
- package/src/ui/PivotTable.tsx +0 -0
- package/src/ui/ReasoningTrace.tsx +83 -0
- package/src/ui/SheetSnap.tsx +264 -0
- package/src/ui/Snippet.tsx +64 -0
- package/src/ui/SuggestionChips.tsx +65 -0
- package/src/ui/ToolCallTimeline.tsx +137 -0
- package/src/ui/TreeTable.tsx +172 -0
- package/src/ui/UsageMeter.tsx +71 -0
- package/src/ui/VideoPlayerShell.tsx +282 -0
- package/src/ui/WorldMap.tsx +191 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { JSX } from 'solid-js';
|
|
2
|
+
/** Status of a single tool call rendered by {@link ToolCallTimeline}. */
|
|
3
|
+
export type ToolCallStatus = 'pending' | 'success' | 'error';
|
|
4
|
+
/** A single tool invocation rendered by {@link ToolCallTimeline}. */
|
|
5
|
+
export interface ToolCall {
|
|
6
|
+
/** Tool/function name, rendered in mono. */
|
|
7
|
+
name: string;
|
|
8
|
+
status: ToolCallStatus;
|
|
9
|
+
/** Arguments passed to the call. Shown in a collapsible details area when present. */
|
|
10
|
+
args?: JSX.Element | string;
|
|
11
|
+
/** Result returned by the call. Shown in a collapsible details area when present. */
|
|
12
|
+
result?: JSX.Element | string;
|
|
13
|
+
}
|
|
14
|
+
export interface ToolCallTimelineProps {
|
|
15
|
+
calls: ToolCall[];
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Vertical timeline of AI tool calls: a connector line runs down the left with
|
|
20
|
+
* a status node per call (spinner while `pending`, check when `success`, x when
|
|
21
|
+
* `error`), the tool name in mono, and — when `args`/`result` are given — a
|
|
22
|
+
* collapsible details panel underneath.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <ToolCallTimeline
|
|
27
|
+
* calls={[
|
|
28
|
+
* { name: 'search_docs', status: 'success', args: 'query: "refunds"', result: '3 matches' },
|
|
29
|
+
* { name: 'update_ticket', status: 'pending' },
|
|
30
|
+
* ]}
|
|
31
|
+
* />
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function ToolCallTimeline(props: ToolCallTimelineProps): JSX.Element;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { JSX } from 'solid-js';
|
|
2
|
+
/** A column definition for {@link TreeTable}. */
|
|
3
|
+
export interface TreeTableColumn<T> {
|
|
4
|
+
/** Row data property this column reads when `cell` is omitted. */
|
|
5
|
+
key: string;
|
|
6
|
+
/** Column heading content. */
|
|
7
|
+
header: JSX.Element;
|
|
8
|
+
/** Custom cell renderer; falls back to `String(row[key])` when omitted. */
|
|
9
|
+
cell?: (row: T) => JSX.Element;
|
|
10
|
+
/** Right-align the column (numbers, totals). */
|
|
11
|
+
align?: 'left' | 'right';
|
|
12
|
+
}
|
|
13
|
+
/** A single node in a {@link TreeTable}; nodes may nest via `children`. */
|
|
14
|
+
export interface TreeTableRow<T> {
|
|
15
|
+
/** Unique identifier; used to track expanded state. */
|
|
16
|
+
id: string;
|
|
17
|
+
/** Row payload passed to each column's `cell` renderer. */
|
|
18
|
+
data: T;
|
|
19
|
+
/** Child rows revealed when this row is expanded. */
|
|
20
|
+
children?: TreeTableRow<T>[];
|
|
21
|
+
}
|
|
22
|
+
export interface TreeTableProps<T> {
|
|
23
|
+
columns: TreeTableColumn<T>[];
|
|
24
|
+
rows: TreeTableRow<T>[];
|
|
25
|
+
/** Expand every row with children on first render. Defaults to false. */
|
|
26
|
+
defaultExpanded?: boolean;
|
|
27
|
+
class?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Hierarchical table: rows may carry `children`, revealed by clicking the
|
|
31
|
+
* chevron in the first column. Depth is shown via indentation; expanded state
|
|
32
|
+
* is tracked internally, seeded fully expanded when `defaultExpanded` is set.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* <TreeTable
|
|
37
|
+
* defaultExpanded
|
|
38
|
+
* columns={[
|
|
39
|
+
* { key: 'name', header: 'Name' },
|
|
40
|
+
* { key: 'size', header: 'Size', align: 'right', cell: (row) => `${row.size} KB` },
|
|
41
|
+
* ]}
|
|
42
|
+
* rows={[
|
|
43
|
+
* {
|
|
44
|
+
* id: 'src',
|
|
45
|
+
* data: { name: 'src', size: 0 },
|
|
46
|
+
* children: [{ id: 'index', data: { name: 'index.ts', size: 2 } }],
|
|
47
|
+
* },
|
|
48
|
+
* ]}
|
|
49
|
+
* />
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function TreeTable<T>(props: TreeTableProps<T>): JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { JSX } from 'solid-js';
|
|
2
|
+
export interface UsageMeterProps {
|
|
3
|
+
used: number;
|
|
4
|
+
limit: number;
|
|
5
|
+
/** Header content shown before the "{used}/{limit}{unit}" count. */
|
|
6
|
+
label?: JSX.Element;
|
|
7
|
+
/** Appended to displayed numbers, e.g. `' tokens'` or `'%'`. */
|
|
8
|
+
unit?: string;
|
|
9
|
+
/** Fraction of `limit` (0–1) at which the fill switches to the warning tone. @default 0.85 */
|
|
10
|
+
warnAt?: number;
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Labeled consumption bar: a header row with `label` and the raw
|
|
15
|
+
* "{used}/{limit}{unit}" count, a track whose fill width is `used / limit`
|
|
16
|
+
* (clamped to 0–100%) and switches to a warning tone once that ratio reaches
|
|
17
|
+
* `warnAt`, and a small "{remaining} left" line underneath. Built on Kobalte's
|
|
18
|
+
* `Meter` primitive, so it carries the same `role="meter"` a11y semantics as
|
|
19
|
+
* {@link Meter}.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <UsageMeter used={92} limit={100} label="API requests" unit=" req" warnAt={0.9} />
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function UsageMeter(props: UsageMeterProps): JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { JSX } from 'solid-js';
|
|
2
|
+
export interface VideoPlayerShellProps {
|
|
3
|
+
src: string;
|
|
4
|
+
poster?: string;
|
|
5
|
+
class?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Native `<video>` wrapped in a glass shell with fully custom controls: a big
|
|
9
|
+
* center play/pause, a bottom bar (play/pause, elapsed/duration, a scrub
|
|
10
|
+
* range, mute toggle, fullscreen, Picture-in-Picture), and a keyboard map
|
|
11
|
+
* (Space = play/pause, ArrowLeft/Right = seek ±5s). Controls auto-hide while
|
|
12
|
+
* playing and reappear on pointer movement.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <VideoPlayerShell src="/media/demo.mp4" poster="/media/demo-poster.jpg" />
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function VideoPlayerShell(props: VideoPlayerShellProps): JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { JSX } from 'solid-js';
|
|
2
|
+
export interface WorldMapPoint {
|
|
3
|
+
lat: number;
|
|
4
|
+
lng: number;
|
|
5
|
+
label?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface WorldMapConnection {
|
|
8
|
+
from: WorldMapPoint;
|
|
9
|
+
to: WorldMapPoint;
|
|
10
|
+
}
|
|
11
|
+
export interface WorldMapProps {
|
|
12
|
+
/** Arcs to draw between projected points. @default [] */
|
|
13
|
+
connections?: WorldMapConnection[];
|
|
14
|
+
class?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A decorative, dependency-free SVG "world map": an evenly spaced dotted-grid
|
|
18
|
+
* backdrop (a stylized map, not accurate coastlines) with connection arcs
|
|
19
|
+
* projected from lat/lng via equirectangular mapping. Each arc bulges upward
|
|
20
|
+
* and carries a traveling primary→accent gradient segment (reusing
|
|
21
|
+
* {@link AnimatedBeam}'s technique); arcs render static under reduced motion.
|
|
22
|
+
* Responsive — scales to its container via the 2:1 `viewBox`.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <WorldMap
|
|
27
|
+
* class="w-full"
|
|
28
|
+
* connections={[
|
|
29
|
+
* { from: { lat: 40.7128, lng: -74.006, label: 'New York' }, to: { lat: 51.5074, lng: -0.1278, label: 'London' } },
|
|
30
|
+
* { from: { lat: 51.5074, lng: -0.1278 }, to: { lat: 35.6762, lng: 139.6503, label: 'Tokyo' } },
|
|
31
|
+
* { from: { lat: 40.7128, lng: -74.006 }, to: { lat: -23.5505, lng: -46.6333, label: 'São Paulo' } },
|
|
32
|
+
* ]}
|
|
33
|
+
* />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function WorldMap(props: WorldMapProps): JSX.Element;
|
package/package.json
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// BarList — a ranked horizontal bar list built from plain flex `div`s (no
|
|
2
|
+
// SVG, no charting library). Rows are sorted by value descending; each row
|
|
3
|
+
// is a full-width track with a low-opacity theme-toned fill sized to
|
|
4
|
+
// `value / max`, the `name` overlaid at the left (truncated, linked when
|
|
5
|
+
// `href` is set) and the formatted value at the right. Colors come from
|
|
6
|
+
// theme tokens only.
|
|
7
|
+
import { For, Show, type JSX } from 'solid-js'
|
|
8
|
+
|
|
9
|
+
import { cn } from '../lib/cn'
|
|
10
|
+
|
|
11
|
+
export interface BarListDatum {
|
|
12
|
+
name: string
|
|
13
|
+
value: number
|
|
14
|
+
href?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface BarListProps {
|
|
18
|
+
data: BarListDatum[]
|
|
19
|
+
/** Formats the raw value shown at the row's end. Default `String`. */
|
|
20
|
+
valueFormat?: (n: number) => string
|
|
21
|
+
/** Fill color token. Default 'primary'. */
|
|
22
|
+
tone?: 'primary' | 'accent'
|
|
23
|
+
class?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Ranked horizontal bar list: rows sorted by `value` descending, each a
|
|
28
|
+
* full-width track with a low-opacity fill sized to `value / max` of the
|
|
29
|
+
* tallest row, the `name` overlaid at the left (truncated, rendered as a
|
|
30
|
+
* link when `href` is set) and the formatted value at the right. Compact
|
|
31
|
+
* and reflows with its container.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* <BarList
|
|
36
|
+
* data={[
|
|
37
|
+
* { name: '/dashboard', value: 842, href: '/pages/dashboard' },
|
|
38
|
+
* { name: '/settings', value: 231 },
|
|
39
|
+
* ]}
|
|
40
|
+
* tone="accent"
|
|
41
|
+
* />
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function BarList(props: BarListProps): JSX.Element {
|
|
45
|
+
const tone = () => props.tone ?? 'primary'
|
|
46
|
+
const format = () => props.valueFormat ?? ((n: number) => String(n))
|
|
47
|
+
const fillClass = () => (tone() === 'accent' ? 'bg-accent/15' : 'bg-primary/15')
|
|
48
|
+
const sorted = () => [...props.data].sort((a, b) => b.value - a.value)
|
|
49
|
+
const max = () => Math.max(...props.data.map((d) => d.value), 0) || 1
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div class={cn('flex w-full flex-col gap-1.5', props.class)}>
|
|
53
|
+
<For each={sorted()}>
|
|
54
|
+
{(datum) => (
|
|
55
|
+
<div class="relative isolate flex h-8 w-full min-w-0 items-center overflow-hidden rounded-md bg-muted/40">
|
|
56
|
+
<div
|
|
57
|
+
class={cn('absolute inset-y-0 left-0 rounded-md transition-all', fillClass())}
|
|
58
|
+
style={{ width: `${Math.max((datum.value / max()) * 100, 0)}%` }}
|
|
59
|
+
/>
|
|
60
|
+
<Show
|
|
61
|
+
when={datum.href}
|
|
62
|
+
fallback={
|
|
63
|
+
<span class="relative z-10 min-w-0 flex-1 truncate px-2.5 text-sm text-foreground">
|
|
64
|
+
{datum.name}
|
|
65
|
+
</span>
|
|
66
|
+
}
|
|
67
|
+
>
|
|
68
|
+
<a
|
|
69
|
+
href={datum.href}
|
|
70
|
+
class="relative z-10 min-w-0 flex-1 truncate px-2.5 text-sm text-foreground underline-offset-2 hover:underline"
|
|
71
|
+
>
|
|
72
|
+
{datum.name}
|
|
73
|
+
</a>
|
|
74
|
+
</Show>
|
|
75
|
+
<span class="relative z-10 shrink-0 px-2.5 text-sm tabular-nums text-muted-foreground">
|
|
76
|
+
{format()(datum.value)}
|
|
77
|
+
</span>
|
|
78
|
+
</div>
|
|
79
|
+
)}
|
|
80
|
+
</For>
|
|
81
|
+
</div>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// CategoryBar — a single horizontal segmented bar built from plain flex
|
|
2
|
+
// `div`s (no SVG, no charting library). Each segment's width is its share of
|
|
3
|
+
// the total (via CSS `flex-grow`), segments join seamlessly inside a
|
|
4
|
+
// rounded track, an optional caret marks a value along the total (pure-CSS
|
|
5
|
+
// border triangle), and cumulative boundary labels sit beneath. `success`/
|
|
6
|
+
// `warning` tones reuse `Alert`/`Badge`'s `emerald-500`/`amber-500` (the repo
|
|
7
|
+
// has no dedicated CSS token for them); `primary`/`accent`/`destructive` are
|
|
8
|
+
// the shared semantic tokens.
|
|
9
|
+
import { createMemo, For, Show, type JSX } from 'solid-js'
|
|
10
|
+
|
|
11
|
+
import { cn } from '../lib/cn'
|
|
12
|
+
|
|
13
|
+
export type CategoryBarTone = 'primary' | 'accent' | 'success' | 'warning' | 'destructive'
|
|
14
|
+
|
|
15
|
+
export interface CategoryBarProps {
|
|
16
|
+
values: number[]
|
|
17
|
+
/** A value along the cumulative total to mark with a caret above the bar. */
|
|
18
|
+
marker?: number
|
|
19
|
+
/** Per-segment color tokens; cycles the default order below when omitted or shorter than `values`. */
|
|
20
|
+
tones?: CategoryBarTone[]
|
|
21
|
+
class?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const DEFAULT_TONES: CategoryBarTone[] = ['primary', 'accent', 'success', 'warning', 'destructive']
|
|
25
|
+
|
|
26
|
+
const TONE_CLASSES: Record<CategoryBarTone, string> = {
|
|
27
|
+
primary: 'bg-primary',
|
|
28
|
+
accent: 'bg-accent',
|
|
29
|
+
success: 'bg-emerald-500',
|
|
30
|
+
warning: 'bg-amber-500',
|
|
31
|
+
destructive: 'bg-destructive',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Cumulative running sum of `values`, one boundary per entry (same length as `values`). */
|
|
35
|
+
function cumulativeBounds(values: number[]): number[] {
|
|
36
|
+
let running = 0
|
|
37
|
+
return values.map((v) => (running += v))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Single segmented bar: each `values[i]` sets a segment's flex-grow share of
|
|
42
|
+
* the total, colored by `tones[i]` (cycling a sensible default), joined
|
|
43
|
+
* seamlessly inside one rounded track. An optional `marker` renders a caret
|
|
44
|
+
* above the bar at that value's position along the total, and cumulative
|
|
45
|
+
* boundary labels sit beneath (muted, tabular-nums).
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```tsx
|
|
49
|
+
* <CategoryBar values={[40, 25, 20, 15]} marker={62} />
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function CategoryBar(props: CategoryBarProps): JSX.Element {
|
|
53
|
+
const total = createMemo(() => props.values.reduce((sum, v) => sum + v, 0) || 1)
|
|
54
|
+
const bounds = createMemo(() => cumulativeBounds(props.values))
|
|
55
|
+
const tones = () => (props.tones && props.tones.length > 0 ? props.tones : DEFAULT_TONES)
|
|
56
|
+
const markerPct = createMemo(() =>
|
|
57
|
+
props.marker == null ? undefined : Math.min(Math.max((props.marker / total()) * 100, 0), 100),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div class={cn('w-full', props.class)}>
|
|
62
|
+
<div class="relative">
|
|
63
|
+
<Show when={markerPct() !== undefined}>
|
|
64
|
+
<div
|
|
65
|
+
class="absolute -top-1.5 h-0 w-0 -translate-x-1/2 border-x-4 border-t-4 border-x-transparent border-t-foreground"
|
|
66
|
+
style={{ left: `${markerPct()}%` }}
|
|
67
|
+
aria-hidden="true"
|
|
68
|
+
/>
|
|
69
|
+
</Show>
|
|
70
|
+
<div class="flex h-2.5 w-full overflow-hidden rounded-full bg-muted">
|
|
71
|
+
<For each={props.values}>
|
|
72
|
+
{(value, i) => (
|
|
73
|
+
<div
|
|
74
|
+
class={cn('h-full', TONE_CLASSES[tones()[i() % tones().length] ?? 'primary'])}
|
|
75
|
+
style={{ flex: `${Math.max(value, 0)} 0 0%` }}
|
|
76
|
+
/>
|
|
77
|
+
)}
|
|
78
|
+
</For>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
<div class="relative mt-1 h-4 w-full text-xs tabular-nums text-muted-foreground">
|
|
82
|
+
<For each={bounds()}>
|
|
83
|
+
{(bound) => (
|
|
84
|
+
<span
|
|
85
|
+
class="absolute -translate-x-1/2 whitespace-nowrap"
|
|
86
|
+
style={{ left: `${Math.min(Math.max((bound / total()) * 100, 0), 100)}%` }}
|
|
87
|
+
>
|
|
88
|
+
{bound}
|
|
89
|
+
</span>
|
|
90
|
+
)}
|
|
91
|
+
</For>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// StatusTracker — a status-page style history bar built from plain flex
|
|
2
|
+
// `div`s (no SVG, no charting library). Each segment is a thin rounded bar
|
|
3
|
+
// colored by its status, with a native tooltip carrying the label. `ok`/
|
|
4
|
+
// `degraded` reuse the same success/warning tones as `Alert`/`Badge`
|
|
5
|
+
// (`emerald-500`/`amber-500` — the repo has no dedicated CSS token for
|
|
6
|
+
// them); `down` uses the `--destructive` semantic token.
|
|
7
|
+
import { For, Show, type JSX } from 'solid-js'
|
|
8
|
+
|
|
9
|
+
import { cn } from '../lib/cn'
|
|
10
|
+
|
|
11
|
+
export interface StatusSegment {
|
|
12
|
+
status: 'ok' | 'degraded' | 'down'
|
|
13
|
+
label?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface StatusTrackerProps {
|
|
17
|
+
segments: StatusSegment[]
|
|
18
|
+
class?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const STATUS_CLASSES: Record<StatusSegment['status'], string> = {
|
|
22
|
+
ok: 'bg-emerald-500',
|
|
23
|
+
degraded: 'bg-amber-500',
|
|
24
|
+
down: 'bg-destructive',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const STATUS_LABEL: Record<StatusSegment['status'], string> = {
|
|
28
|
+
ok: 'Operational',
|
|
29
|
+
degraded: 'Degraded',
|
|
30
|
+
down: 'Down',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Share of `segments` that are `'ok'`, formatted as e.g. `"98.7% uptime"`; `undefined` when empty. */
|
|
34
|
+
function uptimeSummary(segments: StatusSegment[]): string | undefined {
|
|
35
|
+
if (segments.length === 0) return undefined
|
|
36
|
+
const ok = segments.filter((s) => s.status === 'ok').length
|
|
37
|
+
return `${((ok / segments.length) * 100).toFixed(1)}% uptime`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Status-page style history bar: a row of thin rounded segments colored by
|
|
42
|
+
* `status` (ok/degraded/down), each with a native hover tooltip showing its
|
|
43
|
+
* label and status, plus a summary uptime line above.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* <StatusTracker
|
|
48
|
+
* segments={[
|
|
49
|
+
* { status: 'ok', label: 'Jul 1' },
|
|
50
|
+
* { status: 'degraded', label: 'Jul 2' },
|
|
51
|
+
* { status: 'ok', label: 'Jul 3' },
|
|
52
|
+
* { status: 'down', label: 'Jul 4' },
|
|
53
|
+
* ]}
|
|
54
|
+
* />
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function StatusTracker(props: StatusTrackerProps): JSX.Element {
|
|
58
|
+
const summary = () => uptimeSummary(props.segments)
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div class={cn('flex w-full flex-col gap-1.5', props.class)}>
|
|
62
|
+
<Show when={summary()}>
|
|
63
|
+
<span class="text-xs text-muted-foreground">{summary()}</span>
|
|
64
|
+
</Show>
|
|
65
|
+
<div class="flex w-full items-stretch gap-1">
|
|
66
|
+
<For each={props.segments}>
|
|
67
|
+
{(segment) => (
|
|
68
|
+
<div
|
|
69
|
+
title={
|
|
70
|
+
segment.label
|
|
71
|
+
? `${segment.label}: ${STATUS_LABEL[segment.status]}`
|
|
72
|
+
: STATUS_LABEL[segment.status]
|
|
73
|
+
}
|
|
74
|
+
class={cn('h-6 flex-1 rounded-sm transition-colors', STATUS_CLASSES[segment.status])}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
</For>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
)
|
|
81
|
+
}
|
package/src/charts/index.ts
CHANGED
|
@@ -6,3 +6,6 @@ export { DonutChart, type DonutSegment, type DonutChartProps } from './DonutChar
|
|
|
6
6
|
export { LineChart, type LineSeries, type LineChartProps } from './LineChart'
|
|
7
7
|
export { GaugeChart, type GaugeThreshold, type GaugeChartProps } from './GaugeChart'
|
|
8
8
|
export { RadarChart, type RadarSeries, type RadarChartProps } from './RadarChart'
|
|
9
|
+
export { BarList, type BarListDatum, type BarListProps } from './BarList'
|
|
10
|
+
export { StatusTracker, type StatusSegment, type StatusTrackerProps } from './StatusTracker'
|
|
11
|
+
export { CategoryBar, type CategoryBarTone, type CategoryBarProps } from './CategoryBar'
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// import '@a4ui/core/styles.css'
|
|
9
9
|
// import { Button, Card, Modal } from '@a4ui/core'
|
|
10
10
|
|
|
11
|
-
export const A4UI_VERSION = '0.
|
|
11
|
+
export const A4UI_VERSION = '0.34.0'
|
|
12
12
|
|
|
13
13
|
// Helpers (src/lib) — generic, framework-level utilities.
|
|
14
14
|
export { cn } from './lib/cn'
|
|
@@ -186,6 +186,53 @@ export { Dock, type DockItem, type DockProps } from './ui/Dock'
|
|
|
186
186
|
export { AnimatedBeam, type AnimatedBeamProps } from './ui/AnimatedBeam'
|
|
187
187
|
export { BorderBeam, type BorderBeamProps } from './ui/BorderBeam'
|
|
188
188
|
export { Meteors, type MeteorsProps } from './ui/Meteors'
|
|
189
|
+
|
|
190
|
+
// AI agent surface + chat affordances.
|
|
191
|
+
export { ReasoningTrace, type ReasoningTraceProps } from './ui/ReasoningTrace'
|
|
192
|
+
export {
|
|
193
|
+
ToolCallTimeline,
|
|
194
|
+
type ToolCall,
|
|
195
|
+
type ToolCallStatus,
|
|
196
|
+
type ToolCallTimelineProps,
|
|
197
|
+
} from './ui/ToolCallTimeline'
|
|
198
|
+
export { DiffViewer, type DiffLine, type DiffViewerProps } from './ui/DiffViewer'
|
|
199
|
+
export { ModelPicker, type ModelOption, type ModelPickerProps } from './ui/ModelPicker'
|
|
200
|
+
export { UsageMeter, type UsageMeterProps } from './ui/UsageMeter'
|
|
201
|
+
export { SuggestionChips, type SuggestionChipsProps } from './ui/SuggestionChips'
|
|
202
|
+
|
|
203
|
+
// Content blocks.
|
|
204
|
+
export { Callout, type CalloutTone, type CalloutProps } from './ui/Callout'
|
|
205
|
+
export { Snippet, type SnippetProps } from './ui/Snippet'
|
|
206
|
+
|
|
207
|
+
// Spatial showpieces + motion extras.
|
|
208
|
+
export { Globe, type GlobeMarker, type GlobeArc, type GlobeProps } from './ui/Globe'
|
|
209
|
+
export { WorldMap, type WorldMapPoint, type WorldMapConnection, type WorldMapProps } from './ui/WorldMap'
|
|
210
|
+
export { Confetti, fireConfetti, type ConfettiProps } from './ui/Confetti'
|
|
211
|
+
export { CursorTrail, type CursorTrailProps } from './ui/CursorTrail'
|
|
212
|
+
|
|
213
|
+
// Productivity data views.
|
|
214
|
+
export { Kanban, type KanbanCard, type KanbanColumn, type KanbanProps } from './ui/Kanban'
|
|
215
|
+
export { GanttChart, type GanttTask, type GanttChartProps } from './ui/GanttChart'
|
|
216
|
+
export { TreeTable, type TreeTableColumn, type TreeTableRow, type TreeTableProps } from './ui/TreeTable'
|
|
217
|
+
export { PivotTable, type PivotDatum, type PivotTableProps } from './ui/PivotTable'
|
|
218
|
+
|
|
219
|
+
// Onboarding + commerce.
|
|
220
|
+
export {
|
|
221
|
+
OnboardingChecklist,
|
|
222
|
+
type OnboardingStep,
|
|
223
|
+
type OnboardingChecklistProps,
|
|
224
|
+
} from './ui/OnboardingChecklist'
|
|
225
|
+
export { CouponField, type CouponFieldProps } from './ui/CouponField'
|
|
226
|
+
|
|
227
|
+
// Media.
|
|
228
|
+
export { Lightbox, type LightboxImage, type LightboxProps } from './ui/Lightbox'
|
|
229
|
+
export { VideoPlayerShell, type VideoPlayerShellProps } from './ui/VideoPlayerShell'
|
|
230
|
+
export { AudioWaveform, type AudioWaveformProps } from './ui/AudioWaveform'
|
|
231
|
+
|
|
232
|
+
// Spatial + interaction.
|
|
233
|
+
export { Lamp, type LampProps } from './ui/Lamp'
|
|
234
|
+
export { FollowingPointer, type FollowingPointerProps } from './ui/FollowingPointer'
|
|
235
|
+
export { SheetSnap, type SheetSnapProps } from './ui/SheetSnap'
|
|
189
236
|
export {
|
|
190
237
|
CopyButton,
|
|
191
238
|
type CopyButtonProps,
|