mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-01-18 06:20:29 +00:00
Refactor theme font handling and preview logic
Moved font configuration to be managed via theme.css, eliminating the need for separate font initialization and caching. Updated backend to generate @font-face rules and font variables in theme.css. Frontend now uses a dedicated style tag for real-time font preview in the theme config page, and removes legacy font cache logic for improved consistency.
This commit is contained in:
parent
f1756c4d1c
commit
c6ec2126e0
@ -182,16 +182,56 @@ export async function InitWebUi (logger: ILogWrapper, pathWrapper: NapCatPathWra
|
|||||||
|
|
||||||
// 如果是自定义色彩,构建一个css文件
|
// 如果是自定义色彩,构建一个css文件
|
||||||
app.use('/files/theme.css', async (_req, res) => {
|
app.use('/files/theme.css', async (_req, res) => {
|
||||||
const colors = await WebUiConfig.GetTheme();
|
const theme = await WebUiConfig.GetTheme();
|
||||||
|
const fontMode = theme.fontMode || 'system';
|
||||||
|
|
||||||
let css = ':root, .light, [data-theme="light"] {';
|
let css = '';
|
||||||
for (const key in colors.light) {
|
|
||||||
css += `${key}: ${colors.light[key]};`;
|
// 生成字体 @font-face
|
||||||
|
if (fontMode === 'aacute') {
|
||||||
|
css += `
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Aa偷吃可爱长大的';
|
||||||
|
src: url('/webui/fonts/AaCute.woff') format('woff');
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
} else if (fontMode === 'custom') {
|
||||||
|
css += `
|
||||||
|
@font-face {
|
||||||
|
font-family: 'CustomFont';
|
||||||
|
src: url('/webui/fonts/CustomFont.woff') format('woff');
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成颜色主题和字体变量
|
||||||
|
css += ':root, .light, [data-theme="light"] {';
|
||||||
|
for (const key in theme.light) {
|
||||||
|
css += `${key}: ${theme.light[key]};`;
|
||||||
|
}
|
||||||
|
// 添加字体变量
|
||||||
|
if (fontMode === 'aacute') {
|
||||||
|
css += "--font-family-base: 'Aa偷吃可爱长大的', var(--font-family-fallbacks) !important;";
|
||||||
|
} else if (fontMode === 'custom') {
|
||||||
|
css += "--font-family-base: 'CustomFont', var(--font-family-fallbacks) !important;";
|
||||||
|
} else {
|
||||||
|
css += '--font-family-base: var(--font-family-fallbacks) !important;';
|
||||||
}
|
}
|
||||||
css += '}';
|
css += '}';
|
||||||
|
|
||||||
css += '.dark, [data-theme="dark"] {';
|
css += '.dark, [data-theme="dark"] {';
|
||||||
for (const key in colors.dark) {
|
for (const key in theme.dark) {
|
||||||
css += `${key}: ${colors.dark[key]};`;
|
css += `${key}: ${theme.dark[key]};`;
|
||||||
|
}
|
||||||
|
// 添加字体变量
|
||||||
|
if (fontMode === 'aacute') {
|
||||||
|
css += "--font-family-base: 'Aa偷吃可爱长大的', var(--font-family-fallbacks) !important;";
|
||||||
|
} else if (fontMode === 'custom') {
|
||||||
|
css += "--font-family-base: 'CustomFont', var(--font-family-fallbacks) !important;";
|
||||||
|
} else {
|
||||||
|
css += '--font-family-base: var(--font-family-fallbacks) !important;';
|
||||||
}
|
}
|
||||||
css += '}';
|
css += '}';
|
||||||
|
|
||||||
|
|||||||
@ -268,15 +268,17 @@ const ThemeConfigCard = () => {
|
|||||||
|
|
||||||
// 找到已保存的主题名称
|
// 找到已保存的主题名称
|
||||||
const savedThemeName = useMemo(() => {
|
const savedThemeName = useMemo(() => {
|
||||||
if (!originalDataRef.current) return null;
|
const savedData = originalDataRef.current || data;
|
||||||
return themes.find(t => isThemeColorsEqual(t.theme, originalDataRef.current!))?.name || '自定义';
|
if (!savedData) return null;
|
||||||
}, [dataLoaded, hasUnsavedChanges]);
|
return themes.find(t => isThemeColorsEqual(t.theme, savedData))?.name || '自定义';
|
||||||
|
}, [data, dataLoaded, hasUnsavedChanges]);
|
||||||
|
|
||||||
// 已保存的字体模式显示名称
|
// 已保存的字体模式显示名称
|
||||||
const savedFontModeDisplayName = useMemo(() => {
|
const savedFontModeDisplayName = useMemo(() => {
|
||||||
const mode = originalDataRef.current?.fontMode || 'aacute';
|
const savedData = originalDataRef.current || data;
|
||||||
|
const mode = savedData?.fontMode || 'aacute';
|
||||||
return fontModeNames[mode] || mode;
|
return fontModeNames[mode] || mode;
|
||||||
}, [dataLoaded, hasUnsavedChanges]);
|
}, [data, dataLoaded, hasUnsavedChanges]);
|
||||||
|
|
||||||
if (loading) return <PageLoading loading />;
|
if (loading) return <PageLoading loading />;
|
||||||
|
|
||||||
|
|||||||
@ -3,24 +3,27 @@ import { request } from './request';
|
|||||||
const style = document.createElement('style');
|
const style = document.createElement('style');
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
|
|
||||||
// 字体样式标签
|
// 用于主题配置页面实时预览字体的临时样式标签
|
||||||
const fontStyle = document.createElement('style');
|
const fontPreviewStyle = document.createElement('style');
|
||||||
fontStyle.id = 'dynamic-font-style';
|
fontPreviewStyle.id = 'font-preview-style';
|
||||||
document.head.appendChild(fontStyle);
|
document.head.appendChild(fontPreviewStyle);
|
||||||
|
|
||||||
export function loadTheme () {
|
export function loadTheme () {
|
||||||
request('/files/theme.css?_t=' + Date.now())
|
request('/files/theme.css?_t=' + Date.now())
|
||||||
.then((res) => res.data)
|
.then((res) => res.data)
|
||||||
.then((css) => {
|
.then((css) => {
|
||||||
style.innerHTML = css;
|
style.innerHTML = css;
|
||||||
|
// 清除预览样式,使用 theme.css 中的正式配置
|
||||||
|
fontPreviewStyle.innerHTML = '';
|
||||||
|
document.documentElement.style.removeProperty('--font-family-base');
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
console.error('Failed to load theme.css');
|
console.error('Failed to load theme.css');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 动态加载字体 CSS
|
// 动态加载字体 CSS(用于预览)
|
||||||
const loadFontCSS = (mode: string) => {
|
const loadFontCSSForPreview = (mode: string) => {
|
||||||
let css = '';
|
let css = '';
|
||||||
|
|
||||||
if (mode === 'aacute') {
|
if (mode === 'aacute') {
|
||||||
@ -39,7 +42,7 @@ const loadFontCSS = (mode: string) => {
|
|||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
fontStyle.innerHTML = css;
|
fontPreviewStyle.innerHTML = css;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const colorKeys = [
|
export const colorKeys = [
|
||||||
@ -168,11 +171,12 @@ export const generateTheme = (theme: ThemeConfig, validField?: string) => {
|
|||||||
return css;
|
return css;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 用于主题配置页面实时预览字体
|
||||||
export const applyFont = (mode: string) => {
|
export const applyFont = (mode: string) => {
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
|
|
||||||
// 先加载字体 CSS
|
// 加载字体 CSS 用于预览
|
||||||
loadFontCSS(mode);
|
loadFontCSSForPreview(mode);
|
||||||
|
|
||||||
if (mode === 'aacute') {
|
if (mode === 'aacute') {
|
||||||
root.style.setProperty('--font-family-base', "'Aa偷吃可爱长大的', var(--font-family-fallbacks)", 'important');
|
root.style.setProperty('--font-family-base', "'Aa偷吃可爱长大的', var(--font-family-fallbacks)", 'important');
|
||||||
@ -184,36 +188,13 @@ export const applyFont = (mode: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const FONT_MODE_CACHE_KEY = 'webui-font-mode-cache';
|
// 字体配置已通过 theme.css 加载,此函数仅用于兼容性保留
|
||||||
|
|
||||||
export const initFont = () => {
|
export const initFont = () => {
|
||||||
// 先从缓存读取,立即应用
|
// 字体现在由 theme.css 统一管理,无需单独初始化
|
||||||
const cached = localStorage.getItem(FONT_MODE_CACHE_KEY);
|
|
||||||
if (cached) {
|
|
||||||
applyFont(cached);
|
|
||||||
} else {
|
|
||||||
// 默认使用系统字体
|
|
||||||
applyFont('system');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 后台拉取最新配置并更新缓存
|
|
||||||
request('/api/base/Theme')
|
|
||||||
.then((res) => {
|
|
||||||
const data = res.data as { data: ThemeConfig; };
|
|
||||||
const fontMode = data?.data?.fontMode || 'system';
|
|
||||||
// 更新缓存
|
|
||||||
localStorage.setItem(FONT_MODE_CACHE_KEY, fontMode);
|
|
||||||
// 如果与当前不同,则应用新字体
|
|
||||||
if (fontMode !== cached) {
|
|
||||||
applyFont(fontMode);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error('Failed to fetch font config', e);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 保存时更新缓存
|
// 保存主题后调用 loadTheme 会使用 theme.css 中的正式配置
|
||||||
export const updateFontCache = (fontMode: string) => {
|
// 此函数保留用于兼容性
|
||||||
localStorage.setItem(FONT_MODE_CACHE_KEY, fontMode);
|
export const updateFontCache = (_fontMode: string) => {
|
||||||
|
// 不再需要缓存,字体配置已在 theme.css 中
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user