Skip to content

feat: adapt block page layout for mobile and tablet - #1248

Open
C0mberry wants to merge 2 commits into
solana-foundation:masterfrom
hoodieshq:feat/hoo-801-block-page-mobile-layout
Open

feat: adapt block page layout for mobile and tablet#1248
C0mberry wants to merge 2 commits into
solana-foundation:masterfrom
hoodieshq:feat/hoo-801-block-page-mobile-layout

Conversation

@C0mberry

@C0mberry C0mberry commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Description

Adapts the block detail page (/block/[slot]) and all its tabs for mobile and tablet. Card headings move outside their cards with collapse/expand behaviour, the data tables become responsive CSS grids that stack into labelled rows on narrow screens, and spacing/padding are reworked so content uses the full width available.

  • All block tabs (Overview, Transactions, Accounts, Programs, Rewards) — matched to the transaction page: heading lifted above a collapsible section, tight card surface, grid body from md up and a stacked, labelled layout below. All block tables now share the transaction/overview cards' 8px corner radius.
  • Page heading — the "Details / Block" title now matches the transaction page's spacing: airy padding with equal 24px gaps above and below, sitting outside the section rhythm so those gaps stay fixed.
  • Page tabs — on mobile the sticky full-bleed tab bar sits ~12px under the Overview card, with a balanced 28px band above the labels and 36px below the underline; desktop spacing is unchanged. The tab underline now runs edge-to-edge into the page margins on mobile and tablet and is clipped to the content column on desktop, matching the address/token page tabs.
  • Transactions card — CU columns renamed to CUs Reserved / CUs Consumed / Cost and widened to keep headers on one line; header reads "Signature / Programs"; index column fits 4 digits; on mobile the signature is labelled, invoked programs get a "Programs" field and the index sits top-right. Sortable headers show a direction indicator — dim chevrons when clickable, the active column turning white with a bright arrow, re-click reverses (kept in the URL); the "#" header resets to index order. On mobile, where those headers are hidden, a Sort button beside the filter opens the same columns split into "Lowest …" / "Highest …" (ascending / descending). The record count moves into the heading as "N filtered records" / "N records".
  • Transactions filter — reworked into a "Filters" button (icon, plus a dot badge when a filter is active) opening a fixed-width menu with a program search; long option names wrap instead of widening it. The active program filter shows under the heading as a removable chip that clears back to all transactions.
  • Programs card — count and its share of the block shown together on one line as "count (percent)" with the percentage muted; column headers gained info-icon tooltips citing the block's transaction/instruction totals.
  • Accounts card — Total and its share merged into one "count (percent)" column (matching Programs) with an info tooltip; long account addresses now clip and mid-truncate inside the cell instead of forcing horizontal scroll.
  • Rewards card — "New Balance" renamed "Post Balance" with a wider column.
  • Overview — "Total CUs Consumed" label; key/value rows share one label-column width; long value rows (cost utilization, reserved CUs) wrap at spaces instead of breaking mid-token, and their percentages use the same muted colour as the Programs table.
  • Number formatting — block cards use tabular figures on the standard face; monospace kept only for ◎ SOL amounts.

Type of change

  • Design update

Screenshots

block_mobile_desktop

Testing

Block page

Related Issues

HOO-801

Checklist

  • My code follows the project's style guidelines
  • All checks pass locally (pnpm test, pnpm lint, pnpm typecheck)
  • CI/CD checks pass on the PR
  • Screenshots included — recommended for UI changes

@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

@Stulikov is attempting to deploy a commit to the Solana Foundation Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps

greptile-apps Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adapts the block detail route and its tabs for responsive mobile and tablet presentation.

  • Replaces block tables with responsive grids and labeled stacked rows.
  • Adds collapsible sections, mobile filtering and sorting controls, and revised card spacing.
  • Extracts the block overview into a dedicated component and expands Storybook coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
app/block/[slot]/layout.tsx Reworks the block page frame, overview composition, spacing, and sticky responsive tab bar without an accepted correctness issue.
app/components/block/BlockHistoryCard.tsx Adds responsive transaction rows, bidirectional URL-backed sorting, searchable program filters, and mobile controls without an eligible follow-up defect.
app/components/block/BlockOverviewCard.tsx Extracts the block summary and preserves block identity, timing, leader, transaction, and compute-resource information.
app/components/block/BlockAccountsCard.tsx Converts account usage into responsive rows and combines totals with transaction-share percentages.
app/components/block/BlockProgramsCard.tsx Reworks program statistics into a responsive grid with consolidated counts and explanatory tooltips.
app/components/block/BlockRewardsCard.tsx Adapts reward information to the shared responsive card presentation.
app/features/transaction/ui/CollapsibleSection.tsx Introduces the collapsible section structure used by block cards, keeping action controls separate from the collapse trigger.
app/components/common/Address.tsx Extends address presentation behavior to support the responsive block layouts.

