feat: better autocomplete view
parent
d35be77a11
commit
6d0557c959
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue