.toast-container {
max-width: 1200px;
margin: 0 auto;
padding: 32px 24px;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: #f8fafc;
min-height: 100vh;
position: relative;
}
.toast-header {
text-align: center;
margin-bottom: 40px;
}
.toast-title {
font-size: 36px;
font-weight: 700;
color: #1a202c;
margin: 0 0 12px 0;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.toast-subtitle {
font-size: 16px;
color: #6b7280;
margin: 0;
}
.toast-demo {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 32px;
background: white;
border-radius: 16px;
padding: 32px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.demo-controls h2,
.demo-preview h3 {
font-size: 24px;
font-weight: 600;
color: #1a202c;
margin: 0 0 24px 0;
}
.control-buttons {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 12px;
margin-bottom: 32px;
}
.demo-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px 16px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
color: white;
}
.demo-btn svg {
width: 16px;
height: 16px;
}
.demo-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.demo-btn.success {
background: #10b981;
}
.demo-btn.success:hover {
background: #059669;
}
.demo-btn.error {
background: #ef4444;
}
.demo-btn.error:hover {
background: #dc2626;
}
.demo-btn.warning {
background: #f59e0b;
}
.demo-btn.warning:hover {
background: #d97706;
}
.demo-btn.info {
background: #3b82f6;
}
.demo-btn.info:hover {
background: #2563eb;
}
.demo-btn.loading {
background: #8b5cf6;
}
.demo-btn.loading:hover {
background: #7c3aed;
}
.demo-options {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 32px;
}
.option-group {
display: flex;
align-items: center;
gap: 12px;
}
.option-group label {
font-size: 14px;
font-weight: 500;
color: #374151;
min-width: 80px;
}
.option-group select {
flex: 1;
padding: 8px 12px;
border: 1px solid #d1d5db;
border-radius: 6px;
font-size: 14px;
background: white;
}
.option-group input[type="checkbox"] {
margin-right: 8px;
}
.bulk-actions {
display: flex;
gap: 12px;
}
.action-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 16px;
background: #6b7280;
color: white;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
.action-btn:hover {
background: #4b5563;
transform: translateY(-1px);
}
.action-btn svg {
width: 16px;
height: 16px;
}
.demo-preview p {
color: #6b7280;
line-height: 1.6;
margin-bottom: 24px;
}
.preview-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.stat-item {
text-align: center;
padding: 16px;
background: #f8fafc;
border-radius: 8px;
}
.stat-number {
display: block;
font-size: 24px;
font-weight: 700;
color: #1a202c;
margin-bottom: 4px;
}
.stat-label {
font-size: 12px;
color: #6b7280;
font-weight: 500;
}
/* Toast Areas */
.toast-area {
position: fixed;
z-index: 1000;
pointer-events: none;
display: flex;
flex-direction: column;
gap: 12px;
max-width: 400px;
width: 100%;
}
.toast-area.top-right {
top: 20px;
right: 20px;
}
.toast-area.top-left {
top: 20px;
left: 20px;
}
.toast-area.bottom-right {
bottom: 20px;
right: 20px;
flex-direction: column-reverse;
}
.toast-area.bottom-left {
bottom: 20px;
left: 20px;
flex-direction: column-reverse;
}
.toast-area.top-center {
top: 20px;
left: 50%;
transform: translateX(-50%);
align-items: center;
}
.toast-area.bottom-center {
bottom: 20px;
left: 50%;
transform: translateX(-50%);
align-items: center;
flex-direction: column-reverse;
}
/* Toast Styles */
.toast {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 16px;
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
border-left: 4px solid;
pointer-events: auto;
position: relative;
overflow: hidden;
max-width: 400px;
min-width: 300px;
}
.toast.success {
border-left-color: #10b981;
}
.toast.error {
border-left-color: #ef4444;
}
.toast.warning {
border-left-color: #f59e0b;
}
.toast.info {
border-left-color: #3b82f6;
}
.toast.loading {
border-left-color: #8b5cf6;
}
.toast-icon {
width: 20px;
height: 20px;
flex-shrink: 0;
margin-top: 2px;
}
.toast.success .toast-icon {
color: #10b981;
}
.toast.error .toast-icon {
color: #ef4444;
}
.toast.warning .toast-icon {
color: #f59e0b;
}
.toast.info .toast-icon {
color: #3b82f6;
}
.toast.loading .toast-icon {
color: #8b5cf6;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.toast-content {
flex: 1;
min-width: 0;
}
.toast-title {
font-size: 14px;
font-weight: 600;
color: #1a202c;
margin: 0 0 4px 0;
}
.toast-message {
font-size: 13px;
color: #6b7280;
margin: 0;
line-height: 1.4;
}
.toast-close {
width: 20px;
height: 20px;
background: none;
border: none;
color: #9ca3af;
cursor: pointer;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: all 0.2s ease;
flex-shrink: 0;
}
.toast-close:hover {
background: #f3f4f6;
color: #6b7280;
}
.toast-close svg {
width: 14px;
height: 14px;
}
.toast-progress {
position: absolute;
bottom: 0;
left: 0;
height: 3px;
background: rgba(0, 0, 0, 0.1);
transition: width linear;
}
.toast.success .toast-progress {
background: #10b981;
}
.toast.error .toast-progress {
background: #ef4444;
}
.toast.warning .toast-progress {
background: #f59e0b;
}
.toast.info .toast-progress {
background: #3b82f6;
}
.toast.loading .toast-progress {
background: #8b5cf6;
}
/* Toast Animations */
.toast-enter {
opacity: 0;
transform: translateX(100%);
}
.toast-enter-active {
opacity: 1;
transform: translateX(0);
transition: all 0.3s ease;
}
.toast-exit {
opacity: 1;
transform: translateX(0);
}
.toast-exit-active {
opacity: 0;
transform: translateX(100%);
transition: all 0.3s ease;
}
/* Left side animations */
.toast-area.top-left .toast-enter,
.toast-area.bottom-left .toast-enter {
transform: translateX(-100%);
}
.toast-area.top-left .toast-exit-active,
.toast-area.bottom-left .toast-exit-active {
transform: translateX(-100%);
}
/* Center animations */
.toast-area.top-center .toast-enter,
.toast-area.bottom-center .toast-enter {
transform: translateY(-100%);
}
.toast-area.top-center .toast-exit-active,
.toast-area.bottom-center .toast-exit-active {
transform: translateY(-100%);
}
/* Responsive Design */
@media (max-width: 768px) {
.toast-container {
padding: 24px 16px;
}
.toast-title {
font-size: 28px;
}
.toast-demo {
grid-template-columns: 1fr;
gap: 24px;
padding: 24px 16px;
}
.control-buttons {
grid-template-columns: repeat(2, 1fr);
}
.toast-area {
left: 16px !important;
right: 16px !important;
max-width: none;
}
.toast-area.top-center,
.toast-area.bottom-center {
transform: none;
}
.toast {
min-width: 0;
max-width: none;
}
}
@media (max-width: 480px) {
.control-buttons {
grid-template-columns: 1fr;
}
.demo-options {
gap: 12px;
}
.option-group {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
.option-group label {
min-width: auto;
}
.option-group select {
width: 100%;
}
.bulk-actions {
flex-direction: column;
}
.preview-stats {
grid-template-columns: 1fr;
}
}
document.addEventListener('DOMContentLoaded', () => {
const demoButtons = document.querySelectorAll('.demo-btn');
const positionSelect = document.getElementById('positionSelect');
const durationSelect = document.getElementById('durationSelect');
const soundEnabled = document.getElementById('soundEnabled');
const animationEnabled = document.getElementById('animationEnabled');
const showMultipleBtn = document.getElementById('showMultiple');
const clearAllBtn = document.getElementById('clearAll');
const totalShownEl = document.getElementById('totalShown');
const currentActiveEl = document.getElementById('currentActive');
const autoDismissedEl = document.getElementById('autoDismissed');
let toastCounter = 0;
let totalShown = 0;
let autoDismissed = 0;
let activeToasts = new Set();
// Toast messages for different types
const toastMessages = {
success: [
{ title: 'Success!', message: 'Your action was completed successfully.' },
{ title: 'Saved!', message: 'Your changes have been saved.' },
{ title: 'Upload Complete', message: 'File uploaded successfully.' },
{ title: 'Payment Processed', message: 'Your payment was processed successfully.' }
],
error: [
{ title: 'Error!', message: 'Something went wrong. Please try again.' },
{ title: 'Upload Failed', message: 'Failed to upload file. Check your connection.' },
{ title: 'Validation Error', message: 'Please check your input and try again.' },
{ title: 'Network Error', message: 'Unable to connect to server.' }
],
warning: [
{ title: 'Warning!', message: 'This action cannot be undone.' },
{ title: 'Storage Full', message: 'You are running out of storage space.' },
{ title: 'Session Expiring', message: 'Your session will expire in 5 minutes.' },
{ title: 'Unsaved Changes', message: 'You have unsaved changes.' }
],
info: [
{ title: 'Info', message: 'Here is some useful information for you.' },
{ title: 'New Feature', message: 'Check out our new feature in the settings.' },
{ title: 'Maintenance', message: 'Scheduled maintenance tonight at 2 AM.' },
{ title: 'Update Available', message: 'A new version is available for download.' }
],
loading: [
{ title: 'Loading...', message: 'Please wait while we process your request.' },
{ title: 'Uploading...', message: 'Uploading your files, please wait.' },
{ title: 'Processing...', message: 'Processing payment, do not refresh.' },
{ title: 'Syncing...', message: 'Syncing your data across devices.' }
]
};
// Toast icons
const toastIcons = {
success: '<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>',
error: '<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>',
warning: '<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>',
info: '<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>',
loading: '<path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6z"/>'
};
// Create toast element
function createToast(type, title, message, duration) {
const toastId = `toast-${++toastCounter}`;
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.id = toastId;
const progressBar = duration > 0 ? `<div class="toast-progress" style="width: 100%;"></div>` : '';
toast.innerHTML = `
<svg class="toast-icon" viewBox="0 0 24 24" fill="currentColor">
${toastIcons[type]}
</svg>
<div class="toast-content">
<div class="toast-title">${title}</div>
<div class="toast-message">${message}</div>
</div>
<button class="toast-close" aria-label="Close notification">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
</svg>
</button>
${progressBar}
`;
return { toast, toastId };
}
// Show toast
function showToast(type, customTitle = null, customMessage = null, customDuration = null) {
const position = positionSelect.value;
const duration = customDuration !== null ? customDuration : parseInt(durationSelect.value);
const enableAnimation = animationEnabled.checked;
const enableSound = soundEnabled.checked;
// Get random message for type
const messages = toastMessages[type];
const randomMessage = messages[Math.floor(Math.random() * messages.length)];
const title = customTitle || randomMessage.title;
const message = customMessage || randomMessage.message;
const { toast, toastId } = createToast(type, title, message, duration);
const container = document.getElementById(`toast-${position}`);
// Add to active toasts
activeToasts.add(toastId);
totalShown++;
updateStats();
// Play sound if enabled
if (enableSound) {
playNotificationSound(type);
}
// Add animation classes
if (enableAnimation) {
toast.classList.add('toast-enter');
}
container.appendChild(toast);
// Trigger enter animation
if (enableAnimation) {
requestAnimationFrame(() => {
toast.classList.remove('toast-enter');
toast.classList.add('toast-enter-active');
});
}
// Set up close button
const closeBtn = toast.querySelector('.toast-close');
closeBtn.addEventListener('click', () => {
dismissToast(toastId);
});
// Set up auto-dismiss
if (duration > 0) {
const progressBar = toast.querySelector('.toast-progress');
if (progressBar) {
progressBar.style.transition = `width ${duration}ms linear`;
requestAnimationFrame(() => {
progressBar.style.width = '0%';
});
}
setTimeout(() => {
if (activeToasts.has(toastId)) {
autoDismissed++;
dismissToast(toastId);
}
}, duration);
}
// Add hover pause for auto-dismiss
if (duration > 0) {
let remainingTime = duration;
let startTime = Date.now();
let timeoutId;
const pauseTimer = () => {
clearTimeout(timeoutId);
remainingTime -= Date.now() - startTime;
const progressBar = toast.querySelector('.toast-progress');
if (progressBar) {
progressBar.style.transition = 'none';
}
};
const resumeTimer = () => {
startTime = Date.now();
const progressBar = toast.querySelector('.toast-progress');
if (progressBar) {
progressBar.style.transition = `width ${remainingTime}ms linear`;
progressBar.style.width = '0%';
}
timeoutId = setTimeout(() => {
if (activeToasts.has(toastId)) {
autoDismissed++;
dismissToast(toastId);
}
}, remainingTime);
};
toast.addEventListener('mouseenter', pauseTimer);
toast.addEventListener('mouseleave', resumeTimer);
}
}
// Dismiss toast
function dismissToast(toastId) {
const toast = document.getElementById(toastId);
if (!toast || !activeToasts.has(toastId)) return;
activeToasts.delete(toastId);
updateStats();
const enableAnimation = animationEnabled.checked;
if (enableAnimation) {
toast.classList.remove('toast-enter-active');
toast.classList.add('toast-exit', 'toast-exit-active');
setTimeout(() => {
if (toast.parentNode) {
toast.parentNode.removeChild(toast);
}
}, 300);
} else {
if (toast.parentNode) {
toast.parentNode.removeChild(toast);
}
}
}
// Play notification sound
function playNotificationSound(type) {
// Create audio context for sound generation
try {
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
// Different frequencies for different types
const frequencies = {
success: [523.25, 659.25, 783.99], // C5, E5, G5
error: [220, 185], // A3, F#3
warning: [440, 554.37], // A4, C#5
info: [523.25, 659.25], // C5, E5
loading: [440] // A4
};
const freqs = frequencies[type] || [440];
let currentFreq = 0;
function playNote() {
if (currentFreq < freqs.length) {
oscillator.frequency.setValueAtTime(freqs[currentFreq], audioContext.currentTime);
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1);
currentFreq++;
if (currentFreq < freqs.length) {
setTimeout(playNote, 100);
}
}
}
oscillator.start();
playNote();
oscillator.stop(audioContext.currentTime + 0.3);
} catch (e) {
// Fallback: no sound if audio context fails
console.log('Audio not supported');
}
}
// Update statistics
function updateStats() {
totalShownEl.textContent = totalShown;
currentActiveEl.textContent = activeToasts.size;
autoDismissedEl.textContent = autoDismissed;
}
// Show multiple toasts
function showMultipleToasts() {
const types = ['success', 'error', 'warning', 'info', 'loading'];
types.forEach((type, index) => {
setTimeout(() => {
showToast(type);
}, index * 200);
});
}
// Clear all toasts
function clearAllToasts() {
const allToasts = Array.from(activeToasts);
allToasts.forEach(toastId => {
dismissToast(toastId);
});
}
// Event listeners
demoButtons.forEach(btn => {
btn.addEventListener('click', () => {
const type = btn.dataset.type;
showToast(type);
});
});
showMultipleBtn.addEventListener('click', showMultipleToasts);
clearAllBtn.addEventListener('click', clearAllToasts);
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey) {
switch (e.key) {
case '1':
e.preventDefault();
showToast('success');
break;
case '2':
e.preventDefault();
showToast('error');
break;
case '3':
e.preventDefault();
showToast('warning');
break;
case '4':
e.preventDefault();
showToast('info');
break;
case '5':
e.preventDefault();
showToast('loading');
break;
case 'Escape':
e.preventDefault();
clearAllToasts();
break;
}
}
});
// Initialize stats
updateStats();
// Demo: Show welcome toast
setTimeout(() => {
showToast('info', 'Welcome!', 'Try the different notification types above. Use Ctrl+1-5 for quick access.');
}, 1000);
});