diff --git a/public/fomula_demo/complex.png b/public/fomula_demo/complex.png new file mode 100644 index 0000000..943ad64 Binary files /dev/null and b/public/fomula_demo/complex.png differ diff --git a/public/fomula_demo/deformity.png b/public/fomula_demo/deformity.png new file mode 100644 index 0000000..515cb9e Binary files /dev/null and b/public/fomula_demo/deformity.png differ diff --git a/public/fomula_demo/maual.png b/public/fomula_demo/maual.png new file mode 100644 index 0000000..8d93300 Binary files /dev/null and b/public/fomula_demo/maual.png differ diff --git a/public/fomula_demo/mix.png b/public/fomula_demo/mix.png new file mode 100644 index 0000000..d18650d Binary files /dev/null and b/public/fomula_demo/mix.png differ diff --git a/src/components/home/ShowcaseSection.tsx b/src/components/home/ShowcaseSection.tsx index b52349f..b1164cc 100644 --- a/src/components/home/ShowcaseSection.tsx +++ b/src/components/home/ShowcaseSection.tsx @@ -1,8 +1,53 @@ -import { Link } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { useLanguage } from '../../contexts/LanguageContext'; +const DEMO_CASES = [ + { + key: 'complex', + src: '/fomula_demo/complex.png', + tag: { zh: '复杂公式', en: 'Complex' }, + title: { zh: '嵌套数学公式', en: 'Nested Math' }, + desc: { zh: 'arXiv 论文截图', en: 'arXiv paper screenshot' }, + color: 'var(--primary)', + colorBg: 'rgba(200,98,42,0.10)', + }, + { + key: 'deformity', + src: '/fomula_demo/deformity.png', + tag: { zh: '扭曲变形', en: 'Distorted' }, + title: { zh: '倾斜扫描识别', en: 'Skewed Scan' }, + desc: { zh: '低质量扫描文档', en: 'Low-quality scanned doc' }, + color: 'var(--teal)', + colorBg: 'rgba(140,201,190,0.13)', + }, + { + key: 'maual', + src: '/fomula_demo/maual.png', + tag: { zh: '手写公式', en: 'Handwriting Formula' }, + title: { zh: '手写转 LaTeX', en: 'Handwriting → LaTeX' }, + desc: { zh: '手机拍摄课堂笔记', en: 'Phone-captured notes' }, + color: 'var(--gold)', + colorBg: 'rgba(243,201,106,0.15)', + }, + { + key: 'mix', + src: '/fomula_demo/mix.png', + tag: { zh: '文字混排', en: 'Text Layout' }, + title: { zh: '文字混排识别', en: 'Text + Formula' }, + desc: { zh: '论文正文截图', en: 'Paper body with equations' }, + color: 'var(--lavender)', + colorBg: 'rgba(183,175,232,0.15)', + }, +] as const; + export default function ShowcaseSection() { const { language } = useLanguage(); + const navigate = useNavigate(); + + const handleTryIt = (src: string) => { + sessionStorage.setItem('texpixel_demo_image', src); + navigate('/app'); + }; return (
@@ -14,71 +59,56 @@ export default function ShowcaseSection() {

{language === 'zh' - ? '看看 TexPixel 如何处理真实的论文截图与手写笔记。' - : 'See how TexPixel handles real paper screenshots and handwritten notes.'} + ? '点击任意案例,直接体验 TexPixel 的识别效果。' + : 'Click any example to instantly try TexPixel on real formula images.'}

-
-
-
-
{language === 'zh' ? '复杂公式' : 'Complex Formula'}
-
- {language === 'zh' ? '论文截图到可复制 LaTeX' : 'Paper Screenshot to Copyable LaTeX'} +
+ {DEMO_CASES.map((c, i) => ( +
+
+ {c.tag[language]} +
+ +
-
arXiv PDF · 0.41s
-
-
-
- - ∑ ¹/ᵢ² · · · [{language === 'zh' ? '图片占位' : 'image placeholder'}] - -
-
-
\\sum_{i=1}^{n}\\frac{1}{i^2}', - }} - /> -
-
- - {language === 'zh' ? '试试这个例子 →' : 'Try this example →'} - -
-
-
-
-
- {language === 'zh' ? '手写公式' : 'Handwritten Formula'} -
-
- {language === 'zh' ? '课堂笔记到标准表达式' : 'Classroom Notes to Standard Expression'} -
-
{language === 'zh' ? '手机拍摄笔记 · 0.38s' : 'Phone photo of notes · 0.38s'}
-
-
-
- - lim sin(x)/x [{language === 'zh' ? '手写' : 'handwritten'}] +
+ + {c.tag[language]} +
{c.title[language]}
+
{c.desc[language]}
+
+ +
+
-
-
\\lim_{x\\to 0}\\frac{\\sin x}{x}', - }} - />
-
- - {language === 'zh' ? '试试这个例子 →' : 'Try this example →'} - -
-
+ ))}
diff --git a/src/components/home/TestimonialsSection.tsx b/src/components/home/TestimonialsSection.tsx index 2188015..49e7ceb 100644 --- a/src/components/home/TestimonialsSection.tsx +++ b/src/components/home/TestimonialsSection.tsx @@ -4,58 +4,67 @@ import { useLanguage } from '../../contexts/LanguageContext'; const TESTIMONIALS = [ { quote: '写论文的时候截图粘进去,LaTeX 就出来了。以前每个公式都要手敲,现在一个截图解决,省了我大概 40% 的时间。', - name: '林同学', - role: '数学系研究生 · 北京大学', + name: '纪**', + role: '研究生 · 上海交通大学', avatarBg: 'var(--teal)', avatarColor: '#1a5c54', - avatarLetter: '林', + avatarLetter: '纪', stars: '★★★★★', }, { quote: '手写推导拍一张,马上就是干净的 LaTeX。对我这种每天要整理大量笔记的人来说,真的是刚需级别的工具。', - name: '田晓雯', - role: '物理学博士候选人 · 清华大学', + name: '李**', + role: '研究生 · 北京航空航天大学', avatarBg: 'var(--lavender)', avatarColor: '#3d3870', - avatarLetter: '田', + 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', + name: 'E. ***', + role: 'Graduate Student · National University of Singapore', avatarBg: 'var(--rose)', avatarColor: '#7a2e1e', - avatarLetter: 'S', + avatarLetter: 'E', stars: '★★★★★', }, { - quote: 'Desktop 版的离线功能对我来说很重要,论文数据不想上传到云端。买断价格也合理,不用每个月担心订阅。', - name: '陈博士', - role: '生物信息学研究员 · 中科院', + quote: '教材扫描件里的公式以前完全没法用,现在截图一框就搞定。连复杂数学公式都能识别,超出我的预期。', + name: '孟**', + role: '本科生 · 同济大学', avatarBg: 'var(--gold)', avatarColor: '#6f5800', - avatarLetter: '陈', + avatarLetter: '孟', + stars: '★★★★☆', + }, + { + quote: '做毕设推导的时候,把草稿纸拍照上传,几秒就能得到完整的 LaTeX 代码,再也不用对着键盘一个符号一个符号敲了。', + name: '任**', + role: '本科生 · 天津大学', + avatarBg: '#A8C5A0', + avatarColor: '#1e4a18', + 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', + quote: '识别精度真的超预期,矩阵、积分、偏导数全都能准确处理,我们组里几个同学现在都在用。', + name: '姚**', + role: '研究生 · 中山大学', + avatarBg: '#B8A9D9', + avatarColor: '#2e1e5c', + avatarLetter: '姚', + stars: '★★★★★', + }, + { + quote: '科研文档里经常遇到各种冷门符号,之前其他工具基本认不出来,这个都能处理,识别结果直接可用。', + name: '肖**', + role: '研究生 · 国防科技大学', avatarBg: '#8CB4C9', avatarColor: '#1a3d52', - avatarLetter: 'A', + avatarLetter: '肖', stars: '★★★★★', }, - { - quote: '教材扫描件里的公式以前完全没法用,现在截图一框就搞定。连化学方程式都能识别,超出我的预期。', - name: '王梓涵', - role: '化学工程本科 · 浙江大学', - avatarBg: '#C9A88C', - avatarColor: '#4a2e14', - avatarLetter: '王', - stars: '★★★★☆', - }, ]; const VISIBLE = 3; @@ -116,7 +125,7 @@ export default function TestimonialsSection() { {language === 'zh' ? '全球学生都在用' : 'Loved by students worldwide'}

- {language === 'zh' ? '来自真实用户的反馈。' : 'Feedback from real users.'} + {language === 'zh' ? '来自用户的使用体验分享。' : 'What users are saying about their experience.'}

diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 5fe717e..0cf5e29 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -21,15 +21,11 @@ export default function HomePage() { path="/" /> -
-
-
-
); diff --git a/src/pages/WorkspacePage.tsx b/src/pages/WorkspacePage.tsx index 7da4479..641932e 100644 --- a/src/pages/WorkspacePage.tsx +++ b/src/pages/WorkspacePage.tsx @@ -45,6 +45,7 @@ export default function WorkspacePage() { const selectedFileIdRef = useRef(null); const resultsCache = useRef>({}); const hasLoadedFiles = useRef(false); + const demoLoadedRef = useRef(false); const selectedFile = files.find((f) => f.id === selectedFileId) || null; const canUploadAnonymously = !user && guestUsageCount < GUEST_USAGE_LIMIT; @@ -74,6 +75,26 @@ export default function WorkspacePage() { return () => window.removeEventListener('start-user-guide', handleStartGuide); }, []); + useEffect(() => { + if (initializing) return; + if (demoLoadedRef.current) return; + + const demoImageSrc = sessionStorage.getItem('texpixel_demo_image'); + if (!demoImageSrc) return; + + demoLoadedRef.current = true; + sessionStorage.removeItem('texpixel_demo_image'); + + fetch(demoImageSrc) + .then((res) => res.blob()) + .then((blob) => { + const fileName = demoImageSrc.split('/').pop() || 'demo.png'; + const file = new File([blob], fileName, { type: blob.type || 'image/png' }); + handleUpload([file]); + }) + .catch((err) => console.error('Failed to load demo image:', err)); + }, [initializing]); + useEffect(() => { if (!initializing && user && !hasLoadedFiles.current) { hasLoadedFiles.current = true; diff --git a/src/styles/landing.css b/src/styles/landing.css index 0c7ab17..28424a2 100644 --- a/src/styles/landing.css +++ b/src/styles/landing.css @@ -1029,6 +1029,158 @@ padding: 0 28px 28px; } +/* ── DEMO GRID ── */ +.demo-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 20px; + margin-top: 12px; +} + +.demo-card { + background: var(--elevated); + border: 1.5px solid var(--border); + border-radius: var(--r-xl); + overflow: hidden; + display: flex; + flex-direction: column; + box-shadow: var(--shadow-soft); + transition: box-shadow 0.25s, transform 0.25s; +} + +.demo-card:hover { + box-shadow: var(--shadow-float); + transform: translateY(-3px); +} + +.demo-img-wrap { + position: relative; + overflow: hidden; + background: #f7f3ef; +} + +.demo-img { + width: 100%; + height: auto; + display: block; + transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1); +} + +.demo-card:hover .demo-img { + transform: scale(1.02); +} + +.demo-img-overlay { + position: absolute; + inset: 0; + background: rgba(31, 26, 23, 0.45); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.25s; + backdrop-filter: blur(2px); +} + +.demo-card:hover .demo-img-overlay { + opacity: 1; +} + +.demo-try-btn { + display: inline-flex; + align-items: center; + gap: 7px; + background: white; + color: var(--text-strong); + border: none; + border-radius: var(--r-pill); + padding: 8px 16px; + font-size: 13px; + font-weight: 600; + cursor: pointer; + box-shadow: 0 4px 16px rgba(0,0,0,0.18); + transition: transform 0.15s, box-shadow 0.15s; +} + +.demo-try-btn:hover { + transform: scale(1.05); + box-shadow: 0 6px 20px rgba(0,0,0,0.22); +} + +.demo-meta { + padding: 12px 14px 6px; + display: flex; + flex-direction: column; + gap: 4px; + flex: 1; +} + +.demo-tag { + display: inline-block; + padding: 2px 8px; + border-radius: var(--r-pill); + font-size: 11px; + font-weight: 600; + letter-spacing: 0.3px; + align-self: flex-start; + white-space: nowrap; +} + +.demo-title { + font-family: 'Lora', serif; + font-size: 13px; + font-weight: 700; + color: var(--text-strong); + line-height: 1.35; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.demo-desc { + font-size: 11.5px; + color: var(--text-muted); + line-height: 1.45; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.demo-footer { + padding: 8px 14px 14px; + border-top: 1px solid var(--border); +} + +.demo-cta { + display: inline-flex; + align-items: center; + gap: 5px; + background: none; + border: none; + color: var(--primary); + font-size: 12px; + font-weight: 600; + cursor: pointer; + padding: 0; + transition: gap 0.15s; +} + +.demo-cta:hover { + gap: 9px; +} + +@media (max-width: 900px) { + .demo-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 560px) { + .demo-grid { + grid-template-columns: 1fr; + } +} + /* ── USER LOVE ── */ .user-love { padding: 96px 0; @@ -1808,7 +1960,7 @@ .testimonial-track { display: grid; - grid-template-columns: repeat(6, calc(33.333% - 14px)); + grid-template-columns: repeat(7, calc(33.333% - 14px)); gap: 20px; transition: transform 0.45s cubic-bezier(0.4, 0, 0.2, 1); } @@ -1959,6 +2111,10 @@ transition-delay: 0.30s; } +.reveal-delay-4 { + transition-delay: 0.40s; +} + @keyframes blink { 0%,