Spaces:
Running
Running
boot-ux: add no-white-flash branded boot-guard splash to /console (pages/console.html)
Browse filesAdditive inline splash painted as first <body> node so first paint is always branded chrome + honest 'initializing…', never a white void during cold factory-rebuild boot or while the first live fetch resolves. Self-clears on first view paint; honest 'reconnecting' fallback on stall; hard-cap removal; respects prefers-reduced-motion. 0 runtime CDN, no codenames, no fabricated metrics.
- pages/console.html +85 -0
pages/console.html
CHANGED
|
@@ -442,6 +442,91 @@ details.raw[open] summary{color:var(--muted);}
|
|
| 442 |
</style>
|
| 443 |
</head>
|
| 444 |
<body>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 445 |
<div class="topbar">
|
| 446 |
<button class="menu-btn" aria-label="Toggle navigation" aria-expanded="false" onclick="toggleSide()">☰</button>
|
| 447 |
<span>SZL HOLDINGS</span><span class="sep">/</span>
|
|
|
|
| 442 |
</style>
|
| 443 |
</head>
|
| 444 |
<body>
|
| 445 |
+
<!-- ============================================================================
|
| 446 |
+
SZL BOOT-GUARD (no-white-flash) — additive, 0-CDN, byte-identical across flagships.
|
| 447 |
+
PROBLEM: the head loads several synchronous vendored <script src> tags (THREE,
|
| 448 |
+
ECharts, globe.gl, etc.) BEFORE <body> is parsed; on a cold factory-rebuild boot
|
| 449 |
+
or a slow/ flapping egress that download window paints as a WHITE VOID, and the
|
| 450 |
+
bare <main>loading…</main> can persist if a view's first live fetch stalls.
|
| 451 |
+
FIX: paint a branded full-screen splash as the FIRST node in <body> using ONLY
|
| 452 |
+
inline styles (cannot be blocked by any external asset), so first paint is ALWAYS
|
| 453 |
+
the branded shell + an honest "initializing…" — never white. The guard self-clears
|
| 454 |
+
the instant the app's first view renders (MutationObserver on #content), and a
|
| 455 |
+
watchdog turns the copy into an honest "reconnecting" line if boot stalls past the
|
| 456 |
+
cap — NEVER a permanent spinner, NEVER a fabricated number. Respects
|
| 457 |
+
prefers-reduced-motion. Removes itself cleanly; leaves zero residue in the DOM. -->
|
| 458 |
+
<div id="szl-bootguard" role="status" aria-live="polite" style="position:fixed;inset:0;z-index:2147483646;background:#0a0a0a;color:#f5f5f5;display:flex;flex-direction:column;align-items:center;justify-content:center;font-family:'Space Grotesk',Georgia,serif;-webkit-font-smoothing:antialiased;">
|
| 459 |
+
<div style="display:flex;align-items:center;gap:14px;">
|
| 460 |
+
<div id="szl-bg-mark" style="width:48px;height:48px;border-radius:11px;background:linear-gradient(135deg,#c9b787,#5fb3a3);color:#0a0a0a;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:26px;line-height:1;box-shadow:0 0 22px rgba(95,179,163,.28);">A</div>
|
| 461 |
+
<div style="text-align:left;">
|
| 462 |
+
<div style="font-size:13px;letter-spacing:.18em;color:#888;font-family:'JetBrains Mono',ui-monospace,monospace;">SZL HOLDINGS</div>
|
| 463 |
+
<div style="font-size:21px;font-weight:600;color:#c9b787;line-height:1.15;">a11oy</div>
|
| 464 |
+
</div>
|
| 465 |
+
</div>
|
| 466 |
+
<div style="margin-top:26px;width:168px;height:3px;border-radius:3px;background:rgba(201,183,135,.14);overflow:hidden;">
|
| 467 |
+
<div id="szl-bg-bar" style="height:100%;width:38%;border-radius:3px;background:linear-gradient(90deg,#5fb3a3,#c9b787);"></div>
|
| 468 |
+
</div>
|
| 469 |
+
<div id="szl-bg-msg" style="margin-top:16px;font-size:12px;letter-spacing:.08em;color:#9a9a9a;font-family:'JetBrains Mono',ui-monospace,monospace;">initializing…</div>
|
| 470 |
+
</div>
|
| 471 |
+
<style id="szl-bootguard-css">
|
| 472 |
+
@keyframes szlBgSlide{0%{transform:translateX(-120%)}100%{transform:translateX(360%)}}
|
| 473 |
+
#szl-bg-bar{animation:szlBgSlide 1.25s cubic-bezier(.4,0,.2,1) infinite;}
|
| 474 |
+
#szl-bootguard{transition:opacity .42s ease;}
|
| 475 |
+
#szl-bootguard.szl-bg-hide{opacity:0;pointer-events:none;}
|
| 476 |
+
@media (prefers-reduced-motion: reduce){
|
| 477 |
+
#szl-bg-bar{animation:none;width:100%;}
|
| 478 |
+
#szl-bootguard{transition:none;}
|
| 479 |
+
}
|
| 480 |
+
</style>
|
| 481 |
+
<script>
|
| 482 |
+
/* Boot-guard controller (inline, no deps — runs immediately, before the heavy
|
| 483 |
+
bundle). Clears the splash the moment the first real view paints into #content;
|
| 484 |
+
degrades to an honest message if boot stalls; hard-caps removal so the guard can
|
| 485 |
+
NEVER itself become a stuck overlay. Honesty doctrine: no fabricated state. */
|
| 486 |
+
(function(){
|
| 487 |
+
var g=document.getElementById('szl-bootguard'); if(!g) return;
|
| 488 |
+
var msg=document.getElementById('szl-bg-msg');
|
| 489 |
+
var done=false;
|
| 490 |
+
function clear(){
|
| 491 |
+
if(done) return; done=true;
|
| 492 |
+
try{ g.classList.add('szl-bg-hide'); }catch(e){}
|
| 493 |
+
setTimeout(function(){ try{ if(g&&g.parentNode) g.parentNode.removeChild(g); var s=document.getElementById('szl-bootguard-css'); if(s&&s.parentNode) s.parentNode.removeChild(s); }catch(e){} }, 480);
|
| 494 |
+
}
|
| 495 |
+
// Consider the app "booted" when #content holds real rendered markup (not the
|
| 496 |
+
// bare "loading…" seed). Watch for the first substantive paint.
|
| 497 |
+
function contentReady(){
|
| 498 |
+
var c=document.getElementById('content'); if(!c) return false;
|
| 499 |
+
var t=(c.textContent||'').trim();
|
| 500 |
+
// Seed states that are NOT "ready": the bare loading seed and an empty pane.
|
| 501 |
+
if(!t) return false;
|
| 502 |
+
if(c.children && c.children.length>0 && t!=='loading…' && t!=='loading\u2026') return true;
|
| 503 |
+
return false;
|
| 504 |
+
}
|
| 505 |
+
function tick(){ if(contentReady()) clear(); }
|
| 506 |
+
var mo;
|
| 507 |
+
try{
|
| 508 |
+
var c0=document.getElementById('content');
|
| 509 |
+
if(window.MutationObserver && c0){
|
| 510 |
+
mo=new MutationObserver(function(){ tick(); });
|
| 511 |
+
mo.observe(c0,{childList:true,subtree:true,characterData:true});
|
| 512 |
+
}
|
| 513 |
+
}catch(e){}
|
| 514 |
+
// Poll as a belt-and-suspenders backup (covers environments where the observer
|
| 515 |
+
// misses a synchronous innerHTML swap).
|
| 516 |
+
var poll=setInterval(function(){ tick(); if(done){ clearInterval(poll); try{mo&&mo.disconnect();}catch(e){} } }, 140);
|
| 517 |
+
// Honest stall message: if the shell is up but the first view hasn't painted in
|
| 518 |
+
// ~6s (slow cold boot / egress flap), tell the operator the truth — never a void.
|
| 519 |
+
setTimeout(function(){ if(!done && msg){ try{ msg.innerHTML='live meter reconnecting… <span style="color:#5fb3a3">shell ready</span>'; }catch(e){} } }, 6000);
|
| 520 |
+
// Hard cap: the branded chrome below is fully interactive on its own, so the
|
| 521 |
+
// splash MUST come down regardless — it can never be the thing that hangs.
|
| 522 |
+
setTimeout(clear, 9000);
|
| 523 |
+
// Also clear on full load as a floor.
|
| 524 |
+
if(document.readyState==='complete'){ setTimeout(tick,0); }
|
| 525 |
+
else { window.addEventListener('load', function(){ setTimeout(tick,300); }); }
|
| 526 |
+
})();
|
| 527 |
+
</script>
|
| 528 |
+
<!-- ============================ END SZL BOOT-GUARD ============================ -->
|
| 529 |
+
|
| 530 |
<div class="topbar">
|
| 531 |
<button class="menu-btn" aria-label="Toggle navigation" aria-expanded="false" onclick="toggleSide()">☰</button>
|
| 532 |
<span>SZL HOLDINGS</span><span class="sep">/</span>
|