70b87d424d
新增 applyChrome() 在 onLaunch 第一行调用,把导航栏变色点从首页 onShow 提前到 onLaunch,缩短冷启动橙色跳变窗口。app.json 静态橙色在 JS 执行前 生效是框架硬限制,无法完全消除。 Co-Authored-By: Claude <noreply@anthropic.com>
158 lines
4.8 KiB
JavaScript
158 lines
4.8 KiB
JavaScript
const THEMES = [
|
|
{
|
|
id: 'orange',
|
|
name: '活力橙',
|
|
primary: '#FF6B35',
|
|
primaryLight: '#FF8C5A',
|
|
primaryBg: '#FFF3ED',
|
|
primaryRgb: '255,107,53'
|
|
},
|
|
{
|
|
id: 'blue',
|
|
name: '深海蓝',
|
|
primary: '#2979FF',
|
|
primaryLight: '#5C9CFF',
|
|
primaryBg: '#EDF4FF',
|
|
primaryRgb: '41,121,255'
|
|
},
|
|
{
|
|
id: 'green',
|
|
name: '森林绿',
|
|
primary: '#43A047',
|
|
primaryLight: '#6EC072',
|
|
primaryBg: '#EDF7EE',
|
|
primaryRgb: '67,160,71'
|
|
},
|
|
{
|
|
id: 'purple',
|
|
name: '优雅紫',
|
|
primary: '#7E57C2',
|
|
primaryLight: '#A08AD6',
|
|
primaryBg: '#F5F0FA',
|
|
primaryRgb: '126,87,194'
|
|
},
|
|
{
|
|
id: 'pink',
|
|
name: '樱花粉',
|
|
primary: '#EC407A',
|
|
primaryLight: '#F06A9A',
|
|
primaryBg: '#FDEEF3',
|
|
primaryRgb: '236,64,122'
|
|
}
|
|
]
|
|
|
|
// Light-mode base CSS custom properties shared between the cold-start export
|
|
// (used by every page as initial data) and getThemeStyle(isDark=false).
|
|
// Update here ONLY — getThemeStyle picks it up for the light branch.
|
|
const BASE_VARS = '--text:#333333;--text-secondary:#999999;--bg:#F5F5F5;--bg-gradient-start:#F5F5F5;--bg-gradient-end:#FAFAFA;--card-bg:#FFFFFF;--bg-soft:#F0F0F0;--border:#EEEEEE;--success:#4CAF50;--success-rgb:76,175,80;--danger:#E53935;--danger-rgb:229,57,53;'
|
|
const DEFAULT_THEME_ID = 'orange'
|
|
const THEME_KEY = 'app_theme'
|
|
|
|
const getThemeById = (id) => THEMES.find(t => t.id === id) || THEMES[0]
|
|
|
|
const getCurrentTheme = () => {
|
|
let id = wx.getStorageSync(THEME_KEY)
|
|
if (!id) {
|
|
// fallback: try recovering from user_settings backup
|
|
try {
|
|
const s = wx.getStorageSync('user_settings')
|
|
if (s && s.themeId) id = s.themeId
|
|
} catch (e) {}
|
|
}
|
|
return getThemeById(id || DEFAULT_THEME_ID)
|
|
}
|
|
|
|
const _setNavBarColor = (primary) => {
|
|
try {
|
|
wx.setNavigationBarColor({
|
|
frontColor: '#ffffff',
|
|
backgroundColor: primary
|
|
})
|
|
} catch (e) {}
|
|
}
|
|
|
|
const setTheme = (id) => {
|
|
try {
|
|
wx.setStorageSync(THEME_KEY, id)
|
|
// redundant backup in user_settings
|
|
try {
|
|
const s = wx.getStorageSync('user_settings') || {}
|
|
s.themeId = id
|
|
wx.setStorageSync('user_settings', s)
|
|
} catch (e) {}
|
|
} catch (e) {
|
|
console.error('Failed to save theme:', e)
|
|
}
|
|
const theme = getThemeById(id)
|
|
_setNavBarColor(theme.primary)
|
|
const app = getApp()
|
|
if (app && app.globalData) app.globalData.theme = theme
|
|
|
|
// sync to cloud (lazy-require to avoid circular deps)
|
|
try { require('./cloud').pushAll() } catch (e) {}
|
|
return theme
|
|
}
|
|
|
|
const getThemeStyle = (theme, isDark = false) => {
|
|
const t = theme || getCurrentTheme()
|
|
const baseVars = isDark
|
|
? '--text:#E5E5E7;--text-secondary:#98989F;--bg:#2C2C2E;--bg-gradient-start:#2C2C2E;--bg-gradient-end:#38383A;--card-bg:#3A3A3C;--bg-soft:#48484A;--border:#48484A;--success:#30D158;--success-rgb:48,209,88;--danger:#FF6B6B;--danger-rgb:255,107,107;'
|
|
: BASE_VARS
|
|
return `${baseVars}--primary:${t.primary};--primary-light:${t.primaryLight};--primary-bg:${t.primaryBg};--primary-rgb:${t.primaryRgb};`
|
|
}
|
|
|
|
const applyThemeToPage = (self) => {
|
|
const darkMod = require('./darkMode')
|
|
const theme = getCurrentTheme()
|
|
const isDark = darkMod.getInitialDarkMode()
|
|
const nextStyle = getThemeStyle(theme, isDark)
|
|
// Skip setData if nothing changed — avoid unnecessary re-renders on every onShow
|
|
if (self.data && self.data.themeStyle === nextStyle) {
|
|
return
|
|
}
|
|
self.setData({ theme, themeStyle: nextStyle, isDark })
|
|
_setNavBarColor(theme.primary)
|
|
|
|
// theme.json 的 dark section 只响应系统暗黑模式。用户手动选择暗黑
|
|
// 但系统是明亮时,窗口背景仍为浅色,切 tab 会闪白。这里用 API 强制设置
|
|
// 窗口背景,让 tab 切换时的瞬间底色与当前模式一致。
|
|
const bg = isDark ? '#0F0F12' : '#F5F5F5'
|
|
try { wx.setBackgroundColor({ backgroundColor: bg, backgroundColorTop: bg, backgroundColorBottom: bg }) } catch (e) {}
|
|
}
|
|
|
|
/** 仅设置窗口背景色,不触发页面 setData — 供 app.js 冷启动使用 */
|
|
const applyWindowBg = () => {
|
|
try {
|
|
const darkMod = require('./darkMode')
|
|
const isDark = darkMod.getInitialDarkMode()
|
|
const bg = isDark ? '#0F0F12' : '#F5F5F5'
|
|
wx.setBackgroundColor({ backgroundColor: bg, backgroundColorTop: bg, backgroundColorBottom: bg })
|
|
} catch (e) {}
|
|
}
|
|
|
|
/**
|
|
* 冷启动尽早调用:设导航栏色 + 窗口背景。
|
|
* 原生导航栏在 JS 执行前用 app.json 写死的橙色,这里在 onLaunch 第一时间
|
|
* 切到用户主题色,把冷启动橙->主题色的跳变窗口压到最小(无法完全消除,
|
|
* 因为 app.json 静态值在 onLaunch 之前就已应用)。
|
|
*/
|
|
const applyChrome = () => {
|
|
try {
|
|
_setNavBarColor(getCurrentTheme().primary)
|
|
applyWindowBg()
|
|
} catch (e) {}
|
|
}
|
|
|
|
module.exports = {
|
|
THEMES,
|
|
DEFAULT_THEME_ID,
|
|
BASE_VARS,
|
|
applyWindowBg,
|
|
applyChrome,
|
|
getThemeById,
|
|
getCurrentTheme,
|
|
setTheme,
|
|
applyThemeToPage,
|
|
getThemeStyle
|
|
}
|