feat(desktop): show or hide Files changed's tree with ⇧F, drag it wider, and leave a strip of its files while it is hidden

Merged
DA
2d ago
+449-28

Summary

T2 of the "File tree: viewed and counts" stack. It's stacked on #3798 (T1), which is stacked on #3794.

  • ⇧F shows or hides the tree.
    • It's a new row in @luke/settings/shortcuts' Files changed table, under a new "Panels" group, as stage-cli groups it. So the ? sheet and Settings › Keyboard shortcuts list it, and changes-list.tsx's keyRuns handles it.
    • Like the view's other plain keys, it only works while focus is inside Files changed and you're not typing. It doesn't clash with any app chord: ⌘F is Find and ⌃⌘F is Full screen.
    • It acts where the tree is seen. In a panel wide enough, it opens or closes the tree beside the list. In a narrow panel, it opens or closes the floating tree.
  • Resize: a drag handle on the tree's left edge, using the app's own useResizableEdge.
    • The width runs from 220 to 480 px, defaults to 264, and always leaves the list 320 px.
    • It supports the arrow keys and Home/End, Enter or a double-click resets it, and dragging past the minimum shuts the tree.
    • The width is kept in renderer storage (luke.fileTreeWidth), the same way the Inbox list's and the Runs panel's widths are kept (folded-groups.ts). It's one width for every File and Changes tab, matching how the tree's open state is already shared.
    • With a wider tree, T1's +N −M counts show on most rows.
  • Collapsed strip: while the tree is hidden in a wide enough panel, a 12 px strip stands in its place (changes-strip.tsx).
    • It has one mark per changed file, in tree order, coloured by status the same way as the tree's letters. Viewed files are dimmed, and the file the bar names stands out.
    • Resting the pointer on it peeks the tree out over the list, through the same usePaneRoom float as the narrow panel's floating tree. Leaving puts the tree away again, and choosing a file closes it.
    • It's hidden from assistive technology, which reaches the tree through its toggle and ⇧F.
    • The panel's narrow layout is unchanged: it keeps its edge peek and doesn't show the strip.

Screenshots

PR #3645 in the Files changed harness (Chromium, the panel's real CSP and stylesheet).

strip (tree hidden)strip hovered: tree peekstree dragged to 400 px
dark 900
light 900
dark 600
light 600

Tests

New tests in agent-changes-tab.test.ts:

  • ⇧F toggles the tree, and does nothing while typing in its search.
  • The tree wears the kept width, and its edge (Resize files) asks for the default on Enter.
  • With the tree hidden, the strip draws a mark per file in tree order, with status, viewed and current. Pointing at it peeks the tree.

The sheet's and the Settings page's literal rows gain "Show or hide file tree ⇧F".

I also checked by hand in the harness:

  • dragging the edge 120 px stores and draws about 387 px;
  • ⇧F hides the tree and shows the strip at 900, and opens the floating tree at 340.

Evidence

  • pnpm check:affected ran out of memory in discarded-effect on T1. For T2 I ran the fallback list, and everything passed:
    • tsc --noEmit for panel, settings and desktop: clean;
    • vitest --project panel --project settings: 201 files, 2133 tests passed;
    • ./scripts/oxlint.sh: 0 errors;
    • biome check: no errors;
    • pnpm knip: clean;
    • ./scripts/repository-checks.sh: passed.
  • cd apps/desktop && node scripts/build.mjs: passed, bundle budget included.

Invariants

  • Checks green locally, as listed above.
  • JSON Schema goldens unchanged.

Made with Luke