fixed:自定义主题应用所有人

This commit is contained in:
djteang 2025-09-22 17:20:02 +08:00
parent c462e1c2b5
commit 3457a7c565
5 changed files with 153 additions and 278 deletions

View File

@ -15,31 +15,21 @@
// 应用自定义CSS // 应用自定义CSS
if (css) { if (css) {
let customStyleEl = document.getElementById('init-theme-css'); let customStyleEl = document.getElementById('custom-theme-css');
if (!customStyleEl) { if (!customStyleEl) {
customStyleEl = document.createElement('style'); customStyleEl = document.createElement('style');
customStyleEl.id = 'init-theme-css'; customStyleEl.id = 'custom-theme-css';
document.head.appendChild(customStyleEl); document.head.appendChild(customStyleEl);
} }
customStyleEl.textContent = css; customStyleEl.textContent = css;
} }
} }
// 从localStorage获取保存的主题 // 应用默认主题避免闪烁等待GlobalThemeLoader加载全站配置
const savedTheme = localStorage.getItem('app-theme'); applyTheme('default', '');
const savedCustomCSS = localStorage.getItem('app-custom-css') || ''; console.log('主题初始化完成,等待加载全站配置');
// 立即应用已保存的主题(如果有) // 注意GlobalThemeLoader会在React组件挂载后加载并应用全站主题配置
if (savedTheme) {
applyTheme(savedTheme, savedCustomCSS);
console.log('主题已初始化(本地设置):', savedTheme);
} else {
// 没有用户设置时,先应用默认主题
applyTheme('default', '');
console.log('主题已初始化(默认)');
}
// 注意GlobalThemeLoader会在React组件挂载后进一步处理全站配置
} catch (error) { } catch (error) {
console.error('主题初始化失败:', error); console.error('主题初始化失败:', error);
} }

View File

@ -23,7 +23,6 @@ import { DoubanItem } from '@/lib/types';
import CapsuleSwitch from '@/components/CapsuleSwitch'; import CapsuleSwitch from '@/components/CapsuleSwitch';
import ContinueWatching from '@/components/ContinueWatching'; import ContinueWatching from '@/components/ContinueWatching';
import PageLayout from '@/components/PageLayout'; import PageLayout from '@/components/PageLayout';
import { useThemeInit } from '@/hooks/useTheme';
import ScrollableRow from '@/components/ScrollableRow'; import ScrollableRow from '@/components/ScrollableRow';
import { useSite } from '@/components/SiteProvider'; import { useSite } from '@/components/SiteProvider';
import VideoCard from '@/components/VideoCard'; import VideoCard from '@/components/VideoCard';
@ -516,8 +515,6 @@ function HomeClient() {
} }
export default function Home() { export default function Home() {
// 初始化主题
useThemeInit();
return ( return (
<Suspense> <Suspense>
<HomeClient /> <HomeClient />

View File

@ -14,59 +14,19 @@ const GlobalThemeLoader = () => {
console.log('获取到全站主题配置:', result); console.log('获取到全站主题配置:', result);
if (result.success && result.data) { if (result.success && result.data) {
const { defaultTheme, customCSS, allowUserCustomization } = result.data; const { defaultTheme, customCSS } = result.data;
// 检查用户是否有自定义设置 console.log('加载全站主题配置:', { defaultTheme, customCSS });
const userTheme = localStorage.getItem('app-theme');
const userCustomCSS = localStorage.getItem('app-custom-css') || '';
console.log('当前用户设置:', { userTheme, userCustomCSS }); // 直接应用全站配置
console.log('全站配置:', { defaultTheme, customCSS, allowUserCustomization }); applyTheme(defaultTheme, customCSS);
console.log('已应用全站主题:', defaultTheme);
// 如果不允许用户自定义,强制应用全局配置
if (!allowUserCustomization) {
localStorage.setItem('app-theme', defaultTheme);
localStorage.setItem('app-custom-css', customCSS);
applyTheme(defaultTheme, customCSS);
console.log('强制应用全站配置:', defaultTheme);
return;
}
// 智能决定使用哪个主题
let finalTheme = defaultTheme;
let finalCSS = customCSS;
// 检查是否需要强制应用全站主题
// 如果localStorage中存储的主题与全站默认不同说明可能是过期的设置需要更新
const shouldForceGlobalTheme = !userTheme || userTheme !== defaultTheme;
if (shouldForceGlobalTheme) {
// 强制应用全站默认配置
finalTheme = defaultTheme;
finalCSS = customCSS;
localStorage.setItem('app-theme', defaultTheme);
if (customCSS) {
localStorage.setItem('app-custom-css', customCSS);
} else {
localStorage.removeItem('app-custom-css');
}
console.log('强制应用全站默认主题:', defaultTheme, '(替换过期设置:', userTheme, ')');
} else {
// 用户设置与全站默认一致,使用现有设置
finalTheme = userTheme;
finalCSS = userCustomCSS || customCSS;
console.log('保持一致的主题设置:', userTheme);
}
// 应用最终主题
applyTheme(finalTheme, finalCSS);
} }
} catch (error) { } catch (error) {
console.error('加载全局主题配置失败:', error); console.error('加载全站主题配置失败:', error);
// 失败时使用本地设置或默认设置 // 失败时使用默认设置
const savedTheme = localStorage.getItem('app-theme') || 'default'; applyTheme('default', '');
const savedCustomCSS = localStorage.getItem('app-custom-css') || ''; console.log('加载配置失败,使用默认主题');
applyTheme(savedTheme, savedCustomCSS);
} }
}; };
@ -83,10 +43,10 @@ const GlobalThemeLoader = () => {
} }
// 应用自定义CSS // 应用自定义CSS
let customStyleEl = document.getElementById('global-theme-css'); let customStyleEl = document.getElementById('custom-theme-css');
if (!customStyleEl) { if (!customStyleEl) {
customStyleEl = document.createElement('style'); customStyleEl = document.createElement('style');
customStyleEl.id = 'global-theme-css'; customStyleEl.id = 'custom-theme-css';
document.head.appendChild(customStyleEl); document.head.appendChild(customStyleEl);
} }
customStyleEl.textContent = css; customStyleEl.textContent = css;