Reviews (2): Last reviewed commit: "trigger build" | Re-trigger Greptile

* chore: bootstrap development branch

* feat(block): match block page layout and overview to the transaction page

- Page shell now mirrors the transaction page: same max width, side padding
  and vertical rhythm between blocks; the header drops its underline for the
  borderless "Details / Block" treatment.
- Overview moves out of the horizontally-scrolling table into a new
  BlockOverviewCard built on the transaction summary's key/value grid, so long
  blockhashes and leader addresses wrap instead of scrolling sideways on mobile.
- Copy buttons added to Blockhash, Parent Blockhash and Slot; timestamps
  switch from monospace to the regular face.
- Tabs rebuilt as a full-bleed sticky bar matching the transaction page,
  replacing the heavier bordered sticky header.
- Card outline set to outer-space-800 to match the tx-inspector design.

* feat(block): responsive layout for block page tabs

Account, program, reward and transaction lists now lay out as an aligned
grid on md+ and collapse into stacked, labelled rows on mobile.

* feat(block): tighten block transactions card and mobile view

- desktop grid from md (was lg); numeric columns tightened
- mobile: Signature/Programs labelled fields, index top-right,
  label column matched to Overview
- keep program counters ("N ×") on one line; feed logs into
  stories so the Compute column shows

* feat(block): polish transactions card labels, filter and sorting

- rename compute-unit columns to CUs Reserved / CUs Consumed / Cost, plus
  the Overview's "Total CUs Consumed"; column header now reads "Signature / Programs"
- fix the "#" header not resetting rows to index order (stale sort param persisted
  in the URL)
- filter dropdown gains a visible border and a dot marking the selected option
- widen the index column (fits 4 digits), Fee and CUs Consumed; tighten the
  signature/badge wrap gap

* feat(block): sort indicators, program variants, and table polish

- Transactions: sortable headers show a direction indicator — dim up/down
  chevrons when clickable, the active column turning white with a bright
  arrow; re-clicking the active column reverses the sort (kept in the URL).
  Reserved and Consumed columns swapped; CU columns widened to keep their
  headers on one line; Cost tightened.
- Block Programs: a chip switcher (1 / 2 / 2a) flips the table between an
  aligned count+percentage layout, a parenthesised percentage, and a
  swapped variant that foregrounds the percentage. Column headers gained
  info icons whose tooltips cite the block's transaction/instruction
  totals; Success Rate is shortened to "Success" in the compact variants.
- Block Account Usage: Total and its % of transactions merged into one
  column — the header reads "Total" with a matching info tooltip, the share
  stays in the rows.
- Rewards: "New Balance" renamed "Post Balance" with a wider column.
- Numbers across the block cards use the standard face with tabular
  figures; monospace is kept only for ◎ SOL amounts, and the
  count-to-percentage gap is tightened.

* fix(block): stop long addresses overflowing the accounts card

Account links (and the Address wrapper) now shrink and mid-truncate inside
the grid cell instead of forcing horizontal scroll; share label clarified to
"of block transactions".

* feat(block): redesign transactions filter and unify card radius

- Block transactions card: the filter is now a "Filters" button (icon +
  active-state dot) with a fixed-width (280px) menu that has a program
  search and wraps long option names; the active program filter shows as a
  removable chip, and the record count moves into the heading as
  "N filtered records" / "N records". The header is a two-column layout
  with the filter/collapse actions bottom-aligned.
- CollapsibleSection: new `belowTitle` slot renders full-width content in
  the always-visible title group.
- Block tables (history, accounts, programs, rewards): force the tight-card
  radius to 8px so they match the overview and transaction-page cards
  (were rendering at 12px).
- Block overview: long value rows (cost utilization, reserved CUs) wrap at
  spaces instead of breaking mid-token, via a new `Value` breakAll opt-out.
- TokenHistoryCard: broaden Storybook coverage — populated, filter menu,
  filtered-by-mint, loading, failed, empty, and >25-token states.
- Reformat touched files with Prettier to fix the failing CI format check.

* feat(block): add mobile sort menu to transactions card

- The grid's sort headers are hidden below md, so mobile gets a
  "Filters"-style Sort button (left of the filter) opening every sortable
  column split into its two directions ("Lowest …" ascending, "Highest …"
  descending); each row pushes an explicit direction through the same
  URL-param sort the headers already use.

* feat(block): consistent percentage display across block tabs

