Loading...
Loading...
A dismissible banner alert with icon, message, and close button. Supports info, success, warning, and error variants.
import { useState } from "react";
type AlertVariant = "info" | "success" | "warning" | "error";
interface BannerAlertProps {
variant?: AlertVariant;
message: string;
}
const variantStyles: Record<AlertVariant, string> = {
info: "bg-blue-50 border-blue-200 text-blue-800",
success: "bg-emerald-50 border-emerald-200 text-emerald-800",
warning: "bg-amber-50 border-amber-200 text-amber-800",
error: "bg-red-50 border-red-200 text-red-800",
};
const variantIcons: Record<AlertVariant, string> = {
info: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z",
success: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z",
warning: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z",
error: "M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z",
};
export function BannerAlert({ variant = "info", message }: BannerAlertProps) {
const [visible, setVisible] = useState(true);
if (!visible) return null;
return (
<div className={`flex items-start gap-3 px-5 py-4 border rounded-xl shadow-sm ${variantStyles[variant]}`} role="alert">
<svg className="w-5 h-5 mt-0.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d={variantIcons[variant]} />
</svg>
<p className="text-sm font-medium flex-1">{message}</p>
<button
onClick={() => setVisible(false)}
className="shrink-0 p-0.5 rounded-md opacity-60 hover:opacity-100 transition-opacity"
aria-label="Dismiss"
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
);
}