import { useState, useEffect, useCallback, useRef } from 'react'; import { useLanguage } from '../../contexts/LanguageContext'; const TESTIMONIALS = [ { quote: '写论文的时候截图粘进去,LaTeX 就出来了。以前每个公式都要手敲,现在一个截图解决,省了我大概 40% 的时间。', name: '林同学', role: '数学系研究生 · 北京大学', avatarBg: 'var(--teal)', avatarColor: '#1a5c54', avatarLetter: '林', stars: '★★★★★', }, { quote: '手写推导拍一张,马上就是干净的 LaTeX。对我这种每天要整理大量笔记的人来说,真的是刚需级别的工具。', name: '田晓雯', role: '物理学博士候选人 · 清华大学', avatarBg: 'var(--lavender)', avatarColor: '#3d3870', avatarLetter: '田', stars: '★★★★★', }, { quote: "I use it every day for my thesis. The accuracy on complex integrals and matrix expressions is surprisingly good — way better than anything I've tried before.", name: 'Sarah M.', role: 'Applied Math PhD · MIT', avatarBg: 'var(--rose)', avatarColor: '#7a2e1e', avatarLetter: 'S', stars: '★★★★★', }, { quote: 'Desktop 版的离线功能对我来说很重要,论文数据不想上传到云端。买断价格也合理,不用每个月担心订阅。', name: '陈博士', role: '生物信息学研究员 · 中科院', avatarBg: 'var(--gold)', avatarColor: '#6f5800', avatarLetter: '陈', stars: '★★★★★', }, { quote: 'The browser extension is a game changer. I copy equations from Claude or ChatGPT straight into Word as native math — no more reformatting nightmares.', name: 'Alex K.', role: 'Engineering Student · TU Berlin', avatarBg: '#8CB4C9', avatarColor: '#1a3d52', avatarLetter: 'A', stars: '★★★★★', }, { quote: '教材扫描件里的公式以前完全没法用,现在截图一框就搞定。连化学方程式都能识别,超出我的预期。', name: '王梓涵', role: '化学工程本科 · 浙江大学', avatarBg: '#C9A88C', avatarColor: '#4a2e14', avatarLetter: '王', stars: '★★★★☆', }, ]; const VISIBLE = 3; const TOTAL = TESTIMONIALS.length; const PAGES = TOTAL - VISIBLE + 1; // 4 export default function TestimonialsSection() { const { language } = useLanguage(); const [currentPage, setCurrentPage] = useState(0); const trackRef = useRef(null); const autoTimerRef = useRef | null>(null); const goTo = useCallback((idx: number) => { const clamped = Math.max(0, Math.min(idx, PAGES - 1)); setCurrentPage(clamped); if (trackRef.current) { const cardW = trackRef.current.parentElement!.offsetWidth; const gap = 20; const singleW = (cardW - gap * (VISIBLE - 1)) / VISIBLE; const offset = clamped * (singleW + gap); trackRef.current.style.transform = `translateX(-${offset}px)`; } }, []); const resetAuto = useCallback(() => { if (autoTimerRef.current) clearInterval(autoTimerRef.current); autoTimerRef.current = setInterval(() => { setCurrentPage((prev) => { const next = (prev + 1) % PAGES; goTo(next); return next; }); }, 5000); }, [goTo]); useEffect(() => { resetAuto(); return () => { if (autoTimerRef.current) clearInterval(autoTimerRef.current); }; }, [resetAuto]); useEffect(() => { const handleResize = () => goTo(currentPage); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, [currentPage, goTo]); const handleGoTo = (idx: number) => { goTo(idx); resetAuto(); }; return (
User Love

{language === 'zh' ? '全球学生都在用' : 'Loved by students worldwide'}

{language === 'zh' ? '来自真实用户的反馈。' : 'Feedback from real users.'}

{TESTIMONIALS.map((t, i) => (
"

{t.quote}

{t.avatarLetter}
{t.name}
{t.role}
{t.stars}
))}
{Array.from({ length: PAGES }).map((_, i) => (
handleGoTo(i)} /> ))}
); }