User page: hash-routed view, full block hash, aligned rewards
The per-user view was an overlay modal, but users asked for an actual page — focused, scrollable, addressable. Replace the modal with a hash-routed page: selectUser(addr) sets window.location.hash to #/user/<addr> and a hashchange listener syncs the selection state back, so browser back/forward and direct-link refresh all work without a routing library. App renders the dashboard or the UserDetailPage based on selection.user. Make the clickable BTC addresses in the Miners table obviously interactive: accent colour, always-on dashed underline, brighter on hover/focus. The previous styling rendered them as dim static text with a hover underline, so it wasn't obvious they were links. BlocksTable: show the full 64-char block hash as a link to mempool.space (auto-picks testnet4/signet based on snap.chain). word-break: break-all keeps the hash from blowing out the column width. Reward column is split into a tabular-num number span and a dim 0.75em "BTC" unit span, matching the Block reward tile in the overview, so numbers line up cleanly across rows.
This commit is contained in:
@@ -4,9 +4,17 @@
|
||||
|
||||
const blocks = $derived.by(() => {
|
||||
const b = snap.data?.recent_blocks ?? [];
|
||||
// Show newest first.
|
||||
return [...b].reverse();
|
||||
});
|
||||
|
||||
// mempool.space mirror picked per network. If chain isn't known, the
|
||||
// mainnet link still works as a best effort.
|
||||
const explorerBase = $derived.by(() => {
|
||||
const chain = snap.data?.chain?.chain ?? "main";
|
||||
if (chain === "test" || chain === "testnet4") return "https://mempool.space/testnet4";
|
||||
if (chain === "signet") return "https://mempool.space/signet";
|
||||
return "https://mempool.space";
|
||||
});
|
||||
</script>
|
||||
|
||||
<section class="card">
|
||||
@@ -14,28 +22,49 @@
|
||||
{#if blocks.length === 0}
|
||||
<div class="empty">No blocks found yet.</div>
|
||||
{:else}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Height</th>
|
||||
<th>Hash</th>
|
||||
<th class="num">Reward</th>
|
||||
<th class="num">Winning share</th>
|
||||
<th class="num">When</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each blocks as b (b.height + "-" + b.found_at)}
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="mono">{b.height}</td>
|
||||
<td class="hash mono">{b.hash ? b.hash.slice(0, 16) + "…" : "—"}</td>
|
||||
<td class="num">{b.reward_btc ? b.reward_btc.toFixed(4) + " BTC" : "—"}</td>
|
||||
<td class="num">{b.share_diff ? formatDifficulty(b.share_diff) : "—"}</td>
|
||||
<td class="num">{formatAgo(new Date(b.found_at).getTime() / 1000)}</td>
|
||||
<th>Height</th>
|
||||
<th>Hash</th>
|
||||
<th class="num">Reward</th>
|
||||
<th class="num">Winning share</th>
|
||||
<th class="num">When</th>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each blocks as b (b.height + "-" + b.found_at)}
|
||||
<tr>
|
||||
<td class="mono">{b.height}</td>
|
||||
<td class="hash-cell">
|
||||
{#if b.hash}
|
||||
<a
|
||||
class="hash mono"
|
||||
href="{explorerBase}/block/{b.hash}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="Open block on mempool.space"
|
||||
>{b.hash}</a>
|
||||
{:else}
|
||||
<span class="hash mono">—</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="num">
|
||||
{#if b.reward_btc}
|
||||
<span class="reward-num">{b.reward_btc.toFixed(4)}</span>
|
||||
<span class="unit">BTC</span>
|
||||
{:else}
|
||||
<span class="reward-num">—</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="num">{b.share_diff ? formatDifficulty(b.share_diff) : "—"}</td>
|
||||
<td class="num">{formatAgo(new Date(b.found_at).getTime() / 1000)}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
@@ -49,7 +78,36 @@
|
||||
color: var(--fg-dim);
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
.table-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
.hash-cell {
|
||||
/* Let the 64-char hash wrap inside the cell instead of stretching
|
||||
* the whole table. */
|
||||
max-width: 620px;
|
||||
word-break: break-all;
|
||||
}
|
||||
.hash {
|
||||
color: var(--fg-dim);
|
||||
font-size: 0.85em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
a.hash {
|
||||
color: var(--fg-dim);
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dashed transparent;
|
||||
}
|
||||
a.hash:hover {
|
||||
color: var(--accent);
|
||||
border-bottom-color: var(--accent);
|
||||
}
|
||||
.reward-num {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.unit {
|
||||
color: var(--fg-dim);
|
||||
font-size: 0.75em;
|
||||
font-weight: 400;
|
||||
margin-left: 0.25em;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user