81 lines
4.2 KiB
HTML
81 lines
4.2 KiB
HTML
|
|
<!doctype html>
|
||
|
|
<html lang="en"><head>
|
||
|
|
<meta charset="utf-8" /><title>Deviant · chipnet dashboard</title>
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
|
|
<style>
|
||
|
|
:root { color-scheme: dark; --bg:#0c0e12; --fg:#dfe7ee; --muted:#7d8a98; --acid:#a5f050; --row:#161a22; --row2:#1c2230; --bord:#2a3346; }
|
||
|
|
body { margin:0; padding:24px; background:var(--bg); color:var(--fg); font:14px/1.4 ui-sans-serif,system-ui,sans-serif; }
|
||
|
|
h1 { font-size:18px; font-weight:600; margin:0 0 4px; }
|
||
|
|
.sub { color:var(--muted); font-size:12px; margin-bottom:18px; }
|
||
|
|
.sub .acid { color:var(--acid); }
|
||
|
|
table { border-collapse:collapse; width:100%; max-width:980px; background:var(--row); border:1px solid var(--bord); }
|
||
|
|
th, td { padding:9px 12px; border-bottom:1px solid var(--bord); text-align:left; }
|
||
|
|
tr:last-child td { border-bottom:none; }
|
||
|
|
tr:nth-child(even) td { background:var(--row2); }
|
||
|
|
th { font-weight:600; color:var(--muted); font-size:11px; text-transform:uppercase; letter-spacing:.06em; }
|
||
|
|
td.num { font-variant-numeric:tabular-nums; text-align:right; font-family:ui-monospace,monospace; }
|
||
|
|
td.addr { font-family:ui-monospace,monospace; font-size:12px; color:#bcc4cf; }
|
||
|
|
.lbl { display:inline-block; padding:2px 8px; border-radius:11px; background:rgba(165,240,80,.12); border:1px solid rgba(165,240,80,.35); color:var(--acid); font-weight:600; font-size:11px; }
|
||
|
|
.err { color:#ff8079; font-style:italic; }
|
||
|
|
.total { background:#10141a !important; font-weight:600; }
|
||
|
|
.footer { color:var(--muted); font-size:11px; margin-top:14px; }
|
||
|
|
</style></head>
|
||
|
|
<body>
|
||
|
|
<h1>Deviant · chipnet wallet dashboard</h1>
|
||
|
|
<div class="sub">Auto-refreshing every <span class="acid">__INTERVAL__s</span> · last update <span id="ts">—</span></div>
|
||
|
|
<table>
|
||
|
|
<thead><tr>
|
||
|
|
<th>Wallet</th><th>Address</th>
|
||
|
|
<th style="text-align:right">Plain BCH (sats)</th>
|
||
|
|
<th style="text-align:right">Plain BCH</th>
|
||
|
|
<th style="text-align:right">BCH UTXOs</th>
|
||
|
|
<th style="text-align:right">Tok UTXOs</th>
|
||
|
|
<th style="text-align:right">Locked (sats)</th>
|
||
|
|
<th style="text-align:right">Cats</th>
|
||
|
|
</tr></thead>
|
||
|
|
<tbody id="rows"><tr><td colspan="8" style="color:#7d8a98;text-align:center">Loading…</td></tr></tbody>
|
||
|
|
</table>
|
||
|
|
<div class="footer">Served by <code>scripts/dashboard-serve.mjs</code>. Template: <code>scripts/dashboard.html</code>. Source of truth: chipnet electrum (<code>ElectrumNetworkProvider</code>).</div>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
const fmtBch = (sats) => (Number(sats) / 1e8).toFixed(8);
|
||
|
|
const shortAddr = (a) => a ? a.slice(0, 14) + '…' + a.slice(-8) : '';
|
||
|
|
async function tick() {
|
||
|
|
try {
|
||
|
|
const r = await fetch('/api/balances', { cache: 'no-store' });
|
||
|
|
const { ts, rows } = await r.json();
|
||
|
|
document.getElementById('ts').textContent = new Date(ts).toLocaleString();
|
||
|
|
let totalBch = 0n, totalLocked = 0n;
|
||
|
|
let html = '';
|
||
|
|
for (const row of rows) {
|
||
|
|
if (row.error) {
|
||
|
|
html += '<tr><td><span class="lbl">' + row.label + '</span></td><td colspan="7" class="err">' + row.error + '</td></tr>';
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
totalBch += BigInt(row.bchSats);
|
||
|
|
totalLocked += BigInt(row.lockedSats);
|
||
|
|
html += '<tr>'
|
||
|
|
+ '<td><span class="lbl">' + row.label + '</span></td>'
|
||
|
|
+ '<td class="addr" title="' + row.cashaddr + '">' + shortAddr(row.cashaddr) + '</td>'
|
||
|
|
+ '<td class="num">' + Number(row.bchSats).toLocaleString() + '</td>'
|
||
|
|
+ '<td class="num">' + fmtBch(row.bchSats) + '</td>'
|
||
|
|
+ '<td class="num">' + row.bchUtxos + '</td>'
|
||
|
|
+ '<td class="num">' + row.tokUtxos + '</td>'
|
||
|
|
+ '<td class="num">' + Number(row.lockedSats).toLocaleString() + '</td>'
|
||
|
|
+ '<td class="num">' + row.cats + '</td>'
|
||
|
|
+ '</tr>';
|
||
|
|
}
|
||
|
|
html += '<tr class="total"><td colspan="2">Σ all wallets</td>'
|
||
|
|
+ '<td class="num">' + Number(totalBch).toLocaleString() + '</td>'
|
||
|
|
+ '<td class="num">' + fmtBch(totalBch) + '</td>'
|
||
|
|
+ '<td class="num">—</td><td class="num">—</td>'
|
||
|
|
+ '<td class="num">' + Number(totalLocked).toLocaleString() + '</td>'
|
||
|
|
+ '<td class="num">—</td></tr>';
|
||
|
|
document.getElementById('rows').innerHTML = html;
|
||
|
|
} catch (e) { console.error(e); }
|
||
|
|
}
|
||
|
|
tick();
|
||
|
|
setInterval(tick, __INTERVAL__ * 1000);
|
||
|
|
</script>
|
||
|
|
</body></html>
|