First Push
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
/* 主题系统:账户独立主题(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);
|
||||
Reference in New Issue
Block a user