37296b5717
改造概要(30项): - 第一轮:Hero重构/Section差异化/SocialProof强化/CTA对比度/About架构 - 第二轮:字体优化/背景交替/Solutions差异化/Footer五列/MegaDropdown修复 - 第三轮:卡片交互/表单层级/CTA统一/时间线标记/连接线/三列布局/移动导航/Button微交互/SEO Schema - P3-2:template.tsx+Framer Motion页面过渡/loading.tsx加载状态 - 清理:删除未用组件/hooks,修复重复移动导航,清理冗余CSS
69 lines
2.0 KiB
TypeScript
69 lines
2.0 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { CheckCircle2, X, AlertCircle, Info } from 'lucide-react';
|
|
|
|
interface ToastProps {
|
|
message: string;
|
|
type?: 'success' | 'error' | 'info';
|
|
duration?: number;
|
|
onClose: () => void;
|
|
'data-testid'?: string;
|
|
}
|
|
|
|
export function Toast({
|
|
message,
|
|
type = 'success',
|
|
duration = 3000,
|
|
onClose,
|
|
'data-testid': dataTestId
|
|
}: ToastProps) {
|
|
const [isVisible, setIsVisible] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const timer = setTimeout(() => {
|
|
setIsVisible(false);
|
|
setTimeout(onClose, 300);
|
|
}, duration);
|
|
|
|
return () => clearTimeout(timer);
|
|
}, [duration, onClose]);
|
|
|
|
const icons = {
|
|
success: <CheckCircle2 className="h-5 w-5 text-green-500" />,
|
|
error: <AlertCircle className="h-5 w-5 text-red-500" />,
|
|
info: <Info className="h-5 w-5 text-blue-500" />
|
|
};
|
|
|
|
const bgColors = {
|
|
success: 'bg-[var(--color-toast-success-bg)] border-[var(--color-toast-success-border)]',
|
|
error: 'bg-[var(--color-toast-error-bg)] border-[var(--color-toast-error-border)]',
|
|
info: 'bg-[var(--color-toast-info-bg)] border-[var(--color-toast-info-border)]'
|
|
};
|
|
|
|
return (
|
|
<div
|
|
data-testid={dataTestId}
|
|
data-type={type}
|
|
className={`fixed bottom-4 right-4 z-50 flex items-center gap-3 px-4 py-3 bg-[var(--color-bg-primary)] rounded-lg shadow-lg border transition-all duration-300 ${
|
|
isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-2'
|
|
} ${bgColors[type]}`}
|
|
role="alert"
|
|
aria-live="polite"
|
|
>
|
|
{icons[type]}
|
|
<p className="text-sm font-medium text-[var(--color-text-primary)]">{message}</p>
|
|
<button
|
|
onClick={() => {
|
|
setIsVisible(false);
|
|
setTimeout(onClose, 300);
|
|
}}
|
|
className="ml-2 text-[var(--color-toast-close)] hover:text-[var(--color-toast-close-hover)] transition-colors"
|
|
aria-label="关闭提示"
|
|
>
|
|
<X className="h-4 w-4" />
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|