'use client'; import React, { useState, useEffect } from 'react'; import { ChevronDown, ChevronUp, Palette, Eye, Check } from 'lucide-react'; import { Alert, Button, Card, Chip, TextArea } from '@heroui/react'; // CSS模板配置 const cssTemplates = [ { id: 'gradient-bg', name: '渐变背景', description: '为页面添加漂亮的渐变背景', preview: 'body {\n background: linear-gradient(135deg, \n #18181b 0%, #be123c 100%);\n}', css: `/* 渐变背景主题 */ body { background: linear-gradient(135deg, #18181b 0%, #be123c 100%); background-attachment: fixed; } /* 确保内容可读性 */ .admin-panel, .bg-theme-surface { backdrop-filter: blur(10px); background: rgba(255, 255, 255, 0.9) !important; } .dark .admin-panel, .dark .bg-theme-surface { background: rgba(0, 0, 0, 0.8) !important; }` }, { id: 'image-bg', name: '图片背景', description: '使用自定义图片作为背景', preview: 'body {\n background-image: url("图片链接");\n background-size: cover;\n}', css: `/* 图片背景主题 */ body { background-image: url("https://images.unsplash.com/photo-1519681393784-d120c3b3fd60?ixlib=rb-4.0.3"); background-size: cover; background-position: center; background-attachment: fixed; } /* 添加遮罩层确保可读性 */ body::before { content: ""; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.3); z-index: -1; } /* 调整内容区域透明度 */ .admin-panel, .bg-theme-surface { backdrop-filter: blur(15px); background: rgba(255, 255, 255, 0.95) !important; border: 1px solid rgba(255, 255, 255, 0.2); } .dark .admin-panel, .dark .bg-theme-surface { background: rgba(0, 0, 0, 0.85) !important; border: 1px solid rgba(255, 255, 255, 0.1); }` }, { id: 'sidebar-glow', name: '发光侧边栏', description: '为侧边栏添加发光效果', preview: '.sidebar {\n box-shadow: 0 0 20px rgba(225, 29, 72, 0.3);\n border-radius: 15px;\n}', css: `/* 发光侧边栏效果 */ .sidebar, [data-sidebar] { box-shadow: 0 0 20px rgba(225, 29, 72, 0.3); border-radius: 15px; border: 1px solid rgba(225, 29, 72, 0.2); backdrop-filter: blur(10px); } /* 侧边栏项目悬停效果 */ .sidebar a:hover, [data-sidebar] a:hover { background: rgba(225, 29, 72, 0.1); transform: translateX(5px); transition: all 0.3s ease; } /* 活动项目发光 */ .sidebar [data-active="true"], [data-sidebar] [data-active="true"] { background: rgba(225, 29, 72, 0.15); box-shadow: inset 0 0 10px rgba(225, 29, 72, 0.2); border-radius: 8px; }` }, { id: 'card-animations', name: '卡片动画', description: '为视频卡片添加动画效果', preview: '.video-card:hover {\n transform: scale(1.05);\n box-shadow: 0 10px 25px rgba(0,0,0,0.2);\n}', css: `/* 卡片动画效果 */ .video-card, [data-video-card] { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); border-radius: 12px; } .video-card:hover, [data-video-card]:hover { transform: translateY(-5px) scale(1.02); box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); } /* 图片悬停效果 */ .video-card img, [data-video-card] img { transition: transform 0.3s ease; border-radius: 8px; } .video-card:hover img, [data-video-card]:hover img { transform: scale(1.05); } /* 按钮动画 */ .video-card button, [data-video-card] button { transition: all 0.2s ease; } .video-card button:hover, [data-video-card] button:hover { transform: scale(1.1); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }` }, { id: 'glass-theme', name: '毛玻璃主题', description: '现代毛玻璃风格界面', preview: '.glass-effect {\n backdrop-filter: blur(20px);\n background: rgba(255, 255, 255, 0.1);\n}', css: `/* 毛玻璃主题 */ body { background: linear-gradient(45deg, rgba(24, 24, 27, 0.1) 0%, rgba(225, 29, 72, 0.1) 50%, rgba(244, 63, 94, 0.1) 100%); } /* 所有面板使用毛玻璃效果 */ .admin-panel, .bg-theme-surface, [data-panel] { backdrop-filter: blur(20px); background: rgba(255, 255, 255, 0.15) !important; border: 1px solid rgba(255, 255, 255, 0.2); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); } .dark .admin-panel, .dark .bg-theme-surface, .dark [data-panel] { background: rgba(0, 0, 0, 0.3) !important; border: 1px solid rgba(255, 255, 255, 0.1); } /* 按钮毛玻璃效果 */ button { backdrop-filter: blur(10px); transition: all 0.3s ease; } button:hover { backdrop-filter: blur(15px); transform: translateY(-1px); }` }, { id: 'neon-accents', name: '霓虹强调', description: '添加炫酷的霓虹发光效果', preview: '.neon-glow {\n box-shadow: 0 0 20px currentColor;\n text-shadow: 0 0 10px currentColor;\n}', css: `/* 霓虹发光主题 */ :root { --neon-color: #00ff88; --neon-glow: 0 0 20px var(--neon-color); } /* 主要标题霓虹效果 */ h1, h2, h3 { text-shadow: 0 0 10px var(--neon-color); color: var(--neon-color); } /* 按钮霓虹效果 */ button:hover, .btn-primary { box-shadow: var(--neon-glow); border: 1px solid var(--neon-color); transition: all 0.3s ease; } /* 输入框聚焦霓虹效果 */ input:focus, textarea:focus { box-shadow: var(--neon-glow); border-color: var(--neon-color); } /* 卡片边框霓虹效果 */ .card-hover:hover { box-shadow: var(--neon-glow); border: 1px solid var(--neon-color); } /* 侧边栏活动项霓虹效果 */ [data-active="true"] { box-shadow: inset var(--neon-glow); background: rgba(0, 255, 136, 0.1); }` } ]; // 主题配置 const themes = [ { id: 'default', name: '默认主题', description: '石墨玫瑰,冷静高级', preview: { bg: '#fafafa', surface: '#ffffff', accent: '#e11d48', text: '#18181b', border: '#d4d4d8' } }, { id: 'minimal', name: '极简主题', description: '简约黑白,专注内容', preview: { bg: '#ffffff', surface: '#fcfcfc', accent: '#525252', text: '#171717', border: '#e5e5e5' } }, { id: 'warm', name: '暖色主题', description: '温暖橙调,舒适护眼', preview: { bg: '#fffdf7', surface: '#fefaf0', accent: '#ea580c', text: '#7c2d12', border: '#fde68a' } }, { id: 'fresh', name: '清新主题', description: '自然绿色,清新活力', preview: { bg: '#f7fdf9', surface: '#f0fdf4', accent: '#3fcc71', text: '#14532d', border: '#bbf7d0' } } ]; interface ThemeManagerProps { showAlert: (config: any) => void; role?: 'user' | 'admin' | 'owner' | null; } const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => { const [currentTheme, setCurrentTheme] = useState('default'); const [customCSS, setCustomCSS] = useState(''); const [previewMode, setPreviewMode] = useState(false); const [showCustomEditor, setShowCustomEditor] = useState(false); const [globalThemeConfig, setGlobalThemeConfig] = useState<{ defaultTheme: string; customCSS: string; allowUserCustomization: boolean; } | null>(null); const isAdmin = role === 'admin' || role === 'owner'; // 更新主题缓存的辅助函数 const updateThemeCache = (themeId: string, css: string) => { try { const themeConfig = { defaultTheme: themeId, customCSS: css }; localStorage.setItem('theme-cache', JSON.stringify(themeConfig)); console.log('主题配置已缓存:', themeConfig); } catch (error) { console.warn('缓存主题配置失败:', error); } }; // 从API加载主题配置(唯一数据源) const loadGlobalThemeConfig = async () => { try { console.log('从API获取主题配置...'); const response = await fetch('/api/admin/config'); const result = await response.json(); if (result?.Config?.ThemeConfig) { const themeConfig = result.Config.ThemeConfig; console.log('API返回的主题配置:', themeConfig); setGlobalThemeConfig(themeConfig); // 更新运行时配置,保持同步 const runtimeConfig = (window as any).RUNTIME_CONFIG; if (runtimeConfig) { runtimeConfig.THEME_CONFIG = themeConfig; } return themeConfig; } else { console.log('无法获取主题配置,可能未登录或权限不足:', result); } } catch (error) { console.error('从API加载主题配置失败:', error); } return null; }; // 保存全局主题配置 const saveGlobalThemeConfig = async (config: { defaultTheme: string; customCSS: string; allowUserCustomization: boolean; }) => { try { const response = await fetch('/api/admin/theme', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config), }); const result = await response.json(); if (result.success) { setGlobalThemeConfig(result.data); // 更新运行时配置,确保同步 const runtimeConfig = (window as any).RUNTIME_CONFIG; if (runtimeConfig) { runtimeConfig.THEME_CONFIG = result.data; console.log('已更新运行时主题配置:', result.data); } // 立即应用新的主题配置,确保当前页面也能看到更改 applyTheme(result.data.defaultTheme, result.data.customCSS); // 更新本地缓存 updateThemeCache(result.data.defaultTheme, result.data.customCSS); console.log('已立即应用新主题配置:', result.data.defaultTheme); showAlert({ type: 'success', title: '全站主题配置已保存', message: '所有用户将使用新的主题配置', timer: 3000 }); return true; } else { throw new Error(result.error || '保存失败'); } } catch (error) { showAlert({ type: 'error', title: '保存全局主题配置失败', message: error instanceof Error ? error.message : '未知错误', timer: 3000 }); return false; } }; // 从localStorage加载当前主题 useEffect(() => { // 确保在客户端环境中执行 if (typeof window === 'undefined') return; const initTheme = async () => { // 加载全局配置 const globalConfig = await loadGlobalThemeConfig(); if (globalConfig) { // 使用全局配置 setCurrentTheme(globalConfig.defaultTheme); setCustomCSS(globalConfig.customCSS); applyTheme(globalConfig.defaultTheme, globalConfig.customCSS); } else { // 如果没有全局配置,使用默认值 const defaultTheme = 'default'; const defaultCSS = ''; setCurrentTheme(defaultTheme); setCustomCSS(defaultCSS); applyTheme(defaultTheme, defaultCSS); } }; initTheme(); }, []); // 应用主题 const applyTheme = (themeId: string, css: string = '') => { const html = document.documentElement; // 移除所有主题class html.removeAttribute('data-theme'); // 应用新主题 if (themeId !== 'default') { html.setAttribute('data-theme', themeId); } // 应用自定义CSS let customStyleEl = document.getElementById('custom-theme-css'); if (!customStyleEl) { customStyleEl = document.createElement('style'); customStyleEl.id = 'custom-theme-css'; document.head.appendChild(customStyleEl); } customStyleEl.textContent = css; }; // 切换主题 const handleThemeChange = async (themeId: string) => { setCurrentTheme(themeId); applyTheme(themeId, customCSS); if (isAdmin) { // 保存到全局配置 const success = await saveGlobalThemeConfig({ defaultTheme: themeId, customCSS: customCSS, allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, }); // 如果保存成功,立即更新本地全局配置状态 if (success) { setGlobalThemeConfig({ defaultTheme: themeId, customCSS: customCSS, allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, }); } } const theme = themes.find(t => t.id === themeId); showAlert({ type: 'success', title: '全站主题已设置', message: `已切换到${theme?.name}`, timer: 2000 }); }; // 预览主题 const handleThemePreview = (themeId: string) => { if (!previewMode) { setPreviewMode(true); applyTheme(themeId, customCSS); // 3秒后恢复原主题 setTimeout(() => { setPreviewMode(false); applyTheme(currentTheme, customCSS); }, 3000); } }; // 应用自定义CSS const handleCustomCSSApply = async () => { try { applyTheme(currentTheme, customCSS); if (isAdmin) { // 保存到全局配置 const success = await saveGlobalThemeConfig({ defaultTheme: currentTheme, customCSS: customCSS, allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, }); // 如果保存成功,立即更新本地全局配置状态 if (success) { setGlobalThemeConfig({ defaultTheme: currentTheme, customCSS: customCSS, allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, }); } } else { showAlert({ type: 'warning', title: '权限不足', message: '仅管理员可以设置全站主题', timer: 2000 }); } } catch (error) { showAlert({ type: 'error', title: '样式应用失败', message: 'CSS语法可能有误,请检查后重试', timer: 3000 }); } }; // 重置自定义CSS const handleCustomCSSReset = async () => { setCustomCSS(''); applyTheme(currentTheme, ''); if (isAdmin) { // 保存到全局配置 await saveGlobalThemeConfig({ defaultTheme: currentTheme, customCSS: '', allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, }); setGlobalThemeConfig({ defaultTheme: currentTheme, customCSS: '', allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, }); // 更新运行时配置 const runtimeConfig = (window as any).RUNTIME_CONFIG; if (runtimeConfig) { runtimeConfig.THEME_CONFIG = { defaultTheme: currentTheme, customCSS: '', allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, }; } // 更新本地缓存 updateThemeCache(currentTheme, ''); } showAlert({ type: 'success', title: '全站自定义样式已重置', timer: 2000 }); }; // 应用模板CSS const handleApplyTemplate = (templateCSS: string, templateName: string) => { setCustomCSS(templateCSS); showAlert({ type: 'success', title: '模板已复制', message: `${templateName}模板已复制到编辑器`, timer: 2000 }); }; return (
{theme.description}
💡 使用提示:
--color-theme-accent: 255, 0, 0;{`.my-class { @apply bg-red-500; }`}{`.admin-panel { border-radius: 20px; }`}{template.description}
{template.preview}
内置主题:{isAdmin ? '选择预设主题即可一键切换全站整体风格' : '由管理员设置的全站预设主题'}
{isAdmin &&自定义CSS:通过CSS变量或直接样式实现全站个性化定制
} {isAdmin &&样式模板:使用预设模板快速实现炫酷效果
}主题变量:
--color-theme-bg - 背景色--color-theme-surface - 卡片背景--color-theme-accent - 主题色--color-theme-text - 主文本色--color-theme-border - 边框色常用技巧:
{`body { background: linear-gradient(...); }`}{`.my-class { @apply bg-red-500; }`}