diff --git a/pages/src/components/HighlightsSection.tsx b/pages/src/components/HighlightsSection.tsx new file mode 100644 index 0000000..ba149a6 --- /dev/null +++ b/pages/src/components/HighlightsSection.tsx @@ -0,0 +1,88 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { useTranslation } from '../i18n'; + +const HighlightsSection: React.FC = () => { + const { t } = useTranslation(); + const sectionRef = useRef(null); + const [visible, setVisible] = useState(false); + + useEffect(() => { + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting) { + setVisible(true); + observer.disconnect(); + } + }, + { threshold: 0.3 } + ); + if (sectionRef.current) observer.observe(sectionRef.current); + return () => observer.disconnect(); + }, []); + + const stats = [ + { + label: t('highlights.stat1Label'), + value: t('highlights.stat1Value'), + caption: t('highlights.stat1Caption'), + delay: 0, + }, + { + label: t('highlights.stat2Label'), + value: t('highlights.stat2Value'), + caption: t('highlights.stat2Caption'), + delay: 100, + }, + { + label: t('highlights.stat3Label'), + value: '1/5', + caption: t('highlights.stat3Caption'), + delay: 200, + }, + { + label: t('highlights.stat4Label'), + value: '26.1%', + caption: t('highlights.stat4Caption'), + delay: 300, + }, + ]; + + return ( +
+
+ +
+
+
+
+ {stats.map((stat, i) => ( +
+
+ + + {stat.label} + +
+

+ {stat.value} +

+

{stat.caption}

+
+ ))} +
+
+
+
+
+ ); +}; + +export default HighlightsSection; diff --git a/pages/src/components/LandingPage.tsx b/pages/src/components/LandingPage.tsx index eb61e2f..573ae7a 100644 --- a/pages/src/components/LandingPage.tsx +++ b/pages/src/components/LandingPage.tsx @@ -2,6 +2,7 @@ import React, { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; import Navbar from './Navbar'; import HeroSection from './HeroSection'; +import HighlightsSection from './HighlightsSection'; import WhySection from './WhySection'; import FeaturesSection from './FeaturesSection'; import BenchmarkSection from './BenchmarkSection'; @@ -25,6 +26,7 @@ const LandingPage: React.FC = () => {
+ diff --git a/pages/src/i18n/en.ts b/pages/src/i18n/en.ts index ee99833..35692c1 100644 --- a/pages/src/i18n/en.ts +++ b/pages/src/i18n/en.ts @@ -22,6 +22,18 @@ export const en: TranslationKeys = { 'hero.terminal': 'ocr terminal', 'hero.badgeLabel': 'Benchmark #1', + // Highlights + 'highlights.stat1Label': 'Active Users', + 'highlights.stat1Value': '20K+', + 'highlights.stat1Caption': 'Battle-tested inside Alibaba Group', + 'highlights.stat2Label': 'Real-World Tasks', + 'highlights.stat2Value': '1M+', + 'highlights.stat2Caption': 'Code review tasks executed', + 'highlights.stat3Label': 'Token Cost', + 'highlights.stat3Caption': 'vs. generic Agent + Skills', + 'highlights.stat4Label': 'AACR-Bench', + 'highlights.stat4Caption': 'SEM.F1 benchmark score', + // Why Section 'why.sectionLabel': 'Use Cases', 'why.title': 'Who Is Open Code Review For?', diff --git a/pages/src/i18n/zh.ts b/pages/src/i18n/zh.ts index cc2b21d..425650a 100644 --- a/pages/src/i18n/zh.ts +++ b/pages/src/i18n/zh.ts @@ -22,6 +22,18 @@ export const zh: TranslationKeys = { 'hero.terminal': 'ocr 终端', 'hero.badgeLabel': '基准榜第 #1', + // Highlights + 'highlights.stat1Label': '活跃用户', + 'highlights.stat1Value': '20K+', + 'highlights.stat1Caption': '阿里集团内部生产验证', + 'highlights.stat2Label': '真实场景', + 'highlights.stat2Value': '1M+', + 'highlights.stat2Caption': '累计运行代码评审任务', + 'highlights.stat3Label': 'Token 效率', + 'highlights.stat3Caption': '相比通用 Agent + Skills 方案', + 'highlights.stat4Label': 'AACR-Bench', + 'highlights.stat4Caption': 'SEM.F1 基准测试得分', + // Why Section 'why.sectionLabel': '适用场景', 'why.title': 'Open Code Review 适合谁?', diff --git a/pages/src/styles/index.css b/pages/src/styles/index.css index ead6be9..364bb08 100644 --- a/pages/src/styles/index.css +++ b/pages/src/styles/index.css @@ -318,6 +318,27 @@ body { border-left: 3px solid #22c55e; } +/* ========== Highlight Card ========== */ +.highlight-card { + background: linear-gradient(135deg, rgba(34, 197, 94, 0.15), rgba(6, 182, 212, 0.10), rgba(139, 92, 246, 0.08)); + border-radius: 1rem; + position: relative; +} + +.highlight-card::before { + content: ''; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1px; + background: linear-gradient(135deg, rgba(34, 197, 94, 0.3), rgba(6, 182, 212, 0.2), rgba(139, 92, 246, 0.15)); + -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + pointer-events: none; +} + /* ========== Floating Badge ========== */ .floating-badge { animation: float 3s ease-in-out infinite;