Compare commits

...

2 Commits

Author SHA1 Message Date
wangxiaoji 00b7755fe1 chore: 更新 deploy.py 路径指向 D:\tuling_new\web\dist 2026-07-03 16:45:45 +08:00
wangxiaoji b47ea0dd3a 首页重构为 TokenDance 设计系统 + Contact 页面
- Home/index.jsx: 替换为 TokenDance 设计(紫色点缀、白色主题、TuringToken 品牌)
- Contact/index.jsx: 新增联系销售页面
- EmptyState.jsx: 新增通用空状态组件
- i18n/locales: 中英文 i18n 资源同步新增
- i18n.js, utils.jsx: 配合新页面更新工具函数
- App.jsx, AdminInitialSetupModal.jsx, User context: 注册联系页路由及配套调整
2026-07-03 16:40:56 +08:00
12 changed files with 749 additions and 663 deletions

2
web/deploy.py vendored
View File

@ -5,7 +5,7 @@ import sys
host = "26.0.12.13"
user = "root"
password = "root@1234"
local_dist = r"C:\Users\wangxj\tokenFactory\web\dist"
local_dist = r"D:\tuling_new\web\dist"
remote_dist = "/root/tokenFactory/web/dist"
print("Connecting...")

17
web/src/App.jsx vendored
View File

@ -95,6 +95,11 @@ import LuckyBag from './pages/LuckyBag';
import Drawing from './pages/Drawing';
import ProfitDashboard from './pages/ProfitDashboard';
import SettingsAntiAbuse from './pages/Setting/Operation/SettingsAntiAbuse';
import Contact from './pages/Contact';
import About from './pages/About';
import UserAgreement from './pages/UserAgreement';
import PrivacyPolicy from './pages/PrivacyPolicy';
import Docs from './pages/Docs';
const Home = lazy(() => import('./pages/Home'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
@ -102,10 +107,6 @@ const DistributorApply = lazy(() => import('./pages/DistributorApply'));
const DistributorCenter = lazy(() => import('./pages/DistributorCenter'));
const DistributorAdmin = lazy(() => import('./pages/DistributorAdmin'));
const InviteRedirect = lazy(() => import('./pages/InviteRedirect'));
const About = lazy(() => import('./pages/About'));
const UserAgreement = lazy(() => import('./pages/UserAgreement'));
const PrivacyPolicy = lazy(() => import('./pages/PrivacyPolicy'));
const Docs = lazy(() => import('./pages/Docs'));
function DynamicOAuth2Callback() {
const { provider } = useParams();
@ -545,6 +546,14 @@ function App() {
</Suspense>
}
/>
<Route
path='/contact'
element={
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
<Contact />
</Suspense>
}
/>
<Route
path='/docs'
element={

View File

@ -15,16 +15,16 @@ import React, {
useRef,
useState,
} from 'react';
import { Modal, Form, Typography, Space, Button } from '@douyinfe/semi-ui';
import { IconLock } from '@douyinfe/semi-icons';
import { useTranslation } from 'react-i18next';
import { UserContext } from '../../context/User';
import { Lock as IconLock } from 'lucide-react';
import { Modal, Form, Typography, Space, Button } from '@douyinfe/semi-ui';
import {
API,
showError,
showSuccess,
mergeSelfResponseIntoLocalUser,
} from '../../helpers';
import { UserContext } from '../../context/User';
import { buildAdminUserPhoneFieldRules } from '../table/users/modals/userPhoneFormRules';
const { Text, Title } = Typography;

View File

@ -18,8 +18,8 @@ For commercial licensing, please contact support@quantumnous.com
*/
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
import PropTypes from 'prop-types';
import { Button } from '@douyinfe/semi-ui';
import { useIsMobile } from '../../../hooks/common/useIsMobile';
/**

View File

@ -0,0 +1,69 @@
/*
Copyright (C) 2025 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import React from 'react';
import { Inbox } from 'lucide-react';
const ACC = '#635BFF';
const ACC_SOFT = '#EEEBFF';
const INK = '#0A2540';
const SUB = '#425466';
const DIM = '#697386';
const toText = (v) =>
typeof v === 'string'
? v
: v?.props?.children || '';
const EmptyState = ({ icon, title, description, children, style }) => {
const Icon = icon || Inbox;
const titleText = toText(title);
const descText = toText(description);
return (
<div
className='flex flex-col items-center justify-center py-12 text-center'
style={style}
>
<div
className='inline-flex h-12 w-12 items-center justify-center rounded-2xl'
style={{ background: ACC_SOFT, color: ACC }}
>
<Icon size={22} />
</div>
{titleText && (
<p className='mt-4 text-sm font-semibold' style={{ color: INK }}>
{titleText}
</p>
)}
{descText && (
<p className='mt-1 text-sm' style={{ color: DIM }}>
{descText}
</p>
)}
{!titleText && !descText && (
<p className='mt-4 text-sm' style={{ color: DIM }}>
暂无数据
</p>
)}
{children && <div className='mt-4'>{children}</div>}
</div>
);
};
export default EmptyState;

View File

@ -19,9 +19,10 @@ For commercial licensing, please contact support@quantumnous.com
import React, { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { reducer, initialState } from './reducer';
import { API } from '../../helpers/api';
import { initialState, reducer } from './reducer';
import { mergeSelfResponseIntoLocalUser } from '../../helpers/data';
import { normalizeLanguage } from '../../i18n/language';
import { API, mergeSelfResponseIntoLocalUser } from '../../helpers';
import AdminInitialSetupModal from '../../components/auth/AdminInitialSetupModal';
export const UserContext = React.createContext({

View File

@ -18,15 +18,12 @@ For commercial licensing, please contact support@quantumnous.com
*/
import { Toast, Pagination } from '@douyinfe/semi-ui';
import { toastConstants } from '../constants';
import React from 'react';
import { toast } from 'react-toastify';
import {
THINK_TAG_REGEX,
MESSAGE_ROLES,
} from '../constants/playground.constants';
import { TABLE_COMPACT_MODES_KEY } from '../constants';
import { USER_ROLES } from '../constants/user.constants';
import { toastConstants } from '../constants/toast.constants';
import { MOBILE_BREAKPOINT } from '../hooks/common/useIsMobile';
const HTMLToastContent = ({ htmlContent }) => {
@ -144,6 +141,15 @@ export function parseCommissionPercentStringToBps(s) {
export function getSystemName() {
let system_name = localStorage.getItem('system_name');
if (!system_name) return 'TuringToken';
// TokenFactory / TokenFactoryOpen / /
if (
system_name === 'TokenFactory' ||
system_name === 'TokenFactoryOpen' ||
system_name === '开放词元工厂'
) {
localStorage.setItem('system_name', 'TuringToken');
return 'TuringToken';
}
return system_name;
}

22
web/src/i18n/i18n.js vendored
View File

@ -39,17 +39,17 @@ i18n
load: 'currentOnly',
supportedLngs: supportedLanguages,
resources: {
en: enTranslation,
'zh-CN': zhCNTranslation,
'zh-TW': zhTWTranslation,
fr: frTranslation,
ru: ruTranslation,
ja: jaTranslation,
vi: viTranslation,
id: idTranslation,
ms: msTranslation,
th: thTranslation,
sw: swTranslation,
en: { translation: enTranslation },
'zh-CN': { translation: zhCNTranslation },
'zh-TW': { translation: zhTWTranslation },
fr: { translation: frTranslation },
ru: { translation: ruTranslation },
ja: { translation: jaTranslation },
vi: { translation: viTranslation },
id: { translation: idTranslation },
ms: { translation: msTranslation },
th: { translation: thTranslation },
sw: { translation: swTranslation },
},
fallbackLng: 'zh-CN',
lng: 'zh-CN',

View File

@ -5695,6 +5695,21 @@
"主题切换": "Theme Toggle",
"顶栏显示主题切换按钮,允许用户切换亮色/暗色模式": "Show theme toggle in header bar, allowing users to switch between light/dark mode",
"语言选择器": "Language Selector",
"顶栏显示语言选择器,允许用户切换界面语言": "Show language selector in header bar, allowing users to switch interface language"
"顶栏显示语言选择器,允许用户切换界面语言": "Show language selector in header bar, allowing users to switch interface language",
"All systems normal": "All systems normal",
"调用 AI 像调用函": "Call AI like calling a",
"函数": "function",
"一样轻。": "— that light.",
"把 OpenAI、Claude、Gemini、DeepSeek 等几十个模型收进同一个 base_url切换模型、改价格、改延迟不必动客户端。": "Bring OpenAI, Claude, Gemini, DeepSeek and dozens of other models behind a single base_url. Switch models, pricing, latency — no client changes.",
"免费注册": "Sign up free",
"联系销售": "Contact sales",
"注册即送 ¥10": "¥10 free credits on signup",
"无月费": "No monthly fee",
"比开放透明": "Transparent pricing",
"你的客户端只需一句": "Your client only needs one",
",其余的事——路由、价格、容灾——都替你做了。": ", and we handle routing, pricing, and failover for you.",
"立即接入。": "Integrate now.",
"注册送 ¥10 试用金,分键跑完一组 benchmark一拍压测。": "Get ¥10 trial credit on signup. Run a benchmark, then a load test.",
"定价": "Pricing"
}
}

View File

@ -5554,6 +5554,21 @@
"主题切换": "主题切换",
"顶栏显示主题切换按钮,允许用户切换亮色/暗色模式": "顶栏显示主题切换按钮,允许用户切换亮色/暗色模式",
"语言选择器": "语言选择器",
"顶栏显示语言选择器,允许用户切换界面语言": "顶栏显示语言选择器,允许用户切换界面语言"
"顶栏显示语言选择器,允许用户切换界面语言": "顶栏显示语言选择器,允许用户切换界面语言",
"All systems normal": "All systems normal",
"调用 AI 像调用函": "调用 AI 像调用函",
"函数": "函数",
"一样轻。": "一样轻。",
"把 OpenAI、Claude、Gemini、DeepSeek 等几十个模型收进同一个 base_url切换模型、改价格、改延迟不必动客户端。": "把 OpenAI、Claude、Gemini、DeepSeek 等几十个模型收进同一个 base_url切换模型、改价格、改延迟不必动客户端。",
"免费注册": "免费注册",
"联系销售": "联系销售",
"注册即送 ¥10": "注册即送 ¥10",
"无月费": "无月费",
"比开放透明": "比开放透明",
"你的客户端只需一句": "你的客户端只需一句",
",其余的事——路由、价格、容灾——都替你做了。": ",其余的事——路由、价格、容灾——都替你做了。",
"立即接入。": "立即接入。",
"注册送 ¥10 试用金,分键跑完一组 benchmark一拍压测。": "注册送 ¥10 试用金,分键跑完一组 benchmark一拍压测。",
"定价": "定价"
}
}

View File

@ -0,0 +1,364 @@
/*
Copyright (C) 2025 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import React, { useState } from 'react';
import { ArrowRight, Mail, MessageSquare, Building2, ShieldCheck, Check } from 'lucide-react';
import { Link } from 'react-router-dom';
const ACC = '#635BFF';
const ACC_SOFT = '#EEEBFF';
const BG = '#FFFFFF';
const SOFT = '#FBFAF7';
const TINT = '#F6F4FF';
const INK = '#0A2540';
const SUB = '#425466';
const DIM = '#697386';
const LINE = '#E3E8EE';
function Field({ label, value, onChange, type = 'text', required = false, placeholder = '' }) {
return (
<div>
<div className="mb-2 text-xs" style={{ color: DIM }}>
{label}{required && <span style={{ color: ACC }}> *</span>}
</div>
<input
type={type}
value={value}
onChange={onChange}
required={required}
placeholder={placeholder}
className="w-full rounded-lg border bg-white px-3.5 py-2.5 text-sm outline-none transition-colors focus:border-[#635BFF]"
style={{ borderColor: LINE, color: INK }}
/>
</div>
);
}
function InfoCard({ icon, title, primary, sub }) {
return (
<div
className="rounded-xl border bg-white p-5 transition-all hover:-translate-y-0.5 hover:shadow-sm"
style={{ borderColor: LINE }}
>
<div className="flex items-center gap-2.5">
<div
className="inline-flex h-8 w-8 items-center justify-center rounded-lg shrink-0"
style={{ background: ACC_SOFT, color: ACC }}
>
{icon}
</div>
<div className="text-sm font-semibold tracking-tight" style={{ color: INK }}>{title}</div>
</div>
<div className="mt-3.5 pl-[42px]">
<div className="text-[15px] font-medium" style={{ color: ACC }}>{primary}</div>
<div className="mt-1 text-xs leading-[1.6]" style={{ color: DIM }}>{sub}</div>
</div>
</div>
);
}
function MiniTopBar() {
return (
<header className="sticky top-0 z-50 border-b border-[#E3E8EE] bg-white/85 backdrop-blur-md">
<div className="flex h-16 items-center px-6 lg:px-10 max-w-[1200px] mx-auto">
<Link to="/" className="flex items-center gap-2.5">
<img src="/logo.jpg" alt="logo" className="h-7 w-7 rounded-full" />
<span className="font-heading text-[15px] font-semibold tracking-tight" style={{ color: INK }}>TuringToken</span>
</Link>
<div className="hidden md:flex items-center gap-2 ml-6 rounded-full px-2.5 py-1 text-[11px]" style={{ background: '#F6F9FC', color: DIM }}>
<span className="h-1.5 w-1.5 rounded-full bg-emerald-400" />
<span>服务正常 · 99.95%</span>
</div>
<div className="flex-1" />
<Link
to="/console"
className="inline-flex h-9 items-center rounded-full px-3.5 text-sm hover:bg-[#0A254006]"
style={{ color: SUB }}
>
控制台
</Link>
<Link
to="/register"
className="ml-2 inline-flex h-9 items-center gap-1.5 rounded-full px-4 text-sm font-medium text-white hover:opacity-90"
style={{ background: INK }}
>
免费注册 <ArrowRight size={12} />
</Link>
</div>
</header>
);
}
export default function Contact() {
const [form, setForm] = useState({
company: '',
name: '',
email: '',
volume: '',
message: '',
});
const update = (k) => (e) => setForm({ ...form, [k]: e.target.value });
const submit = (e) => {
e.preventDefault();
alert('已收到,我们会在 24 小时内联系你。');
};
return (
<div className="min-h-screen" style={{ background: BG, color: INK }}>
<MiniTopBar />
{/* Hero */}
<section className="relative overflow-hidden" style={{ background: BG }}>
<div
className="pointer-events-none absolute inset-x-0 top-0 h-[600px]"
style={{ background: 'radial-gradient(80% 60% at 50% 0%, #EEEBFF 0%, transparent 70%)' }}
/>
<div className="relative max-w-[1200px] mx-auto px-6 lg:px-10 pt-20 pb-14 lg:pt-28 lg:pb-20 text-center">
<div className="inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs" style={{ borderColor: LINE, color: DIM }}>
<span className="h-1.5 w-1.5 rounded-full" style={{ background: ACC }} />
<span>contact sales</span>
</div>
<h1
className="mt-6 font-heading font-semibold leading-[1.04] tracking-[-0.025em]"
style={{ fontSize: 'clamp(40px, 5.4vw, 72px)', color: INK }}
>
告诉我们<br />
你的 <span style={{ color: ACC }}>AI 场景</span>
</h1>
<p className="mt-6 mx-auto max-w-2xl text-base leading-[1.65]" style={{ color: SUB }}>
大客户定制路由长期合约技术对接 都从这里开始
</p>
<div className="mt-8 flex flex-wrap items-center justify-center gap-6 text-xs" style={{ color: DIM }}>
<span className="inline-flex items-center gap-1.5">
<Check size={12} style={{ color: ACC }} /> 24 小时内回复
</span>
<span className="inline-flex items-center gap-1.5">
<Check size={12} style={{ color: ACC }} /> 可签 NDA
</span>
<span className="inline-flex items-center gap-1.5">
<Check size={12} style={{ color: ACC }} /> 无电销骚扰
</span>
</div>
</div>
</section>
{/* Form + Info */}
<section style={{ background: BG }}>
<div className="max-w-[1200px] mx-auto px-6 lg:px-10 pb-24">
<div className="grid gap-8 lg:grid-cols-[1.4fr_1fr]">
{/* Form */}
<form
onSubmit={submit}
className="rounded-2xl border bg-white p-8 lg:p-10 shadow-sm"
style={{ borderColor: LINE }}
>
<div className="font-mono text-[11px] uppercase tracking-[0.25em]" style={{ color: DIM }}>get in touch</div>
<h2
className="mt-4 font-heading text-2xl font-semibold leading-[1.2] tracking-tight lg:text-[32px]"
style={{ color: INK }}
>
填一下<br />我们 24h 内联系你
</h2>
<div className="mt-8 grid gap-5 md:grid-cols-2">
<Field label="公司名" value={form.company} onChange={update('company')} required />
<Field label="你的姓名" value={form.name} onChange={update('name')} required />
</div>
<div className="mt-5">
<Field
label="工作邮箱"
type="email"
value={form.email}
onChange={update('email')}
required
placeholder="you@company.com"
/>
</div>
<div className="mt-5">
<div className="mb-2 text-xs" style={{ color: DIM }}>月调用量</div>
<div className="relative">
<select
value={form.volume}
onChange={update('volume')}
className="w-full appearance-none rounded-lg border bg-white pl-3.5 pr-9 py-2.5 text-sm outline-none transition-colors focus:border-[#635BFF]"
style={{ borderColor: LINE, color: form.volume ? INK : DIM }}
>
<option value="">选择大致量级</option>
<option>10 万以下</option>
<option>10 100 </option>
<option>100 1000 </option>
<option>1000 万以上</option>
<option>暂未确定</option>
</select>
<span className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-xs" style={{ color: DIM }}></span>
</div>
</div>
<div className="mt-5">
<div className="mb-2 text-xs" style={{ color: DIM }}>你的场景</div>
<textarea
value={form.message}
onChange={update('message')}
rows={4}
placeholder="例如:做企业知识库客服,需要稳定的 Claude + 国产模型双备援,月调用量约 300 万..."
className="w-full rounded-lg border bg-white px-3.5 py-2.5 text-sm outline-none transition-colors focus:border-[#635BFF] resize-y"
style={{ borderColor: LINE, color: INK }}
/>
</div>
<div className="mt-7 flex flex-wrap items-center gap-4">
<button
type="submit"
className="inline-flex h-11 items-center gap-2 rounded-full px-6 text-sm font-semibold text-white hover:opacity-90"
style={{ background: INK }}
>
发送 <ArrowRight size={13} />
</button>
<span className="text-xs" style={{ color: DIM }}>
提交即同意我们通过邮箱回访仅一次
</span>
</div>
</form>
{/* Info side */}
<div className="space-y-4">
<InfoCard
icon={<Mail size={16} />}
title="销售咨询"
primary="sales@turingtoken.ai"
sub="工作日 24h 内回复;加急请电话"
/>
<InfoCard
icon={<MessageSquare size={16} />}
title="技术支持"
primary="support@turingtoken.ai"
sub="已签合约客户优先P0 故障 1h 响应"
/>
<InfoCard
icon={<ShieldCheck size={16} />}
title="法务 / NDA"
primary="legal@turingtoken.ai"
sub="签前可先发 NDA 模板,含双向保密"
/>
<InfoCard
icon={<Building2 size={16} />}
title="办公室"
primary="上海 · 北京 · 深圳"
sub="仅预约接待,不接受 walk-in"
/>
</div>
</div>
</div>
</section>
{/* FAQ */}
<section style={{ background: SOFT }}>
<div className="max-w-[1100px] mx-auto px-6 lg:px-10 py-24 lg:py-32">
<div className="text-center">
<div className="font-mono text-[11px] uppercase tracking-[0.25em]" style={{ color: DIM }}>frequently asked</div>
<h2
className="mt-4 font-heading text-3xl font-semibold tracking-tight lg:text-4xl"
style={{ color: INK }}
>
常见问题
</h2>
</div>
<div className="mt-14 grid gap-5 md:grid-cols-2">
{[
{
q: '支持私有化部署吗?',
a: '支持。签约后 24 周内完成含多模型路由、监控面板、计费、权限管理、SSO。',
},
{
q: '大客户有专属价格吗?',
a: '月调用量 100 万以上可谈。多数客户能拿到比 OpenAI 直连便宜 30%+ 的合约价。',
},
{
q: '能签长期合约吗?',
a: '可以。年付 / 季付都支持,附 SLA 99.95% 兜底,故障按比例退款。',
},
{
q: '数据合规怎么做?',
a: '全链路 TLS 1.3;境内流量走国内供应商;日志 30 天滚动删除;支持 GDPR 与个保法。',
},
].map((f, i) => (
<div
key={i}
className="rounded-xl border bg-white p-6"
style={{ borderColor: LINE }}
>
<h3 className="font-heading text-lg font-semibold tracking-tight" style={{ color: INK }}>{f.q}</h3>
<p className="mt-3 text-sm leading-[1.7]" style={{ color: SUB }}>{f.a}</p>
</div>
))}
</div>
</div>
</section>
{/* Closing */}
<section className="relative overflow-hidden" style={{ background: BG }}>
<div
className="pointer-events-none absolute inset-x-0 bottom-0 h-[400px]"
style={{ background: 'radial-gradient(60% 60% at 50% 100%, #EEEBFF 0%, transparent 70%)' }}
/>
<div className="relative mx-auto max-w-3xl px-6 lg:px-10 py-24 lg:py-32 text-center">
<h2
className="font-heading text-3xl font-semibold leading-tight tracking-[-0.02em] lg:text-[44px]"
style={{ color: INK }}
>
先用起来再聊
</h2>
<p className="mt-5 text-base leading-[1.7]" style={{ color: SUB }}>
注册送 ¥10 试跑金足够跑完一组 benchmark一轮压测聊完再决定也不迟
</p>
<div className="mt-9 flex flex-wrap items-center justify-center gap-3">
<Link
to="/register"
className="inline-flex h-11 items-center gap-2 rounded-full px-6 text-sm font-semibold text-white hover:opacity-90"
style={{ background: INK }}
>
免费注册 <ArrowRight size={13} />
</Link>
<Link
to="/"
className="inline-flex h-11 items-center gap-1.5 rounded-full border px-6 text-sm hover:bg-[#0A254006]"
style={{ borderColor: INK, color: INK }}
>
先看首页
</Link>
</div>
</div>
</section>
{/* Footer */}
<footer className="border-t" style={{ borderColor: LINE, background: BG }}>
<div className="max-w-[1200px] mx-auto px-6 lg:px-10 py-12">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<Link to="/" className="inline-flex items-center gap-2.5">
<img src="/logo.jpg" alt="logo" className="h-7 w-7 rounded-full" />
<span className="font-heading text-base font-semibold tracking-tight" style={{ color: INK }}>TuringToken</span>
</Link>
<span className="text-xs" style={{ color: DIM }}>© 2026 TuringToken · Made for developers.</span>
</div>
</div>
</footer>
</div>
);
}

