feat(desktop): the file tree draws coloured icons, shares a lone folder's row, and gains a search field and a Files Luke showed filter

Merged
DA
7d ago
+510-56

Part 1 of 3 of Dean's file viewer polish. Part 2 (whole-repository search) and part 3 (one top bar: back/forward, breadcrumbs, GitHub, ⋯ menu, collapse) stack on this one.

Summary

The tree beside a File tab:

  • Draws coloured file icons. icons: "complete". Pierre colours only its Complete set (it marks the tree data-file-tree-colored-icons), and Standard was monochrome.
  • Shares a lone folder's row. flattenEmptyDirectories: true, so apps/web/server is one row, as in an editor's explorer. The tree is listed one folder at a time, and Pierre gives the shared row the expansion of the folder at its end. That folder is not listed yet when its parent opens, so a folder holding nothing but one folder now also opens that folder (folder-browser.ts). Otherwise the shared row would show as closed just after you opened it.
  • Has a search field at its top, in place of the repository-name header. The repository is already the first breadcrumb.
    • It uses the app's search-field style (the Settings well, a step shorter).
    • It filters the tree as you type through Pierre's own search (setSearch, hide-non-matches). It matches on the path, case-insensitively, and opens the folders above each match.
    • When nothing matches, the tree's place says No files match. Without this, Pierre would show every row.
    • Escape clears the field, then lets go of the caret. ⌘F (Ctrl+F) anywhere in the pane takes the caret to the field. Nothing else in the window offers ⌘F while a plan is open.
    • In this PR the search covers only the folders listed so far. Part 2 makes it search the whole repository.
  • Has a filter beside the search: "Only files Luke showed". It is a toggle icon button (aria-pressed) that narrows the tree to the files Luke showed of this repository, every folder open. It is disabled with a tooltip while Luke has shown none. A "Changed files" filter does not apply: the viewer reads the default branch as it stands, so nothing is changed. The filter is a second Pierre tree over those paths that stands in the repository tree's place, so turning it off leaves the repository's open folders as they were. Search works inside it too.
  • A breadcrumb's folder clears the search and the filter, because pressing a breadcrumb asks to see that folder.

Bundle

renderer/file-tree.js grew +9 gz bytes (70,853 → 70,862; budget 70,635 × 1.05 = 74,166). Pierre already shipped every icon sprite. The budget is not moved, and renderer.js is unaffected beyond the pane's few lines.

Screenshots (headless Chrome, fixture data)

Light, colored icons, apps/web sharing a row
Dark
Search .ts
Filter: files Luke showed (dark)
No match

Verification

  • ./scripts/check.sh exits 0.
  • New tests, each failing without the change:
    • file-tree/index.test.ts (the real bundle on real Pierre in jsdom): icons are coloured and typed; search narrows rows, says when none match, and an empty search restores them; the filter shows only the given files with folders open, opens a file on a press, searches within, and lets go.
    • file-tree/folder-browser.test.ts: a folder holding one folder opens it too, and the shared row lists what it holds.
    • planning/file-view.test.ts: the field hands the tree the query; Escape clears it; ⌘F focuses it; the filter narrows to this repository's shown files; a breadcrumb's folder clears both; the filter is disabled while Luke has shown nothing.
  • Session replay: the pane stays ph-no-capture, and the field is inside it.
  • CI could not verify this. It is a desktop UI change and ./scripts/verify.sh was not run: this was written on a Linux VM. A Mac break that lands is caught at the release rehearsal on a tag (LUKE-159).

🤖 Generated with Claude Code