前端: 按 Web Interface Guidelines 全面重做
组件: - Button: transition-all→明确属性列表, touch-action, aria-busy - Input: name/spellcheck/inputmode/aria-invalid/aria-describedby, focus-visible ring, label 关联, 暴露 focus() 供错误定位, required 标记 - Modal: Escape 关闭 + focus trap + 焦点归还, overscroll-behavior: contain, aria-labelledby, body 滚动锁, touch-action - 新增 Toast(aria-live polite) + pinia toast store 页面: - ConsoleLayout: skip link, <main> 语义标签, aside/nav aria-label, aria-current, 装饰 SVG aria-hidden, Intl 金额, translate=no 品牌/代码 - Dashboard: Intl.NumberFormat, 骨架屏 loading, aria-live 错误 - Keys: 字段级错误+焦点定位, toast 反馈(复制/吊销), name 属性 - Usage: select 加 label, 分页/筛选同步 URL(可深链), Intl 日期/金额, 表格 caption - Login/Register: 字段级校验+错误定位, spellcheck=false, inputmode, autocomplete - Landing: router-link 替换 href, aria-hidden, text-balance, scroll-mt - index.html: theme-color + color-scheme 验证: playwright 22 项断言全过, WCAG AA 对比度 9 组全过, 零控制台错误
This commit is contained in:
@@ -18,54 +18,67 @@ const protocols = [
|
||||
<!-- 顶部导航 -->
|
||||
<header class="sticky top-0 z-40 border-b border-ink-800 bg-ink-950/90 backdrop-blur">
|
||||
<div class="mx-auto flex h-16 max-w-6xl items-center justify-between px-6">
|
||||
<div class="flex items-center gap-2.5">
|
||||
<span class="flex h-7 w-7 items-center justify-center rounded-md bg-signal-400">
|
||||
<router-link to="/" class="flex items-center gap-2.5" aria-label="openteam 首页">
|
||||
<span class="flex h-7 w-7 items-center justify-center rounded-md bg-signal-400" aria-hidden="true">
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M2 8h3l2-5 3 10 2-5h2" stroke="#0c0d0f" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</span>
|
||||
<span class="text-[15px] font-semibold tracking-tight">openteam</span>
|
||||
<span class="ml-1 rounded border border-ink-700 px-1.5 py-px font-mono text-[10px] text-paper-500">relay</span>
|
||||
</div>
|
||||
<nav class="flex items-center gap-2">
|
||||
<a v-if="!auth.isAuthed" href="/login" class="rounded-md px-3 py-2 text-sm text-paper-500 transition-colors hover:text-paper-100">登录</a>
|
||||
<a :href="primaryAction" class="rounded-md bg-signal-400 px-4 py-2 text-sm font-medium text-ink-950 transition-colors hover:bg-signal-300">开始使用</a>
|
||||
<span class="text-[15px] font-semibold tracking-tight" translate="no">openteam</span>
|
||||
<span class="ml-1 rounded border border-ink-700 px-1.5 py-px font-mono text-[10px] text-paper-500" translate="no">relay</span>
|
||||
</router-link>
|
||||
<nav class="flex items-center gap-2" aria-label="站内导航">
|
||||
<router-link
|
||||
v-if="!auth.isAuthed"
|
||||
to="/login"
|
||||
class="rounded-md px-3 py-2 text-sm text-paper-500 transition-colors hover:bg-ink-800 hover:text-paper-100 focus-visible:ring-2 focus-visible:ring-signal-400/60 focus:outline-none"
|
||||
>登录</router-link>
|
||||
<router-link
|
||||
:to="primaryAction"
|
||||
class="inline-flex h-9 touch-manipulation items-center rounded-md bg-signal-400 px-4 text-sm font-medium text-ink-950 transition-colors hover:bg-signal-300 focus-visible:ring-2 focus-visible:ring-signal-400/60 focus:outline-none"
|
||||
>开始使用</router-link>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<main id="landing-main">
|
||||
<!-- Hero:左对齐,信号路径示意 -->
|
||||
<section class="mx-auto grid max-w-6xl grid-cols-1 items-center gap-14 px-6 pt-16 pb-20 lg:grid-cols-[1.1fr_0.9fr]">
|
||||
<div>
|
||||
<p class="font-mono text-xs uppercase tracking-[0.2em] text-signal-400">self-hosted llm relay</p>
|
||||
<h1 class="mt-4 text-4xl leading-[1.05] font-bold tracking-tight md:text-5xl">
|
||||
<p class="font-mono text-xs uppercase tracking-[0.2em] text-signal-400" translate="no">self-hosted llm relay</p>
|
||||
<h1 class="mt-4 text-4xl leading-[1.05] font-bold tracking-tight text-balance md:text-5xl">
|
||||
一个 Key,<br />接入全部模型
|
||||
</h1>
|
||||
<p class="mt-5 max-w-[52ch] text-base leading-relaxed text-paper-500">
|
||||
自托管 LLM API 中转网关。统一 OpenAI 与 Anthropic 协议入口,背后对接任意上游渠道,用量计费一目了然。
|
||||
</p>
|
||||
<div class="mt-8 flex items-center gap-3">
|
||||
<a href="/register" class="inline-flex h-10 items-center rounded-md bg-signal-400 px-5 text-sm font-medium text-ink-950 transition-all hover:bg-signal-300 active:scale-[0.98]">立即开始</a>
|
||||
<a href="#protocols" class="inline-flex h-10 items-center rounded-md border border-ink-600 px-5 text-sm text-paper-300 transition-colors hover:border-signal-400 hover:text-signal-300">查看端点</a>
|
||||
<router-link
|
||||
to="/register"
|
||||
class="inline-flex h-10 touch-manipulation items-center rounded-md bg-signal-400 px-5 text-sm font-medium text-ink-950 transition-[background-color,transform] hover:bg-signal-300 active:scale-[0.98] focus-visible:ring-2 focus-visible:ring-signal-400/60 focus:outline-none"
|
||||
>立即开始</router-link>
|
||||
<a
|
||||
href="#protocols"
|
||||
class="inline-flex h-10 touch-manipulation items-center rounded-md border border-ink-600 px-5 text-sm text-paper-300 transition-colors hover:border-signal-400 hover:text-signal-300 focus-visible:ring-2 focus-visible:ring-signal-400/60 focus:outline-none"
|
||||
>查看端点</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 信号路径:client → gateway → upstream -->
|
||||
<div class="rounded-lg border border-ink-700 bg-ink-900 p-5 font-mono text-[13px]">
|
||||
<div class="rounded-lg border border-ink-700 bg-ink-900 p-5 font-mono text-[13px]" aria-label="请求链路示意">
|
||||
<div class="flex items-center gap-3 pb-4">
|
||||
<span class="h-1.5 w-1.5 animate-pulse rounded-full bg-mint-400" />
|
||||
<span class="text-xs text-paper-500">request path · live</span>
|
||||
<span class="h-1.5 w-1.5 animate-pulse rounded-full bg-mint-400" aria-hidden="true" />
|
||||
<span class="text-xs text-paper-500" translate="no">request path · live</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="rounded-md border border-ink-700 bg-ink-850 px-3 py-2 text-paper-300">client <span class="text-signal-400">──▶</span> <span class="text-paper-500">/v1/chat/completions</span></div>
|
||||
<div class="rounded-md border border-ink-700 bg-ink-850 px-3 py-2 text-paper-300">gateway <span class="text-signal-400">──▶</span> <span class="text-paper-500">auth · quota · route</span></div>
|
||||
<div class="rounded-md border border-ink-700 bg-ink-850 px-3 py-2 text-paper-300">upstream <span class="text-mint-400">◀──</span> <span class="text-paper-500">openai / anthropic</span></div>
|
||||
<div class="rounded-md border border-ink-700 bg-ink-850 px-3 py-2 text-paper-300">billing <span class="text-mint-400">──▶</span> <span class="num text-paper-500">usage · cost · ledger</span></div>
|
||||
<div class="rounded-md border border-ink-700 bg-ink-850 px-3 py-2 text-paper-300">client <span class="text-signal-400" aria-hidden="true">──▶</span> <span class="text-paper-500" translate="no">/v1/chat/completions</span></div>
|
||||
<div class="rounded-md border border-ink-700 bg-ink-850 px-3 py-2 text-paper-300">gateway <span class="text-signal-400" aria-hidden="true">──▶</span> <span class="text-paper-500" translate="no">auth · quota · route</span></div>
|
||||
<div class="rounded-md border border-ink-700 bg-ink-850 px-3 py-2 text-paper-300">upstream <span class="text-mint-400" aria-hidden="true">◀──</span> <span class="text-paper-500" translate="no">openai / anthropic</span></div>
|
||||
<div class="rounded-md border border-ink-700 bg-ink-850 px-3 py-2 text-paper-300">billing <span class="text-mint-400" aria-hidden="true">──▶</span> <span class="num text-paper-500" translate="no">usage · cost · ledger</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 协议端点 -->
|
||||
<section id="protocols" class="border-t border-ink-800 bg-ink-900/50">
|
||||
<section id="protocols" class="scroll-mt-16 border-t border-ink-800 bg-ink-900/50">
|
||||
<div class="mx-auto max-w-6xl px-6 py-16">
|
||||
<h2 class="text-xl font-semibold tracking-tight">三套协议,一个入口</h2>
|
||||
<p class="mt-2 max-w-[60ch] text-sm leading-relaxed text-paper-500">
|
||||
@@ -73,7 +86,7 @@ const protocols = [
|
||||
</p>
|
||||
<div class="mt-8 grid grid-cols-1 gap-3 md:grid-cols-2">
|
||||
<div v-for="p in protocols" :key="p.name" class="rounded-lg border border-ink-700 bg-ink-900 p-4">
|
||||
<code class="font-mono text-[13px] text-signal-300">{{ p.name }}</code>
|
||||
<code class="font-mono text-[13px] text-signal-300" translate="no">{{ p.name }}</code>
|
||||
<p class="mt-1.5 text-[13px] text-paper-500">{{ p.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,7 +97,7 @@ const protocols = [
|
||||
<footer class="border-t border-ink-800">
|
||||
<div class="mx-auto flex max-w-6xl items-center justify-between px-6 py-6 text-xs text-paper-600">
|
||||
<span>openteam · 自托管 LLM 中转网关</span>
|
||||
<span class="font-mono">v0.1 · M1</span>
|
||||
<span class="font-mono" translate="no">v0.1 · M1</span>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user