Skip to content

feat(mobile): move Chats search into the header - #2377

Merged
DoodleBears merged 2 commits into
mainfrom
claude/project-thread-idejwb
Oct 20, 2026
Merged

DoodleBears merged 2 commits into
mainfrom
claude/project-thread-idejwb

Conversation

@DoodleBears

Copy link
Copy Markdown
Contributor

Requested by Vain · project thread

Why the change

The Chats search field floated above the bottom navigation, stacking two floating layers over the list. It now opens from a header button and fills the header row while active, as Material 3 top app bars and iOS minimized toolbar searches do.

Issue / Discussion: decided in the project thread (Vain picked option B over keeping bottom search or an iOS 26 search-tab circle).

Special things to note

  • Merge risk: JavaScript-only, no native or dependency change; revert the single commit to restore bottom search. Blast radius is the Chats and Activity headers. Review focus: blur/close behavior in HeaderSearch and the Android Back handler.
  • Behavior: tapping 🔍 hides the title and Settings and focuses the field. iOS closes with the native glass close circle; Android with a leading back arrow or system Back, plus its own clear button. On Chats, ending editing with an empty query closes search; with a query the field stays so the filter stays visible. Activity collapses on blur and keeps the query (tinted 🔍), so Filter and sort stay reachable during a search; close clears it.
  • Verification: pnpm --filter @botharness/mobile typecheck clean, pnpm lint passes, pnpm vitest run apps/mobile 907 passed (Chats search tests updated plus a new header-swap test). Web-render screenshots below against an isolated Host. Not run: native iOS/Android checks and the system-text matrix (cloud session, no simulator); needs a Mac/Windows device-QA pass.
  • Web preview on main is currently blank: app-dialog-host.tsx (from feat(mobile): HIG and system-UI pass: glass sidebar, bottom search, chat soft edge, native dialogs and menus #2333) imports @expo/ui/jetpack-compose without a platform split, which throws on web. The screenshots used a local, uncommitted web stub for that module; worth a separate fix.
  • CI test plan: affected (mobile only); no new rule needed.

Change outline

  • New src/ui/shell/header-search.tsx: HeaderSearchButton and HeaderSearch (platform close affordances, Android Back).
  • HomeHeader takes a search slot that replaces the title chip and actions.
  • Chats: BottomSearch removed (file deleted); list reserves only the navigation height.
  • Activity toolbar: field now opens in the header row instead of a second row.
  • DESIGN.md Chats and Activity search rules updated.

Chats, 390 × 844 web render: before / after idle / after searching "la"

Web render shows layout only: native text fields and SwiftUI glass buttons draw empty on web.

Chats light: before with bottom search, after idle with header search button, after searching

Chats dark: before with bottom search, after idle with header search button, after searching

Activity, 390 × 844 web render: idle / searching

Activity light: idle header and search filling the header row

Activity dark: idle header and search filling the header row


Generated by Claude Code

The Chats search field floated above the bottom navigation island, so two
floating layers stacked over the list. Search is now a magnifying-glass
button left of Settings; tapping it turns the header row into the search
field and hides the title and Settings. iOS closes it with the circular
close button, Android with a back arrow or system Back. Activity opens
its search in the header row the same way.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJWgC9dD6cje8rYMAMukjv
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EJWgC9dD6cje8rYMAMukjv
@DoodleBears DoodleBears self-assigned this Oct 20, 2026
@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 75b2e341-9e13-4fb1-870f-5177cb6f1328
📥 Commits

Reviewing files that changed from the base of the PR and between 40e50d2 and 0b0e81c.

⛔ Files ignored due to path filters: 4
  • .github/pr-screenshots/chats-header-search/activity-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/chats-header-search/activity-light.png is excluded by !**/*.png
  • .github/pr-screenshots/chats-header-search/chats-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/chats-header-search/chats-light.png is excluded by !**/*.png
📒 Files selected for processing: 9
  • apps/mobile/DESIGN.md
  • apps/mobile/app/(tabs)/(home)/index.tsx
  • apps/mobile/src/ui/shell/activity-toolbar-base.tsx
  • apps/mobile/src/ui/shell/bottom-search.tsx
  • apps/mobile/src/ui/shell/header-search.tsx
  • apps/mobile/src/ui/shell/home-header.tsx
  • apps/mobile/src/ui/strings.ts
  • apps/mobile/test/home-search.test.tsx
  • changes/2377-mobile-header-search.md
+-------------------------------------+
| I don't chase bugs; they surrender. |
+-------------------------------------+
  \
   \     /)/)
        ( '')
        /  |
      o(___)
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DoodleBears
DoodleBears merged commit 4c02815 into main Oct 20, 2026
12 of 13 checks passed
DoodleBears added a commit that referenced this pull request Oct 20, 2026
Captured on a Xiaomi phone (Android 16, HyperOS 3, arm64, gesture navigation,
zh-CN) running an arm64 debug dev client with this branch's JavaScript, in light,
dark and font scale 2.0: the search button left of Settings, Chats search open in
the header, closing it with the back arrow and with system Back (the first Back
hides the keyboard, the second closes search), and Activity search open.
Status bar, computer names and the keyboard suggestion strip are redacted.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

