mirror of
https://github.com/alibaba/open-code-review.git
synced 2026-07-09 17:28:58 +00:00
feat(i18n): add highlights section translations
This commit is contained in:
parent
a91fec38ef
commit
9a6a87b397
5 changed files with 135 additions and 0 deletions
88
pages/src/components/HighlightsSection.tsx
Normal file
88
pages/src/components/HighlightsSection.tsx
Normal file
|
|
@ -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<HTMLDivElement>(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 (
|
||||
<section ref={sectionRef} className="relative py-16 overflow-hidden">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-dark-900 via-dark-800/50 to-dark-900 pointer-events-none"></div>
|
||||
|
||||
<div className="relative z-10 max-w-7xl mx-auto px-6">
|
||||
<div className="highlight-card rounded-2xl p-1">
|
||||
<div className="rounded-2xl bg-dark-900/80 backdrop-blur-md p-10 md:p-14">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-10 md:gap-8 lg:gap-0 lg:divide-x lg:divide-dark-500/40">
|
||||
{stats.map((stat, i) => (
|
||||
<article
|
||||
key={i}
|
||||
className={`flex flex-col items-center lg:items-start lg:px-10 xl:px-14 first:lg:pl-0 last:lg:pr-0 transition-all duration-700 ${
|
||||
visible
|
||||
? 'opacity-100 translate-y-0'
|
||||
: 'opacity-0 translate-y-6'
|
||||
}`}
|
||||
style={{ transitionDelay: `${stat.delay}ms` }}
|
||||
>
|
||||
<header className="flex items-center gap-3 mb-4">
|
||||
<span className="block w-8 h-px bg-gradient-to-r from-brand-400 to-transparent"></span>
|
||||
<span className="text-xs font-medium uppercase tracking-widest text-slate-500 whitespace-nowrap">
|
||||
{stat.label}
|
||||
</span>
|
||||
</header>
|
||||
<p className="text-4xl md:text-5xl font-bold bg-gradient-to-r from-brand-400 to-cyan-400 bg-clip-text text-transparent leading-tight">
|
||||
{stat.value}
|
||||
</p>
|
||||
<p className="mt-2 text-sm text-slate-400">{stat.caption}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default HighlightsSection;
|
||||
|
|
@ -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 = () => {
|
|||
<div className="min-h-screen bg-dark-900 noise-overlay">
|
||||
<Navbar />
|
||||
<HeroSection />
|
||||
<HighlightsSection />
|
||||
<WhySection />
|
||||
<FeaturesSection />
|
||||
<BenchmarkSection />
|
||||
|
|
|
|||
|
|
@ -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?',
|
||||
|
|
|
|||
|
|
@ -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 适合谁?',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue