ui: a miner and an account are pages, not dialogs
Some checks failed
deploy / build (push) Waiting to run
deploy / deploy-api (push) Has been cancelled
deploy / deploy-web (push) Has been cancelled

Both were panels that opened above the standings, which is right for a block —
"who won this one, and where do they sit" is read against the board, and the
ticker row below is what you clicked to get here — and wrong for the other two.
A miner's page and an account's page are somebody's own record and the whole
subject of the URL that reached them; eleven other miners' rows underneath is
the site failing to notice which page it is on.

The close buttons go with it. Neither panel opened over something the reader
was looking at, so there is nothing to close back to, and the back button and
the chain chip already do what it would. "Mark as yours" stays: that is a real
control and not navigation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jp6a8EDar9ueEhAxzep4V5
This commit is contained in:
2026-09-09 17:21:06 +03:00
parent d6f4c0c21e
commit e330d2b78a
3 changed files with 48 additions and 71 deletions

View File

@@ -156,44 +156,46 @@ export default function App() {
// balance on this page wrong and look entirely plausible doing it.
decimals={info?.token_decimals ?? 12}
symbol={info?.token_symbol ?? ''}
onClose={closePanel}
/>
)}
{route.miner && chain && (
<MinerPanel
chain={chain}
miner={route.miner}
windowName={route.window}
onClose={closePanel}
/>
<MinerPanel chain={chain} miner={route.miner} windowName={route.window} />
)}
<div className="two-col">
<section className="panel">
<div className="panel-head">
<h2 className="panel-title">The Standings</h2>
<span className="eyebrow">
last {activeWindow.blocks.toLocaleString('en-US')} blocks ·{' '}
{windowSpan(activeWindow.blocks, interval)}
{pinned.length > 0 && ` · ${pinned.length} marked yours`}
</span>
</div>
<Leaderboard rows={state.leaderboard} chain={chain} ready={state.ready} />
</section>
{/* A miner and an account are pages, not things opened over the board.
Each is somebody's own record and the whole subject of the URL that
reached it; leaving eleven other miners' rows underneath is the site
failing to notice which page it is on. A block keeps the board,
because a block is read *against* it — who won this one, and where do
they sit — and the ticker below is the row you clicked to get here. */}
{!route.account && !route.miner && (
<div className="two-col">
<section className="panel">
<div className="panel-head">
<h2 className="panel-title">The Standings</h2>
<span className="eyebrow">
last {activeWindow.blocks.toLocaleString('en-US')} blocks ·{' '}
{windowSpan(activeWindow.blocks, interval)}
{pinned.length > 0 && ` · ${pinned.length} marked yours`}
</span>
</div>
<Leaderboard rows={state.leaderboard} chain={chain} ready={state.ready} />
</section>
<section className="panel">
<div className="panel-head">
<h2 className="panel-title">Live Blocks</h2>
<span className="eyebrow">
{state.summary?.block_interval_seconds
? `${seconds(state.summary.block_interval_seconds)} apart`
: 'measuring'}
</span>
</div>
<BlockTicker blocks={state.blocks} chain={chain} />
</section>
</div>
<section className="panel">
<div className="panel-head">
<h2 className="panel-title">Live Blocks</h2>
<span className="eyebrow">
{state.summary?.block_interval_seconds
? `${seconds(state.summary.block_interval_seconds)} apart`
: 'measuring'}
</span>
</div>
<BlockTicker blocks={state.blocks} chain={chain} />
</section>
</div>
)}
<footer className="footer">
<span>

View File

@@ -148,14 +148,12 @@ export function AccountPanel({
address,
decimals,
symbol,
onClose,
}: {
chain: string
address: string
/** The chain's token decimals; 12 on Quantus, but read rather than assumed. */
decimals: number
symbol: string
onClose: () => void
}) {
const [detail, setDetail] = useState<AccountDetail | null>(null)
const [error, setError] = useState<string | null>(null)
@@ -205,9 +203,10 @@ export function AccountPanel({
)}
</dl>
</div>
<button className="segmented panel-button" onClick={onClose}>
Close
</button>
{/* No close button. This is a URL somebody navigated to, not a dialog
that opened over something they were reading — there is nothing
underneath to get back to, and the back button and the chain chip
both already do what a close button would. */}
</div>
{error && <p className="empty">{error}</p>}

View File

@@ -22,12 +22,10 @@ export function MinerPanel({
chain,
miner,
windowName,
onClose,
}: {
chain: string
miner: string
windowName: WindowName
onClose: () => void
}) {
const [detail, setDetail] = useState<MinerDetail | null>(null)
const [error, setError] = useState<string | null>(null)
@@ -90,39 +88,17 @@ export function MinerPanel({
<dd className="numeral">{miner}</dd>
</dl>
</div>
<div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
<button
className="segmented"
style={{
padding: '7px 13px',
font: 'inherit',
fontSize: 12,
letterSpacing: '0.1em',
textTransform: 'uppercase',
color: mine ? 'var(--accent-bright)' : 'var(--text-secondary)',
cursor: 'pointer',
}}
aria-pressed={mine}
onClick={() => toggle(miner)}
>
{mine ? '★ Yours' : '☆ Mark as yours'}
</button>
<button
className="segmented"
style={{
padding: '7px 13px',
font: 'inherit',
fontSize: 12,
letterSpacing: '0.1em',
textTransform: 'uppercase',
color: 'var(--text-secondary)',
cursor: 'pointer',
}}
onClick={onClose}
>
Close
</button>
</div>
{/* No close button: this is a URL somebody navigated to, not a dialog
that opened over something they were reading. The back button and
the chain chip both already do what it would. */}
<button
className="segmented panel-button"
style={{ color: mine ? 'var(--accent-bright)' : 'var(--text-secondary)' }}
aria-pressed={mine}
onClick={() => toggle(miner)}
>
{mine ? '★ Yours' : '☆ Mark as yours'}
</button>
</div>
{error && <p className="empty">{error}</p>}