Auto-select search results tab (#9159)

When the user clicks the search button next to "Discover New Feeds" or "Suggested Accounts" on the Explore page, we'll auto-select the respective search results tab (feeds or users).
This commit is contained in:
Alex Benzer
2025-10-09 05:02:38 -07:00
committed by GitHub
parent d68fc78e93
commit b38edc52b8
4 changed files with 80 additions and 18 deletions
+4 -4
View File
@@ -67,7 +67,7 @@ export type CommonNavigatorParams = {
InterestsSettings: undefined
AboutSettings: undefined
AppIconSettings: undefined
Search: {q?: string}
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
Hashtag: {tag: string; author?: string}
Topic: {topic: string}
MessagesConversation: {conversation: string; embed?: string; accept?: true}
@@ -102,7 +102,7 @@ export type HomeTabNavigatorParams = CommonNavigatorParams & {
}
export type SearchTabNavigatorParams = CommonNavigatorParams & {
Search: {q?: string}
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
}
export type NotificationsTabNavigatorParams = CommonNavigatorParams & {
@@ -119,7 +119,7 @@ export type MessagesTabNavigatorParams = CommonNavigatorParams & {
export type FlatNavigatorParams = CommonNavigatorParams & {
Home: undefined
Search: {q?: string}
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
Feeds: undefined
Notifications: undefined
Messages: {pushToConversation?: string; animation?: 'push' | 'pop'}
@@ -129,7 +129,7 @@ export type AllNavigatorParams = CommonNavigatorParams & {
HomeTab: undefined
Home: undefined
SearchTab: undefined
Search: {q?: string}
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
Feeds: undefined
NotificationsTab: undefined
Notifications: undefined
+12 -2
View File
@@ -726,7 +726,12 @@ export function Explore({
<ModuleHeader.SearchButton
{...item.searchButton}
onPress={() =>
focusSearchInput(item.searchButton?.tab || 'user')
focusSearchInput(
(item.searchButton?.tab || 'user') as
| 'user'
| 'profile'
| 'feed',
)
}
/>
)}
@@ -743,7 +748,12 @@ export function Explore({
<ModuleHeader.SearchButton
{...item.searchButton}
onPress={() =>
focusSearchInput(item.searchButton?.tab || 'user')
focusSearchInput(
(item.searchButton?.tab || 'user') as
| 'user'
| 'profile'
| 'feed',
)
}
/>
)}
+3 -1
View File
@@ -30,12 +30,14 @@ let SearchResults = ({
activeTab,
onPageSelected,
headerHeight,
initialPage = 0,
}: {
query: string
queryWithParams: string
activeTab: number
onPageSelected: (page: number) => void
headerHeight: number
initialPage?: number
}): React.ReactNode => {
const {_} = useLingui()
@@ -89,7 +91,7 @@ let SearchResults = ({
<TabBar items={sections.map(section => section.title)} {...props} />
</Layout.Center>
)}
initialPage={0}>
initialPage={initialPage}>
{sections.map((section, i) => (
<View key={i}>{section.component}</View>
))}
+61 -11
View File
@@ -190,15 +190,19 @@ export function SearchScreenShell({
setShowAutocomplete(false)
if (isWeb) {
// Empty params resets the URL to be /search rather than /search?q=
const {q: _q, ...parameters} = (route.params ?? {}) as {
// Also clear the tab parameter
const {
q: _q,
tab: _tab,
...parameters
} = (route.params ?? {}) as {
[key: string]: string
}
// @ts-expect-error route is not typesafe
navigation.replace(route.name, parameters)
} else {
setSearchText('')
navigation.setParams({q: ''})
navigation.setParams({q: '', tab: undefined})
}
}, [setShowAutocomplete, setSearchText, navigation, route.params, route.name])
@@ -236,15 +240,19 @@ export function SearchScreenShell({
const onSoftReset = useCallback(() => {
if (isWeb) {
// Empty params resets the URL to be /search rather than /search?q=
const {q: _q, ...parameters} = (route.params ?? {}) as {
// Also clear the tab parameter when soft resetting
const {
q: _q,
tab: _tab,
...parameters
} = (route.params ?? {}) as {
[key: string]: string
}
// @ts-expect-error route is not typesafe
navigation.replace(route.name, parameters)
} else {
setSearchText('')
navigation.setParams({q: ''})
navigation.setParams({q: '', tab: undefined})
textInput.current?.focus()
}
}, [navigation, route])
@@ -268,9 +276,21 @@ export function SearchScreenShell({
}
}, [setShowAutocomplete])
const focusSearchInput = useCallback(() => {
textInput.current?.focus()
}, [])
const focusSearchInput = useCallback(
(tab?: 'user' | 'profile' | 'feed') => {
textInput.current?.focus()
// If a tab is specified, set the tab parameter
if (tab) {
if (isWeb) {
navigation.setParams({...route.params, tab})
} else {
navigation.setParams({tab})
}
}
},
[navigation, route],
)
const showHeader = !gtMobile || navButton !== 'menu'
@@ -421,13 +441,42 @@ let SearchScreenInner = ({
query: string
queryWithParams: string
headerHeight: number
focusSearchInput: () => void
focusSearchInput: (tab?: 'user' | 'profile' | 'feed') => void
}): React.ReactNode => {
const t = useTheme()
const setMinimalShellMode = useSetMinimalShellMode()
const {hasSession} = useSession()
const {gtTablet} = useBreakpoints()
const [activeTab, setActiveTab] = useState(0)
const route = useRoute()
// Get tab parameter from route params
const tabParam = (
route.params as {q?: string; tab?: 'user' | 'profile' | 'feed'}
)?.tab
// Map tab parameter to tab index
const getInitialTabIndex = useCallback(() => {
if (!tabParam) return 0
switch (tabParam) {
case 'user':
case 'profile':
return 2 // People tab
case 'feed':
return 3 // Feeds tab
default:
return 0
}
}, [tabParam])
const [activeTab, setActiveTab] = useState(getInitialTabIndex())
// Update activeTab when tabParam changes
useLayoutEffect(() => {
const newTabIndex = getInitialTabIndex()
if (newTabIndex !== activeTab) {
setActiveTab(newTabIndex)
}
}, [tabParam, activeTab, getInitialTabIndex])
const onPageSelected = useCallback(
(index: number) => {
@@ -444,6 +493,7 @@ let SearchScreenInner = ({
activeTab={activeTab}
headerHeight={headerHeight}
onPageSelected={onPageSelected}
initialPage={activeTab}
/>
) : hasSession ? (
<Explore focusSearchInput={focusSearchInput} headerHeight={headerHeight} />