Retour au catalogue
Banners Alert
Banniere d'alerte systeme. 4 variantes : info, success, warning, error. Avec icone contextuelle.
bannerssimple Both Responsive a11y
corporateuniversalstacked
Theme
"use client";
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { X, Info, CheckCircle, AlertTriangle, XCircle } from "lucide-react";
type AlertType = "info" | "success" | "warning" | "error";
interface BannersAlertProps {
text?: string;
type?: AlertType;
linkLabel?: string;
linkUrl?: string;
dismissible?: boolean;
}
const alertConfig: Record<
AlertType,
{ bg: string; border: string; text: string; icon: typeof Info }
> = {
info: {
bg: "rgba(59, 130, 246, 0.08)",
border: "rgba(59, 130, 246, 0.2)",
text: "rgb(59, 130, 246)",
icon: Info,
},
success: {
bg: "rgba(34, 197, 94, 0.08)",
border: "rgba(34, 197, 94, 0.2)",
text: "rgb(34, 197, 94)",
icon: CheckCircle,
},
warning: {
bg: "rgba(234, 179, 8, 0.08)",
border: "rgba(234, 179, 8, 0.2)",
text: "rgb(180, 140, 10)",
icon: AlertTriangle,
},
error: {
bg: "rgba(239, 68, 68, 0.08)",
border: "rgba(239, 68, 68, 0.2)",
text: "rgb(239, 68, 68)",
icon: XCircle,
},
};
export default function BannersAlert({
text = "Maintenance prevue prochainement.",
type = "info",
linkLabel,
linkUrl,
dismissible = true,
}: BannersAlertProps) {
const [visible, setVisible] = useState(true);
const config = alertConfig[type];
const Icon = config.icon;
return (
<AnimatePresence>
{visible && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: "auto", opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.3 }}
className="overflow-hidden"
>
<div
className="mx-auto"
style={{
maxWidth: "var(--container-max-width)",
paddingLeft: "var(--container-padding-x)",
paddingRight: "var(--container-padding-x)",
paddingTop: "0.75rem",
paddingBottom: "0.75rem",
}}
>
<div
className="flex items-center gap-3 px-4 py-3 rounded-xl"
style={{
backgroundColor: config.bg,
border: `1px solid ${config.border}`,
}}
>
<Icon
className="h-4 w-4 shrink-0"
style={{ color: config.text }}
/>
<p className="text-sm flex-1" style={{ color: config.text }}>
{text}
{linkLabel && (
<a
href={linkUrl}
className="ml-2 font-semibold underline underline-offset-2"
style={{ color: config.text }}
>
{linkLabel}
</a>
)}
</p>
{dismissible && (
<button
onClick={() => setVisible(false)}
className="w-6 h-6 flex items-center justify-center cursor-pointer rounded-md transition-opacity hover:opacity-60 shrink-0"
style={{ color: config.text }}
aria-label="Fermer"
>
<X className="h-3.5 w-3.5" />
</button>
)}
</div>
</div>
</motion.div>
)}
</AnimatePresence>
);
}