A DEFCON-style readiness indicator with five stacked level bars, a restrained breathing glow that only appears at escalated conditions, and reduced-motion-safe color-driven state.
npx shadcn@latest add @paragon/alert-condition"use client";
import * as React from "react";
import { useReducedMotion } from "motion/react";
import { cn } from "@/lib/utils";
export type ConditionLevel = 5 | 4 | 3 | 2 | 1;
interface LevelSpec {
name: string;
color: string;
posture: string;
}
const LEVELS: Record<ConditionLevel, LevelSpec> = {
5: { name: "COND 5", color: "var(--color-success)", posture: "Normal readiness" },
4: { name: "COND 4", color: "oklch(0.72 0.15 130)", posture: "Increased watch" },
3: { name: "COND 3", color: "var(--color-warning)", posture: "Elevated — forces ready" },
2: { name: "COND 2", color: "oklch(0.66 0.2 45)", posture: "Further escalation" },
1: { name: "COND 1", color: "var(--color-destructive)", posture: "Maximum readiness" },
};
export interface AlertConditionProps extends React.ComponentProps<"div"> {
/** Current condition, 5 (normal) → 1 (maximum). */
level?: ConditionLevel;
/** Short mission / sector label. */
sector?: string;
static?: boolean;
}
/**
* A DEFCON-style readiness indicator. Five stacked bars fill up to the active
* level; only the active bar carries a restrained breathing glow, and only
* when the condition is 2 or 1 (escalated). The glow is a looping opacity
* pulse — no movement — and is removed entirely under reduced motion, leaving
* the color to carry the state. Level changes color-transition, never restart.
*/
export function AlertCondition({
level = 4,
sector = "SECTOR-7 / DEMO",
static: isStatic = false,
className,
...props
}: AlertConditionProps) {
const reduced = useReducedMotion();
const spec = LEVELS[level];
const escalated = level <= 2;
const pulse = escalated && !isStatic && !reduced;
return (
<div
className={cn(
"w-full max-w-xs rounded-xl bg-card p-4 text-card-foreground shadow-border",
className,
)}
{...props}
>
<style href="paragon-alert-condition" precedence="paragon">{`
@keyframes pg-cond-pulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 0.9; } }
.pg-cond-glow { animation: pg-cond-pulse 1.8s var(--ease-in-out) infinite; }
@media (prefers-reduced-motion: reduce) { .pg-cond-glow { animation: none; opacity: 0.6; } }
`}</style>
<div className="flex items-center justify-between">
<span className="text-[10px] uppercase tracking-wider text-muted-foreground">
Alert Condition
</span>
<span className="font-mono text-[10px] text-muted-foreground">
{sector}
</span>
</div>
<div className="mt-3 flex items-stretch gap-3">
<div className="flex flex-1 flex-col-reverse gap-1.5">
{([5, 4, 3, 2, 1] as ConditionLevel[]).map((l) => {
const active = l >= level; // bars from top(1) down to current fill
const isCurrent = l === level;
const c = LEVELS[l].color;
return (
<div key={l} className="relative flex items-center gap-2">
<span
className={cn(
"w-8 shrink-0 text-right font-mono text-[10px] tabular-nums transition-colors duration-(--duration-base)",
isCurrent ? "text-foreground" : "text-muted-foreground/60",
)}
>
{l}
</span>
<div className="relative h-4 flex-1 overflow-hidden rounded-sm bg-secondary">
<div
className="absolute inset-0 transition-[opacity,background-color] duration-(--duration-base) ease-(--ease-out)"
style={{
backgroundColor: c,
opacity: active ? (isCurrent ? 1 : 0.55) : 0.08,
}}
/>
{isCurrent && pulse && (
<div
aria-hidden
className="pg-cond-glow pointer-events-none absolute inset-0"
style={{ backgroundColor: c }}
/>
)}
</div>
</div>
);
})}
</div>
</div>
<div className="mt-3 flex items-center gap-2 border-t border-border pt-3">
<span
className="size-2.5 shrink-0 rounded-full transition-colors duration-(--duration-base)"
style={{ backgroundColor: spec.color }}
/>
<div className="min-w-0">
<p
className="font-mono text-sm font-semibold transition-colors duration-(--duration-base)"
style={{ color: spec.color }}
>
{spec.name}
</p>
<p className="truncate text-xs text-muted-foreground">{spec.posture}</p>
</div>
</div>
</div>
);
}