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' }, { id: 'teal', name: '湖青', primary: '#00BCD4', primaryLight: '#4DD0E1', primaryBg: '#E0F7FA', primaryRgb: '0,188,212' } ] // 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() // Dark palette is unified with theme.json (#131316 family) so the chrome // background and the page background stop disagreeing. Card is brightened // to keep elevation readable on the darker backdrop. const baseVars = isDark ? '--text:#E5E5E7;--text-secondary:#98989F;--bg:#131316;--bg-gradient-start:#131316;--bg-gradient-end:#1C1C20;--card-bg:#26262B;--bg-soft:#343439;--border:#343439;--success:#30D158;--success-rgb:48,209,88;--danger:#FF6B6B;--danger-rgb:255,107,107;' : `--text:#333333;--text-secondary:#999999;--bg:${t.primaryBg};--bg-gradient-start:${t.primaryBg};--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;` 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 ? '#131316' : theme.primaryBg 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 ? '#131316' : getCurrentTheme().primaryBg 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 }