style(desktop): Files changed as cards that share one edge, with a quiet fold and a clearer header

Merged
DA
12h ago
+132-23

Summary

The developer asked for a design pass on Files changed:

  • the collapse/expand button sits on a background;
  • files don't reach the full width of their headers;
  • the scrollbar leaves a strange gap;
  • the rest should get good UI/UX.

This PR is stacked on #3789, since it touches the same chip rules.

Why the edges didn't line up. Pierre gives every file's code area scrollbar-gutter: stable, and that area only scrolls sideways (overflow-x: scroll). On a Mac set to show scroll bars always, or in any Chromium drawing classic bars, that reserves a ~10 px strip at the end of every line. So the rows and the "N unmodified lines" bands stopped short of the header, which sits outside that box. Measured in Electron at 900 px: header 0–626, rows 0–616. The list's own scrollbar then added a second strip.

What changes

  • One edge. [data-code] { scrollbar-gutter: auto } is set in the diff's shadow CSS. Header, hunk bands, code rows and thread cards now share one left and one right edge. Lines wider than the panel still scroll sideways.
  • Scrollbar. The list's own bar is now a single strip at the list's outer edge, against the tree's divider, rather than splitting the cards.
  • Files as cards.
    • Each file is a card: a 1 px border, the control radius, and the whole card rounded so a folded file and an open one read as the same object.
    • Cards sit on the panel ground with 12 px between them and around the list (Pierre's own layout gap/paddingTop, so the virtualizer measures them).
    • The card is clipped at its own edge, so a header stuck at the top stands square: the card's rounded top has scrolled away.
  • Fold button. It's the compact quiet IconButton: no fill at rest or while open. The filled square was @luke/ui's aria-expanded="true" look for menu buttons. It's still a real button with aria-expanded and its ; key.
  • Header hierarchy.
    • The status letter stands on a tint of its own colour. The letter keeps the meaning, so it reads without colour.
    • The path shows the folder quiet and the name in normal ink at medium weight. Where the row runs short the folder is cut first, so at 600 px the name stays whole.
    • The row is 36 px.
    • Viewed stays @luke/ui's Checkbox, now with a hint: "Mark as viewed V".
  • Hunk bands. 32 → 24 px, on a quieter fill, in caption-size sans, with the 20-line arrows kept. Pierre is told the height (hunkSeparatorHeight) so the list stays measured.
  • Rhythm. Notes, threads and the chip get 8 px vertical padding, on the 4/8/12 scale.
  • Tree. Beside Files changed, the tree's search sits level with the first card.
  • Keys. SHORTCUT_KEY gains V for the hint, with a note that bare V is Files changed's.
  • Unchanged. The gutter "+" keeps #3646's place and keyboard behaviour; its look was already a quiet rounded button.

Screenshots

From Electron under xvfb with classic scrollbars, as on a Mac with "Show scroll bars: Always". PR #2908, with Minimize inline comments on: a minimized thread chip on line 356, the collapsed "347 unmodified lines" gap, and a folded file. Before is #3789.

beforeafter
dark 900
dark 900, file end + folded file
light 900
light 900, file end + folded file
dark 600
dark 600, folded file
light 600
light 600, folded file

Evidence

  • tsc --noEmit for settings, panel and desktop: clean.
  • ./scripts/oxlint.sh: 0 errors.
  • pnpm knip: clean.
  • ./scripts/repository-checks.sh: passed. Every new CSS variable is a defined --luke-* role.
  • biome check: no errors.
  • vitest run --project panel --project desktop --project settings: 234 files, 2353 tests passed.
  • No behaviour changes: this is markup and style only, apart from the Viewed hint. Existing tests that read the header's text still pass, because the path's two parts read as one.

Invariants

  • Checks green locally, as listed above.
  • JSON Schema goldens unchanged.
  • No new as.
  • No raw async primitives.
  • Test count unchanged.
  • PRIVACY.md unchanged.
  • Deps unchanged.

Made with Luke