This commit is contained in:
2026-06-15 13:55:05 +08:00
parent 7094e6c3b0
commit cebb65fb35
10 changed files with 330 additions and 3 deletions

View File

@@ -159,6 +159,55 @@ const SharedCSS = `
.app-footer-version { opacity: 0.75; text-align: center; white-space: nowrap; }
.app-footer-link { justify-self: end; padding: 0; background: transparent; color: #a7a7a7; border: 0; cursor: pointer; font: inherit; opacity: 0.72; }
.app-footer-link:hover { background: transparent; opacity: 1; text-decoration: underline; }
.app-footer-version-button { justify-self: center; padding: 0; background: transparent; color: #a7a7a7; border: 0; cursor: pointer; font: inherit; opacity: 0.75; text-align: center; white-space: nowrap; }
.app-footer-version-button:hover { background: transparent; opacity: 1; text-decoration: underline; }
.toast-box {
position: fixed;
right: 18px;
bottom: 18px;
z-index: 50;
max-width: min(420px, calc(100vw - 36px));
padding: 10px 12px;
display: none;
align-items: center;
gap: 10px;
color: #ddd;
background: #252526;
border: 1px solid #444;
border-left: 3px solid #007fd4;
border-radius: 5px;
box-shadow: 0 10px 28px rgba(0,0,0,0.35);
font-size: 12px;
line-height: 1.35;
}
.toast-box.is-visible { display: flex; }
.toast-box.is-update { border-left-color: #ffd580; }
.toast-box.is-current { border-left-color: #89d185; }
.toast-box.is-error { border-left-color: #f48771; }
.toast-message { min-width: 0; flex: 1; overflow-wrap: anywhere; }
.toast-action {
flex: 0 0 auto;
padding: 4px 8px;
background: #0e639c;
color: #fff;
border: 0;
border-radius: 2px;
font-size: 12px;
}
.toast-close {
flex: 0 0 auto;
width: 22px;
height: 22px;
padding: 0;
display: grid;
place-items: center;
background: transparent;
color: #a7a7a7;
border: 0;
font-size: 16px;
line-height: 1;
}
.toast-close:hover { background: rgba(255,255,255,0.08); color: #fff; }
body.sidebar-collapsed .sidebar { align-items: stretch; }
body.sidebar-collapsed .sidebar-title,
body.sidebar-collapsed .nav-text,
@@ -539,10 +588,15 @@ func Page(activePath, title, body string) string {
<div class="content">` + body + `</div>
<div class="app-footer">
<button id="betaToolsToggle" class="beta-tools-toggle" data-enabled="` + boolAttr(betaToolsEnabled) + `">` + betaButtonLabel + `</button>
<span class="app-footer-version">` + AppVersion + ` - JJGC 00784</span>
<button id="updateCheck" type="button" class="app-footer-version-button" title="Check for updates">` + AppVersion + ` - JJGC 00784</button>
<button type="button" class="app-footer-link" data-path="/changelog">Changelog</button>
</div>
</div>
<div id="toastBox" class="toast-box" role="status" aria-live="polite">
<span id="toastMessage" class="toast-message"></span>
<button id="toastAction" type="button" class="toast-action is-hidden">Open Repository</button>
<button id="toastClose" type="button" class="toast-close" aria-label="Close">x</button>
</div>
<script>
if (localStorage.getItem('hplSidebarCollapsed') === 'true') {
document.body.classList.add('sidebar-collapsed');
@@ -628,6 +682,51 @@ document.getElementById('betaToolsToggle').addEventListener('click', async (even
});
window.location.reload();
});
const toastBox = document.getElementById('toastBox');
const toastMessage = document.getElementById('toastMessage');
const toastAction = document.getElementById('toastAction');
const toastClose = document.getElementById('toastClose');
let toastTimer = null;
let updateRepositoryUrl = '';
function showToast(message, status, repositoryUrl) {
window.clearTimeout(toastTimer);
updateRepositoryUrl = repositoryUrl || '';
toastMessage.textContent = message || '';
toastAction.classList.toggle('is-hidden', !updateRepositoryUrl);
toastBox.className = 'toast-box is-visible is-' + (status || 'current');
toastTimer = window.setTimeout(() => {
toastBox.classList.remove('is-visible');
}, updateRepositoryUrl ? 9000 : 5000);
}
async function checkForUpdates(showCurrent) {
try {
const response = await fetch('/api/update/check');
const result = await response.json();
if (result.status === 'current' && !showCurrent) return;
showToast(result.message || 'HPL Toolbox update check finished.', result.status, result.repositoryUrl);
} catch (error) {
showToast('HPL Toolbox update check failed: ' + (error.message || error), 'error');
}
}
document.getElementById('updateCheck').addEventListener('click', () => {
checkForUpdates(true);
});
toastClose.addEventListener('click', () => {
window.clearTimeout(toastTimer);
toastBox.classList.remove('is-visible');
});
toastAction.addEventListener('click', async () => {
if (!updateRepositoryUrl) return;
await fetch('/api/open', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: updateRepositoryUrl }),
});
});
if (sessionStorage.getItem('hplToolboxUpdateChecked') !== 'true') {
sessionStorage.setItem('hplToolboxUpdateChecked', 'true');
checkForUpdates(true);
}
</script>
</body></html>`
}