前端: 修复浅色模式白字 + 主题优化

- 修 nav 激活态残留 text-zinc-50 导致浅色下白字白底
- @theme 令牌改实色字面量, 浅色用 [data-theme=light] 覆盖同一批 --color-*
- 新增 soft 令牌(accent/ok/warn/err, color-mix 运行时解析)替代烘焙的透明度修饰符,
  修复 badge 实色底、focus ring 实线等问题
- ThemeToggle 改三选下拉(浅色/深色/跟随系统), 系统自动为显式选项
- 浅色强调色调深保证 WCAG 对比度, 全量复查无残留硬编码颜色类

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Sakurasan
2026-08-15 16:30:11 +08:00
co-authored by Claude
parent a422034b2b
commit 6adadebaf0
14 changed files with 148 additions and 107 deletions
+9 -9
View File
@@ -7,7 +7,7 @@ const auth = useAuthStore()
<template>
<div class="min-h-[100dvh] bg-bg text-ink">
<!-- 导航 -->
<header class="sticky top-0 z-40 border-b border-edge/60 bg-bg/80 backdrop-blur">
<header class="sticky top-0 z-40 border-b border-edge bg-bg backdrop-blur">
<div class="mx-auto flex h-14 max-w-6xl items-center justify-between px-4">
<div class="flex items-center gap-2">
<img src="/favicon.svg" alt="" class="size-5" />
@@ -28,7 +28,7 @@ const auth = useAuthStore()
<router-link
v-if="!auth.isAuthed"
to="/register"
class="rounded-md bg-accent px-3.5 py-1.5 text-sm font-medium text-ink transition hover:bg-accent-strong"
class="rounded-md bg-accent px-3.5 py-1.5 text-sm font-medium text-accent-ink transition hover:bg-accent-strong"
>
免费注册
</router-link>
@@ -51,7 +51,7 @@ const auth = useAuthStore()
<div class="mt-8 flex items-center gap-3">
<router-link
to="/register"
class="inline-flex h-10 items-center rounded-md bg-accent px-5 text-sm font-medium text-ink transition hover:bg-accent-strong active:scale-[0.98]"
class="inline-flex h-10 items-center rounded-md bg-accent px-5 text-sm font-medium text-accent-ink transition hover:bg-accent-strong active:scale-[0.98]"
>
免费注册
</router-link>
@@ -91,13 +91,13 @@ const auth = useAuthStore()
</section>
<!-- 协议入口 -->
<section class="border-t border-edge/60">
<section class="border-t border-edge">
<div class="mx-auto max-w-6xl px-4 py-16">
<h2 class="text-2xl font-semibold tracking-tight">三套协议,一个入口</h2>
<p class="mt-2 max-w-xl text-sm text-muted">
对客户端暴露统一的 OpenAI 兼容入口;客户端协议与上游渠道不匹配时自动转换,无需关心背后接的是哪家。
</p>
<div class="card mt-8 divide-y divide-edge/70">
<div class="card mt-8 divide-y divide-edge">
<div v-for="p in [
{ path: 'POST /v1/chat/completions', desc: 'OpenAI Chat,兼容面最广,SDK 与工具链最全', tag: 'OpenAI' },
{ path: 'POST /v1/responses', desc: 'OpenAI Responses,新一代 SDK 与 Agents 首选', tag: 'OpenAI' },
@@ -113,7 +113,7 @@ const auth = useAuthStore()
</section>
<!-- 网关能力 -->
<section class="border-t border-edge/60">
<section class="border-t border-edge">
<div class="mx-auto max-w-6xl px-4 py-16">
<h2 class="text-2xl font-semibold tracking-tight">网关替你处理的事</h2>
<div class="mt-8 grid gap-4 lg:grid-cols-3">
@@ -150,20 +150,20 @@ const auth = useAuthStore()
</section>
<!-- CTA -->
<section class="border-t border-edge/60">
<section class="border-t border-edge">
<div class="mx-auto max-w-6xl px-4 py-20 text-center">
<h2 class="text-2xl font-semibold tracking-tight">自托管,密钥在自己手里</h2>
<p class="mx-auto mt-3 max-w-md text-sm text-muted">Docker Compose 一键部署,PostgreSQL 存账,渠道密钥加密存储。</p>
<router-link
to="/register"
class="mt-8 inline-flex h-10 items-center rounded-md bg-accent px-6 text-sm font-medium text-ink transition hover:bg-accent-strong active:scale-[0.98]"
class="mt-8 inline-flex h-10 items-center rounded-md bg-accent px-6 text-sm font-medium text-accent-ink transition hover:bg-accent-strong active:scale-[0.98]"
>
开始使用
</router-link>
</div>
</section>
<footer class="border-t border-edge/60">
<footer class="border-t border-edge">
<div class="mx-auto flex max-w-6xl items-center justify-between px-4 py-6 text-xs text-muted">
<div class="flex items-center gap-2">
<img src="/favicon.svg" alt="" class="size-4" />
+3 -3
View File
@@ -53,14 +53,14 @@ onMounted(load)
<div class="flex gap-2">
<button
class="flex-1 rounded-md border px-3 py-2 text-sm transition"
:class="config.registration_mode === 'open' ? 'border-accent bg-accent/10 text-accent' : 'border-edge2 text-muted'"
:class="config.registration_mode === 'open' ? 'border-accent bg-accent-soft text-accent' : 'border-edge2 text-muted'"
@click="config.registration_mode = 'open'"
>
开放注册
</button>
<button
class="flex-1 rounded-md border px-3 py-2 text-sm transition"
:class="config.registration_mode === 'invite' ? 'border-accent bg-accent/10 text-accent' : 'border-edge2 text-muted'"
:class="config.registration_mode === 'invite' ? 'border-accent bg-accent-soft text-accent' : 'border-edge2 text-muted'"
@click="config.registration_mode = 'invite'"
>
邀请码
@@ -78,7 +78,7 @@ onMounted(load)
/>
</div>
<div class="flex items-center justify-between rounded-md border border-edge bg-surface/60 px-4 py-3">
<div class="flex items-center justify-between rounded-md border border-edge bg-surface px-4 py-3">
<div>
<p class="text-sm text-ink">其他配置项</p>
<p class="text-xs text-muted">汇率、限流阈值、维护开关在后续里程碑开放</p>
+2 -2
View File
@@ -154,7 +154,7 @@ onMounted(load)
</div>
</div>
<div v-if="m.channels.length" class="border-t border-edge/70 px-4 py-2">
<div v-if="m.channels.length" class="border-t border-edge px-4 py-2">
<div class="flex flex-wrap gap-2">
<span
v-for="b in m.channels"
@@ -166,7 +166,7 @@ onMounted(load)
</span>
</div>
</div>
<p v-else class="border-t border-edge/70 px-4 py-2 text-xs text-muted">
<p v-else class="border-t border-edge px-4 py-2 text-xs text-muted">
未绑定渠道,客户端无法调用该模型
</p>
</div>
+1 -1
View File
@@ -82,7 +82,7 @@ onMounted(load)
<h2 class="text-sm font-semibold">全局最近请求</h2>
<span class="font-mono text-[11px] text-muted">共 {{ data.month.requests }} / 月</span>
</div>
<ul class="divide-y divide-edge/70">
<ul class="divide-y divide-edge">
<li v-for="l in logs" :key="l.id" class="flex items-center justify-between py-2">
<div class="min-w-0">
<p class="truncate text-xs text-ink">
+2 -2
View File
@@ -95,13 +95,13 @@ onMounted(load)
<h2 class="text-sm font-semibold">最近请求</h2>
<router-link to="/console/usage" class="text-xs text-accent hover:text-accent-strong">查看全部</router-link>
</div>
<ul v-if="loading" class="divide-y divide-edge/70">
<ul v-if="loading" class="divide-y divide-edge">
<li v-for="i in 4" :key="i" class="flex items-center justify-between py-2">
<Skeleton height="0.75rem" width="40%" />
<Skeleton height="0.75rem" width="30%" />
</li>
</ul>
<ul v-else class="divide-y divide-edge/70">
<ul v-else class="divide-y divide-edge">
<li v-for="l in logs" :key="l.id" class="flex items-center justify-between py-2">
<div class="min-w-0">
<p class="truncate font-mono text-xs text-ink">{{ l.model }}</p>
+1 -1
View File
@@ -136,7 +136,7 @@ onMounted(load)
<div class="space-y-4">
<p class="text-xs text-muted">请复制并妥善保存,关闭后不再显示。</p>
<div class="flex items-center gap-2">
<code class="mono-num flex-1 truncate rounded-md border border-accent/40 bg-surface px-3 py-2 text-xs text-accent">
<code class="mono-num flex-1 truncate rounded-md border border-accent bg-surface px-3 py-2 text-xs text-accent">
{{ created?.key }}
</code>
<Button size="sm" @click="copyKey">