Standardize all spacing to multiples of 4px (0.25rem): - 0.15rem (2.4px) → 0.25rem (4px) - 0.35rem (5.6px) → 0.25rem (4px) - 0.375rem (6px) → 0.25rem (4px) for borderRadius - 0.4rem (6.4px) → 0.5rem (8px) - 0.6rem (9.6px) → 0.5rem (8px) Updated theme.css density variables, silo-base.css focus ring, and all TSX component inline styles. Closes #71
89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
import type { AuditSummary } from "../../api/types";
|
|
|
|
const tierConfig = [
|
|
{ key: "critical", label: "Critical", color: "var(--ctp-red)" },
|
|
{ key: "low", label: "Low", color: "var(--ctp-peach)" },
|
|
{ key: "partial", label: "Partial", color: "var(--ctp-yellow)" },
|
|
{ key: "good", label: "Good", color: "var(--ctp-green)" },
|
|
{ key: "complete", label: "Complete", color: "var(--ctp-teal)" },
|
|
] as const;
|
|
|
|
interface AuditSummaryBarProps {
|
|
summary: AuditSummary;
|
|
activeTier: string;
|
|
onTierClick: (tier: string) => void;
|
|
}
|
|
|
|
export function AuditSummaryBar({
|
|
summary,
|
|
activeTier,
|
|
onTierClick,
|
|
}: AuditSummaryBarProps) {
|
|
const total = summary.total_items || 1;
|
|
|
|
return (
|
|
<div style={{ marginBottom: "0.75rem" }}>
|
|
{/* Stacked bar */}
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
height: 32,
|
|
borderRadius: "0.5rem",
|
|
overflow: "hidden",
|
|
cursor: "pointer",
|
|
}}
|
|
>
|
|
{tierConfig.map(({ key, label, color }) => {
|
|
const count = summary.by_tier[key] ?? 0;
|
|
if (count === 0) return null;
|
|
const pct = (count / total) * 100;
|
|
const isActive = activeTier === key;
|
|
return (
|
|
<div
|
|
key={key}
|
|
onClick={() => onTierClick(activeTier === key ? "" : key)}
|
|
title={`${label}: ${count}`}
|
|
style={{
|
|
width: `${pct}%`,
|
|
minWidth: count > 0 ? 28 : 0,
|
|
backgroundColor: color,
|
|
opacity: !activeTier || isActive ? 1 : 0.35,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
fontSize: "var(--font-sm)",
|
|
fontWeight: 600,
|
|
color: "var(--ctp-crust)",
|
|
transition: "all 0.15s ease",
|
|
outline: isActive ? "2px solid var(--ctp-text)" : "none",
|
|
outlineOffset: -2,
|
|
}}
|
|
>
|
|
{pct > 8 ? `${label} ${count}` : count}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* Stats line */}
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
gap: "1.5rem",
|
|
marginTop: "0.5rem",
|
|
fontSize: "var(--font-table)",
|
|
color: "var(--ctp-subtext0)",
|
|
}}
|
|
>
|
|
<span>{summary.total_items} items</span>
|
|
<span>Avg score: {(summary.avg_score * 100).toFixed(1)}%</span>
|
|
{summary.manufactured_without_bom > 0 && (
|
|
<span style={{ color: "var(--ctp-red)" }}>
|
|
{summary.manufactured_without_bom} manufactured without BOM
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|