feat(webui): optimize CSS build system and enhance UI quality

This commit is contained in:
Wha1eChai
2026-01-11 02:56:51 +08:00
parent a56bc06cc1
commit bda9623f3a
11 changed files with 81 additions and 35 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Mark generated CSS file to reduce diff noise
public/css/style.css linguist-generated=true -diff

View File

@@ -63,6 +63,10 @@
} }
/* Custom Scrollbar */ /* Custom Scrollbar */
.custom-scrollbar {
scrollbar-gutter: stable;
}
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 8px; width: 8px;
height: 8px; height: 8px;
@@ -259,6 +263,7 @@
rgba(15, 15, 17, 0.75) 0%, rgba(15, 15, 17, 0.75) 0%,
rgba(18, 18, 20, 0.70) 100% rgba(18, 18, 20, 0.70) 100%
); );
-webkit-backdrop-filter: blur(12px);
backdrop-filter: blur(12px); backdrop-filter: blur(12px);
box-shadow: box-shadow:
0 0 0 1px rgba(255, 255, 255, 0.02) inset, 0 0 0 1px rgba(255, 255, 255, 0.02) inset,

2
public/css/style.css generated

File diff suppressed because one or more lines are too long

View File

@@ -91,8 +91,8 @@
<div class="h-4 w-px bg-space-border"></div> <div class="h-4 w-px bg-space-border"></div>
<!-- Refresh Button --> <!-- Refresh Button -->
<button class="btn btn-ghost btn-xs btn-square text-gray-400 hover:text-white hover:bg-white/5" <button type="button" class="btn btn-ghost btn-xs btn-square text-gray-400 hover:text-white hover:bg-white/5"
@click="fetchData" :disabled="loading" :title="$store.global.t('refreshData')"> @click="fetchData" :disabled="loading" :title="$store.global.t('refreshData')" aria-label="Refresh data">
<svg class="w-4 h-4" :class="{'animate-spin': loading}" fill="none" stroke="currentColor" <svg class="w-4 h-4" :class="{'animate-spin': loading}" fill="none" stroke="currentColor"
viewBox="0 0 24 24"> viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
@@ -171,15 +171,15 @@
<!-- Footer Info --> <!-- Footer Info -->
<div class="mt-auto px-6 text-[10px] text-gray-700 font-mono"> <div class="mt-auto px-6 text-[10px] text-gray-700 font-mono">
<div class="flex justify-between"> <div class="flex justify-between">
<span>V 1.0.0</span> <span x-text="'V ' + $store.global.version">V 1.0.0</span>
<a href="https://github.com/badri-s2001/antigravity-claude-proxy" target="_blank" <a href="https://github.com/badri-s2001/antigravity-claude-proxy" target="_blank" rel="noopener noreferrer"
class="hover:text-neon-purple transition-colors">GitHub</a> class="hover:text-neon-purple transition-colors">GitHub</a>
</div> </div>
</div> </div>
</div> </div>
<!-- Main Content --> <!-- Main Content -->
<div class="flex-1 overflow-auto bg-space-950 relative custom-scrollbar" style="scrollbar-gutter: stable;"> <div class="flex-1 overflow-auto bg-space-950 relative custom-scrollbar">
<!-- Views Container --> <!-- Views Container -->
<!-- Dashboard --> <!-- Dashboard -->
@@ -257,12 +257,12 @@
<div class="modal-action mt-6"> <div class="modal-action mt-6">
<form method="dialog"> <form method="dialog">
<button class="btn btn-ghost hover:bg-white/10" x-text="$store.global.t('close')">Close</button> <button type="button" class="btn btn-ghost hover:bg-white/10" x-text="$store.global.t('close')">Close</button>
</form> </form>
</div> </div>
</div> </div>
<form method="dialog" class="modal-backdrop"> <form method="dialog" class="modal-backdrop">
<button x-text="$store.global.t('close')">close</button> <button type="button" x-text="$store.global.t('close')">close</button>
</form> </form>
</dialog> </dialog>

View File

