Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update Search to use ALF atoms (#10146)

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

authored by

DS Boyce
Samuel Newman
and committed by
GitHub
e8ee3039 68971166

+59 -69
+59 -69
src/view/shell/desktop/Search.tsx
··· 1 1 import {memo, useCallback, useState} from 'react' 2 2 import { 3 - ActivityIndicator, 4 - StyleSheet, 3 + type StyleProp, 5 4 TouchableOpacity, 6 5 View, 7 6 type ViewStyle, ··· 9 8 import {useLingui} from '@lingui/react/macro' 10 9 import {StackActions, useNavigation} from '@react-navigation/native' 11 10 12 - import {usePalette} from '#/lib/hooks/usePalette' 13 11 import {type NavigationProp} from '#/lib/routes/types' 14 12 import {useModerationOpts} from '#/state/preferences/moderation-opts' 15 13 import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' 16 - import {Link} from '#/view/com/util/Link' 17 - import {Text} from '#/view/com/util/text/Text' 18 14 import {SearchProfileCard} from '#/screens/Search/components/SearchProfileCard' 19 - import {atoms as a} from '#/alf' 15 + import {atoms as a, useTheme} from '#/alf' 20 16 import {SearchInput} from '#/components/forms/SearchInput' 17 + import {Link} from '#/components/Link' 18 + import {Loader} from '#/components/Loader' 19 + import {Text} from '#/components/Typography' 20 + 21 + const WHITESPACE_RE = /\s+/gu 21 22 22 23 let SearchLinkCard = ({ 23 24 label, ··· 28 29 label: string 29 30 to?: string 30 31 onPress?: () => void 31 - style?: ViewStyle 32 + style?: StyleProp<ViewStyle> 32 33 }): React.ReactNode => { 33 - const pal = usePalette('default') 34 + const t = useTheme() 34 35 35 36 const inner = ( 36 - <View 37 - style={[pal.border, {paddingVertical: 16, paddingHorizontal: 12}, style]}> 38 - <Text type="md" style={[pal.text]}> 39 - {label} 40 - </Text> 37 + <View style={[a.py_lg, a.px_md, t.atoms.border_contrast_low, style]}> 38 + <Text style={[a.text_md, t.atoms.text]}>{label}</Text> 41 39 </View> 42 40 ) 43 41 44 - if (onPress) { 42 + if (onPress || !to) { 45 43 return ( 46 44 <TouchableOpacity 47 45 onPress={onPress} ··· 53 51 } 54 52 55 53 return ( 56 - <Link href={to} asAnchor anchorNoUnderline> 57 - <View 58 - style={[ 59 - pal.border, 60 - {paddingVertical: 16, paddingHorizontal: 12}, 61 - style, 62 - ]}> 63 - <Text type="md" style={[pal.text]}> 64 - {label} 65 - </Text> 66 - </View> 54 + <Link 55 + label={label} 56 + to={to} 57 + style={[a.py_lg, a.px_md, t.atoms.border_contrast_low, style]} 58 + hoverStyle={[t.atoms.bg_contrast_25]}> 59 + <Text style={[a.text_md, t.atoms.text]}>{label}</Text> 67 60 </Link> 68 61 ) 69 62 } ··· 71 64 export {SearchLinkCard} 72 65 73 66 export function DesktopSearch() { 67 + const t = useTheme() 74 68 const {t: l} = useLingui() 75 - const pal = usePalette('default') 76 69 const navigation = useNavigation<NavigationProp>() 77 70 const [isActive, setIsActive] = useState<boolean>(false) 78 71 const [query, setQuery] = useState<string>('') ··· 80 73 query, 81 74 true, 82 75 ) 76 + const tQuery = query.replace(WHITESPACE_RE, ' ').trim() 83 77 84 78 const moderationOpts = useModerationOpts() 85 79 ··· 95 89 96 90 const onSubmit = useCallback(() => { 97 91 setIsActive(false) 98 - if (!query.length) return 99 - navigation.dispatch(StackActions.push('Search', {q: query})) 100 - }, [query, navigation]) 92 + if (!tQuery.length) return 93 + navigation.dispatch(StackActions.push('Search', {q: tQuery})) 94 + }, [tQuery, navigation]) 101 95 102 96 const onSearchProfileCardPress = useCallback(() => { 103 97 setQuery('') ··· 105 99 }, []) 106 100 107 101 return ( 108 - <View style={[styles.container, pal.view]}> 102 + <View style={[a.relative, a.w_full, a.z_10, t.atoms.bg]}> 109 103 <SearchInput 110 104 value={query} 111 105 onChangeText={onChangeText} 112 106 onClearText={onPressCancelSearch} 113 107 onSubmitEditing={onSubmit} 114 108 /> 115 - {query !== '' && isActive && moderationOpts && ( 109 + {tQuery !== '' && isActive && moderationOpts && ( 116 110 <View 117 111 style={[ 118 - pal.view, 119 - pal.borderDark, 120 - styles.resultsContainer, 121 - a.overflow_hidden, 112 + a.mt_sm, 113 + a.flex_col, 114 + a.w_full, 115 + a.border, 116 + a.rounded_sm, 117 + a.zoom_fade_in, 118 + t.atoms.bg, 119 + t.atoms.shadow_sm, 120 + t.atoms.border_contrast_low, 121 + { 122 + overflow: 'hidden', 123 + position: 'absolute', 124 + top: '100%', 125 + }, 122 126 ]}> 127 + <SearchLinkCard 128 + label={l`Search for “${tQuery}”`} 129 + to={`/search?q=${encodeURIComponent(tQuery)}`} 130 + style={(autocompleteData?.length ?? 0) > 0 ? a.border_b : undefined} 131 + /> 123 132 {isFetching && !autocompleteData?.length ? ( 124 - <View style={{padding: 8}}> 125 - <ActivityIndicator /> 133 + <View 134 + style={[ 135 + a.py_lg, 136 + a.align_center, 137 + a.border_t, 138 + t.atoms.border_contrast_low, 139 + ]}> 140 + <Loader size="lg" /> 126 141 </View> 127 142 ) : ( 128 - <> 129 - <SearchLinkCard 130 - label={l`Search for "${query}"`} 131 - to={`/search?q=${encodeURIComponent(query)}`} 132 - style={ 133 - (autocompleteData?.length ?? 0) > 0 134 - ? {borderBottomWidth: 1} 135 - : undefined 136 - } 143 + autocompleteData?.map(item => ( 144 + <SearchProfileCard 145 + key={item.did} 146 + profile={item} 147 + moderationOpts={moderationOpts} 148 + onPress={onSearchProfileCardPress} 137 149 /> 138 - {autocompleteData?.map(item => ( 139 - <SearchProfileCard 140 - key={item.did} 141 - profile={item} 142 - moderationOpts={moderationOpts} 143 - onPress={onSearchProfileCardPress} 144 - /> 145 - ))} 146 - </> 150 + )) 147 151 )} 148 152 </View> 149 153 )} 150 154 </View> 151 155 ) 152 156 } 153 - 154 - const styles = StyleSheet.create({ 155 - container: { 156 - position: 'relative', 157 - width: '100%', 158 - }, 159 - resultsContainer: { 160 - marginTop: 10, 161 - flexDirection: 'column', 162 - width: '100%', 163 - borderWidth: 1, 164 - borderRadius: 6, 165 - }, 166 - })