Repository navigation
[#912 Slice 3] Breadcrumb navigation + filetree dropdown + search #921
Description
Important
Problem — After Slice 2 provides the Finder-style directory navigation, users still lack three key navigation aids: a breadcrumb path bar for jumping to ancestor directories, a filetree dropdown for quick-jumping anywhere, and a search bar for finding files by name across the project.
Approach — Build preview-breadcrumb.tsx with individually clickable path segments and a dropdown trigger that opens a FileTreeV2 (static mode) overlay for files, plus a custom click interceptor for folder navigation. Add a persistent search bar at the top that replaces the directory view with flat substring-matched results. Both the dropdown and search need the full renderable file set, so this slice adds a recursive tree walk + cache on tab mount.
Scope — in: breadcrumb component, filetree dropdown overlay, search bar, recursive file enumeration + cache · out: CodeMirror editor, image/PDF rendering, no-project fallback
Acceptance Criteria
- Breadcrumb path bar replaces the plain-text path from Slice 2; each segment (e.g.
src,components,session) is individually clickable and navigates to that directory - A separate dropdown trigger (chevron icon) on the breadcrumb opens an overlay showing the full filtered filetree
- The dropdown overlay uses
FileTreeV2in static mode (passallowed={cachedRenderablePaths}to the component, which internally callsbuildFileTreeV2Model). File clicks fire via the existingonFileClickprop and navigate to that file. - Folder navigation in the dropdown: since
FileTreeV2has noonFolderClickprop (folder clicks toggle expand/collapse), add a click interceptor on[data-slot="file-tree-v2-row"]directory rows that intercepts the click, updatescurrentPath, and closes the dropdown. The interceptor sits on the dropdown container, not insideFileTreeV2. - Clicking outside the dropdown or selecting a file/folder closes it
- The full renderable file set is obtained by recursively walking
file.tree.childrenon tab mount, filtering withisRenderable()frommarkdown-utils.ts, and caching the path array - The cache refreshes when the tab regains focus
- A search bar is always visible above the breadcrumb in both directory and file views
- Typing in the search bar replaces the directory view with a flat substring-matched list of all renderable files (case-insensitive, matching against full relative paths)
- Clicking a search result opens that file directly
- Clearing the search bar (or pressing Escape) restores the directory view at whatever folder the user was in
- Arrow keys navigate the search results list; Enter opens the highlighted result
Testing Decisions
Add unit tests for the recursive file enumeration and cache logic (mock file.tree.children). Test the search filter as a pure function (substring matching against path arrays). Test breadcrumb segment extraction from a path string. Extends Slice 2's navigation state tests for the search-query transitions.
Key Decisions
Recursive walk on tab mount for the dropdown and search. The lazy per-directory approach from Slice 2 works for the Finder view, but the dropdown and search need all renderable paths up front. Walk the tree recursively via repeated file.tree.children calls, filter with isRenderable(), cache the result. Refresh on tab focus to pick up new files.
FileTreeV2 in static mode via allowed prop. Pass the cached path array as the allowed prop to FileTreeV2. The component internally calls buildFileTreeV2Model — the implementing agent does not call the model function directly.
Folder navigation via click interceptor. FileTreeV2 hardcodes folder clicks to toggleDirectory with no onFolderClick prop. Rather than modifying the upstream component, attach a delegated click listener on the dropdown container that intercepts clicks on [data-slot="file-tree-v2-row"] elements with a directory data-path. This navigates to the folder and closes the dropdown while leaving FileTreeV2's expand/collapse intact for browsing.
Search replaces directory view, doesn't overlay it. When the search bar has text, the entire content area below the breadcrumb switches to a flat results list. Same pattern as Files Changed's SessionFileListV2.
Constraints & Invariants
- The breadcrumb must always reflect the true current directory path — clicking a segment must navigate to exactly that directory
- The dropdown must show the same filtered set as the search (same cache, same filter)
- Search must be responsive for the expected file count (dozens to low hundreds of renderable files)
isRenderable()frommarkdown-utils.tsis the single filter — never a local extension list
Prior Art
file-tree-v2.tsx+file-tree-v2-model.ts— reused in static mode viaallowedprop for the dropdownsession-file-list-v2.tsx— pattern for flat search resultsreview-panel-v2.tsxbuildCollapsedTree()— pattern for collapsed-path dropdown (though we useFileTreeV2instead)review-diff-kinds.tsfilterReviewFiles()— pattern for substring filtering
Activity
jeonghun-jj-lee commentedon Sep 9, 2026
Superseded by #931 (Preview as sidebar companion). The Finder-based design is replaced by the reactive companion model — sidebar drives file selection, Preview is a pure viewer.