mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-13 09:36:05 +00:00
fix(frontend): real dark mode + silence dev proxy ECONNREFUSED noise
Two issues from running login.html against no Go backend:
1. Dark mode toggled the body class but didn't actually re-theme any
AD-Vue components. The legacy panel relied on custom.min.css which
we haven't ported. AD-Vue 4 ships its own dark algorithm — wrap
LoginPage in <a-config-provider :theme="{ algorithm }"> driven by
our useTheme state, and AD-Vue restyles every component for free.
Page chrome (background, card, title) gets explicit .is-dark CSS
since the algorithm only covers AD-Vue components.
2. Vite logged every failed proxy attempt loudly. When the Go panel
isn't running locally that's pure noise. Added a configure()
callback that swallows ECONNREFUSED specifically; real errors
(timeouts, 5xx, anything else) still surface.
Both fixes are dev-experience only — production build is unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
1faecbe1dd
commit
6056fda518
2 changed files with 48 additions and 8 deletions
|
|
@ -1,11 +1,19 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, reactive, ref } from 'vue';
|
import { computed, onMounted, reactive, ref } from 'vue';
|
||||||
import { UserOutlined, LockOutlined, KeyOutlined, SettingOutlined } from '@ant-design/icons-vue';
|
import { UserOutlined, LockOutlined, KeyOutlined, SettingOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { theme as antdTheme } from 'ant-design-vue';
|
||||||
|
|
||||||
import { HttpUtil } from '@/utils';
|
import { HttpUtil } from '@/utils';
|
||||||
import { currentTheme } from '@/composables/useTheme.js';
|
import { currentTheme, theme as themeState } from '@/composables/useTheme.js';
|
||||||
import ThemeSwitchLogin from '@/components/ThemeSwitchLogin.vue';
|
import ThemeSwitchLogin from '@/components/ThemeSwitchLogin.vue';
|
||||||
|
|
||||||
|
// Drive AD-Vue 4's built-in dark algorithm from our useTheme state.
|
||||||
|
// This re-themes every AD-Vue component without depending on the
|
||||||
|
// legacy panel's custom.min.css.
|
||||||
|
const antdThemeConfig = computed(() => ({
|
||||||
|
algorithm: themeState.isDark ? antdTheme.darkAlgorithm : antdTheme.defaultAlgorithm,
|
||||||
|
}));
|
||||||
|
|
||||||
// Phase 4 ships this page in English only. Translations come back in
|
// Phase 4 ships this page in English only. Translations come back in
|
||||||
// Phase 7 (vue-i18n) once we decide how the new build pipeline reads
|
// Phase 7 (vue-i18n) once we decide how the new build pipeline reads
|
||||||
// the existing TOML translation files.
|
// the existing TOML translation files.
|
||||||
|
|
@ -47,7 +55,8 @@ async function login() {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a-layout class="login-app">
|
<a-config-provider :theme="antdThemeConfig">
|
||||||
|
<a-layout class="login-app" :class="{ 'is-dark': themeState.isDark }">
|
||||||
<a-layout-content class="login-content">
|
<a-layout-content class="login-content">
|
||||||
<div class="waves-header">
|
<div class="waves-header">
|
||||||
<svg class="waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
<svg class="waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
|
@ -139,6 +148,7 @@ async function login() {
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-layout-content>
|
</a-layout-content>
|
||||||
</a-layout>
|
</a-layout>
|
||||||
|
</a-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
@ -146,6 +156,16 @@ async function login() {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #f0f2f5;
|
background: #f0f2f5;
|
||||||
}
|
}
|
||||||
|
.login-app.is-dark {
|
||||||
|
background: #141a26;
|
||||||
|
}
|
||||||
|
.login-app.is-dark :deep(.login-card) {
|
||||||
|
background: #1f2937;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
.login-app.is-dark :deep(.login-title) {
|
||||||
|
color: #2dd4bf;
|
||||||
|
}
|
||||||
|
|
||||||
.login-settings {
|
.login-settings {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,27 @@ import path from 'node:path';
|
||||||
// via embed.FS without reaching outside the web/ tree.
|
// via embed.FS without reaching outside the web/ tree.
|
||||||
const outDir = path.resolve(__dirname, '../web/dist');
|
const outDir = path.resolve(__dirname, '../web/dist');
|
||||||
|
|
||||||
|
// Build a proxy config that suppresses ECONNREFUSED noise when the Go
|
||||||
|
// backend isn't running locally. Real errors (timeouts, 5xx, etc.) still
|
||||||
|
// surface in the Vite log.
|
||||||
|
function makeBackendProxy(target, patterns) {
|
||||||
|
const config = {};
|
||||||
|
for (const pattern of patterns) {
|
||||||
|
config[pattern] = {
|
||||||
|
target,
|
||||||
|
changeOrigin: true,
|
||||||
|
configure(proxy) {
|
||||||
|
proxy.on('error', (err) => {
|
||||||
|
if (err.code === 'ECONNREFUSED') return;
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('[proxy]', err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|
@ -30,13 +51,12 @@ export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: 5173,
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
proxy: {
|
proxy: makeBackendProxy('http://localhost:2053', [
|
||||||
// Proxy API calls during `npm run dev` to the local Go panel.
|
|
||||||
// Patterns are anchored regex so /login.html and /index.html
|
// Patterns are anchored regex so /login.html and /index.html
|
||||||
// (which Vite serves itself) are NOT forwarded — only the bare
|
// (which Vite serves itself) are NOT forwarded — only the bare
|
||||||
// backend paths and their sub-routes.
|
// backend paths and their sub-routes.
|
||||||
'^/(login|logout|getTwoFactorEnable)$': 'http://localhost:2053',
|
'^/(login|logout|getTwoFactorEnable)$',
|
||||||
'^/(panel|server)(/|$)': 'http://localhost:2053',
|
'^/(panel|server)(/|$)',
|
||||||
},
|
]),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue