feedback · toast · notification
Pile de notifications flottantes (succès, info, avertissement, erreur), chacune avec un bouton de fermeture fonctionnel.
<style>
.bn-toast-stack {
display: flex;
flex-direction: column;
gap: 0.6rem;
max-width: 340px;
padding: 2rem;
font-family: 'Inter', sans-serif;
background: #0B0F10;
}
.bn-toast {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 0.9rem 1rem;
border-radius: 8px;
border: 1px solid;
background: rgba(255, 255, 255, 0.02);
transition: opacity 0.25s ease, transform 0.25s ease;
}
.bn-toast.is-closing {
opacity: 0;
transform: translateX(20px);
}
.bn-toast__icon {
flex-shrink: 0;
width: 22px;
height: 22px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.7rem;
}
.bn-toast__body {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.1rem;
}
.bn-toast__body strong {
color: #E6E4DD;
font-size: 0.85rem;
}
.bn-toast__body span {
color: #979793;
font-size: 0.78rem;
}
.bn-toast__close {
flex-shrink: 0;
background: none;
border: none;
color: #5C6160;
cursor: pointer;
font-size: 0.7rem;
}
.bn-toast__close:hover {
color: #E6E4DD;
}
/* --- Variantes de couleur --- */
.bn-toast--success { border-color: rgba(63, 185, 80, 0.35); }
.bn-toast--success .bn-toast__icon { background: rgba(63, 185, 80, 0.15); color: #3FB950; }
.bn-toast--info { border-color: rgba(96, 165, 250, 0.35); }
.bn-toast--info .bn-toast__icon { background: rgba(96, 165, 250, 0.15); color: #60A5FA; }
.bn-toast--warning { border-color: rgba(245, 197, 24, 0.35); }
.bn-toast--warning .bn-toast__icon { background: rgba(245, 197, 24, 0.15); color: #F5C518; }
.bn-toast--error { border-color: rgba(229, 72, 77, 0.35); }
.bn-toast--error .bn-toast__icon { background: rgba(229, 72, 77, 0.15); color: #E5484D; }
</style>
<div class="bn-toast-stack" data-fx-root>
<div class="bn-toast bn-toast--success">
<span class="bn-toast__icon">✓</span>
<div class="bn-toast__body">
<strong>Projet enregistré</strong>
<span>Votre projet a bien été enregistré.</span>
</div>
<button type="button" class="bn-toast__close" aria-label="Fermer">✕</button>
</div>
<div class="bn-toast bn-toast--info">
<span class="bn-toast__icon">i</span>
<div class="bn-toast__body">
<strong>Mise à jour disponible</strong>
<span>Une nouvelle version est disponible.</span>
</div>
<button type="button" class="bn-toast__close" aria-label="Fermer">✕</button>
</div>
<div class="bn-toast bn-toast--warning">
<span class="bn-toast__icon">!</span>
<div class="bn-toast__body">
<strong>Modification non enregistrée</strong>
<span>Vos changements seront perdus.</span>
</div>
<button type="button" class="bn-toast__close" aria-label="Fermer">✕</button>
</div>
<div class="bn-toast bn-toast--error">
<span class="bn-toast__icon">✕</span>
<div class="bn-toast__body">
<strong>Erreur de connexion</strong>
<span>Impossible de se connecter au serveur.</span>
</div>
<button type="button" class="bn-toast__close" aria-label="Fermer">✕</button>
</div>
</div>
<script>
/* ==========================================================
TOAST / NOTIFICATION
Chaque bouton "✕" fait disparaître SA notification (fondu +
léger déplacement) puis la retire du DOM.
========================================================== */
(function () {
const root = document.querySelector('.bn-toast-stack[data-fx-root]');
if (!root) return;
root.querySelectorAll('.bn-toast__close').forEach((btn) => {
btn.addEventListener('click', () => {
const toast = btn.closest('.bn-toast');
toast.classList.add('is-closing');
toast.addEventListener('transitionend', () => toast.remove(), { once: true });
});
});
})();
</script>