From 004cdd9fc9bd9732447c225b3dee9fb010c4ed2b Mon Sep 17 00:00:00 2001 From: shangzy Date: Wed, 15 Apr 2026 18:03:06 +0800 Subject: [PATCH] Refine embedded portal homepage --- app/globals.css | 477 ++++++++++++++++++++++++++++++++++++++++++-- app/portal/page.tsx | 407 ++++++++++++++++++++++++++----------- lib/i18n.tsx | 70 ++++++- 3 files changed, 809 insertions(+), 145 deletions(-) diff --git a/app/globals.css b/app/globals.css index 375888b..4c4c80b 100644 --- a/app/globals.css +++ b/app/globals.css @@ -207,11 +207,16 @@ body { position: relative; display: flex; flex-direction: column; - align-items: center; - justify-content: center; min-height: 100vh; - overflow: hidden; - padding: 2rem; + overflow-x: hidden; +} +.portal-main { + position: relative; + z-index: 10; +} +.portal-container { + width: min(calc(100% - 3rem), 1440px); + margin: 0 auto; } /* ── Background: animated grid ── */ @@ -374,22 +379,15 @@ body { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; - max-width: 960px; width: 100%; } -@media (max-width: 768px) { - .portal-cards { - grid-template-columns: 1fr; - max-width: 400px; - } -} /* Individual card */ .portal-card { position: relative; display: flex; flex-direction: column; - align-items: center; + align-items: flex-start; padding: 2.5rem 2rem 2rem; border-radius: 16px; background: var(--surface); @@ -400,6 +398,7 @@ body { cursor: pointer; overflow: hidden; transition: border-color 0.35s ease, box-shadow 0.35s ease; + min-height: 100%; } .portal-card:hover { border-color: var(--card-accent); @@ -476,7 +475,7 @@ body { font-size: 0.82rem; line-height: 1.55; color: var(--text-muted); - text-align: center; + text-align: left; margin-bottom: 1.25rem; } @@ -490,13 +489,13 @@ body { letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); - opacity: 0; - transform: translateY(6px); + opacity: 0.78; + transform: none; transition: all 0.35s ease; + margin-top: auto; } .portal-card:hover .portal-card-action { opacity: 1; - transform: translateY(0); color: var(--card-accent); } .portal-card-action-icon { @@ -510,15 +509,18 @@ body { /* Bottom highlight bar */ .portal-card-bar { position: absolute; - bottom: 0; left: 50%; - transform: translateX(-50%); - width: 0; height: 2px; + bottom: 0; + left: 2rem; + width: 64px; + height: 2px; border-radius: 2px; background: var(--card-accent); - transition: width 0.4s cubic-bezier(0.22, 1, 0.36, 1); + opacity: 0.5; + transition: width 0.4s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.3s ease; } .portal-card:hover .portal-card-bar { - width: 60%; + width: calc(100% - 4rem); + opacity: 1; } /* ── Footer ── */ @@ -527,8 +529,9 @@ body { z-index: 10; display: flex; align-items: center; + justify-content: center; gap: 0.5rem; - margin-top: 3rem; + padding: 2.5rem 0 2rem; } .portal-status-dot { width: 6px; height: 6px; @@ -549,6 +552,436 @@ body { color: var(--text-muted); } +/* ── Portal Landing: Nav ── */ +.portal-nav { + position: sticky; + top: 0; + z-index: 100; + padding: 0.85rem 0; + background: color-mix(in srgb, var(--background) 78%, transparent); + backdrop-filter: blur(18px); + border-bottom: 1px solid var(--surface-border); +} +.portal-nav-inner { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1.5rem; +} +.portal-nav-logo { + display: flex; + align-items: center; + gap: 0.6rem; + font-family: var(--font-mono); + font-size: 1rem; + font-weight: 600; + letter-spacing: 0.06em; + text-decoration: none; +} +.portal-nav-menu, +.portal-nav-controls { + display: flex; + align-items: center; + gap: 1rem; +} +.portal-nav-menu a { + font-family: var(--font-mono); + font-size: 0.75rem; + font-weight: 400; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--text-muted); + text-decoration: none; + transition: color 0.2s; +} +.portal-nav-menu a:hover { color: var(--text-accent); } + +/* ── Portal Landing: Hero ── */ +.portal-hero { + position: relative; + min-height: calc(100vh - 78px); + padding: clamp(3.5rem, 7vw, 6rem) 0 5.5rem; +} +.portal-hero-scan { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent), transparent); + animation: portal-hero-scan-move 4s linear infinite; + opacity: 0.4; +} +@keyframes portal-hero-scan-move { + 0% { transform: translateY(-100%); } + 100% { transform: translateY(80vh); } +} +.portal-hero-grid { + display: grid; + grid-template-columns: minmax(0, 1.08fr) minmax(340px, 0.92fr); + gap: clamp(2rem, 4vw, 4rem); + align-items: center; +} +.portal-hero-copy { + max-width: 760px; +} +.portal-hero-badge { + display: inline-flex; + align-items: center; + gap: 0.5rem; + font-family: var(--font-mono); + font-size: 0.72rem; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--accent-dim); + border: 1px solid var(--surface-border); + padding: 0.35rem 0.9rem; + margin-bottom: 2rem; + border-radius: 2px; +} +.portal-hero-badge::before { + content: ''; + width: 6px; + height: 6px; + background: var(--accent); + border-radius: 50%; + animation: portal-pulse 1.5s ease-in-out infinite; +} +.portal-hero h1 { + font-weight: 800; + font-size: clamp(3.25rem, 7vw, 6.25rem); + line-height: 0.98; + letter-spacing: -0.04em; + margin-bottom: 1.5rem; +} +.portal-hero h1 .hero-sub { + display: block; + margin-top: 0.8rem; + font-size: 0.28em; + font-weight: 300; + letter-spacing: 0.18em; + color: var(--text-muted); + -webkit-text-fill-color: var(--text-muted); + background: none; +} +.portal-hero-desc { + font-size: clamp(1rem, 1.25vw, 1.18rem); + color: var(--text-secondary); + max-width: 640px; + margin-bottom: 2.5rem; + line-height: 1.9; +} +.portal-hero-actions { + display: flex; + gap: 0.85rem; + flex-wrap: wrap; +} +.portal-hero-panel { + position: relative; + overflow: hidden; + padding: 1.5rem; + border-radius: 24px; + box-shadow: 0 16px 60px rgba(0, 0, 0, 0.16); +} +.portal-hero-panel::before { + content: ''; + position: absolute; + inset: 0; + background: + linear-gradient(135deg, rgba(255, 255, 255, 0.04), transparent 32%), + radial-gradient(circle at top right, rgba(0, 229, 255, 0.12), transparent 45%); + pointer-events: none; +} +.portal-panel-header, +.portal-panel-shortcuts { + position: relative; + z-index: 1; +} +.portal-panel-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 1rem; + margin-bottom: 1rem; +} +.portal-panel-label { + font-family: var(--font-mono); + font-size: 0.66rem; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--accent-dim); + margin-bottom: 0.5rem; +} +.portal-panel-title { + font-size: clamp(1.35rem, 2vw, 1.85rem); + font-weight: 700; + color: var(--text-primary); + letter-spacing: -0.02em; +} +.portal-panel-shortcuts { + display: grid; + gap: 0.85rem; +} +.portal-shortcut { + display: grid; + grid-template-columns: 3rem minmax(0, 1fr) auto; + align-items: center; + gap: 1rem; + padding: 1rem 1.05rem; + border-radius: 18px; + border: 1px solid var(--surface-border); + background: color-mix(in srgb, var(--background) 36%, transparent); + text-decoration: none; + transition: transform 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease, background 0.3s ease; +} +.portal-shortcut:hover { + transform: translateY(-2px); + border-color: var(--card-accent); + box-shadow: 0 0 28px var(--card-glow); + background: color-mix(in srgb, var(--background) 28%, transparent); +} +.portal-shortcut-icon { + display: flex; + align-items: center; + justify-content: center; + width: 3rem; + height: 3rem; + border-radius: 14px; + border: 1px solid color-mix(in srgb, var(--card-accent) 24%, var(--surface-border)); + color: var(--card-accent); + background: color-mix(in srgb, var(--card-accent) 12%, transparent); +} +.portal-shortcut-copy { + min-width: 0; + display: flex; + flex-direction: column; + gap: 0.2rem; +} +.portal-shortcut-title { + color: var(--text-primary); + font-weight: 600; + letter-spacing: -0.01em; +} +.portal-shortcut-desc { + color: var(--text-muted); + font-size: 0.8rem; + line-height: 1.5; +} +.portal-shortcut-arrow { + width: 1rem; + height: 1rem; + color: var(--card-accent); + opacity: 0.8; + transition: transform 0.25s ease, opacity 0.25s ease; +} +.portal-shortcut:hover .portal-shortcut-arrow { + transform: translate(2px, -2px); + opacity: 1; +} +.portal-hero-voltage { + position: absolute; + right: clamp(1rem, 3vw, 3rem); + top: 50%; + transform: translateY(-50%); + display: flex; + flex-direction: column; + gap: 0.5rem; + opacity: 0.22; + pointer-events: none; +} +.portal-voltage-bar { + width: 4px; + height: 40px; + background: var(--surface-border); + border-radius: 2px; + overflow: hidden; + position: relative; +} +.portal-voltage-bar::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: var(--accent); + border-radius: 2px; + animation: portal-voltage 3s ease-in-out infinite; +} +@keyframes portal-voltage { + 0%, 100% { height: 60%; } + 25% { height: 85%; } + 50% { height: 72%; } + 75% { height: 95%; } +} +.portal-voltage-bar:nth-child(2)::after { animation-delay: 0.5s; } +.portal-voltage-bar:nth-child(3)::after { animation-delay: 1s; } +.portal-voltage-bar:nth-child(4)::after { animation-delay: 1.5s; } +.portal-voltage-bar:nth-child(5)::after { animation-delay: 0.3s; } + +/* ── Portal Landing: Section common ── */ +.portal-section { + padding: 4.75rem 0; +} +.portal-section-tag { + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--accent-dim); + margin-bottom: 0.75rem; + display: flex; + align-items: center; + gap: 0.75rem; +} +.portal-section-tag::before { + content: ''; + width: 20px; + height: 1px; + background: var(--accent); +} +.portal-section-title { + font-size: clamp(1.7rem, 3.5vw, 2.7rem); + font-weight: 700; + letter-spacing: -0.02em; + line-height: 1.15; + margin-bottom: 3rem; + max-width: 760px; +} + +/* ── Portal Landing: Feature cards ── */ +.portal-features-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1.4rem; +} +.portal-feature-card { + position: relative; + overflow: hidden; + transition: transform 0.3s, border-color 0.3s, box-shadow 0.3s; +} +.portal-feature-card::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, var(--accent), transparent); + opacity: 0; + transition: opacity 0.3s; +} +.portal-feature-card:hover { + transform: translateY(-4px); + border-color: var(--input-border); + box-shadow: var(--glow-cyan); +} +.portal-feature-card:hover::after { opacity: 1; } + +/* ── Portal Landing: Model/Tool cards ── */ +.portal-model-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 1rem; +} +.portal-model-card { + text-align: center; + transition: transform 0.3s, border-color 0.3s, box-shadow 0.3s; +} +.portal-model-card:hover { + transform: translateY(-2px); + border-color: var(--input-border); + box-shadow: var(--glow-cyan); +} +.portal-tool-card { + text-align: center; + position: relative; + overflow: hidden; + transition: transform 0.3s, border-color 0.3s; +} +.portal-tool-card::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent-purple), transparent); + opacity: 0; + transition: opacity 0.3s; +} +.portal-tool-card:hover { + transform: translateY(-2px); + border-color: rgba(124, 77, 255, 0.2); +} +.portal-tool-card:hover::after { opacity: 1; } + +/* ── Portal Landing: Disclaimer ── */ +.portal-disclaimer { + border-top: 1px solid var(--surface-border); + padding: 4.5rem 0 0; +} +.portal-disclaimer-panel { + position: relative; + overflow: hidden; + padding: 2.2rem; +} +.portal-disclaimer-panel::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, var(--accent-dim), var(--accent), transparent); + opacity: 0.7; +} + +/* ── Portal Landing: Responsive ── */ +@media (max-width: 1180px) { + .portal-hero-grid { + grid-template-columns: 1fr; + } + .portal-hero-voltage { + display: none; + } + .portal-cards { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} +@media (max-width: 1024px) { + .portal-features-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} +@media (max-width: 768px) { + .portal-container { + width: min(calc(100% - 1.5rem), 1440px); + } + .portal-nav-inner { + gap: 0.75rem; + } + .portal-nav-menu { + display: none; + } + .portal-nav-controls { + gap: 0.5rem; + } + .portal-hero { + min-height: auto; + padding: 2.75rem 0 4rem; + } + .portal-hero h1 { + font-size: clamp(2.7rem, 12vw, 4rem); + } + .portal-features-grid, + .portal-cards { + grid-template-columns: 1fr; + } + .portal-disclaimer-panel { + padding: 1.5rem; + } +} + /* Recharts overrides */ .recharts-cartesian-grid-horizontal line, .recharts-cartesian-grid-vertical line { diff --git a/app/portal/page.tsx b/app/portal/page.tsx index 353f6ca..f4387df 100644 --- a/app/portal/page.tsx +++ b/app/portal/page.tsx @@ -2,7 +2,6 @@ import { motion } from "motion/react"; import { - Activity, MonitorCheck, BookOpen, BarChart3, @@ -11,13 +10,21 @@ import { Zap, Shield, Server, + Globe, + RefreshCw, + Puzzle, } from "lucide-react"; -import { useI18n } from "@/lib/i18n"; +import { useI18n, type TranslationKey } from "@/lib/i18n"; -/* ═══════════════════════════════════════════════════════ - Configure service URLs here. - Change these to your actual endpoints. - ═══════════════════════════════════════════════════════ */ +const PLATFORM_URL = "http://192.168.111.90:8016/console/personal"; + +const SERVICE_URLS: Record = { + monitoring: "http://192.168.111.90:8018", + docs: "http://192.168.111.90:8087/sinocode/current/", + analytics: "http://192.168.111.90:8019", +}; + +/* ═══ Data ═══ */ const SERVICES = [ { key: "monitoring" as const, @@ -42,11 +49,44 @@ const SERVICES = [ }, ]; -const SERVICE_URLS: Record = { - monitoring: "http://192.168.111.90:8018", - docs: "http://192.168.111.90:8087/sinocode/current/", - analytics: "http://192.168.111.90:8019", +interface FeatureItem { + icon: typeof Zap; + titleKey: TranslationKey; + descKey: TranslationKey; +} + +const FEATURES: FeatureItem[] = [ + { icon: Zap, titleKey: "portal.features.unified", descKey: "portal.features.unifiedDesc" }, + { icon: Shield, titleKey: "portal.features.security", descKey: "portal.features.securityDesc" }, + { icon: BarChart3, titleKey: "portal.features.monitor", descKey: "portal.features.monitorDesc" }, + { icon: Globe, titleKey: "portal.features.global", descKey: "portal.features.globalDesc" }, + { icon: RefreshCw, titleKey: "portal.features.failover", descKey: "portal.features.failoverDesc" }, + { icon: Puzzle, titleKey: "portal.features.flexible", descKey: "portal.features.flexibleDesc" }, +]; + +interface ModelItem { name: string; provider: string; } +const MODELS: ModelItem[] = [ + { name: "Claude", provider: "Anthropic" }, + { name: "GPT", provider: "OpenAI" }, + { name: "Gemini", provider: "Google" }, + { name: "DeepSeek", provider: "DeepSeek" }, + { name: "Grok", provider: "xAI" }, +]; + +interface ToolItem { name: string; tag: string; } +const TOOLS: ToolItem[] = [ + { name: "Claude Code", tag: "Anthropic" }, + { name: "Codex", tag: "OpenAI" }, + { name: "Gemini CLI", tag: "Google" }, + { name: "OpenCode", tag: "Community" }, + { name: "Droid", tag: "Community" }, +]; + +const fadeUp = { + hidden: { opacity: 0, y: 24 }, + visible: { opacity: 1, y: 0, transition: { duration: 0.5, ease: "easeOut" as const } }, }; +const stagger = { visible: { transition: { staggerChildren: 0.08 } } }; export default function PortalPage() { const { t } = useI18n(); @@ -59,13 +99,11 @@ export default function PortalPage() { return (
- {/* ── Background layers ── */} + {/* ── Background layers (preserved) ── */}
- - {/* Decorative floating particles */}
{Array.from({ length: 6 }).map((_, i) => (
- {/* ── Header / Branding ── */} - - {/* Logo mark */} - - - +
+ {/* ── 2. HERO ── */} +
+
+
+ + + {t("portal.hero.badge")} + + + SinoCode + {t("portal.subtitle")} + + + {t("portal.hero.desc")} + + + + {t("portal.hero.cta")} + + + {t("portal.hero.docs")} → + + + -

- Sino - Code -

- - - {t("portal.subtitle")} - - - {/* Animated scan divider */} - -
- - - - {/* ── Service Cards ── */} -
- {SERVICES.map((service, i) => { - const Icon = service.icon; - const DecorIcon = service.decorIcon; - const info = i18nMap[service.key]; - const url = SERVICE_URLS[service.key]; - - return ( - - {/* Corner brackets */} - - - - - - {/* Decorative bg icon */} - - - {/* Icon container */} -
- +
+
+
{t("portal.services.tag")}
+
{t("common.systemOnline")}
+
+
- {/* Text content */} -

{info.title}

-

{info.desc}

+
+ {SERVICES.map((service) => { + const Icon = service.icon; + const info = i18nMap[service.key]; + const url = SERVICE_URLS[service.key]; - {/* Enter indicator */} -
- {t("portal.enter")} - + return ( + +
+ +
+
+ {info.title} + {info.desc} +
+ +
+ ); + })}
+ +
- {/* Bottom highlight bar */} -
- - ); - })} -
+
- {/* ── Footer status ── */} - -
- - - System Online - - + {/* ── 3. FEATURES ── */} +
+
+ +
{t("portal.features.tag")}
+

{t("portal.features.title")}

+
+ + {FEATURES.map((f) => { + const Icon = f.icon; + return ( + +
+ +
+

{t(f.titleKey)}

+

{t(f.descKey)}

+
+ ); + })} +
+
+
+ + {/* ── 4. SERVICES ── */} +
+
+ +
{t("portal.services.tag")}
+

{t("portal.services.title")}

+
+
+ {SERVICES.map((service, i) => { + const Icon = service.icon; + const DecorIcon = service.decorIcon; + const info = i18nMap[service.key]; + const url = SERVICE_URLS[service.key]; + + return ( + + + + + + +
+

{info.title}

+

{info.desc}

+
+ {t("portal.enter")} + +
+
+ + ); + })} +
+
+
+ + {/* ── 5. ECOSYSTEM ── */} +
+
+ +
{t("portal.ecosystem.tag")}
+

{t("portal.ecosystem.title")}

+
+ + +

{t("portal.ecosystem.models")}

+
+ + {MODELS.map((m) => ( + +
{m.name}
+
{m.provider}
+
+ ))} +
+ + +

{t("portal.ecosystem.tools")}

+

{t("portal.ecosystem.toolsDesc")}

+
+ + {TOOLS.map((tool) => ( + +
{tool.name}
+
{tool.tag}
+
+ ))} +
+
+
+ + {/* ── 6. DISCLAIMER ── */} +
+
+ +
{t("portal.disclaimer.tag")}
+

{t("portal.disclaimer.title")}

+
+ +

{t("portal.disclaimer.p1")}

+

{t("portal.disclaimer.p2")}

+
+ {t("portal.disclaimer.copyright")} +
+
+
+
+ + {/* ── Footer status ── */} + +
+ + + {t("common.systemOnline")} + + +
); } diff --git a/lib/i18n.tsx b/lib/i18n.tsx index 4514dac..68f572d 100644 --- a/lib/i18n.tsx +++ b/lib/i18n.tsx @@ -95,6 +95,40 @@ const translations = { "portal.analytics": "使用统计", "portal.analyticsDesc": "API 调用数据分析与可视化看板", "portal.enter": "进入", + "portal.nav.features": "功能", + "portal.nav.services": "服务", + "portal.nav.ecosystem": "生态", + "portal.nav.start": "开始使用", + "portal.hero.badge": "企业内部平台 · 系统运行中", + "portal.hero.desc": "统一 AI 模型接口,兼容 OpenAI 格式,支持平滑迁移与稳定响应。为企业内所有人提供统一、稳定的 AI 能力入口。", + "portal.hero.cta": "进入平台", + "portal.hero.docs": "查看文档", + "portal.features.tag": "核心能力", + "portal.features.title": "平台特性", + "portal.features.unified": "统一接口", + "portal.features.unifiedDesc": "完全兼容 OpenAI API 格式,一行代码切换 GPT、Claude、Gemini、DeepSeek 等主流模型", + "portal.features.security": "安全可靠", + "portal.features.securityDesc": "企业级加密传输,密钥隔离管理,完整审计日志,数据安全有保障", + "portal.features.monitor": "用量监控", + "portal.features.monitorDesc": "实时 Token 消耗统计,按模型、按渠道精细化分析,成本一目了然", + "portal.features.global": "全球加速", + "portal.features.globalDesc": "跨区域链路调度与稳定转发能力,自动选择更优访问路径,兼顾响应速度与可用性。", + "portal.features.failover": "自动容灾", + "portal.features.failoverDesc": "内置多渠道负载均衡与故障转移,单一渠道异常时自动切换,服务永不中断", + "portal.features.flexible": "灵活扩展", + "portal.features.flexibleDesc": "支持自定义模型映射、请求改写、速率限制,完善的 Webhook 与回调机制", + "portal.services.tag": "平台服务", + "portal.services.title": "服务入口", + "portal.ecosystem.tag": "生态接入", + "portal.ecosystem.title": "支持的模型与工具", + "portal.ecosystem.models": "主流 AI 模型", + "portal.ecosystem.tools": "AI 编程工具", + "portal.ecosystem.toolsDesc": "统一 API Key,即可接入以下工具", + "portal.disclaimer.tag": "合规声明", + "portal.disclaimer.title": "服务使用与内容责任说明", + "portal.disclaimer.p1": "本平台作为 AI 模型 API 网关服务提供者,严禁利用本平台生成任何涉及色情、暴力、政治敏感、侵犯知识产权或其他违反中华人民共和国法律法规的内容。如发现违规使用,平台有权立即终止服务并配合相关部门依法处理。", + "portal.disclaimer.p2": "用户须自觉遵守所在地区法律法规及相关政策。因用户自身行为产生的一切法律后果,由用户自行承担。", + "portal.disclaimer.copyright": "© 2025 SinoCode", }, en: { "nav.overview": "Overview", @@ -173,10 +207,44 @@ const translations = { "portal.analytics": "Usage Analytics", "portal.analyticsDesc": "API usage data analytics & visualization dashboard", "portal.enter": "Enter", + "portal.nav.features": "Features", + "portal.nav.services": "Services", + "portal.nav.ecosystem": "Ecosystem", + "portal.nav.start": "Get Started", + "portal.hero.badge": "Enterprise Internal Platform · System Online", + "portal.hero.desc": "A unified AI model interface compatible with the OpenAI format, designed for smooth migration and stable response times. It provides a single, reliable AI access point for everyone across the enterprise.", + "portal.hero.cta": "Enter Platform", + "portal.hero.docs": "View Docs", + "portal.features.tag": "Core Capabilities", + "portal.features.title": "Platform Features", + "portal.features.unified": "Unified Interface", + "portal.features.unifiedDesc": "Fully compatible with OpenAI API format. Switch between GPT, Claude, Gemini, DeepSeek with a single line of code", + "portal.features.security": "Security & Reliability", + "portal.features.securityDesc": "Enterprise-grade encryption, isolated key management, complete audit logs, data security guaranteed", + "portal.features.monitor": "Usage Monitoring", + "portal.features.monitorDesc": "Real-time token consumption stats, granular analysis by model and channel, costs at a glance", + "portal.features.global": "Global Acceleration", + "portal.features.globalDesc": "Cross-region routing and resilient forwarding automatically choose the better path for responsive and reliable access.", + "portal.features.failover": "Auto Failover", + "portal.features.failoverDesc": "Built-in multi-channel load balancing and failover, automatic switching on channel failure, zero downtime", + "portal.features.flexible": "Flexible Extension", + "portal.features.flexibleDesc": "Custom model mapping, request rewriting, rate limiting, complete webhook and callback mechanisms", + "portal.services.tag": "Platform Services", + "portal.services.title": "Service Portal", + "portal.ecosystem.tag": "Ecosystem", + "portal.ecosystem.title": "Supported Models & Tools", + "portal.ecosystem.models": "AI Models", + "portal.ecosystem.tools": "AI Coding Tools", + "portal.ecosystem.toolsDesc": "One unified API Key for the following tools", + "portal.disclaimer.tag": "Compliance", + "portal.disclaimer.title": "Service Usage & Content Responsibility", + "portal.disclaimer.p1": "As an AI model API gateway, this platform strictly prohibits generating content involving pornography, violence, political sensitivity, IP infringement, or other violations of PRC laws. Violations will result in immediate service termination and cooperation with authorities.", + "portal.disclaimer.p2": "Users must comply with local laws and regulations. All legal consequences arising from user actions are the sole responsibility of the user.", + "portal.disclaimer.copyright": "© 2025 SinoCode", }, } as const; -type TranslationKey = keyof typeof translations.zh; +export type TranslationKey = keyof typeof translations.zh; interface I18nContextType { locale: Locale;