mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-27 02:44:50 +01:00
design(decisions): severity → outline badge, red = Critical only (2a)
Critical renders as an outline badge on the destructive tokens (border-destructive/60 text-destructive; AA vs --card: 4.76:1 light, 4.69:1 dark — no dark override needed). High becomes a neutral outline (border-border text-muted-foreground). Medium/Low stay badge-less. Deletes the unconsumed severityStyle/SEVERITY_STYLE map (filled red/orange/yellow/blue accents; zero component call sites) — severity keys a badge, never card color, and the tone-vs-severity invariant test is preserved. Badge tests updated in lockstep: old literal assertions replaced with token-shaped ones (outline = no bg- class, no palette red/ orange). Part of the Quiet Ledger series (commit 1 of 6). Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
c6d4ee10f7
commit
b2a9e09dab
3 files changed
+27
-26
No files matched your search
@@ -19,7 +19,6 @@ import {
|
||||
planAttentionRenderRows,
|
||||
saveAttentionGroupBy,
|
||||
severityBadge,
|
||||
severityStyle,
|
||||
sortAttentionItems,
|
||||
sourceMeta,
|
||||
} from "./attention";
|
||||
@@ -110,7 +109,7 @@ describe("attentionBadgeCount", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("sourceMeta + severityStyle", () => {
|
||||
describe("sourceMeta", () => {
|
||||
it("labels every catalog source kind", () => {
|
||||
const kinds: AttentionSourceKind[] = [
|
||||
"approval",
|
||||
@@ -130,9 +129,6 @@ describe("sourceMeta + severityStyle", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("maps escalation severity to distinct accents", () => {
|
||||
expect(severityStyle("critical").accent).not.toBe(severityStyle("low").accent);
|
||||
});
|
||||
});
|
||||
|
||||
describe("attentionTone + attentionToneStyle (canonical color map §4)", () => {
|
||||
@@ -186,13 +182,30 @@ describe("attentionTone + attentionToneStyle (canonical color map §4)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("severityBadge", () => {
|
||||
describe("severityBadge (anatomy 2a — outline badges, red = Critical only)", () => {
|
||||
it("only surfaces a badge for Critical/High", () => {
|
||||
expect(severityBadge("critical")?.label).toBe("Critical");
|
||||
expect(severityBadge("high")?.label).toBe("High");
|
||||
expect(severityBadge("medium")).toBeNull();
|
||||
expect(severityBadge("low")).toBeNull();
|
||||
});
|
||||
|
||||
it("draws Critical as an outline on the destructive tokens — the page's only red", () => {
|
||||
const badge = severityBadge("critical");
|
||||
expect(badge?.className).toContain("border-destructive");
|
||||
expect(badge?.className).toContain("text-destructive");
|
||||
// Outline, not filled: no background class of any kind.
|
||||
expect(badge?.className).not.toMatch(/\bbg-/);
|
||||
expect(badge?.className).not.toMatch(/red|orange/);
|
||||
});
|
||||
|
||||
it("draws High as a neutral outline (no palette color)", () => {
|
||||
const badge = severityBadge("high");
|
||||
expect(badge?.className).toContain("border-border");
|
||||
expect(badge?.className).toContain("text-muted-foreground");
|
||||
expect(badge?.className).not.toMatch(/\bbg-/);
|
||||
expect(badge?.className).not.toMatch(/red|orange|destructive/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("attentionDetailLine (§7)", () => {
|
||||
|
||||
+4
-20
@@ -60,24 +60,6 @@ export function sourceMeta(kind: AttentionSourceKind): SourceMeta {
|
||||
return SOURCE_META[kind] ?? { label: kind.replaceAll("_", " "), icon: AlertTriangle };
|
||||
}
|
||||
|
||||
interface SeverityStyle {
|
||||
/** Left accent bar + dot color. */
|
||||
accent: string;
|
||||
dot: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const SEVERITY_STYLE: Record<AttentionSeverity, SeverityStyle> = {
|
||||
critical: { accent: "bg-red-500", dot: "bg-red-500", label: "Critical" },
|
||||
high: { accent: "bg-orange-500", dot: "bg-orange-500", label: "High" },
|
||||
medium: { accent: "bg-yellow-500", dot: "bg-yellow-500", label: "Medium" },
|
||||
low: { accent: "bg-blue-500", dot: "bg-blue-500", label: "Low" },
|
||||
};
|
||||
|
||||
export function severityStyle(severity: AttentionSeverity): SeverityStyle {
|
||||
return SEVERITY_STYLE[severity] ?? SEVERITY_STYLE.low;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Canonical type → color map (PAP-13409 §4)
|
||||
//
|
||||
@@ -168,10 +150,12 @@ export function attentionToneStyle(item: AttentionItem): AttentionToneStyle {
|
||||
*/
|
||||
export function severityBadge(severity: AttentionSeverity): { label: string; className: string } | null {
|
||||
if (severity === "critical") {
|
||||
return { label: "Critical", className: "border-red-500/60 bg-red-500/10 text-red-700 dark:text-red-300" };
|
||||
// Red is reserved for Critical, and only as an outline — no fill. AA on
|
||||
// --card: 4.76:1 light, 4.69:1 dark (--destructive vs --card, WCAG 2.1).
|
||||
return { label: "Critical", className: "border-destructive/60 text-destructive" };
|
||||
}
|
||||
if (severity === "high") {
|
||||
return { label: "High", className: "border-orange-500/60 bg-orange-500/10 text-orange-700 dark:text-orange-300" };
|
||||
return { label: "High", className: "border-border text-muted-foreground" };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user