View File

@ -274,7 +274,6 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
customCSS: string; customCSS: string;
allowUserCustomization: boolean; allowUserCustomization: boolean;
} | null>(null); } | null>(null);
const [isGlobalMode, setIsGlobalMode] = useState(false);
const isAdmin = role === 'admin' || role === 'owner'; const isAdmin = role === 'admin' || role === 'owner';
@ -338,23 +337,23 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
// 加载全局配置 // 加载全局配置
const globalConfig = await loadGlobalThemeConfig(); const globalConfig = await loadGlobalThemeConfig();
if (isGlobalMode && globalConfig) { if (globalConfig) {
// 使用全局配置 // 使用全局配置
setCurrentTheme(globalConfig.defaultTheme); setCurrentTheme(globalConfig.defaultTheme);
setCustomCSS(globalConfig.customCSS); setCustomCSS(globalConfig.customCSS);
applyTheme(globalConfig.defaultTheme, globalConfig.customCSS); applyTheme(globalConfig.defaultTheme, globalConfig.customCSS);
} else { } else {
// 使用本地配置 // 如果没有全局配置,使用默认值
const savedTheme = localStorage.getItem('app-theme') || globalConfig?.defaultTheme || 'default'; const defaultTheme = 'default';
const savedCustomCSS = localStorage.getItem('app-custom-css') || ''; const defaultCSS = '';
setCurrentTheme(savedTheme); setCurrentTheme(defaultTheme);
setCustomCSS(savedCustomCSS); setCustomCSS(defaultCSS);
applyTheme(savedTheme, savedCustomCSS); applyTheme(defaultTheme, defaultCSS);
} }
}; };
initTheme(); initTheme();
}, [isGlobalMode]); }, []);
// 应用主题 // 应用主题
const applyTheme = (themeId: string, css: string = '') => { const applyTheme = (themeId: string, css: string = '') => {
@ -383,7 +382,7 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
setCurrentTheme(themeId); setCurrentTheme(themeId);
applyTheme(themeId, customCSS); applyTheme(themeId, customCSS);
if (isGlobalMode && isAdmin) { if (isAdmin) {
// 保存到全局配置 // 保存到全局配置
const success = await saveGlobalThemeConfig({ const success = await saveGlobalThemeConfig({
defaultTheme: themeId, defaultTheme: themeId,
@ -399,15 +398,12 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true,
}); });
} }
} else {
// 保存到本地
localStorage.setItem('app-theme', themeId);
} }
const theme = themes.find(t => t.id === themeId); const theme = themes.find(t => t.id === themeId);
showAlert({ showAlert({
type: 'success', type: 'success',
title: isGlobalMode ? '全局主题已设置' : '主题已切换', title: '全站主题已设置',
message: `已切换到${theme?.name}`, message: `已切换到${theme?.name}`,
timer: 2000 timer: 2000
}); });
@ -432,7 +428,7 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
try { try {
applyTheme(currentTheme, customCSS); applyTheme(currentTheme, customCSS);
if (isGlobalMode && isAdmin) { if (isAdmin) {
// 保存到全局配置 // 保存到全局配置
const success = await saveGlobalThemeConfig({ const success = await saveGlobalThemeConfig({
defaultTheme: currentTheme, defaultTheme: currentTheme,
@ -449,12 +445,10 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
}); });
} }
} else { } else {
// 保存到本地
localStorage.setItem('app-custom-css', customCSS);
showAlert({ showAlert({
type: 'success', type: 'warning',
title: '自定义样式已应用', title: '权限不足',
message: '您的自定义CSS已生效', message: '仅管理员可以设置全站主题',
timer: 2000 timer: 2000
}); });
} }
@ -469,14 +463,28 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
}; };
// 重置自定义CSS // 重置自定义CSS
const handleCustomCSSReset = () => { const handleCustomCSSReset = async () => {
setCustomCSS(''); setCustomCSS('');
applyTheme(currentTheme, ''); applyTheme(currentTheme, '');
localStorage.removeItem('app-custom-css');
if (isAdmin) {
// 保存到全局配置
await saveGlobalThemeConfig({
defaultTheme: currentTheme,
customCSS: '',
allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true,
});
setGlobalThemeConfig({
defaultTheme: currentTheme,
customCSS: '',
allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true,
});
}
showAlert({ showAlert({
type: 'success', type: 'success',
title: '自定义样式已重置', title: '全站自定义样式已重置',
timer: 2000 timer: 2000
}); });
}; };
@ -495,68 +503,33 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
{/* 管理员控制面板 */} {/* 管理员控制面板 */}
{isAdmin && ( {isAdmin && globalThemeConfig && (
<div className="bg-theme-surface border border-theme-border rounded-lg p-4"> <div className="bg-theme-surface border border-theme-border rounded-lg p-4">
<h3 className="text-lg font-semibold text-theme-text mb-4 flex items-center gap-2"> <h3 className="text-lg font-semibold text-theme-text mb-4 flex items-center gap-2">
<Palette className="h-5 w-5" /> <Palette className="h-5 w-5" />
</h3> </h3>
<div className="space-y-4"> <div className="space-y-4">
<div className="flex items-center justify-between"> <div className="p-3 bg-theme-accent/5 border border-theme-accent/20 rounded-lg">
<div> <div className="text-sm text-theme-text">
<label className="text-sm font-medium text-theme-text"></label> <strong></strong>
<p className="text-xs text-theme-text-secondary mt-1">
</p>
</div> </div>
<div className="flex items-center gap-3"> <div className="text-xs text-theme-text-secondary mt-1">
<label className="flex items-center gap-2 cursor-pointer"> : {themes.find(t => t.id === globalThemeConfig.defaultTheme)?.name || globalThemeConfig.defaultTheme}
<input {globalThemeConfig.customCSS && ' | 包含自定义CSS'}
type="radio" {!globalThemeConfig.allowUserCustomization && ' | 禁止用户自定义'}
name="configMode"
checked={!isGlobalMode}
onChange={() => setIsGlobalMode(false)}
className="w-4 h-4 text-theme-accent"
/>
<span className="text-sm text-theme-text"></span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<input
type="radio"
name="configMode"
checked={isGlobalMode}
onChange={() => setIsGlobalMode(true)}
className="w-4 h-4 text-theme-accent"
/>
<span className="text-sm text-theme-text"></span>
</label>
</div> </div>
</div> </div>
{globalThemeConfig && ( <div className="p-3 bg-blue-50 border border-blue-200 rounded-lg dark:bg-blue-900/20 dark:border-blue-700">
<div className="p-3 bg-theme-accent/5 border border-theme-accent/20 rounded-lg"> <div className="flex items-center gap-2 text-blue-800 dark:text-blue-200">
<div className="text-sm text-theme-text"> <span className="text-sm font-medium"> </span>
<strong></strong>
</div>
<div className="text-xs text-theme-text-secondary mt-1">
: {themes.find(t => t.id === globalThemeConfig.defaultTheme)?.name || globalThemeConfig.defaultTheme}
{globalThemeConfig.customCSS && ' | 包含自定义CSS'}
{!globalThemeConfig.allowUserCustomization && ' | 禁止用户自定义'}
</div>
</div> </div>
)} <p className="text-xs text-blue-700 dark:text-blue-300 mt-1">
{isGlobalMode && ( </p>
<div className="p-3 bg-yellow-50 border border-yellow-200 rounded-lg dark:bg-yellow-900/20 dark:border-yellow-700"> </div>
<div className="flex items-center gap-2 text-yellow-800 dark:text-yellow-200">
<span className="text-sm font-medium"> </span>
</div>
<p className="text-xs text-yellow-700 dark:text-yellow-300 mt-1">
</p>
</div>
)}
</div> </div>
</div> </div>
)} )}
@ -565,18 +538,18 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
<div> <div>
<h3 className="text-lg font-semibold text-theme-text mb-4 flex items-center gap-2"> <h3 className="text-lg font-semibold text-theme-text mb-4 flex items-center gap-2">
<Palette className="h-5 w-5" /> <Palette className="h-5 w-5" />
{isGlobalMode && isAdmin ? '全站默认主题' : '主题选择'}
</h3> </h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{themes.map((theme) => ( {themes.map((theme) => (
<div <div
key={theme.id} key={theme.id}
className={`relative p-4 border-2 rounded-xl cursor-pointer transition-all ${currentTheme === theme.id className={`relative p-4 border-2 rounded-xl transition-all ${currentTheme === theme.id
? 'border-theme-accent bg-theme-accent/5' ? 'border-theme-accent bg-theme-accent/5'
: 'border-theme-border bg-theme-surface hover:border-theme-accent/50' : 'border-theme-border bg-theme-surface'
}`} } ${isAdmin ? 'cursor-pointer hover:border-theme-accent/50' : 'cursor-not-allowed opacity-60'}`}
onClick={() => handleThemeChange(theme.id)} onClick={() => isAdmin && handleThemeChange(theme.id)}
> >
{/* 主题预览 */} {/* 主题预览 */}
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
@ -589,11 +562,11 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
<button <button
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
handleThemePreview(theme.id); if (isAdmin) handleThemePreview(theme.id);
}} }}
className="p-1 text-theme-text-secondary hover:text-theme-accent transition-colors" className={`p-1 transition-colors ${isAdmin ? 'text-theme-text-secondary hover:text-theme-accent' : 'text-theme-text-secondary opacity-50 cursor-not-allowed'}`}
title="预览主题" title={isAdmin ? "预览主题" : "仅管理员可预览"}
disabled={previewMode} disabled={previewMode || !isAdmin}
> >
<Eye className="h-4 w-4" /> <Eye className="h-4 w-4" />
</button> </button>
@ -621,18 +594,35 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-theme-text flex items-center gap-2"> <h3 className="text-lg font-semibold text-theme-text flex items-center gap-2">
<Palette className="h-5 w-5" /> <Palette className="h-5 w-5" />
</h3> </h3>
<button {isAdmin ? (
onClick={() => setShowCustomEditor(!showCustomEditor)} <button
className="flex items-center gap-2 px-3 py-1.5 text-sm bg-theme-surface border border-theme-border rounded-lg hover:bg-theme-accent/5 transition-colors" onClick={() => setShowCustomEditor(!showCustomEditor)}
> className="flex items-center gap-2 px-3 py-1.5 text-sm bg-theme-surface border border-theme-border rounded-lg hover:bg-theme-accent/5 transition-colors"
{showCustomEditor ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />} >
{showCustomEditor ? '收起编辑器' : '展开编辑器'} {showCustomEditor ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
</button> {showCustomEditor ? '收起编辑器' : '展开编辑器'}
</button>
) : (
<div className="text-sm text-theme-text-secondary">
</div>
)}
</div> </div>
{showCustomEditor && ( {!isAdmin && (
<div className="p-4 bg-yellow-50 border border-yellow-200 rounded-lg dark:bg-yellow-900/20 dark:border-yellow-700 mb-4">
<div className="flex items-center gap-2 text-yellow-800 dark:text-yellow-200">
<span className="text-sm font-medium"> </span>
</div>
<p className="text-xs text-yellow-700 dark:text-yellow-300 mt-1">
</p>
</div>
)}
{isAdmin && showCustomEditor && (
<div className="space-y-4"> <div className="space-y-4">
<div className="text-sm text-theme-text-secondary bg-theme-surface p-3 rounded-lg border border-theme-border"> <div className="text-sm text-theme-text-secondary bg-theme-surface p-3 rounded-lg border border-theme-border">
<p className="mb-2">💡 <strong>使</strong></p> <p className="mb-2">💡 <strong>使</strong></p>
@ -685,47 +675,49 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
</div> </div>
{/* CSS 模板库 */} {/* CSS 模板库 */}
<div className="bg-theme-surface border border-theme-border rounded-lg p-4"> {isAdmin && (
<h4 className="font-medium text-theme-text mb-3 flex items-center gap-2"> <div className="bg-theme-surface border border-theme-border rounded-lg p-4">
<Palette className="h-4 w-4" /> <h4 className="font-medium text-theme-text mb-3 flex items-center gap-2">
🎨 <Palette className="h-4 w-4" />
</h4> 🎨
<p className="text-sm text-theme-text-secondary mb-4"></p> </h4>
<p className="text-sm text-theme-text-secondary mb-4"></p>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
{cssTemplates.map((template) => ( {cssTemplates.map((template) => (
<div key={template.id} className="p-3 border border-theme-border rounded-lg hover:bg-theme-accent/5 transition-colors group"> <div key={template.id} className="p-3 border border-theme-border rounded-lg hover:bg-theme-accent/5 transition-colors group">
<div className="flex items-center justify-between mb-2"> <div className="flex items-center justify-between mb-2">
<h5 className="text-sm font-medium text-theme-text">{template.name}</h5> <h5 className="text-sm font-medium text-theme-text">{template.name}</h5>
<button <button
onClick={() => handleApplyTemplate(template.css, template.name)} onClick={() => handleApplyTemplate(template.css, template.name)}
className="text-xs px-2 py-1 bg-theme-accent text-white rounded hover:opacity-90 transition-opacity opacity-0 group-hover:opacity-100" className="text-xs px-2 py-1 bg-theme-accent text-white rounded hover:opacity-90 transition-opacity opacity-0 group-hover:opacity-100"
> >
</button> </button>
</div>
<p className="text-xs text-theme-text-secondary mb-2">{template.description}</p>
<div className="text-xs bg-theme-bg rounded p-2 max-h-16 overflow-y-auto">
<code className="whitespace-pre-wrap text-theme-text-secondary">{template.preview}</code>
</div>
</div> </div>
<p className="text-xs text-theme-text-secondary mb-2">{template.description}</p> ))}
<div className="text-xs bg-theme-bg rounded p-2 max-h-16 overflow-y-auto"> </div>
<code className="whitespace-pre-wrap text-theme-text-secondary">{template.preview}</code>
</div>
</div>
))}
</div>
<div className="mt-4 p-3 bg-theme-accent/5 border border-theme-accent/20 rounded-lg"> <div className="mt-4 p-3 bg-theme-accent/5 border border-theme-accent/20 rounded-lg">
<p className="text-xs text-theme-text-secondary"> <p className="text-xs text-theme-text-secondary">
<strong>💡 使</strong> "应用"CSS编辑器"应用样式" <strong>💡 使</strong> "应用"CSS编辑器"应用样式"
</p> </p>
</div>
</div> </div>
</div> )}
{/* 使用说明 */} {/* 使用说明 */}
<div className="bg-theme-surface border border-theme-border rounded-lg p-4"> <div className="bg-theme-surface border border-theme-border rounded-lg p-4">
<h4 className="font-medium text-theme-text mb-2">📖 </h4> <h4 className="font-medium text-theme-text mb-2">📖 </h4>
<div className="text-sm text-theme-text-secondary space-y-2"> <div className="text-sm text-theme-text-secondary space-y-2">
<p><strong></strong></p> <p><strong></strong>{isAdmin ? '选择预设主题即可一键切换全站整体风格' : '由管理员设置的全站预设主题'}</p>
<p><strong>CSS</strong>CSS变量或直接样式实现个性化定制</p> {isAdmin && <p><strong>CSS</strong>CSS变量或直接样式实现全站个性化定制</p>}
<p><strong></strong>使</p> {isAdmin && <p><strong></strong>使</p>}
<p><strong></strong></p> <p><strong></strong></p>
<ul className="text-xs space-y-1 ml-4 mt-1"> <ul className="text-xs space-y-1 ml-4 mt-1">
<li> <code className="bg-theme-bg px-1 rounded">--color-theme-bg</code> - </li> <li> <code className="bg-theme-bg px-1 rounded">--color-theme-bg</code> - </li>
@ -734,12 +726,16 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => {
<li> <code className="bg-theme-bg px-1 rounded">--color-theme-text</code> - </li> <li> <code className="bg-theme-bg px-1 rounded">--color-theme-text</code> - </li>
<li> <code className="bg-theme-bg px-1 rounded">--color-theme-border</code> - </li> <li> <code className="bg-theme-bg px-1 rounded">--color-theme-border</code> - </li>
</ul> </ul>
<p><strong></strong></p> {isAdmin && (
<ul className="text-xs space-y-1 ml-4 mt-1"> <>
<li> <code className="bg-theme-bg px-1 rounded">{`body { background: linear-gradient(...); }`}</code></li> <p><strong></strong></p>
<li> 使Tailwind<code className="bg-theme-bg px-1 rounded">{`.my-class { @apply bg-red-500; }`}</code></li> <ul className="text-xs space-y-1 ml-4 mt-1">
<li> </li> <li> <code className="bg-theme-bg px-1 rounded">{`body { background: linear-gradient(...); }`}</code></li>
</ul> <li> 使Tailwind<code className="bg-theme-bg px-1 rounded">{`.my-class { @apply bg-red-500; }`}</code></li>
<li> </li>
</ul>
</>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,87 +1,19 @@
// 全局主题Hook - 用于在任何组件中初始化和使用主题 // 全局主题Hook - 已弃用,主题现在由 GlobalThemeLoader 统一管理
import { useEffect } from 'react'; // 保留此文件是为了向后兼容性,但不再使用
export const useThemeInit = () => { export const useThemeInit = () => {
useEffect(() => { // 不再执行任何操作,主题由 GlobalThemeLoader 处理
// 确保在客户端环境中执行 console.warn('useThemeInit is deprecated. Theme is now managed by GlobalThemeLoader.');
if (typeof window === 'undefined') return;
try {
// 从localStorage获取保存的主题
const savedTheme = localStorage.getItem('app-theme') || 'default';
const savedCustomCSS = localStorage.getItem('app-custom-css') || '';
// 立即应用主题到HTML元素
const html = document.documentElement;
// 移除所有主题属性
html.removeAttribute('data-theme');
// 应用保存的主题
if (savedTheme !== 'default') {
html.setAttribute('data-theme', savedTheme);
}
// 应用自定义CSS
if (savedCustomCSS) {
let customStyleEl = document.getElementById('custom-theme-css');
if (!customStyleEl) {
customStyleEl = document.createElement('style');
customStyleEl.id = 'custom-theme-css';
document.head.appendChild(customStyleEl);
}
customStyleEl.textContent = savedCustomCSS;
}
console.log(`主题已初始化: ${savedTheme}`);
} catch (error) {
console.error('主题初始化失败:', error);
}
}, []);
}; };
export const useTheme = () => { export const useTheme = () => {
const applyTheme = (themeId: string, css: string = '') => { // 已弃用:主题现在由 GlobalThemeLoader 和 ThemeManager 统一管理
if (typeof window === 'undefined') return; console.warn('useTheme is deprecated. Use ThemeManager component for theme management.');
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;
// 保存到localStorage
localStorage.setItem('app-theme', themeId);
localStorage.setItem('app-custom-css', css);
};
const getCurrentTheme = () => {
if (typeof window === 'undefined') return 'default';
return localStorage.getItem('app-theme') || 'default';
};
const getCurrentCustomCSS = () => {
if (typeof window === 'undefined') return '';
return localStorage.getItem('app-custom-css') || '';
};
return { return {
applyTheme, applyTheme: () => console.warn('applyTheme is deprecated'),
getCurrentTheme, getCurrentTheme: () => 'default',
getCurrentCustomCSS getCurrentCustomCSS: () => ''
}; };
}; };