Spaces:
Sleeping
Sleeping
| import { cn } from "@/lib/utils"; | |
| type StatusType = "active" | "waiting" | "issue"; | |
| interface StatusIndicatorProps { | |
| status: StatusType; | |
| size?: "sm" | "md" | "lg"; | |
| showLabel?: boolean; | |
| className?: string; | |
| } | |
| const statusConfig: Record<StatusType, { color: string; label: string; pulseColor: string }> = { | |
| active: { | |
| color: "bg-emerald-500", | |
| label: "Active", | |
| pulseColor: "bg-emerald-400", | |
| }, | |
| waiting: { | |
| color: "bg-amber-500", | |
| label: "Waiting", | |
| pulseColor: "bg-amber-400", | |
| }, | |
| issue: { | |
| color: "bg-red-500", | |
| label: "Issue", | |
| pulseColor: "bg-red-400", | |
| }, | |
| }; | |
| const sizeConfig = { | |
| sm: "h-2 w-2", | |
| md: "h-3 w-3", | |
| lg: "h-4 w-4", | |
| }; | |
| export function StatusIndicator({ status, size = "md", showLabel = false, className }: StatusIndicatorProps) { | |
| const config = statusConfig[status]; | |
| const sizeClass = sizeConfig[size]; | |
| return ( | |
| <div className={cn("flex items-center gap-2", className)} role="status" aria-label={`Status: ${config.label}`} data-testid={`status-indicator-${status}`}> | |
| <span className="relative flex"> | |
| {status === "active" || status === "issue" ? ( | |
| <span | |
| className={cn( | |
| "absolute inline-flex h-full w-full animate-ping rounded-full opacity-75", | |
| config.pulseColor | |
| )} | |
| /> | |
| ) : null} | |
| <span className={cn("relative inline-flex rounded-full", sizeClass, config.color)} /> | |
| </span> | |
| {showLabel && ( | |
| <span className="text-xs font-medium text-muted-foreground">{config.label}</span> | |
| )} | |
| </div> | |
| ); | |
| } | |