Refactor search history

This commit is contained in:
Eric Bailey
2025-04-21 18:02:27 -05:00
parent 3f47c8cf06
commit 2b27d346ca
2 changed files with 73 additions and 107 deletions
+1 -1
View File
@@ -112,7 +112,7 @@ export function SearchScreenShell({
const newAccountHistory = [ const newAccountHistory = [
item.did, item.did,
...accountHistory.filter(p => p !== item.did), ...accountHistory.filter(p => p !== item.did),
].slice(0, 5) ].slice(0, 10)
setAccountHistory(newAccountHistory) setAccountHistory(newAccountHistory)
}, },
[accountHistory, setAccountHistory], [accountHistory, setAccountHistory],
+54 -88
View File
@@ -1,4 +1,4 @@
import {Pressable, ScrollView, StyleSheet, View} from 'react-native' import {Pressable, ScrollView, View} from 'react-native'
import {moderateProfile, type ModerationOpts} from '@atproto/api' import {moderateProfile, type ModerationOpts} from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
@@ -8,13 +8,13 @@ import {makeProfileLink} from '#/lib/routes/links'
import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles' import {sanitizeHandle} from '#/lib/strings/handles'
import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {Link} from '#/view/com/util/Link'
import {UserAvatar} from '#/view/com/util/UserAvatar' import {UserAvatar} from '#/view/com/util/UserAvatar'
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture' import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
import {atoms as a, tokens, useBreakpoints, useTheme, web} from '#/alf' import {atoms as a} from '#/alf'
import {Button, ButtonIcon} from '#/components/Button' import {Button, ButtonIcon} from '#/components/Button'
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times' import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
import * as Layout from '#/components/Layout' import * as Layout from '#/components/Layout'
import {Link} from '#/components/Link'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {useSimpleVerificationState} from '#/components/verification' import {useSimpleVerificationState} from '#/components/verification'
import {VerificationCheck} from '#/components/verification/VerificationCheck' import {VerificationCheck} from '#/components/verification/VerificationCheck'
@@ -35,7 +35,6 @@ export function SearchHistory({
onRemoveItemClick: (item: string) => void onRemoveItemClick: (item: string) => void
onRemoveProfileClick: (profile: bsky.profile.AnyProfileView) => void onRemoveProfileClick: (profile: bsky.profile.AnyProfileView) => void
}) { }) {
const {gtMobile} = useBreakpoints()
const {_} = useLingui() const {_} = useLingui()
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
@@ -43,33 +42,30 @@ export function SearchHistory({
<Layout.Content <Layout.Content
keyboardDismissMode="interactive" keyboardDismissMode="interactive"
keyboardShouldPersistTaps="handled"> keyboardShouldPersistTaps="handled">
<View style={[a.w_full, a.px_md]}> <View style={[a.w_full, a.gap_md]}>
{(searchHistory.length > 0 || selectedProfiles.length > 0) && ( {(searchHistory.length > 0 || selectedProfiles.length > 0) && (
<Text style={[a.text_md, a.font_bold, a.p_md]}> <View style={[a.px_lg, a.pt_sm]}>
<Text style={[a.text_md, a.font_bold]}>
<Trans>Recent Searches</Trans> <Trans>Recent Searches</Trans>
</Text> </Text>
</View>
)} )}
{selectedProfiles.length > 0 && ( {selectedProfiles.length > 0 && (
<View <View>
style={[
styles.selectedProfilesContainer,
!gtMobile && styles.selectedProfilesContainerMobile,
]}>
<BlockDrawerGesture> <BlockDrawerGesture>
<ScrollView <ScrollView
horizontal horizontal
keyboardShouldPersistTaps="handled" keyboardShouldPersistTaps="handled"
showsHorizontalScrollIndicator={false} showsHorizontalScrollIndicator={false}
style={[ contentContainerStyle={[
a.px_lg,
a.flex_row, a.flex_row,
a.flex_nowrap, a.flex_nowrap,
{marginHorizontal: tokens.space._2xl * -1}, a.gap_xl,
]} ]}>
contentContainerStyle={[a.px_2xl, a.border_0]}>
{moderationOpts && {moderationOpts &&
selectedProfiles selectedProfiles.map(profile => (
.slice(0, 5)
.map(profile => (
<RecentProfileItem <RecentProfileItem
key={profile.did} key={profile.did}
profile={profile} profile={profile}
@@ -82,15 +78,16 @@ export function SearchHistory({
</BlockDrawerGesture> </BlockDrawerGesture>
</View> </View>
)} )}
{searchHistory.length > 0 && ( {searchHistory.length > 0 && (
<View style={[a.pl_md, a.pr_xs, a.mt_md]}> <View style={[a.px_lg, a.pt_sm]}>
{searchHistory.slice(0, 5).map((historyItem, index) => ( {searchHistory.slice(0, 5).map((historyItem, index) => (
<View key={index} style={[a.flex_row, a.align_center, a.mt_xs]}> <View key={index} style={[a.flex_row, a.align_center]}>
<Pressable <Pressable
accessibilityRole="button" accessibilityRole="button"
onPress={() => onItemClick(historyItem)} onPress={() => onItemClick(historyItem)}
hitSlop={HITSLOP_10} hitSlop={HITSLOP_10}
style={[a.flex_1, a.py_md]}> style={[a.flex_1, a.py_sm]}>
<Text style={[a.text_md]}>{historyItem}</Text> <Text style={[a.text_md]}>{historyItem}</Text>
</Pressable> </Pressable>
<Button <Button
@@ -123,8 +120,7 @@ function RecentProfileItem({
onRemove: () => void onRemove: () => void
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const {gtMobile} = useBreakpoints() const width = 80
const t = useTheme()
const moderation = moderateProfile(profile, moderationOpts) const moderation = moderateProfile(profile, moderationOpts)
const name = sanitizeDisplayName( const name = sanitizeDisplayName(
@@ -134,88 +130,58 @@ function RecentProfileItem({
const verification = useSimpleVerificationState({profile}) const verification = useSimpleVerificationState({profile})
return ( return (
<View style={[styles.profileItem, !gtMobile && styles.profileItemMobile]}> <View style={[a.relative]}>
<Link <Link
href={makeProfileLink(profile)} to={makeProfileLink(profile)}
title={profile.handle} label={profile.handle}
asAnchor onPress={onPress}
anchorNoUnderline style={[
onBeforePress={onPress} a.flex_col,
style={[a.align_center, a.w_full]}> a.align_center,
a.gap_xs,
{
width,
},
]}>
<UserAvatar <UserAvatar
avatar={profile.avatar} avatar={profile.avatar}
type={profile.associated?.labeler ? 'labeler' : 'user'} type={profile.associated?.labeler ? 'labeler' : 'user'}
size={60} size={width - 8}
moderation={moderation.ui('avatar')} moderation={moderation.ui('avatar')}
/> />
<View style={styles.profileName}> <View style={[a.flex_row, a.align_center, a.justify_center, a.w_full]}>
<View <Text emoji style={[a.text_xs, a.leading_snug]} numberOfLines={1}>
style={[
a.flex_row,
a.align_center,
a.justify_center,
web([a.flex_1]),
]}>
<Text
emoji
style={[a.text_xs, a.leading_snug, a.self_start]}
numberOfLines={1}>
{name} {name}
</Text> </Text>
{verification.showBadge && ( {verification.showBadge && (
<View style={[a.pl_xs]}> <View style={[a.pl_2xs]}>
<VerificationCheck <VerificationCheck
width={12} width={10}
verifier={verification.role === 'verifier'} verifier={verification.role === 'verifier'}
/> />
</View> </View>
)} )}
</View> </View>
</View>
</Link> </Link>
<Pressable <Button
accessibilityRole="button" label={_(msg`Remove profile`)}
accessibilityLabel={_(msg`Remove profile`)}
accessibilityHint={_(msg`Removes profile from search history`)}
hitSlop={createHitslop(6)} hitSlop={createHitslop(6)}
style={styles.profileRemoveBtn} size="tiny"
onPress={onRemove}> variant="outline"
<XIcon size="xs" style={t.atoms.text_contrast_low} /> color="secondary"
</Pressable> shape="round"
onPress={onRemove}
style={[
a.absolute,
{
top: 0,
right: 0,
height: 18,
width: 18,
},
]}>
<ButtonIcon icon={XIcon} />
</Button>
</View> </View>
) )
} }
const styles = StyleSheet.create({
selectedProfilesContainer: {
marginTop: 10,
paddingHorizontal: 12,
height: 80,
},
selectedProfilesContainerMobile: {
height: 100,
},
profileItem: {
alignItems: 'center',
marginRight: 15,
width: 78,
},
profileItemMobile: {
width: 70,
},
profileName: {
width: 78,
marginTop: 6,
},
profileRemoveBtn: {
position: 'absolute',
top: 0,
right: 5,
backgroundColor: 'white',
borderRadius: 10,
width: 18,
height: 18,
alignItems: 'center',
justifyContent: 'center',
},
})