diff options
author | Eric Bailey <git@esb.lol> | 2025-04-16 18:42:41 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-16 18:42:41 -0500 |
commit | faab49bd9eabe43c3493b2a20c1460accaad45ba (patch) | |
tree | 22f94e53798ef3dee653bc41b8353f9a7e41ca58 | |
parent | fb8ab9f26d9d6b24fa40ce2f54057470fe3ff1de (diff) | |
download | voidsky-faab49bd9eabe43c3493b2a20c1460accaad45ba.tar.zst |
ALF search cards (#8210)
-rw-r--r-- | src/screens/Search/components/AutocompleteResults.tsx | 9 | ||||
-rw-r--r-- | src/screens/Search/components/SearchProfileCard.tsx | 62 | ||||
-rw-r--r-- | src/view/shell/desktop/Search.tsx | 92 |
3 files changed, 78 insertions, 85 deletions
diff --git a/src/screens/Search/components/AutocompleteResults.tsx b/src/screens/Search/components/AutocompleteResults.tsx index 58a0dec77..b3bccd1d4 100644 --- a/src/screens/Search/components/AutocompleteResults.tsx +++ b/src/screens/Search/components/AutocompleteResults.tsx @@ -1,12 +1,13 @@ import {memo} from 'react' import {ActivityIndicator, View} from 'react-native' -import {type AppBskyActorDefs, moderateProfile} from '@atproto/api' +import {type AppBskyActorDefs} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {isNative} from '#/platform/detection' import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {SearchLinkCard, SearchProfileCard} from '#/view/shell/desktop/Search' +import {SearchLinkCard} from '#/view/shell/desktop/Search' +import {SearchProfileCard} from '#/screens/Search/components/SearchProfileCard' import {atoms as a, native} from '#/alf' import * as Layout from '#/components/Layout' @@ -25,8 +26,8 @@ let AutocompleteResults = ({ onResultPress: () => void onProfileClick: (profile: AppBskyActorDefs.ProfileViewBasic) => void }): React.ReactNode => { - const moderationOpts = useModerationOpts() const {_} = useLingui() + const moderationOpts = useModerationOpts() return ( <> {(isAutocompleteFetching && !autocompleteData?.length) || @@ -54,7 +55,7 @@ let AutocompleteResults = ({ <SearchProfileCard key={item.did} profile={item} - moderation={moderateProfile(item, moderationOpts)} + moderationOpts={moderationOpts} onPress={() => { onProfileClick(item) onResultPress() diff --git a/src/screens/Search/components/SearchProfileCard.tsx b/src/screens/Search/components/SearchProfileCard.tsx new file mode 100644 index 000000000..69a12cc0a --- /dev/null +++ b/src/screens/Search/components/SearchProfileCard.tsx @@ -0,0 +1,62 @@ +import {useCallback} from 'react' +import {View} from 'react-native' +import {type AppBskyActorDefs, type ModerationOpts} from '@atproto/api' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useQueryClient} from '@tanstack/react-query' + +import {makeProfileLink} from '#/lib/routes/links' +import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache' +import {atoms as a, useTheme} from '#/alf' +import {Link} from '#/components/Link' +import * as ProfileCard from '#/components/ProfileCard' + +export function SearchProfileCard({ + profile, + moderationOpts, + onPress: onPressInner, +}: { + profile: AppBskyActorDefs.ProfileViewBasic + moderationOpts: ModerationOpts + onPress?: () => void +}) { + const t = useTheme() + const {_} = useLingui() + const qc = useQueryClient() + + const onPress = useCallback(() => { + unstableCacheProfileView(qc, profile) + onPressInner?.() + }, [qc, profile, onPressInner]) + + return ( + <Link + testID={`searchAutoCompleteResult-${profile.handle}`} + to={makeProfileLink(profile)} + label={_(msg`View ${profile.handle}'s profile`)} + onPress={onPress}> + {({hovered, pressed}) => ( + <View + style={[ + a.flex_1, + a.px_md, + a.py_sm, + (hovered || pressed) && t.atoms.bg_contrast_25, + ]}> + <ProfileCard.Outer> + <ProfileCard.Header> + <ProfileCard.Avatar + profile={profile} + moderationOpts={moderationOpts} + /> + <ProfileCard.NameAndHandle + profile={profile} + moderationOpts={moderationOpts} + /> + </ProfileCard.Header> + </ProfileCard.Outer> + </View> + )} + </Link> + ) +} diff --git a/src/view/shell/desktop/Search.tsx b/src/view/shell/desktop/Search.tsx index de3ccad39..38da4e246 100644 --- a/src/view/shell/desktop/Search.tsx +++ b/src/view/shell/desktop/Search.tsx @@ -4,30 +4,19 @@ import { StyleSheet, TouchableOpacity, View, - ViewStyle, + type ViewStyle, } from 'react-native' -import { - AppBskyActorDefs, - moderateProfile, - ModerationDecision, -} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {StackActions, useNavigation} from '@react-navigation/native' -import {useQueryClient} from '@tanstack/react-query' import {usePalette} from '#/lib/hooks/usePalette' -import {makeProfileLink} from '#/lib/routes/links' -import {NavigationProp} from '#/lib/routes/types' -import {sanitizeDisplayName} from '#/lib/strings/display-names' -import {sanitizeHandle} from '#/lib/strings/handles' -import {s} from '#/lib/styles' +import {type NavigationProp} from '#/lib/routes/types' import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' -import {precacheProfile} from '#/state/queries/profile' import {Link} from '#/view/com/util/Link' import {Text} from '#/view/com/util/text/Text' -import {UserAvatar} from '#/view/com/util/UserAvatar' +import {SearchProfileCard} from '#/screens/Search/components/SearchProfileCard' import {atoms as a} from '#/alf' import {SearchInput} from '#/components/forms/SearchInput' @@ -82,71 +71,6 @@ let SearchLinkCard = ({ SearchLinkCard = React.memo(SearchLinkCard) export {SearchLinkCard} -let SearchProfileCard = ({ - profile, - moderation, - onPress: onPressInner, -}: { - profile: AppBskyActorDefs.ProfileViewBasic - moderation: ModerationDecision - onPress: () => void -}): React.ReactNode => { - const pal = usePalette('default') - const queryClient = useQueryClient() - - const onPress = React.useCallback(() => { - precacheProfile(queryClient, profile) - onPressInner() - }, [queryClient, profile, onPressInner]) - - return ( - <Link - testID={`searchAutoCompleteResult-${profile.handle}`} - href={makeProfileLink(profile)} - title={profile.handle} - asAnchor - anchorNoUnderline - onBeforePress={onPress}> - <View - style={[ - pal.border, - { - flexDirection: 'row', - alignItems: 'center', - gap: 12, - paddingVertical: 8, - paddingHorizontal: 12, - }, - ]}> - <UserAvatar - size={40} - avatar={profile.avatar} - moderation={moderation.ui('avatar')} - type={profile.associated?.labeler ? 'labeler' : 'user'} - /> - <View style={{flex: 1}}> - <Text - emoji - type="lg" - style={[s.bold, pal.text, a.self_start]} - numberOfLines={1} - lineHeight={1.2}> - {sanitizeDisplayName( - profile.displayName || sanitizeHandle(profile.handle), - moderation.ui('displayName'), - )} - </Text> - <Text type="md" style={[pal.textLight]} numberOfLines={1}> - {sanitizeHandle(profile.handle, '@')} - </Text> - </View> - </View> - </Link> - ) -} -SearchProfileCard = React.memo(SearchProfileCard) -export {SearchProfileCard} - export function DesktopSearch() { const {_} = useLingui() const pal = usePalette('default') @@ -190,7 +114,13 @@ export function DesktopSearch() { onSubmitEditing={onSubmit} /> {query !== '' && isActive && moderationOpts && ( - <View style={[pal.view, pal.borderDark, styles.resultsContainer]}> + <View + style={[ + pal.view, + pal.borderDark, + styles.resultsContainer, + a.overflow_hidden, + ]}> {isFetching && !autocompleteData?.length ? ( <View style={{padding: 8}}> <ActivityIndicator /> @@ -210,7 +140,7 @@ export function DesktopSearch() { <SearchProfileCard key={item.did} profile={item} - moderation={moderateProfile(item, moderationOpts)} + moderationOpts={moderationOpts} onPress={onSearchProfileCardPress} /> ))} |