初始化项目
This commit is contained in:
64
components/Toast.tsx
Normal file
64
components/Toast.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { CheckCircle, AlertCircle, X } from 'lucide-react';
|
||||
|
||||
export interface ToastMessage {
|
||||
id: string;
|
||||
type: 'success' | 'error' | 'info';
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface ToastProps {
|
||||
toasts: ToastMessage[];
|
||||
onRemove: (id: string) => void;
|
||||
}
|
||||
|
||||
const ToastContainer: React.FC<ToastProps> = ({ toasts, onRemove }) => {
|
||||
return (
|
||||
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 z-[100] flex flex-col gap-2 w-full max-w-md px-4">
|
||||
{toasts.map((toast) => (
|
||||
<ToastItem key={toast.id} toast={toast} onRemove={onRemove} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ToastItem: React.FC<{ toast: ToastMessage; onRemove: (id: string) => void }> = ({ toast, onRemove }) => {
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
onRemove(toast.id);
|
||||
}, 3000);
|
||||
return () => clearTimeout(timer);
|
||||
}, [toast.id, onRemove]);
|
||||
|
||||
const getStyles = () => {
|
||||
switch (toast.type) {
|
||||
case 'success':
|
||||
return 'bg-emerald-50 border-emerald-100 text-emerald-700';
|
||||
case 'error':
|
||||
return 'bg-red-50 border-red-100 text-red-700';
|
||||
default:
|
||||
return 'bg-indigo-50 border-indigo-100 text-indigo-700';
|
||||
}
|
||||
};
|
||||
|
||||
const getIcon = () => {
|
||||
switch (toast.type) {
|
||||
case 'success': return <CheckCircle size={20} className="text-emerald-500" />;
|
||||
case 'error': return <AlertCircle size={20} className="text-red-500" />;
|
||||
default: return <AlertCircle size={20} className="text-indigo-500" />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`flex items-center gap-3 p-4 rounded-2xl border shadow-lg animate-fade-in-up ${getStyles()}`}>
|
||||
{getIcon()}
|
||||
<p className="text-sm font-bold flex-1">{toast.message}</p>
|
||||
<button onClick={() => onRemove(toast.id)} className="opacity-50 hover:opacity-100">
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ToastContainer;
|
||||
Reference in New Issue
Block a user