Import source: src/context/ToastContext
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { createContext, useContext, useState, useCallback, type ReactNode } from 'react';
|
||||
|
||||
export type ToastType = 'success' | 'error' | 'info';
|
||||
interface Toast { id: number; message: string; type: ToastType }
|
||||
interface ToastCtx { show: (message: string, type?: ToastType) => void }
|
||||
|
||||
const ToastContext = createContext<ToastCtx>({ show: () => {} });
|
||||
|
||||
export function ToastProvider({ children }: { children: ReactNode }) {
|
||||
const [toasts, setToasts] = useState<Toast[]>([]);
|
||||
|
||||
const show = useCallback((message: string, type: ToastType = 'success') => {
|
||||
const id = Date.now();
|
||||
setToasts(t => [...t, { id, message, type }]);
|
||||
setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 2800);
|
||||
}, []);
|
||||
|
||||
const ICONS = {
|
||||
success: <path d="M4 8l4 4 7-7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>,
|
||||
error: <path d="M6 6l6 6m0-6L6 12" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/>,
|
||||
info: <><circle cx="9" cy="5" r="1" fill="currentColor"/><path d="M9 8v5" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/></>,
|
||||
};
|
||||
const COLORS = {
|
||||
success: { bg: 'rgba(34,197,94,0.12)', border: 'rgba(34,197,94,0.3)', icon: '#22c55e' },
|
||||
error: { bg: 'rgba(239,68,68,0.12)', border: 'rgba(239,68,68,0.3)', icon: '#ef4444' },
|
||||
info: { bg: 'rgba(124,111,224,0.12)',border: 'rgba(124,111,224,0.3)',icon: '#7C6FE0' },
|
||||
};
|
||||
|
||||
return (
|
||||
<ToastContext.Provider value={{ show }}>
|
||||
{children}
|
||||
<div className="fixed bottom-6 right-6 flex flex-col gap-2 z-50 pointer-events-none">
|
||||
{toasts.map(t => {
|
||||
const c = COLORS[t.type];
|
||||
return (
|
||||
<div key={t.id} className="flex items-center gap-2.5 px-4 py-3 rounded-[12px] text-[14px] font-medium pointer-events-auto"
|
||||
style={{ background: 'var(--bg-card)', border: `1px solid ${c.border}`, color: 'var(--text-primary)', boxShadow: '0 8px 32px rgba(0,0,0,0.3)', animation: 'toast-in 0.25s ease both', backdropFilter: 'blur(12px)', minWidth: '220px' }}>
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" style={{ color: c.icon, flexShrink: 0 }}>{ICONS[t.type]}</svg>
|
||||
{t.message}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ToastContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useToast = () => useContext(ToastContext);
|
||||
Reference in New Issue
Block a user