Refactor search history
This commit is contained in:
@@ -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],
|
||||||
|
|||||||
@@ -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,54 +42,52 @@ 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]}>
|
||||||
<Trans>Recent Searches</Trans>
|
<Text style={[a.text_md, a.font_bold]}>
|
||||||
</Text>
|
<Trans>Recent Searches</Trans>
|
||||||
|
</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)
|
<RecentProfileItem
|
||||||
.map(profile => (
|
key={profile.did}
|
||||||
<RecentProfileItem
|
profile={profile}
|
||||||
key={profile.did}
|
moderationOpts={moderationOpts}
|
||||||
profile={profile}
|
onPress={() => onProfileClick(profile)}
|
||||||
moderationOpts={moderationOpts}
|
onRemove={() => onRemoveProfileClick(profile)}
|
||||||
onPress={() => onProfileClick(profile)}
|
/>
|
||||||
onRemove={() => onRemoveProfileClick(profile)}
|
))}
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</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={[
|
{name}
|
||||||
a.flex_row,
|
</Text>
|
||||||
a.align_center,
|
{verification.showBadge && (
|
||||||
a.justify_center,
|
<View style={[a.pl_2xs]}>
|
||||||
web([a.flex_1]),
|
<VerificationCheck
|
||||||
]}>
|
width={10}
|
||||||
<Text
|
verifier={verification.role === 'verifier'}
|
||||||
emoji
|
/>
|
||||||
style={[a.text_xs, a.leading_snug, a.self_start]}
|
</View>
|
||||||
numberOfLines={1}>
|
)}
|
||||||
{name}
|
|
||||||
</Text>
|
|
||||||
{verification.showBadge && (
|
|
||||||
<View style={[a.pl_xs]}>
|
|
||||||
<VerificationCheck
|
|
||||||
width={12}
|
|
||||||
verifier={verification.role === 'verifier'}
|
|
||||||
/>
|
|
||||||
</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',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|||||||
Reference in New Issue
Block a user