feat(webui): refactor settings architecture and achieve full i18n coverage

This commit is contained in:
Wha1eChai
2026-01-09 00:39:25 +08:00
parent c9c5e7d486
commit a4814b8c34
10 changed files with 711 additions and 423 deletions

View File

@@ -74,14 +74,14 @@
<div class="flex items-center gap-1.5 truncate">
<div class="w-1.5 h-1.5 rounded-full bg-neon-purple shadow-[0_0_4px_rgba(168,85,247,0.4)] flex-shrink-0">
</div>
<span class="truncate">Claude</span>
<span class="truncate" x-text="$store.global.t('familyClaude')">Claude</span>
</div>
</div>
<div class="flex items-center justify-between text-[10px] text-gray-400">
<div class="flex items-center gap-1.5 truncate">
<div class="w-1.5 h-1.5 rounded-full bg-neon-green shadow-[0_0_4px_rgba(34,197,94,0.4)] flex-shrink-0">
</div>
<span class="truncate">Gemini</span>
<span class="truncate" x-text="$store.global.t('familyGemini')">Gemini</span>
</div>
</div>
</div>
@@ -111,15 +111,15 @@
<!-- Usage Stats Pills -->
<div class="flex flex-wrap gap-2 text-[10px] font-mono">
<div class="px-2 py-1 rounded bg-space-800 border border-space-border/50 whitespace-nowrap">
<span class="text-gray-500">Total:</span>
<span class="text-gray-500" x-text="$store.global.t('totalColon')">Total:</span>
<span class="text-white ml-1" x-text="usageStats.total"></span>
</div>
<div class="px-2 py-1 rounded bg-space-800 border border-space-border/50 whitespace-nowrap">
<span class="text-gray-500">Today:</span>
<span class="text-gray-500" x-text="$store.global.t('todayColon')">Today:</span>
<span class="text-neon-cyan ml-1" x-text="usageStats.today"></span>
</div>
<div class="px-2 py-1 rounded bg-space-800 border border-space-border/50 whitespace-nowrap">
<span class="text-gray-500">1H:</span>
<span class="text-gray-500" x-text="$store.global.t('hour1Colon')">1H:</span>
<span class="text-neon-green ml-1" x-text="usageStats.thisHour"></span>
</div>
</div>
@@ -148,7 +148,7 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
</svg>
<span>Filter (<span x-text="getSelectedCount()"></span>)</span>
<span x-text="$store.global.t('filter') + ' (' + getSelectedCount() + ')'">Filter (0/0)</span>
<svg class="w-3 h-3 transition-transform" :class="{'rotate-180': showModelFilter}" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
@@ -170,12 +170,7 @@
x-text="displayMode === 'family' ? $store.global.t('selectFamilies') : $store.global.t('selectModels')"></span>
<div class="flex gap-1">
<button @click="autoSelectTopN(5)" class="text-[10px] text-neon-purple hover:underline"
title="Select Top 5 most used models (24h)">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3 h-3 inline-block" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
:title="$store.global.t('smartTitle')" x-text="$store.global.t('smart')">
Smart
</button>
<span class="text-gray-600">|</span>
@@ -199,8 +194,8 @@
@change="toggleFamily(family)" class="checkbox checkbox-xs checkbox-primary">
<div class="w-2 h-2 rounded-full flex-shrink-0"
:style="'background-color:' + getFamilyColor(family)"></div>
<span class="text-xs text-gray-300 font-medium capitalize group-hover:text-white"
x-text="family"></span>
<span class="text-xs text-gray-300 font-medium group-hover:text-white"
x-text="$store.global.t('family' + family.charAt(0).toUpperCase() + family.slice(1))"></span>
<span class="text-[10px] text-gray-600 ml-auto"
x-text="'(' + (modelTree[family] || []).length + ')'"></span>
</label>
@@ -210,7 +205,7 @@
x-show="displayMode === 'model'">
<div class="w-1.5 h-1.5 rounded-full"
:style="'background-color:' + getFamilyColor(family)"></div>
<span x-text="family"></span>
<span x-text="$store.global.t('family' + family.charAt(0).toUpperCase() + family.slice(1))"></span>
</div>
<!-- Models in Family -->
@@ -254,7 +249,7 @@
<template x-for="family in selectedFamilies" :key="family">
<div class="flex items-center gap-1.5 text-[10px] font-mono">
<div class="w-2 h-2 rounded-full" :style="'background-color:' + getFamilyColor(family)"></div>
<span class="text-gray-400 capitalize" x-text="family"></span>
<span class="text-gray-400" x-text="$store.global.t('family' + family.charAt(0).toUpperCase() + family.slice(1))"></span>
</div>
</template>
</template>
@@ -319,15 +314,15 @@
<button
class="join-item btn btn-sm h-full flex-1 md:flex-none px-4 md:px-6 border-space-border bg-space-800 text-gray-400 hover:text-white hover:bg-space-700 hover:border-space-600 transition-all font-medium text-xs tracking-wide whitespace-nowrap"
:class="{'bg-neon-purple text-white border-neon-purple hover:bg-purple-600 hover:border-purple-500': $store.data.filters.family === 'all'}"
@click="$store.data.filters.family = 'all'; $store.data.computeQuotaRows()">ALL</button>
@click="$store.data.filters.family = 'all'; $store.data.computeQuotaRows()" x-text="$store.global.t('allCaps')">ALL</button>
<button
class="join-item btn btn-sm h-full flex-1 md:flex-none px-4 md:px-6 border-space-border bg-space-800 text-gray-400 hover:text-white hover:bg-space-700 hover:border-space-600 transition-all font-medium text-xs tracking-wide whitespace-nowrap"
:class="{'bg-neon-purple text-white border-neon-purple hover:bg-purple-600 hover:border-purple-500': $store.data.filters.family === 'claude'}"
@click="$store.data.filters.family = 'claude'; $store.data.computeQuotaRows()">CLAUDE</button>
@click="$store.data.filters.family = 'claude'; $store.data.computeQuotaRows()" x-text="$store.global.t('claudeCaps')">CLAUDE</button>
<button
class="join-item btn btn-sm h-full flex-1 md:flex-none px-4 md:px-6 border-space-border bg-space-800 text-gray-400 hover:text-white hover:bg-space-700 hover:border-space-600 transition-all font-medium text-xs tracking-wide whitespace-nowrap"
:class="{'bg-neon-purple text-white border-neon-purple hover:bg-purple-600 hover:border-purple-500': $store.data.filters.family === 'gemini'}"
@click="$store.data.filters.family = 'gemini'; $store.data.computeQuotaRows()">GEMINI</button>
@click="$store.data.filters.family = 'gemini'; $store.data.computeQuotaRows()" x-text="$store.global.t('geminiCaps')">GEMINI</button>
</div>
</div>
@@ -370,7 +365,8 @@
<td>
<div class="font-bold text-gray-200 group-hover:text-neon-purple transition-colors"
x-text="row.modelId"></div>
<div class="text-[10px] font-mono text-gray-500 uppercase" x-text="row.family">
<div class="text-[10px] font-mono text-gray-500 uppercase"
x-text="$store.global.t('family' + row.family.charAt(0).toUpperCase() + row.family.slice(1))">
</div>
</td>
<td>
@@ -392,7 +388,7 @@
<div class="flex items-center justify-end gap-3 pr-4">
<div
class="text-[10px] font-mono text-gray-500 hidden xl:block text-right leading-tight opacity-70">
<div x-text="row.quotaInfo.filter(q => q.pct > 0).length + ' Active'"></div>
<div x-text="$store.global.t('activeCount', {count: row.quotaInfo.filter(q => q.pct > 0).length})"></div>
</div>
<div class="flex flex-wrap gap-1 justify-end max-w-[200px]">
<template x-for="q in row.quotaInfo" :key="q.fullEmail">