Android physical-phone check (Xiaomi, Android 16 / HyperOS 3, Chinese UI), JS from this PR's head 0b0e81cf over Metro on a debug dev client, paired to an isolated QA Host. Light, dark and text size 2.0 for each step. Status bar, computer names and the keyboard suggestion strip are redacted.

Result: PASS in all three modes.

Step Result
🔍 sits left of ⚙ in the Chats header PASS
Search expands across the header and focuses PASS
← closes search and restores the title PASS
System Back: first press hides the keyboard, second closes search, app stays open PASS
Activity search expands in the header PASS

Seen while testing, not caused by this PR: at text size 2.0 the Activity filter tabs wrap inside a word ("待你处 / 理").

This PR was already merged, so the 18 screenshots live on branch claude/project-thread-idejwb at 2be9ef62, under .github/pr-screenshots/2377-android-search/phone/ (chats-header-*, search-open-*, closed-by-arrow-*, after-system-back-1-*, closed-by-system-back-*, activity-search-open-*).


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

iOS Simulator: pass on main (iOS 26, dev client) at default, xLarge and AX5 text sizes, in light and dark. All 36 screenshots are on branch claude/2377-ios-shots @ 8b66aac, under .github/pr-screenshots/chats-header-search/ (prefix ios-).

  • Activity:
    • Opening search brings up the keyboard. The term "Grant" filters the list to 1 row.
    • After Return or blur, the header collapses back to the title, the 🔍 turns accent-colored, the list stays filtered, and reopening search shows "Grant" still there.
    • The glass ✕ clears the term and restores the header.
  • Chats: search opens with the keyboard up, "Te" finds Testa, and ✕ closes search.
  • AX5: the field, the ✕ and the keyboard all fit.
State Default, light Default, dark AX5, light AX5, dark
Chats, keyboard up <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-chats-search-keyboard-default-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-chats-search-keyboard-default-dark.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-chats-search-keyboard-ax5-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-chats-search-keyboard-ax5-dark.png" width="160">
Chats, closed with ✕ <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-chats-search-closed-default-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-chats-search-closed-default-dark.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-chats-search-closed-ax5-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-chats-search-closed-ax5-dark.png" width="160">
Activity, keyboard up <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-keyboard-default-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-keyboard-default-dark.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-keyboard-ax5-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-keyboard-ax5-dark.png" width="160">
Activity, term kept after blur <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-term-kept-default-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-term-kept-default-dark.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-term-kept-ax5-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-term-kept-ax5-dark.png" width="160">
Activity, reopened <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-reopened-default-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-reopened-default-dark.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-reopened-ax5-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-reopened-ax5-dark.png" width="160">
Activity, closed with ✕ <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-closed-default-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-closed-default-dark.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-closed-ax5-light.png" width="160"> <img src="https://raw.githubusercontent.com/botharness/deepseekbot/8b66aaca0119d5079019f63a307a67acd967af92/.github/pr-screenshots/chats-header-search/ios-activity-search-closed-ax5-dark.png" width="160">

Not caused by this PR: at AX5, the Activity segment labels break mid-word ("Nee/ds/you", "Oth/er/unre/ad").


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants