feat(webui): refactor settings architecture and achieve full i18n coverage
This commit is contained in:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user