Retour au catalogue

Banner Floating

Banniere flottante en bas de page avec animation slide-up et bouton de fermeture.

bannerssimple Both Responsive a11y
minimaluniversalstacked
Theme
"use client";

import { useState } from "react";
import { X, ArrowRight, Bell } from "lucide-react";

interface BannerFloatingProps {
  text?: string;
  linkLabel?: string;
  linkUrl?: string;
  dismissible?: boolean;
}

export default function BannerFloating({
  text = "Mise a jour importante : de nouvelles fonctionnalites sont disponibles.",
  linkLabel = "Decouvrir",
  linkUrl = "#",
  dismissible = true,
}: BannerFloatingProps) {
  const [visible, setVisible] = useState(true);

  if (!visible) return null;

  return (
    <div className="fixed bottom-6 left-1/2 z-50 w-[calc(100%-3rem)] max-w-xl"
      style={{
        transform: "translateX(-50%)",
        animation: "banner-float-in 0.5s cubic-bezier(0.16,1,0.3,1)",
      }}
    >
      <div
        className="flex items-center gap-3 px-5 py-3.5 rounded-2xl shadow-2xl"
        style={{
          background: "var(--color-background-card)",
          border: "1px solid var(--color-border)",
          backdropFilter: "blur(12px)",
        }}
      >
        <div
          className="w-9 h-9 rounded-xl flex items-center justify-center shrink-0"
          style={{ background: "var(--color-accent-subtle)" }}
        >
          <Bell size={16} style={{ color: "var(--color-accent)" }} />
        </div>

        <div className="flex-1 min-w-0">
          <p
            className="text-sm font-medium leading-snug"
            style={{ color: "var(--color-foreground)" }}
          >
            {text}
          </p>
        </div>

        {linkLabel && (
          <a
            href={linkUrl}
            className="flex items-center gap-1 text-sm font-semibold whitespace-nowrap shrink-0 transition-opacity duration-200 hover:opacity-80"
            style={{ color: "var(--color-accent)" }}
          >
            {linkLabel}
            <ArrowRight size={14} />
          </a>
        )}

        {dismissible && (
          <button
            onClick={() => setVisible(false)}
            className="p-1.5 rounded-lg cursor-pointer shrink-0 transition-colors duration-150"
            style={{ color: "var(--color-foreground-light)" }}
            aria-label="Fermer"
          >
            <X size={16} />
          </button>
        )}
      </div>

      <style>{`
        @keyframes banner-float-in {
          from {
            opacity: 0;
            transform: translateX(-50%) translateY(100%);
          }
          to {
            opacity: 1;
            transform: translateX(-50%) translateY(0);
          }
        }
      `}</style>
    </div>
  );
}

Avis