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

View File

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