Move iOS search and page creation to bottom toolbar#17
Conversation
Use SwiftUI's native bottom toolbar search item for the iOS page browser and move the root page creation action into a separate bottom toolbar button. Reuse the existing search results model so focused search swaps the page list into live results without duplicating search logic.
There was a problem hiding this comment.
1 issue found across 3 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Greptile SummaryThis PR migrates iOS search and root page creation from the top navigation toolbar/sidebar into a native bottom toolbar, and refactors the search UI into a reusable
Confidence Score: 5/5Safe to merge — the change is additive on iOS, non-breaking on macOS, and the search/debounce wiring follows the same pattern already in SearchView. All three files change in a straightforward, well-scoped way. The new PageTreeSearchProvider correctly threads the current space ID through the existing SearchProviding protocol, the debounce task mirrors the established pattern in SearchView, and the #if os(iOS) guards keep the macOS toolbar unchanged. The only finding is a file-organisation nit. No files require special attention beyond the cosmetic note about SearchResultsContent belonging in its own file. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User opens Space on iOS] --> B[PageTreeView shown]
B --> C{Bottom toolbar}
C -->|Tap search icon| D[isSearchPresented = true
searchable focused]
C -->|Tap pencil icon| E[PageCreationSheet]
D --> F{isShowingSearch = true}
F -->|query empty| G[SearchResultsContent
shows filter bar only]
F -->|query >= 2 chars| H[task debounce 300ms]
H --> I[PageTreeSearchProvider.search
scoped to current space]
I --> J[SearchResultsContent
shows results]
J -->|Tap result| K[SearchResultDestinationView]
J -->|Show More| L[SearchViewModel.loadMore]
D -->|Cancel| M[query cleared
isSearchPresented = false]
M --> N[Back to normal
PageTreeView list]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[User opens Space on iOS] --> B[PageTreeView shown]
B --> C{Bottom toolbar}
C -->|Tap search icon| D[isSearchPresented = true
searchable focused]
C -->|Tap pencil icon| E[PageCreationSheet]
D --> F{isShowingSearch = true}
F -->|query empty| G[SearchResultsContent
shows filter bar only]
F -->|query >= 2 chars| H[task debounce 300ms]
H --> I[PageTreeSearchProvider.search
scoped to current space]
I --> J[SearchResultsContent
shows results]
J -->|Tap result| K[SearchResultDestinationView]
J -->|Show More| L[SearchViewModel.loadMore]
D -->|Cancel| M[query cleared
isSearchPresented = false]
M --> N[Back to normal
PageTreeView list]
Reviews (3): Last reviewed commit: "Pin page tree search scope to displayed ..." | Re-trigger Greptile |
Include the viewed space in the page-tree search task identity so active queries refresh when switching spaces, and simplify the debounce cancellation path.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 71c1453227
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| do { | ||
| try await Task.sleep(for: .milliseconds(300)) | ||
| try Task.checkCancellation() | ||
| await searchViewModel.search(provider: appState) |
There was a problem hiding this comment.
Pin current-space search to this page tree
When this embedded search uses SearchViewModel.search(provider: appState), the .currentSpace filter is resolved from AppState.selectedSpaceID rather than the space being displayed by PageTreeView. In this new flow, a user can search all spaces from space A, open a result from space B, and SearchResultDestinationView updates selectedSpaceID to B without changing the sidebar destination; after navigating back, the picker still says “Current Space” in space A but subsequent searches/load-more requests are scoped to B. Pass a provider or pinned current-space ID based on space.id for the page-tree search path.
Useful? React with 👍 / 👎.
| .task(id: pageBrowserTaskKey) { | ||
| await refreshBrowser() | ||
| } | ||
| .task(id: searchViewModel.searchTaskKey) { |
There was a problem hiding this comment.
Re-run embedded search when the space changes
When a user searches in one space and then selects another space, PageTreeView state is reused while this new task is keyed only by the query/filter values. With a non-empty query the search UI therefore remains visible in the new space without issuing a new request, leaving stale results from the previous space on screen; pressing “Show More” can also reuse the old offset against the new scope. Include space.id in the search task key or clear/reload the search model when the displayed space changes.
Useful? React with 👍 / 👎.
Use a page-tree search provider that resolves the current-space scope from the displayed space instead of mutable global navigation selection.
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
Summary
Verification
Apple docs referenced: