refactor(ui): organize component source tree

This commit is contained in:
vince 2026-06-20 06:43:09 +02:00
parent 8927f2ab8a
commit 32ad2cebe4
66 changed files with 194 additions and 124 deletions

View file

@ -0,0 +1,26 @@
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 (
<div
className="corner-bracket-frame"
data-density={density}
data-size={size}
data-tone={tone}
aria-hidden="true"
>
<span data-corner="top-left" />
<span data-corner="top-right" />
<span data-corner="bottom-left" />
<span data-corner="bottom-right" />
</div>
);
}

View file

@ -0,0 +1,59 @@
import { useId } from "react";
import type { ReactNode } from "react";
import type { UiDashboardPreview } from "../../types";
import { ModuleCard } from "./ModuleCard";
import { ServicePanel } from "../operations/ServicePanel";
import { StatusStrip } from "../operations/StatusStrip";
import { TelemetryGrid } from "../telemetry/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 (
<main className="dashboard-frame" aria-labelledby={resolvedTitleId}>
<header className="dashboard-frame__header console-header">
<div className="dashboard-frame__title">
<div className="dashboard-frame__title-copy">
{dashboard.eyebrow ? <p>{dashboard.eyebrow}</p> : null}
<h1 id={resolvedTitleId}>{dashboard.title}</h1>
{dashboard.subtitle ? <span>{dashboard.subtitle}</span> : null}
</div>
{actions ? (
<div className="dashboard-frame__actions">{actions}</div>
) : null}
</div>
{dashboard.modules.length ? (
<div className="dashboard-frame__modules">
{dashboard.modules.map((module) => (
<ModuleCard key={module.id} module={module} />
))}
</div>
) : null}
</header>
<TelemetryGrid cards={dashboard.telemetry} />
<section className="dashboard-frame__panels" aria-label="Service groups">
{dashboard.serviceGroups.map((group) => (
<ServicePanel key={group.id} group={group} />
))}
</section>
<StatusStrip
id={dashboard.statusStripId}
items={dashboard.statusItems}
/>
</main>
);
}

View file

@ -0,0 +1,30 @@
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 (
<header className="dashboard-header" aria-labelledby={titleId}>
<div>
{eyebrow ? <p>{eyebrow}</p> : null}
<h1 id={titleId}>{title}</h1>
{subtitle ? <span>{subtitle}</span> : null}
</div>
{module ? <ModuleCard module={module} /> : null}
</header>
);
}

View file

@ -0,0 +1,24 @@
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 (
<div
className="diagonal-stripe-field"
data-density={density}
data-direction={direction}
data-size={size}
data-tone={tone}
aria-hidden="true"
/>
);
}

View file

@ -0,0 +1,42 @@
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 = (
<>
<span>{item.label}</span>
<strong>{item.value}</strong>
</>
);
if (item.link) {
return (
<a
className="footer-cell"
data-severity={item.severity || "neutral"}
data-model-id={item.id}
href={item.link.href}
target={target}
rel={rel}
aria-label={item.link.label}
>
{content}
</a>
);
}
return (
<div
className="footer-cell"
data-severity={item.severity || "neutral"}
data-model-id={item.id}
>
{content}
</div>
);
}

View file

@ -0,0 +1,6 @@
import type { UiStatusItem } from "../../types";
import { FooterCell } from "./FooterCell";
export function FooterStatusCell({ item }: { item: UiStatusItem }) {
return <FooterCell item={item} />;
}

View file

@ -0,0 +1,13 @@
import type { PropsWithChildren } from "react";
export interface GridFrameProps extends PropsWithChildren {
density?: "compact" | "dense";
}
export function GridFrame({ children, density = "dense" }: GridFrameProps) {
return (
<section className="grid-frame" data-density={density}>
{children}
</section>
);
}

View file

@ -0,0 +1,32 @@
import { useId } from "react";
import type { UiModuleBlock } from "../../types";
import { IconGlyph } from "../foundation/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 (
<aside
className="module-card"
data-severity={module.severity || "neutral"}
data-model-id={module.id}
aria-labelledby={module.title ? titleId : undefined}
aria-label={ariaLabel}
>
<div>
{module.title ? <h2 id={titleId}>{module.title}</h2> : null}
{module.value ? <strong>{module.value}</strong> : null}
{module.detail || module.label ? (
<p>{module.detail || module.label}</p>
) : null}
</div>
{module.icon ? <IconGlyph name={module.icon} size="lg" /> : null}
</aside>
);
}

View file

@ -0,0 +1,19 @@
import type { PropsWithChildren } from "react";
export interface PanelProps extends PropsWithChildren {
title?: string;
density?: "compact" | "dense";
}
export function Panel({ title, density = "dense", children }: PanelProps) {
return (
<section className="panel" data-density={density}>
{title ? (
<header className="panel__header">
<h2>{title}</h2>
</header>
) : null}
<div className="panel__body">{children}</div>
</section>
);
}

View file

@ -0,0 +1,21 @@
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 (
<div
className="scanline-field"
data-intensity={intensity}
data-size={size}
data-tone={tone}
aria-hidden="true"
/>
);
}