- 添加4个数据库索引提升查询性能 - 启用ESLint并配置React支持 - 修复ESLint错误(未使用的导入和状态) - 简化Toast组件UI样式 - 移除重复文件(server.js.backup) - 清理.gitignore中的.next目录 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
56 lines
1.6 KiB
JavaScript
56 lines
1.6 KiB
JavaScript
import { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';
|
|
|
|
const ToastContext = createContext(null);
|
|
|
|
export function ToastProvider({ children }) {
|
|
const [toasts, setToasts] = useState([]);
|
|
const timers = useRef(new Map());
|
|
|
|
const removeToast = useCallback((id) => {
|
|
const timer = timers.current.get(id);
|
|
if (timer) {
|
|
clearTimeout(timer);
|
|
timers.current.delete(id);
|
|
}
|
|
setToasts((current) => current.filter((toast) => toast.id !== id));
|
|
}, []);
|
|
|
|
const showToast = useCallback((message, options = {}) => {
|
|
const id = `${Date.now()}-${Math.random()}`;
|
|
const toast = {
|
|
id,
|
|
message,
|
|
tone: options.tone || 'info',
|
|
};
|
|
|
|
setToasts((current) => [...current, toast]);
|
|
const duration = options.duration ?? 2600;
|
|
const timer = setTimeout(() => removeToast(id), duration);
|
|
timers.current.set(id, timer);
|
|
return id;
|
|
}, [removeToast]);
|
|
|
|
const value = useMemo(() => ({ showToast, removeToast }), [showToast, removeToast]);
|
|
|
|
return (
|
|
<ToastContext.Provider value={value}>
|
|
{children}
|
|
<div className="toast-stack" aria-live="polite" aria-atomic="true">
|
|
{toasts.map((toast) => (
|
|
<div key={toast.id} className={`toast toast--${toast.tone}`}>
|
|
<span className="toast__message">{toast.message}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</ToastContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useToast() {
|
|
const context = useContext(ToastContext);
|
|
if (!context) {
|
|
throw new Error('useToast must be used within ToastProvider');
|
|
}
|
|
return context;
|
|
}
|