Files
Logan Cusano 3a786bc227
Build & Deploy / Build & push images (push) Successful in 5m11s
Build & Deploy / Deploy to VM (push) Failing after 3m33s
Frontend redesign chunk 2: primitives and marks
Rewrite components/ui/* (Button, Card, Badge, PageHeader, EmptyState,
Skeleton) against the chunk-1 tokens instead of hardcoded gray-9xx classes,
and drop the remaining font-mono from label/heading text.

Add the three colour-blindness-validated encoding components from
UI_REDESIGN.md §2.3:
- components/marks/SeverityMark.tsx — glyph (filled triangle / outline
  triangle / outline circle) + optional spine + optional label, from the
  four-level severity ladder. Colour is never the only channel.
- components/marks/TypeGlyph.tsx — five stroked SVG glyphs (fire, police,
  ems, collision, other) in currentColor. Incident type is now shape, not
  hue, since five hues can't clear an all-pairs CVD gate.
- components/marks/NodeMark.tsx — diamond at four weights (filled+ring /
  filled / hollow / hollow-dashed). Green is gone from node state entirely.

lib/severity.tsx now renders through SeverityMark; SEVERITY_COLORS reads
the validated sev-moderate/sev-major tokens with routine/minor neutral.
IncidentBadges.tsx's TypeBadge is reimplemented on TypeGlyph instead of a
coloured pill.

Per UI_REDESIGN.md chunk 2.
2026-08-19 22:56:02 -04:00

43 lines
2.0 KiB
TypeScript

/**
* Shared severity ladder for calls and incidents: routine < minor < moderate < major.
* Every call/incident gets one of these four. `"unknown"` (and any other
* unrecognized value) is a legacy value still present on historical docs —
* treat it as "no severity", not as a fifth level.
*/
import type { ReactElement } from "react";
import { SeverityMark } from "@/components/marks/SeverityMark";
export type Severity = "routine" | "minor" | "moderate" | "major";
export const SEVERITY_ORDER: Record<Severity, number> = { routine: 0, minor: 1, moderate: 2, major: 3 };
export const SEVERITY_LABEL: Record<Severity, string> = { routine: "Routine", minor: "Minor", moderate: "Moderate", major: "Major" };
/**
* Validated against the dataviz all-pairs colour-blindness checker (see
* UI_REDESIGN.md §2.3). Severity is the ONLY hue channel in the whole app —
* moderate/major carry colour, routine/minor are neutral ink with no hue.
* Colour is never the sole channel: SeverityMark also carries glyph shape
* and spine thickness so the ladder survives grayscale.
*/
export const SEVERITY_COLORS: Record<Severity, string> = {
routine: "var(--ink-muted)",
minor: "var(--ink-2)",
moderate: "var(--sev-moderate)",
major: "var(--sev-major)",
};
export function isKnownSeverity(s: string | null | undefined): s is Severity {
return s === "routine" || s === "minor" || s === "moderate" || s === "major";
}
/** Legacy/unset severities rank below `routine` so a recency-sorted list never confuses them with a real (low) severity. */
export function severityRank(s: string | null | undefined): number {
return isKnownSeverity(s) ? SEVERITY_ORDER[s] : -1;
}
/** Renders the full severity mark (glyph + word chip). Use `<SeverityMark>` directly for more control (spine, size, label-off). */
export function severityBadge(severity: string | null | undefined): ReactElement | null {
if (!isKnownSeverity(severity)) return null;
return <SeverityMark severity={severity} showLabel />;
}