// Dependencies: react ^18, lucide-react
import React from 'react';
import {
Circle, Clock, Eye, CheckCircle2, XCircle, AlertOctagon,
} from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
function cn(...classes: (string | false | null | undefined)[]) {
return classes.filter(Boolean).join(' ');
}
export type Status =
| 'todo'
| 'in-progress'
| 'in-review'
| 'done'
| 'canceled'
| 'blocked';
type Token = {
label: string;
icon: LucideIcon;
dot: string;
iconClass: string;
bg: string;
border: string;
text: string;
};
export const STATUS_TOKENS: Record<Status, Token> = {
todo: {
label: 'Todo', icon: Circle,
dot: 'bg-zinc-400', iconClass: 'text-zinc-400',
bg: 'bg-zinc-500/10', border: 'border-zinc-500/20', text: 'text-zinc-300',
},
'in-progress': {
label: 'In Progress', icon: Clock,
dot: 'bg-amber-400', iconClass: 'text-amber-400',
bg: 'bg-amber-500/10', border: 'border-amber-500/20', text: 'text-amber-300',
},
'in-review': {
label: 'In Review', icon: Eye,
dot: 'bg-indigo-400', iconClass: 'text-indigo-400',
bg: 'bg-indigo-500/10', border: 'border-indigo-500/20', text: 'text-indigo-300',
},
done: {
label: 'Done', icon: CheckCircle2,
dot: 'bg-emerald-400', iconClass: 'text-emerald-400',
bg: 'bg-emerald-500/10', border: 'border-emerald-500/20', text: 'text-emerald-300',
},
canceled: {
label: 'Canceled', icon: XCircle,
dot: 'bg-zinc-600', iconClass: 'text-zinc-500',
bg: 'bg-zinc-700/30', border: 'border-zinc-600/40', text: 'text-zinc-500',
},
blocked: {
label: 'Blocked', icon: AlertOctagon,
dot: 'bg-red-400', iconClass: 'text-red-400',
bg: 'bg-red-500/10', border: 'border-red-500/20', text: 'text-red-300',
},
};
type Props = {
status: Status;
size?: 'sm' | 'md';
variant?: 'dot' | 'icon';
};
export function StatusBadge({ status, size = 'md', variant = 'dot' }: Props) {
const t = STATUS_TOKENS[status];
const sizeCls =
size === 'sm'
? 'px-1.5 py-0.5 text-[10px] gap-1'
: 'px-2 py-0.5 text-[11px] gap-1.5';
const dotSize = size === 'sm' ? 'w-1.5 h-1.5' : 'w-2 h-2';
const iconSize = size === 'sm' ? 'w-2.5 h-2.5' : 'w-3 h-3';
return (
<span
className={cn(
'inline-flex items-center rounded-full border font-medium whitespace-nowrap',
t.bg, t.border, t.text, sizeCls
)}
>
{variant === 'dot' ? (
<span className={cn('rounded-full shrink-0', dotSize, t.dot)} />
) : (
<t.icon className={cn('shrink-0', iconSize, t.iconClass)} />
)}
{t.label}
</span>
);
}