First Push

This commit is contained in:
喆OvO
2026-08-06 11:11:11 +08:00
commit 0fef309972
551 changed files with 15793 additions and 0 deletions
+172
View File
@@ -0,0 +1,172 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Cal Display - Custom</title>
<style>
:root {
--bg: #0f1117;
--text: #e0e0e0;
--text-dim: #888;
--accent: #4A90D9;
--radius: 12px;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100vw; height: 100vh; height: 100dvh;
overflow: hidden;
font-family: -apple-system, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
background: var(--bg);
color: var(--text);
user-select: none; -webkit-user-select: none; touch-action: manipulation;
}
#custom-container {
width: 100%; height: 100%;
padding: clamp(10px, 2vw, 28px);
overflow-y: auto;
position: relative;
}
.alarm-overlay {
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
width: 100vw; height: 100vh; height: 100dvh;
background: rgba(15, 17, 23, 0.92);
display: flex; align-items: center; justify-content: center;
z-index: 100;
}
.alarm-overlay.hidden { display: none; }
.alarm-overlay-box {
text-align: center;
padding: clamp(24px, 5vw, 56px) clamp(32px, 6.5vw, 72px);
background: var(--card-bg); border-radius: clamp(12px, 2vw, 24px);
border: 2px solid #E05555;
animation: overlay-in 0.3s ease;
}
@keyframes overlay-in {
from { transform: scale(0.85); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
.alarm-overlay-icon { font-size: clamp(40px, 7vw, 80px); margin-bottom: clamp(8px, 1.5vh, 16px); }
.alarm-overlay-title { font-size: clamp(18px, 2.75vw, 36px); font-weight: 700; margin-bottom: clamp(6px, 1vh, 12px); color: #E05555; }
.alarm-overlay-info { font-size: clamp(14px, 2vw, 26px); color: var(--text-dim); margin-bottom: clamp(16px, 3vh, 32px); line-height: 1.6; }
.alarm-dismiss-btn {
padding: clamp(10px, 1.75vw, 20px) clamp(32px, 6vw, 64px);
font-size: clamp(14px, 2.25vw, 26px); font-weight: 600;
background: #E05555; color: #fff;
border: none; border-radius: clamp(8px, 1.25vw, 14px); cursor: pointer;
font-family: inherit;
}
.alarm-dismiss-btn:active { opacity: 0.8; }
</style>
</head>
<body>
<div id="custom-container">
{{ custom_html | safe }}
</div>
<!-- Custom notification overlay (hidden by default) -->
<div id="custom-notify-overlay" class="alarm-overlay hidden">
<div class="alarm-overlay-box">
<div class="alarm-overlay-icon" id="custom-notify-icon">&#128276;</div>
<div class="alarm-overlay-title" id="custom-notify-title">提醒</div>
<div class="alarm-overlay-info" id="custom-notify-info"></div>
<button id="custom-notify-dismiss" class="alarm-dismiss-btn">知道了</button>
</div>
</div>
<script>
(function () {
'use strict';
// Custom notification overlay
var customNotifyActive = false;
var customNotifyAutoDismiss = null;
var customNotifyAudioCtx = null;
function showCustomNotification(data) {
if (customNotifyActive) return;
customNotifyActive = true;
var overlay = document.getElementById('custom-notify-overlay');
var iconEl = document.getElementById('custom-notify-icon');
var titleEl = document.getElementById('custom-notify-title');
var infoEl = document.getElementById('custom-notify-info');
if (iconEl) iconEl.innerHTML = data.icon || '&#128276;';
if (titleEl) titleEl.textContent = data.title || '提醒';
if (infoEl) infoEl.textContent = data.message || '';
if (overlay) overlay.classList.remove('hidden');
if (data.sound !== false) {
playNotifySound();
}
customNotifyAutoDismiss = setTimeout(function () {
dismissCustomNotification();
}, 5000);
}
function playNotifySound() {
try {
var ctx = new (window.AudioContext || window.webkitAudioContext)();
customNotifyAudioCtx = ctx;
var t = ctx.currentTime;
[0, 0.3, 0.6].forEach(function (offset) {
var osc = ctx.createOscillator();
var gain = ctx.createGain();
osc.type = 'sine';
osc.frequency.value = 880;
gain.gain.setValueAtTime(1.0, t + offset);
gain.gain.exponentialRampToValueAtTime(0.001, t + offset + 0.15);
osc.connect(gain);
gain.connect(ctx.destination);
osc.start(t + offset);
osc.stop(t + offset + 0.15);
});
setTimeout(function () { ctx.close(); }, 2000);
} catch (_) {}
}
function dismissCustomNotification() {
customNotifyActive = false;
var overlay = document.getElementById('custom-notify-overlay');
if (overlay) overlay.classList.add('hidden');
if (customNotifyAudioCtx) {
try { customNotifyAudioCtx.close(); } catch (_) {}
customNotifyAudioCtx = null;
}
if (customNotifyAutoDismiss) {
clearTimeout(customNotifyAutoDismiss);
customNotifyAutoDismiss = null;
}
}
var customNotifyDismissBtn = document.getElementById('custom-notify-dismiss');
if (customNotifyDismissBtn) {
customNotifyDismissBtn.addEventListener('click', dismissCustomNotification);
}
// SSE: listen for control commands (force_refresh / mode_change / custom_notification)
function connectSSE() {
var es = new EventSource('/api/events');
es.onmessage = function (e) {
try {
var msg = JSON.parse(e.data);
if (msg.type === 'force_refresh' || msg.type === 'display_mode_changed') {
location.reload();
} else if (msg.type === 'custom_notification') {
showCustomNotification(msg.data);
}
} catch (_) {}
};
es.onerror = function () {
es.close();
setTimeout(connectSSE, 5000);
};
}
connectSSE();
})();
</script>
</body>
</html>