img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
- className
- )}
- {...props}
- />
- )
-}
-
-function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardAction({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardContent({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-export {
- Card,
- CardHeader,
- CardFooter,
- CardTitle,
- CardAction,
- CardDescription,
- CardContent,
-}
diff --git a/src/lib/components/ui/progress.tsx b/src/lib/components/ui/progress.tsx
deleted file mode 100644
index 65d0a6b..0000000
--- a/src/lib/components/ui/progress.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import * as React from "react"
-import { Progress as ProgressPrimitive } from "radix-ui"
-
-import { cn } from "$lib/utils"
-
-function Progress({
- className,
- value,
- ...props
-}: React.ComponentProps
) {
- return (
-
-
-
- )
-}
-
-export { Progress }
diff --git a/src/lib/components/ui/separator.tsx b/src/lib/components/ui/separator.tsx
deleted file mode 100644
index 84e3c64..0000000
--- a/src/lib/components/ui/separator.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-"use client"
-
-import * as React from "react"
-import { Separator as SeparatorPrimitive } from "radix-ui"
-
-import { cn } from "$lib/utils"
-
-function Separator({
- className,
- orientation = "horizontal",
- decorative = true,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export { Separator }
diff --git a/src/lib/components/ui/skeleton.tsx b/src/lib/components/ui/skeleton.tsx
deleted file mode 100644
index 61466a8..0000000
--- a/src/lib/components/ui/skeleton.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { cn } from "$lib/utils"
-
-function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-export { Skeleton }
diff --git a/src/lib/model/fixtures/index.ts b/src/lib/model/fixtures/index.ts
deleted file mode 100644
index a04278d..0000000
--- a/src/lib/model/fixtures/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { dimensionLabDashboardFixture } from "./dimensionlab";
-export { genericDashboardFixture } from "./generic";
diff --git a/src/lib/ui/components/Badge.tsx b/src/lib/ui/components/Badge.tsx
deleted file mode 100644
index a21ade8..0000000
--- a/src/lib/ui/components/Badge.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import type { UiSeverity } from "../types";
-import { StatusBadge } from "./StatusBadge";
-
-export interface BadgeProps {
- label: string;
- severity?: UiSeverity;
-}
-
-export function Badge({ label, severity = "neutral" }: BadgeProps) {
- return ;
-}
diff --git a/src/lib/ui/components/Button.tsx b/src/lib/ui/components/Button.tsx
deleted file mode 100644
index 8ae3b4e..0000000
--- a/src/lib/ui/components/Button.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import type { ButtonHTMLAttributes } from "react";
-import { IconGlyph } from "./IconGlyph";
-
-export interface ButtonProps
- extends Omit, "type"> {
- label: string;
- variant?: "primary" | "secondary" | "danger" | "ghost";
- size?: "default" | "compact";
- icon?: string;
- loading?: boolean;
- type?: "button" | "submit" | "reset";
-}
-
-export function Button({
- label,
- variant = "primary",
- size = "default",
- icon,
- disabled = false,
- loading = false,
- type = "button",
- className = "",
- ...buttonProps
-}: ButtonProps) {
- return (
-
- );
-}
diff --git a/src/lib/ui/components/CornerBracketFrame.tsx b/src/lib/ui/components/CornerBracketFrame.tsx
deleted file mode 100644
index 1dfd4f7..0000000
--- a/src/lib/ui/components/CornerBracketFrame.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-export interface CornerBracketFrameProps {
- density?: "regular" | "tight";
- size?: "sm" | "md" | "lg";
- tone?: "neutral" | "accent" | "danger";
-}
-
-export function CornerBracketFrame({
- density = "regular",
- size = "md",
- tone = "neutral",
-}: CornerBracketFrameProps) {
- return (
-
-
-
-
-
-
- );
-}
diff --git a/src/lib/ui/components/DashboardFrame.tsx b/src/lib/ui/components/DashboardFrame.tsx
deleted file mode 100644
index 6a3a35b..0000000
--- a/src/lib/ui/components/DashboardFrame.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { useId } from "react";
-import type { ReactNode } from "react";
-import type { UiDashboardPreview } from "../types";
-import { ModuleCard } from "./ModuleCard";
-import { ServicePanel } from "./ServicePanel";
-import { StatusStrip } from "./StatusStrip";
-import { TelemetryGrid } from "./TelemetryGrid";
-
-export interface DashboardFrameProps {
- actions?: ReactNode;
- dashboard: UiDashboardPreview;
- titleId?: string;
-}
-
-export function DashboardFrame({
- actions,
- dashboard,
- titleId,
-}: DashboardFrameProps) {
- const generatedTitleId = useId();
- const resolvedTitleId = titleId || `${generatedTitleId}-title`;
-
- return (
-
-
-
-
-
-
- {dashboard.serviceGroups.map((group) => (
-
- ))}
-
-
-
-
- );
-}
diff --git a/src/lib/ui/components/DashboardHeader.tsx b/src/lib/ui/components/DashboardHeader.tsx
deleted file mode 100644
index 68b4e11..0000000
--- a/src/lib/ui/components/DashboardHeader.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { useId } from "react";
-import type { UiModuleBlock } from "../types";
-import { ModuleCard } from "./ModuleCard";
-
-export interface DashboardHeaderProps {
- title: string;
- subtitle?: string;
- eyebrow?: string;
- module?: UiModuleBlock;
-}
-
-export function DashboardHeader({
- title,
- subtitle,
- eyebrow,
- module,
-}: DashboardHeaderProps) {
- const titleId = useId();
-
- return (
-
-
- {eyebrow ?
{eyebrow}
: null}
-
{title}
- {subtitle ?
{subtitle} : null}
-
- {module ? : null}
-
- );
-}
diff --git a/src/lib/ui/components/DiagonalStripeField.tsx b/src/lib/ui/components/DiagonalStripeField.tsx
deleted file mode 100644
index b4c60f8..0000000
--- a/src/lib/ui/components/DiagonalStripeField.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-export interface DiagonalStripeFieldProps {
- density?: "open" | "regular" | "tight";
- direction?: "forward" | "backward";
- size?: "sm" | "md" | "lg";
- tone?: "neutral" | "accent" | "warning" | "danger";
-}
-
-export function DiagonalStripeField({
- density = "regular",
- direction = "forward",
- size = "md",
- tone = "accent",
-}: DiagonalStripeFieldProps) {
- return (
-
- );
-}
diff --git a/src/lib/ui/components/FooterCell.tsx b/src/lib/ui/components/FooterCell.tsx
deleted file mode 100644
index 760e853..0000000
--- a/src/lib/ui/components/FooterCell.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import type { UiStatusItem } from "../types";
-
-export interface FooterCellProps {
- item: UiStatusItem;
-}
-
-export function FooterCell({ item }: FooterCellProps) {
- const target = item.link?.external ? "_blank" : undefined;
- const rel = item.link?.external ? "noreferrer" : undefined;
- const content = (
- <>
- {item.label}
- {item.value}
- >
- );
-
- if (item.link) {
- return (
-
- {content}
-
- );
- }
-
- return (
-
- {content}
-
- );
-}
diff --git a/src/lib/ui/components/FooterStatusCell.tsx b/src/lib/ui/components/FooterStatusCell.tsx
deleted file mode 100644
index dcfb8b4..0000000
--- a/src/lib/ui/components/FooterStatusCell.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import type { UiStatusItem } from "../types";
-import { FooterCell } from "./FooterCell";
-
-export function FooterStatusCell({ item }: { item: UiStatusItem }) {
- return ;
-}
diff --git a/src/lib/ui/components/GridFrame.tsx b/src/lib/ui/components/GridFrame.tsx
deleted file mode 100644
index 0d9c91f..0000000
--- a/src/lib/ui/components/GridFrame.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import type { PropsWithChildren } from "react";
-
-export interface GridFrameProps extends PropsWithChildren {
- density?: "compact" | "dense";
-}
-
-export function GridFrame({ children, density = "dense" }: GridFrameProps) {
- return (
-
- );
-}
diff --git a/src/lib/ui/components/IconButton.tsx b/src/lib/ui/components/IconButton.tsx
deleted file mode 100644
index 92fcb46..0000000
--- a/src/lib/ui/components/IconButton.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import type { ButtonHTMLAttributes } from "react";
-import { IconGlyph } from "./IconGlyph";
-
-export interface IconButtonProps
- extends Omit, "type"> {
- icon: string;
- label: string;
- active?: boolean;
- type?: "button" | "submit" | "reset";
-}
-
-export function IconButton({
- icon,
- label,
- active = false,
- disabled = false,
- type = "button",
- className = "",
- ...buttonProps
-}: IconButtonProps) {
- return (
-
- );
-}
diff --git a/src/lib/ui/components/IconGlyph.tsx b/src/lib/ui/components/IconGlyph.tsx
deleted file mode 100644
index d21feb1..0000000
--- a/src/lib/ui/components/IconGlyph.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { Icon } from "@iconify/react";
-
-export interface IconGlyphProps {
- name?: string;
- label?: string;
- size?: "sm" | "md" | "lg";
-}
-
-export function IconGlyph({ name, label, size = "md" }: IconGlyphProps) {
- return (
-
- {name ? : null}
-
- );
-}
diff --git a/src/lib/ui/components/LineChart.tsx b/src/lib/ui/components/LineChart.tsx
deleted file mode 100644
index 386b515..0000000
--- a/src/lib/ui/components/LineChart.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import "uplot/dist/uPlot.min.css";
-import { useEffect, useRef } from "react";
-import type { UiSeverity } from "../types";
-
-export interface LineChartProps {
- values?: number[];
- severity?: UiSeverity;
- label?: string;
-}
-
-export function LineChart({
- values = [],
- severity = "neutral",
- label = "Telemetry trend",
-}: LineChartProps) {
- const chartElementRef = useRef(null);
- const valuesKey = values.join(",");
-
- useEffect(() => {
- const chartElement = chartElementRef.current;
- if (!chartElement) return;
-
- let chart: ChartInstance | null = null;
- let resizeObserver: ResizeObserver | null = null;
- let disposed = false;
-
- void import("uplot").then((module) => {
- if (disposed || !chartElementRef.current) return;
-
- const element = chartElementRef.current;
- chart = new module.default(chartOptions(element, severity), chartData(values), element);
-
- if (typeof ResizeObserver !== "undefined") {
- resizeObserver = new ResizeObserver(() => {
- chart?.setSize(chartSize(element));
- });
- resizeObserver.observe(element);
- }
- });
-
- return () => {
- disposed = true;
- resizeObserver?.disconnect();
- chart?.destroy();
- };
- }, [severity, valuesKey, values]);
-
- return (
-
- );
-}
-
-type ChartInstance = {
- destroy(): void;
- setSize(size: { width: number; height: number }): void;
-};
-
-function chartData(values: number[]): import("uplot").AlignedData {
- const normalized = values.length ? values : [0, 0];
- return [
- normalized.map((_, index) => index),
- normalized.map((value) => Math.max(0, Number(value) || 0)),
- ];
-}
-
-function chartOptions(
- element: HTMLElement,
- severity: UiSeverity,
-): import("uplot").Options {
- return {
- ...chartSize(element),
- cursor: { show: false },
- legend: { show: false },
- padding: [2, 0, 2, 0],
- scales: {
- x: { time: false },
- y: { auto: true },
- },
- axes: [{ show: false }, { show: false }],
- series: [
- {},
- {
- stroke: chartStroke(element, severity),
- width: 2,
- points: { show: false },
- },
- ],
- };
-}
-
-function chartSize(element?: HTMLElement): { width: number; height: number } {
- return {
- width: Math.max(80, Math.round(element?.clientWidth || 120)),
- height: Math.max(20, Math.round(element?.clientHeight || 24)),
- };
-}
-
-function chartStroke(element: HTMLElement, severity: UiSeverity): string {
- const styles = window.getComputedStyle(element.closest(".line-chart") || element);
- const currentColor = styles.color;
- if (currentColor) return currentColor;
- if (severity === "danger") return "#ff1744";
- if (severity === "warning") return "#ffb020";
- return "#d7ff00";
-}
diff --git a/src/lib/ui/components/ModuleCard.tsx b/src/lib/ui/components/ModuleCard.tsx
deleted file mode 100644
index d05bee0..0000000
--- a/src/lib/ui/components/ModuleCard.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { useId } from "react";
-import type { UiModuleBlock } from "../types";
-import { IconGlyph } from "./IconGlyph";
-
-export interface ModuleCardProps {
- module: UiModuleBlock;
-}
-
-export function ModuleCard({ module }: ModuleCardProps) {
- const generatedId = useId();
- const titleId = `${generatedId}-title`;
- const ariaLabel = module.title ? undefined : module.label || module.id;
-
- return (
-
- );
-}
diff --git a/src/lib/ui/components/Panel.tsx b/src/lib/ui/components/Panel.tsx
deleted file mode 100644
index 20acbd0..0000000
--- a/src/lib/ui/components/Panel.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import type { PropsWithChildren } from "react";
-
-export interface PanelProps extends PropsWithChildren {
- title?: string;
- density?: "compact" | "dense";
-}
-
-export function Panel({ title, density = "dense", children }: PanelProps) {
- return (
-
- {title ? (
-
- ) : null}
- {children}
-
- );
-}
diff --git a/src/lib/ui/components/ProgressMeter.tsx b/src/lib/ui/components/ProgressMeter.tsx
deleted file mode 100644
index c7278bf..0000000
--- a/src/lib/ui/components/ProgressMeter.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import type { CSSProperties } from "react";
-import { clampPercent } from "../format";
-import type { UiSeverity } from "../types";
-
-export interface ProgressMeterProps {
- value?: number;
- severity?: UiSeverity;
- label?: string;
-}
-
-export function ProgressMeter({
- value,
- severity = "neutral",
- label = "Progress",
-}: ProgressMeterProps) {
- const progress = value === undefined ? null : clampPercent(value);
-
- return (
-
- {progress !== null ? (
-
- ) : null}
-
- );
-}
diff --git a/src/lib/ui/components/ScanlineField.tsx b/src/lib/ui/components/ScanlineField.tsx
deleted file mode 100644
index 017fa0a..0000000
--- a/src/lib/ui/components/ScanlineField.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-export interface ScanlineFieldProps {
- intensity?: "soft" | "medium" | "hard";
- size?: "sm" | "md" | "lg";
- tone?: "neutral" | "accent" | "warning";
-}
-
-export function ScanlineField({
- intensity = "medium",
- size = "md",
- tone = "neutral",
-}: ScanlineFieldProps) {
- return (
-
- );
-}
diff --git a/src/lib/ui/components/Separator.tsx b/src/lib/ui/components/Separator.tsx
deleted file mode 100644
index ca1a955..0000000
--- a/src/lib/ui/components/Separator.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-export interface SeparatorProps {
- orientation?: "horizontal" | "vertical";
- dense?: boolean;
-}
-
-export function Separator({
- orientation = "horizontal",
- dense = false,
-}: SeparatorProps) {
- return (
-
- );
-}
diff --git a/src/lib/ui/components/ServiceGroupPanel.tsx b/src/lib/ui/components/ServiceGroupPanel.tsx
deleted file mode 100644
index 4252cc9..0000000
--- a/src/lib/ui/components/ServiceGroupPanel.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import type { UiServiceGroup } from "../types";
-import { ServicePanel } from "./ServicePanel";
-
-export function ServiceGroupPanel({ group }: { group: UiServiceGroup }) {
- return ;
-}
diff --git a/src/lib/ui/components/ServicePanel.tsx b/src/lib/ui/components/ServicePanel.tsx
deleted file mode 100644
index 12a2e74..0000000
--- a/src/lib/ui/components/ServicePanel.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import type { UiServiceGroup } from "../types";
-import { Panel } from "./Panel";
-import { ServiceRow } from "./ServiceRow";
-import { StatusStrip } from "./StatusStrip";
-
-export interface ServicePanelProps {
- group: UiServiceGroup;
-}
-
-export function ServicePanel({ group }: ServicePanelProps) {
- return (
-
-
- {group.summary?.length ? (
-
- ) : null}
- {group.services.map((service) => (
-
- ))}
-
-
- );
-}
diff --git a/src/lib/ui/components/ServiceRow.tsx b/src/lib/ui/components/ServiceRow.tsx
deleted file mode 100644
index 1030092..0000000
--- a/src/lib/ui/components/ServiceRow.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import type { UiServiceRow } from "../types";
-import { IconGlyph } from "./IconGlyph";
-import { StatusBadge } from "./StatusBadge";
-
-export interface ServiceRowProps {
- service: UiServiceRow;
-}
-
-export function ServiceRow({ service }: ServiceRowProps) {
- const target = service.link?.external ? "_blank" : undefined;
- const rel = service.link?.external ? "noreferrer" : undefined;
- const content = (
- <>
-
-
-
{service.label}
-
{service.description}
-
- {service.detail ? (
-
- ) : null}
- >
- );
-
- if (service.link) {
- return (
-
- {content}
-
- );
- }
-
- return (
-
- {content}
-
- );
-}
diff --git a/src/lib/ui/components/SignalTrace.tsx b/src/lib/ui/components/SignalTrace.tsx
deleted file mode 100644
index 86bc924..0000000
--- a/src/lib/ui/components/SignalTrace.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-export interface SignalTraceProps {
- density?: "regular" | "tight";
- orientation?: "horizontal" | "vertical";
- tone?: "neutral" | "accent" | "warning";
-}
-
-export function SignalTrace({
- density = "regular",
- orientation = "horizontal",
- tone = "accent",
-}: SignalTraceProps) {
- return (
-
-
-
-
-
-
- );
-}
diff --git a/src/lib/ui/components/Sparkline.tsx b/src/lib/ui/components/Sparkline.tsx
deleted file mode 100644
index a79f532..0000000
--- a/src/lib/ui/components/Sparkline.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import type { UiSeverity } from "../types";
-
-export interface SparklineProps {
- values?: number[];
- severity?: UiSeverity;
-}
-
-export function Sparkline({
- values = [],
- severity = "neutral",
-}: SparklineProps) {
- const points = toPoints(values);
-
- return (
-
- );
-}
-
-function toPoints(values: number[]): string {
- if (values.length === 0) return "";
- const max = Math.max(...values, 1);
- const step = values.length > 1 ? 100 / (values.length - 1) : 100;
- return values
- .map((value, index) => {
- const x = index * step;
- const y = 24 - (Math.max(0, value) / max) * 22;
- return `${x.toFixed(2)},${y.toFixed(2)}`;
- })
- .join(" ");
-}
diff --git a/src/lib/ui/components/StatusBadge.tsx b/src/lib/ui/components/StatusBadge.tsx
deleted file mode 100644
index fb63a04..0000000
--- a/src/lib/ui/components/StatusBadge.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import type { UiSeverity } from "../types";
-
-export interface StatusBadgeProps {
- label: string;
- severity?: UiSeverity;
-}
-
-export function StatusBadge({ label, severity = "neutral" }: StatusBadgeProps) {
- return (
-
- {label}
-
- );
-}
diff --git a/src/lib/ui/components/StatusStrip.tsx b/src/lib/ui/components/StatusStrip.tsx
deleted file mode 100644
index fbbd89e..0000000
--- a/src/lib/ui/components/StatusStrip.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import type { UiStatusItem } from "../types";
-import { FooterCell } from "./FooterCell";
-
-export interface StatusStripProps {
- id?: string;
- items: UiStatusItem[];
- compact?: boolean;
-}
-
-export function StatusStrip({ id, items, compact = false }: StatusStripProps) {
- return (
-
- {items.map((item) => (
-
- ))}
-
- );
-}
diff --git a/src/lib/ui/components/SystemState.tsx b/src/lib/ui/components/SystemState.tsx
deleted file mode 100644
index e817e2b..0000000
--- a/src/lib/ui/components/SystemState.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import type { UiSeverity } from "../types";
-import { IconGlyph } from "./IconGlyph";
-
-export interface SystemStateProps {
- title: string;
- detail?: string;
- icon?: string;
- severity?: UiSeverity;
-}
-
-export function SystemState({
- title,
- detail,
- icon = "mdi:information-outline",
- severity = "neutral",
-}: SystemStateProps) {
- return (
-
-
-
-
{title}
- {detail ?
{detail}
: null}
-
-
- );
-}
diff --git a/src/lib/ui/components/TelemetryCard.tsx b/src/lib/ui/components/TelemetryCard.tsx
deleted file mode 100644
index 950a1e0..0000000
--- a/src/lib/ui/components/TelemetryCard.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import type { CSSProperties } from "react";
-import { clampPercent, formatMetricValue } from "../format";
-import type { UiTelemetryCard } from "../types";
-import { IconGlyph } from "./IconGlyph";
-import { LineChart } from "./LineChart";
-
-export interface TelemetryCardProps {
- card: UiTelemetryCard;
-}
-
-export function TelemetryCard({ card }: TelemetryCardProps) {
- const progress = resolveProgress(card);
- const value = formatMetricValue(card.value);
-
- return (
-
-
- {card.icon ? : null}
- {card.label}
-
- {value}
- {progress !== null ? (
-
-
-
- ) : null}
- {card.sparkline?.length ? (
-
- ) : null}
- {card.detail || card.description ? (
- {card.detail || card.description}
- ) : null}
-
- );
-}
-
-function resolveProgress(card: UiTelemetryCard): number | null {
- if (typeof card.progress === "number") return clampPercent(card.progress);
- if (card.value.kind !== "percent") return null;
-
- const progress = Number(card.value.value);
- return Number.isFinite(progress) ? clampPercent(progress) : null;
-}
diff --git a/src/lib/ui/components/TelemetryGrid.tsx b/src/lib/ui/components/TelemetryGrid.tsx
deleted file mode 100644
index 773ece5..0000000
--- a/src/lib/ui/components/TelemetryGrid.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { UiTelemetryCard } from "../types";
-import { TelemetryCard } from "./TelemetryCard";
-
-export interface TelemetryGridProps {
- cards: UiTelemetryCard[];
-}
-
-export function TelemetryGrid({ cards }: TelemetryGridProps) {
- return (
-
- {cards.map((card) => (
-
- ))}
-
- );
-}
diff --git a/src/lib/ui/components/TelemetryStrip.tsx b/src/lib/ui/components/TelemetryStrip.tsx
deleted file mode 100644
index 765c1e2..0000000
--- a/src/lib/ui/components/TelemetryStrip.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import type { UiTelemetryCard } from "../types";
-import { TelemetryGrid } from "./TelemetryGrid";
-
-export function TelemetryStrip({ cards }: { cards: UiTelemetryCard[] }) {
- return ;
-}
diff --git a/src/lib/ui/components/ThemeToggle.tsx b/src/lib/ui/components/ThemeToggle.tsx
deleted file mode 100644
index 1c8fb1a..0000000
--- a/src/lib/ui/components/ThemeToggle.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import type { UiTheme } from "../theme";
-import { getNextUiTheme } from "../theme";
-import { IconGlyph } from "./IconGlyph";
-
-export interface ThemeToggleProps {
- theme: UiTheme;
- onThemeChange: (theme: UiTheme) => void;
-}
-
-export function ThemeToggle({ theme, onThemeChange }: ThemeToggleProps) {
- const nextTheme = getNextUiTheme(theme);
- const label = `Switch to ${nextTheme} theme`;
-
- return (
-
- );
-}
diff --git a/src/lib/ui/components/WeatherModule.tsx b/src/lib/ui/components/WeatherModule.tsx
deleted file mode 100644
index 0967cfb..0000000
--- a/src/lib/ui/components/WeatherModule.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import type { UiModuleBlock } from "../types";
-import { ModuleCard } from "./ModuleCard";
-
-export function WeatherModule({ module }: { module: UiModuleBlock }) {
- return ;
-}
diff --git a/src/lib/ui/components/render.test.tsx b/src/lib/ui/components/render.test.tsx
deleted file mode 100644
index 14c1ff5..0000000
--- a/src/lib/ui/components/render.test.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import { renderToString } from "react-dom/server";
-import { describe, expect, test } from "vitest";
-import { Button } from "./Button";
-import { DashboardFrame } from "./DashboardFrame";
-import { FooterCell } from "./FooterCell";
-import { IconButton } from "./IconButton";
-import { ServiceRow } from "./ServiceRow";
-import { TelemetryCard } from "./TelemetryCard";
-import { dashboardPreviewFixtures } from "../fixtures";
-
-describe("dashboard UI components", () => {
- test("renders the primary generic dashboard fixture", () => {
- const body = renderToString(
- ,
- );
-
- expect(body).toContain("Operations Console");
- expect(body).toContain("Core Throughput");
- expect(body).toContain("Queue Workers");
- expect(body).toContain("data-icon-name=\"mdi:server-network\"");
- expect(body).toContain("data-severity=\"warning\"");
- expect(body).not.toContain("dashboard-title");
- });
-
- test("renders another generic dashboard fixture through the same component", () => {
- const body = renderToString(
- ,
- );
-
- expect(body).toContain("Support Desk");
- expect(body).toContain("Response Window");
- expect(body).toContain("Regional Nodes");
- expect(body).toContain("data-icon-name=\"mdi:headset\"");
- expect(body).toContain("data-severity=\"loading\"");
- });
-
- test("renders optional service and status links as focusable anchors", () => {
- const service = renderToString(
- ,
- );
- const footer = renderToString(
- ,
- );
-
- expect(service).toContain(" {
- const body = renderToString(
- ,
- );
-
- expect(body).toContain("data-model-id=\"queue-workers\"");
- expect(body).toContain("data-model-id=\"dashboard-status\"");
- });
-
- test("does not render progress bars for non-percent metrics without explicit progress", () => {
- const withoutProgress = renderToString(
- ,
- );
- const withProgress = renderToString(
- ,
- );
-
- expect(withoutProgress).not.toContain("telemetry-card__bar");
- expect(withProgress).toContain("--metric-progress:42%");
- });
-
- test("renders telemetry trends through the uPlot chart surface", () => {
- const body = renderToString(
- ,
- );
-
- expect(body).toContain('data-chart-library="uplot"');
- });
-
- test("base button controls forward native attributes", () => {
- const button = renderToString(
- ,
- );
- const iconButton = renderToString(
- ,
- );
-
- expect(button).toContain("id=\"refresh-action\"");
- expect(button).toContain("class=\"ui-button custom-action ");
- expect(button).toContain("aria-controls=\"refresh-target\"");
- expect(iconButton).toContain("id=\"refresh-icon-action\"");
- expect(iconButton).toContain("class=\"icon-button custom-icon-action ");
- expect(iconButton).toContain("aria-expanded=\"false\"");
- });
-});
diff --git a/src/lib/ui/components/styles.css b/src/lib/ui/components/styles.css
deleted file mode 100644
index 086c0c4..0000000
--- a/src/lib/ui/components/styles.css
+++ /dev/null
@@ -1,706 +0,0 @@
-.dashboard-frame {
- display: grid;
- box-sizing: border-box;
- height: 100vh;
- min-height: 100vh;
- gap: 0.36rem;
- grid-template-rows: auto auto minmax(0, 1fr) auto;
- overflow: hidden;
- padding: clamp(0.42rem, 0.65vw, 0.62rem);
- background:
- linear-gradient(90deg, transparent 0 49%, var(--ui-color-frame-spine) 50%, transparent 51%),
- var(--ui-color-frame-wash);
-}
-
-.dashboard-frame__header,
-.dashboard-header {
- display: grid;
- gap: 0.5rem;
- align-items: start;
- border-bottom: var(--ui-border);
-}
-
-.dashboard-frame__header {
- grid-template-columns: minmax(30rem, 1fr) minmax(30rem, 0.9fr);
- min-height: 5.35rem;
- padding-bottom: 0.34rem;
-}
-
-.dashboard-frame__title {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- gap: var(--ui-space-3);
- align-items: start;
- min-width: 0;
-}
-
-.dashboard-frame__title-copy {
- min-width: 0;
-}
-
-.dashboard-frame__actions {
- justify-self: end;
-}
-
-.dashboard-header {
- grid-template-columns: minmax(0, 1fr) auto;
- padding: var(--ui-space-3);
-}
-
-.dashboard-frame__header p,
-.dashboard-frame__header span,
-.dashboard-header p,
-.dashboard-header span,
-.dashboard-frame h1,
-.dashboard-header h1 {
- margin: 0;
- text-transform: uppercase;
-}
-
-.dashboard-frame__header p,
-.dashboard-frame__header span,
-.dashboard-header p,
-.dashboard-header span {
- color: var(--ui-color-muted);
- font-size: 0.78rem;
- font-weight: 800;
-}
-
-.dashboard-frame h1,
-.dashboard-header h1 {
- max-width: 100%;
- overflow-wrap: anywhere;
- font-family: var(--ui-font-display);
- font-size: clamp(2.2rem, 3.3vw, 2.95rem);
- font-weight: 850;
- letter-spacing: 0;
- line-height: 0.8;
- white-space: nowrap;
-}
-
-.dashboard-frame__modules {
- display: grid;
- grid-template-columns: minmax(15rem, 0.66fr) minmax(17rem, 1fr);
- justify-content: end;
- gap: 0.5rem;
-}
-
-.dashboard-frame__panels {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- align-content: start;
- gap: 0.36rem;
- min-height: 0;
- overflow: hidden;
-}
-
-.dashboard-frame__panels .service-panel[data-layout="grid"] {
- grid-column: 1 / -1;
-}
-
-.dashboard-frame__panels .service-panel[data-layout="grid"] .panel__body {
- grid-template-columns: repeat(4, minmax(0, 1fr));
-}
-
-.telemetry-grid {
- display: grid;
- grid-template-columns: repeat(8, minmax(0, 1fr));
- gap: 1px;
- border: var(--ui-border);
- background: var(--ui-color-line);
-}
-
-.telemetry-card,
-.module-card,
-.panel,
-.system-state {
- border: var(--ui-border);
- background: var(--ui-color-surface-panel);
- color: var(--ui-color-text);
-}
-
-.telemetry-card {
- display: grid;
- min-height: 5.15rem;
- gap: 0.25rem;
- background: linear-gradient(
- 180deg,
- var(--ui-color-card-gradient-start),
- var(--ui-color-card-gradient-end)
- );
- padding: 0.45rem 0.55rem 0.42rem;
-}
-
-.telemetry-card[data-severity="warning"] {
- border-color: color-mix(in srgb, var(--ui-color-warning), transparent 42%);
-}
-
-.telemetry-card[data-severity="danger"] {
- border-color: color-mix(in srgb, var(--ui-color-danger), transparent 22%);
- color: var(--ui-color-danger);
-}
-
-.telemetry-card[data-severity="stale"],
-.telemetry-card[data-severity="unavailable"] {
- color: var(--ui-color-stale);
-}
-
-.telemetry-card[data-severity="loading"] {
- color: var(--ui-color-accent);
-}
-
-.telemetry-card header {
- display: flex;
- min-width: 0;
- align-items: center;
- gap: 0.35rem;
-}
-
-.telemetry-card header .icon-glyph {
- display: none;
-}
-
-.telemetry-card h3,
-.telemetry-card p,
-.module-card h2,
-.module-card p,
-.service-row h3,
-.service-row p,
-.panel h2,
-.system-state h2,
-.system-state p {
- margin: 0;
-}
-
-.telemetry-card h3,
-.service-row h3 {
- overflow: hidden;
- font-weight: 850;
- letter-spacing: 0;
- line-height: 1.05;
- text-overflow: ellipsis;
- text-transform: uppercase;
- white-space: nowrap;
-}
-
-.telemetry-card h3 {
- overflow-wrap: anywhere;
- color: inherit;
- font-size: 0.58rem;
- font-weight: 800;
- line-height: 1.02;
- white-space: normal;
-}
-
-.service-row h3 {
- font-size: 0.72rem;
-}
-
-.telemetry-card strong,
-.module-card strong {
- display: block;
- font-family: var(--ui-font-display);
- font-size: clamp(1.55rem, 2.45vw, 2.22rem);
- font-weight: 800;
- letter-spacing: 0;
- line-height: 0.76;
- white-space: nowrap;
-}
-
-.telemetry-card p,
-.module-card p,
-.service-row p {
- overflow: hidden;
- color: var(--ui-color-muted);
- line-height: 1.08;
- text-overflow: ellipsis;
- text-transform: uppercase;
- white-space: nowrap;
-}
-
-.telemetry-card p {
- font-size: 0.49rem;
- line-height: 1.05;
-}
-
-.module-card p,
-.service-row p {
- font-size: 0.56rem;
-}
-
-.telemetry-card__bar,
-.progress-meter {
- height: 0.25rem;
- border: var(--ui-border);
- background: var(--ui-color-surface-inset);
-}
-
-.telemetry-card__bar span,
-.progress-meter span {
- display: block;
- width: var(--metric-progress, var(--meter-progress));
- height: 100%;
- background: currentColor;
-}
-
-.telemetry-card[data-severity="loading"] .telemetry-card__bar span {
- min-width: 1.25rem;
-}
-
-.line-chart {
- position: relative;
- min-width: 0;
- height: 1rem;
- color: var(--ui-color-accent);
-}
-
-.line-chart[data-severity="warning"] {
- color: var(--ui-color-warning);
-}
-
-.line-chart[data-severity="danger"] {
- color: var(--ui-color-danger);
-}
-
-.line-chart[data-severity="stale"],
-.line-chart[data-severity="unavailable"] {
- color: var(--ui-color-stale);
-}
-
-.line-chart__canvas {
- width: 100%;
- height: 100%;
-}
-
-.line-chart__canvas .uplot {
- width: 100% !important;
- height: 100% !important;
- background: transparent;
- font-family: var(--ui-font-mono);
-}
-
-.line-chart__canvas .u-over,
-.line-chart__canvas .u-under {
- overflow: visible;
-}
-
-.module-card {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- gap: 0.5rem;
- align-items: start;
- min-width: 0;
- min-height: 4.15rem;
- background: var(--ui-color-surface-module);
- padding: 0.5rem;
-}
-
-.module-card h2 {
- color: var(--ui-color-muted);
- font-size: 0.56rem;
- line-height: 1;
- text-transform: uppercase;
-}
-
-.module-card strong {
- margin-top: 0.15rem;
- font-size: clamp(1.25rem, 1.75vw, 1.72rem);
- line-height: 0.82;
- overflow-wrap: anywhere;
-}
-
-.module-card p {
- margin-top: 0.2rem;
- font-size: 0.49rem;
- line-height: 1.05;
-}
-
-.module-card[data-severity="ok"] .icon-glyph {
- background: var(--ui-color-accent);
- color: var(--ui-color-accent-contrast);
-}
-
-.module-card[data-severity="warning"] {
- border-color: color-mix(in srgb, var(--ui-color-warning), transparent 42%);
- color: var(--ui-color-warning);
-}
-
-.module-card[data-severity="danger"] {
- border-color: color-mix(in srgb, var(--ui-color-danger), transparent 32%);
- color: var(--ui-color-danger);
-}
-
-.module-card[data-severity="stale"],
-.module-card[data-severity="unavailable"] {
- color: var(--ui-color-stale);
-}
-
-.module-card[data-severity="loading"] {
- color: var(--ui-color-accent);
-}
-
-.service-row {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr) auto;
- gap: 0.24rem;
- align-items: center;
- min-height: 2.02rem;
- border: 0;
- border-bottom: var(--ui-border);
- background: transparent;
- color: inherit;
- padding: 0.14rem 0;
- text-decoration: none;
-}
-
-.service-row[data-severity="warning"] {
- border-bottom-color: color-mix(in srgb, var(--ui-color-warning), transparent 54%);
-}
-
-.service-row[data-severity="danger"],
-.service-row[data-severity="unavailable"] {
- border-bottom-color: color-mix(in srgb, var(--ui-color-danger), transparent 50%);
-}
-
-.service-row[data-severity="loading"] {
- border-bottom-color: color-mix(in srgb, var(--ui-color-accent), transparent 56%);
-}
-
-.service-row:where(a):hover {
- border-bottom-color: var(--ui-color-accent);
- background: var(--ui-color-hover);
-}
-
-.service-row__main {
- min-width: 0;
-}
-
-.status-badge {
- display: inline-grid;
- min-height: 1.12rem;
- align-items: center;
- border: var(--ui-border);
- padding: 0 0.3rem;
- color: var(--ui-color-muted);
- font-size: 0.55rem;
- font-weight: 800;
- letter-spacing: 0;
- text-transform: uppercase;
- white-space: nowrap;
-}
-
-.status-badge[data-severity="ok"] {
- border-color: color-mix(in srgb, var(--ui-color-ok), transparent 42%);
- color: var(--ui-color-ok);
-}
-
-.status-badge[data-severity="warning"] {
- border-color: color-mix(in srgb, var(--ui-color-warning), transparent 35%);
- color: var(--ui-color-warning);
-}
-
-.status-badge[data-severity="danger"] {
- border-color: color-mix(in srgb, var(--ui-color-danger), transparent 30%);
- color: var(--ui-color-danger);
-}
-
-.status-badge[data-severity="stale"],
-.status-badge[data-severity="unavailable"] {
- color: var(--ui-color-stale);
-}
-
-.status-badge[data-severity="loading"] {
- color: var(--ui-color-accent);
-}
-
-.footer-cell {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr);
- min-height: 1.9rem;
- align-items: center;
- background: var(--ui-color-surface-footer);
- color: inherit;
- text-decoration: none;
-}
-
-.footer-cell span,
-.footer-cell strong {
- min-width: 0;
- padding: 0.34rem 0.52rem;
- overflow-wrap: anywhere;
- text-transform: uppercase;
-}
-
-.footer-cell span {
- height: 100%;
- border-right: var(--ui-border);
- color: var(--ui-color-muted);
- font-size: 0.52rem;
- font-weight: 800;
-}
-
-.footer-cell strong {
- color: var(--ui-color-text);
- font-size: 0.58rem;
-}
-
-.footer-cell[data-severity="ok"] strong {
- background: var(--ui-color-accent);
- color: var(--ui-color-accent-contrast);
-}
-
-.footer-cell[data-severity="warning"] strong {
- color: var(--ui-color-warning);
-}
-
-.footer-cell[data-severity="danger"] strong {
- color: var(--ui-color-danger);
-}
-
-.footer-cell[data-severity="stale"] strong,
-.footer-cell[data-severity="unavailable"] strong {
- color: var(--ui-color-stale);
-}
-
-.footer-cell[data-severity="loading"] strong {
- color: var(--ui-color-accent);
-}
-
-.footer-cell:where(a):hover strong {
- color: var(--ui-color-accent);
-}
-
-.status-strip {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
- gap: 1px;
- border: var(--ui-border);
- background: var(--ui-color-line);
-}
-
-.status-strip[data-compact="true"] {
- grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
-}
-
-.panel {
- position: relative;
- min-width: 0;
- box-shadow: var(--ui-shadow-hard);
-}
-
-.panel::before,
-.panel::after {
- position: absolute;
- width: 0.55rem;
- height: 0.55rem;
- border-color: var(--ui-color-line-strong);
- content: "";
-}
-
-.panel::before {
- top: 0.2rem;
- right: 0.2rem;
- border-top: 1px solid;
- border-right: 1px solid;
-}
-
-.panel::after {
- right: 0.2rem;
- bottom: 0.2rem;
- border-right: 1px solid;
- border-bottom: 1px solid;
-}
-
-.panel__header {
- padding: 0.42rem 0.55rem 0;
-}
-
-.panel h2 {
- font-family: var(--ui-font-display);
- font-size: clamp(1.25rem, 1.8vw, 1.75rem);
- font-weight: 800;
- line-height: 0.92;
- text-transform: uppercase;
-}
-
-.panel__body {
- display: grid;
- gap: 0.25rem;
- padding: 0.42rem 0.55rem 0.55rem;
-}
-
-.service-panel .panel__body {
- gap: 0;
- padding-block: 0.24rem 0.42rem;
-}
-
-.ui-button,
-.icon-button {
- display: inline-grid;
- align-items: center;
- justify-content: center;
- border: var(--ui-border);
- cursor: pointer;
-}
-
-.ui-button {
- grid-auto-flow: column;
- gap: var(--ui-space-2);
- min-height: 2.5rem;
- background: var(--ui-color-accent);
- color: var(--ui-color-canvas);
- font-size: 0.76rem;
- font-weight: 850;
- padding: 0 var(--ui-space-4);
- text-transform: uppercase;
-}
-
-.icon-button {
- width: 2.5rem;
- height: 2.5rem;
- place-items: center;
- background: var(--ui-color-surface-footer);
- color: var(--ui-color-muted);
- padding: 0;
-}
-
-.theme-toggle {
- display: inline-grid;
- grid-auto-flow: column;
- gap: var(--ui-space-2);
- align-items: center;
- justify-content: center;
- min-width: 6.5rem;
- min-height: 2.15rem;
- border: var(--ui-border);
- background: var(--ui-color-surface-raised);
- color: var(--ui-color-text);
- cursor: pointer;
- font: inherit;
- font-size: 0.62rem;
- font-weight: 850;
- letter-spacing: 0;
- padding: 0 var(--ui-space-3);
- text-transform: uppercase;
-}
-
-.theme-toggle:hover {
- border-color: var(--ui-color-accent);
- color: var(--ui-color-accent);
-}
-
-.theme-toggle span {
- line-height: 1;
- white-space: nowrap;
-}
-
-.icon-glyph {
- display: inline-grid;
- width: 1.55rem;
- height: 1.55rem;
- place-items: center;
- border: var(--ui-border);
- background: var(--ui-color-surface-icon);
- color: currentColor;
- line-height: 1;
-}
-
-.icon-glyph svg {
- width: 0.95rem;
- height: 0.95rem;
-}
-
-.icon-glyph[data-size="sm"] {
- width: 1.1rem;
- height: 1.1rem;
-}
-
-.icon-glyph[data-size="lg"] {
- width: 2.35rem;
- height: 2.35rem;
-}
-
-.system-state {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr);
- gap: var(--ui-space-3);
- align-items: center;
- padding: var(--ui-space-4);
-}
-
-.grid-frame {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
- gap: var(--ui-space-3);
- padding: var(--ui-space-3);
-}
-
-.separator {
- background: var(--ui-color-line);
-}
-
-.separator[data-orientation="horizontal"] {
- width: 100%;
- height: 1px;
- margin-block: var(--ui-space-3);
-}
-
-.corner-bracket-frame,
-.diagonal-stripe-field,
-.scanline-field,
-.signal-trace {
- display: block;
- min-height: 3rem;
-}
-
-@media (max-width: 1100px) {
- .telemetry-grid {
- grid-template-columns: repeat(4, minmax(0, 1fr));
- }
-}
-
-@media (max-width: 780px) {
- .dashboard-frame {
- height: auto;
- min-height: 100vh;
- overflow: visible;
- }
-
- .dashboard-frame__header,
- .dashboard-frame__title,
- .dashboard-header,
- .dashboard-frame__modules,
- .dashboard-frame__panels {
- grid-template-columns: 1fr;
- }
-
- .dashboard-frame h1,
- .dashboard-header h1 {
- white-space: normal;
- }
-
- .dashboard-frame__panels {
- overflow: visible;
- }
-
- .dashboard-frame__panels .service-panel[data-layout="grid"] .panel__body {
- grid-template-columns: 1fr;
- }
-}
-
-@media (max-width: 700px) {
- .telemetry-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-}
-
-@media (max-width: 580px) {
- .service-row {
- grid-template-columns: auto minmax(0, 1fr);
- }
-
- .service-row .status-badge {
- grid-column: 2;
- justify-self: start;
- }
-}
diff --git a/src/lib/ui/content-boundary.test.ts b/src/lib/ui/content-boundary.test.ts
deleted file mode 100644
index 6613644..0000000
--- a/src/lib/ui/content-boundary.test.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { readdirSync, readFileSync, statSync } from "node:fs";
-import { join } from "node:path";
-import { describe, expect, test } from "vitest";
-
-const forbiddenTerms = [
- "dimensionlab",
- "dimension lab",
- "vaultwarden",
- "forgejo",
- "grafana",
- "uptime kuma",
- "prometheus",
- "backrest",
- "open webui",
- "comfyui",
- "adminer",
- "cockpit",
- "ollama",
-];
-
-describe("UI content boundary", () => {
- test("keeps environment-specific content out of reusable UI source", () => {
- const source = readUiSource(join(process.cwd(), "src", "lib", "ui"));
- const normalized = source.toLowerCase();
-
- expect(
- forbiddenTerms.filter((term) => normalized.includes(term)),
- ).toEqual([]);
- });
-
- test("keeps icon rendering driven by icon identifiers", () => {
- const source = readUiSource(join(process.cwd(), "src", "lib", "ui"));
-
- expect(source).not.toContain("@iconify-json/");
- expect(source).not.toContain("/icons/");
- });
-});
-
-function readUiSource(path: string): string {
- const stats = statSync(path);
- if (stats.isFile()) {
- if (path.endsWith(".test.ts")) return "";
- return readFileSync(path, "utf8");
- }
-
- return readdirSync(path)
- .map((entry) => readUiSource(join(path, entry)))
- .join("\n");
-}
diff --git a/src/lib/ui/fixtures.ts b/src/lib/ui/fixtures.ts
deleted file mode 100644
index b8008c1..0000000
--- a/src/lib/ui/fixtures.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import type { UiDashboardPreview } from "./types";
-
-export const dashboardPreviewFixtures: Record = {
- primary: {
- eyebrow: "Command Surface",
- title: "Operations Console",
- subtitle: "Capacity, latency, and queue health",
- telemetry: [
- metric("core-throughput", "Core Throughput", "mdi:server-network", 82, "ok"),
- metric("edge-cache", "Edge Cache", "mdi:database-clock", 67, "neutral"),
- metric("queue-depth", "Queue Depth", "mdi:tray-full", 74, "warning"),
- metric("error-budget", "Error Budget", "mdi:chart-timeline-variant", 18, "danger"),
- metric("build-latency", "Build Latency", "mdi:timer-sand", 23, "stale"),
- metric("worker-load", "Worker Load", "mdi:cpu-64-bit", 55, "ok"),
- ],
- modules: [
- {
- id: "ambient-conditions",
- title: "Local Node",
- value: "21.4 C",
- detail: "clear window",
- icon: "mdi:weather-partly-cloudy",
- severity: "ok",
- },
- ],
- serviceGroups: [
- {
- id: "queue-workers",
- title: "Queue Workers",
- services: [
- service("ingest", "Ingest", "Event intake pipeline", "mdi:arrow-collapse-down", "ok", "1.252 ms"),
- service("scheduler", "Scheduler", "Timed job coordinator", "mdi:calendar-clock", "warning", "1.487 ms"),
- service("archive", "Archive", "Cold storage transfer", "mdi:archive-arrow-down", "ok", "1.301 ms"),
- ],
- },
- {
- id: "regional-nodes",
- title: "Regional Nodes",
- services: [
- service("north", "North", "Primary traffic cell", "mdi:access-point", "ok", "899 ms"),
- service("west", "West", "Replica traffic cell", "mdi:access-point-network", "neutral", "1.118 ms"),
- service("south", "South", "Maintenance window", "mdi:wrench-clock", "stale", "paused"),
- ],
- },
- {
- id: "control-plane",
- title: "Control Plane",
- services: [
- service("identity", "Identity", "Access token exchange", "mdi:account-key", "ok", "721 ms"),
- service("policy", "Policy", "Rules evaluation", "mdi:shield-check", "ok", "812 ms"),
- service("audit", "Audit", "Event ledger writer", "mdi:text-box-search", "warning", "1.442 ms"),
- ],
- },
- ],
- statusItems: [
- { id: "system", label: "System", value: "Nominal", severity: "ok" },
- { id: "sync", label: "Last Sync", value: "2 minutes ago", severity: "stale" },
- { id: "uptime", label: "Uptime", value: "14d 08h", severity: "neutral" },
- { id: "refresh", label: "Refresh", value: "15s", severity: "neutral" },
- ],
- statusStripId: "dashboard-status",
- },
- secondary: {
- eyebrow: "Support Surface",
- title: "Support Desk",
- subtitle: "Response, routing, and regional health",
- telemetry: [
- metric("response-window", "Response Window", "mdi:headset", 41, "ok"),
- metric("ticket-load", "Ticket Load", "mdi:ticket-confirmation", 68, "warning"),
- metric("handoff-drift", "Handoff Drift", "mdi:swap-horizontal", 11, "neutral"),
- metric("coverage-gap", "Coverage Gap", "mdi:map-marker-alert", 7, "danger"),
- metric("routing-warmup", "Routing Warmup", "mdi:progress-clock", 0, "loading"),
- ],
- modules: [
- {
- id: "shift-state",
- title: "Shift State",
- value: "covered",
- detail: "static fixture",
- icon: "mdi:clipboard-check-outline",
- severity: "ok",
- },
- ],
- serviceGroups: [
- {
- id: "regional-nodes",
- title: "Regional Nodes",
- services: [
- service("desk-a", "Desk A", "Frontline queue", "mdi:monitor-dashboard", "ok", "843 ms"),
- service("desk-b", "Desk B", "Escalation queue", "mdi:monitor-star", "warning", "1.204 ms"),
- service("desk-c", "Desk C", "Overflow queue", "mdi:monitor-off", "unavailable", "offline"),
- ],
- },
- ],
- statusItems: [
- { id: "desk", label: "Desk", value: "Covered", severity: "ok" },
- { id: "handoff", label: "Handoff", value: "Pending", severity: "warning" },
- { id: "routing", label: "Routing", value: "Manual", severity: "neutral" },
- ],
- statusStripId: "support-status",
- },
-};
-
-function metric(
- id: string,
- label: string,
- icon: string,
- progress: number,
- severity: UiDashboardPreview["telemetry"][number]["severity"],
-) {
- return {
- id,
- label,
- icon,
- progress,
- severity,
- value: { kind: "percent" as const, value: progress },
- detail: "static fixture",
- sparkline: [12, 18, 15, 28, 24, progress],
- };
-}
-
-function service(
- id: string,
- label: string,
- description: string,
- icon: string,
- severity: UiDashboardPreview["serviceGroups"][number]["services"][number]["severity"],
- detail: string,
-) {
- return { id, label, description, icon, severity, detail };
-}
diff --git a/src/lib/ui/format.ts b/src/lib/ui/format.ts
deleted file mode 100644
index 9a10434..0000000
--- a/src/lib/ui/format.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import type { UiMetricValue } from "./types";
-
-const byteUnits = ["B", "KB", "MB", "GB", "TB"];
-
-export function formatMetricValue(metric: UiMetricValue): string {
- if (metric.kind === "text") return String(metric.value);
-
- const value = typeof metric.value === "number" ? metric.value : Number(metric.value);
- const precision = metric.precision ?? inferPrecision(value);
- const unit = metric.unit ?? defaultUnit(metric.kind);
-
- if (metric.kind === "bytes") return formatBytes(value, precision);
- if (metric.kind === "percent") return `${value.toFixed(precision)}%`;
- if (metric.kind === "temperature") return `${value.toFixed(precision)}°C`;
- return `${value.toFixed(precision)}${unit ? ` ${unit}` : ""}`;
-}
-
-export function clampPercent(value = 0): number {
- if (!Number.isFinite(value)) return 0;
- return Math.max(0, Math.min(100, value));
-}
-
-function defaultUnit(kind: UiMetricValue["kind"]): string {
- if (kind === "percent") return "%";
- if (kind === "temperature") return "C";
- if (kind === "latency") return "ms";
- return "";
-}
-
-function inferPrecision(value: number): number {
- return Number.isInteger(value) ? 0 : 1;
-}
-
-function formatBytes(value: number, precision: number): string {
- let size = value;
- let index = 0;
- while (size >= 1024 && index < byteUnits.length - 1) {
- size /= 1024;
- index += 1;
- }
-
- return `${size.toFixed(precision)} ${byteUnits[index]}`;
-}
diff --git a/src/lib/ui/index.ts b/src/lib/ui/index.ts
deleted file mode 100644
index 9eb5448..0000000
--- a/src/lib/ui/index.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-export { Badge } from "./components/Badge";
-export { Button } from "./components/Button";
-export { CornerBracketFrame } from "./components/CornerBracketFrame";
-export { DashboardHeader } from "./components/DashboardHeader";
-export { DashboardFrame } from "./components/DashboardFrame";
-export { DiagonalStripeField } from "./components/DiagonalStripeField";
-export { FooterCell } from "./components/FooterCell";
-export { FooterStatusCell } from "./components/FooterStatusCell";
-export { GridFrame } from "./components/GridFrame";
-export { IconGlyph } from "./components/IconGlyph";
-export { IconButton } from "./components/IconButton";
-export { LineChart } from "./components/LineChart";
-export { ModuleCard } from "./components/ModuleCard";
-export { Panel } from "./components/Panel";
-export { ProgressMeter } from "./components/ProgressMeter";
-export { Separator } from "./components/Separator";
-export { ServiceGroupPanel } from "./components/ServiceGroupPanel";
-export { ServicePanel } from "./components/ServicePanel";
-export { ServiceRow } from "./components/ServiceRow";
-export { ScanlineField } from "./components/ScanlineField";
-export { SignalTrace } from "./components/SignalTrace";
-export { Sparkline } from "./components/Sparkline";
-export { StatusBadge } from "./components/StatusBadge";
-export { StatusStrip } from "./components/StatusStrip";
-export { SystemState } from "./components/SystemState";
-export { TelemetryCard } from "./components/TelemetryCard";
-export { TelemetryGrid } from "./components/TelemetryGrid";
-export { TelemetryStrip } from "./components/TelemetryStrip";
-export { ThemeToggle } from "./components/ThemeToggle";
-export { WeatherModule } from "./components/WeatherModule";
-export { dashboardPreviewFixtures } from "./fixtures";
-export { dashboardDocumentToUiDashboard } from "./model-renderer";
-export {
- getNextUiTheme,
- isUiTheme,
- persistUiTheme,
- resolveInitialUiTheme,
- UI_THEME_STORAGE_KEY,
-} from "./theme";
-export type {
- UiDashboardPreview,
- UiLink,
- UiMetricValue,
- UiModuleBlock,
- UiServiceGroup,
- UiServiceRow,
- UiSeverity,
- UiStatusItem,
- UiTelemetryCard,
-} from "./types";
-export type { UiTheme } from "./theme";
diff --git a/src/lib/ui/stories/Badge.stories.tsx b/src/lib/ui/stories/Badge.stories.tsx
deleted file mode 100644
index d33394d..0000000
--- a/src/lib/ui/stories/Badge.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { Badge } from "../components/Badge";
-
-const meta = {
- title: "UI/Badge",
- component: Badge,
- args: {
- label: "Ready",
- severity: "ok",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {};
diff --git a/src/lib/ui/stories/Button.stories.tsx b/src/lib/ui/stories/Button.stories.tsx
deleted file mode 100644
index c207233..0000000
--- a/src/lib/ui/stories/Button.stories.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { Button } from "../components/Button";
-
-const meta = {
- title: "UI/Button",
- component: Button,
- args: {
- label: "Refresh",
- icon: "mdi:refresh",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Primary: Story = {};
-export const Secondary: Story = {
- args: {
- variant: "secondary",
- },
-};
diff --git a/src/lib/ui/stories/CornerBracketFrame.stories.tsx b/src/lib/ui/stories/CornerBracketFrame.stories.tsx
deleted file mode 100644
index dd7efbf..0000000
--- a/src/lib/ui/stories/CornerBracketFrame.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { CornerBracketFrame } from "../components/CornerBracketFrame";
-
-const meta = {
- title: "UI/CornerBracketFrame",
- component: CornerBracketFrame,
- args: {
- tone: "accent",
- size: "md",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {};
diff --git a/src/lib/ui/stories/DashboardFrame.stories.tsx b/src/lib/ui/stories/DashboardFrame.stories.tsx
deleted file mode 100644
index e1963af..0000000
--- a/src/lib/ui/stories/DashboardFrame.stories.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { DashboardFrame } from "../components/DashboardFrame";
-import { fullCompositionDashboard, secondaryDashboard } from "./story-data";
-
-const meta = {
- title: "UI/DashboardFrame",
- component: DashboardFrame,
- args: {
- dashboard: fullCompositionDashboard,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const FullComposition: Story = {};
-export const Secondary: Story = {
- args: {
- dashboard: secondaryDashboard,
- },
-};
diff --git a/src/lib/ui/stories/DashboardHeader.stories.tsx b/src/lib/ui/stories/DashboardHeader.stories.tsx
deleted file mode 100644
index 8263dd1..0000000
--- a/src/lib/ui/stories/DashboardHeader.stories.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { DashboardHeader } from "../components/DashboardHeader";
-import { moduleBlocks } from "./story-data";
-
-const meta = {
- title: "UI/DashboardHeader",
- component: DashboardHeader,
- args: {
- eyebrow: "Preview Surface",
- title: "Operations Console",
- subtitle: "Generic dashboard header",
- module: moduleBlocks.compact,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const WithModule: Story = {};
diff --git a/src/lib/ui/stories/DashboardOnePager.stories.tsx b/src/lib/ui/stories/DashboardOnePager.stories.tsx
deleted file mode 100644
index c44364b..0000000
--- a/src/lib/ui/stories/DashboardOnePager.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { DashboardFrame } from "../components/DashboardFrame";
-import { fullCompositionDashboard } from "./story-data";
-
-const meta = {
- title: "UI/DashboardOnePager",
- component: DashboardFrame,
- args: {
- dashboard: fullCompositionDashboard,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const OnePager: Story = {};
diff --git a/src/lib/ui/stories/DiagonalStripeField.stories.tsx b/src/lib/ui/stories/DiagonalStripeField.stories.tsx
deleted file mode 100644
index 4ca01f2..0000000
--- a/src/lib/ui/stories/DiagonalStripeField.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { DiagonalStripeField } from "../components/DiagonalStripeField";
-
-const meta = {
- title: "UI/DiagonalStripeField",
- component: DiagonalStripeField,
- args: {
- tone: "accent",
- density: "regular",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {};
diff --git a/src/lib/ui/stories/FooterCell.stories.tsx b/src/lib/ui/stories/FooterCell.stories.tsx
deleted file mode 100644
index 3ba26c7..0000000
--- a/src/lib/ui/stories/FooterCell.stories.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { FooterCell } from "../components/FooterCell";
-import { statusItems } from "./story-data";
-
-const meta = {
- title: "UI/FooterCell",
- component: FooterCell,
- args: {
- item: statusItems.ok,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Operational: Story = {};
-export const Linked: Story = {
- args: {
- item: statusItems.action,
- },
-};
diff --git a/src/lib/ui/stories/FooterStatusCell.stories.tsx b/src/lib/ui/stories/FooterStatusCell.stories.tsx
deleted file mode 100644
index 8097ba3..0000000
--- a/src/lib/ui/stories/FooterStatusCell.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { FooterStatusCell } from "../components/FooterStatusCell";
-import { statusItems } from "./story-data";
-
-const meta = {
- title: "UI/FooterStatusCell",
- component: FooterStatusCell,
- args: {
- item: statusItems.degraded,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Warning: Story = {};
diff --git a/src/lib/ui/stories/GridFrame.stories.tsx b/src/lib/ui/stories/GridFrame.stories.tsx
deleted file mode 100644
index a43ad22..0000000
--- a/src/lib/ui/stories/GridFrame.stories.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { GridFrame } from "../components/GridFrame";
-import { ModuleCard } from "../components/ModuleCard";
-import { moduleBlocks } from "./story-data";
-
-const meta = {
- title: "UI/GridFrame",
- component: GridFrame,
- render: (args) => (
-
-
-
-
-
- ),
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Dense: Story = {
- args: {
- density: "dense",
- },
-};
diff --git a/src/lib/ui/stories/IconButton.stories.tsx b/src/lib/ui/stories/IconButton.stories.tsx
deleted file mode 100644
index 35b58b9..0000000
--- a/src/lib/ui/stories/IconButton.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { IconButton } from "../components/IconButton";
-
-const meta = {
- title: "UI/IconButton",
- component: IconButton,
- args: {
- icon: "mdi:refresh",
- label: "Refresh status",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {};
diff --git a/src/lib/ui/stories/IconGlyph.stories.tsx b/src/lib/ui/stories/IconGlyph.stories.tsx
deleted file mode 100644
index 3f1715a..0000000
--- a/src/lib/ui/stories/IconGlyph.stories.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { IconGlyph } from "../components/IconGlyph";
-
-const meta = {
- title: "UI/IconGlyph",
- component: IconGlyph,
- args: {
- name: "mdi:server-network",
- label: "Generic service",
- size: "md",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {};
diff --git a/src/lib/ui/stories/LineChart.stories.tsx b/src/lib/ui/stories/LineChart.stories.tsx
deleted file mode 100644
index bbf8690..0000000
--- a/src/lib/ui/stories/LineChart.stories.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { LineChart } from "../components/LineChart";
-
-const meta = {
- title: "UI/LineChart",
- component: LineChart,
- args: {
- values: [12, 18, 24, 20, 36, 44],
- severity: "ok",
- label: "Generic trend",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Trend: Story = {};
diff --git a/src/lib/ui/stories/ModuleCard.stories.tsx b/src/lib/ui/stories/ModuleCard.stories.tsx
deleted file mode 100644
index 3366a55..0000000
--- a/src/lib/ui/stories/ModuleCard.stories.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { ModuleCard } from "../components/ModuleCard";
-import { moduleBlocks } from "./story-data";
-
-const meta = {
- title: "UI/ModuleCard",
- component: ModuleCard,
- args: {
- module: moduleBlocks.compact,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Compact: Story = {};
-export const Long: Story = {
- args: {
- module: moduleBlocks.long,
- },
-};
diff --git a/src/lib/ui/stories/Panel.stories.tsx b/src/lib/ui/stories/Panel.stories.tsx
deleted file mode 100644
index 730c2d9..0000000
--- a/src/lib/ui/stories/Panel.stories.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { Panel } from "../components/Panel";
-import { ServiceRow } from "../components/ServiceRow";
-import { serviceRows } from "./story-data";
-
-const meta = {
- title: "UI/Panel",
- component: Panel,
- render: (args) => (
-
-
-
-
- ),
- args: {
- title: "Generic Panel",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Dense: Story = {};
diff --git a/src/lib/ui/stories/ProgressMeter.stories.tsx b/src/lib/ui/stories/ProgressMeter.stories.tsx
deleted file mode 100644
index d3bfdac..0000000
--- a/src/lib/ui/stories/ProgressMeter.stories.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { ProgressMeter } from "../components/ProgressMeter";
-
-const meta = {
- title: "UI/ProgressMeter",
- component: ProgressMeter,
- args: {
- value: 72,
- severity: "ok",
- label: "Capacity",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Filled: Story = {};
diff --git a/src/lib/ui/stories/ScanlineField.stories.tsx b/src/lib/ui/stories/ScanlineField.stories.tsx
deleted file mode 100644
index 89e554e..0000000
--- a/src/lib/ui/stories/ScanlineField.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { ScanlineField } from "../components/ScanlineField";
-
-const meta = {
- title: "UI/ScanlineField",
- component: ScanlineField,
- args: {
- tone: "accent",
- intensity: "medium",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {};
diff --git a/src/lib/ui/stories/Separator.stories.tsx b/src/lib/ui/stories/Separator.stories.tsx
deleted file mode 100644
index e261f52..0000000
--- a/src/lib/ui/stories/Separator.stories.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { Separator } from "../components/Separator";
-
-const meta = {
- title: "UI/Separator",
- component: Separator,
- args: {
- orientation: "horizontal",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Horizontal: Story = {};
diff --git a/src/lib/ui/stories/ServiceGroupPanel.stories.tsx b/src/lib/ui/stories/ServiceGroupPanel.stories.tsx
deleted file mode 100644
index 7183771..0000000
--- a/src/lib/ui/stories/ServiceGroupPanel.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { ServiceGroupPanel } from "../components/ServiceGroupPanel";
-import { serviceGroups } from "./story-data";
-
-const meta = {
- title: "UI/ServiceGroupPanel",
- component: ServiceGroupPanel,
- args: {
- group: serviceGroups.mixed,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Mixed: Story = {};
diff --git a/src/lib/ui/stories/ServicePanel.stories.tsx b/src/lib/ui/stories/ServicePanel.stories.tsx
deleted file mode 100644
index 750c428..0000000
--- a/src/lib/ui/stories/ServicePanel.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { ServicePanel } from "../components/ServicePanel";
-import { serviceGroups } from "./story-data";
-
-const meta = {
- title: "UI/ServicePanel",
- component: ServicePanel,
- args: {
- group: serviceGroups.long,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const LongList: Story = {};
diff --git a/src/lib/ui/stories/ServiceRow.stories.tsx b/src/lib/ui/stories/ServiceRow.stories.tsx
deleted file mode 100644
index 9513d2c..0000000
--- a/src/lib/ui/stories/ServiceRow.stories.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { ServiceRow } from "../components/ServiceRow";
-import { serviceRows } from "./story-data";
-
-const meta = {
- title: "UI/ServiceRow",
- component: ServiceRow,
- args: {
- service: serviceRows.normal,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Normal: Story = {};
-export const Warning: Story = {
- args: {
- service: serviceRows.degraded,
- },
-};
diff --git a/src/lib/ui/stories/SignalTrace.stories.tsx b/src/lib/ui/stories/SignalTrace.stories.tsx
deleted file mode 100644
index ae8785b..0000000
--- a/src/lib/ui/stories/SignalTrace.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { SignalTrace } from "../components/SignalTrace";
-
-const meta = {
- title: "UI/SignalTrace",
- component: SignalTrace,
- args: {
- tone: "accent",
- orientation: "horizontal",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Horizontal: Story = {};
diff --git a/src/lib/ui/stories/Sparkline.stories.tsx b/src/lib/ui/stories/Sparkline.stories.tsx
deleted file mode 100644
index efecfbd..0000000
--- a/src/lib/ui/stories/Sparkline.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { Sparkline } from "../components/Sparkline";
-
-const meta = {
- title: "UI/Sparkline",
- component: Sparkline,
- args: {
- values: [8, 14, 12, 24, 18, 30],
- severity: "ok",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {};
diff --git a/src/lib/ui/stories/StatusBadge.stories.tsx b/src/lib/ui/stories/StatusBadge.stories.tsx
deleted file mode 100644
index 4513a08..0000000
--- a/src/lib/ui/stories/StatusBadge.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { StatusBadge } from "../components/StatusBadge";
-
-const meta = {
- title: "UI/StatusBadge",
- component: StatusBadge,
- args: {
- label: "Ready",
- severity: "ok",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Ready: Story = {};
diff --git a/src/lib/ui/stories/StatusStrip.stories.tsx b/src/lib/ui/stories/StatusStrip.stories.tsx
deleted file mode 100644
index 7b808fa..0000000
--- a/src/lib/ui/stories/StatusStrip.stories.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { StatusStrip } from "../components/StatusStrip";
-import { mixedStatusStrip } from "./story-data";
-
-const meta = {
- title: "UI/StatusStrip",
- component: StatusStrip,
- args: {
- id: "generic-status",
- items: mixedStatusStrip,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Mixed: Story = {};
diff --git a/src/lib/ui/stories/SystemState.stories.tsx b/src/lib/ui/stories/SystemState.stories.tsx
deleted file mode 100644
index 585540e..0000000
--- a/src/lib/ui/stories/SystemState.stories.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { SystemState } from "../components/SystemState";
-
-const meta = {
- title: "UI/SystemState",
- component: SystemState,
- args: {
- title: "Loading Dashboard",
- detail: "Fetching active model",
- severity: "loading",
- icon: "mdi:progress-clock",
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Loading: Story = {};
diff --git a/src/lib/ui/stories/TelemetryCard.stories.tsx b/src/lib/ui/stories/TelemetryCard.stories.tsx
deleted file mode 100644
index dbdf301..0000000
--- a/src/lib/ui/stories/TelemetryCard.stories.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { TelemetryCard } from "../components/TelemetryCard";
-import { telemetryCards } from "./story-data";
-
-const meta = {
- title: "UI/TelemetryCard",
- component: TelemetryCard,
- args: {
- card: telemetryCards.percent,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Percent: Story = {};
-export const Danger: Story = {
- args: {
- card: telemetryCards.danger,
- },
-};
diff --git a/src/lib/ui/stories/TelemetryGrid.stories.tsx b/src/lib/ui/stories/TelemetryGrid.stories.tsx
deleted file mode 100644
index 6b0166e..0000000
--- a/src/lib/ui/stories/TelemetryGrid.stories.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { TelemetryGrid } from "../components/TelemetryGrid";
-import { eightTelemetryCards, sixteenTelemetryCards } from "./story-data";
-
-const meta = {
- title: "UI/TelemetryGrid",
- component: TelemetryGrid,
- args: {
- cards: eightTelemetryCards,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const EightCards: Story = {};
-export const SixteenCards: Story = {
- args: {
- cards: sixteenTelemetryCards,
- },
-};
diff --git a/src/lib/ui/stories/TelemetryStrip.stories.tsx b/src/lib/ui/stories/TelemetryStrip.stories.tsx
deleted file mode 100644
index 76fc983..0000000
--- a/src/lib/ui/stories/TelemetryStrip.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { TelemetryStrip } from "../components/TelemetryStrip";
-import { eightTelemetryCards } from "./story-data";
-
-const meta = {
- title: "UI/TelemetryStrip",
- component: TelemetryStrip,
- args: {
- cards: eightTelemetryCards,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {};
diff --git a/src/lib/ui/stories/ThemeToggle.stories.tsx b/src/lib/ui/stories/ThemeToggle.stories.tsx
deleted file mode 100644
index 33e494a..0000000
--- a/src/lib/ui/stories/ThemeToggle.stories.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { ThemeToggle } from "../components/ThemeToggle";
-
-const meta = {
- title: "UI/ThemeToggle",
- component: ThemeToggle,
- args: {
- onThemeChange: () => undefined,
- theme: "dark",
- },
-} satisfies Meta;
-
-export default meta;
-
-type Story = StoryObj;
-
-export const Dark: Story = {};
-
-export const Light: Story = {
- args: {
- theme: "light",
- },
- globals: {
- theme: "light",
- },
-};
diff --git a/src/lib/ui/stories/WeatherModule.stories.tsx b/src/lib/ui/stories/WeatherModule.stories.tsx
deleted file mode 100644
index 6429de2..0000000
--- a/src/lib/ui/stories/WeatherModule.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from "@storybook/react-vite";
-import { WeatherModule } from "../components/WeatherModule";
-import { moduleBlocks } from "./story-data";
-
-const meta = {
- title: "UI/WeatherModule",
- component: WeatherModule,
- args: {
- module: moduleBlocks.compact,
- },
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {};
diff --git a/src/lib/ui/stories/story-data.ts b/src/lib/ui/stories/story-data.ts
deleted file mode 100644
index 4085dac..0000000
--- a/src/lib/ui/stories/story-data.ts
+++ /dev/null
@@ -1,258 +0,0 @@
-import { dashboardPreviewFixtures } from "../fixtures";
-import type {
- UiDashboardPreview,
- UiModuleBlock,
- UiServiceGroup,
- UiServiceRow,
- UiSeverity,
- UiStatusItem,
- UiTelemetryCard,
-} from "../types";
-
-export const primaryDashboard = dashboardPreviewFixtures.primary;
-export const secondaryDashboard = dashboardPreviewFixtures.secondary;
-
-export const emptyDashboard: UiDashboardPreview = {
- eyebrow: "Preview Surface",
- title: "Empty Console",
- subtitle: "No records available",
- telemetry: [],
- modules: [],
- serviceGroups: [],
- statusItems: [],
-};
-
-export const moduleBlocks: Record = {
- compact: {
- id: "module-compact",
- title: "Local Node",
- value: "21.4 C",
- detail: "static sample",
- icon: "mdi:weather-partly-cloudy",
- severity: "ok",
- },
- unavailable: {
- id: "module-unavailable",
- title: "External Signal",
- value: "n/a",
- detail: "fallback value",
- icon: "mdi:cloud-off-outline",
- severity: "unavailable",
- },
- long: {
- id: "module-long",
- title: "Regional Aggregate Signal",
- value: "manual review queued",
- detail: "long generic label wraps without layout shift",
- icon: "mdi:map-marker-radius-outline",
- severity: "warning",
- },
-};
-
-export const telemetryCards: Record = {
- percent: {
- id: "telemetry-percent",
- label: "Capacity Used",
- value: { kind: "percent", value: 82 },
- progress: 82,
- icon: "mdi:gauge",
- severity: "ok",
- detail: "static sample",
- sparkline: [24, 36, 28, 44, 52, 82],
- },
- bytes: {
- id: "telemetry-bytes",
- label: "Data Volume",
- value: { kind: "bytes", value: 982451653, precision: 1 },
- icon: "mdi:database",
- severity: "neutral",
- detail: "static sample",
- sparkline: [8, 12, 20, 18, 24, 29],
- },
- temperature: {
- id: "telemetry-temperature",
- label: "Node Temperature",
- value: { kind: "temperature", value: 21.4, precision: 1 },
- icon: "mdi:thermometer",
- severity: "neutral",
- detail: "static sample",
- sparkline: [18, 20, 19, 21, 20, 21.4],
- },
- latency: {
- id: "telemetry-latency",
- label: "Median Latency",
- value: { kind: "latency", value: 87 },
- icon: "mdi:timer-outline",
- severity: "warning",
- detail: "static sample",
- sparkline: [45, 51, 72, 63, 80, 87],
- },
- unavailable: {
- id: "telemetry-unavailable",
- label: "Remote Signal",
- value: { kind: "text", value: "n/a" },
- icon: "mdi:cloud-off-outline",
- severity: "unavailable",
- detail: "fallback value",
- },
- stale: {
- id: "telemetry-stale",
- label: "Sync Age",
- value: { kind: "text", value: "stale" },
- icon: "mdi:clock-alert-outline",
- severity: "stale",
- detail: "cached sample",
- sparkline: [22, 22, 22, 22, 22, 22],
- },
- danger: {
- id: "telemetry-danger",
- label: "Error Budget",
- value: { kind: "percent", value: 7 },
- progress: 7,
- icon: "mdi:alert-octagon-outline",
- severity: "danger",
- detail: "threshold breached",
- sparkline: [56, 41, 34, 20, 13, 7],
- },
- loading: {
- id: "telemetry-loading",
- label: "Pending Refresh",
- value: { kind: "text", value: "sync" },
- icon: "mdi:progress-clock",
- severity: "loading",
- detail: "waiting for update",
- },
- long: {
- id: "telemetry-long",
- label: "Very Long Generic Source Label That Must Wrap",
- value: { kind: "percent", value: 63 },
- progress: 63,
- icon: "mdi:chart-box-outline",
- severity: "neutral",
- detail: "long source label",
- sparkline: [14, 20, 28, 31, 49, 63],
- },
-};
-
-export const serviceRows: Record = {
- normal: row("service-normal", "Ingest", "Event intake pipeline", "mdi:arrow-collapse-down", "ok", "1.252 ms", {
- href: "#ingest",
- label: "Open ingest",
- }),
- down: row("service-down", "Replica", "Replica traffic cell", "mdi:access-point-off", "danger", "down"),
- degraded: row("service-degraded", "Scheduler", "Timed job coordinator", "mdi:calendar-clock", "warning", "1.487 ms"),
- stale: row("service-stale", "Archive", "Cold storage transfer", "mdi:archive-clock", "stale", "paused"),
- noLink: row("service-no-link", "Policy", "Rules evaluation", "mdi:shield-check", "neutral", "manual"),
- long: row(
- "service-long",
- "Long Generic Service Name That Wraps Cleanly",
- "Long generic service description with enough detail to exercise wrapping in constrained panels",
- "mdi:text-box-search-outline",
- "warning",
- "review queued",
- ),
-};
-
-export const serviceGroups: Record = {
- short: {
- id: "group-short",
- title: "Short List",
- services: [serviceRows.normal, serviceRows.degraded],
- },
- long: {
- id: "group-long",
- title: "Long List",
- services: [
- serviceRows.normal,
- serviceRows.degraded,
- serviceRows.stale,
- serviceRows.down,
- serviceRows.noLink,
- serviceRows.long,
- ],
- },
- empty: {
- id: "group-empty",
- title: "Empty Group",
- services: [],
- },
- mixed: {
- id: "group-mixed",
- title: "Mixed Statuses",
- services: [serviceRows.normal, serviceRows.down, serviceRows.degraded, serviceRows.stale],
- summary: [
- { id: "summary-ok", label: "Ok", value: "3", severity: "ok" },
- { id: "summary-warn", label: "Warn", value: "1", severity: "warning" },
- { id: "summary-down", label: "Down", value: "1", severity: "danger" },
- ],
- },
-};
-
-export const statusItems: Record = {
- ok: { id: "status-ok", label: "System", value: "Operational", severity: "ok" },
- degraded: { id: "status-degraded", label: "Routing", value: "Degraded", severity: "warning" },
- incident: { id: "status-incident", label: "Incident", value: "Active", severity: "danger" },
- syncing: { id: "status-syncing", label: "Refresh", value: "Syncing", severity: "loading" },
- stale: { id: "status-stale", label: "Last Sync", value: "18 minutes ago", severity: "stale" },
- action: {
- id: "status-action",
- label: "Action",
- value: "Inspect",
- severity: "neutral",
- link: { href: "#inspect", label: "Inspect status" },
- },
- long: {
- id: "status-long",
- label: "Long Generic Status Label",
- value: "long generic status value wraps",
- severity: "neutral",
- },
-};
-
-export const eightTelemetryCards = [
- telemetryCards.percent,
- telemetryCards.bytes,
- telemetryCards.temperature,
- telemetryCards.latency,
- telemetryCards.unavailable,
- telemetryCards.stale,
- telemetryCards.danger,
- telemetryCards.loading,
-];
-
-export const sixteenTelemetryCards = Array.from({ length: 16 }, (_, index) => {
- const card = eightTelemetryCards[index % eightTelemetryCards.length];
- return {
- ...card,
- id: `${card.id}-${index}`,
- label: `${card.label} ${index + 1}`,
- };
-});
-
-export const mixedStatusStrip = [
- statusItems.ok,
- statusItems.degraded,
- statusItems.incident,
- statusItems.syncing,
- statusItems.stale,
-];
-
-export const fullCompositionDashboard: UiDashboardPreview = {
- ...primaryDashboard,
- telemetry: eightTelemetryCards,
- modules: [moduleBlocks.compact, moduleBlocks.unavailable],
- serviceGroups: [serviceGroups.mixed, serviceGroups.short, serviceGroups.long],
- statusItems: mixedStatusStrip,
-};
-
-function row(
- id: string,
- label: string,
- description: string,
- icon: string,
- severity: UiSeverity,
- detail: string,
- link?: UiServiceRow["link"],
-): UiServiceRow {
- return { id, label, description, icon, severity, detail, link };
-}
diff --git a/src/lib/ui/storybook.test.ts b/src/lib/ui/storybook.test.ts
deleted file mode 100644
index aa76cad..0000000
--- a/src/lib/ui/storybook.test.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-import { existsSync, readdirSync, readFileSync } from "node:fs";
-import { join } from "node:path";
-import { describe, expect, test } from "vitest";
-
-const root = process.cwd();
-const componentsDir = join(root, "src/lib/ui/components");
-const storiesDir = join(root, "src/lib/ui/stories");
-
-const requiredStoryFiles = [
- "Badge.stories.tsx",
- "Button.stories.tsx",
- "DashboardFrame.stories.tsx",
- "DashboardHeader.stories.tsx",
- "DashboardOnePager.stories.tsx",
- "CornerBracketFrame.stories.tsx",
- "DiagonalStripeField.stories.tsx",
- "FooterCell.stories.tsx",
- "FooterStatusCell.stories.tsx",
- "GridFrame.stories.tsx",
- "IconButton.stories.tsx",
- "IconGlyph.stories.tsx",
- "LineChart.stories.tsx",
- "ModuleCard.stories.tsx",
- "Panel.stories.tsx",
- "ProgressMeter.stories.tsx",
- "Separator.stories.tsx",
- "ServiceGroupPanel.stories.tsx",
- "ServicePanel.stories.tsx",
- "ServiceRow.stories.tsx",
- "SignalTrace.stories.tsx",
- "Sparkline.stories.tsx",
- "StatusBadge.stories.tsx",
- "StatusStrip.stories.tsx",
- "SystemState.stories.tsx",
- "ScanlineField.stories.tsx",
- "TelemetryCard.stories.tsx",
- "TelemetryGrid.stories.tsx",
- "TelemetryStrip.stories.tsx",
- "ThemeToggle.stories.tsx",
- "WeatherModule.stories.tsx",
-] as const;
-
-const forbiddenStoryContent = [
- "dimension lab",
- "dimensionlab",
- "vince",
- "homepage",
-] as const;
-
-describe("Storybook inventory", () => {
- test("exposes scripts for local and static Storybook review", () => {
- const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as {
- scripts?: Record;
- };
-
- expect(packageJson.scripts?.storybook).toBeTypeOf("string");
- expect(packageJson.scripts?.storybook).toContain("storybook dev");
- expect(packageJson.scripts?.["build-storybook"]).toBe("storybook build");
- });
-
- test("has a story for every reusable dashboard UI component", () => {
- for (const filename of requiredStoryFiles) {
- expect(existsSync(join(storiesDir, filename)), `${filename} is missing`).toBe(true);
- }
- });
-
- test("loads dashboard component styles through the global app stylesheet", () => {
- const appStyles = readFileSync(join(root, "src/app.css"), "utf8");
- const dashboardFrame = readFileSync(
- join(componentsDir, "DashboardFrame.tsx"),
- "utf8",
- );
-
- expect(appStyles).toContain('./lib/ui/components/styles.css');
- expect(dashboardFrame).not.toContain('./styles.css');
- });
-
- test("configures Storybook theme switching for reusable components", () => {
- const previewSource = readFileSync(join(root, ".storybook/preview.ts"), "utf8");
-
- expect(previewSource).toContain("globalTypes");
- expect(previewSource).toContain("data-ui-theme");
- });
-
- test("keeps component and story files paired as the UI inventory changes", () => {
- const componentStoryFiles = readdirSync(componentsDir)
- .filter((filename) => filename.endsWith(".tsx") && !filename.endsWith(".test.tsx"))
- .map((filename) => filename.replace(".tsx", ".stories.tsx"));
-
- for (const filename of componentStoryFiles) {
- expect(existsSync(join(storiesDir, filename)), `${filename} is missing`).toBe(true);
- }
- });
-
- test("keeps Storybook fixtures generic and content-free", () => {
- const storyText = readdirSync(storiesDir)
- .filter((filename) => filename.endsWith(".tsx") || filename.endsWith(".ts"))
- .map((filename) => readFileSync(join(storiesDir, filename), "utf8").toLowerCase())
- .join("\n");
-
- for (const forbidden of forbiddenStoryContent) {
- expect(storyText).not.toContain(forbidden);
- }
- });
-
- test("includes style-only decorative primitives in the reusable UI inventory", () => {
- for (const component of [
- "CornerBracketFrame",
- "DiagonalStripeField",
- "ScanlineField",
- "SignalTrace",
- ]) {
- expect(existsSync(join(componentsDir, `${component}.tsx`)), `${component} is missing`).toBe(
- true,
- );
- expect(
- existsSync(join(storiesDir, `${component}.stories.tsx`)),
- `${component}.stories.tsx is missing`,
- ).toBe(true);
- }
- });
-
- test("keeps decorative primitives hidden from assistive technology", () => {
- for (const component of [
- "CornerBracketFrame",
- "DiagonalStripeField",
- "ScanlineField",
- "SignalTrace",
- ]) {
- const source = readFileSync(join(componentsDir, `${component}.tsx`), "utf8");
-
- expect(source).toContain('aria-hidden="true"');
- }
- });
-
- test("does not add deferred form/navigation primitives", () => {
- for (const component of ["Input", "ToggleGroup", "ScrollArea"]) {
- expect(existsSync(join(root, `src/lib/ui/components/${component}.tsx`))).toBe(false);
- expect(existsSync(join(storiesDir, `${component}.stories.tsx`))).toBe(false);
- }
- });
-
- test("does not keep legacy stories in the React Storybook inventory", () => {
- const legacyStoryExtension = [".stories", ".sve", "lte"].join("");
- const legacyStories = readdirSync(storiesDir).filter((filename) =>
- filename.endsWith(legacyStoryExtension),
- );
-
- expect(legacyStories).toEqual([]);
- });
-});
diff --git a/src/lib/ui/theme.test.ts b/src/lib/ui/theme.test.ts
deleted file mode 100644
index 8ed3f04..0000000
--- a/src/lib/ui/theme.test.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { describe, expect, test } from "vitest";
-import {
- getNextUiTheme,
- isUiTheme,
- persistUiTheme,
- resolveInitialUiTheme,
- UI_THEME_STORAGE_KEY,
-} from "./theme";
-
-describe("UI theme preference", () => {
- test("defaults to dark when no stored preference exists", () => {
- const storage = new Map();
-
- expect(resolveInitialUiTheme(storage)).toBe("dark");
- });
-
- test("restores a valid stored preference", () => {
- const storage = new Map([[UI_THEME_STORAGE_KEY, "light"]]);
-
- expect(resolveInitialUiTheme(storage)).toBe("light");
- });
-
- test("ignores invalid stored preferences", () => {
- const storage = new Map([[UI_THEME_STORAGE_KEY, "solarized"]]);
-
- expect(resolveInitialUiTheme(storage)).toBe("dark");
- });
-
- test("falls back when stored preferences cannot be read", () => {
- const storage = {
- getItem() {
- throw new Error("storage blocked");
- },
- };
-
- expect(resolveInitialUiTheme(storage)).toBe("dark");
- });
-
- test("ignores persistence failures", () => {
- const storage = {
- setItem() {
- throw new Error("quota exceeded");
- },
- };
-
- expect(() => persistUiTheme("light", storage)).not.toThrow();
- });
-
- test("detects and toggles supported themes", () => {
- expect(isUiTheme("light")).toBe(true);
- expect(isUiTheme("dark")).toBe(true);
- expect(isUiTheme("contrast")).toBe(false);
- expect(getNextUiTheme("dark")).toBe("light");
- expect(getNextUiTheme("light")).toBe("dark");
- });
-});
diff --git a/src/lib/ui/theme.ts b/src/lib/ui/theme.ts
deleted file mode 100644
index 9f48df5..0000000
--- a/src/lib/ui/theme.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-export const UI_THEME_STORAGE_KEY = "dashboard-ui-theme";
-
-export type UiTheme = "dark" | "light";
-
-type ReadableThemeStorage =
- | { getItem(key: string): string | null }
- | { get(key: string): string | undefined };
-
-type WritableThemeStorage =
- | { setItem(key: string, value: string): void }
- | { set(key: string, value: string): unknown };
-
-export function isUiTheme(value: unknown): value is UiTheme {
- return value === "dark" || value === "light";
-}
-
-export function getNextUiTheme(theme: UiTheme): UiTheme {
- return theme === "dark" ? "light" : "dark";
-}
-
-export function resolveInitialUiTheme(
- storage?: ReadableThemeStorage | null,
- fallback: UiTheme = "dark",
-): UiTheme {
- const stored = safeReadStoredTheme(storage);
-
- return isUiTheme(stored) ? stored : fallback;
-}
-
-export function persistUiTheme(
- theme: UiTheme,
- storage?: WritableThemeStorage | null,
-): void {
- if (!storage) return;
-
- try {
- if ("setItem" in storage) {
- storage.setItem(UI_THEME_STORAGE_KEY, theme);
- return;
- }
-
- storage.set(UI_THEME_STORAGE_KEY, theme);
- } catch {
- // Browser storage may be blocked or quota-constrained.
- }
-}
-
-function safeReadStoredTheme(
- storage?: ReadableThemeStorage | null,
-): string | undefined {
- try {
- return readStoredTheme(storage);
- } catch {
- return undefined;
- }
-}
-
-function readStoredTheme(
- storage?: ReadableThemeStorage | null,
-): string | undefined {
- if (!storage) return undefined;
-
- if ("getItem" in storage) {
- return storage.getItem(UI_THEME_STORAGE_KEY) ?? undefined;
- }
-
- return storage.get(UI_THEME_STORAGE_KEY);
-}
diff --git a/src/lib/ui/tokens.css b/src/lib/ui/tokens.css
deleted file mode 100644
index 3e70132..0000000
--- a/src/lib/ui/tokens.css
+++ /dev/null
@@ -1,125 +0,0 @@
-:root,
-[data-ui-theme="dark"] {
- color-scheme: dark;
- --ui-color-canvas: #020302;
- --ui-color-surface: #060706;
- --ui-color-surface-raised: #0b0d0c;
- --ui-color-surface-panel: rgba(3, 4, 3, 0.86);
- --ui-color-surface-module: rgba(6, 8, 7, 0.82);
- --ui-color-surface-footer: rgba(2, 3, 2, 0.92);
- --ui-color-surface-inset: #030403;
- --ui-color-surface-icon: #050605;
- --ui-color-line: rgba(244, 244, 244, 0.16);
- --ui-color-line-strong: rgba(244, 244, 244, 0.32);
- --ui-color-grid-line: rgba(255, 255, 255, 0.035);
- --ui-color-frame-spine: rgba(255, 255, 255, 0.08);
- --ui-color-frame-wash: rgba(0, 0, 0, 0.18);
- --ui-color-card-gradient-start: rgba(13, 15, 14, 0.82);
- --ui-color-card-gradient-end: rgba(2, 3, 2, 0.92);
- --ui-color-hover: rgba(244, 244, 244, 0.035);
- --ui-color-text: #f3f4ed;
- --ui-color-muted: #8d948c;
- --ui-color-dim: #555b55;
- --ui-color-accent: #d7ff00;
- --ui-color-accent-contrast: #050605;
- --ui-color-ok: #bfff00;
- --ui-color-warning: #ffb020;
- --ui-color-danger: #ff1744;
- --ui-color-stale: #82909a;
- --ui-color-unavailable: #65707a;
- --ui-font-mono: "IBM Plex Mono", "Roboto Mono", "SFMono-Regular", Consolas, monospace;
- --ui-font-display: "Teko", "IBM Plex Mono", "Roboto Mono", monospace;
- --ui-space-1: 0.25rem;
- --ui-space-2: 0.5rem;
- --ui-space-3: 0.75rem;
- --ui-space-4: 1rem;
- --ui-space-5: 1.25rem;
- --ui-space-6: 1.5rem;
- --ui-radius-none: 0;
- --ui-border: 1px solid var(--ui-color-line);
- --ui-border-strong: 1px solid var(--ui-color-line-strong);
- --ui-shadow-hard: 0 0 0 1px rgba(215, 255, 0, 0.12) inset;
- --ui-z-base: 0;
- --ui-z-panel: 1;
- --ui-z-overlay: 10;
- --ui-density-card-min: 9.75rem;
- --ui-focus-ring: 0 0 0 2px var(--ui-color-canvas), 0 0 0 4px var(--ui-color-accent);
-}
-
-[data-ui-theme="light"] {
- color-scheme: light;
- --ui-color-canvas: #f3f5ed;
- --ui-color-surface: #ffffff;
- --ui-color-surface-raised: #eef1e7;
- --ui-color-surface-panel: rgba(255, 255, 255, 0.9);
- --ui-color-surface-module: rgba(255, 255, 255, 0.84);
- --ui-color-surface-footer: rgba(248, 250, 241, 0.94);
- --ui-color-surface-inset: #e4e8db;
- --ui-color-surface-icon: #f8faf1;
- --ui-color-line: rgba(19, 25, 19, 0.18);
- --ui-color-line-strong: rgba(19, 25, 19, 0.34);
- --ui-color-grid-line: rgba(19, 25, 19, 0.055);
- --ui-color-frame-spine: rgba(19, 25, 19, 0.1);
- --ui-color-frame-wash: rgba(255, 255, 255, 0.48);
- --ui-color-card-gradient-start: rgba(255, 255, 255, 0.92);
- --ui-color-card-gradient-end: rgba(230, 235, 221, 0.88);
- --ui-color-hover: rgba(19, 25, 19, 0.055);
- --ui-color-text: #11170f;
- --ui-color-muted: #5d665a;
- --ui-color-dim: #7d8779;
- --ui-color-accent: #516f00;
- --ui-color-accent-contrast: #ffffff;
- --ui-color-ok: #4c7400;
- --ui-color-warning: #a45b00;
- --ui-color-danger: #bd173f;
- --ui-color-stale: #596975;
- --ui-color-unavailable: #6c7479;
- --ui-shadow-hard: 0 0 0 1px rgba(81, 111, 0, 0.18) inset;
-}
-
-html {
- background: var(--ui-color-canvas);
-}
-
-body {
- min-width: 320px;
- min-height: 100vh;
- margin: 0;
- background:
- linear-gradient(var(--ui-color-grid-line) 1px, transparent 1px),
- linear-gradient(90deg, var(--ui-color-grid-line) 1px, transparent 1px),
- var(--ui-color-canvas);
- background-size: 48px 48px, 48px 48px, auto;
- color: var(--ui-color-text);
- font-family: var(--ui-font-mono);
- text-rendering: geometricPrecision;
-}
-
-button,
-input,
-textarea,
-select {
- font: inherit;
-}
-
-button:focus-visible,
-a:focus-visible,
-[tabindex]:focus-visible {
- outline: 0;
- box-shadow: var(--ui-focus-ring);
-}
-
-a {
- color: inherit;
-}
-
-@media (prefers-reduced-motion: reduce) {
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- scroll-behavior: auto !important;
- transition-duration: 0.01ms !important;
- }
-}
diff --git a/src/lib/ui/types.ts b/src/lib/ui/types.ts
deleted file mode 100644
index 792a24b..0000000
--- a/src/lib/ui/types.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-export type UiSeverity =
- | "neutral"
- | "ok"
- | "warning"
- | "danger"
- | "stale"
- | "unavailable"
- | "loading";
-
-export type UiMetricKind =
- | "bytes"
- | "latency"
- | "number"
- | "percent"
- | "temperature"
- | "text";
-
-export interface UiMetricValue {
- kind: UiMetricKind;
- value: number | string;
- unit?: string;
- precision?: number;
-}
-
-export interface UiLink {
- href: string;
- label?: string;
- external?: boolean;
-}
-
-export interface UiTelemetryCard {
- id: string;
- label: string;
- value: UiMetricValue;
- detail?: string;
- description?: string;
- icon?: string;
- severity: UiSeverity;
- progress?: number;
- sparkline?: number[];
-}
-
-export interface UiServiceRow {
- id: string;
- label: string;
- description: string;
- icon?: string;
- severity: UiSeverity;
- detail?: string;
- link?: UiLink;
-}
-
-export interface UiServiceGroup {
- id: string;
- layout?: "grid" | "list";
- title: string;
- services: UiServiceRow[];
- summary?: UiStatusItem[];
-}
-
-export interface UiStatusItem {
- id: string;
- label: string;
- value: string;
- severity?: UiSeverity;
- link?: UiLink;
-}
-
-export interface UiModuleBlock {
- id: string;
- title?: string;
- label?: string;
- value?: string;
- detail?: string;
- icon?: string;
- severity?: UiSeverity;
-}
-
-export interface UiDashboardPreview {
- title: string;
- subtitle?: string;
- eyebrow?: string;
- telemetry: UiTelemetryCard[];
- serviceGroups: UiServiceGroup[];
- modules: UiModuleBlock[];
- statusItems: UiStatusItem[];
- statusStripId?: string;
-}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
deleted file mode 100644
index bd0c391..0000000
--- a/src/lib/utils.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { clsx, type ClassValue } from "clsx"
-import { twMerge } from "tailwind-merge"
-
-export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
-}
diff --git a/src/server/routes/dashboard.test.ts b/src/server/routes/dashboard.test.ts
deleted file mode 100644
index ebe575b..0000000
--- a/src/server/routes/dashboard.test.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { describe, expect, test } from "vitest";
-import { dimensionLabDashboardFixture } from "$lib/model/fixtures/dimensionlab";
-import { loadDashboardResponse } from "./dashboard";
-
-describe("dashboard API route", () => {
- test("returns ready dashboard runtime state from the existing model loader", async () => {
- const response = await loadDashboardResponse({
- disableLiveDatasources: true,
- refreshSeedDocument: true,
- seedIfEmpty: true,
- });
-
- expect(response.state).toBe("ready");
- if (response.state !== "ready") throw new Error("expected ready dashboard");
- expect(response.document.metadata.title).toBe(
- dimensionLabDashboardFixture.metadata.title,
- );
- });
-});
diff --git a/src/server/routes/dashboard.ts b/src/server/routes/dashboard.ts
deleted file mode 100644
index 21c30e4..0000000
--- a/src/server/routes/dashboard.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import {
- loadDashboardRuntime,
- type DashboardRuntimeOptions,
- type DashboardRuntimeState,
-} from "$lib/server/dashboard";
-import { resolveDashboardDatasources } from "$lib/server/datasources";
-
-export interface LoadDashboardResponseOptions
- extends Pick<
- DashboardRuntimeOptions,
- "refreshSeedDocument" | "seedIfEmpty" | "seedDocument"
- > {
- disableLiveDatasources?: boolean;
-}
-
-export async function loadDashboardResponse(
- options: LoadDashboardResponseOptions = {},
-): Promise {
- const dashboard = loadDashboardRuntime(undefined, {
- refreshSeedDocument: options.refreshSeedDocument ?? true,
- seedIfEmpty: options.seedIfEmpty ?? true,
- seedDocument: options.seedDocument,
- });
-
- if (dashboard.state !== "ready") {
- return dashboard;
- }
-
- if (options.disableLiveDatasources || process.env.DISABLE_LIVE_DATASOURCES === "1") {
- return dashboard;
- }
-
- return {
- ...dashboard,
- document: await resolveDashboardDatasources(dashboard.document),
- };
-}
-
-export async function handleDashboardRoute(): Promise {
- return Response.json(await loadDashboardResponse());
-}
diff --git a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-desktop-chromium-desktop-linux.png b/tests/e2e/dashboard.spec.ts-snapshots/dashboard-desktop-chromium-desktop-linux.png
deleted file mode 100644
index 848033e..0000000
Binary files a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-desktop-chromium-desktop-linux.png and /dev/null differ
diff --git a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-light-desktop-chromium-desktop-linux.png b/tests/e2e/dashboard.spec.ts-snapshots/dashboard-light-desktop-chromium-desktop-linux.png
deleted file mode 100644
index 5b04c30..0000000
Binary files a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-light-desktop-chromium-desktop-linux.png and /dev/null differ
diff --git a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-mobile-chromium-mobile-linux.png b/tests/e2e/dashboard.spec.ts-snapshots/dashboard-mobile-chromium-mobile-linux.png
deleted file mode 100644
index 1f6baf4..0000000
Binary files a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-mobile-chromium-mobile-linux.png and /dev/null differ
diff --git a/tsconfig.base.json b/tsconfig.base.json
new file mode 100644
index 0000000..dcde3db
--- /dev/null
+++ b/tsconfig.base.json
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "ignoreDeprecations": "6.0",
+ "jsx": "react-jsx",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "target": "ES2022",
+ "types": ["node", "bun-types", "react", "react-dom"]
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
index ab92320..8fe9b00 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,35 +1,8 @@
{
- "compilerOptions": {
- "allowJs": true,
- "baseUrl": ".",
- "checkJs": true,
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "ignoreDeprecations": "6.0",
- "jsx": "react-jsx",
- "module": "ESNext",
- "moduleResolution": "bundler",
- "paths": {
- "$lib/*": ["src/lib/*"]
- },
- "resolveJsonModule": true,
- "skipLibCheck": true,
- "sourceMap": true,
- "strict": true,
- "target": "ES2022",
- "types": ["node", "bun-types", "react", "react-dom"]
- },
- "include": [
- "src/**/*.ts",
- "src/**/*.tsx",
- "tests/**/*.ts",
- "vite.config.ts",
- "playwright.config.ts",
- "drizzle.config.ts"
- ],
- "exclude": [
- "build",
- "node_modules",
- ".storybook"
+ "files": [],
+ "references": [
+ { "path": "./packages/dashboard-model" },
+ { "path": "./apps/web" },
+ { "path": "./packages/ui" }
]
}
diff --git a/turbo.json b/turbo.json
new file mode 100644
index 0000000..e1b2e7c
--- /dev/null
+++ b/turbo.json
@@ -0,0 +1,98 @@
+{
+ "$schema": "https://turbo.build/schema.json",
+ "globalDependencies": [
+ "bun.lock",
+ "package.json",
+ "tsconfig.base.json",
+ "tsconfig.json"
+ ],
+ "tasks": {
+ "build": {
+ "dependsOn": ["^build"],
+ "inputs": ["$TURBO_DEFAULT$", ".env*"],
+ "outputs": ["dist/**", "build/**"],
+ "env": ["NODE_ENV", "VITE_*"]
+ },
+ "check": {
+ "dependsOn": ["^build"],
+ "outputs": []
+ },
+ "test:unit": {
+ "dependsOn": ["^build"],
+ "outputs": [],
+ "env": [
+ "AGENT_CONFIG_TOKEN",
+ "DASHBOARD_MIGRATIONS_DIR",
+ "DATABASE_URL",
+ "DISABLE_LIVE_DATASOURCES",
+ "PROMETHEUS_BASE_URL"
+ ]
+ },
+ "build-storybook": {
+ "dependsOn": ["^build"],
+ "inputs": ["$TURBO_DEFAULT$", ".env*"],
+ "outputs": ["storybook-static/**"],
+ "env": ["NODE_ENV", "STORYBOOK_*", "VITE_*"]
+ },
+ "test:e2e": {
+ "dependsOn": [
+ "build",
+ "^build",
+ "@dimensionlab/ui#build-storybook"
+ ],
+ "outputs": ["test-results/**", "playwright-report/**"],
+ "env": [
+ "AGENT_CONFIG_TOKEN",
+ "CI",
+ "DASHBOARD_MIGRATIONS_DIR",
+ "DATABASE_URL",
+ "DISABLE_LIVE_DATASOURCES",
+ "PLAYWRIGHT_DATABASE_URL",
+ "PLAYWRIGHT_PORT",
+ "PLAYWRIGHT_STORYBOOK_PORT",
+ "PROMETHEUS_BASE_URL",
+ "STORYBOOK_STATIC_PORT"
+ ]
+ },
+ "db:generate": {
+ "cache": false
+ },
+ "db:check": {
+ "outputs": [],
+ "env": ["DATABASE_URL"]
+ },
+ "dev": {
+ "dependsOn": ["^build"],
+ "cache": false,
+ "persistent": true,
+ "env": [
+ "AGENT_CONFIG_TOKEN",
+ "DASHBOARD_DEV_API_HOST",
+ "DASHBOARD_DEV_API_PORT",
+ "DASHBOARD_DEV_API_TARGET",
+ "DASHBOARD_MIGRATIONS_DIR",
+ "DATABASE_URL",
+ "HOST",
+ "PORT",
+ "PROMETHEUS_BASE_URL"
+ ]
+ },
+ "preview": {
+ "cache": false,
+ "persistent": true,
+ "env": [
+ "AGENT_CONFIG_TOKEN",
+ "DASHBOARD_MIGRATIONS_DIR",
+ "DATABASE_URL",
+ "HOST",
+ "PORT",
+ "PROMETHEUS_BASE_URL"
+ ]
+ },
+ "storybook": {
+ "cache": false,
+ "persistent": true,
+ "env": ["HOST", "PORT", "STORYBOOK_*", "VITE_*"]
+ }
+ }
+}