this repo has no description
0
fork

Configure Feed

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

at e28f6d2f370b4e882ed6f23d08ca0f8d94dbac5f 135 lines 3.7 kB view raw
1import {View} from 'react-native' 2import Animated, {FadeInDown, FadeOut} from 'react-native-reanimated' 3import {type AppBskyActorDefs} from '@atproto/api' 4import {Trans} from '@lingui/react/macro' 5 6import {PressableScale} from '#/lib/custom-animations/PressableScale' 7import {sanitizeDisplayName} from '#/lib/strings/display-names' 8import {sanitizeHandle} from '#/lib/strings/handles' 9import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' 10import {UserAvatar} from '#/view/com/util/UserAvatar' 11import {atoms as a, platform, useTheme} from '#/alf' 12import {ProfileBadges} from '#/components/ProfileBadges' 13import {Text} from '#/components/Typography' 14 15export function Autocomplete({ 16 prefix, 17 onSelect, 18}: { 19 prefix: string 20 onSelect: (item: string) => void 21}) { 22 const t = useTheme() 23 24 const isActive = !!prefix 25 const {data: suggestions, isFetching} = useActorAutocompleteQuery( 26 prefix, 27 true, 28 ) 29 30 if (!isActive) return null 31 32 return ( 33 <Animated.View 34 entering={FadeInDown.duration(200)} 35 exiting={FadeOut.duration(100)} 36 style={[ 37 t.atoms.bg, 38 a.mt_sm, 39 a.border, 40 a.rounded_sm, 41 t.atoms.border_contrast_high, 42 {marginLeft: -62}, 43 ]}> 44 {suggestions?.length ? ( 45 suggestions.slice(0, 5).map((item, index, arr) => { 46 return ( 47 <AutocompleteProfileCard 48 key={item.did} 49 profile={item} 50 itemIndex={index} 51 totalItems={arr.length} 52 onPress={() => { 53 onSelect(item.handle) 54 }} 55 /> 56 ) 57 }) 58 ) : ( 59 <Text style={[a.text_md, a.px_sm, a.py_md]}> 60 {isFetching ? <Trans>Loading...</Trans> : <Trans>No result</Trans>} 61 </Text> 62 )} 63 </Animated.View> 64 ) 65} 66 67function AutocompleteProfileCard({ 68 profile, 69 itemIndex, 70 totalItems, 71 onPress, 72}: { 73 profile: AppBskyActorDefs.ProfileViewBasic 74 itemIndex: number 75 totalItems: number 76 onPress: () => void 77}) { 78 const t = useTheme() 79 const displayName = sanitizeDisplayName( 80 profile.displayName || sanitizeHandle(profile.handle), 81 ) 82 return ( 83 <View 84 style={[ 85 itemIndex !== totalItems - 1 && a.border_b, 86 t.atoms.border_contrast_high, 87 a.px_sm, 88 a.py_md, 89 ]} 90 key={profile.did}> 91 <PressableScale 92 testID="autocompleteButton" 93 style={[a.flex_row, a.gap_lg, a.justify_between, a.align_center]} 94 onPress={onPress} 95 accessibilityLabel={`Select ${profile.handle}`} 96 accessibilityHint=""> 97 <View style={[a.flex_row, a.gap_sm, a.align_center, a.flex_1]}> 98 <UserAvatar 99 avatar={profile.avatar ?? null} 100 size={24} 101 type={profile.associated?.labeler ? 'labeler' : 'user'} 102 /> 103 <View 104 style={[ 105 a.flex_row, 106 a.align_center, 107 a.gap_xs, 108 platform({ios: a.flex_1}), 109 ]}> 110 <Text 111 style={[a.text_md, a.font_semi_bold, a.leading_snug]} 112 emoji 113 numberOfLines={1}> 114 {displayName} 115 </Text> 116 <ProfileBadges 117 profile={profile} 118 size="sm" 119 style={[ 120 { 121 marginTop: platform({android: -2}), 122 }, 123 ]} 124 /> 125 </View> 126 </View> 127 <Text 128 style={[t.atoms.text_contrast_medium, a.text_right, a.leading_snug]} 129 numberOfLines={1}> 130 {sanitizeHandle(profile.handle, '@')} 131 </Text> 132 </PressableScale> 133 </View> 134 ) 135}