refactor: homepage - remove demo section, adapt for token relay station, move providers to bottom
Docker Build / Build and Push Docker Image (push) Successful in 4m17s

This commit is contained in:
2026-06-14 19:52:31 +08:00
parent 5c4ed6206e
commit 64326a86d5
3 changed files with 45 additions and 210 deletions
+29 -210
View File
@@ -21,11 +21,8 @@ import { Link } from '@tanstack/react-router'
import {
ArrowDown,
ArrowRight,
BarChart3,
Check,
Copy,
Shield,
Zap,
} from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { cn } from '@/lib/utils'
@@ -39,7 +36,7 @@ interface HeroProps {
const providers = [
'OpenAI', 'Claude', 'Gemini', 'Mistral', 'DeepSeek',
'Llama', 'Qwen', 'Cohere', 'Groq', 'Perplexity',
'Codex', 'Qwen', 'Cohere', 'Groq', 'Perplexity',
]
const jsCode = `import OpenAI from 'openai';
@@ -64,7 +61,7 @@ client = OpenAI(
)
response = client.chat.completions.create(
model="gpt-4o",
model="claude-sonnet-4-20250514",
messages=[
{"role": "user", "content": "Hello!"}
]
@@ -74,7 +71,7 @@ const curlCode = `curl https://your-gateway.com/v1/chat/completions \\
-H "Authorization: Bearer sk-your-api-key" \\
-H "Content-Type: application/json" \\
-d '{
"model": "gpt-4o",
"model": "deepseek-chat",
"messages": [{"role": "user", "content": "Hello!"}]
}'`
@@ -87,17 +84,10 @@ export function Hero(props: HeroProps) {
const [activeSection, setActiveSection] = useState(0)
const [activeTab, setActiveTab] = useState<TabKey>('javascript')
const [copied, setCopied] = useState(false)
const [demoState, setDemoState] = useState<'idle' | 'running' | 'done'>('idle')
const [demoStep, setDemoStep] = useState(0)
const serverAddress =
(status?.server_address as string | undefined) ||
`${window.location.origin}`
const sections = [
{ id: 'hero', ref: useRef<HTMLDivElement>(null) },
{ id: 'code', ref: useRef<HTMLDivElement>(null) },
{ id: 'demo', ref: useRef<HTMLDivElement>(null) },
]
// Scroll spy
@@ -136,22 +126,6 @@ export function Hero(props: HeroProps) {
setTimeout(() => setCopied(false), 2000)
}, [activeTab])
const handleDemo = useCallback(() => {
if (demoState === 'running') return
setDemoState('running')
setDemoStep(0)
const steps = [
{ step: 1, delay: 600 },
{ step: 2, delay: 1200 },
{ step: 3, delay: 2000 },
{ step: 4, delay: 2800 },
]
steps.forEach(({ step, delay }) => {
setTimeout(() => setDemoStep(step), delay)
})
setTimeout(() => setDemoState('done'), 3200)
}, [demoState])
const tabCodeMap: Record<TabKey, string> = {
javascript: jsCode,
python: pythonCode,
@@ -164,13 +138,6 @@ export function Hero(props: HeroProps) {
{ key: 'curl', label: 'cURL' },
]
const stepLabels = [
t('Connecting'),
t('Authenticating'),
t('Processing'),
t('Complete'),
]
return (
<section className='relative overflow-hidden bg-background' ref={containerRef}>
{/* Subtle dot grid */}
@@ -196,7 +163,7 @@ export function Hero(props: HeroProps) {
{/* Section navigation dots (desktop only) */}
<div className='fixed right-6 top-1/2 z-30 hidden -translate-y-1/2 flex-col gap-3 lg:flex'>
{[0, 1, 2].map((i) => (
{[0, 1].map((i) => (
<button
key={i}
onClick={() => scrollToSection(i)}
@@ -223,7 +190,7 @@ export function Hero(props: HeroProps) {
</h1>
<p className='mx-auto mt-4 max-w-xl text-[15px] leading-relaxed text-muted-foreground'>
{t('Route, monitor, and manage LLM traffic through a single gateway. Switch providers in seconds.')}
{t('Token relay station supporting Codex, Claude, GPT, DeepSeek and more. Unified API, unified billing, unified management.')}
</p>
{/* CTA */}
@@ -267,28 +234,6 @@ export function Hero(props: HeroProps) {
</button>
</div>
{/* ── Provider logos marquee ── */}
<div className='relative py-12'>
<p className='mb-4 text-center text-xs font-medium uppercase tracking-widest text-muted-foreground/60'>
{t('Supported providers')}
</p>
<div className='relative overflow-hidden'>
<div className='flex animate-[marquee_30s_linear_infinite] gap-8'>
{[...providers, ...providers].map((name, i) => (
<span
key={`${name}-${i}`}
className='shrink-0 text-sm font-semibold text-muted-foreground/40'
>
{name}
</span>
))}
</div>
{/* Fade edges */}
<div className='pointer-events-none absolute inset-y-0 left-0 w-16 bg-gradient-to-r from-background to-transparent' />
<div className='pointer-events-none absolute inset-y-0 right-0 w-16 bg-gradient-to-l from-background to-transparent' />
</div>
</div>
{/* ── Section 2: Code Demo ── */}
<div
ref={sections[1].ref}
@@ -350,20 +295,20 @@ export function Hero(props: HeroProps) {
{/* Right: Text content */}
<div>
<h2 className='text-[clamp(1.5rem,3vw,2rem)] leading-tight font-bold tracking-[-0.02em] text-foreground'>
{t('Quick Integration')}
{t('Token Relay Station')}
</h2>
<p className='mt-1 bg-gradient-to-r from-primary to-primary/60 bg-clip-text text-[clamp(1.5rem,3vw,2rem)] leading-tight font-bold tracking-[-0.02em] text-transparent'>
{t('Drop-in Replacement')}
{t('Multi-model Access')}
</p>
<p className='mt-4 max-w-md text-[15px] leading-relaxed text-muted-foreground'>
{t('Route, monitor, and manage LLM traffic through a single gateway. Switch providers in seconds.')}
{t('Supports Codex, Claude, GPT, DeepSeek, Gemini, Qwen and more. One API key to access all models, with automatic failover and load balancing.')}
</p>
<ul className='mt-6 space-y-3'>
{[
t('OpenAI-compatible API interface'),
t('Zero code changes required'),
t('Automatic model routing'),
t('Real-time request monitoring'),
t('Supports Codex, Claude, GPT, DeepSeek and more'),
t('Unified API, zero code changes required'),
t('Automatic model routing and failover'),
t('Real-time usage tracking and cost control'),
].map((feature) => (
<li key={feature} className='flex items-center gap-2.5 text-sm text-foreground'>
<div className='flex size-5 shrink-0 items-center justify-center rounded-full bg-primary/10'>
@@ -377,151 +322,25 @@ export function Hero(props: HeroProps) {
</div>
</div>
{/* ── Section 3: Interactive Demo ── */}
<div
ref={sections[2].ref}
className='relative flex min-h-svh items-center px-6 py-20'
>
<div className='mx-auto grid w-full max-w-6xl gap-12 lg:grid-cols-2 lg:items-center'>
{/* Left: Text content */}
<div>
<h2 className='text-[clamp(1.5rem,3vw,2rem)] leading-tight font-bold tracking-[-0.02em] text-foreground'>
{t('Try it Live')}
</h2>
<p className='mt-1 bg-gradient-to-r from-primary to-primary/60 bg-clip-text text-[clamp(1.5rem,3vw,2rem)] leading-tight font-bold tracking-[-0.02em] text-transparent'>
{t('See it in Action')}
</p>
<p className='mt-4 max-w-md text-[15px] leading-relaxed text-muted-foreground'>
{t('Route, monitor, and manage LLM traffic through a single gateway. Switch providers in seconds.')}
</p>
<ul className='mt-6 space-y-3'>
{[
{ icon: Zap, text: t('Automatic model routing') },
{ icon: Shield, text: t('OpenAI-compatible API interface') },
{ icon: BarChart3, text: t('Real-time request monitoring') },
].map(({ icon: Icon, text }) => (
<li key={text} className='flex items-center gap-2.5 text-sm text-foreground'>
<div className='flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary/10'>
<Icon className='size-4 text-primary' />
</div>
{text}
</li>
))}
</ul>
</div>
{/* Right: Interactive card */}
<div className='overflow-hidden rounded-lg border border-border bg-card shadow-sm'>
<div className='border-b border-border px-5 py-3'>
<h3 className='text-sm font-semibold text-foreground'>API Request</h3>
<p className='text-xs text-muted-foreground'>Simulated gateway call</p>
</div>
<div className='p-5'>
{/* Input area */}
<div className='space-y-3'>
<div>
<label className='mb-1 block text-xs font-medium text-muted-foreground'>
API Key
</label>
<div className='flex h-9 items-center rounded-md border border-border bg-muted/50 px-3 font-mono text-xs text-foreground/70'>
sk-
</div>
</div>
<div>
<label className='mb-1 block text-xs font-medium text-muted-foreground'>
Endpoint
</label>
<div className='flex h-9 items-center rounded-md border border-border bg-muted/50 px-3 font-mono text-xs text-foreground/70'>
{serverAddress}/v1/chat/completions
</div>
</div>
</div>
{/* Send button */}
<Button
className='mt-4 w-full'
onClick={handleDemo}
disabled={demoState === 'running'}
{/* ── Provider logos marquee (bottom) ── */}
<div className='relative py-16'>
<p className='mb-4 text-center text-xs font-medium uppercase tracking-widest text-muted-foreground/60'>
{t('Supported providers')}
</p>
<div className='relative overflow-hidden'>
<div className='flex animate-[marquee_30s_linear_infinite] gap-8'>
{[...providers, ...providers].map((name, i) => (
<span
key={`${name}-${i}`}
className='shrink-0 text-sm font-semibold text-muted-foreground/40'
>
{demoState === 'running' ? '...' : t('Send Request')}
</Button>
{/* Animated steps */}
{(demoState === 'running' || demoState === 'done') && (
<div className='mt-4 space-y-2'>
{stepLabels.map((label, i) => {
const stepNum = i + 1
const isActive = demoStep >= stepNum
const isCurrent = demoStep === stepNum && demoState === 'running'
return (
<div
key={label}
className={cn(
'flex items-center gap-2.5 rounded-md px-3 py-2 text-xs transition-all duration-500',
isActive
? 'bg-primary/5 text-foreground'
: 'text-muted-foreground/50',
isCurrent && 'bg-primary/10'
)}
>
<div
className={cn(
'flex size-5 shrink-0 items-center justify-center rounded-full transition-all duration-300',
isActive
? 'bg-primary text-primary-foreground'
: 'bg-muted text-muted-foreground'
)}
>
{isActive ? (
stepNum === 4 ? (
<Check className='size-3' />
) : (
<span className='text-[10px] font-bold'>{stepNum}</span>
)
) : (
<span className='text-[10px] font-bold'>{stepNum}</span>
)}
</div>
<span className={cn('font-medium', isCurrent && 'animate-pulse')}>
{label}
</span>
{isCurrent && (
<div className='ml-auto'>
<div className='size-1.5 animate-pulse rounded-full bg-primary' />
</div>
)}
</div>
)
})}
</div>
)}
{/* Result */}
{demoState === 'done' && (
<div className='mt-4 rounded-md border border-border bg-muted/30 p-3'>
<div className='mb-2 flex items-center gap-2'>
<span className='inline-block size-1.5 rounded-full bg-green-500' />
<span className='text-[11px] font-medium text-muted-foreground'>200 OK</span>
<span className='text-[11px] text-muted-foreground/60'>142ms</span>
</div>
<div className='font-mono text-xs text-foreground/70'>
<div>{'{'}</div>
<div className='pl-3'>
<span className='text-primary'>"model"</span>
{': '}
<span>"gpt-4o"</span>,
</div>
<div className='pl-3'>
<span className='text-primary'>"usage"</span>
{': '}
<span>{'{ "prompt_tokens": 12, "completion_tokens": 47 }'}</span>
</div>
<div>{'}'}</div>
</div>
</div>
)}
</div>
{name}
</span>
))}
</div>
{/* Fade edges */}
<div className='pointer-events-none absolute inset-y-0 left-0 w-16 bg-gradient-to-r from-background to-transparent' />
<div className='pointer-events-none absolute inset-y-0 right-0 w-16 bg-gradient-to-l from-background to-transparent' />
</div>
</div>
+8
View File
@@ -4595,6 +4595,14 @@
"OpenAI-compatible API interface": "OpenAI-compatible API interface",
"Processing": "Processing",
"Quick Integration": "Quick Integration",
"Token Relay Station": "Token Relay Station",
"Multi-model Access": "Multi-model Access",
"Token relay station supporting Codex, Claude, GPT, DeepSeek and more. Unified API, unified billing, unified management.": "Token relay station supporting Codex, Claude, GPT, DeepSeek and more. Unified API, unified billing, unified management.",
"Supports Codex, Claude, GPT, DeepSeek, Gemini, Qwen and more. One API key to access all models, with automatic failover and load balancing.": "Supports Codex, Claude, GPT, DeepSeek, Gemini, Qwen and more. One API key to access all models, with automatic failover and load balancing.",
"Supports Codex, Claude, GPT, DeepSeek and more": "Supports Codex, Claude, GPT, DeepSeek and more",
"Unified API, zero code changes required": "Unified API, zero code changes required",
"Automatic model routing and failover": "Automatic model routing and failover",
"Real-time usage tracking and cost control": "Real-time usage tracking and cost control",
"Real-time request monitoring": "Real-time request monitoring",
"Search documents...": "Search documents...",
"Select a document to start reading": "Select a document to start reading",
+8
View File
@@ -4595,6 +4595,14 @@
"OpenAI-compatible API interface": "兼容 OpenAI 的 API 接口",
"Processing": "处理中",
"Quick Integration": "快速集成",
"Token Relay Station": "Token 中转站",
"Multi-model Access": "多模型接入",
"Token relay station supporting Codex, Claude, GPT, DeepSeek and more. Unified API, unified billing, unified management.": "Token 中转站,支持 Codex、Claude、GPT、DeepSeek 等模型接入。统一接口,统一计费,统一管理。",
"Supports Codex, Claude, GPT, DeepSeek, Gemini, Qwen and more. One API key to access all models, with automatic failover and load balancing.": "支持 Codex、Claude、GPT、DeepSeek、Gemini、通义千问等模型。一个 API Key 访问所有模型,自动故障转移与负载均衡。",
"Supports Codex, Claude, GPT, DeepSeek and more": "支持 Codex、Claude、GPT、DeepSeek 等接入",
"Unified API, zero code changes required": "统一接口,零代码改动即可使用",
"Automatic model routing and failover": "自动模型路由与故障转移",
"Real-time usage tracking and cost control": "实时用量追踪与成本控制",
"Real-time request monitoring": "实时请求监控",
"Search documents...": "搜索文档...",
"Select a document to start reading": "选择文档开始阅读",