初始化
This commit is contained in:
268
index.html
Normal file
268
index.html
Normal file
@@ -0,0 +1,268 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>YOLO 更新检查</title>
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; style-src 'unsafe-inline' 'self'; script-src 'self' 'unsafe-inline'; img-src 'self' data:;">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0b1220;
|
||||
--card: #0f172a;
|
||||
--text: #e5e7eb;
|
||||
--muted: #9ca3af;
|
||||
--accent: #60a5fa;
|
||||
--accent-2: #34d399;
|
||||
--bar-bg: #1f2937;
|
||||
--bar-fg: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
--ok: #34d399;
|
||||
--error: #ef4444;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--bg: #f8fafc;
|
||||
--card: #ffffff;
|
||||
--text: #0f172a;
|
||||
--muted: #64748b;
|
||||
--bar-bg: #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
|
||||
background: radial-gradient(1200px 600px at 20% -10%, rgba(96, 165, 250, .25), transparent 50%),
|
||||
radial-gradient(1200px 600px at 120% 120%, rgba(52, 211, 153, .25), transparent 50%),
|
||||
var(--bg);
|
||||
color: var(--text);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 560px;
|
||||
max-width: calc(100% - 40px);
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, .04), rgba(255, 255, 255, 0)), var(--card);
|
||||
border: 1px solid rgba(255, 255, 255, .08);
|
||||
border-radius: 20px;
|
||||
padding: 28px;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, .25);
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: white;
|
||||
font-weight: 900;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, .3);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 18px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sub {
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin: 20px 0 16px;
|
||||
padding: 12px 14px;
|
||||
background: rgba(255, 255, 255, .04);
|
||||
border: 1px dashed rgba(255, 255, 255, .18);
|
||||
border-radius: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.progress-wrap {
|
||||
background: var(--bar-bg);
|
||||
border-radius: 999px;
|
||||
overflow: hidden;
|
||||
height: 14px;
|
||||
width: 100%;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .25);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background: var(--bar-fg);
|
||||
transition: width .25s ease;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 18px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
appearance: none;
|
||||
border: 0;
|
||||
border-radius: 12px;
|
||||
padding: 10px 14px;
|
||||
cursor: pointer;
|
||||
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
box-shadow: 0 6px 18px rgba(56, 189, 248, .35);
|
||||
}
|
||||
|
||||
button.ghost {
|
||||
background: transparent;
|
||||
border: 1px solid rgba(255, 255, 255, .18);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.ok {
|
||||
color: var(--ok);
|
||||
}
|
||||
|
||||
.err {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.fade {
|
||||
animation: fade .3s ease both;
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
from {
|
||||
opacity: .0;
|
||||
transform: translateY(6px)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: none
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="card fade">
|
||||
<div class="header">
|
||||
<div class="logo">PY</div>
|
||||
<div>
|
||||
<h1>YOLO 启动 / 更新检查</h1>
|
||||
<div class="sub">为你自动检查可用更新并在后台下载</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="status" class="status">正在初始化…</div>
|
||||
|
||||
<div class="progress-wrap" aria-label="下载进度">
|
||||
<div id="bar" class="progress-bar"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div>速度:<span id="speed">0</span> MB/s</div>
|
||||
<div>已下:<span id="transferred">0</span>/<span id="total">0</span> MB</div>
|
||||
<div>进度:<span id="percent">0</span>%</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button id="btn-install" style="display:none;">立即重启安装</button>
|
||||
<button id="btn-hide" class="ghost">最小化到托盘</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const $ = (id) => document.getElementById(id);
|
||||
const statusEl = $('status');
|
||||
const bar = $('bar');
|
||||
const sp = $('speed'), tf = $('transferred'), tt = $('total'), pc = $('percent');
|
||||
const btnInstall = $('btn-install');
|
||||
const btnHide = $('btn-hide');
|
||||
|
||||
// 订阅主进程事件
|
||||
window.electronAPI.onUpdateStatus(({ status, version, notes, currentVersion, message }) => {
|
||||
switch (status) {
|
||||
case 'checking':
|
||||
statusEl.textContent = '正在检查更新…';
|
||||
break;
|
||||
case 'available':
|
||||
statusEl.innerHTML = `检测到新版本 <b>v${version}</b>,正在下载…`;
|
||||
break;
|
||||
case 'none':
|
||||
statusEl.innerHTML = `已是最新版本 <span class="ok">(v${currentVersion})</span>。3 秒后自动最小化。`;
|
||||
bar.style.width = '100%'; pc.textContent = '100';
|
||||
setTimeout(() => window.close(), 3000);
|
||||
break;
|
||||
case 'downloaded':
|
||||
statusEl.innerHTML = `下载完成!可立即安装更新 <b>v${version}</b>。`;
|
||||
bar.style.width = '100%'; pc.textContent = '100';
|
||||
btnInstall.style.display = '';
|
||||
// 也可自动倒计时安装:
|
||||
// setTimeout(() => btnInstall.click(), 3000);
|
||||
break;
|
||||
case 'error':
|
||||
statusEl.innerHTML = `更新失败:<span class="err">${message || '未知错误'}</span>`;
|
||||
break;
|
||||
default:
|
||||
statusEl.textContent = '状态:' + status;
|
||||
}
|
||||
});
|
||||
|
||||
window.electronAPI.onUpdateProgress(({ percent, transferred, total, speed }) => {
|
||||
bar.style.width = Math.max(0, Math.min(100, percent || 0)) + '%';
|
||||
sp.textContent = speed ?? 0;
|
||||
tf.textContent = transferred ?? 0;
|
||||
tt.textContent = total ?? 0;
|
||||
pc.textContent = (percent ?? 0).toFixed(1);
|
||||
});
|
||||
|
||||
// 交互
|
||||
btnInstall.addEventListener('click', () => {
|
||||
statusEl.textContent = '即将重启并安装更新…';
|
||||
window.electronAPI.installNow();
|
||||
});
|
||||
|
||||
btnHide.addEventListener('click', () => {
|
||||
window.close(); // 在 main.js 里拦截 close -> hide()
|
||||
});
|
||||
|
||||
// 首次加载立即请求检查
|
||||
window.electronAPI.checkForUpdates();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user