Add API endpoint links to home pages

This commit is contained in:
abingyyds committed 2026-04-28 18:58:16 +08:00
1 parent dae5c121b7
commit 5a35fb2100
10 files changed
+153

No files matched your search

+118
View File
@@ -0,0 +1,118 @@
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import toast from 'react-hot-toast';
import { useSite } from '../context/SiteContext';
const SHARED_API_ENDPOINTS = [
{
id: 'world',
labelKey: 'home.apiEndpointWorld',
url: 'https://world.claudecoder.me',
},
{
id: 'china',
labelKey: 'home.apiEndpointChina',
url: 'https://china.claudecoder.me',
},
];
const normalizeEndpoint = (value = '') => {
const raw = String(value || '').trim();
if (!raw) return '';
if (/^https?:\/\//i.test(raw)) {
return raw.replace(/\/+$/, '');
}
return `https://${raw.replace(/^\/+/, '').replace(/\/+$/, '')}`;
};
const copyToClipboard = async (text) => {
try {
await navigator.clipboard.writeText(text);
} catch (e) {
const ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.opacity = '0';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
}
};
export default function ApiEndpoints() {
const { t } = useTranslation();
const { site } = useSite();
const siteEndpoint = useMemo(() => {
const currentOrigin =
typeof window !== 'undefined' ? window.location.origin : '';
return normalizeEndpoint(site?.domain || currentOrigin);
}, [site?.domain]);
const endpoints = useMemo(
() => [
{
id: 'site',
label: t('home.apiEndpointSite'),
url: siteEndpoint,
},
...SHARED_API_ENDPOINTS.map((endpoint) => ({
...endpoint,
label: t(endpoint.labelKey),
apiOnly: true,
})),
].filter((endpoint) => endpoint.url),
[siteEndpoint, t],
);
const handleCopy = async (url) => {
await copyToClipboard(url);
toast.success(t('config.apiUrlCopied'));
};
return (
<section className="max-w-5xl mx-auto px-6 pb-12">
<div className="glass rounded-2xl p-5 md:p-6">
<div className="mb-4 flex flex-col gap-2 md:flex-row md:items-end md:justify-between">
<div>
<p className="text-sm font-semibold text-page">
{t('home.apiEndpointsTitle')}
</p>
<p className="mt-1 text-xs text-page-muted">
{t('home.apiEndpointsDesc')}
</p>
</div>
<span className="text-[11px] text-page-muted">
{t('home.apiEndpointClickToCopy')}
</span>
</div>
<div className="grid gap-3 md:grid-cols-3">
{endpoints.map((endpoint) => (
<button
key={endpoint.id}
type="button"
onClick={() => handleCopy(endpoint.url)}
className="rounded-xl border border-page-divider bg-page-inset/40 px-4 py-3 text-left transition-colors hover:bg-page-surface-hover"
>
<div className="mb-1 flex items-center gap-2">
<span className="text-xs font-medium text-page-label">
{endpoint.label}
</span>
{endpoint.apiOnly && (
<span className="rounded-full bg-brand-500/10 px-2 py-0.5 text-[10px] font-medium text-brand-400">
{t('home.apiEndpointApiOnly')}
</span>
)}
</div>
<code className="block break-all text-[11px] leading-relaxed text-page-secondary">
{endpoint.url}
</code>
</button>
))}
</div>
</div>
</section>
);
}
+7
View File
@@ -38,6 +38,13 @@
"home.createFreeAccount": "Create Free Account",
"home.signIn": "Sign In",
"home.defaultHeroTitle": "AI API Platform",
"home.apiEndpointsTitle": "API Endpoints",
"home.apiEndpointsDesc": "After creating an API key, use any of these URLs. Pick the endpoint closest to your network.",
"home.apiEndpointClickToCopy": "Click an address to copy it",
"home.apiEndpointSite": "Sub-site Domain",
"home.apiEndpointWorld": "Overseas calls",
"home.apiEndpointChina": "China calls",
"home.apiEndpointApiOnly": "API only",
"login.welcomeBack": "Welcome Back",
"login.signInTo": "Sign in to {{name}}",
+7
View File
@@ -38,6 +38,13 @@
"home.createFreeAccount": "免费创建账户",
"home.signIn": "登录",
"home.defaultHeroTitle": "AI API 平台",
"home.apiEndpointsTitle": "API 调用地址",
"home.apiEndpointsDesc": "创建 API Key 后,可使用以下任一地址调用。优先选择最适合当前网络的位置。",
"home.apiEndpointClickToCopy": "点击地址即可复制",
"home.apiEndpointSite": "分站域名",
"home.apiEndpointWorld": "海外调用",
"home.apiEndpointChina": "中国调用",
"home.apiEndpointApiOnly": "仅支持 API",
"login.welcomeBack": "欢迎回来",
"login.signInTo": "登录到 {{name}}",
+3
View File
@@ -8,6 +8,7 @@ import { calcOfficialEquivList } from '../../utils/officialEquiv';
import RotatingEquiv from '../../components/bits/RotatingEquiv';
import CountUp from '../../components/bits/CountUp';
import FadeContent from '../../components/bits/FadeContent';
import ApiEndpoints from '../../components/ApiEndpoints';
export default function ClaudeHome() {
const { t } = useTranslation();
@@ -81,6 +82,8 @@ export default function ClaudeHome() {
</FadeContent>
</section>
<ApiEndpoints />
{/* Features */}
<section className="bg-[#F5EEE6]">
<div className="max-w-5xl mx-auto px-6 py-20">
+3
View File
@@ -8,6 +8,7 @@ import { calcOfficialEquivList } from '../../utils/officialEquiv';
import RotatingEquiv from '../../components/bits/RotatingEquiv';
import CountUp from '../../components/bits/CountUp';
import FadeContent from '../../components/bits/FadeContent';
import ApiEndpoints from '../../components/ApiEndpoints';
export default function CleanHome() {
const { t } = useTranslation();
@@ -82,6 +83,8 @@ export default function CleanHome() {
</FadeContent>
</section>
<ApiEndpoints />
{/* Features */}
<section className="max-w-5xl mx-auto px-6 py-20">
<FadeContent blur duration={800} delay={100}>
+3
View File
@@ -8,6 +8,7 @@ import { calcOfficialEquivList } from '../../utils/officialEquiv';
import RotatingEquiv from '../../components/bits/RotatingEquiv';
import CountUp from '../../components/bits/CountUp';
import FadeContent from '../../components/bits/FadeContent';
import ApiEndpoints from '../../components/ApiEndpoints';
export default function CorporateHome() {
const { t } = useTranslation();
@@ -81,6 +82,8 @@ export default function CorporateHome() {
</FadeContent>
</section>
<ApiEndpoints />
{/* Features */}
<section className="bg-slate-50 border-y border-slate-200">
<div className="max-w-6xl mx-auto px-6 lg:px-8 py-20">
+3
View File
@@ -8,6 +8,7 @@ import { calcOfficialEquivList } from '../../utils/officialEquiv';
import RotatingEquiv from '../../components/bits/RotatingEquiv';
import CountUp from '../../components/bits/CountUp';
import FadeContent from '../../components/bits/FadeContent';
import ApiEndpoints from '../../components/ApiEndpoints';
export default function DarkHome() {
const { t } = useTranslation();
@@ -86,6 +87,8 @@ export default function DarkHome() {
</FadeContent>
</section>
<ApiEndpoints />
{/* Features */}
<section className="max-w-5xl mx-auto px-6 py-20">
<FadeContent blur duration={800} delay={100}>
+3
View File
@@ -8,6 +8,7 @@ import { calcOfficialEquivList } from '../../utils/officialEquiv';
import RotatingEquiv from '../../components/bits/RotatingEquiv';
import CountUp from '../../components/bits/CountUp';
import FadeContent from '../../components/bits/FadeContent';
import ApiEndpoints from '../../components/ApiEndpoints';
export default function DefaultHome() {
const { t } = useTranslation();
@@ -81,6 +82,8 @@ export default function DefaultHome() {
</FadeContent>
</section>
<ApiEndpoints />
{/* Features */}
<section className="max-w-5xl mx-auto px-6 py-20">
<FadeContent blur duration={800} delay={100}>
+3
View File
@@ -8,6 +8,7 @@ import { calcOfficialEquivList } from '../../utils/officialEquiv';
import RotatingEquiv from '../../components/bits/RotatingEquiv';
import CountUp from '../../components/bits/CountUp';
import FadeContent from '../../components/bits/FadeContent';
import ApiEndpoints from '../../components/ApiEndpoints';
export default function MinimalHome() {
const { t } = useTranslation();
@@ -81,6 +82,8 @@ export default function MinimalHome() {
</FadeContent>
</section>
<ApiEndpoints />
{/* Features — two-column layout */}
<section className="max-w-5xl mx-auto px-6 py-20">
<FadeContent blur duration={800} delay={100}>
+3
View File
@@ -8,6 +8,7 @@ import { calcOfficialEquivList } from '../../utils/officialEquiv';
import RotatingEquiv from '../../components/bits/RotatingEquiv';
import CountUp from '../../components/bits/CountUp';
import FadeContent from '../../components/bits/FadeContent';
import ApiEndpoints from '../../components/ApiEndpoints';
export default function StarterHome() {
const { t } = useTranslation();
@@ -87,6 +88,8 @@ export default function StarterHome() {
</FadeContent>
</section>
<ApiEndpoints />
{/* Features */}
<section className="max-w-5xl mx-auto px-6 py-20">
<FadeContent blur duration={800} delay={100}>