diff --git a/packages/napcat-webui-frontend/src/pages/dashboard/config/theme.tsx b/packages/napcat-webui-frontend/src/pages/dashboard/config/theme.tsx
index 18dc8063..a1654127 100644
--- a/packages/napcat-webui-frontend/src/pages/dashboard/config/theme.tsx
+++ b/packages/napcat-webui-frontend/src/pages/dashboard/config/theme.tsx
@@ -1,8 +1,8 @@
-import { Accordion, AccordionItem } from '@heroui/accordion';
import { Button } from '@heroui/button';
import { Card, CardBody, CardHeader } from '@heroui/card';
import { Select, SelectItem } from '@heroui/select';
import { Chip } from '@heroui/chip';
+import { Tab, Tabs } from '@heroui/tabs';
import { useRequest } from 'ahooks';
import clsx from 'clsx';
import { useEffect, useRef, useState, useMemo, useCallback } from 'react';
@@ -298,159 +298,180 @@ const ThemeConfigCard = () => {
主题配置 - NapCat WebUI
{/* 顶部操作栏 */}
-
-
-
-
-
当前主题:
-
- {savedThemeName || '加载中...'}
-
+
+
+
+
外观设置
+
+
+
+ {savedThemeName || '加载中...'}
+
+
+
+
+ {savedFontModeDisplayName}
+
+ {hasUnsavedChanges && (
+ <>
+
+
+ >
+ )}
-
- 字体:
-
- {savedFontModeDisplayName}
-
-
- {hasUnsavedChanges && (
-
- 有未保存的更改
-
- )}
-
+
+
+
-
+ }
>
-
-
(
-
- )}
- />
- {theme.fontMode === 'custom' && (
-
-
- 上传自定义字体(仅在选择"自定义字体"时生效)
+
+
+
+
+
WebUI 字体
+
自定义界面显示的字体风格
+
(
+
+ )}
+ />
- {customFontExists && (
-
- 已上传自定义字体
-
- )}
-
{
- try {
- // 如果已存在自定义字体,先尝试删除
- if (customFontExists) {
+
+ {theme.fontMode === 'custom' && (
+
+
+
自定义字体文件
+ {customFontExists && (
+
}>
+ 已上传
+
+ )}
+
+
+
{
+ try {
+ if (customFontExists) {
+ try {
+ await FileManager.deleteWebUIFont();
+ } catch (e) {
+ console.warn('Failed to delete existing font before upload:', e);
+ }
+ }
+ await FileManager.uploadWebUIFont(file);
+ toast.success('上传成功,即将刷新页面');
+ setTimeout(() => window.location.reload(), 1000);
+ } catch (error) {
+ toast.error('上传失败: ' + (error as Error).message);
+ }
+ }}
+ onDelete={async () => {
try {
await FileManager.deleteWebUIFont();
- } catch (e) {
- console.warn('Failed to delete existing font before upload:', e);
- // 继续尝试上传,后端可能会覆盖或报错
+ toast.success('删除成功,即将刷新页面');
+ setTimeout(() => window.location.reload(), 1000);
+ } catch (error) {
+ toast.error('删除失败: ' + (error as Error).message);
}
- }
-
- await FileManager.uploadWebUIFont(file);
- toast.success('上传成功,即将刷新页面');
- setTimeout(() => {
- window.location.reload();
- }, 1000);
- } catch (error) {
- toast.error('上传失败: ' + (error as Error).message);
- }
- }}
- onDelete={async () => {
- try {
- await FileManager.deleteWebUIFont();
- toast.success('删除成功,即将刷新页面');
- setTimeout(() => {
- window.location.reload();
- }, 1000);
- } catch (error) {
- toast.error('删除失败: ' + (error as Error).message);
- }
- }}
- />
+ }}
+ />
+
+ 注意:上传新字体会覆盖旧字体文件,更改后需要刷新页面生效。
+
+
+ )}
- )}
-
-
+
+
+
-
}
+
+
+ 选择主题
+
+ }
>
-
+
{themes.map((t) => (
{
/>
))}
-
+
-
}
+
+
+ 自定义配色
+
+ }
>
-
+
{(['light', 'dark'] as const).map((mode) => (
-
-
- {mode === 'dark' ? : }
- {mode === 'dark' ? '深色模式' : '浅色模式'}
-
-
- {colorKeys.map((colorKey) => (
-
- {
- const hslArray = value?.split(' ') ?? [0, 0, 0];
- const color = `hsl(${hslArray[0]}, ${hslArray[1]}, ${hslArray[2]})`;
- return (
- {
- // ColorPicker returns hsl(h, s%, l%) string
- // We need to parse it and convert to "h s% l%" format for theme config
- const match = hslString.match(/hsl\((\d+(?:\.\d+)?),\s*(\d+(?:\.\d+)?)%,\s*(\d+(?:\.\d+)?)%\)/);
- if (match) {
- onChange(`${match[1]} ${match[2]}% ${match[3]}%`);
- }
- }}
- />
- );
- }}
- />
-
- {colorKey.replace('--heroui-', '')}
-
-
- ))}
-
-
+
+
+
+ {mode === 'dark' ? : }
+
+ {mode === 'dark' ? '深色模式' : '浅色模式'}
+
+
+
+ 调整{mode === 'dark' ? '深色' : '浅色'}主题下的颜色变量
+
+
+
+
+ {colorKeys.map((colorKey) => (
+
+
{
+ const hslArray = value?.split(' ') ?? [0, 0, 0];
+ const color = `hsl(${hslArray[0]}, ${hslArray[1]}, ${hslArray[2]})`;
+ return (
+ {
+ const match = hslString.match(/hsl\((\d+(?:\.\d+)?),\s*(\d+(?:\.\d+)?)%,\s*(\d+(?:\.\d+)?)%\)/);
+ if (match) {
+ onChange(`${match[1]} ${match[2]}% ${match[3]}%`);
+ }
+ }}
+ />
+ );
+ }}
+ />
+
+
+ {colorKey.replace('--heroui-', '')}
+
+
+ Variable
+
+
+
+ ))}
+
+
+
))}
-
-
+
+
>
);