Skip to content

fix(v2): right-align the list-view quantity columns - #4603

Merged
sdornan merged 5 commits into
masterfrom
claude/size-align-column-0912f4
Sep 17, 2026
Merged

sdornan merged 5 commits into
masterfrom
claude/size-align-column-0912f4

Conversation

@sdornan

@sdornan sdornan commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Description
Explain the changes or enhancements you are proposing with this pull request.

In the v2 gallery list view, Size, Added, Released, Rating and Length now read as quantities: the value and its column header both sit on the right edge of the track, and tabular figures keep the digits in a straight column.

  • Added and Released are right-aligned for the same reason as the quantities, and it is what makes tabular figures pay off there. Tabular figures only equalise digit widths, so while the date columns were start-aligned the year still stepped with the month abbreviation, measured at 6.3px across the Added column and 7.5px across Released. From the right edge inward the comma, day and year are all fixed width, so every row's year now starts at the same x; only the month's left edge stays ragged (Dec 09, 2024 / Sep 09, 1988 below).
  • An end-aligned cell spends the track slack that used to separate it from the column beside it, so the shared gutter grows from 12px to 20px, and the mirrored LIST_GRID_GAP_PX with it. Without that, Size/Added and Length/Languages collapsed to the bare 12px gap, and a sorted Rating header (label + glyph = 56px) filled its track edge to edge.
  • The Released track widens 84px to 96px, matching Added. Tabular figures push the widest dates to 85px, so "May 19, 1994" and "May 18, 2002" ellipsized in the old track.
  • The sort glyph leads the label once a label is end-aligned. Appending it shoved the label sideways on click (the glyph now sits on the label's left, so the label's right edge stays put).
  • ListColumn.align was declaration-only: the header read it, the row never did, so flipping a column to end produced a right-aligned header over left-aligned values. The row now reads its classes off the same config via cellModifiers(), in the hydrated and the per-position skeleton branch alike.
  • ListColumn.numeric is new, for the tabular figures.

The skeleton flavours follow so the placeholders stay in parity: GameListSkeletonRow is its own grid, so it needed the wider gutter, and its placeholder bars needed to move to the right edge for the end-aligned columns. Measured with the tail rows held open, the bars sit at rightSlack=0 on those columns, so nothing jumps when a row hydrates.

No issue to link: this came out of a design pass on the list view rather than a filed bug.

Checklist
Please check all that apply.

  • I've tested the changes locally
  • I've updated relevant comments
  • I've assigned reviewers for this PR
  • I've added unit tests that cover the changes

Screenshots (if applicable)

Before, dark theme: the date columns are start-aligned, so the year steps with the month abbreviation ("Sep" is wider than "Jul", "May" the widest).

before, dark theme

After, dark theme: Added and Released share the right-aligned edge with Size, Rating and Length, and every row's year starts at the same x.

after, dark theme

After, light theme, same view:

after, light theme

Notes for reviewers

  • Years measured in the running app at 1680x1000 across the 13 visible rows: year-left spread is 0px in both date columns after the change, against 6.3px (Added) and 7.5px (Released) before it. Day-left spread is 0.1px, subpixel rounding only.
  • Checked at 375px and 1680px in both themes: no header is wider than its track in any sorted state, and both date columns keep a 0px year spread. Minimum header label gap and minimum row value gap are both 20px at 1680px.
  • The bootstrap GameListSkeletonRow is only visible before the first page lands, and this dev library has 21 roms against a 72-row page size, so it cannot be driven into view locally. That flavour rests on GameListSkeletonParity.test.ts, which asserts the per-column right-edge flags of all three row flavours against the column config.
  • 1539 tests pass across 152 files, vue-tsc is clean, npm run build succeeds, trunk fmt && trunk check is clean.

AI assistance disclosure

Implemented with Claude Code (Anthropic), driving the change end to end: the column-config edit, the component changes, the regression test, and the browser verification and screenshots above. Reviewed by me before opening.

sdornan and others added 2 commits September 17, 2026 16:41
Size, Rating and Length now read as quantities: their values and their
headers sit on the right edge of the track, and tabular figures keep the
digits in a straight column. The two date columns stay start-aligned but
take tabular figures too.

An end-aligned cell spends the track slack that used to separate it from
the column beside it, so the shared gutter grows from 12px to 20px (and
the mirrored LIST_GRID_GAP_PX with it). Without that, Size/Added and
Length/Languages collapsed to the bare gap and the sorted Rating header
filled its track edge to edge.

The Released track widens to 96px: tabular figures push the widest dates
past its old 84px, and they ellipsized.

The header sort glyph leads the label once the label is end-aligned, so
clicking a sorted column no longer shoves it sideways.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tabular figures only equalise digit widths, so the year in "Sep 09, 1988"
still stepped with the month abbreviation, up to 7.5px across rows. Pinning
Added and Released to the right edge puts the fixed-width tail (comma, day,
year) on the same x in every row.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@sdornan
sdornan marked this pull request as ready for review September 17, 2026 22:20
Copilot AI lite review requested due to automatic review settings September 17, 2026 22:20
@greptile-apps

