Files
silo/web/src/components/audit/AuditSummaryBar.tsx
Forbes ba92dd363c fix(web): align all spacing values to 4px grid
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
2026-02-14 13:36:22 -06:00

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>
);
}