174 lines
5.0 KiB
TypeScript
174 lines
5.0 KiB
TypeScript
/**
|
||
* 主题管理 composable
|
||
* 提供主题切换、持久化、CSS 变量注入、暗黑模式等功能
|
||
*
|
||
* 使用方式:
|
||
* const { currentTheme, themes, setTheme, getDarkMode, setDarkMode, isInDarkMode, getAvailableThemes, initTheme } = useTheme()
|
||
*/
|
||
|
||
import type { DarkMode, Theme } from '../../types/global';
|
||
import configProvider, { type DefaultThemeConfig } from '../util/config-provider';
|
||
import { defaultThemes } from '../config/theme-tokens';
|
||
|
||
const THEME_STORAGE_KEY = 'uview-pro-theme';
|
||
const DARK_MODE_STORAGE_KEY = 'uview-pro-dark-mode';
|
||
const themesRef = configProvider.themesRef;
|
||
const currentTheme = configProvider.currentThemeRef;
|
||
const darkModeRef = configProvider.darkModeRef;
|
||
|
||
/**
|
||
* 保存主题到 Storage
|
||
*/
|
||
function saveThemeToStorage(themeName: string) {
|
||
try {
|
||
uni.setStorageSync(THEME_STORAGE_KEY, themeName);
|
||
} catch (e) {
|
||
console.warn('[useTheme] failed to write storage', e);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 保存暗黑模式设置到 Storage
|
||
*/
|
||
function saveDarkModeToStorage(mode: DarkMode) {
|
||
try {
|
||
uni.setStorageSync(DARK_MODE_STORAGE_KEY, mode);
|
||
} catch (e) {
|
||
console.warn('[useTheme] failed to write storage', e);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置主题
|
||
*/
|
||
function setTheme(themeName: string) {
|
||
configProvider.setTheme(themeName);
|
||
currentTheme.value = configProvider.getCurrentTheme();
|
||
saveThemeToStorage(themeName);
|
||
}
|
||
|
||
/**
|
||
* 获取当前主题
|
||
*/
|
||
function getCurrentTheme(): Theme | null {
|
||
return currentTheme.value || configProvider.getCurrentTheme();
|
||
}
|
||
|
||
/**
|
||
* 获取所有可用主题
|
||
*/
|
||
function getAvailableThemes() {
|
||
return configProvider.getThemes();
|
||
}
|
||
|
||
/**
|
||
* 初始化主题系统
|
||
* @param themes 可选的主题列表,如果未提供则尝试从 uni.$u.themes 读取
|
||
* @param defaultConfig 可选的默认主题配置,支持字符串(默认主题名)或对象({ defaultTheme?, defaultDarkMode? })
|
||
*/
|
||
export function initTheme(themes?: Theme[], defaultConfig?: string | DefaultThemeConfig, isForce?: boolean) {
|
||
// 如果有传入主题列表,使用传入的
|
||
if (Array.isArray(themes) && themes.length > 0) {
|
||
configProvider.initTheme(themes, defaultConfig, isForce);
|
||
return;
|
||
}
|
||
|
||
// // 若已通过插件或其他方式完成初始化,则不再覆盖,最多按需切换默认主题
|
||
// const existingThemes = configProvider.getThemes();
|
||
// if (existingThemes.length > 0) {
|
||
// if (typeof defaultConfig === 'string') {
|
||
// configProvider.setTheme(defaultConfig);
|
||
// } else if (defaultConfig && typeof defaultConfig === 'object' && (defaultConfig as any).defaultTheme) {
|
||
// configProvider.setTheme(defaultConfig.defaultTheme);
|
||
// } else if (!configProvider.getCurrentTheme()) {
|
||
// configProvider.setTheme(existingThemes[0].name);
|
||
// } else {
|
||
// // 触发一次 apply,便于初始化 CSS 变量
|
||
// configProvider.setTheme(configProvider.getCurrentTheme()!.name);
|
||
// }
|
||
// return;
|
||
// }
|
||
|
||
// // 初始化 configProvider(如果运行时提供了内置主题)
|
||
// try {
|
||
// const builtin = (typeof uni !== 'undefined' && (uni as any).$u && (uni as any).$u.themes) || [];
|
||
// if (Array.isArray(builtin) && builtin.length > 0) {
|
||
// configProvider.initTheme(builtin as Theme[], defaultConfig);
|
||
// return;
|
||
// }
|
||
// } catch (e) {
|
||
// // ignore
|
||
// }
|
||
|
||
// 回退到内置默认主题
|
||
configProvider.initTheme(defaultThemes as Theme[], defaultConfig);
|
||
}
|
||
|
||
/**
|
||
* 初始化暗黑模式
|
||
* @param darkMode 暗黑模式设置
|
||
* @param isForce 是否强制初始化
|
||
*/
|
||
function initDarkMode(darkMode?: DarkMode, isForce?: boolean) {
|
||
configProvider.initDarkMode(darkMode, isForce);
|
||
}
|
||
/**
|
||
* 获取当前暗黑模式设置
|
||
*/
|
||
function getDarkMode(): DarkMode {
|
||
return configProvider.getDarkMode();
|
||
}
|
||
|
||
/**
|
||
* 设置暗黑模式
|
||
* @param mode 'auto' (跟随系统) | 'light' (强制亮色) | 'dark' (强制暗黑)
|
||
*/
|
||
function setDarkMode(mode: DarkMode) {
|
||
configProvider.setDarkMode(mode);
|
||
darkModeRef.value = mode;
|
||
saveDarkModeToStorage(mode);
|
||
}
|
||
|
||
/**
|
||
* 检查当前是否处于暗黑模式
|
||
*/
|
||
function isInDarkMode(): boolean {
|
||
return configProvider.isInDarkMode();
|
||
}
|
||
|
||
/**
|
||
* 切换暗黑模式(在当前模式的基础上切换)
|
||
*/
|
||
function toggleDarkMode() {
|
||
const current = getDarkMode();
|
||
const nextMode = current === 'dark' ? 'light' : 'dark';
|
||
setDarkMode(nextMode);
|
||
}
|
||
|
||
/**
|
||
* 使用主题的 composable
|
||
* 返回所有主题相关的响应式引用和方法
|
||
*/
|
||
export function useTheme() {
|
||
return {
|
||
// 响应式引用
|
||
currentTheme,
|
||
themes: themesRef,
|
||
darkMode: darkModeRef,
|
||
cssVars: configProvider.cssVarsRef,
|
||
|
||
// 主题相关方法
|
||
initTheme,
|
||
setTheme,
|
||
getCurrentTheme,
|
||
getAvailableThemes,
|
||
|
||
// 暗黑模式相关方法
|
||
initDarkMode,
|
||
getDarkMode,
|
||
setDarkMode,
|
||
isInDarkMode,
|
||
toggleDarkMode
|
||
};
|
||
}
|