View File

@ -1,4 +1,4 @@
/*
/*
Copyright (C) 2025 QuantumNous
This program is free software: you can redistribute it and/or modify
@ -17,220 +17,186 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import React, { useState, useEffect, useCallback, useRef, useContext } from 'react';
import React, { useState, useContext, useCallback } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Copy, Check, Code, Terminal, FileCode, Box, Grid3X3, Play, Trophy, PieChart, BookOpen, Search, Sun, Moon, Monitor, Languages } from 'lucide-react';
import { Copy, Check, ArrowRight, Terminal, Box, Trophy, BookOpen, Grid3X3 } from 'lucide-react';
import { UserContext } from '../../context/User';
import { StatusContext } from '../../context/Status';
import { stringToColor, getSystemName } from '../../helpers';
/* ==================================================================
TokenDance-style Home Page
Design: black/white minimal with serif headings
Light-themed Home Page
Design: clean white with purple accents
================================================================== */
/* ─── Hero Marquee Carousel Texts ────────────────────────── */
const CAROUSEL_TEXTS = [
'OpenAI 协议',
'Claude 协议',
'Gemini 协议',
'智能路由',
'统一计费',
'模型丰富',
'安全可靠',
'开箱即用',
];
const ACC = '#635BFF';
const ACC_SOFT = '#EEEBFF';
const BG = '#FFFFFF';
const SOFT = '#FBFAF7';
const TINT = '#F6F4FF';
const INK = '#0A2540';
const SUB = '#425466';
const DIM = '#697386';
const LINE = '#E3E8EE';
/* ─── Hero Section ──────────────────────────────────────────── */
/* ─── NavBar ────────────────────────────────────────────────── */
/* --- Helper: Theme Toggle --- */
function HomeThemeToggle() {
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const ref = useRef(null);
useEffect(() => {
if (!open) return;
const handler = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
document.addEventListener("mousedown", handler);
return () => document.removeEventListener("mousedown", handler);
}, [open]);
const theme = localStorage.getItem("theme-mode") || "auto";
const applyTheme = useCallback((val) => {
const actualTheme = val === 'auto'
? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
: val;
if (actualTheme === 'dark') {
document.body.setAttribute('theme-mode', 'dark');
document.documentElement.classList.add('dark');
} else {
document.body.removeAttribute('theme-mode');
document.documentElement.classList.remove('dark');
}
}, []);
const setTheme = (val) => {
localStorage.setItem("theme-mode", val);
applyTheme(val);
setOpen(false);
};
useEffect(() => {
applyTheme(theme);
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handleChange = () => {
const stored = localStorage.getItem("theme-mode") || "auto";
applyTheme(stored);
};
mediaQuery.addEventListener('change', handleChange);
return () => mediaQuery.removeEventListener('change', handleChange);
}, [applyTheme]);
const icons = { light: <Sun size={16} />, dark: <Moon size={16} />, auto: <Monitor size={16} /> };
return (
<div className="relative" ref={ref}>
<button type="button" onClick={() => setOpen(!open)} className="inline-flex items-center justify-center p-2 rounded-md text-white/60 hover:text-white hover:bg-white/10 transition-colors">
{icons[theme] || icons.auto}
</button>
{open && (
<div className="absolute right-0 top-full mt-1 z-50 min-w-[10rem] rounded-lg border border-white/10 bg-neutral-900 p-1 shadow-md">
{[
{ key: "light", icon: <Sun size={16} />, label: t("浅色模式") },
{ key: "dark", icon: <Moon size={16} />, label: t("深色模式") },
{ key: "auto", icon: <Monitor size={16} />, label: t("自动模式") },
].map((opt) => (
<button key={opt.key} type="button" onClick={() => setTheme(opt.key)} className={`flex w-full items-center gap-2 rounded-md px-2.5 py-2 text-sm transition-colors ${theme === opt.key ? "bg-white/10 text-white font-medium" : "text-white/50 hover:bg-white/10 hover:text-white"}`}>
{opt.icon}<span>{opt.label}</span>
{theme === opt.key && <span className="ml-auto flex h-3.5 w-3.5 items-center justify-center"><span className="h-1.5 w-1.5 rounded-full bg-white"></span></span>}
</button>
))}
</div>
)}
</div>
);
}
/* --- Helper: Language Selector --- */
function HomeLanguageSelector() {
const { t, i18n } = useTranslation();
const [open, setOpen] = useState(false);
const ref = useRef(null);
useEffect(() => {
if (!open) return;
const handler = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
document.addEventListener("mousedown", handler);
return () => document.removeEventListener("mousedown", handler);
}, [open]);
const current = (i18n.language || "").startsWith("zh") ? "zh-CN" : "en";
const switchLang = (code) => { i18n.changeLanguage(code); setOpen(false); };
const langLabels = { "zh-CN": "简体中文", "en": "English" };
return (
<div className="relative" ref={ref}>
<button type="button" onClick={() => setOpen(!open)} className="inline-flex items-center gap-1 rounded-md px-2 py-1.5 text-sm text-white/60 hover:text-white hover:bg-white/10 transition-colors">
<Languages size={16} /><span className="hidden sm:inline text-xs">{langLabels[current] || current}</span>
</button>
{open && (
<div className="absolute right-0 top-full mt-1 z-50 min-w-[8rem] rounded-lg border border-white/10 bg-neutral-900 p-1 shadow-md">
{Object.entries(langLabels).map(([code, label]) => (
<button key={code} type="button" onClick={() => switchLang(code)} className={`flex w-full items-center rounded-md px-2.5 py-1.5 text-sm transition-colors ${current === code ? "bg-white/10 text-white font-medium" : "text-white/50 hover:bg-white/10 hover:text-white"}`}>
{label}
{current === code && <span className="ml-auto flex h-3.5 w-3.5 items-center justify-center"><span className="h-1.5 w-1.5 rounded-full bg-white"></span></span>}
</button>
))}
</div>
)}
</div>
);
}
function HeroSection() {
function HomeNavBar() {
const { t } = useTranslation();
const [userState] = useContext(UserContext);
const [statusState] = useContext(StatusContext);
const [copied, setCopied] = useState(false);
const navigate = useNavigate();
// true status
const showThemeToggle = statusState?.status?.HeaderShowThemeToggle !== false;
const showLanguageSelector = statusState?.status?.HeaderShowLanguageSelector !== false;
const copyCmd = useCallback(() => {
navigator.clipboard.writeText("https://tokendance.space");
setCopied(true);
setTimeout(() => setCopied(false), 1500);
}, []);
return (
<section className="relative bg-black text-white overflow-hidden">
<div className="absolute inset-0 pointer-events-none opacity-[0.04]" style={{ backgroundImage: "radial-gradient(circle, white 1px, transparent 1px)", backgroundSize: "24px 24px" }} />
<div className="fixed top-0 z-50 w-full border-b border-white/10 bg-black">
<div className="flex h-14 items-center px-4 lg:px-6 max-w-[1400px] mx-auto">
<Link to="/" className="flex items-center gap-2 flex-shrink-0">
<img src="/logo.jpg" alt="logo" className="w-7 h-7 rounded-full object-cover" />
<span className="font-heading text-lg font-bold tracking-tight text-white">TuringToken</span>
<span className="text-[10px] font-mono px-1.5 py-0.5 rounded border border-white/20 text-white/40">BETA</span>
<header className="sticky top-0 z-50 border-b bg-white/85 backdrop-blur-md" style={{ borderColor: LINE }}>
<div className="flex h-16 items-center px-6 lg:px-10 max-w-[1400px] mx-auto">
<Link to="/" className="flex items-center gap-2.5">
<img src="/logo.jpg" alt="logo" className="h-7 w-7 rounded-full" />
<span className="font-heading text-[15px] font-semibold tracking-tight" style={{ color: INK }}>TuringToken</span>
<span className="text-[10px] font-mono px-1.5 py-0.5 rounded border" style={{ borderColor: LINE, color: DIM }}>BETA</span>
</Link>
<div className="hidden md:block flex-1" />
<div className="hidden md:flex items-center gap-2 ml-6 rounded-full px-2.5 py-1 text-[11px]" style={{ background: '#F6F9FC', color: DIM }}>
<span className="h-1.5 w-1.5 rounded-full bg-emerald-400" />
<span>{t('All systems normal')}</span>
</div>
<div className="flex-1" />
<nav className="hidden md:flex items-center gap-0.5">
{[
{ key: "model", label: "模型", icon: <Box size={16} />, to: "/pricing" },
{ key: "benchmark", label: "评测", icon: <Trophy size={16} />, to: "/benchmarks" },
{ key: "docs", label: "文档", icon: <BookOpen size={16} />, to: "/docs" },
{ key: "console", label: "控制台", icon: <Grid3X3 size={16} />, to: "/console" },
{ key: 'model', label: t('定价'), icon: <Box size={16} />, to: '/pricing' },
{ key: 'benchmark', label: t('评测'), icon: <Trophy size={16} />, to: '/benchmarks' },
{ key: 'docs', label: t('文档'), icon: <BookOpen size={16} />, to: '/docs' },
{ key: 'console', label: t('控制台'), icon: <Grid3X3 size={16} />, to: '/console' },
].map((item) => (
<Link key={item.key} to={item.to} className="inline-flex items-center gap-1.5 px-3 py-1.5 text-[14px] rounded-md transition-colors duration-150 text-white/60 hover:text-white">{item.icon}<span className="hidden sm:inline">{t(item.label)}</span></Link>
<Link key={item.key} to={item.to} className="inline-flex items-center gap-1.5 px-3 py-1.5 text-[14px] rounded-md transition-colors duration-150 hover:bg-[#0A254008]" style={{ color: SUB }}>
{item.icon}<span className="hidden sm:inline">{item.label}</span>
</Link>
))}
</nav>
<div className="flex items-center gap-1">
{showThemeToggle && <HomeThemeToggle />}
{showLanguageSelector && <HomeLanguageSelector />}
<div className="flex items-center ml-4">
{userState.user ? (
<Link to="/console" className="inline-flex items-center justify-center w-8 h-8 rounded-full hover:bg-white/20 border border-white/20 transition-colors duration-200 ml-2" title={userState.user.display_name || userState.user.username}>
<Link to="/console" className="inline-flex items-center justify-center w-8 h-8 rounded-full hover:bg-black/5 border transition-colors duration-200" style={{ borderColor: LINE }} title={userState.user.display_name || userState.user.username}>
<span className="w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold text-white" style={{ backgroundColor: stringToColor(userState.user.username) }}>
{userState.user.username?.charAt(0).toUpperCase()}
</span>
</Link>
) : (
<Link to="/login" className="inline-flex items-center bg-white text-black px-4 py-1.5 text-sm font-mono font-medium uppercase tracking-widest rounded hover:bg-transparent hover:text-white border border-white transition-colors duration-200 ml-2">
{t("登录")}
<Link
to="/login"
className="inline-flex h-9 items-center rounded-full px-4 text-sm font-medium text-white hover:opacity-90"
style={{ background: INK }}
>
{t('登录')}
</Link>
)}
</div>
</div>
</div>
<div className="relative flex-1 grid md:grid-cols-2 gap-8 px-6 md:px-12 pt-[88px] pb-12 items-center max-w-[1400px] mx-auto w-full" style={{ minHeight: "90vh" }}>
</header>
);
}
/* ─── Hero Section ──────────────────────────────────────────── */
function HeroSection() {
const { t } = useTranslation();
const navigate = useNavigate();
const [userState] = useContext(UserContext);
const [copied, setCopied] = useState(false);
const copyCmd = useCallback(() => {
navigator.clipboard.writeText('https://api.turingtoken.ai');
setCopied(true);
setTimeout(() => setCopied(false), 1500);
}, []);
return (
<section className="relative overflow-hidden" style={{ background: BG }}>
{/* Subtle purple center glow */}
<div
className="pointer-events-none absolute inset-x-0 top-0 h-[700px]"
style={{ background: `radial-gradient(60% 60% at 50% 0%, ${ACC_SOFT} 0%, transparent 70%)` }}
/>
<div className="relative max-w-[1400px] mx-auto px-6 lg:px-10 pt-20 pb-8 lg:pt-28 lg:pb-12">
<div className="grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
{/* Left: Text */}
<div className="home-fade-in">
<p className="font-mono text-sm text-white/30 mb-6 tracking-wide font-body">
{"// unified model API gateway"}
</p>
<div className="w-[60px] h-[4px] bg-white mb-6" />
<h1 className="font-heading text-3xl sm:text-5xl md:text-6xl lg:text-7xl font-bold leading-[1.1] mb-6">
{t("更快、更稳、更省")}<br />{t("Token服务平台")}
<div className="inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs mb-8" style={{ borderColor: LINE, color: DIM }}>
<span className="h-1.5 w-1.5 rounded-full" style={{ background: ACC }} />
<span>{t('All systems normal')}</span>
</div>
<h1
className="font-heading font-semibold leading-[1.08] tracking-[-0.025em] mb-6"
style={{ fontSize: 'clamp(36px, 5vw, 64px)', color: INK }}
>
{t('调用 AI 像调用函')}
<span style={{ color: ACC }}>{t('函数')}</span>
{t('一样轻。')}
</h1>
<p className="font-body text-white/50 text-base md:text-lg leading-relaxed mb-10">
{t("兼容 OpenAI / Claude / Gemini 等协议,覆盖文本、图像、视频、语音,智能路由,统一计费。")}
<p className="text-base md:text-lg leading-[1.65] mb-8 max-w-xl" style={{ color: SUB }}>
{t('把 OpenAI、Claude、Gemini、DeepSeek 等几十个模型收进同一个 base_url切换模型、改价格、改延迟不必动客户端。')}
</p>
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-3 sm:gap-4 font-body">
<Link to="/console/token" className="inline-flex items-center bg-white text-black px-6 py-3 text-sm font-mono font-medium uppercase tracking-widest hover:bg-transparent hover:text-white border border-white transition-colors duration-200">
{t("开始使用")}
<div className="flex flex-wrap items-center gap-3 mb-8">
{userState.user ? (
<Link
to="/console/token"
className="inline-flex h-11 items-center gap-2 rounded-full px-6 text-sm font-semibold text-white hover:opacity-90"
style={{ background: INK }}
>
{t('开始使用')} <ArrowRight size={14} />
</Link>
<Link to="/pricing" className="inline-flex items-center text-white/60 px-6 py-3 text-sm font-mono font-medium uppercase tracking-widest hover:text-white transition-colors duration-200">
{t("查看价格")} &rarr;
) : (
<Link
to="/register"
className="inline-flex h-11 items-center gap-2 rounded-full px-6 text-sm font-semibold text-white hover:opacity-90"
style={{ background: INK }}
>
{t('免费注册')} <ArrowRight size={14} />
</Link>
)}
<Link
to="/contact"
className="inline-flex h-11 items-center gap-1.5 rounded-full border px-6 text-sm font-medium hover:bg-[#0A254006]"
style={{ borderColor: INK, color: INK }}
>
{t('联系销售')}
</Link>
</div>
<div className="flex flex-wrap items-center gap-5 text-xs" style={{ color: DIM }}>
<span className="inline-flex items-center gap-1.5">
<span className="h-1.5 w-1.5 rounded-full" style={{ background: '#10b981' }} />
{t('注册即送 ¥10')}
</span>
<span className="inline-flex items-center gap-1.5">
<span className="h-1.5 w-1.5 rounded-full" style={{ background: ACC }} />
{t('无月费')}
</span>
<span className="inline-flex items-center gap-1.5">
<span className="h-1.5 w-1.5 rounded-full" style={{ background: '#f59e0b' }} />
{t('比开放透明')}
</span>
</div>
<div className="home-fade-in-delay-1 font-body">
<div className="bg-neutral-900 border border-white/10 rounded-none overflow-hidden">
<div className="flex items-center justify-between px-4 py-2.5 border-b border-white/10 bg-neutral-800/50">
</div>
{/* Right: Code Example */}
<div className="home-fade-in-delay-1">
<div className="rounded-2xl border bg-white overflow-hidden shadow-sm" style={{ borderColor: LINE }}>
<div className="flex items-center justify-between px-4 py-2.5 border-b" style={{ borderColor: LINE, background: '#F9FAFB' }}>
<div className="flex gap-1.5">
<span className="w-3 h-3 rounded-full bg-red-500/60" />
<span className="w-3 h-3 rounded-full bg-yellow-500/60" />
<span className="w-3 h-3 rounded-full bg-green-500/60" />
<span className="w-3 h-3 rounded-full bg-red-400/60" />
<span className="w-3 h-3 rounded-full bg-yellow-400/60" />
<span className="w-3 h-3 rounded-full bg-green-400/60" />
</div>
<span className="font-mono text-[10px] text-white/20 tracking-wide">terminal</span>
<button type="button" onClick={copyCmd} className="text-white/30 hover:text-white/70 transition-colors" aria-label="Copy">
<span className="font-mono text-[10px] tracking-wide" style={{ color: DIM }}>terminal</span>
<button type="button" onClick={copyCmd} className="hover:opacity-70 transition-opacity" style={{ color: DIM }} aria-label="Copy">
{copied ? <Check size={14} /> : <Copy size={14} />}
</button>
</div>
<pre className="p-5 text-sm font-mono leading-relaxed text-white/80 overflow-x-auto">
<code>{`curl https://api.turingtoken.ai/v1/chat/completions \\
-H "Authorization: Bearer \$YOUR_API_KEY" \\
<pre className="p-5 text-sm font-mono leading-relaxed overflow-x-auto" style={{ color: INK, background: '#1e1e2e' }}>
<code className="text-[#cdd6f4]">{`curl https://api.turingtoken.ai/v1/chat/completions \\
-H "Authorization: Bearer $YOUR_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"model": "gpt-4o",
@ -238,70 +204,61 @@ function HeroSection() {
}'`}</code>
</pre>
</div>
<p className="mt-5 text-sm leading-[1.6]" style={{ color: DIM }}>
{t('你的客户端只需一句')}
<code className="mx-1 px-1.5 py-0.5 rounded text-xs font-mono" style={{ background: TINT, color: ACC }}>base_url</code>
{t(',其余的事——路由、价格、容灾——都替你做了。')}
</p>
</div>
</div>
</div>
{/* Hero brand wordmark — TURINGTOKEN */}
<div className="w-full overflow-hidden px-6 pb-2">
{/* Dark brand wordmark strip */}
<div className="w-full overflow-hidden border-t" style={{ borderColor: LINE, background: INK }}>
<div
className="inline-flex whitespace-nowrap origin-left font-mono font-bold uppercase leading-[0.85] select-none tracking-tight"
style={{ fontSize: 'clamp(4rem, 20vw, 12rem)', transform: 'scaleX(1.04)' }}
className="inline-flex whitespace-nowrap origin-left font-mono font-bold uppercase leading-[0.85] select-none tracking-tight py-8 px-6"
style={{ fontSize: 'clamp(3rem, 16vw, 10rem)', transform: 'scaleX(1.04)' }}
>
<span className="text-white">Turing</span>
<span className="text-white/30" style={{ textShadow: '0 0 30px rgba(255,255,255,0.15), 4px 4px 12px rgba(0,0,0,0.5)' }}>Token</span>
</div>
</div>
{/* Feature marquee strip — 轮播: OpenAI 协议 / Claude 协议 / 智能路由 ... */}
<div className="w-full border-t border-white/10 py-5 px-6 overflow-hidden">
<div className="home-marquee flex gap-12 items-center">
{[...CAROUSEL_TEXTS, ...CAROUSEL_TEXTS].map((text, i) => (
<span
key={i}
className="font-mono text-sm text-white/40 whitespace-nowrap tracking-wider"
>
{text}
</span>
))}
</div>
</div>
</section>
);
}const FEATURES = [
}
/* ─── Features Section ──────────────────────────────────────── */
const FEATURES = [
{
titleKey: '多协议兼容',
descKey:
'原生支持 OpenAI、Claude、Gemini 文本协议,覆盖图像 / 视频 / 文本转语音生成。无需修改代码,切换 Base URL 即可接入。',
descKey: '原生支持 OpenAI、Claude、Gemini 文本协议,覆盖图像 / 视频 / 文本转语音生成。无需修改代码,切换 Base URL 即可接入。',
code: 'baseURL: "api.turingtoken.ai"',
},
{
titleKey: '智能路由',
descKey:
'根据模型名称自动路由至对应供应商。一个入口,无需关心底层调度。',
descKey: '根据模型名称自动路由至对应供应商。一个入口,无需关心底层调度。',
code: 'route(model) → provider',
},
{
titleKey: '统一计费',
descKey:
'跨供应商统一 Token 消耗统计与账单。告别多平台分别充值的混乱。',
descKey: '跨供应商统一 Token 消耗统计与账单。告别多平台分别充值的混乱。',
code: 'billing.unified()',
},
{
titleKey: '容错降级',
descKey:
'同一模型支持多供应商端点自动切换;单次请求可指定多个候选模型,逐级降级,保障服务持续可用。',
descKey: '同一模型支持多供应商端点自动切换;单次请求可指定多个候选模型,逐级降级,保障服务持续可用。',
code: 'fallback: model[] → provider[]',
},
{
titleKey: '模型丰富',
descKey:
'接入 MiniMax、通义千问、Kimi、智谱、DeepSeek 等国内头部模型。持续扩展中。',
descKey: '接入 MiniMax、通义千问、Kimi、智谱、DeepSeek 等国内头部模型。持续扩展中。',
code: 'models.list() → 80+',
},
{
titleKey: '开箱即用',
descKey:
'一键登录,分钟级接入。兼容现有 SDK零迁移成本。',
descKey: '一键登录,分钟级接入。兼容现有 SDK零迁移成本。',
code: 'import OpenAI from "openai"',
},
];
@ -309,27 +266,28 @@ function HeroSection() {
function FeaturesSection() {
const { t } = useTranslation();
return (
<section id="features" className="py-24 px-6">
<section className="py-24 px-6 lg:px-10" style={{ background: BG }}>
<div className="max-w-6xl mx-auto">
<p className="font-mono text-xs text-muted-foreground tracking-widest uppercase mb-3">
{/* features */}
</p>
<h2 className="font-heading text-3xl font-bold md:text-4xl tracking-tight mb-16 text-foreground">
<div className="font-mono text-[11px] tracking-[0.25em] uppercase mb-3" style={{ color: DIM }}>
{'// features'}
</div>
<h2 className="font-heading text-3xl font-bold md:text-4xl tracking-tight mb-16" style={{ color: INK }}>
{t('为接入 AI 模型的开发者而造。')}
</h2>
<div className="grid sm:grid-cols-2 lg:grid-cols-3">
{FEATURES.map((f, i) => (
<div
key={i}
className="group p-8 flex flex-col transition-all duration-200 hover:bg-foreground hover:text-background border-b sm:border-r border-border"
className="group p-8 flex flex-col transition-all duration-200 hover:bg-[#0A2540] border-b sm:border-r"
style={{ borderColor: LINE }}
>
<code className="inline-block text-xs mb-4 font-mono border border-foreground/10 px-2 py-1 w-fit group-hover:border-background/30 group-hover:text-background transition-all duration-200">
<code className="inline-block text-xs mb-4 font-mono border px-2 py-1 w-fit rounded group-hover:border-white/30 group-hover:text-white/80 transition-all duration-200" style={{ borderColor: LINE, color: DIM }}>
{f.code}
</code>
<h3 className="font-heading text-lg font-bold mb-2 text-foreground group-hover:text-background transition-all duration-200">
<h3 className="font-heading text-lg font-bold mb-2 group-hover:text-white transition-all duration-200" style={{ color: INK }}>
{t(f.titleKey)}
</h3>
<p className="text-sm text-muted-foreground leading-relaxed group-hover:text-background/70 transition-all duration-200">
<p className="text-sm leading-relaxed group-hover:text-white/60 transition-all duration-200" style={{ color: SUB }}>
{t(f.descKey)}
</p>
</div>
@ -340,422 +298,76 @@ function FeaturesSection() {
);
}
/* ─── How It Works Section ──────────────────────────────────── */
/* ─── CTA Section ───────────────────────────────────────────── */
const STEPS = [
{
step: '01',
titleKey: '注册账号',
descKey: '通过邮箱一键注册,即刻开始使用。',
link: '/register',
},
{
step: '02',
titleKey: '创建 API Key',
descKey: '在控制台创建密钥,支持多 Key 管理与权限控制。',
link: '/console/token',
},
{
step: '03',
titleKey: '发起请求',
descKey: '使用你熟悉的 SDK 调用任意模型,完全兼容原生协议。',
link: '/pricing',
},
];
function HowItWorksSection() {
function CTASection() {
const { t } = useTranslation();
return (
<section
id="how-it-works"
className="border-y-4 border-border"
<section className="relative overflow-hidden" style={{ background: BG }}>
<div
className="pointer-events-none absolute inset-x-0 bottom-0 h-[400px]"
style={{ background: `radial-gradient(60% 60% at 50% 100%, ${ACC_SOFT} 0%, transparent 70%)` }}
/>
<div className="relative mx-auto max-w-3xl px-6 lg:px-10 py-24 lg:py-32 text-center">
<h2
className="font-heading text-3xl font-semibold leading-tight tracking-[-0.02em] lg:text-[44px] mb-5"
style={{ color: INK }}
>
<div className="max-w-5xl mx-auto">
<div className="px-6 md:px-12 pt-24 pb-12">
<div className="font-mono text-xs text-muted-foreground tracking-widest uppercase mb-3">
{'// how it works'}
</div>
<h2 className="font-heading text-3xl font-bold md:text-4xl tracking-tight text-foreground">
{t('三步接入,分钟级上线')}
{t('立即接入。')}
</h2>
</div>
{STEPS.map((s, i) => (
<Link
key={i}
to={s.link}
className={`group block border-t border-border ${
i === STEPS.length - 1 ? 'border-b border-border' : ''
} hover:bg-foreground transition-all duration-200`}
>
<div className="grid md:grid-cols-[120px_1fr_auto] gap-0 items-center">
<div className="px-6 md:px-12 py-8 md:border-r border-border group-hover:border-background/10 flex items-baseline transition-all duration-200">
<span className="font-mono text-5xl md:text-6xl font-bold text-muted-foreground/30 group-hover:text-background leading-none transition-all duration-200">
{s.step}
</span>
</div>
<div className="px-6 md:px-12 py-8">
<h3 className="font-mono text-lg font-bold uppercase tracking-wide mb-2 text-foreground group-hover:text-background transition-all duration-200">
{t(s.titleKey)}
</h3>
<p className="text-sm text-muted-foreground group-hover:text-background/50 transition-all duration-200">
{t(s.descKey)}
<p className="text-base leading-[1.7] mb-9" style={{ color: SUB }}>
{t('注册送 ¥10 试用金,分键跑完一组 benchmark一拍压测。')}
</p>
</div>
<span className="hidden md:block pr-8 font-mono text-xl text-muted-foreground/30 group-hover:text-background transition-all duration-200">
&rarr;
</span>
</div>
</Link>
))}
</div>
</section>
);
}
/* ─── Quick Start Section (Code Tabs) ───────────────────────── */
const PROVIDERS = ['openai', 'claude', 'gemini'];
const PROVIDER_LABELS = { openai: 'OpenAI', claude: 'Claude', gemini: 'Gemini' };
const LANGUAGES = ['curl', 'python', 'nodejs'];
const LANG_LABELS = { curl: 'cURL', python: 'Python', nodejs: 'Node.js' };
const CODE_SAMPLES = {
openai: {
curl: `curl https://api.turingtoken.ai/v1/chat/completions \\
-H "Authorization: Bearer $OPENAI_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "Hello!"}]
}'`,
python: `from openai import OpenAI
client = OpenAI(
base_url="https://api.turingtoken.ai",
api_key="sk-your-key"
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)`,
nodejs: `import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.turingtoken.ai",
apiKey: "sk-your-key",
});
const response = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello!" }],
});
console.log(response.choices[0].message.content);`,
},
claude: {
curl: `curl https://api.turingtoken.ai/v1/messages \\
-H "x-api-key: sk-your-key" \\
-H "anthropic-version: 2023-06-01" \\
-H "Content-Type: application/json" \\
-d '{
"model": "claude-sonnet-4-20250514",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello!"}]
}'`,
python: `import anthropic
client = anthropic.Anthropic(
base_url="https://api.turingtoken.ai",
api_key="sk-your-key"
)
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}]
)
print(response.content[0].text)`,
nodejs: `import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
baseURL: "https://api.turingtoken.ai",
apiKey: "sk-your-key",
});
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello!" }],
});
console.log(response.content[0].text);`,
},
gemini: {
curl: `curl "https://api.turingtoken.ai/v1beta/models/gemini-2.0-flash:generateContent?key=sk-your-key" \\
-H "Content-Type: application/json" \\
-d '{
"contents": [{"parts":[{"text": "Hello!"}]}]
}'`,
python: `import google.generativeai as genai
genai.configure(api_key="sk-your-key")
model = genai.GenerativeModel("gemini-2.0-flash")
response = model.generate_content("Hello!")
print(response.text)`,
nodejs: `import { GoogleGenerativeAI } from "@google/generative-ai";
const genAI = new GoogleGenerativeAI("sk-your-key");
const model = genAI.getGenerativeModel({
model: "gemini-2.0-flash",
});
const result = await model.generateContent("Hello!");
console.log(result.response.text());`,
},
};
function QuickStartSection() {
const { t } = useTranslation();
const [provider, setProvider] = useState('openai');
const [lang, setLang] = useState('curl');
const [copied, setCopied] = useState(false);
const code = CODE_SAMPLES[provider]?.[lang] || '';
const handleCopy = useCallback(() => {
navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
}, [code]);
return (
<section id="quick-start" className="px-6 py-16">
<div className="max-w-4xl mx-auto">
<p className="font-mono text-xs text-muted-foreground tracking-widest uppercase mb-2">
Quick Start
</p>
<h2 className="font-heading text-2xl font-bold mb-8 text-foreground">
{t('快速开始')}
</h2>
{/* Provider tabs */}
<div className="flex gap-0 mb-0">
{PROVIDERS.map((p) => (
<button
key={p}
type="button"
onClick={() => setProvider(p)}
className={`font-mono text-sm px-4 py-2 transition-all duration-200 ${
provider === p
? 'bg-foreground text-background'
: 'border-2 border-border bg-transparent hover:bg-foreground hover:text-background'
}`}
>
{PROVIDER_LABELS[p]}
</button>
))}
</div>
{/* Code block */}
<div className="border-2 border-border">
<div className="flex items-center justify-between px-4 py-2.5 border-b-2 border-border bg-muted">
<div className="flex gap-3">
{LANGUAGES.map((l) => (
<button
key={l}
type="button"
onClick={() => setLang(l)}
className={`font-mono text-xs transition-colors ${
lang === l
? 'text-foreground font-bold border-b-2 border-foreground'
: 'text-muted-foreground hover:text-foreground'
}`}
>
{LANG_LABELS[l]}
</button>
))}
</div>
<button
type="button"
onClick={handleCopy}
className="text-muted-foreground hover:text-foreground transition-colors"
title="Copy"
>
{copied ? <Check size={16} className="text-green-600" /> : <Copy size={16} />}
</button>
</div>
<div className="bg-foreground text-background">
<pre className="p-5 text-sm leading-relaxed overflow-x-auto font-mono">
<code>{code}</code>
</pre>
</div>
</div>
{/* Call to docs */}
<Link
to="/pricing"
className="group mt-6 flex items-center justify-between border-2 border-border p-5 hover:bg-foreground transition-all duration-200"
>
<div>
<p className="font-mono text-xs text-muted-foreground group-hover:text-background/50 tracking-widest uppercase mb-1 transition-all duration-200">
Model Pricing
</p>
<p className="font-heading text-lg font-bold text-foreground group-hover:text-background transition-all duration-200">
{t('查看模型定价,了解完整列表')}
</p>
</div>
<span className="font-mono text-2xl text-foreground group-hover:text-background transition-all duration-200">
&rarr;
</span>
</Link>
</div>
</section>
);
}
/* ─── Pricing / CTA Section ──────────────────────────────────── */
function PricingSection() {
const { t } = useTranslation();
return (
<section id="pricing" className="py-24 px-6">
<div className="max-w-4xl mx-auto">
<div className="text-xs font-mono text-muted-foreground mb-3 tracking-widest uppercase">
{'// pricing'}
</div>
<h2 className="font-heading text-3xl font-bold md:text-4xl tracking-tight mb-16 text-foreground">
{t('获取 Token 额度')}
</h2>
{/* Token credit callout */}
<div className="bg-foreground text-background px-8 py-5 mb-6 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
<div className="flex items-center gap-4">
<span className="shrink-0 border border-background/30 px-2.5 py-0.5 text-xs font-mono tracking-widest uppercase">
{t('今日特惠')}
</span>
<span className="font-heading text-lg font-bold">
{t('注册即送 ¥10 额度')}
</span>
</div>
<span className="text-sm text-background/50">
{t('新用户注册即赠 ¥10 Token7 天有效期')}
</span>
</div>
{/* Call to action */}
<Link
to="/register"
className="group block border-2 border-border p-8 mb-6 hover:bg-foreground transition-all duration-200"
className="inline-flex h-11 items-center gap-2 rounded-full px-8 text-sm font-semibold text-white hover:opacity-90"
style={{ background: INK }}
>
<h3 className="font-heading text-2xl font-bold mb-3 text-foreground group-hover:text-background transition-all duration-200">
{t('立即注册,开始使用')}
</h3>
<p className="text-sm text-muted-foreground group-hover:text-background/60 leading-relaxed mb-6 transition-all duration-200">
{t(
'兼容 OpenAI / Claude / Gemini 协议。一个 API Key调用所有主流模型。免去多平台充值与管理的麻烦。'
)}
</p>
<span className="inline-flex items-center bg-foreground text-background border-2 border-foreground px-6 py-3 text-sm font-mono font-bold uppercase tracking-widest group-hover:bg-background group-hover:text-foreground transition-colors duration-200">
{t('免费注册')} &rarr;
</span>
{t('免费注册')} <ArrowRight size={14} />
</Link>
</div>
</section>
);
}
/* ─── Providers Marquee Section ──────────────────────────────── */
/* ─── Footer ────────────────────────────────────────────────── */
const PROVIDER_LOGOS = [
{ name: 'OpenAI', className: 'opacity-60' },
{ name: 'Claude', className: 'opacity-60' },
{ name: 'Gemini', className: 'opacity-60' },
{ name: 'DeepSeek', className: 'opacity-60' },
{ name: 'Qwen', className: 'opacity-60' },
{ name: 'MiniMax', className: 'opacity-60' },
{ name: 'Kimi', className: 'opacity-60' },
{ name: '智谱', className: 'opacity-60' },
{ name: 'Groq', className: 'opacity-60' },
{ name: 'Azure', className: 'opacity-60' },
];
function ProvidersSection() {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<section className="bg-foreground text-background border-t-4 border-background">
{/* Provider logos marquee area */}
<div className="w-full py-16 px-6">
<div className="max-w-6xl mx-auto text-center">
<p className="font-mono text-xs text-background/30 tracking-widest uppercase mb-3">
{'// supported providers'}
</p>
<h2 className="font-heading text-2xl font-bold mb-8">
{t('40+ AI 供应商,统一接入')}
</h2>
<div className="overflow-hidden">
<div className="home-marquee flex gap-16 items-center">
{[...PROVIDER_LOGOS, ...PROVIDER_LOGOS].map((logo, i) => (
<span
key={i}
className="font-mono text-sm text-background/40 whitespace-nowrap tracking-wider"
>
{logo.name}
</span>
))}
</div>
</div>
<div className="mt-10">
<button
type="button"
onClick={() => navigate('/pricing')}
className="inline-flex items-center bg-background text-foreground border-2 border-background px-8 py-3 text-sm font-mono font-bold uppercase tracking-widest hover:bg-transparent hover:text-background transition-colors duration-200"
>
{t('查看全部模型')} &rarr;
</button>
</div>
</div>
</div>
<div className="text-center pt-6 pb-8">
<p className="font-mono text-xs text-background/30 tracking-wide">
{t('免费注册,分钟级接入。兼容你现有的 SDK 和工作流。')}
</p>
</div>
</section>
);
}
/* ─── Dark Footer ────────────────────────────────────────────── */
function DarkFooter() {
function HomeFooter() {
const { t } = useTranslation();
return (
<footer className="bg-foreground text-background border-t border-background/10 py-12 px-6">
<div className="max-w-6xl mx-auto">
<footer className="border-t" style={{ borderColor: LINE, background: BG }}>
<div className="max-w-[1400px] mx-auto px-6 lg:px-10 py-12">
<div className="flex flex-col md:flex-row items-center justify-between gap-6 mb-8">
<div className="flex items-center gap-6">
<Link
to="/pricing"
className="font-mono text-xs text-background/40 hover:text-background transition-all duration-200"
>
<Link to="/pricing" className="font-mono text-xs hover:opacity-70 transition-all duration-200" style={{ color: DIM }}>
{t('定价')}
</Link>
<Link
to="/console"
className="font-mono text-xs text-background/40 hover:text-background transition-all duration-200"
>
{t('控制台')}
<Link to="/contact" className="font-mono text-xs hover:opacity-70 transition-all duration-200" style={{ color: DIM }}>
{t('联系销售')}
</Link>
<Link to="/docs" className="font-mono text-xs hover:opacity-70 transition-all duration-200" style={{ color: DIM }}>
{t('文档')}
</Link>
<Link to="/about" className="font-mono text-xs hover:opacity-70 transition-all duration-200" style={{ color: DIM }}>
About
</Link>
</div>
<div className="flex items-center gap-4">
<Link to="/user-agreement" className="text-xs hover:opacity-70" style={{ color: DIM }}>
{t('用户协议')}
</Link>
<Link to="/privacy-policy" className="text-xs hover:opacity-70" style={{ color: DIM }}>
{t('隐私政策')}
</Link>
</div>
</div>
<div className="border-t border-background/10 pt-6 flex flex-col md:flex-row items-center justify-between gap-4">
<span className="font-mono text-xs text-background/30">
&copy; 2026 {getSystemName()}
<div className="border-t pt-6 flex flex-col md:flex-row items-center justify-between gap-4" style={{ borderColor: LINE }}>
<div className="flex items-center gap-2.5">
<img src="/logo.jpg" alt="logo" className="h-6 w-6 rounded-full" />
<span className="font-heading text-sm font-semibold tracking-tight" style={{ color: INK }}>TuringToken</span>
</div>
<span className="text-xs" style={{ color: DIM }}>
&copy; 2026 {getSystemName()} &middot; Made for developers.
</span>
</div>
</div>
@ -766,22 +378,17 @@ function DarkFooter() {
/* ─── Main Home Page ────────────────────────────────────────── */
const Home = () => {
const { t } = useTranslation();
return (
<div className="min-h-screen bg-background text-foreground">
<div className="min-h-screen" style={{ background: BG }}>
<div className="home-page">
<HomeNavBar />
<HeroSection />
<FeaturesSection />
<HowItWorksSection />
<QuickStartSection />
<PricingSection />
<ProvidersSection />
<DarkFooter />
<CTASection />
<HomeFooter />
</div>
</div>
);
};
export default Home;