fix: 评测页面浅色模式样式异常 - 切换为 shadcn/ui 主题变量系统
根因:Benchmarks 页面所有 Tailwind 样式使用硬编码暗色类 (bg-gray-950/text-white/bg-white/5/border-white/10 等), 导致浅色模式下显示为深色背景+白字,完全不可见。 修改:将所有 hardcoded dark-mode 类替换为 shadcn/ui CSS 变量类: - bg-gray-950 → bg-background - text-white/text-gray-* → text-foreground/text-muted-foreground - border-white/* → border-border - bg-white/* → bg-muted/* 和 bg-primary/* - 卡片:添加上下模式 gradient(light:from-purple-50 dark:from-purple-950/40) - 筛选/搜索/进度条/标签等全部适配 dual-theme - 额外优化:分类图标更新、加载动画主题化
This commit is contained in:
parent
e29f61aa68
commit
d455641b86
|
|
@ -0,0 +1,5 @@
|
|||
### Error
|
||||
SyntaxError: Unexpected token ')'
|
||||
at eval (eval at evaluate (:303:30), <anonymous>:2:38)
|
||||
at UtilityScript.evaluate (<anonymous>:305:16)
|
||||
at UtilityScript.<anonymous> (<anonymous>:1:44)
|
||||
|
|
@ -23,6 +23,8 @@ import {
|
|||
TrendingUp,
|
||||
Gauge,
|
||||
Sparkles,
|
||||
Activity,
|
||||
BarChart3,
|
||||
} from 'lucide-react';
|
||||
|
||||
const COLORS = {
|
||||
|
|
@ -34,10 +36,10 @@ const COLORS = {
|
|||
};
|
||||
|
||||
const CATEGORIES = [
|
||||
{ key: 'all', label: '全部', icon: Sparkles },
|
||||
{ key: 'all', label: '全部', icon: BarChart3 },
|
||||
{ key: 'language', label: '语言模型', icon: Brain },
|
||||
{ key: 'image', label: '图像模型', icon: Zap },
|
||||
{ key: 'video', label: '视频模型', icon: Zap },
|
||||
{ key: 'image', label: '图像模型', icon: Sparkles },
|
||||
{ key: 'video', label: '视频模型', icon: Activity },
|
||||
];
|
||||
|
||||
/* ─── Default benchmark data (fallback when API unavailable) ─── */
|
||||
|
|
@ -165,19 +167,19 @@ const Benchmarks = () => {
|
|||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-950 flex items-center justify-center">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-white/30" />
|
||||
<div className="min-h-screen bg-background flex items-center justify-center">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-foreground/20" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const SortHeader = ({ label, sortField, icon: Icon }) => (
|
||||
<th
|
||||
className="px-4 py-3 text-left text-xs font-semibold text-gray-400 uppercase tracking-wider cursor-pointer hover:text-white/70 transition-colors select-none"
|
||||
className="px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider cursor-pointer hover:text-foreground/70 transition-colors select-none"
|
||||
onClick={() => toggleSort(sortField)}
|
||||
>
|
||||
<div className="flex items-center gap-1.5">
|
||||
{Icon && <Icon size={13} className="text-gray-500" />}
|
||||
{Icon && <Icon size={13} className="text-muted-foreground/60" />}
|
||||
<span>{label}</span>
|
||||
{sortKey === sortField && (
|
||||
<ArrowUpDown
|
||||
|
|
@ -190,14 +192,14 @@ const Benchmarks = () => {
|
|||
);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-950 text-white">
|
||||
<div className="min-h-screen bg-background text-foreground">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 sm:py-12">
|
||||
{/* Header */}
|
||||
<div className="mb-8 sm:mb-12">
|
||||
<h1 className="text-3xl sm:text-4xl font-bold font-heading mb-3">
|
||||
{t('AI 模型评测排行榜')}
|
||||
</h1>
|
||||
<p className="text-gray-400 text-sm sm:text-base font-body max-w-2xl">
|
||||
<p className="text-muted-foreground text-sm sm:text-base font-body max-w-2xl">
|
||||
{t('基于 Artificial Analysis 数据,从智能指数、输出速度、价格成本、延迟等维度对主流 AI 模型进行多维度对比评测')}
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -205,82 +207,82 @@ const Benchmarks = () => {
|
|||
{/* Highlight Cards */}
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mb-8 sm:mb-10">
|
||||
{topIntel[0] && (
|
||||
<div className="bg-gradient-to-br from-purple-900/30 to-purple-950/30 border border-purple-800/30 rounded-xl p-4 sm:p-5">
|
||||
<div className="bg-gradient-to-br from-purple-50 to-purple-100/50 dark:from-purple-950/40 dark:to-purple-900/20 border border-purple-200 dark:border-purple-800/30 rounded-xl p-4 sm:p-5">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Trophy size={18} className="text-purple-400" />
|
||||
<span className="text-xs font-semibold text-purple-300 uppercase tracking-wider">
|
||||
<Trophy size={18} className="text-purple-500 dark:text-purple-400" />
|
||||
<span className="text-xs font-semibold text-purple-600 dark:text-purple-300 uppercase tracking-wider">
|
||||
{t('智能冠军')}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-lg sm:text-xl font-bold text-white mb-1">
|
||||
<div className="text-lg sm:text-xl font-bold text-foreground mb-1">
|
||||
{topIntel[0].name}
|
||||
</div>
|
||||
<div className="text-xs text-gray-400 mb-2">{topIntel[0].provider}</div>
|
||||
<div className="text-xs text-muted-foreground mb-2">{topIntel[0].provider}</div>
|
||||
<div className="flex items-baseline gap-1">
|
||||
<span className="text-2xl sm:text-3xl font-bold text-purple-400">
|
||||
<span className="text-2xl sm:text-3xl font-bold text-purple-500 dark:text-purple-400">
|
||||
{topIntel[0].intelligence}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">/ 60</span>
|
||||
<span className="text-xs text-muted-foreground/60">/ 60</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{fastest && (
|
||||
<div className="bg-gradient-to-br from-cyan-900/30 to-cyan-950/30 border border-cyan-800/30 rounded-xl p-4 sm:p-5">
|
||||
<div className="bg-gradient-to-br from-cyan-50 to-cyan-100/50 dark:from-cyan-950/40 dark:to-cyan-900/20 border border-cyan-200 dark:border-cyan-800/30 rounded-xl p-4 sm:p-5">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Gauge size={18} className="text-cyan-400" />
|
||||
<span className="text-xs font-semibold text-cyan-300 uppercase tracking-wider">
|
||||
<Gauge size={18} className="text-cyan-500 dark:text-cyan-400" />
|
||||
<span className="text-xs font-semibold text-cyan-600 dark:text-cyan-300 uppercase tracking-wider">
|
||||
{t('速度之王')}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-lg sm:text-xl font-bold text-white mb-1">
|
||||
<div className="text-lg sm:text-xl font-bold text-foreground mb-1">
|
||||
{fastest.name}
|
||||
</div>
|
||||
<div className="text-xs text-gray-400 mb-2">{fastest.provider}</div>
|
||||
<div className="text-xs text-muted-foreground mb-2">{fastest.provider}</div>
|
||||
<div className="flex items-baseline gap-1">
|
||||
<span className="text-2xl sm:text-3xl font-bold text-cyan-400">
|
||||
<span className="text-2xl sm:text-3xl font-bold text-cyan-500 dark:text-cyan-400">
|
||||
{fastest.speed?.toLocaleString()}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">tok/s</span>
|
||||
<span className="text-xs text-muted-foreground/60">tok/s</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{cheapest && (
|
||||
<div className="bg-gradient-to-br from-emerald-900/30 to-emerald-950/30 border border-emerald-800/30 rounded-xl p-4 sm:p-5">
|
||||
<div className="bg-gradient-to-br from-emerald-50 to-emerald-100/50 dark:from-emerald-950/40 dark:to-emerald-900/20 border border-emerald-200 dark:border-emerald-800/30 rounded-xl p-4 sm:p-5">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<DollarSign size={18} className="text-emerald-400" />
|
||||
<span className="text-xs font-semibold text-emerald-300 uppercase tracking-wider">
|
||||
<DollarSign size={18} className="text-emerald-500 dark:text-emerald-400" />
|
||||
<span className="text-xs font-semibold text-emerald-600 dark:text-emerald-300 uppercase tracking-wider">
|
||||
{t('性价比首选')}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-lg sm:text-xl font-bold text-white mb-1">
|
||||
<div className="text-lg sm:text-xl font-bold text-foreground mb-1">
|
||||
{cheapest.name}
|
||||
</div>
|
||||
<div className="text-xs text-gray-400 mb-2">{cheapest.provider}</div>
|
||||
<div className="text-xs text-muted-foreground mb-2">{cheapest.provider}</div>
|
||||
<div className="flex items-baseline gap-1">
|
||||
<span className="text-2xl sm:text-3xl font-bold text-emerald-400">
|
||||
<span className="text-2xl sm:text-3xl font-bold text-emerald-500 dark:text-emerald-400">
|
||||
${cheapest.price?.toFixed(2)}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">/M tokens</span>
|
||||
<span className="text-xs text-muted-foreground/60">/M tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{lowestLatency && (
|
||||
<div className="bg-gradient-to-br from-amber-900/30 to-amber-950/30 border border-amber-800/30 rounded-xl p-4 sm:p-5">
|
||||
<div className="bg-gradient-to-br from-amber-50 to-amber-100/50 dark:from-amber-950/40 dark:to-amber-900/20 border border-amber-200 dark:border-amber-800/30 rounded-xl p-4 sm:p-5">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Clock size={18} className="text-amber-400" />
|
||||
<span className="text-xs font-semibold text-amber-300 uppercase tracking-wider">
|
||||
<Clock size={18} className="text-amber-500 dark:text-amber-400" />
|
||||
<span className="text-xs font-semibold text-amber-600 dark:text-amber-300 uppercase tracking-wider">
|
||||
{t('低延迟标杆')}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-lg sm:text-xl font-bold text-white mb-1">
|
||||
<div className="text-lg sm:text-xl font-bold text-foreground mb-1">
|
||||
{lowestLatency.name}
|
||||
</div>
|
||||
<div className="text-xs text-gray-400 mb-2">{lowestLatency.provider}</div>
|
||||
<div className="text-xs text-muted-foreground mb-2">{lowestLatency.provider}</div>
|
||||
<div className="flex items-baseline gap-1">
|
||||
<span className="text-2xl sm:text-3xl font-bold text-amber-400">
|
||||
<span className="text-2xl sm:text-3xl font-bold text-amber-500 dark:text-amber-400">
|
||||
{lowestLatency.latency?.toFixed(2)}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">{t('秒')}</span>
|
||||
<span className="text-xs text-muted-foreground/60">{t('秒')}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -298,8 +300,8 @@ const Benchmarks = () => {
|
|||
onClick={() => setActiveCategory(cat.key)}
|
||||
className={`flex items-center gap-1.5 px-3.5 py-1.5 rounded-lg text-xs font-medium transition-all duration-150 ${
|
||||
isActive
|
||||
? 'bg-white/10 text-white border border-white/20'
|
||||
: 'bg-white/5 text-gray-400 border border-transparent hover:bg-white/10 hover:text-gray-300'
|
||||
? 'bg-primary/10 text-foreground border border-border'
|
||||
: 'bg-muted/40 text-muted-foreground border border-transparent hover:bg-muted/60 hover:text-foreground/80'
|
||||
}`}
|
||||
>
|
||||
<Icon size={13} />
|
||||
|
|
@ -311,34 +313,34 @@ const Benchmarks = () => {
|
|||
<div className="relative w-full sm:w-64">
|
||||
<Search
|
||||
size={15}
|
||||
className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"
|
||||
className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground/60"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t('搜索模型名称或供应商...')}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="w-full bg-white/5 border border-white/10 rounded-lg pl-9 pr-3 py-2 text-sm text-white placeholder-gray-500 focus:outline-none focus:border-white/30 focus:bg-white/10 transition-all"
|
||||
className="w-full bg-muted/30 border border-input rounded-lg pl-9 pr-3 py-2 text-sm text-foreground placeholder-muted-foreground/50 focus:outline-none focus:border-ring focus:bg-muted/50 transition-all"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Model Count */}
|
||||
<div className="text-xs text-gray-500 mb-3">
|
||||
<div className="text-xs text-muted-foreground/60 mb-3">
|
||||
{t('共 {count} 个模型', { count: filteredModels.length })}
|
||||
</div>
|
||||
|
||||
{/* Table */}
|
||||
<div className="overflow-x-auto rounded-xl border border-white/10">
|
||||
<div className="overflow-x-auto rounded-xl border border-border">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="bg-white/5 border-b border-white/10">
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-gray-400 uppercase tracking-wider w-10">
|
||||
<tr className="bg-muted/30 border-b border-border">
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider w-10">
|
||||
#
|
||||
</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-gray-400 uppercase tracking-wider">
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Brain size={13} className="text-gray-500" />
|
||||
<Brain size={13} className="text-muted-foreground/60" />
|
||||
<span>{t('模型名称')}</span>
|
||||
</div>
|
||||
</th>
|
||||
|
|
@ -354,39 +356,39 @@ const Benchmarks = () => {
|
|||
icon={DollarSign}
|
||||
/>
|
||||
<SortHeader label="延迟" sortField="latency" icon={Clock} />
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-gray-400 uppercase tracking-wider">
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Maximize2 size={13} className="text-gray-500" />
|
||||
<Maximize2 size={13} className="text-muted-foreground/60" />
|
||||
<span>{t('上下文')}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th className="px-4 py-3 text-center text-xs font-semibold text-gray-400 uppercase tracking-wider">
|
||||
<th className="px-4 py-3 text-center text-xs font-semibold text-muted-foreground uppercase tracking-wider">
|
||||
{t('类型')}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/5">
|
||||
<tbody className="divide-y divide-border/40">
|
||||
{filteredModels.map((model, idx) => (
|
||||
<tr
|
||||
key={model.name + model.provider}
|
||||
className="hover:bg-white/5 transition-colors"
|
||||
className="hover:bg-muted/50 transition-colors"
|
||||
>
|
||||
<td className="px-4 py-3.5 text-gray-500 text-xs font-mono">
|
||||
<td className="px-4 py-3.5 text-muted-foreground text-xs font-mono">
|
||||
{idx + 1}
|
||||
</td>
|
||||
<td className="px-4 py-3.5">
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium text-white text-sm">
|
||||
<span className="font-medium text-foreground text-sm">
|
||||
{model.name}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{model.provider}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-20 sm:w-24 h-2 bg-white/10 rounded-full overflow-hidden">
|
||||
<div className="w-20 sm:w-24 h-2 bg-muted rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full rounded-full transition-all"
|
||||
style={{
|
||||
|
|
@ -395,14 +397,14 @@ const Benchmarks = () => {
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-xs font-mono text-gray-300 w-8 text-right">
|
||||
<span className="text-xs font-mono text-foreground/70 w-8 text-right">
|
||||
{model.intelligence}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-16 sm:w-20 h-2 bg-white/10 rounded-full overflow-hidden">
|
||||
<div className="w-16 sm:w-20 h-2 bg-muted rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full rounded-full transition-all"
|
||||
style={{
|
||||
|
|
@ -411,23 +413,23 @@ const Benchmarks = () => {
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-xs font-mono text-gray-300 whitespace-nowrap">
|
||||
<span className="text-xs font-mono text-foreground/70 whitespace-nowrap">
|
||||
{model.speed?.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3.5">
|
||||
<span className="text-xs font-mono text-gray-300">
|
||||
<span className="text-xs font-mono text-foreground/70">
|
||||
${model.price?.toFixed(2)}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3.5">
|
||||
<span className="text-xs font-mono text-gray-300">
|
||||
<span className="text-xs font-mono text-foreground/70">
|
||||
{model.latency?.toFixed(2)}s
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3.5">
|
||||
<span className="text-xs text-gray-400">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{model.context_window || '-'}
|
||||
</span>
|
||||
</td>
|
||||
|
|
@ -435,8 +437,8 @@ const Benchmarks = () => {
|
|||
<span
|
||||
className={`inline-block px-2 py-0.5 rounded text-[10px] font-medium ${
|
||||
model.type === 'reasoning'
|
||||
? 'bg-purple-900/50 text-purple-300 border border-purple-700/50'
|
||||
: 'bg-blue-900/50 text-blue-300 border border-blue-700/50'
|
||||
? 'bg-purple-100 text-purple-700 border border-purple-200 dark:bg-purple-900/50 dark:text-purple-300 dark:border-purple-700/50'
|
||||
: 'bg-blue-100 text-blue-700 border border-blue-200 dark:bg-blue-900/50 dark:text-blue-300 dark:border-blue-700/50'
|
||||
}`}
|
||||
>
|
||||
{model.type === 'reasoning'
|
||||
|
|
@ -449,14 +451,14 @@ const Benchmarks = () => {
|
|||
</tbody>
|
||||
</table>
|
||||
{filteredModels.length === 0 && (
|
||||
<div className="text-center py-12 text-gray-500 text-sm">
|
||||
<div className="text-center py-12 text-muted-foreground text-sm">
|
||||
{t('暂未找到匹配的模型')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="mt-6 text-center text-xs text-gray-600">
|
||||
<div className="mt-6 text-center text-xs text-muted-foreground/50">
|
||||
{t('数据来源: Artificial Analysis | 数据持续更新中')}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue