feat: 添加注释

This commit is contained in:
Blizzard
2026-04-01 15:29:35 +08:00
parent aef2e152dc
commit 6162c9110c
28 changed files with 1293 additions and 298 deletions
+49
View File
@@ -0,0 +1,49 @@
import { useCallback, useEffect, useRef, useState } from 'react';
export interface ToastItem {
id: number;
message: string;
type: 'success' | 'error' | 'info';
}
interface ToastProps { toasts: ToastItem[]; }
export function Toast({ toasts }: ToastProps) {
return (
<div className="fixed bottom-4 left-1/2 -translate-x-1/2 z-[100] flex flex-col gap-2 items-center pointer-events-none">
{toasts.map(t => (
<div key={t.id}
className={`px-4 py-2 rounded-xl text-[12px] font-medium shadow-xl border animate-toast-in
${t.type === 'success' ? 'bg-green-500/20 text-green-300 border-green-500/30' :
t.type === 'error' ? 'bg-red-500/20 text-red-300 border-red-500/30' :
'bg-white/10 text-white/70 border-white/15'}`}>
{t.type === 'success' ? '✓ ' : t.type === 'error' ? '✕ ' : ' '}{t.message}
</div>
))}
</div>
);
}
let _toastId = 0;
export function useToast() {
const [toasts, setToasts] = useState<ToastItem[]>([]);
const timerRef = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map());
const showToast = useCallback((message: string, type: ToastItem['type'] = 'success', duration = 2500) => {
const id = ++_toastId;
setToasts(prev => [...prev, { id, message, type }]);
const timer = setTimeout(() => {
setToasts(prev => prev.filter(t => t.id !== id));
timerRef.current.delete(id);
}, duration);
timerRef.current.set(id, timer);
}, []);
useEffect(() => {
const timers = timerRef.current;
return () => { timers.forEach(t => clearTimeout(t)); };
}, []);
return { toasts, showToast };
}