feat: better autocomplete view

zio/stable
Mary 2024-01-16 07:31:01 +07:00
parent d35be77a11
commit 6d0557c959
No known key found for this signature in database
2 changed files with 86 additions and 34 deletions

View File

@ -42,7 +42,11 @@ import {useSetDrawerOpen} from '#/state/shell'
import {useAnalytics} from '#/lib/analytics/analytics'
import {MagnifyingGlassIcon} from '#/lib/icons'
import {useModerationOpts} from '#/state/queries/preferences'
import {SearchResultCard} from '#/view/shell/desktop/Search'
import {
MATCH_HANDLE,
SearchLinkCard,
SearchProfileCard,
} from '#/view/shell/desktop/Search'
import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell'
import {isWeb} from '#/platform/detection'
import {listenSoftReset} from '#/state/events'
@ -511,6 +515,11 @@ export function SearchScreen(
onPressCancelSearch()
}, [onPressCancelSearch])
const queryMaybeHandle = React.useMemo(() => {
const match = MATCH_HANDLE.exec(query)
return match && match[1]
}, [query])
useFocusEffect(
React.useCallback(() => {
setMinimalShellMode(false)
@ -617,18 +626,26 @@ export function SearchScreen(
dataSet={{stableGutters: '1'}}
keyboardShouldPersistTaps="handled"
keyboardDismissMode="on-drag">
{searchResults.length ? (
searchResults.map((item, i) => (
<SearchResultCard
key={item.did}
profile={item}
moderation={moderateProfile(item, moderationOpts)}
style={i === 0 ? {borderTopWidth: 0} : {}}
/>
))
) : (
<EmptyState message={_(msg`No results found for ${query}`)} />
)}
<SearchLinkCard
label={_(msg`Search for "${query}"`)}
to={`/search?q=${encodeURIComponent(query)}`}
style={{borderBottomWidth: 1}}
/>
{queryMaybeHandle ? (
<SearchLinkCard
label={_(msg`Go to @${queryMaybeHandle}`)}
to={`/profile/${queryMaybeHandle}`}
/>
) : null}
{searchResults.map(item => (
<SearchProfileCard
key={item.did}
profile={item}
moderation={moderateProfile(item, moderationOpts)}
/>
))}
<View style={{height: 200}} />
</ScrollView>

View File

@ -29,13 +29,41 @@ import {UserAvatar} from '#/view/com/util/UserAvatar'
import {useActorAutocompleteFn} from '#/state/queries/actor-autocomplete'
import {useModerationOpts} from '#/state/queries/preferences'
export function SearchResultCard({
profile,
export const MATCH_HANDLE =
/@?([a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*(?:\.[a-zA-Z]{2,}))/
export function SearchLinkCard({
label,
to,
style,
}: {
label: string
to: string
style?: ViewStyle
}) {
const pal = usePalette('default')
return (
<Link href={to} asAnchor anchorNoUnderline>
<View
style={[
pal.border,
{paddingVertical: 16, paddingHorizontal: 12},
style,
]}>
<Text type="md" style={[pal.text]}>
{label}
</Text>
</View>
</Link>
)
}
export function SearchProfileCard({
profile,
moderation,
}: {
profile: AppBskyActorDefs.ProfileViewBasic
style: ViewStyle
moderation: ProfileModeration
}) {
const pal = usePalette('default')
@ -50,9 +78,7 @@ export function SearchResultCard({
<View
style={[
pal.border,
style,
{
borderTopWidth: 1,
flexDirection: 'row',
alignItems: 'center',
gap: 12,
@ -147,6 +173,11 @@ export function DesktopSearch() {
navigation.dispatch(StackActions.push('Search', {q: query}))
}, [query, navigation, setSearchResults])
const queryMaybeHandle = React.useMemo(() => {
const match = MATCH_HANDLE.exec(query)
return match && match[1]
}, [query])
return (
<View style={[styles.container, pal.view]}>
<View
@ -198,22 +229,26 @@ export function DesktopSearch() {
</View>
) : (
<>
{searchResults.length ? (
searchResults.map((item, i) => (
<SearchResultCard
key={item.did}
profile={item}
moderation={moderateProfile(item, moderationOpts)}
style={i === 0 ? {borderTopWidth: 0} : {}}
/>
))
) : (
<View>
<Text style={[pal.textLight, styles.noResults]}>
<Trans>No results found for {query}</Trans>
</Text>
</View>
)}
<SearchLinkCard
label={_(msg`Search for "${query}"`)}
to={`/search?q=${encodeURIComponent(query)}`}
style={{borderBottomWidth: 1}}
/>
{queryMaybeHandle ? (
<SearchLinkCard
label={_(msg`Go to @${queryMaybeHandle}`)}
to={`/profile/${queryMaybeHandle}`}
/>
) : null}
{searchResults.map(item => (
<SearchProfileCard
key={item.did}
profile={item}
moderation={moderateProfile(item, moderationOpts)}
/>
))}
</>
)}
</View>