greptile-apps Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge, with no outstanding correctness, security, or repository-rule issues.

Summary

This PR improves the v2 gallery list view’s column alignment and visual consistency.

  • Right-aligns quantity and date headers, hydrated values, and loading placeholders from shared column configuration.
  • Uses tabular figures for numeric columns and preserves header-label position when sort icons appear.
  • Widens the released-date track and shared grid gutter while keeping header, row, and skeleton geometry synchronized.
  • Adds typed regression fixtures and parity tests for alignment and numeric modifiers.

Reviews (3) · Last reviewed commit: "test(v2): tighten the parity test commen..."

Comment thread frontend/src/v2/components/Gallery/GameListSkeletonParity.test.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

One or more issues must be addressed before approval.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Aligns v2 gallery list quantity columns and date values to the right, using tabular figures and synchronized skeleton layouts.

Changes:

  • Updated column alignment, numeric formatting, track widths, and grid gaps.
  • Applied alignment consistently to headers, hydrated rows, and skeleton rows.
  • Added skeleton parity coverage for column alignment.
File summaries
File Description
frontend/src/v2/components/Gallery/listColumns.ts Updated as part of this pull request.
frontend/src/v2/components/Gallery/GameListSkeletonRow.vue Updated as part of this pull request.
frontend/src/v2/components/Gallery/GameListSkeletonParity.test.ts Updated as part of this pull request.
frontend/src/v2/components/Gallery/GameListRow.vue Updated as part of this pull request.
frontend/src/v2/components/Gallery/GameListHeader.vue Updated as part of this pull request.
Review details

Suppressed comments (4)

frontend/src/v2/components/Gallery/GameListRow.vue:135

  • The new numeric contract is not covered by the regression test: rightEdges() only checks --end, so dropping the --num mapping or any numeric flags would still leave the test green. Please assert that the hydrated metric cells expose the numeric modifier, or otherwise verify the tabular-figure styling.
    "game-list-row__cell--num": column?.numeric === true,

frontend/src/v2/components/Gallery/GameListRow.vue:136

  • align is documented as applying to the cell body, but cellModifiers() is only used for the metric and action cells. The hydrated platform, title, language, and region branches still ignore the config, so changing any of those columns to end would leave the header and skeleton aligned differently from hydrated rows. Apply the same modifier to every body cell or derive the body from columns.
/** Alignment / figure modifiers for a cell, read off the column config so
 *  the body cannot drift from the header above it. */
function cellModifiers(key: ListColumn["key"]) {
  const column = columns.value.find((col) => col.key === key);
  return {
    "game-list-row__cell--end": column?.align === "end",
    "game-list-row__cell--num": column?.numeric === true,
  };

frontend/src/v2/components/Gallery/GameListSkeletonParity.test.ts:91

  • This regression test covers the new --end classes, but it never asserts that the new numeric flag produces --num on hydrated cells. A regression could remove font-variant-numeric: tabular-nums while all current assertions remain green, so add a numeric-class assertion for the configured columns.
    const expected = getListColumns(true).map((col) => col.align === "end");
    const pending = mount(GameListRow, { props: { position: 0 } }).element;
    const hydrated = mountHydratedRow().element;
    const bootstrap = mount(GameListSkeletonRow).element;

    expect(rightEdges(pending)).toEqual(expected);
    expect(rightEdges(hydrated)).toEqual(expected);
    expect(rightEdges(bootstrap)).toEqual(expected);

frontend/src/v2/components/Gallery/listColumns.ts:79

  • The new numeric contract is not covered by the regression test: rightEdges() only checks --end, so the suite still passes if the --num binding or font-variant-numeric: tabular-nums is removed. Add a hydrated-row assertion for the metric cells to protect the tabular-figure behavior.
      numeric: true,
  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread frontend/src/v2/components/Gallery/GameListSkeletonParity.test.ts Outdated
sdornan and others added 2 commits September 17, 2026 17:26
The row fixture was an object literal forced through `as unknown as
SimpleRom`, which the v2 rules prohibit and which hid a real type error:
`metadatum.first_release_date` is an epoch number, and the fixture passed a
date string. A complete `SimpleRom` default now fails the build when a
required field changes, behind a factory that takes per-test overrides.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The parity assertions only checked the `--end` wiring, so dropping the
`--num` mapping or a `numeric` flag from the config would have stayed green
while the tabular figures quietly went proportional. Verified the new
assertion fails when the mapping is removed.

Also narrows the `align` doc: only the value and action cells read it, the
structural cells lay themselves out, so the field no longer claims a reach
it does not have.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread frontend/src/v2/components/Gallery/GameListSkeletonParity.test.ts Outdated
Each of the three rationale comments in the list-row parity test now states
its invariant on a single line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUpZ4rcSyfZbnUeJ3X9JJB
@sdornan
sdornan merged commit 0f99484 into master Sep 17, 2026
13 checks passed
@sdornan
sdornan deleted the claude/size-align-column-0912f4 branch September 17, 2026 22:41
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.

2 participants