/* 主题系统:账户独立主题(dark/light/auto)。 * * - 后端 GET /api/theme 返回 {mode, effective};auto 已解析为 dark/light * (按用户经纬度+时区计算日出日落)。 * - 应用方式:html 元素加 .theme-light class(CSS 变量覆盖浅色)。 * - 切换动画:切换瞬间给 html 加 .theme-anim,触发全局 CSS transition * 平滑渐变,平时无全局 transition(不影响交互反馈)。 * - auto 模式每 5 分钟轮询一次(日落日出边界切换);显示端还会在收到 * SSE theme_changed 时立即刷新。 */ (function (global) { 'use strict'; var current = 'dark'; var pollTimer = null; function apply(effective) { if (!effective) return; if (effective === current) return; current = effective; var root = document.documentElement; root.classList.add('theme-anim'); root.classList.toggle('theme-light', effective === 'light'); // 过渡结束后移除动画 class,恢复常规交互反馈 setTimeout(function () { root.classList.remove('theme-anim'); }, 600); } function fetchTheme(cb) { var xhr = new XMLHttpRequest(); xhr.open('GET', '/api/theme'); xhr.onload = function () { if (xhr.status === 200) { var d = {}; try { d = JSON.parse(xhr.responseText || '{}'); } catch (e) {} if (d.effective) apply(d.effective); if (cb) cb(d); } }; xhr.onerror = function () { /* 网络失败保持当前主题 */ }; xhr.send(); } function initTheme() { fetchTheme(); if (!pollTimer) { // auto 模式日落/日出切换:每 5 分钟刷新一次 pollTimer = setInterval(fetchTheme, 5 * 60 * 1000); } } global.ThemeBridge = { apply: apply, fetch: fetchTheme, init: initTheme, getCurrent: function () { return current; } }; // 页面加载即应用主题 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initTheme); } else { initTheme(); } })(window);