ui: the window belongs to the miner page, not just the standings
Choosing a window on a miner's page navigated back to the standings. Not a mis-wired link: there was no URL for "this miner, over a day", so the only thing the control could do was go somewhere that had one. So the miner route carries it: `/quantus/miner/0x…/day`. That is the right place for it regardless — a miner's rank and hashrate are *of* a window, and a link sent without one shows the recipient something other than what the sender was looking at. In the path rather than a query string, so it reads the way the standings' own window already does. The bare `/quantus/miner/0x…` still resolves, at the default window, so existing links keep working. And the control now appears only where it changes something: the standings, and a miner's page, which is one row of those same standings. A block happened once, a balance has no span, a runtime is not a rate, and the three indexes are not ranked — on all of those it was a live control that did nothing, which teaches a reader to distrust it on the two pages where it works. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jp6a8EDar9ueEhAxzep4V5
This commit is contained in:
@@ -305,6 +305,15 @@ Route segments are named — `/quantus/block/13160` rather than
|
||||
two kinds of thing can look alike, and an SS58 address is arbitrary base58 with
|
||||
no rule keeping it clear of a window name forever.
|
||||
|
||||
A miner's page carries the window too: `/quantus/miner/0x…/day`. Its rank and
|
||||
hashrate are *of* a window, so a link without one means something different from
|
||||
what the sender was looking at — and until it was in the path, changing the
|
||||
window on a miner's page could only navigate back to the standings, because
|
||||
there was no URL for "this miner, over a day". The window control appears on
|
||||
exactly the two pages where it changes something, the standings and a miner;
|
||||
a block happened once and a balance has no span, and a control that does nothing
|
||||
where it sits teaches a reader to distrust it everywhere else.
|
||||
|
||||
Everything navigable is an `<a>`, including the chain chips and the window
|
||||
control. That is what "real URLs" has to mean in practice: middle-click opens
|
||||
the 24-hour view of another chain in a tab, right-click copies a link to a
|
||||
|
||||
@@ -53,6 +53,11 @@ export default function App() {
|
||||
}
|
||||
}, [route.chain, route.window, fallbackChain, navigate])
|
||||
|
||||
// The standings and a miner's page, which is one row of them. Everything
|
||||
// else is about a thing that happened once.
|
||||
const windowApplies =
|
||||
route.index === null && route.block === null && route.account === null && route.runtime === null
|
||||
|
||||
// Normalise a path that resolves to the standings but is not spelled like
|
||||
// them: `/quantus`, `/quantus/miner` (the standings *are* the miner index),
|
||||
// and anything unrecognised, which `parse` degrades to the front page rather
|
||||
@@ -109,21 +114,29 @@ export default function App() {
|
||||
</div>
|
||||
|
||||
<div className="masthead-right">
|
||||
{/* Links, not buttons: a window is part of the address, so "the
|
||||
last 24 hours on Quantus" is a thing to send someone rather than
|
||||
a control state that a shared link would drop. */}
|
||||
<nav className="segmented" aria-label="Leaderboard window">
|
||||
{WINDOWS.map((w) => (
|
||||
<Link
|
||||
key={w.id}
|
||||
to={href({ chain, window: w.id })}
|
||||
aria-current={w.id === route.window ? 'page' : undefined}
|
||||
title={`${w.blocks.toLocaleString('en-US')} blocks — ${windowSpan(w.blocks, interval)}`}
|
||||
>
|
||||
{w.label}
|
||||
</Link>
|
||||
))}
|
||||
</nav>
|
||||
{/* Only where a window means something. It sets the span the ranks
|
||||
are computed over, so it belongs on the standings and on a
|
||||
miner's page — which is one row of those same standings. A block,
|
||||
an account, a runtime and the three indexes have no window: a
|
||||
block happened once, a balance has no span, and a control that
|
||||
does nothing where it sits teaches a reader to distrust it. */}
|
||||
{windowApplies && (
|
||||
<nav className="segmented" aria-label="Leaderboard window">
|
||||
{WINDOWS.map((w) => (
|
||||
<Link
|
||||
key={w.id}
|
||||
// Carried onto whatever page this is, not back to the
|
||||
// standings: changing the span of a miner's rank is not a
|
||||
// reason to stop looking at that miner.
|
||||
to={href({ ...route, chain, window: w.id })}
|
||||
aria-current={w.id === route.window ? 'page' : undefined}
|
||||
title={`${w.blocks.toLocaleString('en-US')} blocks — ${windowSpan(w.blocks, interval)}`}
|
||||
>
|
||||
{w.label}
|
||||
</Link>
|
||||
))}
|
||||
</nav>
|
||||
)}
|
||||
|
||||
<div className={`status status-${state.connection}`}>
|
||||
<span className="status-dot" />
|
||||
|
||||
@@ -117,7 +117,7 @@ export function parse(pathname: string): Route {
|
||||
// same account on every Quantus chain, so the only thing it lacks is which
|
||||
// chain's figures to show, and the default is the right guess.
|
||||
if (parts[0] === 'miner' && parts[1]) {
|
||||
return { ...EMPTY, miner: parts[1].toLowerCase() }
|
||||
return { ...EMPTY, miner: parts[1].toLowerCase(), window: asWindow(parts[2]) ?? DEFAULT_WINDOW }
|
||||
}
|
||||
// Likewise a bare runtime: a spec_version is only meaningful against a chain,
|
||||
// and the default chain is the one a link without one means.
|
||||
@@ -132,7 +132,18 @@ export function parse(pathname: string): Route {
|
||||
const value = parts[2]
|
||||
if (kind && value) {
|
||||
if (kind === 'block') return { ...EMPTY, chain, block: value.toLowerCase() }
|
||||
if (kind === 'miner') return { ...EMPTY, chain, miner: value.toLowerCase() }
|
||||
// A miner carries a window, because its rank and hashrate are *of* a
|
||||
// window and a link to one without it means something different from what
|
||||
// the sender was looking at. In the path rather than a query string, so it
|
||||
// reads the same way the standings' own window does.
|
||||
if (kind === 'miner') {
|
||||
return {
|
||||
...EMPTY,
|
||||
chain,
|
||||
miner: value.toLowerCase(),
|
||||
window: asWindow(parts[3]) ?? DEFAULT_WINDOW,
|
||||
}
|
||||
}
|
||||
if (kind === 'account') return { ...EMPTY, chain, account: value }
|
||||
if (kind === 'runtime') return { ...EMPTY, chain, runtime: spec(value) }
|
||||
}
|
||||
@@ -155,7 +166,10 @@ export function parse(pathname: string): Route {
|
||||
export function href(route: Partial<Route>): string {
|
||||
const chain = route.chain ?? ''
|
||||
if (route.block) return `/${chain}/block/${route.block}`
|
||||
if (route.miner) return chain ? `/${chain}/miner/${route.miner}` : `/miner/${route.miner}`
|
||||
if (route.miner) {
|
||||
const window = route.window ?? DEFAULT_WINDOW
|
||||
return chain ? `/${chain}/miner/${route.miner}/${window}` : `/miner/${route.miner}/${window}`
|
||||
}
|
||||
if (route.index) return `/${chain}/${route.index}`
|
||||
if (route.account) return `/${chain}/account/${route.account}`
|
||||
if (route.runtime !== null && route.runtime !== undefined) {
|
||||
|
||||
Reference in New Issue
Block a user