import { cn } from "@/lib/utils"; /** * UI-Basisbausteine (Craftvia-CD): PageHead (Crumb/Titel/Sub + Aktionen), KPI-Kapsel, * Tag-Chip, Owner-Chip, Status-Pille. Farbe nie als einziges Statussignal — Pillen * tragen immer Text. */ export function PageHead({ crumb, title, sub, actions, }: { crumb: string; title: string; sub?: string; actions?: React.ReactNode; }) { return (
{crumb}

{title}

{sub &&
{sub}
}
{actions &&
{actions}
}
); } export function KpiCard({ label, value, trend, trendColor = "muted", }: { label: string; value: React.ReactNode; trend?: string; trendColor?: "muted" | "risk" | "warn" | "ok"; }) { const trendColors = { muted: "text-muted-foreground", risk: "text-[var(--risk)]", warn: "text-[var(--warn)]", ok: "text-[var(--ok)]", }; return (
{label}
{value}
{trend &&
{trend}
}
); } export function Tag({ children }: { children: React.ReactNode }) { return ( {children} ); } export function OwnerChip({ name, noOwnerLabel }: { name?: string | null; noOwnerLabel: string }) { if (!name) return {noOwnerLabel}; const initials = name .split(/\s+/) .map((p) => p[0]) .slice(0, 2) .join("") .toUpperCase(); return ( {initials} {name} ); } // Status-Chips: ~12 % Alpha der Funktionsfarbe auf hellem Grund (Brandbook §11.4). const PILL_TONES = { ok: "bg-[rgba(35,132,93,0.12)] text-[var(--ok)]", warn: "bg-[rgba(200,121,18,0.12)] text-[var(--warn)]", orange: "bg-[rgba(255,106,0,0.12)] text-[#b34a00]", risk: "bg-[rgba(198,66,66,0.12)] text-[var(--risk)]", info: "bg-[rgba(47,111,163,0.12)] text-[var(--info)]", mut: "bg-[rgba(102,114,125,0.12)] text-muted-foreground", violet: "bg-[rgba(8,46,91,0.1)] text-[var(--primary)]", } as const; export function Pill({ tone, children, }: { tone: keyof typeof PILL_TONES; children: React.ReactNode; }) { return ( {children} ); } export function SectTitle({ title, sub }: { title: string; sub?: string }) { return (
{title}
{sub &&
{sub}
}
); }