统一前后台主题颜色管理

This commit is contained in:
2026-09-05 23:12:17 +08:00
parent 69ab5676b4
commit 390c4ac53f
11 changed files with 643 additions and 88 deletions
+28 -7
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useRef, useState } from 'react';
import { Link, NavLink, Outlet, useLocation } from 'react-router-dom';
import { useTheme } from '../theme.jsx';
import { getThemePreference, useTheme } from '../theme.jsx';
import { applyThemeTokens, THEME_SETTINGS_EVENT, THEME_SETTINGS_SYNC_KEY } from '../themeTokens.js';
import * as authApi from '../api/auth.js';
import * as settingsApi from '../api/settings.js';
import { getToken, setToken, notifyAuthChange } from '../api/client.js';
@@ -81,9 +82,13 @@ export default function Layout() {
// 加载站点设置 / 版本号 / 登录态(监听 authchange 事件,登录/退出/头像更新后刷新)
useEffect(() => {
const updateSettings = (next) => {
if (!next || typeof next !== 'object') return;
setSettings((previous) => ({ ...previous, ...next }));
};
settingsApi.getPublicSettings()
.then((s) => {
setSettings(s);
updateSettings(s);
// 供第三方验证码(reCAPTCHA/Turnstile)读取(照搬 nav.js
window._recaptchaSiteKey = s.recaptcha_site_key || '';
window._turnstileSiteKey = s.turnstile_site_key || '';
@@ -102,17 +107,33 @@ export default function Layout() {
};
loadUser();
window.addEventListener('authchange', loadUser);
return () => window.removeEventListener('authchange', loadUser);
const onThemeSettings = (event) => updateSettings(event.detail);
const onStorage = (event) => {
if (event.key !== THEME_SETTINGS_SYNC_KEY || !event.newValue) return;
try { updateSettings(JSON.parse(event.newValue)); } catch {}
};
window.addEventListener(THEME_SETTINGS_EVENT, onThemeSettings);
window.addEventListener('storage', onStorage);
return () => {
window.removeEventListener('authchange', loadUser);
window.removeEventListener(THEME_SETTINGS_EVENT, onThemeSettings);
window.removeEventListener('storage', onStorage);
};
}, []);
// 强制深色模式(迁移自 nav.js applyTheme
useEffect(() => {
if (settings.theme_force_dark === '1') {
setTheme('dark');
document.documentElement.setAttribute('data-theme', 'dark');
}
setTheme(settings.theme_force_dark === '1' ? 'dark' : getThemePreference(), { persist: false });
}, [settings.theme_force_dark, setTheme]);
useEffect(() => {
applyThemeTokens({
primary_color: settings.primary_color,
mode: theme,
glass_opacity: settings.glass_opacity,
});
}, [settings.primary_color, settings.glass_opacity, theme]);
// 壁纸背景 + 玻璃磨砂(迁移自 nav.js applyTheme,直接作用于 body
useEffect(() => {
const body = document.body;