feat: glass effect toggle, media refresh timing fix, page transition perf

This commit is contained in:
2026-08-16 18:42:04 +08:00
parent a65205b8d2
commit 6915c54832
9 changed files with 119 additions and 23 deletions
+16 -11
View File
@@ -42,9 +42,10 @@ body {
.rail {
width: 80px;
background: var(--glass-bg);
backdrop-filter: blur(20px) saturate(1.2) brightness(1.05) contrast(1.1);
-webkit-backdrop-filter: blur(20px) saturate(1.2) brightness(1.05) contrast(1.1);
backdrop-filter: var(--blur-filter);
-webkit-backdrop-filter: var(--blur-filter);
border-right: 1px solid var(--glass-border);
box-shadow: var(--glass-shadow);
display: flex;
flex-direction: column;
align-items: center;
@@ -70,6 +71,8 @@ body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
gap: 3px;
background: none;
border: none;
@@ -87,7 +90,7 @@ body {
justify-content: center;
}
.rail-item .ico svg { width: 100%; height: 100%; display: block; }
.rail-item .lbl { font-size: 11px; }
.rail-item .lbl { font-size: 11px; text-align: center; width: 100%; }
.rail-item.active { background: var(--accent); color: #fff; }
@@ -140,9 +143,10 @@ body {
/* Card: soft-glass morphism (reuse Task 4 tokens, not a solid color) */
.card {
background: var(--glass-bg);
backdrop-filter: blur(20px) saturate(1.2) brightness(1.05) contrast(1.1);
-webkit-backdrop-filter: blur(20px) saturate(1.2) brightness(1.05) contrast(1.1);
backdrop-filter: var(--blur-filter);
-webkit-backdrop-filter: var(--blur-filter);
border: 1px solid var(--glass-border);
box-shadow: var(--glass-shadow);
border-radius: 14px;
padding: 20px;
color: var(--text);
@@ -298,8 +302,8 @@ body {
padding: 6px 10px;
border-radius: 999px;
background: var(--glass-bg);
backdrop-filter: blur(20px) saturate(1.2);
-webkit-backdrop-filter: blur(20px) saturate(1.2);
backdrop-filter: var(--blur-filter);
-webkit-backdrop-filter: var(--blur-filter);
border: 1px solid var(--glass-border);
z-index: 100;
}
@@ -343,8 +347,8 @@ body {
padding: 8px;
border-radius: 16px;
background: var(--glass-bg);
backdrop-filter: blur(20px) saturate(1.2);
-webkit-backdrop-filter: blur(20px) saturate(1.2);
backdrop-filter: var(--blur-filter);
-webkit-backdrop-filter: var(--blur-filter);
border: 1px solid var(--glass-border);
z-index: 100;
}
@@ -408,9 +412,10 @@ body {
margin-bottom: 8px;
border-radius: 14px;
background: var(--glass-bg);
backdrop-filter: blur(20px) saturate(1.2) brightness(1.05) contrast(1.1);
-webkit-backdrop-filter: blur(20px) saturate(1.2) brightness(1.05) contrast(1.1);
backdrop-filter: var(--blur-filter);
-webkit-backdrop-filter: var(--blur-filter);
border: 1px solid var(--glass-border);
box-shadow: var(--glass-shadow);
color: var(--text);
}
+12
View File
@@ -6,6 +6,18 @@
--text: #1a1a1a;
--text-dim: #8a8a90;
--accent: #ff6900;
/* 玻璃效果默认关闭:无模糊、无高光(普通半透明) */
/* Glass effect off by default: no blur, no highlight (plain translucent) */
--blur-filter: none;
--glass-shadow: none;
}
/* 玻璃效果开启:磨砂模糊 + 边缘反射高光(液态玻璃,参考 Apple WWDC25 */
/* Glass effect on: frosted blur + edge-reflection highlight (liquid glass) */
:root[data-glass="on"] {
--blur-filter: blur(20px) saturate(1.2) brightness(1.05) contrast(1.1);
--glass-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18),
inset 0 -1px 0 rgba(255, 255, 255, 0.04);
}
/* 系统深色:仅在未强制浅色时生效(跟随系统) */
+1
View File
@@ -7,6 +7,7 @@
<link rel="stylesheet" href="css/tokens.css">
<link rel="stylesheet" href="css/app.css">
<script src="js/theme.js"></script>
<script src="js/glass.js"></script>
</head>
<body>
<div id="wallpaper-dim"></div>
+24
View File
@@ -0,0 +1,24 @@
// 玻璃效果开关:普通半透明(默认)/ 液态玻璃(backdrop-filter 磨砂 + 边缘高光)
// Glass effect toggle: plain translucent (default) / liquid glass (backdrop-filter
// frost + edge highlight), persisted in localStorage
(function () {
const KEY = 'hearth-glass';
window.glass = {
enabled() {
return localStorage.getItem(KEY) === '1';
},
setEnabled(on) {
localStorage.setItem(KEY, on ? '1' : '0');
this.apply();
},
// 应用开关:写 data-glass 属性,CSS 据此切换 --blur-filter 等变量
// Apply: set the data-glass attribute; CSS switches --blur-filter etc. from it
apply() {
document.documentElement.setAttribute('data-glass', this.enabled() ? 'on' : 'off');
},
};
// 启动即应用(默认关闭 = 普通半透明)
window.glass.apply();
})();
@@ -10,6 +10,10 @@ window.loadSettings = function () {
<span class="lbl">主题</span>
<span class="arrow" id="theme-state">跟随系统</span>
</div>
<div class="st-item" id="glass-item">
<span class="lbl">玻璃效果</span>
<span class="sw" id="glass-sw"><i></i></span>
</div>
<div class="st-item" id="brightness-item">
<span class="lbl">屏幕亮度</span>
<span class="arrow" id="brightness-state"></span>
@@ -41,6 +45,7 @@ window.loadSettings = function () {
<div class="st-item"><span class="lbl">版本 0.1.0</span><span class="arrow"></span></div>
</div>`;
setupTheme(page);
setupGlass(page);
setupMask(page);
setupNotificationAccess(page);
setupBrightness(page);
@@ -71,6 +76,18 @@ function setupTheme(page) {
};
}
// 玻璃效果开关:普通半透明 ↔ 液态玻璃(backdrop-filter 磨砂 + 边缘高光)
// Glass effect toggle: plain translucent vs liquid glass
function setupGlass(page) {
const sw = page.querySelector('#glass-sw');
const refresh = () => sw.classList.toggle('on', glass.enabled());
refresh();
page.querySelector('#glass-item').onclick = () => {
glass.setEnabled(!glass.enabled());
refresh();
};
}
// 背景遮罩:开关 + 明暗度(仅夜间主题显示)
// Wallpaper dim: toggle + opacity (shown only under dark theme)
function setupMask(page) {
+11 -4
View File
@@ -29,9 +29,16 @@ const router = {
// always occupies space; only toggle visibility to avoid shifting icons)
const clock = document.getElementById('rail-clock');
if (clock) clock.style.visibility = (id === 'home') ? 'hidden' : 'visible';
if (id === 'home') window.updateHomeCards && window.updateHomeCards();
if (id === 'applist') window.loadAppList && window.loadAppList();
if (id === 'webapplist') window.loadWebAppList && window.loadWebAppList();
if (id === 'settings') window.loadSettings && window.loadSettings();
// 延迟内容加载到下一帧:让切换动画先流畅播放,避免加载重活(查应用/拉清单)
// 在动画帧内阻塞导致卡顿
// Defer content loading to the next frame: let the switch animation play
// smoothly first, avoiding jank from heavy loads (app query / manifest fetch)
// blocking within the animation frame
requestAnimationFrame(() => {
if (id === 'home') window.updateHomeCards && window.updateHomeCards();
if (id === 'applist') window.loadAppList && window.loadAppList();
if (id === 'webapplist') window.loadWebAppList && window.loadWebAppList();
if (id === 'settings') window.loadSettings && window.loadSettings();
});
}
};