@@ -6,6 +6,7 @@ window.Components = window.Components || {};
window.Components.claudeConfig = () => ({ window.Components.claudeConfig = () => ({
config: { env: {} }, config: { env: {} },
configPath: '', // Dynamic path from backend
models: [], models: [],
loading: false, loading: false,
gemini1mSuffix: false, gemini1mSuffix: false,
@@ -97,6 +98,7 @@ window.Components.claudeConfig = () => ({
if (!response.ok) throw new Error(`HTTP ${response.status}`); if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json(); const data = await response.json();
this.config = data.config || {}; this.config = data.config || {};
this.configPath = data.path || '~/.claude/settings.json'; // Save dynamic path
if (!this.config.env) this.config.env = {}; if (!this.config.env) this.config.env = {};
// Default MCP CLI to true if not set // Default MCP CLI to true if not set

View File

@@ -149,7 +149,7 @@ window.DashboardCharts.updateCharts = function (component) {
// Safety checks // Safety checks
if (!canvas) { if (!canvas) {
console.warn("quotaChart canvas not found"); console.debug("quotaChart canvas not found");
return; return;
} }
if (typeof Chart === "undefined") { if (typeof Chart === "undefined") {
@@ -157,7 +157,7 @@ window.DashboardCharts.updateCharts = function (component) {
return; return;
} }
if (!isCanvasReady(canvas)) { if (!isCanvasReady(canvas)) {
console.warn("quotaChart canvas not ready, skipping update"); console.debug("quotaChart canvas not ready, skipping update");
return; return;
} }

View File

@@ -69,6 +69,11 @@ document.addEventListener('alpine:init', () => {
this.connectionStatus = 'connected'; this.connectionStatus = 'connected';
this.lastUpdated = new Date().toLocaleTimeString(); this.lastUpdated = new Date().toLocaleTimeString();
// Fetch version from config endpoint if not already loaded
if (this.initialLoad) {
this.fetchVersion(password);
}
} catch (error) { } catch (error) {
console.error('Fetch error:', error); console.error('Fetch error:', error);
this.connectionStatus = 'disconnected'; this.connectionStatus = 'disconnected';
@@ -80,6 +85,20 @@ document.addEventListener('alpine:init', () => {
} }
}, },
async fetchVersion(password) {
try {
const { response } = await window.utils.request('/api/config', {}, password);
if (response.ok) {
const data = await response.json();
if (data.version) {
Alpine.store('global').version = data.version;
}
}
} catch (error) {
console.warn('Failed to fetch version:', error);
}
},
computeQuotaRows() { computeQuotaRows() {
const models = this.models || []; const models = this.models || [];
const rows = []; const rows = [];

View File

@@ -98,7 +98,8 @@ document.addEventListener('alpine:init', () => {
opusAlias: "Opus Alias", opusAlias: "Opus Alias",
sonnetAlias: "Sonnet Alias", sonnetAlias: "Sonnet Alias",
haikuAlias: "Haiku Alias", haikuAlias: "Haiku Alias",
claudeSettingsAlert: "Settings below directly modify ~/.claude/settings.json. Restart Claude CLI to apply.", claudeSettingsAlertPrefix: "Settings below directly modify",
claudeSettingsAlertSuffix: "Restart Claude CLI to apply.",
applyToClaude: "Apply to Claude CLI", applyToClaude: "Apply to Claude CLI",
// Settings - Server // Settings - Server
port: "Port", port: "Port",
@@ -118,7 +119,7 @@ document.addEventListener('alpine:init', () => {
sonnetModel: "Sonnet Model", sonnetModel: "Sonnet Model",
haikuModel: "Haiku Model", haikuModel: "Haiku Model",
authToken: "Auth Token", authToken: "Auth Token",
saveConfig: "Save to ~/.claude/settings.json", saveConfig: "Save to Claude CLI settings",
envVar: "Env", envVar: "Env",
// New Keys // New Keys
systemName: "ANTIGRAVITY", systemName: "ANTIGRAVITY",
@@ -346,7 +347,8 @@ document.addEventListener('alpine:init', () => {
opusAlias: "Opus 别名", opusAlias: "Opus 别名",
sonnetAlias: "Sonnet 别名", sonnetAlias: "Sonnet 别名",
haikuAlias: "Haiku 别名", haikuAlias: "Haiku 别名",
claudeSettingsAlert: "以下设置直接修改 ~/.claude/settings.json。重启 Claude CLI 生效。", claudeSettingsAlertPrefix: "以下设置直接修改",
claudeSettingsAlertSuffix: "重启 Claude CLI 生效。",
applyToClaude: "应用到 Claude CLI", applyToClaude: "应用到 Claude CLI",
// Settings - Server // Settings - Server
port: "端口", port: "端口",
@@ -366,7 +368,7 @@ document.addEventListener('alpine:init', () => {
sonnetModel: "Sonnet 模型", sonnetModel: "Sonnet 模型",
haikuModel: "Haiku 模型", haikuModel: "Haiku 模型",
authToken: "认证令牌", authToken: "认证令牌",
saveConfig: "保存到 ~/.claude/settings.json", saveConfig: "保存到 Claude CLI 设置",
envVar: "环境变量", envVar: "环境变量",
// New Keys // New Keys
systemName: "ANTIGRAVITY", systemName: "ANTIGRAVITY",

View File

@@ -53,7 +53,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24"
stroke="currentColor"> stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" /> d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" />
</svg> </svg>
<span x-text="$store.global.t('tabServer')">Server</span> <span x-text="$store.global.t('tabServer')">Server</span>
</button> </button>
@@ -197,9 +197,11 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path> d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg> </svg>
<span class="text-gray-400" x-text="$store.global.t('claudeSettingsAlert')">Settings below directly <span class="text-gray-400">
modify <code class="text-neon-cyan font-mono">~/.claude/settings.json</code>. Restart Claude CLI <span x-text="$store.global.t('claudeSettingsAlertPrefix')">Settings below directly modify</span>
to apply.</span> <code class="text-neon-cyan font-mono" x-text="configPath">~/.claude/settings.json</code>.
<span x-text="$store.global.t('claudeSettingsAlertSuffix')">Restart Claude CLI to apply.</span>
</span>
</div> </div>
<!-- Base URL --> <!-- Base URL -->

View File

@@ -13,6 +13,8 @@
*/ */
import path from 'path'; import path from 'path';
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import express from 'express'; import express from 'express';
import { getPublicConfig, saveConfig, config } from '../config.js'; import { getPublicConfig, saveConfig, config } from '../config.js';
import { DEFAULT_PORT, ACCOUNT_CONFIG_PATH } from '../constants.js'; import { DEFAULT_PORT, ACCOUNT_CONFIG_PATH } from '../constants.js';
@@ -21,6 +23,18 @@ import { logger } from '../utils/logger.js';
import { getAuthorizationUrl, completeOAuthFlow, startCallbackServer } from '../auth/oauth.js'; import { getAuthorizationUrl, completeOAuthFlow, startCallbackServer } from '../auth/oauth.js';
import { loadAccounts, saveAccounts } from '../account-manager/storage.js'; import { loadAccounts, saveAccounts } from '../account-manager/storage.js';
// Get package version
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
let packageVersion = '1.0.0';
try {
const packageJsonPath = path.join(__dirname, '../../package.json');
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
packageVersion = packageJson.version;
} catch (error) {
logger.warn('[WebUI] Could not read package.json version, using default');
}
// OAuth state storage (state -> { server, verifier, state, timestamp }) // OAuth state storage (state -> { server, verifier, state, timestamp })
// Maps state ID to active OAuth flow data // Maps state ID to active OAuth flow data
const pendingOAuthFlows = new Map(); const pendingOAuthFlows = new Map();
@@ -254,6 +268,7 @@ export function mountWebUI(app, dirname, accountManager) {
res.json({ res.json({
status: 'ok', status: 'ok',
config: publicConfig, config: publicConfig,
version: packageVersion,
note: 'Edit ~/.config/antigravity-proxy/config.json or use env vars to change these values' note: 'Edit ~/.config/antigravity-proxy/config.json or use env vars to change these values'
}); });
} catch (error) { } catch (error) {

View File

@@ -1,9 +1,7 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
content: [ content: [
"./public/**/*.{html,js}", "./public/**/*.{html,js}" // Simplified: already covers all subdirectories
"./public/views/**/*.html",
"./public/js/**/*.js"
], ],
darkMode: 'class', darkMode: 'class',
theme: { theme: {
@@ -37,16 +35,17 @@ export default {
daisyui: { daisyui: {
themes: [{ themes: [{
antigravity: { antigravity: {
"primary": "var(--color-neon-purple)", "primary": "#a855f7", // neon-purple
"secondary": "var(--color-neon-green)", "secondary": "#22c55e", // neon-green
"accent": "var(--color-neon-cyan)", "accent": "#06b6d4", // neon-cyan
"neutral": "var(--color-space-800)", "neutral": "#18181b", // space-800
"base-100": "var(--color-space-950)", "base-100": "#09090b", // space-950
"info": "var(--color-neon-cyan)", "info": "#06b6d4", // neon-cyan
"success": "var(--color-neon-green)", "success": "#22c55e", // neon-green
"warning": "var(--color-neon-yellow)", "warning": "#eab308", // neon-yellow
"error": "var(--color-neon-red)", "error": "#ef4444", // neon-red
} }
}] }],
logs: false // Disable console logs in production
} }
} }