Dialog
This commit is contained in:
+177
-139
@@ -22,7 +22,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||||
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {LANGUAGES} from '#/lib/../locale/languages'
|
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
import {useAnalytics} from '#/lib/analytics/analytics'
|
||||||
import {createHitslop} from '#/lib/constants'
|
import {createHitslop} from '#/lib/constants'
|
||||||
import {HITSLOP_10} from '#/lib/constants'
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
@@ -37,6 +36,7 @@ import {
|
|||||||
SearchTabNavigatorParams,
|
SearchTabNavigatorParams,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import {augmentSearchQuery} from '#/lib/strings/helpers'
|
import {augmentSearchQuery} from '#/lib/strings/helpers'
|
||||||
|
import {LANGUAGES} from '#/locale/languages'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {isNative, isWeb} from '#/platform/detection'
|
import {isNative, isWeb} from '#/platform/detection'
|
||||||
import {listenSoftReset} from '#/state/events'
|
import {listenSoftReset} from '#/state/events'
|
||||||
@@ -61,11 +61,13 @@ import {Explore} from '#/view/screens/Search/Explore'
|
|||||||
import {SearchLinkCard, SearchProfileCard} from '#/view/shell/desktop/Search'
|
import {SearchLinkCard, SearchProfileCard} from '#/view/shell/desktop/Search'
|
||||||
import {atoms as a, useBreakpoints, useTheme as useThemeNew, web} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme as useThemeNew, web} from '#/alf'
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
|
import * as Dialog from '#/components/Dialog'
|
||||||
import * as FeedCard from '#/components/FeedCard'
|
import * as FeedCard from '#/components/FeedCard'
|
||||||
import * as TextField from '#/components/forms/TextField'
|
import * as TextField from '#/components/forms/TextField'
|
||||||
import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron'
|
import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron'
|
||||||
import {MagnifyingGlass2_Stroke2_Corner0_Rounded as MagnifyingGlass} from '#/components/icons/MagnifyingGlass2'
|
import {MagnifyingGlass2_Stroke2_Corner0_Rounded as MagnifyingGlass} from '#/components/icons/MagnifyingGlass2'
|
||||||
import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu'
|
import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu'
|
||||||
|
import {SettingsGear2_Stroke2_Corner0_Rounded as Gear} from '#/components/icons/SettingsGear2'
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||||
import {Text as NewText} from '#/components/Typography'
|
import {Text as NewText} from '#/components/Typography'
|
||||||
|
|
||||||
@@ -409,8 +411,14 @@ function SearchLanguageDropdown({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let SearchScreenInner = ({query}: {query?: string}): React.ReactNode => {
|
let SearchScreenInner = ({
|
||||||
const t = useThemeNew()
|
queryWithoutLanguage,
|
||||||
|
queryWithLanguage,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
queryWithoutLanguage: string
|
||||||
|
queryWithLanguage: string
|
||||||
|
}): React.ReactNode => {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
|
const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
|
||||||
@@ -418,14 +426,6 @@ let SearchScreenInner = ({query}: {query?: string}): React.ReactNode => {
|
|||||||
const {isDesktop} = useWebMediaQueries()
|
const {isDesktop} = useWebMediaQueries()
|
||||||
const [activeTab, setActiveTab] = React.useState(0)
|
const [activeTab, setActiveTab] = React.useState(0)
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {gtMobile} = useBreakpoints()
|
|
||||||
|
|
||||||
const {contentLanguages} = useLanguagePrefs()
|
|
||||||
const [language, setLanguage] = React.useState(
|
|
||||||
parseLanguageFromQuery(query || '') || contentLanguages[0],
|
|
||||||
)
|
|
||||||
const queryWithoutLang = sanitizeLangFromQuery(query || '')
|
|
||||||
const queryWithLang = queryWithoutLang + ` lang:${language}`
|
|
||||||
|
|
||||||
const onPageSelected = React.useCallback(
|
const onPageSelected = React.useCallback(
|
||||||
(index: number) => {
|
(index: number) => {
|
||||||
@@ -437,13 +437,13 @@ let SearchScreenInner = ({query}: {query?: string}): React.ReactNode => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const sections = React.useMemo(() => {
|
const sections = React.useMemo(() => {
|
||||||
if (!queryWithoutLang) return []
|
if (!queryWithoutLanguage) return []
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: _(msg`Top`),
|
title: _(msg`Top`),
|
||||||
component: (
|
component: (
|
||||||
<SearchScreenPostResults
|
<SearchScreenPostResults
|
||||||
query={queryWithLang}
|
query={queryWithLanguage}
|
||||||
sort="top"
|
sort="top"
|
||||||
active={activeTab === 0}
|
active={activeTab === 0}
|
||||||
/>
|
/>
|
||||||
@@ -453,7 +453,7 @@ let SearchScreenInner = ({query}: {query?: string}): React.ReactNode => {
|
|||||||
title: _(msg`Latest`),
|
title: _(msg`Latest`),
|
||||||
component: (
|
component: (
|
||||||
<SearchScreenPostResults
|
<SearchScreenPostResults
|
||||||
query={queryWithLang}
|
query={queryWithLanguage}
|
||||||
sort="latest"
|
sort="latest"
|
||||||
active={activeTab === 1}
|
active={activeTab === 1}
|
||||||
/>
|
/>
|
||||||
@@ -463,7 +463,7 @@ let SearchScreenInner = ({query}: {query?: string}): React.ReactNode => {
|
|||||||
title: _(msg`People`),
|
title: _(msg`People`),
|
||||||
component: (
|
component: (
|
||||||
<SearchScreenUserResults
|
<SearchScreenUserResults
|
||||||
query={queryWithoutLang}
|
query={queryWithoutLanguage}
|
||||||
active={activeTab === 2}
|
active={activeTab === 2}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
@@ -472,49 +472,29 @@ let SearchScreenInner = ({query}: {query?: string}): React.ReactNode => {
|
|||||||
title: _(msg`Feeds`),
|
title: _(msg`Feeds`),
|
||||||
component: (
|
component: (
|
||||||
<SearchScreenFeedsResults
|
<SearchScreenFeedsResults
|
||||||
query={queryWithoutLang}
|
query={queryWithoutLanguage}
|
||||||
active={activeTab === 3}
|
active={activeTab === 3}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}, [_, queryWithoutLang, queryWithLang, activeTab])
|
}, [_, queryWithoutLanguage, queryWithLanguage, activeTab])
|
||||||
|
|
||||||
return queryWithoutLang ? (
|
return queryWithoutLanguage ? (
|
||||||
<>
|
<Pager
|
||||||
<CenteredView
|
onPageSelected={onPageSelected}
|
||||||
sideBorders={gtMobile}
|
renderTabBar={props => (
|
||||||
style={[
|
<CenteredView
|
||||||
isWeb && a.pt_sm,
|
sideBorders
|
||||||
isNative && a.pb_xs,
|
style={[pal.border, pal.view, styles.tabBarContainer]}>
|
||||||
a.px_md,
|
<TabBar items={sections.map(section => section.title)} {...props} />
|
||||||
t.atoms.border_contrast_low,
|
</CenteredView>
|
||||||
]}>
|
)}
|
||||||
<View style={[a.flex_row, a.justify_end, a.align_center, a.gap_sm]}>
|
initialPage={0}>
|
||||||
<NewText style={[a.font_bold, t.atoms.text_contrast_medium]}>
|
{sections.map((section, i) => (
|
||||||
<Trans>Language:</Trans>
|
<View key={i}>{section.component}</View>
|
||||||
</NewText>
|
))}
|
||||||
<View style={[{width: 120}]}>
|
</Pager>
|
||||||
<SearchLanguageDropdown value={language} onChange={setLanguage} />
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</CenteredView>
|
|
||||||
|
|
||||||
<Pager
|
|
||||||
onPageSelected={onPageSelected}
|
|
||||||
renderTabBar={props => (
|
|
||||||
<CenteredView
|
|
||||||
sideBorders
|
|
||||||
style={[pal.border, pal.view, styles.tabBarContainer]}>
|
|
||||||
<TabBar items={sections.map(section => section.title)} {...props} />
|
|
||||||
</CenteredView>
|
|
||||||
)}
|
|
||||||
initialPage={0}>
|
|
||||||
{sections.map((section, i) => (
|
|
||||||
<View key={i}>{section.component}</View>
|
|
||||||
))}
|
|
||||||
</Pager>
|
|
||||||
</>
|
|
||||||
) : hasSession ? (
|
) : hasSession ? (
|
||||||
<Explore />
|
<Explore />
|
||||||
) : (
|
) : (
|
||||||
@@ -784,95 +764,153 @@ export function SearchScreen(
|
|||||||
[selectedProfiles],
|
[selectedProfiles],
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
const {contentLanguages} = useLanguagePrefs()
|
||||||
<View style={isWeb ? null : {flex: 1}}>
|
const [language, setLanguage] = React.useState(
|
||||||
<CenteredView
|
parseLanguageFromQuery(queryParam || '') || contentLanguages[0],
|
||||||
style={[
|
)
|
||||||
a.p_md,
|
const queryWithoutLanguage = sanitizeLangFromQuery(queryParam || '')
|
||||||
a.pb_0,
|
const queryWithLanguage = queryWithoutLanguage + ` lang:${language}`
|
||||||
a.flex_row,
|
const control = Dialog.useDialogControl()
|
||||||
a.gap_sm,
|
|
||||||
t.atoms.bg,
|
|
||||||
web({
|
|
||||||
height: HEADER_HEIGHT, // TODO
|
|
||||||
position: 'sticky',
|
|
||||||
top: 0,
|
|
||||||
zIndex: 1,
|
|
||||||
}),
|
|
||||||
]}
|
|
||||||
sideBorders={gtMobile}>
|
|
||||||
{!gtMobile && (
|
|
||||||
<Button
|
|
||||||
testID="viewHeaderBackOrMenuBtn"
|
|
||||||
onPress={onPressMenu}
|
|
||||||
hitSlop={HITSLOP_10}
|
|
||||||
label={_(msg`Menu`)}
|
|
||||||
accessibilityHint={_(msg`Access navigation links and settings`)}
|
|
||||||
size="large"
|
|
||||||
variant="ghost"
|
|
||||||
color="secondary"
|
|
||||||
shape="square">
|
|
||||||
<ButtonIcon icon={Menu} size="lg" />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<SearchInputBox
|
|
||||||
textInput={textInput}
|
|
||||||
searchText={searchText}
|
|
||||||
showAutocomplete={showAutocomplete}
|
|
||||||
setShowAutocomplete={setShowAutocomplete}
|
|
||||||
onChangeText={onChangeText}
|
|
||||||
onSubmit={onSubmit}
|
|
||||||
onPressClearQuery={onPressClearQuery}
|
|
||||||
/>
|
|
||||||
{showAutocomplete && (
|
|
||||||
<Button
|
|
||||||
label={_(msg`Cancel search`)}
|
|
||||||
size="large"
|
|
||||||
variant="ghost"
|
|
||||||
color="secondary"
|
|
||||||
style={[a.px_sm]}
|
|
||||||
onPress={onPressCancelSearch}
|
|
||||||
hitSlop={HITSLOP_10}>
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Cancel</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</CenteredView>
|
|
||||||
|
|
||||||
<View
|
return (
|
||||||
style={{
|
<>
|
||||||
display: showAutocomplete ? 'flex' : 'none',
|
<Dialog.Outer control={control}>
|
||||||
flex: 1,
|
<Dialog.Handle />
|
||||||
}}>
|
|
||||||
{searchText.length > 0 ? (
|
<Dialog.ScrollableInner
|
||||||
<AutocompleteResults
|
label={_(msg`Advanced search parameters`)}
|
||||||
isAutocompleteFetching={isAutocompleteFetching}
|
style={[
|
||||||
autocompleteData={autocompleteData}
|
gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full,
|
||||||
searchText={searchText}
|
]}>
|
||||||
onSubmit={onSubmit}
|
<View style={[a.gap_xs]}>
|
||||||
onResultPress={onAutocompleteResultPress}
|
<NewText style={[a.text_lg, a.font_heavy]}>
|
||||||
onProfileClick={handleProfileClick}
|
<Trans>Advanced search</Trans>
|
||||||
|
</NewText>
|
||||||
|
<NewText style={[a.text_md, t.atoms.text_contrast_medium]}>
|
||||||
|
<Trans>For more tips and tricks, check out this blog post.</Trans>
|
||||||
|
</NewText>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={[a.pt_md]}>
|
||||||
|
<SearchLanguageDropdown value={language} onChange={setLanguage} />
|
||||||
|
</View>
|
||||||
|
<Dialog.Close />
|
||||||
|
</Dialog.ScrollableInner>
|
||||||
|
</Dialog.Outer>
|
||||||
|
|
||||||
|
<View style={isWeb ? null : {flex: 1}}>
|
||||||
|
<CenteredView
|
||||||
|
style={[
|
||||||
|
a.p_md,
|
||||||
|
a.pb_0,
|
||||||
|
a.flex_row,
|
||||||
|
a.gap_xs,
|
||||||
|
t.atoms.bg,
|
||||||
|
web({
|
||||||
|
height: HEADER_HEIGHT, // TODO
|
||||||
|
position: 'sticky',
|
||||||
|
top: 0,
|
||||||
|
zIndex: 1,
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
sideBorders={gtMobile}>
|
||||||
|
{!gtMobile && (
|
||||||
|
<Button
|
||||||
|
testID="viewHeaderBackOrMenuBtn"
|
||||||
|
onPress={onPressMenu}
|
||||||
|
hitSlop={HITSLOP_10}
|
||||||
|
label={_(msg`Menu`)}
|
||||||
|
accessibilityHint={_(msg`Access navigation links and settings`)}
|
||||||
|
size="large"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
shape="square"
|
||||||
|
style={{
|
||||||
|
marginLeft: -6,
|
||||||
|
}}>
|
||||||
|
<ButtonIcon icon={Menu} size="lg" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<View style={[a.flex_1]}>
|
||||||
|
<SearchInputBox
|
||||||
|
textInput={textInput}
|
||||||
|
searchText={searchText}
|
||||||
|
showAutocomplete={showAutocomplete}
|
||||||
|
setShowAutocomplete={setShowAutocomplete}
|
||||||
|
onChangeText={onChangeText}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
onPressClearQuery={onPressClearQuery}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
{showAutocomplete && (
|
||||||
|
<Button
|
||||||
|
label={_(msg`Cancel search`)}
|
||||||
|
size="large"
|
||||||
|
variant="ghost"
|
||||||
|
color="secondary"
|
||||||
|
style={[a.px_sm]}
|
||||||
|
onPress={onPressCancelSearch}
|
||||||
|
hitSlop={HITSLOP_10}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Cancel</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{searchText && !showAutocomplete && (
|
||||||
|
<Button
|
||||||
|
label={_(msg`Customize search`)}
|
||||||
|
size="large"
|
||||||
|
shape="square"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
style={{
|
||||||
|
marginRight: -6,
|
||||||
|
}}
|
||||||
|
onPress={() => {
|
||||||
|
control.open()
|
||||||
|
}}>
|
||||||
|
<ButtonIcon icon={Gear} size="lg" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</CenteredView>
|
||||||
|
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
display: showAutocomplete ? 'flex' : 'none',
|
||||||
|
flex: 1,
|
||||||
|
}}>
|
||||||
|
{searchText.length > 0 ? (
|
||||||
|
<AutocompleteResults
|
||||||
|
isAutocompleteFetching={isAutocompleteFetching}
|
||||||
|
autocompleteData={autocompleteData}
|
||||||
|
searchText={searchText}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
onResultPress={onAutocompleteResultPress}
|
||||||
|
onProfileClick={handleProfileClick}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<SearchHistory
|
||||||
|
searchHistory={searchHistory}
|
||||||
|
selectedProfiles={selectedProfiles}
|
||||||
|
onItemClick={handleHistoryItemClick}
|
||||||
|
onProfileClick={handleProfileClick}
|
||||||
|
onRemoveItemClick={handleRemoveHistoryItem}
|
||||||
|
onRemoveProfileClick={handleRemoveProfile}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
display: showAutocomplete ? 'none' : 'flex',
|
||||||
|
flex: 1,
|
||||||
|
}}>
|
||||||
|
<SearchScreenInner
|
||||||
|
queryWithoutLanguage={queryWithoutLanguage}
|
||||||
|
queryWithLanguage={queryWithLanguage}
|
||||||
/>
|
/>
|
||||||
) : (
|
</View>
|
||||||
<SearchHistory
|
|
||||||
searchHistory={searchHistory}
|
|
||||||
selectedProfiles={selectedProfiles}
|
|
||||||
onItemClick={handleHistoryItemClick}
|
|
||||||
onProfileClick={handleProfileClick}
|
|
||||||
onRemoveItemClick={handleRemoveHistoryItem}
|
|
||||||
onRemoveProfileClick={handleRemoveProfile}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
<View
|
</>
|
||||||
style={{
|
|
||||||
display: showAutocomplete ? 'none' : 'flex',
|
|
||||||
flex: 1,
|
|
||||||
}}>
|
|
||||||
<SearchScreenInner query={queryParam} />
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,7 +935,7 @@ let SearchInputBox = ({
|
|||||||
const t = useThemeNew()
|
const t = useThemeNew()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.flex_1, a.relative]}>
|
<View style={[a.w_full, a.relative]}>
|
||||||
<TextField.Root>
|
<TextField.Root>
|
||||||
<TextField.Icon icon={MagnifyingGlass} />
|
<TextField.Icon icon={MagnifyingGlass} />
|
||||||
<TextField.Input
|
<TextField.Input
|
||||||
|
|||||||
Reference in New Issue
Block a user