ui: the block route is a page too
Same reasoning as the miner and account routes one commit ago, which the block route was deliberately left out of: a block is read against the standings, and the ticker row below is what you clicked to get here. On reflection that is an argument about how someone arrived, not about what the URL names — and the URL names one block. The board is what `/:chain/:window` is for. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jp6a8EDar9ueEhAxzep4V5
This commit is contained in:
@@ -16,6 +16,7 @@ import { BlockTicker } from './components/BlockTicker'
|
||||
import { ChainSwitcher } from './components/ChainSwitcher'
|
||||
import { Leaderboard } from './components/Leaderboard'
|
||||
import { MinerPanel } from './components/MinerPanel'
|
||||
import { RuntimePanel } from './components/RuntimePanel'
|
||||
import { StatBar } from './components/StatBar'
|
||||
import { seconds, windowSpan } from './lib/format'
|
||||
import { href, parse, WINDOWS } from './lib/routes'
|
||||
@@ -67,12 +68,6 @@ export default function App() {
|
||||
[chain, navigate],
|
||||
)
|
||||
|
||||
/** Back to the standings, keeping the window the panel was opened from. */
|
||||
const closePanel = useCallback(
|
||||
() => navigate(href({ chain, window: route.window })),
|
||||
[chain, route.window, navigate],
|
||||
)
|
||||
|
||||
const interval =
|
||||
state.summary?.block_interval_seconds ?? state.summary?.target_block_time_seconds ?? 6
|
||||
const activeWindow = WINDOWS.find((w) => w.id === route.window) ?? WINDOWS[1]!
|
||||
@@ -143,7 +138,6 @@ export default function App() {
|
||||
block={route.block}
|
||||
targetSeconds={info?.target_block_time_seconds ?? 6}
|
||||
onResolved={blockResolved}
|
||||
onClose={closePanel}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -163,13 +157,14 @@ export default function App() {
|
||||
<MinerPanel chain={chain} miner={route.miner} windowName={route.window} />
|
||||
)}
|
||||
|
||||
{/* 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 && (
|
||||
{/* Every one of these is a page, not something opened over the board. A
|
||||
URL that names one thing has that thing as its whole subject, and
|
||||
leaving eleven unrelated mining rows underneath is the site failing to
|
||||
notice which page it is on. The board is what `/:chain/:window` is
|
||||
for. */}
|
||||
{route.runtime !== null && chain && <RuntimePanel chain={chain} spec={route.runtime} />}
|
||||
|
||||
{!route.account && !route.miner && !route.block && route.runtime === null && (
|
||||
<div className="two-col">
|
||||
<section className="panel">
|
||||
<div className="panel-head">
|
||||
@@ -215,6 +210,22 @@ export default function App() {
|
||||
is the only identity the chain itself asserts. An <code>elsewhere</code> tag means the
|
||||
name was earned by the same reward preimage on another chain, not observed on this one.
|
||||
</span>
|
||||
{state.summary?.spec_version !== null && state.summary?.spec_version !== undefined && (
|
||||
<span>
|
||||
{/* "Decoded how?" has an answer, and it is a page. Every event and
|
||||
reward on this site was read against this runtime's own type
|
||||
registry rather than against anything written here, so the
|
||||
runtime is a load-bearing part of the explanation and not a
|
||||
footnote. */}
|
||||
Rewards and transfers are decoded against the chain's own metadata — the type registry
|
||||
the node produces by running the runtime WASM in each block's state, not a schema
|
||||
written here. This chain is on{' '}
|
||||
<Link to={href({ chain, runtime: state.summary.spec_version })}>
|
||||
{state.summary.spec_name ?? 'runtime'} v{state.summary.spec_version}
|
||||
</Link>
|
||||
.
|
||||
</span>
|
||||
)}
|
||||
<span className="colophon">
|
||||
{/* Its own line rather than a fourth item in the `space-between`
|
||||
flow: the three above are caveats about the numbers, this is
|
||||
|
||||
@@ -56,7 +56,6 @@ export function BlockPanel({
|
||||
block,
|
||||
targetSeconds,
|
||||
onResolved,
|
||||
onClose,
|
||||
}: {
|
||||
chain: string
|
||||
/** Height or hash, as it appeared in the URL. */
|
||||
@@ -65,7 +64,6 @@ export function BlockPanel({
|
||||
targetSeconds: number
|
||||
/** Called with the canonical hash once a height has resolved to one. */
|
||||
onResolved: (hash: string) => void
|
||||
onClose: () => void
|
||||
}) {
|
||||
const [detail, setDetail] = useState<BlockDetail | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
@@ -122,21 +120,9 @@ export function BlockPanel({
|
||||
{detail?.hash ?? ''}
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
{/* 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. */}
|
||||
</div>
|
||||
|
||||
{error && <p className="empty">{error}</p>}
|
||||
|
||||
Reference in New Issue
Block a user