220 lines
9.3 KiB
Plaintext
220 lines
9.3 KiB
Plaintext
@namespace MidrandBooks.Components.Layout
|
|
@inject IJSRuntime JSRuntime
|
|
|
|
<dialog id="components-reconnect-modal" data-nosnippet class="fixed inset-0 w-screen h-screen m-0 p-0 border-0 bg-transparent z-[99999] overflow-hidden flex items-center justify-center opacity-0 pointer-events-none transition-opacity duration-300">
|
|
<!-- Dark Frosted Jacket Layer -->
|
|
<div class="absolute inset-0 bg-slate-950/60 backdrop-blur-md cursor-wait z-[1] animate-in fade-in duration-300"></div>
|
|
|
|
<!-- Centered Content Wrapper -->
|
|
<div class="reconnect-content relative z-[2] flex flex-col items-center gap-6 text-center text-slate-100 max-w-sm px-6">
|
|
|
|
<!-- Waveform Animation -->
|
|
<svg class="waveform-svg text-violet-400" viewBox="0 0 54 50" width="60" height="60" xmlns="http://www.w3.org/2000/svg">
|
|
<rect class="bar bar-1" x="2" y="15" width="4" height="20" rx="2" fill="currentColor" />
|
|
<rect class="bar bar-2" x="14" y="5" width="4" height="40" rx="2" fill="currentColor" />
|
|
<rect class="bar bar-3" x="26" y="20" width="4" height="10" rx="2" fill="currentColor" />
|
|
<rect class="bar bar-4" x="38" y="10" width="4" height="30" rx="2" fill="currentColor" />
|
|
<rect class="bar bar-5" x="50" y="18" width="4" height="14" rx="2" fill="currentColor" />
|
|
</svg>
|
|
|
|
<!-- Message Body -->
|
|
<div class="sync-message-body font-mono uppercase text-xs tracking-widest text-slate-300 space-y-2">
|
|
<span class="components-reconnect-first-attempt-visible hidden">
|
|
Losing signal...
|
|
</span>
|
|
|
|
<span class="components-reconnect-repeated-attempt-visible hidden">
|
|
reconnecting in <span id="components-seconds-to-next-attempt" class="font-bold text-violet-400">0</span>s...
|
|
</span>
|
|
|
|
<span class="components-reconnect-failed-visible text-rose-400 font-semibold hidden">
|
|
Playback disconnected.
|
|
</span>
|
|
|
|
<span class="components-pause-visible hidden">
|
|
Reading layout paused.
|
|
</span>
|
|
|
|
<span class="components-resume-failed-visible text-rose-400 font-semibold hidden">
|
|
State alignment broken.
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Glass Action Buttons -->
|
|
<div class="sync-action-node flex items-center justify-center gap-3">
|
|
<button id="components-reconnect-button" class="btn-glass-action hidden px-4 py-2.5 bg-white/5 border border-white/10 hover:bg-white/10 text-white font-mono uppercase text-[10px] tracking-widest rounded-xl transition-all items-center gap-2 cursor-pointer shadow-lg hover:scale-102 hover:border-violet-500/30">
|
|
<span>Retry Sync</span>
|
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67" />
|
|
</svg>
|
|
</button>
|
|
<button id="components-resume-button" class="btn-glass-action hidden px-4 py-2.5 bg-white/5 border border-white/10 hover:bg-white/10 text-white font-mono uppercase text-[10px] tracking-widest rounded-xl transition-all items-center gap-2 cursor-pointer shadow-lg hover:scale-102 hover:border-violet-500/30">
|
|
<span>Reload Session</span>
|
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="23 4 23 10 17 10"></polyline>
|
|
<polyline points="1 20 1 14 7 14"></polyline>
|
|
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
</dialog>
|
|
|
|
<style>
|
|
/* --- Show the modal smoothly when Blazor attaches state classes --- */
|
|
#components-reconnect-modal.components-reconnect-show,
|
|
#components-reconnect-modal.components-reconnect-failed,
|
|
#components-reconnect-modal.components-reconnect-rejected {
|
|
opacity: 1 !important;
|
|
pointer-events: all !important;
|
|
}
|
|
|
|
#components-reconnect-modal.components-reconnect-hide {
|
|
display: none !important;
|
|
}
|
|
|
|
/* --- SVG Waveform Animation --- */
|
|
#components-reconnect-modal .bar {
|
|
transform-origin: center;
|
|
animation: reconnectWavePulse 1.2s ease-in-out infinite alternate;
|
|
}
|
|
|
|
#components-reconnect-modal .bar-1 {
|
|
animation-delay: 0.0s;
|
|
}
|
|
|
|
#components-reconnect-modal .bar-2 {
|
|
animation-delay: 0.3s;
|
|
}
|
|
|
|
#components-reconnect-modal .bar-3 {
|
|
animation-delay: 0.6s;
|
|
}
|
|
|
|
#components-reconnect-modal .bar-4 {
|
|
animation-delay: 0.2s;
|
|
}
|
|
|
|
#components-reconnect-modal .bar-5 {
|
|
animation-delay: 0.5s;
|
|
}
|
|
|
|
@@keyframes reconnectWavePulse {
|
|
0% {
|
|
transform: scaleY(0.3);
|
|
opacity: 0.5;
|
|
}
|
|
|
|
100% {
|
|
transform: scaleY(1);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
/* Stop the waveform if the connection completely fails */
|
|
#components-reconnect-modal.components-reconnect-failed .bar,
|
|
#components-reconnect-modal.components-reconnect-rejected .bar,
|
|
#components-reconnect-modal.components-reconnect-paused .bar {
|
|
animation: none !important;
|
|
transform: scaleY(0.1) !important;
|
|
opacity: 0.3 !important;
|
|
}
|
|
|
|
/* --- Display Mechanics Matrix Controllers --- */
|
|
#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible,
|
|
#components-reconnect-modal.components-reconnect-paused .components-pause-visible,
|
|
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible,
|
|
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible,
|
|
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible {
|
|
display: inline-block !important;
|
|
}
|
|
|
|
#components-reconnect-modal.components-reconnect-failed .btn-glass-action,
|
|
#components-reconnect-modal.components-reconnect-paused .btn-glass-action,
|
|
#components-reconnect-modal.components-reconnect-resume-failed .btn-glass-action {
|
|
display: inline-flex !important;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
(function() {
|
|
function initReconnectModal() {
|
|
const reconnectModal = document.getElementById("components-reconnect-modal");
|
|
if (!reconnectModal) {
|
|
setTimeout(initReconnectModal, 100);
|
|
return;
|
|
}
|
|
|
|
reconnectModal.addEventListener("components-reconnect-state-changed", handleReconnectStateChanged);
|
|
|
|
const retryButton = document.getElementById("components-reconnect-button");
|
|
if (retryButton) {
|
|
retryButton.addEventListener("click", retry);
|
|
}
|
|
|
|
const resumeButton = document.getElementById("components-resume-button");
|
|
if (resumeButton) {
|
|
resumeButton.addEventListener("click", resume);
|
|
}
|
|
|
|
function handleReconnectStateChanged(event) {
|
|
if (event.detail.state === "show") {
|
|
reconnectModal.showModal();
|
|
} else if (event.detail.state === "hide") {
|
|
reconnectModal.close();
|
|
} else if (event.detail.state === "failed") {
|
|
document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible);
|
|
} else if (event.detail.state === "rejected") {
|
|
location.reload();
|
|
}
|
|
}
|
|
|
|
async function retry() {
|
|
document.removeEventListener("visibilitychange", retryWhenDocumentBecomesVisible);
|
|
|
|
try {
|
|
if (window.Blazor) {
|
|
const successful = await window.Blazor.reconnect();
|
|
if (!successful) {
|
|
const resumeSuccessful = await window.Blazor.resumeCircuit();
|
|
if (!resumeSuccessful) {
|
|
location.reload();
|
|
} else {
|
|
reconnectModal.close();
|
|
}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible);
|
|
}
|
|
}
|
|
|
|
async function resume() {
|
|
try {
|
|
if (window.Blazor) {
|
|
const successful = await window.Blazor.resumeCircuit();
|
|
if (!successful) {
|
|
location.reload();
|
|
}
|
|
}
|
|
} catch {
|
|
reconnectModal.classList.replace("components-reconnect-paused", "components-reconnect-resume-failed");
|
|
}
|
|
}
|
|
|
|
async function retryWhenDocumentBecomesVisible() {
|
|
if (document.visibilityState === "visible") {
|
|
await retry();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", initReconnectModal);
|
|
} else {
|
|
initReconnectModal();
|
|
}
|
|
})();
|
|
</script>
|