fix(webui/admin): paint page header immediately, confine spinner to content
The Admin Dashboard (OverviewPage) and Admin System (SystemPage) boards each blanked the whole content pane to a bare headerless lpLoadingBox() on init(), then rendered the .page-header + panel only once data arrived. So clicking either tab flashed a full-pane spinner with no indication of which page you'd landed on, then everything appeared at once. Extract the page header into a _headerHtml() helper on each page and render it up front in both the loading state and render(). Now navigating to a board paints its header (breadcrumb + title + description) instantly and the spinner is confined to the .admin-panel beneath it — the header stays put and only the content swaps in when the fetch resolves. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
parent
d96a9646bc
commit
6dd729d0ac
@ -14,7 +14,10 @@ class OverviewPage {
|
||||
|
||||
async init() {
|
||||
const r = this.root();
|
||||
if (r) r.innerHTML = '<div class="admin-page">' + lpLoadingBox() + '</div>';
|
||||
// Paint the header immediately and confine the spinner to the content
|
||||
// panel below it, rather than blanking the whole pane to a headerless
|
||||
// loader while the board's data loads.
|
||||
if (r) r.innerHTML = `<div class="admin-page">${this._headerHtml()}<div class="admin-panel">${lpLoadingBox()}</div></div>`;
|
||||
this.bindEvents();
|
||||
const [upd, verify, backup, ssh, disk, mem, info] = await Promise.all([
|
||||
this.fetchJson('/data/system/update_status.json'),
|
||||
@ -156,6 +159,22 @@ class OverviewPage {
|
||||
return `<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${paths[name] || ''}</svg>`;
|
||||
}
|
||||
|
||||
// The page header (breadcrumb + title + description) — rendered up front on
|
||||
// the loading state AND by render(), so navigating here paints the header
|
||||
// immediately and the spinner is confined to the content panel below it,
|
||||
// instead of the whole pane blanking to a headerless loader.
|
||||
_headerHtml() {
|
||||
return `
|
||||
<div class="page-header config-page-header">
|
||||
<div class="page-header-icon-slot"><svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="9"></rect><rect x="14" y="3" width="7" height="5"></rect><rect x="14" y="12" width="7" height="9"></rect><rect x="3" y="16" width="7" height="5"></rect></svg></div>
|
||||
<div class="page-header-title">
|
||||
<div class="admin-breadcrumb">Admin</div>
|
||||
<h1>Dashboard</h1>
|
||||
<p>System health and admin status at a glance. Manage anything from the cards below.</p>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
render() {
|
||||
const root = this.root();
|
||||
if (!root) return;
|
||||
@ -235,14 +254,7 @@ class OverviewPage {
|
||||
|
||||
root.innerHTML = `
|
||||
<div class="admin-page">
|
||||
<div class="page-header config-page-header">
|
||||
<div class="page-header-icon-slot"><svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="9"></rect><rect x="14" y="3" width="7" height="5"></rect><rect x="14" y="12" width="7" height="9"></rect><rect x="3" y="16" width="7" height="5"></rect></svg></div>
|
||||
<div class="page-header-title">
|
||||
<div class="admin-breadcrumb">Admin</div>
|
||||
<h1>Dashboard</h1>
|
||||
<p>System health and admin status at a glance. Manage anything from the cards below.</p>
|
||||
</div>
|
||||
</div>
|
||||
${this._headerHtml()}
|
||||
<div class="admin-panel">
|
||||
<div class="admin-card-grid">
|
||||
${updCard}
|
||||
|
||||
@ -83,8 +83,10 @@ class SystemPage {
|
||||
return;
|
||||
}
|
||||
|
||||
// Default: index view.
|
||||
r.innerHTML = '<div class="admin-page">' + lpLoadingBox('Loading system stats…') + '</div>';
|
||||
// Default: index view. Paint the header immediately and keep the spinner
|
||||
// inside the content panel, so the page reads as "System, loading its
|
||||
// stats" rather than a blank headerless loader.
|
||||
r.innerHTML = `<div class="admin-page sys-page">${this._headerHtml('—')}<div class="admin-panel">${lpLoadingBox('Loading system stats…')}</div></div>`;
|
||||
await this.refresh();
|
||||
this.bind();
|
||||
if (window.LiveSystem) {
|
||||
@ -257,6 +259,22 @@ class SystemPage {
|
||||
if (subEl) subEl.textContent = `Live host and per-app statistics. Updated ${new Date(s.t || Date.now()).toLocaleTimeString()}.`;
|
||||
}
|
||||
|
||||
// The page header (breadcrumb + title + description) — rendered up front on
|
||||
// the loading state AND by render(), so navigating here paints the header
|
||||
// immediately and the spinner is confined to the content panel below it,
|
||||
// instead of the whole pane blanking to a headerless loader.
|
||||
_headerHtml(updated = '—') {
|
||||
return `
|
||||
<div class="page-header config-page-header">
|
||||
<div class="page-header-icon-slot"><svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline></svg></div>
|
||||
<div class="page-header-title">
|
||||
<div class="admin-breadcrumb">Admin</div>
|
||||
<h1>System</h1>
|
||||
<p>Live host and per-app statistics. Updated ${updated}.</p>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
render() {
|
||||
const root = this.root();
|
||||
if (!root) return;
|
||||
@ -328,14 +346,7 @@ class SystemPage {
|
||||
|
||||
root.innerHTML = `
|
||||
<div class="admin-page sys-page">
|
||||
<div class="page-header config-page-header">
|
||||
<div class="page-header-icon-slot"><svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline></svg></div>
|
||||
<div class="page-header-title">
|
||||
<div class="admin-breadcrumb">Admin</div>
|
||||
<h1>System</h1>
|
||||
<p>Live host and per-app statistics. Updated ${updated}.</p>
|
||||
</div>
|
||||
</div>
|
||||
${this._headerHtml(updated)}
|
||||
<div class="admin-panel">
|
||||
${gauges}
|
||||
${charts}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user