- Block Programs settles on one design — count with the percentage in
  parentheses ("count (percent)"); the on-page 1/2/2a variant chips are
  removed.
- Block Accounts shows Total the same way — "count (percent)".
- Block Overview mutes the "(NN%)" in the compute-utilization rows to
  match the Programs table.

* feat(block): tighten mobile tab-bar spacing

- On mobile the sticky tab bar now sits ~12px under the Overview card, with
  a balanced 28px band above the tab labels and 36px below the underline;
  desktop spacing is unchanged (reset at `lg`).
- BlockOverviewCard takes an optional `className` so the layout can control
  its bottom margin.

* feat(block): match page heading spacing to the inspector

The "Details / Block" heading now shares the transaction inspector's
airy vertical rhythm — py-6 padding with a 24px gap above and below,
instead of the previous tighter, uneven spacing.

Pull the header out of the section space-y (moved onto an inner
wrapper) so its own margin controls the gap to the first card, rather
than a section band stacking on top of it.

* dedupe card helpers and tidy comments

* collapse to single card variant and share grid primitives

---------

Co-authored-by: Tania Markina <tania.markina@hoodies.team>
@C0mberry
C0mberry force-pushed the feat/hoo-801-block-page-mobile-layout branch from 69ea7a1 to dbe57e8 Compare August 26, 2026 11:07
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

Deployment failed for project explorer with the following error:

You don't have permission to create a Preview Deployment for this Vercel project: explorer.

View Documentation: https://vercel.com/docs/accounts/team-members-and-roles

@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
explorer Ready Ready Preview Aug 26, 2026 2:39pm

Request Review

@@ -0,0 +1,97 @@
import { Button } from '@components/shared/ui/button';

@askov askov Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question/issue: Why are there two components in the PR, this one and the shared collapsible-section?

if (sort === 'fee') return 'fee';
if (sort === 'reservedCUs') return 'reservedCUs';
return 'index';
const mode: SortMode =

@askov askov Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: This is too much of ternary, hardly readable

import { Button } from '@/app/components/shared/ui/button';
import { Dropdown, DropdownItem, DropdownMenu, DropdownToggle } from '@/app/components/shared/ui/dropdown';
import { Input } from '@/app/components/shared/ui/input';
import { CollapsibleSection } from '@/app/features/transaction/ui/CollapsibleSection';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: Import from the feature barrel file, or explain in comments why it's not a good idea (the only that I could imagine is bundle size implication)

const nextParams = new URLSearchParams(currentSearchParams?.toString());
const nextDirection: SortDirection =
explicitDirection ??
(sortKey && sortKey === sortMode

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Please make it more readable

// passing no key clears the sort entirely (the old table's "#" reset). The mobile sort menu passes an
// explicit direction (its rows are per-direction) which short-circuits the toggle. We build the URL
// from a copy of the current params so a `delete` drops the keys — `pickClusterParams` only overrides.
const pushSort = React.useCallback(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: should be tested carefully

</>
}
className=""
titleClassName="!items-end gap-4"

@askov askov Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought/issue: There are conditional classes and important hacks here and there. Hard to read/debug/understand in general. For such cases we usually use cva

return (
<div className="border-b border-solid border-white/10 last:border-b-0">
{/* Mobile — stacked labelled rows with the index pinned to the top-right corner. */}
<div className="relative flex flex-col gap-1.5 px-4 py-3 md:hidden">

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: This is not the best practice to have both branches mounted for every single case when markup is not trivial. See how the problem is addressed in AccountsCard.tsx

success: { label: 'Success', variant: 'success' },
} as const;

const numberFmt = (n: number) => new Intl.NumberFormat('en-US').format(n);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: You don't need a new formatter every time, could reuse

// explicit direction (its rows are per-direction) which short-circuits the toggle. We build the URL
// from a copy of the current params so a `delete` drops the keys — `pickClusterParams` only overrides.
const pushSort = React.useCallback(
(sortKey?: SortMode, explicitDirection?: SortDirection) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Should sortKey be optional? It is not used without a key and maybe shouldn't

let totalCUs = 0;
let totalRequestedCUs = 0;
let totalCostUnits = 0;
for (const tx of block.transactions) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Maybe extract to the lib helper, for example app/entities/compute-unit/lib/block-compute-units.ts and do something like (or even better with some proper named type for the data) + tests:

export function summarizeBlockComputeUnits({ block, epoch, cluster }: {
    block: BlockWithV1; epoch: bigint | undefined; cluster: Cluster;
}): { consumed: number; requested: number; cost: number; max: number } {  }

The card then receives four numbers and renders them. Right now it's doing too much and the props are messy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants