Files
wot-uniapp/src/composables/useTheme.ts
李琦 fe5a5b6c0f 1. 小程序端
2. 视频优化
2026-07-30 14:11:51 +08:00

146 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 主题与 wot ConfigProvider 变量。
* 后台模式强制按暗色注入,避免用户浅色偏好导致表单字色/底色错乱。
*/
import { computed, ref } from 'vue'
import { useAppMode } from './useAppMode'
export type ThemePref = 'system' | 'light' | 'dark'
const THEME_KEY = 'theme-pref'
const themePref = ref<ThemePref>((uni.getStorageSync(THEME_KEY) as ThemePref) || 'system')
const isDark = ref(false)
function resolveDark(pref: ThemePref): boolean {
if (pref === 'dark') return true
if (pref === 'light') return false
try {
// 优先新 API避免 wx.getSystemInfoSync 弃用警告
const base = typeof uni.getAppBaseInfo === 'function' ? uni.getAppBaseInfo() : null
if (base && 'theme' in base) {
return (base as { theme?: string }).theme === 'dark'
}
const info = uni.getSystemInfoSync()
return (info as UniApp.GetSystemInfoResult & { theme?: string }).theme === 'dark'
}
catch {
return false
}
}
/**
* 同步窗口底色到 art 主题色。
* theme.json 的 @bgColor 只跟系统深色App 内选手动深色时必须靠此 API避免 page 露白。
*/
function syncPageBackground(dark: boolean, admin = false) {
const bg = admin ? '#0a0a0a' : dark ? '#050505' : '#faf8f4'
try {
uni.setBackgroundColor({
backgroundColor: bg,
backgroundColorTop: bg,
backgroundColorBottom: bg,
})
}
catch { /* H5 may ignore */ }
try {
uni.setNavigationBarColor({
frontColor: dark || admin ? '#ffffff' : '#000000',
backgroundColor: bg,
})
}
catch { /* custom nav may ignore */ }
uni.setStorageSync('theme-bg-sync', `${dark || admin ? 1 : 0}-${Date.now()}`)
}
export function useTheme() {
const { appMode } = useAppMode()
/** 用户偏好暗色,或当前处于后台模式 */
const effectiveDark = computed(() => isDark.value || appMode.value === 'admin')
const apply = () => {
isDark.value = resolveDark(themePref.value)
syncPageBackground(isDark.value, appMode.value === 'admin')
}
const setThemePref = (pref: ThemePref) => {
themePref.value = pref
uni.setStorageSync(THEME_KEY, pref)
apply()
}
const themeLabel = computed(() => {
if (themePref.value === 'system') return '跟随系统'
if (themePref.value === 'light') return '浅色'
return '深色'
})
const wotTheme = computed(() => (effectiveDark.value ? 'dark' : 'light'))
/** 注入 wot ConfigProvider主题色 + 导航/弹层/表单/搜索深色,避免白底割裂 */
const themeVars = computed(() => {
const dark = effectiveDark.value
const admin = appMode.value === 'admin'
const bg = dark ? '#121214' : '#ffffff'
const pageBg = admin ? '#0a0a0a' : dark ? '#050505' : '#faf8f4'
const title = dark ? '#ececec' : '#171717'
const muted = dark ? '#888888' : '#6b6b6b'
const border = dark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.08)'
return {
colorTheme: '#d4b383',
navbarColor: title,
navbarBg: admin
? 'rgba(10,10,10,0.92)'
: dark
? 'rgba(5,5,5,0.92)'
: 'rgba(250,248,244,0.92)',
navbarDescColor: title,
colorBg: bg,
colorTitle: title,
colorContent: title,
colorSecondary: muted,
darkColor: bg,
darkBackground: pageBg,
tabsNavBg: 'transparent',
tabsNavColor: muted,
tabsNavActiveColor: title,
tabsNavLineColor: '#d4b383',
tabsNavBorder: border,
cellBg: bg,
cellTitleColor: title,
cellValueColor: muted,
cellLabelColor: muted,
cellBorderColor: border,
collapseBg: bg,
collapseBodyBg: bg,
collapseHeaderBg: bg,
collapseTitleColor: title,
/* 后台表单需要可见底色,不能跟卡片同色透明 */
inputBg: dark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.03)',
inputInnerColor: title,
inputInnerPlaceholderColor: muted,
inputBorderColor: border,
textareaBg: dark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.03)',
textareaInnerColor: title,
textareaInnerPlaceholderColor: muted,
searchInputBg: dark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)',
searchInputColor: title,
searchPlaceholderColor: muted,
searchIconColor: muted,
}
})
apply()
return {
themePref,
isDark,
effectiveDark,
themeLabel,
wotTheme,
themeVars,
setThemePref,
apply,
}
}