mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-07 08:06:37 +08:00
prettier
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import type { ThemeConfig } from "./types"
|
||||
import type { ThemeConfig } from './types';
|
||||
|
||||
/**
|
||||
* 主题系统配置
|
||||
* 定义主题文件的存储位置和 localStorage 键名
|
||||
*/
|
||||
export const THEME_CONFIG: ThemeConfig = {
|
||||
styleDir: "public/style",
|
||||
storageKey: "app-theme-id",
|
||||
}
|
||||
styleDir: 'public/style',
|
||||
storageKey: 'app-theme-id',
|
||||
};
|
||||
|
||||
@@ -1,70 +1,80 @@
|
||||
"use client"
|
||||
'use client';
|
||||
|
||||
import React, { createContext, useContext, useEffect, useState, useCallback } from "react"
|
||||
import { useTheme as useNextTheme } from "next-themes"
|
||||
import type { Theme } from "./types"
|
||||
import { getStoredThemeId, setStoredThemeId } from "./storage"
|
||||
import { getAvailableThemes } from "./parser"
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
useCallback,
|
||||
} from 'react';
|
||||
import { useTheme as useNextTheme } from 'next-themes';
|
||||
import type { Theme } from './types';
|
||||
import { getStoredThemeId, setStoredThemeId } from './storage';
|
||||
import { getAvailableThemes } from './parser';
|
||||
|
||||
/**
|
||||
* 主题上下文类型定义
|
||||
*/
|
||||
interface ThemeContextValue {
|
||||
/** 所有可用主题列表 */
|
||||
themes: Theme[]
|
||||
themes: Theme[];
|
||||
/** 当前激活的主题对象 */
|
||||
currentTheme: Theme | null
|
||||
currentTheme: Theme | null;
|
||||
/** 当前激活的主题 ID */
|
||||
currentThemeId: string | null
|
||||
currentThemeId: string | null;
|
||||
/** 设置主题的方法 */
|
||||
setTheme: (themeId: string) => void
|
||||
setTheme: (themeId: string) => void;
|
||||
/** 是否正在加载主题 */
|
||||
isLoading: boolean
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
const ThemeContext = createContext<ThemeContextValue | null>(null)
|
||||
const ThemeContext = createContext<ThemeContextValue | null>(null);
|
||||
|
||||
/**
|
||||
* 自定义主题 Hook
|
||||
* 必须在 CustomThemeProvider 内部使用
|
||||
*/
|
||||
export function useCustomTheme() {
|
||||
const context = useContext(ThemeContext)
|
||||
const context = useContext(ThemeContext);
|
||||
if (!context) {
|
||||
throw new Error("useCustomTheme must be used within CustomThemeProvider")
|
||||
throw new Error('useCustomTheme must be used within CustomThemeProvider');
|
||||
}
|
||||
return context
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义主题提供者
|
||||
* 管理用户选择的界面外观主题(配色方案),独立于明暗模式
|
||||
*/
|
||||
export function CustomThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
const [themes, setThemes] = useState<Theme[]>([])
|
||||
const [currentThemeId, setCurrentThemeId] = useState<string | null>(null)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const { resolvedTheme } = useNextTheme()
|
||||
export function CustomThemeProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [themes, setThemes] = useState<Theme[]>([]);
|
||||
const [currentThemeId, setCurrentThemeId] = useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const { resolvedTheme } = useNextTheme();
|
||||
|
||||
/* 加载所有可用主题 */
|
||||
useEffect(() => {
|
||||
async function loadThemes() {
|
||||
const availableThemes = await getAvailableThemes()
|
||||
const storedId = getStoredThemeId()
|
||||
const availableThemes = await getAvailableThemes();
|
||||
const storedId = getStoredThemeId();
|
||||
|
||||
setThemes(availableThemes)
|
||||
setCurrentThemeId(storedId)
|
||||
setIsLoading(false)
|
||||
setThemes(availableThemes);
|
||||
setCurrentThemeId(storedId);
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
loadThemes()
|
||||
}, [])
|
||||
loadThemes();
|
||||
}, []);
|
||||
|
||||
/* 确保组件已挂载,避免水合不一致 */
|
||||
useEffect(() => {
|
||||
setMounted(true)
|
||||
}, [])
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* 将主题颜色应用到 DOM
|
||||
@@ -72,46 +82,49 @@ export function CustomThemeProvider({ children }: { children: React.ReactNode })
|
||||
* @param isDark - 是否为暗色模式
|
||||
*/
|
||||
const applyThemeColors = useCallback((theme: Theme, isDark: boolean) => {
|
||||
if (typeof window === "undefined") return
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
const root = document.documentElement
|
||||
const colors = isDark ? theme.colors.dark : theme.colors.light
|
||||
const root = document.documentElement;
|
||||
const colors = isDark ? theme.colors.dark : theme.colors.light;
|
||||
|
||||
/* 应用所有 CSS 变量到根元素 */
|
||||
Object.entries(colors).forEach(([key, value]) => {
|
||||
root.style.setProperty(`--${ key }`, value)
|
||||
})
|
||||
}, [])
|
||||
root.style.setProperty(`--${key}`, value);
|
||||
});
|
||||
}, []);
|
||||
|
||||
/* 当主题 ID 或模式改变时,重新应用颜色 */
|
||||
useEffect(() => {
|
||||
if (!mounted || !currentThemeId || themes.length === 0) return
|
||||
if (!mounted || !currentThemeId || themes.length === 0) return;
|
||||
|
||||
const theme = themes.find(t => t.id === currentThemeId)
|
||||
if (!theme) return
|
||||
const theme = themes.find((t) => t.id === currentThemeId);
|
||||
if (!theme) return;
|
||||
|
||||
/* 使用 next-themes 的 resolvedTheme,它会自动处理系统偏好 */
|
||||
const isDark = resolvedTheme === "dark"
|
||||
applyThemeColors(theme, isDark)
|
||||
}, [currentThemeId, resolvedTheme, themes, mounted, applyThemeColors])
|
||||
const isDark = resolvedTheme === 'dark';
|
||||
applyThemeColors(theme, isDark);
|
||||
}, [currentThemeId, resolvedTheme, themes, mounted, applyThemeColors]);
|
||||
|
||||
/**
|
||||
* 设置主题
|
||||
* @param themeId - 要设置的主题 ID
|
||||
*/
|
||||
const setTheme = useCallback((themeId: string) => {
|
||||
const theme = themes.find(t => t.id === themeId)
|
||||
if (!theme) return
|
||||
const setTheme = useCallback(
|
||||
(themeId: string) => {
|
||||
const theme = themes.find((t) => t.id === themeId);
|
||||
if (!theme) return;
|
||||
|
||||
setCurrentThemeId(themeId)
|
||||
setStoredThemeId(themeId)
|
||||
setCurrentThemeId(themeId);
|
||||
setStoredThemeId(themeId);
|
||||
|
||||
/* 根据当前解析的主题模式计算是否为暗色 */
|
||||
const isDark = resolvedTheme === "dark"
|
||||
applyThemeColors(theme, isDark)
|
||||
}, [themes, resolvedTheme, applyThemeColors])
|
||||
/* 根据当前解析的主题模式计算是否为暗色 */
|
||||
const isDark = resolvedTheme === 'dark';
|
||||
applyThemeColors(theme, isDark);
|
||||
},
|
||||
[themes, resolvedTheme, applyThemeColors],
|
||||
);
|
||||
|
||||
const currentTheme = themes.find(t => t.id === currentThemeId) || null
|
||||
const currentTheme = themes.find((t) => t.id === currentThemeId) || null;
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider
|
||||
@@ -120,10 +133,10 @@ export function CustomThemeProvider({ children }: { children: React.ReactNode })
|
||||
currentTheme,
|
||||
currentThemeId,
|
||||
setTheme,
|
||||
isLoading
|
||||
isLoading,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,16 +4,20 @@
|
||||
*/
|
||||
|
||||
/* 类型定义 */
|
||||
export type { Theme, ThemeColors, ThemeConfig } from "./types"
|
||||
export type { Theme, ThemeColors, ThemeConfig } from './types';
|
||||
|
||||
/* 配置 */
|
||||
export { THEME_CONFIG } from "./config"
|
||||
export { THEME_CONFIG } from './config';
|
||||
|
||||
/* 服务端工具 */
|
||||
export { getAvailableThemes } from "./parser"
|
||||
export { getAvailableThemes } from './parser';
|
||||
|
||||
/* 客户端工具 */
|
||||
export { getStoredThemeId, setStoredThemeId, removeStoredThemeId } from "./storage"
|
||||
export {
|
||||
getStoredThemeId,
|
||||
setStoredThemeId,
|
||||
removeStoredThemeId,
|
||||
} from './storage';
|
||||
|
||||
/* React 上下文和 Hooks */
|
||||
export { CustomThemeProvider, useCustomTheme } from "./context"
|
||||
export { CustomThemeProvider, useCustomTheme } from './context';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type {Theme} from "./types"
|
||||
import themesData from "./themes.json"
|
||||
import type { Theme } from './types';
|
||||
import themesData from './themes.json';
|
||||
|
||||
/**
|
||||
* 获取所有可用主题
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
'use client';
|
||||
|
||||
import { THEME_CONFIG } from "./config"
|
||||
import { THEME_CONFIG } from './config';
|
||||
|
||||
/**
|
||||
* 客户端主题存储工具
|
||||
@@ -11,22 +11,22 @@ import { THEME_CONFIG } from "./config"
|
||||
* 获取存储的主题 ID
|
||||
*/
|
||||
export function getStoredThemeId(): string | null {
|
||||
if (typeof window === "undefined") return null
|
||||
return localStorage.getItem(THEME_CONFIG.storageKey)
|
||||
if (typeof window === 'undefined') return null;
|
||||
return localStorage.getItem(THEME_CONFIG.storageKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存主题 ID 到本地存储
|
||||
*/
|
||||
export function setStoredThemeId(themeId: string): void {
|
||||
if (typeof window === "undefined") return
|
||||
localStorage.setItem(THEME_CONFIG.storageKey, themeId)
|
||||
if (typeof window === 'undefined') return;
|
||||
localStorage.setItem(THEME_CONFIG.storageKey, themeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除存储的主题 ID
|
||||
*/
|
||||
export function removeStoredThemeId(): void {
|
||||
if (typeof window === "undefined") return
|
||||
localStorage.removeItem(THEME_CONFIG.storageKey)
|
||||
if (typeof window === 'undefined') return;
|
||||
localStorage.removeItem(THEME_CONFIG.storageKey);
|
||||
}
|
||||
|
||||
@@ -4559,4 +4559,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
* 包含明亮和暗色两种模式的 CSS 变量映射
|
||||
*/
|
||||
export interface ThemeColors {
|
||||
light: Record<string, string>
|
||||
dark: Record<string, string>
|
||||
light: Record<string, string>;
|
||||
dark: Record<string, string>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16,11 +16,11 @@ export interface ThemeColors {
|
||||
*/
|
||||
export interface Theme {
|
||||
/** 主题唯一标识符(CSS 文件名) */
|
||||
id: string
|
||||
id: string;
|
||||
/** 主题显示名称 */
|
||||
name: string
|
||||
name: string;
|
||||
/** 主题颜色配置 */
|
||||
colors: ThemeColors
|
||||
colors: ThemeColors;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,7 +28,7 @@ export interface Theme {
|
||||
*/
|
||||
export interface ThemeConfig {
|
||||
/** CSS 样式文件所在目录 */
|
||||
styleDir: string
|
||||
styleDir: string;
|
||||
/** 主题 ID 在 localStorage 中的存储键名 */
|
||||
storageKey: string
|
||||
storageKey: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user