From 15d86e32523f85db6aafc1c3f40b3acd139aacb4 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Fri, 12 Dec 2025 18:06:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E4=B8=BB=E9=A2=98=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/admin/page.tsx | 333 ++++++++++++++++++++++++++ src/app/api/admin/theme/route.ts | 111 +++++++++ src/app/api/theme/css/route.ts | 74 ++++++ src/app/layout.tsx | 2 + src/lib/admin.types.ts | 8 + src/middleware.ts | 2 +- src/styles/themes.ts | 389 +++++++++++++++++++++++++++++++ 7 files changed, 918 insertions(+), 1 deletion(-) create mode 100644 src/app/api/admin/theme/route.ts create mode 100644 src/app/api/theme/css/route.ts create mode 100644 src/styles/themes.ts diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 03bc9db..43001b4 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -32,6 +32,7 @@ import { ExternalLink, FileText, FolderOpen, + Palette, Settings, Tv, Users, @@ -4235,6 +4236,322 @@ const ConfigFileComponent = ({ ); }; +// 主题配置组件 +const ThemeConfigComponent = ({ + config, + refreshConfig, +}: { + config: AdminConfig | null; + refreshConfig: () => Promise; +}) => { + const { alertModal, showAlert, hideAlert } = useAlertModal(); + const { isLoading, withLoading } = useLoadingState(); + const [themeSettings, setThemeSettings] = useState({ + enableBuiltInTheme: false, + builtInTheme: 'default', + customCSS: '', + enableCache: true, + cacheMinutes: 1440, // 默认1天(1440分钟) + }); + + useEffect(() => { + if (config?.ThemeConfig) { + setThemeSettings({ + enableBuiltInTheme: config.ThemeConfig.enableBuiltInTheme || false, + builtInTheme: config.ThemeConfig.builtInTheme || 'default', + customCSS: config.ThemeConfig.customCSS || '', + enableCache: config.ThemeConfig.enableCache !== false, + cacheMinutes: config.ThemeConfig.cacheMinutes || 1440, + }); + } + }, [config]); + + const handleSave = async () => { + await withLoading('saveThemeConfig', async () => { + try { + const response = await fetch('/api/admin/theme', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(themeSettings), + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || '保存失败'); + } + + showAlert({ + type: 'success', + title: '保存成功', + message: '主题配置已更新', + timer: 2000, + }); + + await refreshConfig(); + + // 刷新页面以应用新主题 + setTimeout(() => { + window.location.reload(); + }, 1000); + } catch (error) { + showAlert({ + type: 'error', + title: '保存失败', + message: (error as Error).message, + }); + } + }); + }; + + const builtInThemes = [ + { + value: 'default', + label: '默认主题', + color: '#3b82f6', + }, + { + value: 'dark_blue', + label: '深蓝夜空', + color: '#3b82f6', + }, + { + value: 'purple_dream', + label: '紫色梦境', + color: '#a78bfa', + }, + { + value: 'green_forest', + label: '翠绿森林', + color: '#10b981', + }, + { + value: 'orange_sunset', + label: '橙色日落', + color: '#f97316', + }, + { + value: 'pink_candy', + label: '粉色糖果', + color: '#ec4899', + }, + { + value: 'cyan_ocean', + label: '青色海洋', + color: '#06b6d4', + }, + ]; + + return ( +
+ {/* 主题类型选择 */} +
+

+ 主题类型 +

+
+ + +
+
+ + {/* 内置主题选择 */} + {themeSettings.enableBuiltInTheme && ( +
+

+ 选择内置主题 +

+
+ {builtInThemes.map((theme) => ( +
+ setThemeSettings((prev) => ({ + ...prev, + builtInTheme: theme.value, + })) + } + className={`cursor-pointer rounded-lg border-2 p-3 transition-all hover:shadow-md ${ + themeSettings.builtInTheme === theme.value + ? 'border-blue-500 ring-2 ring-blue-200 dark:ring-blue-800 bg-blue-50 dark:bg-blue-900/20' + : 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600' + }`} + > +
+ {/* 圆形颜色预览 */} +
+ {/* 主题名称 */} +
+ + {theme.label} + + {themeSettings.builtInTheme === theme.value && ( +
+ + + +
+ )} +
+
+
+ ))} +
+

+ 注意:启用内置主题时,自定义CSS将被禁用 +

+
+ )} + + {/* 自定义CSS编辑器 */} + {!themeSettings.enableBuiltInTheme && ( +
+

+ 自定义CSS +

+