Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 162x 162x 131x 31x 15x 16x 10x 6x 4x 2x 4185x 4185x | import { cn } from "../../lib/utils";
import {
STATUS_CODE_TYPE,
STATUS_INK,
STATUS_TINT,
type StatusTone,
} from "./status-ink";
/**
* A status is a PRINTED CODE, never a pill.
*
* 2px radius (`rounded-sm`), `.label` caps, status ink on its own `-light`
* tint — `.context/mockups/_base.css` §7.2. The old implementation was a
* `rounded-full` pill whose light-mode ink/tint pairs failed WCAG AA (success
* 2.07:1, warning 1.93:1, error 3.08:1, info 3.01:1, default 3.31:1); the AA
* argument and the measured ratios now live in `status-ink.ts`, next to the
* values, and are enforced by `status-ink.test.ts` against the real
* stylesheets in both palettes and both themes.
*
* Fixing it in the primitive fixes every call site at once, which is the whole
* reason the ink does not live at the call sites.
*/
type StatusVariant = StatusTone;
interface StatusBadgeProps {
status: string;
variant?: StatusVariant;
className?: string;
}
/**
* Get the appropriate variant for common status values.
*
* The word lists are unchanged from the pill implementation on purpose: this
* change is about ink and shape, and re-tagging a status (the mockup's family
* table puts `archived` in graphite rather than red) is a product decision for
* the page PRs, not a side effect of a contrast fix.
*/
function getVariantForStatus(status: string): StatusVariant {
const statusLower = status.toLowerCase();
// Success states
if (
["published", "active", "converted", "verified", "ready"].includes(
statusLower,
)
) {
return "success";
}
// Warning states
if (
["draft", "pending", "contacted", "unverified", "expired"].includes(
statusLower,
)
) {
return "warning";
}
// Error states
if (
["archived", "banned", "closed", "rejected", "failed"].includes(statusLower)
) {
return "error";
}
// Info states
if (["new", "processing"].includes(statusLower)) {
return "info";
}
return "default";
}
export function StatusBadge({ status, variant, className }: StatusBadgeProps) {
const computedVariant = variant || getVariantForStatus(status);
return (
<span
className={cn(
"inline-flex items-center gap-1 whitespace-nowrap rounded-sm px-1.5 py-0.5",
STATUS_CODE_TYPE,
STATUS_TINT[computedVariant],
STATUS_INK[computedVariant],
className,
)}
>
{status}
</span>
);
}
|