From c137bdcc636540b9e0177fd0bbff096686d42f63 Mon Sep 17 00:00:00 2001 From: sagitchu Date: Fri, 20 Mar 2026 23:37:35 +0800 Subject: [PATCH 1/2] fix: theme persistence and update version to 2.1.9-beta9 --- vite-frontend/index.html | 25 +++++++++++++++---- .../src/components/theme-provider.tsx | 6 +++++ vite-frontend/src/pages/config.tsx | 6 +++++ vite-frontend/src/pages/settings.tsx | 2 -- vite-frontend/src/themes/context.tsx | 6 ----- 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/vite-frontend/index.html b/vite-frontend/index.html index 22bb708..be002a4 100644 --- a/vite-frontend/index.html +++ b/vite-frontend/index.html @@ -85,11 +85,22 @@ shortcutIconLink.removeAttribute('type'); } - // 立即检测系统主题并应用 - const isDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; + // 立即检测主题并应用(优先读取 localStorage 中的用户偏好) + var savedMode = ''; + try { savedMode = localStorage.getItem('flvx:theme') || ''; } catch (_) {} + + var useDark; + if (savedMode === 'dark') { + useDark = true; + } else if (savedMode === 'light') { + useDark = false; + } else { + // "system" 或无保存:跟随系统 + useDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; + } // 立即设置主题类,避免闪烁 - if (isDarkMode) { + if (useDark) { document.documentElement.classList.add('dark'); document.documentElement.style.colorScheme = 'dark'; } else { @@ -97,9 +108,13 @@ document.documentElement.style.colorScheme = 'light'; } - // 监听系统主题变化 - if (window.matchMedia) { + // 仅在"跟随系统"模式下监听系统主题变化 + if ((!savedMode || savedMode === 'system') && window.matchMedia) { window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) { + // 运行时可能已由 React 接管,这里仅做 fallback + var currentMode = ''; + try { currentMode = localStorage.getItem('flvx:theme') || ''; } catch (_) {} + if (currentMode && currentMode !== 'system') return; // 用户已手动选择,不干预 if (e.matches) { document.documentElement.classList.add('dark'); document.documentElement.style.colorScheme = 'dark'; diff --git a/vite-frontend/src/components/theme-provider.tsx b/vite-frontend/src/components/theme-provider.tsx index d347244..cad9517 100644 --- a/vite-frontend/src/components/theme-provider.tsx +++ b/vite-frontend/src/components/theme-provider.tsx @@ -12,6 +12,12 @@ import React from "react"; import "@/themes/loader"; import { ThemeProvider as ThemeContextProvider } from "@/themes/context"; +import { initThemeSystem } from "@/themes/registry"; + +// Restore saved theme SYNCHRONOUSLY at module load time — before first render. +// This ensures the CSS tokens are injected before any component renders, +// preventing a flash of the default theme. +initThemeSystem(); interface ThemeProviderProps { children: React.ReactNode; diff --git a/vite-frontend/src/pages/config.tsx b/vite-frontend/src/pages/config.tsx index 6c3412d..4a005a1 100644 --- a/vite-frontend/src/pages/config.tsx +++ b/vite-frontend/src/pages/config.tsx @@ -27,6 +27,7 @@ import { type AnnouncementData, } from "@/api"; import { BackIcon, SettingsIcon } from "@/components/icons"; +import { ThemeSettings } from "@/components/theme-settings"; import { isAdmin } from "@/utils/auth"; import { getCachedConfigs, configCache, updateSiteConfig } from "@/config/site"; import { @@ -979,6 +980,11 @@ export default function ConfigPage() { + {/* 主题设置 */} +
+ +
+ {hasChanges && (
diff --git a/vite-frontend/src/pages/settings.tsx b/vite-frontend/src/pages/settings.tsx index bf69d5e..55e3217 100644 --- a/vite-frontend/src/pages/settings.tsx +++ b/vite-frontend/src/pages/settings.tsx @@ -10,7 +10,6 @@ import { Switch } from "@/shadcn-bridge/heroui/switch"; import { reinitializeBaseURL } from "@/api/network"; import { getConfigByName, updateConfig } from "@/api"; import { BackIcon } from "@/components/icons"; -import { ThemeSettings } from "@/components/theme-settings"; import { type UpdateReleaseChannel, getUpdateReleaseChannel, @@ -182,7 +181,6 @@ export const SettingsPage = () => { {/* 内容区域 */}
-

diff --git a/vite-frontend/src/themes/context.tsx b/vite-frontend/src/themes/context.tsx index 492f317..7a4a10d 100644 --- a/vite-frontend/src/themes/context.tsx +++ b/vite-frontend/src/themes/context.tsx @@ -29,7 +29,6 @@ import { getSavedMode, saveMode, getEffectiveMode, - initThemeSystem, registerTheme, unregisterTheme, type ThemeMode, @@ -95,11 +94,6 @@ export const ThemeProvider: React.FC = ({ children }) => { // Re-render whenever register changes useSyncExternalStore(originalSubscribe, getSnapshot); - // Initialise on mount - useEffect(() => { - initThemeSystem(); - }, []); - // Listen for system mode changes useEffect(() => { const mq = window.matchMedia("(prefers-color-scheme: dark)"); From 9d05d75fd642b045a5b9b51b5a9d756210249ed2 Mon Sep 17 00:00:00 2001 From: sagitchu Date: Fri, 20 Mar 2026 23:37:47 +0800 Subject: [PATCH 2/2] docs: update AGENTS.md for release v2.1.9-beta9 --- AGENTS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7dd3fc2..a3c4269 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,9 +1,9 @@ # PROJECT KNOWLEDGE BASE **Generated:** Fri Mar 20 2026 -**Commit:** f45f960 +**Commit:** c137bdc **Branch:** main -**Tag:** 2.1.9-beta8 +**Tag:** 2.1.9-beta9 ## OVERVIEW FLVX (formerly Flux Panel) is a traffic forwarding management system built on a forked GOST v3 stack. It ships as a Go-based admin API (SQLite/PostgreSQL) + Vite/React UI + Go forwarding agent, with optional mobile WebView wrappers.