mitai-jinkendo/frontend/src/components/Toast.jsx

96 lines
2.2 KiB
React
Raw Normal View History

import { useEffect } from 'react'
/**
* Toast Notification Component
*
* Auto-closing notification that appears at the top of the screen
*
* Props:
* - message: string
* - type: 'success' | 'error' | 'warning' | 'info'
* - duration: number (ms, default 3000)
* - onClose: callback when toast closes
*/
export function Toast({ message, type = 'info', duration = 3000, onClose }) {
useEffect(() => {
const timer = setTimeout(() => {
if (onClose) onClose()
}, duration)
return () => clearTimeout(timer)
}, [duration, onClose])
const styles = {
success: {
background: '#4CAF50',
color: 'white',
icon: '✅'
},
error: {
background: 'var(--danger)',
color: 'white',
icon: '❌'
},
warning: {
background: '#FFC107',
color: '#856404',
icon: '⚠️'
},
info: {
background: 'var(--accent)',
color: 'white',
icon: 'ℹ️'
}
}
const style = styles[type] || styles.info
return (
<div
style={{
position: 'fixed',
top: '80px',
left: '50%',
transform: 'translateX(-50%)',
background: style.background,
color: style.color,
padding: '12px 24px',
borderRadius: '8px',
boxShadow: '0 4px 12px rgba(0,0,0,0.3)',
zIndex: 10000,
display: 'flex',
alignItems: 'center',
gap: '8px',
fontSize: '14px',
fontWeight: 500,
minWidth: '300px',
maxWidth: '600px',
animation: 'slideDown 0.3s ease-out'
}}
onClick={onClose}
>
<span style={{ fontSize: '18px' }}>{style.icon}</span>
<span>{message}</span>
</div>
)
}
// Add animation CSS if not already in global styles
const styleElement = document.createElement('style')
styleElement.textContent = `
@keyframes slideDown {
from {
opacity: 0;
transform: translateX(-50%) translateY(-20px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
`
if (!document.querySelector('style[data-toast-styles]')) {
styleElement.setAttribute('data-toast-styles', 'true')
document.head.appendChild(styleElement)
}