Add search button to header on feeds screen (#2848)

* add search bar to header

* add button on web
zio/stable
Hailey 2024-02-12 13:47:48 -08:00 committed by GitHub
parent ba7463cadf
commit b936da1c0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 127 additions and 73 deletions

View File

@ -26,14 +26,23 @@ interface Props {
onSubmitQuery: () => void onSubmitQuery: () => void
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
} }
export function SearchInput({
export interface SearchInputRef {
focus?: () => void
}
export const SearchInput = React.forwardRef<SearchInputRef, Props>(
function SearchInput(
{
query, query,
setIsInputFocused, setIsInputFocused,
onChangeQuery, onChangeQuery,
onPressCancelSearch, onPressCancelSearch,
onSubmitQuery, onSubmitQuery,
style, style,
}: Props) { },
ref,
) {
const theme = useTheme() const theme = useTheme()
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
@ -44,6 +53,11 @@ export function SearchInput({
textInput.current?.blur() textInput.current?.blur()
}, [onPressCancelSearch, textInput]) }, [onPressCancelSearch, textInput])
React.useImperativeHandle(ref, () => ({
focus: () => textInput.current?.focus(),
blur: () => textInput.current?.blur(),
}))
return ( return (
<View style={[pal.viewLight, styles.container, style]}> <View style={[pal.viewLight, styles.container, style]}>
<MagnifyingGlassIcon style={[pal.icon, styles.icon]} size={21} /> <MagnifyingGlassIcon style={[pal.icon, styles.icon]} size={21} />
@ -83,7 +97,8 @@ export function SearchInput({
) : undefined} ) : undefined}
</View> </View>
) )
} },
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {

View File

@ -1,5 +1,11 @@
import React from 'react' import React from 'react'
import {ActivityIndicator, StyleSheet, View, type FlatList} from 'react-native' import {
ActivityIndicator,
StyleSheet,
View,
type FlatList,
Pressable,
} from 'react-native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
import {ViewHeader} from 'view/com/util/ViewHeader' import {ViewHeader} from 'view/com/util/ViewHeader'
@ -8,9 +14,9 @@ import {Link} from 'view/com/util/Link'
import {NativeStackScreenProps, FeedsTabNavigatorParams} from 'lib/routes/types' import {NativeStackScreenProps, FeedsTabNavigatorParams} from 'lib/routes/types'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {ComposeIcon2, CogIcon} from 'lib/icons' import {ComposeIcon2, CogIcon, MagnifyingGlassIcon2} from 'lib/icons'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {SearchInput} from 'view/com/util/forms/SearchInput' import {SearchInput, SearchInputRef} from 'view/com/util/forms/SearchInput'
import {UserAvatar} from 'view/com/util/UserAvatar' import {UserAvatar} from 'view/com/util/UserAvatar'
import { import {
LoadingPlaceholder, LoadingPlaceholder,
@ -36,6 +42,7 @@ import {cleanError} from 'lib/strings/errors'
import {useComposerControls} from '#/state/shell/composer' import {useComposerControls} from '#/state/shell/composer'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
import {HITSLOP_10} from 'lib/constants'
type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'> type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
@ -121,6 +128,7 @@ export function FeedsScreen(_props: Props) {
} = useSearchPopularFeedsMutation() } = useSearchPopularFeedsMutation()
const {hasSession} = useSession() const {hasSession} = useSession()
const listRef = React.useRef<FlatList>(null) const listRef = React.useRef<FlatList>(null)
const searchInputRef = React.useRef<SearchInputRef>(null)
/** /**
* A search query is present. We may not have search results yet. * A search query is present. We may not have search results yet.
@ -330,6 +338,17 @@ export function FeedsScreen(_props: Props) {
const renderHeaderBtn = React.useCallback(() => { const renderHeaderBtn = React.useCallback(() => {
return ( return (
<View style={styles.headerBtnGroup}>
<Pressable
accessibilityRole="button"
hitSlop={HITSLOP_10}
onPress={searchInputRef.current?.focus}>
<MagnifyingGlassIcon2
size={22}
strokeWidth={2}
style={pal.textLight}
/>
</Pressable>
<Link <Link
href="/settings/saved-feeds" href="/settings/saved-feeds"
hitSlop={10} hitSlop={10}
@ -338,6 +357,7 @@ export function FeedsScreen(_props: Props) {
accessibilityHint={_(msg`Opens screen to edit Saved Feeds`)}> accessibilityHint={_(msg`Opens screen to edit Saved Feeds`)}>
<CogIcon size={22} strokeWidth={2} style={pal.textLight} /> <CogIcon size={22} strokeWidth={2} style={pal.textLight} />
</Link> </Link>
</View>
) )
}, [pal, _]) }, [pal, _])
@ -398,6 +418,17 @@ export function FeedsScreen(_props: Props) {
<Text type="title-lg" style={[pal.text, s.bold]}> <Text type="title-lg" style={[pal.text, s.bold]}>
<Trans>My Feeds</Trans> <Trans>My Feeds</Trans>
</Text> </Text>
<View style={styles.headerBtnGroup}>
<Pressable
accessibilityRole="button"
hitSlop={HITSLOP_10}
onPress={searchInputRef.current?.focus}>
<MagnifyingGlassIcon2
size={22}
strokeWidth={2}
style={pal.icon}
/>
</Pressable>
<Link <Link
href="/settings/saved-feeds" href="/settings/saved-feeds"
accessibilityLabel={_(msg`Edit My Feeds`)} accessibilityLabel={_(msg`Edit My Feeds`)}
@ -405,6 +436,7 @@ export function FeedsScreen(_props: Props) {
<CogIcon strokeWidth={1.5} style={pal.icon} size={28} /> <CogIcon strokeWidth={1.5} style={pal.icon} size={28} />
</Link> </Link>
</View> </View>
</View>
) )
} }
return <View /> return <View />
@ -443,6 +475,7 @@ export function FeedsScreen(_props: Props) {
{!isMobile && ( {!isMobile && (
<SearchInput <SearchInput
ref={searchInputRef}
query={query} query={query}
onChangeQuery={onChangeQuery} onChangeQuery={onChangeQuery}
onPressCancelSearch={onPressCancelSearch} onPressCancelSearch={onPressCancelSearch}
@ -456,6 +489,7 @@ export function FeedsScreen(_props: Props) {
{isMobile && ( {isMobile && (
<View style={{paddingHorizontal: 8, paddingBottom: 10}}> <View style={{paddingHorizontal: 8, paddingBottom: 10}}>
<SearchInput <SearchInput
ref={searchInputRef}
query={query} query={query}
onChangeQuery={onChangeQuery} onChangeQuery={onChangeQuery}
onPressCancelSearch={onPressCancelSearch} onPressCancelSearch={onPressCancelSearch}
@ -663,4 +697,9 @@ const styles = StyleSheet.create({
paddingHorizontal: 4, paddingHorizontal: 4,
paddingVertical: 2, paddingVertical: 2,
}, },
headerBtnGroup: {
flexDirection: 'row',
gap: 15,
alignItems: 'center',
},
}) })