Add page transition animations and background wallpapers

Wrap page views in {#key} blocks with a fade-in animation for smooth
transitions. Add Demon Slayer wallpapers as fixed pseudo-element
backgrounds on main (Tanjiro for dashboard, Rengoku for accelerator)
with CSS crossfade. Fix section spacing lost by the page-enter wrapper
div. Minor tooltip text fixes.
This commit is contained in:
satoshi
2026-05-11 09:11:50 +03:00
parent dc7da6ab19
commit 5e7be22e8e
8 changed files with 85 additions and 18 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

+61 -2
View File
@@ -20,7 +20,7 @@
}); });
</script> </script>
<main> <main class:no-bg={selection.page === "accelerator"}>
<Header /> <Header />
{#if snap.data} {#if snap.data}
@@ -28,7 +28,7 @@
{/if} {/if}
{#if !snap.data} {#if !snap.data}
<div class="card placeholder"> <div class="card placeholder page-enter">
<div class="stat-label">Status</div> <div class="stat-label">Status</div>
<div class="stat-value">Connecting to kamado-api…</div> <div class="stat-value">Connecting to kamado-api…</div>
{#if snap.error} {#if snap.error}
@@ -36,18 +36,34 @@
{/if} {/if}
</div> </div>
{:else if selection.page === "accelerator"} {:else if selection.page === "accelerator"}
{#key 'accelerator'}
<div class="page-enter">
<AcceleratorPage /> <AcceleratorPage />
</div>
{/key}
{:else if selection.worker} {:else if selection.worker}
{#key selection.worker}
<div class="page-enter">
<WorkerDetailPage /> <WorkerDetailPage />
</div>
{/key}
{:else if selection.user} {:else if selection.user}
{#key selection.user}
<div class="page-enter">
<UserDetailPage /> <UserDetailPage />
</div>
{/key}
{:else} {:else}
{#key 'dashboard'}
<div class="page-enter">
<PoolOverview /> <PoolOverview />
<SharesBar /> <SharesBar />
<HashrateChart /> <HashrateChart />
<BlocksTable /> <BlocksTable />
<BestShares /> <BestShares />
<MinersTable /> <MinersTable />
</div>
{/key}
{/if} {/if}
</main> </main>
@@ -55,6 +71,7 @@
<style> <style>
main { main {
position: relative;
max-width: 1280px; max-width: 1280px;
margin: 0 auto; margin: 0 auto;
padding: 1.5rem 1.25rem 4rem; padding: 1.5rem 1.25rem 4rem;
@@ -62,10 +79,52 @@
flex-direction: column; flex-direction: column;
gap: 1.25rem; gap: 1.25rem;
} }
main::before {
content: '';
position: fixed;
inset: 0;
z-index: -1;
background: url('/tanjiro2.jpg') center center / cover no-repeat;
opacity: 0.12;
pointer-events: none;
transition: opacity 0.4s ease;
}
main.no-bg::before {
opacity: 0;
}
main::after {
content: '';
position: fixed;
inset: 0;
z-index: -1;
background: url('/rengoku1.jpg') center center / cover no-repeat;
opacity: 0;
pointer-events: none;
transition: opacity 0.4s ease;
}
main.no-bg::after {
opacity: 0.30;
}
.placeholder { .placeholder {
text-align: center; text-align: center;
} }
.bad { .bad {
color: var(--bad); color: var(--bad);
} }
.page-enter {
display: flex;
flex-direction: column;
gap: 1.25rem;
animation: page-fade-in 0.3s ease-out;
}
@keyframes page-fade-in {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style> </style>
+8
View File
@@ -21,6 +21,7 @@
let boostedList = $state<BoostedTx[]>([]); let boostedList = $state<BoostedTx[]>([]);
let loadingMax = $state(false); let loadingMax = $state(false);
const feerate = $derived(parseFloat(feerateInput) || 0); const feerate = $derived(parseFloat(feerateInput) || 0);
const validTxid = $derived(/^[0-9a-fA-F]{64}$/.test(txid.trim())); const validTxid = $derived(/^[0-9a-fA-F]{64}$/.test(txid.trim()));
const overCap = $derived(feerate > 2000); const overCap = $derived(feerate > 2000);
@@ -310,8 +311,10 @@
</section> </section>
</section> </section>
<style> <style>
.page { .page {
position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1.5rem; gap: 1.5rem;
@@ -406,13 +409,18 @@
/* ── Boost form ── */ /* ── Boost form ── */
.boost-form { .boost-form {
position: relative;
overflow: hidden;
padding: 2rem; padding: 2rem;
} }
.boost-form h3 { .boost-form h3 {
position: relative;
z-index: 1;
margin: 0 0 1.5rem; margin: 0 0 1.5rem;
font-size: 1.3rem; font-size: 1.3rem;
font-weight: 700; font-weight: 700;
} }
.field { .field {
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
} }
+2 -2
View File
@@ -133,7 +133,7 @@
title="View per-worker stats" title="View per-worker stats"
>{r.workerName}</button> >{r.workerName}</button>
{#if r.tls} {#if r.tls}
<span class="badge tls" title="Connected via TLS"> <span class="badge tls" title="Encrypted connection via TLS">
<svg viewBox="0 0 16 16" aria-hidden="true"> <svg viewBox="0 0 16 16" aria-hidden="true">
<path d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7H4a1.5 1.5 0 0 0-1.5 1.5v5A1.5 1.5 0 0 0 4 15h8a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 12 7h-.5V4.5A3.5 3.5 0 0 0 8 1Zm2 6H6V4.5a2 2 0 1 1 4 0V7Z"/> <path d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7H4a1.5 1.5 0 0 0-1.5 1.5v5A1.5 1.5 0 0 0 4 15h8a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 12 7h-.5V4.5A3.5 3.5 0 0 0 8 1Zm2 6H6V4.5a2 2 0 1 1 4 0V7Z"/>
</svg> </svg>
@@ -154,7 +154,7 @@
<td> <td>
{r.hardware} {r.hardware}
{#if r.openSource} {#if r.openSource}
<span class="oss" title="Open source hardware or firmware"></span> <span class="oss" title="Open source hardware and firmware"></span>
{/if} {/if}
</td> </td>
<td class="num">{formatHashrate(r.hashrate1m)}</td> <td class="num">{formatHashrate(r.hashrate1m)}</td>
+1 -1
View File
@@ -83,7 +83,7 @@
position: relative; position: relative;
z-index: 1; z-index: 1;
display: flex; display: flex;
align-items: center; align-items: baseline;
justify-content: center; justify-content: center;
gap: 2rem; gap: 2rem;
} }
+2 -2
View File
@@ -232,7 +232,7 @@
title="View per-worker stats" title="View per-worker stats"
>{r.worker}</button> >{r.worker}</button>
{#if r.tls} {#if r.tls}
<span class="badge tls" title="Connected via TLS"> <span class="badge tls" title="Encrypted connection via TLS">
<svg viewBox="0 0 16 16" aria-hidden="true"> <svg viewBox="0 0 16 16" aria-hidden="true">
<path d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7H4a1.5 1.5 0 0 0-1.5 1.5v5A1.5 1.5 0 0 0 4 15h8a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 12 7h-.5V4.5A3.5 3.5 0 0 0 8 1Zm2 6H6V4.5a2 2 0 1 1 4 0V7Z"/> <path d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7H4a1.5 1.5 0 0 0-1.5 1.5v5A1.5 1.5 0 0 0 4 15h8a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 12 7h-.5V4.5A3.5 3.5 0 0 0 8 1Zm2 6H6V4.5a2 2 0 1 1 4 0V7Z"/>
</svg> </svg>
@@ -247,7 +247,7 @@
<td> <td>
{r.hardware} {r.hardware}
{#if r.openSource} {#if r.openSource}
<span class="oss" title="Open source hardware or firmware"></span> <span class="oss" title="Open source hardware and firmware"></span>
{/if} {/if}
</td> </td>
<td> <td>
+2 -2
View File
@@ -88,7 +88,7 @@
title="View per-user stats" title="View per-user stats"
>{btcAddress}</button> >{btcAddress}</button>
{#if tls} {#if tls}
<span class="badge tls" title="Connected via TLS"> <span class="badge tls" title="Encrypted connection via TLS">
<svg viewBox="0 0 16 16" aria-hidden="true"> <svg viewBox="0 0 16 16" aria-hidden="true">
<path d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7H4a1.5 1.5 0 0 0-1.5 1.5v5A1.5 1.5 0 0 0 4 15h8a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 12 7h-.5V4.5A3.5 3.5 0 0 0 8 1Zm2 6H6V4.5a2 2 0 1 1 4 0V7Z"/> <path d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7H4a1.5 1.5 0 0 0-1.5 1.5v5A1.5 1.5 0 0 0 4 15h8a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 12 7h-.5V4.5A3.5 3.5 0 0 0 8 1Zm2 6H6V4.5a2 2 0 1 1 4 0V7Z"/>
</svg> </svg>
@@ -96,7 +96,7 @@
</span> </span>
{/if} {/if}
{#if openSource} {#if openSource}
<span class="oss" title="Open source hardware or firmware">&#9733;</span> <span class="oss" title="Open source hardware and firmware">&#9733;</span>
{/if} {/if}
</div> </div>
</header> </header>