UI: тёплый современный дизайн + русификация

This commit is contained in:
2026-05-29 10:38:01 +03:00
parent e4b25fe4b7
commit ea0df060e8
17 changed files with 576 additions and 527 deletions

View File

@@ -3,7 +3,7 @@ import { X } from 'lucide-react';
type ToastType = 'success' | 'error' | 'info' | 'like';
interface Toast {
interface ToastItem {
id: number;
message: string;
type: ToastType;
@@ -14,44 +14,35 @@ interface ToastContextType {
}
const ToastContext = createContext<ToastContextType>(null!);
let nextId = 0;
const iconMap: Record<ToastType, string> = {
success: '✓',
error: '✕',
info: '·',
like: '♥',
};
export function ToastProvider({ children }: { children: ReactNode }) {
const [toasts, setToasts] = useState<Toast[]>([]);
const [toasts, setToasts] = useState<ToastItem[]>([]);
const addToast = useCallback((message: string, type: ToastType = 'info') => {
const id = nextId++;
setToasts((prev) => [...prev, { id, message, type }]);
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 2200);
setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), 2500);
}, []);
const remove = (id: number) => {
setToasts((prev) => prev.filter((t) => t.id !== id));
};
const remove = (id: number) => setToasts((prev) => prev.filter((t) => t.id !== id));
return (
<ToastContext.Provider value={{ toast: addToast }}>
{children}
<div className="fixed bottom-4 right-4 z-[100] flex flex-col gap-1.5">
<div className="fixed bottom-5 right-5 z-[100] flex flex-col gap-2">
{toasts.map((t) => (
<div
key={t.id}
className="animate-slide-up flex items-center gap-2 bg-foreground text-background px-3 py-2 text-sm shadow-lg"
className={`animate-slide-up flex items-center gap-2.5 rounded-xl px-4 py-2.5 text-sm font-medium shadow-lg backdrop-blur-sm ${
t.type === 'error'
? 'bg-destructive text-destructive-foreground'
: 'bg-foreground/90 text-background'
}`}
>
<span className="opacity-70">{iconMap[t.type]}</span>
<span>{t.message}</span>
<button onClick={() => remove(t.id)} className="ml-2 opacity-50 hover:opacity-100">
<X className="h-3 w-3" />
<button onClick={() => remove(t.id)} className="opacity-60 hover:opacity-100 transition-opacity">
<X className="h-3.5 w-3.5" />
</button>
</div>
))}