diff options
Diffstat (limited to 'src/view/screens')
-rw-r--r-- | src/view/screens/Feeds.tsx | 128 | ||||
-rw-r--r-- | src/view/screens/Lists.tsx | 72 | ||||
-rw-r--r-- | src/view/screens/ModerationBlockedAccounts.tsx | 26 | ||||
-rw-r--r-- | src/view/screens/ModerationModlists.tsx | 64 | ||||
-rw-r--r-- | src/view/screens/ModerationMutedAccounts.tsx | 28 | ||||
-rw-r--r-- | src/view/screens/Notifications.tsx | 178 | ||||
-rw-r--r-- | src/view/screens/PostThread.tsx | 6 | ||||
-rw-r--r-- | src/view/screens/Profile.tsx | 6 | ||||
-rw-r--r-- | src/view/screens/ProfileFeed.tsx | 9 | ||||
-rw-r--r-- | src/view/screens/ProfileFollowers.tsx | 2 | ||||
-rw-r--r-- | src/view/screens/ProfileFollows.tsx | 2 | ||||
-rw-r--r-- | src/view/screens/ProfileList.tsx | 10 | ||||
-rw-r--r-- | src/view/screens/SavedFeeds.tsx | 238 | ||||
-rw-r--r-- | src/view/screens/Search/Search.tsx | 236 |
14 files changed, 404 insertions, 601 deletions
diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx index 406f11792..0dcf1f016 100644 --- a/src/view/screens/Feeds.tsx +++ b/src/view/screens/Feeds.tsx @@ -24,14 +24,13 @@ import {useSetMinimalShellMode} from '#/state/shell' import {useComposerControls} from '#/state/shell/composer' import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' import {FAB} from '#/view/com/util/fab/FAB' -import {TextLink} from '#/view/com/util/Link' import {List, ListMethods} from '#/view/com/util/List' import {FeedFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import {Text} from '#/view/com/util/text/Text' -import {ViewHeader} from '#/view/com/util/ViewHeader' import {NoFollowingFeed} from '#/screens/Feeds/NoFollowingFeed' import {NoSavedFeedsOfAnyType} from '#/screens/Feeds/NoSavedFeedsOfAnyType' import {atoms as a, useTheme} from '#/alf' +import {ButtonIcon} from '#/components/Button' import {Divider} from '#/components/Divider' import * as FeedCard from '#/components/FeedCard' import {SearchInput} from '#/components/forms/SearchInput' @@ -40,7 +39,9 @@ import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline' import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass' import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle' +import {SettingsGear2_Stroke2_Corner0_Rounded as Gear} from '#/components/icons/SettingsGear2' import * as Layout from '#/components/Layout' +import {Link} from '#/components/Link' import * as ListCard from '#/components/ListCard' type Props = NativeStackScreenProps<CommonNavigatorParams, 'Feeds'> @@ -102,7 +103,7 @@ type FlatlistSlice = export function FeedsScreen(_props: Props) { const pal = usePalette('default') const {openComposer} = useComposerControls() - const {isMobile, isTabletOrDesktop} = useWebMediaQueries() + const {isMobile} = useWebMediaQueries() const [query, setQuery] = React.useState('') const [isPTR, setIsPTR] = React.useState(false) const { @@ -374,22 +375,6 @@ export function FeedsScreen(_props: Props) { isUserSearching, ]) - const renderHeaderBtn = React.useCallback(() => { - return ( - <View style={styles.headerBtnGroup}> - <TextLink - testID="editFeedsBtn" - type="lg-medium" - href="/settings/saved-feeds" - accessibilityLabel={_(msg`Edit My Feeds`)} - accessibilityHint="" - text={_(msg`Edit`)} - style={[pal.link, a.pr_xs]} - /> - </View> - ) - }, [pal, _]) - const searchBarIndex = items.findIndex( item => item.type === 'popularFeedsHeader', ) @@ -430,36 +415,7 @@ export function FeedsScreen(_props: Props) { </View> ) } else if (item.type === 'savedFeedsHeader') { - return ( - <> - {!isMobile && ( - <View - style={[ - pal.view, - styles.header, - pal.border, - { - borderBottomWidth: 1, - }, - ]}> - <Text type="title-lg" style={[pal.text, s.bold]}> - <Trans>Feeds</Trans> - </Text> - <View style={styles.headerBtnGroup}> - <TextLink - type="lg" - href="/settings/saved-feeds" - accessibilityLabel={_(msg`Edit My Feeds`)} - accessibilityHint="" - text={_(msg`Edit`)} - style={[pal.link]} - /> - </View> - </View> - )} - <FeedsSavedHeader /> - </> - ) + return <FeedsSavedHeader /> } else if (item.type === 'savedFeedNoResults') { return ( <View @@ -530,13 +486,8 @@ export function FeedsScreen(_props: Props) { return null }, [ - isMobile, - pal.view, pal.border, - pal.text, pal.textLight, - pal.link, - _, query, onChangeQuery, onPressCancelSearch, @@ -547,31 +498,45 @@ export function FeedsScreen(_props: Props) { return ( <Layout.Screen testID="FeedsScreen"> - {isMobile && ( - <ViewHeader - title={_(msg`Feeds`)} - renderButton={renderHeaderBtn} - showBorder + <Layout.Center> + <Layout.Header.Outer> + <Layout.Header.BackButton /> + <Layout.Header.Content> + <Layout.Header.TitleText> + <Trans>Feeds</Trans> + </Layout.Header.TitleText> + </Layout.Header.Content> + <Layout.Header.Slot> + <Link + testID="editFeedsBtn" + to="/settings/saved-feeds" + label={_(msg`Edit My Feeds`)} + size="small" + variant="ghost" + color="secondary" + shape="round" + style={[a.justify_center, {right: -3}]}> + <ButtonIcon icon={Gear} size="lg" /> + </Link> + </Layout.Header.Slot> + </Layout.Header.Outer> + + <List + ref={listRef} + data={items} + keyExtractor={item => item.key} + contentContainerStyle={styles.contentContainer} + renderItem={renderItem} + refreshing={isPTR} + onRefresh={isUserSearching ? undefined : onPullToRefresh} + initialNumToRender={10} + onEndReached={onEndReached} + desktopFixedHeight + keyboardShouldPersistTaps="handled" + keyboardDismissMode="on-drag" + sideBorders={false} /> - )} - - <List - ref={listRef} - style={[!isTabletOrDesktop && s.flex1, styles.list]} - data={items} - keyExtractor={item => item.key} - contentContainerStyle={styles.contentContainer} - renderItem={renderItem} - refreshing={isPTR} - onRefresh={isUserSearching ? undefined : onPullToRefresh} - initialNumToRender={10} - onEndReached={onEndReached} - // @ts-ignore our .web version only -prf - desktopFixedHeight - scrollIndicatorInsets={{right: 1}} - keyboardShouldPersistTaps="handled" - keyboardDismissMode="on-drag" - /> + </Layout.Center> {hasSession && ( <FAB @@ -728,7 +693,7 @@ function FeedsSavedHeader() { }> <IconCircle icon={ListSparkle_Stroke2_Corner0_Rounded} size="lg" /> <View style={[a.flex_1, a.gap_xs]}> - <Text style={[a.flex_1, a.text_2xl, a.font_bold, t.atoms.text]}> + <Text style={[a.flex_1, a.text_2xl, a.font_heavy, t.atoms.text]}> <Trans>My Feeds</Trans> </Text> <Text style={[t.atoms.text_contrast_high]}> @@ -754,7 +719,7 @@ function FeedsAboutHeader() { size="lg" /> <View style={[a.flex_1, a.gap_sm]}> - <Text style={[a.flex_1, a.text_2xl, a.font_bold, t.atoms.text]}> + <Text style={[a.flex_1, a.text_2xl, a.font_heavy, t.atoms.text]}> <Trans>Discover New Feeds</Trans> </Text> <Text style={[t.atoms.text_contrast_high]}> @@ -769,9 +734,6 @@ function FeedsAboutHeader() { } const styles = StyleSheet.create({ - list: { - height: '100%', - }, contentContainer: { paddingBottom: 100, }, diff --git a/src/view/screens/Lists.tsx b/src/view/screens/Lists.tsx index f654f2bd9..99abf0603 100644 --- a/src/view/screens/Lists.tsx +++ b/src/view/screens/Lists.tsx @@ -1,33 +1,26 @@ import React from 'react' -import {StyleSheet, View} from 'react-native' import {AtUri} from '@atproto/api' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useFocusEffect, useNavigation} from '@react-navigation/native' import {useEmail} from '#/lib/hooks/useEmail' -import {usePalette} from '#/lib/hooks/usePalette' -import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' import {NavigationProp} from '#/lib/routes/types' -import {s} from '#/lib/styles' import {useModalControls} from '#/state/modals' import {useSetMinimalShellMode} from '#/state/shell' import {MyLists} from '#/view/com/lists/MyLists' -import {Button} from '#/view/com/util/forms/Button' -import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader' -import {Text} from '#/view/com/util/text/Text' +import {atoms as a} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {useDialogControl} from '#/components/Dialog' import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog' +import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' import * as Layout from '#/components/Layout' type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'> export function ListsScreen({}: Props) { const {_} = useLingui() - const pal = usePalette('default') const setMinimalShellMode = useSetMinimalShellMode() - const {isMobile} = useWebMediaQueries() const navigation = useNavigation<NavigationProp>() const {openModal} = useModalControls() const {needsEmailVerification} = useEmail() @@ -62,43 +55,30 @@ export function ListsScreen({}: Props) { return ( <Layout.Screen testID="listsScreen"> - <SimpleViewHeader - showBackButton={isMobile} - style={[ - pal.border, - isMobile - ? {borderBottomWidth: StyleSheet.hairlineWidth} - : { - borderLeftWidth: StyleSheet.hairlineWidth, - borderRightWidth: StyleSheet.hairlineWidth, - }, - ]}> - <View style={{flex: 1}}> - <Text type="title-lg" style={[pal.text, {fontWeight: '600'}]}> - <Trans>User Lists</Trans> - </Text> - <Text style={pal.textLight}> + <Layout.Header.Outer> + <Layout.Header.BackButton /> + <Layout.Header.Content align="left"> + <Layout.Header.TitleText> + <Trans>Lists</Trans> + </Layout.Header.TitleText> + <Layout.Header.SubtitleText> <Trans>Public, shareable lists which can drive feeds.</Trans> - </Text> - </View> - <View style={[{marginLeft: 18}, isMobile && {marginLeft: 12}]}> - <Button - testID="newUserListBtn" - type="default" - onPress={onPressNewList} - style={{ - flexDirection: 'row', - alignItems: 'center', - gap: 8, - }}> - <FontAwesomeIcon icon="plus" color={pal.colors.text} /> - <Text type="button" style={pal.text}> - <Trans context="action">New</Trans> - </Text> - </Button> - </View> - </SimpleViewHeader> - <MyLists filter="curate" style={s.flexGrow1} /> + </Layout.Header.SubtitleText> + </Layout.Header.Content> + <Button + label={_(msg`New list`)} + testID="newUserListBtn" + color="secondary" + variant="solid" + size="small" + onPress={onPressNewList}> + <ButtonIcon icon={PlusIcon} /> + <ButtonText> + <Trans context="action">New</Trans> + </ButtonText> + </Button> + </Layout.Header.Outer> + <MyLists filter="curate" style={a.flex_grow} /> <VerifyEmailDialog reasonText={_( msg`Before creating a list, you must first verify your email.`, diff --git a/src/view/screens/ModerationBlockedAccounts.tsx b/src/view/screens/ModerationBlockedAccounts.tsx index 53e31d1d2..9b0f54984 100644 --- a/src/view/screens/ModerationBlockedAccounts.tsx +++ b/src/view/screens/ModerationBlockedAccounts.tsx @@ -23,7 +23,6 @@ import {ProfileCard} from '#/view/com/profile/ProfileCard' import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' import {Text} from '#/view/com/util/text/Text' import {ViewHeader} from '#/view/com/util/ViewHeader' -import {CenteredView} from '#/view/com/util/Views' import * as Layout from '#/components/Layout' type Props = NativeStackScreenProps< @@ -97,14 +96,7 @@ export function ModerationBlockedAccounts({}: Props) { ) return ( <Layout.Screen testID="blockedAccountsScreen"> - <CenteredView - style={[ - styles.container, - isTabletOrDesktop && styles.containerDesktop, - pal.view, - pal.border, - ]} - testID="blockedAccountsScreen"> + <Layout.Center> <ViewHeader title={_(msg`Blocked Accounts`)} showOnDesktop /> <Text type="sm" @@ -112,6 +104,9 @@ export function ModerationBlockedAccounts({}: Props) { styles.description, pal.text, isTabletOrDesktop && styles.descriptionDesktop, + { + marginTop: 20, + }, ]}> <Trans> Blocked accounts cannot reply in your threads, mention you, or @@ -120,7 +115,7 @@ export function ModerationBlockedAccounts({}: Props) { </Trans> </Text> {isEmpty ? ( - <View style={[pal.border, !isTabletOrDesktop && styles.flex1]}> + <View style={[pal.border]}> {isError ? ( <ErrorScreen title="Oops!" @@ -166,21 +161,12 @@ export function ModerationBlockedAccounts({}: Props) { desktopFixedHeight /> )} - </CenteredView> + </Layout.Center> </Layout.Screen> ) } const styles = StyleSheet.create({ - container: { - flex: 1, - paddingBottom: 100, - }, - containerDesktop: { - borderLeftWidth: 1, - borderRightWidth: 1, - paddingBottom: 0, - }, title: { textAlign: 'center', marginTop: 12, diff --git a/src/view/screens/ModerationModlists.tsx b/src/view/screens/ModerationModlists.tsx index c623c5376..0ef4d4389 100644 --- a/src/view/screens/ModerationModlists.tsx +++ b/src/view/screens/ModerationModlists.tsx @@ -1,33 +1,26 @@ import React from 'react' -import {View} from 'react-native' import {AtUri} from '@atproto/api' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useFocusEffect, useNavigation} from '@react-navigation/native' import {useEmail} from '#/lib/hooks/useEmail' -import {usePalette} from '#/lib/hooks/usePalette' -import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' import {NavigationProp} from '#/lib/routes/types' -import {s} from '#/lib/styles' import {useModalControls} from '#/state/modals' import {useSetMinimalShellMode} from '#/state/shell' import {MyLists} from '#/view/com/lists/MyLists' -import {Button} from '#/view/com/util/forms/Button' -import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader' -import {Text} from '#/view/com/util/text/Text' +import {atoms as a} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {useDialogControl} from '#/components/Dialog' import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog' +import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' import * as Layout from '#/components/Layout' type Props = NativeStackScreenProps<CommonNavigatorParams, 'ModerationModlists'> export function ModerationModlistsScreen({}: Props) { const {_} = useLingui() - const pal = usePalette('default') const setMinimalShellMode = useSetMinimalShellMode() - const {isMobile} = useWebMediaQueries() const navigation = useNavigation<NavigationProp>() const {openModal} = useModalControls() const {needsEmailVerification} = useEmail() @@ -62,39 +55,32 @@ export function ModerationModlistsScreen({}: Props) { return ( <Layout.Screen testID="moderationModlistsScreen"> - <SimpleViewHeader - showBackButton={isMobile} - style={ - !isMobile && [pal.border, {borderLeftWidth: 1, borderRightWidth: 1}] - }> - <View style={{flex: 1}}> - <Text type="title-lg" style={[pal.text, {fontWeight: '600'}]}> + <Layout.Header.Outer> + <Layout.Header.BackButton /> + <Layout.Header.Content align="left"> + <Layout.Header.TitleText> <Trans>Moderation Lists</Trans> - </Text> - <Text style={pal.textLight}> + </Layout.Header.TitleText> + <Layout.Header.SubtitleText> <Trans> Public, shareable lists of users to mute or block in bulk. </Trans> - </Text> - </View> - <View style={[{marginLeft: 18}, isMobile && {marginLeft: 12}]}> - <Button - testID="newModListBtn" - type="default" - onPress={onPressNewList} - style={{ - flexDirection: 'row', - alignItems: 'center', - gap: 8, - }}> - <FontAwesomeIcon icon="plus" color={pal.colors.text} /> - <Text type="button" style={pal.text}> - <Trans>New</Trans> - </Text> - </Button> - </View> - </SimpleViewHeader> - <MyLists filter="mod" style={s.flexGrow1} /> + </Layout.Header.SubtitleText> + </Layout.Header.Content> + <Button + label={_(msg`New list`)} + testID="newModListBtn" + color="secondary" + variant="solid" + size="small" + onPress={onPressNewList}> + <ButtonIcon icon={PlusIcon} /> + <ButtonText> + <Trans context="action">New</Trans> + </ButtonText> + </Button> + </Layout.Header.Outer> + <MyLists filter="mod" style={a.flex_grow} /> <VerifyEmailDialog reasonText={_( msg`Before creating a list, you must first verify your email.`, diff --git a/src/view/screens/ModerationMutedAccounts.tsx b/src/view/screens/ModerationMutedAccounts.tsx index 6d34c8a5f..6a8c6c3e6 100644 --- a/src/view/screens/ModerationMutedAccounts.tsx +++ b/src/view/screens/ModerationMutedAccounts.tsx @@ -23,7 +23,6 @@ import {ProfileCard} from '#/view/com/profile/ProfileCard' import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' import {Text} from '#/view/com/util/text/Text' import {ViewHeader} from '#/view/com/util/ViewHeader' -import {CenteredView} from '#/view/com/util/Views' import * as Layout from '#/components/Layout' type Props = NativeStackScreenProps< @@ -97,21 +96,17 @@ export function ModerationMutedAccounts({}: Props) { ) return ( <Layout.Screen testID="mutedAccountsScreen"> - <CenteredView - style={[ - styles.container, - isTabletOrDesktop && styles.containerDesktop, - pal.view, - pal.border, - ]} - testID="mutedAccountsScreen"> - <ViewHeader title={_(msg`Muted Accounts`)} showOnDesktop /> + <ViewHeader title={_(msg`Muted Accounts`)} showOnDesktop /> + <Layout.Center> <Text type="sm" style={[ styles.description, pal.text, isTabletOrDesktop && styles.descriptionDesktop, + { + marginTop: 20, + }, ]}> <Trans> Muted accounts have their posts removed from your feed and from your @@ -119,7 +114,7 @@ export function ModerationMutedAccounts({}: Props) { </Trans> </Text> {isEmpty ? ( - <View style={[pal.border, !isTabletOrDesktop && styles.flex1]}> + <View style={[pal.border]}> {isError ? ( <ErrorScreen title="Oops!" @@ -165,21 +160,12 @@ export function ModerationMutedAccounts({}: Props) { desktopFixedHeight /> )} - </CenteredView> + </Layout.Center> </Layout.Screen> ) } const styles = StyleSheet.create({ - container: { - flex: 1, - paddingBottom: 100, - }, - containerDesktop: { - borderLeftWidth: 1, - borderRightWidth: 1, - paddingBottom: 0, - }, title: { textAlign: 'center', marginTop: 12, diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx index 531d10a7f..35591f270 100644 --- a/src/view/screens/Notifications.tsx +++ b/src/view/screens/Notifications.tsx @@ -1,4 +1,4 @@ -import React, {useCallback} from 'react' +import React from 'react' import {View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -6,7 +6,6 @@ import {useFocusEffect, useIsFocused} from '@react-navigation/native' import {useQueryClient} from '@tanstack/react-query' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' -import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {ComposeIcon2} from '#/lib/icons' import { NativeStackScreenProps, @@ -14,7 +13,7 @@ import { } from '#/lib/routes/types' import {s} from '#/lib/styles' import {logger} from '#/logger' -import {isNative} from '#/platform/detection' +import {isNative, isWeb} from '#/platform/detection' import {emitSoftReset, listenSoftReset} from '#/state/events' import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed' import { @@ -29,28 +28,25 @@ import {FAB} from '#/view/com/util/fab/FAB' import {ListMethods} from '#/view/com/util/List' import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' import {MainScrollProvider} from '#/view/com/util/MainScrollProvider' -import {ViewHeader} from '#/view/com/util/ViewHeader' -import {CenteredView} from '#/view/com/util/Views' -import {atoms as a, useTheme} from '#/alf' -import {Button} from '#/components/Button' +import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {Button, ButtonIcon} from '#/components/Button' import {SettingsGear2_Stroke2_Corner0_Rounded as SettingsIcon} from '#/components/icons/SettingsGear2' import * as Layout from '#/components/Layout' import {Link} from '#/components/Link' import {Loader} from '#/components/Loader' -import {Text} from '#/components/Typography' type Props = NativeStackScreenProps< NotificationsTabNavigatorParams, 'Notifications' > export function NotificationsScreen({route: {params}}: Props) { + const t = useTheme() + const {gtTablet} = useBreakpoints() const {_} = useLingui() const setMinimalShellMode = useSetMinimalShellMode() const [isScrolledDown, setIsScrolledDown] = React.useState(false) const [isLoadingLatest, setIsLoadingLatest] = React.useState(false) const scrollElRef = React.useRef<ListMethods>(null) - const t = useTheme() - const {isDesktop} = useWebMediaQueries() const queryClient = useQueryClient() const unreadNotifs = useUnreadNotifications() const unreadApi = useUnreadNotificationsApi() @@ -110,121 +106,77 @@ export function NotificationsScreen({route: {params}}: Props) { return listenSoftReset(onPressLoadLatest) }, [onPressLoadLatest, isScreenFocused]) - const renderButton = useCallback(() => { - return ( - <Link - to="/notifications/settings" - label={_(msg`Notification settings`)} - size="small" - variant="ghost" - color="secondary" - shape="square" - style={[a.justify_center]}> - <SettingsIcon size="md" style={t.atoms.text_contrast_medium} /> - </Link> - ) - }, [_, t]) - - const ListHeaderComponent = React.useCallback(() => { - if (isDesktop) { - return ( - <View - style={[ - t.atoms.bg, - a.flex_row, - a.align_center, - a.justify_between, - a.gap_lg, - a.px_lg, - a.pr_md, - a.py_sm, - ]}> + return ( + <Layout.Screen testID="notificationsScreen"> + <Layout.Header.Outer> + <Layout.Header.MenuButton /> + <Layout.Header.Content> <Button label={_(msg`Notifications`)} accessibilityHint={_(msg`Refresh notifications`)} - onPress={emitSoftReset}> - {({hovered, pressed}) => ( - <Text - style={[ - a.text_2xl, - a.font_bold, - (hovered || pressed) && a.underline, - ]}> + onPress={emitSoftReset} + style={[a.justify_start]}> + {({hovered}) => ( + <Layout.Header.TitleText + style={[a.w_full, hovered && a.underline]}> <Trans>Notifications</Trans> - {hasNew && ( + {isWeb && gtTablet && hasNew && ( <View - style={{ - left: 4, - top: -8, - backgroundColor: t.palette.primary_500, - width: 8, - height: 8, - borderRadius: 4, - }} + style={[ + a.rounded_full, + { + width: 8, + height: 8, + bottom: 3, + left: 6, + backgroundColor: t.palette.primary_500, + }, + ]} /> )} - </Text> + </Layout.Header.TitleText> )} </Button> - <View style={[a.flex_row, a.align_center, a.gap_sm]}> - {isLoadingLatest ? <Loader size="md" /> : <></>} - {renderButton()} - </View> - </View> - ) - } - return <></> - }, [isDesktop, t, hasNew, renderButton, _, isLoadingLatest]) - - const renderHeaderSpinner = React.useCallback(() => { - return ( - <View - style={[ - {width: 30, height: 20}, - a.flex_row, - a.align_center, - a.justify_end, - a.gap_md, - ]}> - {isLoadingLatest ? <Loader width={20} /> : <></>} - {renderButton()} - </View> - ) - }, [renderButton, isLoadingLatest]) + </Layout.Header.Content> + <Layout.Header.Slot> + <Link + to="/notifications/settings" + label={_(msg`Notification settings`)} + size="small" + variant="ghost" + color="secondary" + shape="round" + style={[a.justify_center]}> + <ButtonIcon + icon={isLoadingLatest ? Loader : SettingsIcon} + size="lg" + /> + </Link> + </Layout.Header.Slot> + </Layout.Header.Outer> - return ( - <Layout.Screen testID="notificationsScreen"> - <CenteredView style={[a.flex_1, {paddingTop: 2}]} sideBorders={true}> - <ViewHeader - title={_(msg`Notifications`)} - canGoBack={false} - showBorder={true} - renderButton={renderHeaderSpinner} + <MainScrollProvider> + <Feed + onScrolledDownChange={setIsScrolledDown} + scrollElRef={scrollElRef} + overridePriorityNotifications={params?.show === 'all'} /> - <MainScrollProvider> - <Feed - onScrolledDownChange={setIsScrolledDown} - scrollElRef={scrollElRef} - ListHeaderComponent={ListHeaderComponent} - overridePriorityNotifications={params?.show === 'all'} - /> - </MainScrollProvider> - {(isScrolledDown || hasNew) && ( - <LoadLatestBtn - onPress={onPressLoadLatest} - label={_(msg`Load new notifications`)} - showIndicator={hasNew} - /> - )} - <FAB - testID="composeFAB" - onPress={() => openComposer({})} - icon={<ComposeIcon2 strokeWidth={1.5} size={29} style={s.white} />} - accessibilityRole="button" - accessibilityLabel={_(msg`New post`)} - accessibilityHint="" + </MainScrollProvider> + {(isScrolledDown || hasNew) && ( + <LoadLatestBtn + onPress={onPressLoadLatest} + label={_(msg`Load new notifications`)} + showIndicator={hasNew} /> - </CenteredView> + )} + <FAB + testID="composeFAB" + onPress={() => openComposer({})} + icon={<ComposeIcon2 strokeWidth={1.5} size={29} style={s.white} />} + accessibilityRole="button" + accessibilityLabel={_(msg`New post`)} + accessibilityHint="" + /> </Layout.Screen> ) } diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx index c183569b7..1bad9b6cd 100644 --- a/src/view/screens/PostThread.tsx +++ b/src/view/screens/PostThread.tsx @@ -1,12 +1,10 @@ import React from 'react' -import {View} from 'react-native' import {useFocusEffect} from '@react-navigation/native' import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' import {makeRecordUri} from '#/lib/strings/url-helpers' import {useSetMinimalShellMode} from '#/state/shell' import {PostThread as PostThreadComponent} from '#/view/com/post-thread/PostThread' -import {atoms as a} from '#/alf' import * as Layout from '#/components/Layout' type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'> @@ -24,9 +22,7 @@ export function PostThreadScreen({route}: Props) { return ( <Layout.Screen testID="postThreadScreen"> - <View style={a.flex_1}> - <PostThreadComponent uri={uri} /> - </View> + <PostThreadComponent uri={uri} /> </Layout.Screen> ) } diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 677fe09f4..6a9b6f7f2 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -40,11 +40,9 @@ import {PagerWithHeader} from '#/view/com/pager/PagerWithHeader' import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' import {FAB} from '#/view/com/util/fab/FAB' import {ListRef} from '#/view/com/util/List' -import {CenteredView} from '#/view/com/util/Views' import {ProfileHeader, ProfileHeaderLoading} from '#/screens/Profile/Header' import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed' import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels' -import {web} from '#/alf' import * as Layout from '#/components/Layout' import {ScreenHider} from '#/components/moderation/ScreenHider' import {ProfileStarterPacks} from '#/components/StarterPack/ProfileStarterPacks' @@ -116,9 +114,9 @@ function ProfileScreenInner({route}: Props) { // Most pushes will happen here, since we will have only placeholder data if (isLoadingDid || isLoadingProfile || starterPacksQuery.isLoading) { return ( - <CenteredView sideBorders style={web({height: '100vh'})}> + <Layout.Content> <ProfileHeaderLoading /> - </CenteredView> + </Layout.Content> ) } if (resolveError || profileError) { diff --git a/src/view/screens/ProfileFeed.tsx b/src/view/screens/ProfileFeed.tsx index b34f0f1b0..63469ef4f 100644 --- a/src/view/screens/ProfileFeed.tsx +++ b/src/view/screens/ProfileFeed.tsx @@ -49,7 +49,6 @@ import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' import {LoadingScreen} from '#/view/com/util/LoadingScreen' import {Text} from '#/view/com/util/text/Text' import * as Toast from '#/view/com/util/Toast' -import {CenteredView} from '#/view/com/util/Views' import {atoms as a, useTheme} from '#/alf' import {Button as NewButton, ButtonText} from '#/components/Button' import {useRichText} from '#/components/hooks/useRichText' @@ -98,7 +97,7 @@ export function ProfileFeedScreen(props: Props) { if (error) { return ( <Layout.Screen testID="profileFeedScreenError"> - <CenteredView> + <Layout.Content> <View style={[pal.view, pal.border, styles.notFoundContainer]}> <Text type="title-lg" style={[pal.text, s.mb10]}> <Trans>Could not load feed</Trans> @@ -120,7 +119,7 @@ export function ProfileFeedScreen(props: Props) { </Button> </View> </View> - </CenteredView> + </Layout.Content> </Layout.Screen> ) } @@ -394,7 +393,7 @@ export function ProfileFeedScreenInner({ ]) return ( - <View style={s.hContentRegion}> + <> <ReportDialog control={reportDialogControl} params={{ @@ -434,7 +433,7 @@ export function ProfileFeedScreenInner({ accessibilityHint="" /> )} - </View> + </> ) } diff --git a/src/view/screens/ProfileFollowers.tsx b/src/view/screens/ProfileFollowers.tsx index 9fa98cb1a..90c0a57f9 100644 --- a/src/view/screens/ProfileFollowers.tsx +++ b/src/view/screens/ProfileFollowers.tsx @@ -10,7 +10,6 @@ import {ProfileFollowers as ProfileFollowersComponent} from '#/view/com/profile/ import {ViewHeader} from '#/view/com/util/ViewHeader' import {CenteredView} from '#/view/com/util/Views' import * as Layout from '#/components/Layout' -import {ListHeaderDesktop} from '#/components/Lists' type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollowers'> export const ProfileFollowersScreen = ({route}: Props) => { @@ -27,7 +26,6 @@ export const ProfileFollowersScreen = ({route}: Props) => { return ( <Layout.Screen testID="profileFollowersScreen"> <CenteredView sideBorders={true}> - <ListHeaderDesktop title={_(msg`Followers`)} /> <ViewHeader title={_(msg`Followers`)} showBorder={!isWeb} /> <ProfileFollowersComponent name={name} /> </CenteredView> diff --git a/src/view/screens/ProfileFollows.tsx b/src/view/screens/ProfileFollows.tsx index 483ee93ec..134f79993 100644 --- a/src/view/screens/ProfileFollows.tsx +++ b/src/view/screens/ProfileFollows.tsx @@ -10,7 +10,6 @@ import {ProfileFollows as ProfileFollowsComponent} from '#/view/com/profile/Prof import {ViewHeader} from '#/view/com/util/ViewHeader' import {CenteredView} from '#/view/com/util/Views' import * as Layout from '#/components/Layout' -import {ListHeaderDesktop} from '#/components/Lists' type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollows'> export const ProfileFollowsScreen = ({route}: Props) => { @@ -27,7 +26,6 @@ export const ProfileFollowsScreen = ({route}: Props) => { return ( <Layout.Screen testID="profileFollowsScreen"> <CenteredView sideBorders={true}> - <ListHeaderDesktop title={_(msg`Following`)} /> <ViewHeader title={_(msg`Following`)} showBorder={!isWeb} /> <ProfileFollowsComponent name={name} /> </CenteredView> diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx index cb333befa..a927526ad 100644 --- a/src/view/screens/ProfileList.tsx +++ b/src/view/screens/ProfileList.tsx @@ -69,7 +69,6 @@ import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' import {LoadingScreen} from '#/view/com/util/LoadingScreen' import {Text} from '#/view/com/util/text/Text' import * as Toast from '#/view/com/util/Toast' -import {CenteredView} from '#/view/com/util/Views' import {ListHiddenScreen} from '#/screens/List/ListHiddenScreen' import {atoms as a, useTheme} from '#/alf' import {useDialogControl} from '#/components/Dialog' @@ -107,20 +106,20 @@ function ProfileListScreenInner(props: Props) { if (resolveError) { return ( - <CenteredView> + <Layout.Content> <ErrorScreen error={_( msg`We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @${handleOrDid}.`, )} /> - </CenteredView> + </Layout.Content> ) } if (listError) { return ( - <CenteredView> + <Layout.Content> <ErrorScreen error={cleanError(listError)} /> - </CenteredView> + </Layout.Content> ) } @@ -1010,7 +1009,6 @@ function ErrorScreen({error}: {error: string}) { pal.view, pal.border, { - marginTop: 10, paddingHorizontal: 18, paddingVertical: 14, borderTopWidth: StyleSheet.hairlineWidth, diff --git a/src/view/screens/SavedFeeds.tsx b/src/view/screens/SavedFeeds.tsx index 3c04ec36f..1b4c84a60 100644 --- a/src/view/screens/SavedFeeds.tsx +++ b/src/view/screens/SavedFeeds.tsx @@ -25,13 +25,12 @@ import {FeedSourceCard} from '#/view/com/feeds/FeedSourceCard' import {TextLink} from '#/view/com/util/Link' import {Text} from '#/view/com/util/text/Text' import * as Toast from '#/view/com/util/Toast' -import {ViewHeader} from '#/view/com/util/ViewHeader' -import {CenteredView, ScrollView} from '#/view/com/util/Views' import {NoFollowingFeed} from '#/screens/Feeds/NoFollowingFeed' import {NoSavedFeedsOfAnyType} from '#/screens/Feeds/NoSavedFeedsOfAnyType' import {atoms as a, useTheme} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline' +import {FloppyDisk_Stroke2_Corner0_Rounded as SaveIcon} from '#/components/icons/FloppyDisk' import * as Layout from '#/components/Layout' import {Loader} from '#/components/Loader' @@ -51,7 +50,7 @@ function SavedFeedsInner({ }) { const pal = usePalette('default') const {_} = useLingui() - const {isMobile, isTabletOrDesktop, isDesktop} = useWebMediaQueries() + const {isMobile, isDesktop} = useWebMediaQueries() const setMinimalShellMode = useSetMinimalShellMode() const {mutateAsync: overwriteSavedFeeds, isPending: isOverwritePending} = useOverwriteSavedFeedsMutation() @@ -88,136 +87,128 @@ function SavedFeedsInner({ } }, [_, overwriteSavedFeeds, currentFeeds, navigation]) - const renderHeaderBtn = React.useCallback(() => { - return ( - <Button - size="small" - variant={hasUnsavedChanges ? 'solid' : 'solid'} - color={hasUnsavedChanges ? 'primary' : 'secondary'} - onPress={onSaveChanges} - label={_(msg`Save changes`)} - disabled={isOverwritePending || !hasUnsavedChanges} - style={[isDesktop && a.mt_sm]} - testID="saveChangesBtn"> - <ButtonText style={[isDesktop && a.text_md]}> - {isDesktop ? <Trans>Save changes</Trans> : <Trans>Save</Trans>} - </ButtonText> - {isOverwritePending && <ButtonIcon icon={Loader} />} - </Button> - ) - }, [_, isDesktop, onSaveChanges, hasUnsavedChanges, isOverwritePending]) - return ( <Layout.Screen> - <CenteredView - style={[a.util_screen_outer]} - sideBorders={isTabletOrDesktop}> - <ViewHeader - title={_(msg`Edit My Feeds`)} - showOnDesktop - showBorder - renderButton={renderHeaderBtn} - /> - <ScrollView style={[a.flex_1]} contentContainerStyle={[a.border_0]}> - {noSavedFeedsOfAnyType && ( - <View style={[pal.border, a.border_b]}> - <NoSavedFeedsOfAnyType /> - </View> - )} + <Layout.Header.Outer> + <Layout.Header.BackButton /> + <Layout.Header.Content align="left"> + <Layout.Header.TitleText> + <Trans>Feeds</Trans> + </Layout.Header.TitleText> + </Layout.Header.Content> + <Button + testID="saveChangesBtn" + size="small" + variant={hasUnsavedChanges ? 'solid' : 'solid'} + color={hasUnsavedChanges ? 'primary' : 'secondary'} + onPress={onSaveChanges} + label={_(msg`Save changes`)} + disabled={isOverwritePending || !hasUnsavedChanges}> + <ButtonIcon icon={isOverwritePending ? Loader : SaveIcon} /> + <ButtonText> + {isDesktop ? <Trans>Save changes</Trans> : <Trans>Save</Trans>} + </ButtonText> + </Button> + </Layout.Header.Outer> - <View style={[pal.text, pal.border, styles.title]}> - <Text type="title" style={pal.text}> - <Trans>Pinned Feeds</Trans> - </Text> + <Layout.Content> + {noSavedFeedsOfAnyType && ( + <View style={[pal.border, a.border_b]}> + <NoSavedFeedsOfAnyType /> </View> + )} - {preferences ? ( - !pinnedFeeds.length ? ( - <View - style={[ - pal.border, - isMobile && s.flex1, - pal.viewLight, - styles.empty, - ]}> - <Text type="lg" style={[pal.text]}> - <Trans>You don't have any pinned feeds.</Trans> - </Text> - </View> - ) : ( - pinnedFeeds.map(f => ( - <ListItem - key={f.id} - feed={f} - isPinned - currentFeeds={currentFeeds} - setCurrentFeeds={setCurrentFeeds} - preferences={preferences} - /> - )) - ) - ) : ( - <ActivityIndicator style={{marginTop: 20}} /> - )} + <View style={[pal.text, pal.border, styles.title]}> + <Text type="title" style={pal.text}> + <Trans>Pinned Feeds</Trans> + </Text> + </View> - {noFollowingFeed && ( - <View style={[pal.border, a.border_b]}> - <NoFollowingFeed /> + {preferences ? ( + !pinnedFeeds.length ? ( + <View + style={[ + pal.border, + isMobile && s.flex1, + pal.viewLight, + styles.empty, + ]}> + <Text type="lg" style={[pal.text]}> + <Trans>You don't have any pinned feeds.</Trans> + </Text> </View> - )} + ) : ( + pinnedFeeds.map(f => ( + <ListItem + key={f.id} + feed={f} + isPinned + currentFeeds={currentFeeds} + setCurrentFeeds={setCurrentFeeds} + preferences={preferences} + /> + )) + ) + ) : ( + <ActivityIndicator style={{marginTop: 20}} /> + )} - <View style={[pal.text, pal.border, styles.title]}> - <Text type="title" style={pal.text}> - <Trans>Saved Feeds</Trans> - </Text> + {noFollowingFeed && ( + <View style={[pal.border, a.border_b]}> + <NoFollowingFeed /> </View> - {preferences ? ( - !unpinnedFeeds.length ? ( - <View - style={[ - pal.border, - isMobile && s.flex1, - pal.viewLight, - styles.empty, - ]}> - <Text type="lg" style={[pal.text]}> - <Trans>You don't have any saved feeds.</Trans> - </Text> - </View> - ) : ( - unpinnedFeeds.map(f => ( - <ListItem - key={f.id} - feed={f} - isPinned={false} - currentFeeds={currentFeeds} - setCurrentFeeds={setCurrentFeeds} - preferences={preferences} - /> - )) - ) + )} + + <View style={[pal.text, pal.border, styles.title]}> + <Text type="title" style={pal.text}> + <Trans>Saved Feeds</Trans> + </Text> + </View> + {preferences ? ( + !unpinnedFeeds.length ? ( + <View + style={[ + pal.border, + isMobile && s.flex1, + pal.viewLight, + styles.empty, + ]}> + <Text type="lg" style={[pal.text]}> + <Trans>You don't have any saved feeds.</Trans> + </Text> + </View> ) : ( - <ActivityIndicator style={{marginTop: 20}} /> - )} + unpinnedFeeds.map(f => ( + <ListItem + key={f.id} + feed={f} + isPinned={false} + currentFeeds={currentFeeds} + setCurrentFeeds={setCurrentFeeds} + preferences={preferences} + /> + )) + ) + ) : ( + <ActivityIndicator style={{marginTop: 20}} /> + )} - <View style={styles.footerText}> - <Text type="sm" style={pal.textLight}> - <Trans> - Feeds are custom algorithms that users build with a little - coding expertise.{' '} - <TextLink - type="sm" - style={pal.link} - href="https://github.com/bluesky-social/feed-generator" - text={_(msg`See this guide`)} - />{' '} - for more information. - </Trans> - </Text> - </View> - <View style={{height: 100}} /> - </ScrollView> - </CenteredView> + <View style={styles.footerText}> + <Text type="sm" style={pal.textLight}> + <Trans> + Feeds are custom algorithms that users build with a little coding + expertise.{' '} + <TextLink + type="sm" + style={pal.link} + href="https://github.com/bluesky-social/feed-generator" + text={_(msg`See this guide`)} + />{' '} + for more information. + </Trans> + </Text> + </View> + </Layout.Content> </Layout.Screen> ) } @@ -456,7 +447,6 @@ const styles = StyleSheet.create({ }, footerText: { paddingHorizontal: 26, - paddingTop: 22, - paddingBottom: 100, + paddingVertical: 22, }, }) diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx index 0518bc506..0871458c9 100644 --- a/src/view/screens/Search/Search.tsx +++ b/src/view/screens/Search/Search.tsx @@ -55,7 +55,6 @@ import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard' import {Link} from '#/view/com/util/Link' import {List} from '#/view/com/util/List' import {Text} from '#/view/com/util/text/Text' -import {CenteredView, ScrollView} from '#/view/com/util/Views' import {Explore} from '#/view/screens/Search/Explore' import {SearchLinkCard, SearchProfileCard} from '#/view/shell/desktop/Search' import {makeSearchQuery, parseSearchQuery} from '#/screens/Search/utils' @@ -68,63 +67,46 @@ import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu' import * as Layout from '#/components/Layout' function Loader() { - const pal = usePalette('default') - const {isMobile} = useWebMediaQueries() return ( - <CenteredView - style={[ - // @ts-ignore web only -prf - { - padding: 18, - height: isWeb ? '100vh' : undefined, - }, - pal.border, - ]} - sideBorders={!isMobile}> - <ActivityIndicator /> - </CenteredView> + <Layout.Content> + <View style={[a.py_xl]}> + <ActivityIndicator /> + </View> + </Layout.Content> ) } function EmptyState({message, error}: {message: string; error?: string}) { const pal = usePalette('default') - const {isMobile} = useWebMediaQueries() return ( - <CenteredView - sideBorders={!isMobile} - style={[ - pal.border, - // @ts-ignore web only -prf - { - padding: 18, - height: isWeb ? '100vh' : undefined, - }, - ]}> - <View style={[pal.viewLight, {padding: 18, borderRadius: 8}]}> - <Text style={[pal.text]}>{message}</Text> + <Layout.Content> + <View style={[a.p_xl]}> + <View style={[pal.viewLight, {padding: 18, borderRadius: 8}]}> + <Text style={[pal.text]}>{message}</Text> - {error && ( - <> - <View - style={[ - { - marginVertical: 12, - height: 1, - width: '100%', - backgroundColor: pal.text.color, - opacity: 0.2, - }, - ]} - /> + {error && ( + <> + <View + style={[ + { + marginVertical: 12, + height: 1, + width: '100%', + backgroundColor: pal.text.color, + opacity: 0.2, + }, + ]} + /> - <Text style={[pal.textLight]}> - <Trans>Error:</Trans> {error} - </Text> - </> - )} + <Text style={[pal.textLight]}> + <Trans>Error:</Trans> {error} + </Text> + </> + )} + </View> </View> - </CenteredView> + </Layout.Content> ) } @@ -224,7 +206,7 @@ let SearchScreenPostResults = ({ if (item.type === 'post') { return <Post post={item.post} /> } else { - return <Loader /> + return null } }} keyExtractor={item => item.key} @@ -550,19 +532,13 @@ let SearchScreenInner = ({ <Pager onPageSelected={onPageSelected} renderTabBar={props => ( - <CenteredView - sideBorders + <Layout.Center style={[ - pal.border, - pal.view, - web({ - position: isWeb ? 'sticky' : '', - zIndex: 1, - }), + web([a.sticky, a.z_10]), {top: isWeb ? headerHeight : undefined}, ]}> <TabBar items={sections.map(section => section.title)} {...props} /> - </CenteredView> + </Layout.Center> )} initialPage={0}> {sections.map((section, i) => ( @@ -572,7 +548,7 @@ let SearchScreenInner = ({ ) : hasSession ? ( <Explore /> ) : ( - <CenteredView sideBorders style={pal.border}> + <Layout.Center> <View // @ts-ignore web only -esb style={{ @@ -614,7 +590,7 @@ let SearchScreenInner = ({ </Text> </View> </View> - </CenteredView> + </Layout.Center> ) } SearchScreenInner = React.memo(SearchScreenInner) @@ -650,7 +626,7 @@ export function SearchScreen( * Arbitrary sizing, so guess and check, used for sticky header alignment and * sizing. */ - const headerHeight = 64 + (showFilters ? 40 : 0) + const headerHeight = 60 + (showFilters ? 40 : 0) useFocusEffect( useNonReactiveCallback(() => { @@ -861,73 +837,79 @@ export function SearchScreen( return ( <Layout.Screen testID="searchScreen"> - <CenteredView + <View style={[ - a.p_md, - a.pb_sm, - a.gap_sm, - t.atoms.bg, web({ height: headerHeight, position: 'sticky', top: 0, zIndex: 1, }), - ]} - sideBorders={gtMobile}> - <View style={[a.flex_row, a.gap_sm]}> - {!gtMobile && ( - <Button - testID="viewHeaderBackOrMenuBtn" - onPress={onPressMenu} - hitSlop={HITSLOP_10} - label={_(msg`Menu`)} - accessibilityHint={_(msg`Access navigation links and settings`)} - size="large" - variant="solid" - color="secondary" - shape="square"> - <ButtonIcon icon={Menu} size="lg" /> - </Button> - )} - <View style={[a.flex_1]}> - <SearchInput - ref={textInput} - value={searchText} - onFocus={onSearchInputFocus} - onChangeText={onChangeText} - onClearText={onPressClearQuery} - onSubmitEditing={onSubmit} - /> - </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> - )} - </View> - - {showFilters && ( - <View - style={[a.flex_row, a.align_center, a.justify_between, a.gap_sm]}> - <View style={[{width: 140}]}> - <SearchLanguageDropdown - value={params.lang} - onChange={params.setLang} - /> + ]}> + <Layout.Center> + <View style={[a.p_md, a.pb_sm, a.gap_sm, t.atoms.bg]}> + <View style={[a.flex_row, a.gap_sm]}> + {!gtMobile && ( + <Button + testID="viewHeaderBackOrMenuBtn" + onPress={onPressMenu} + hitSlop={HITSLOP_10} + label={_(msg`Menu`)} + accessibilityHint={_( + msg`Access navigation links and settings`, + )} + size="large" + variant="solid" + color="secondary" + shape="square"> + <ButtonIcon icon={Menu} size="lg" /> + </Button> + )} + <View style={[a.flex_1]}> + <SearchInput + ref={textInput} + value={searchText} + onFocus={onSearchInputFocus} + onChangeText={onChangeText} + onClearText={onPressClearQuery} + onSubmitEditing={onSubmit} + /> + </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> + )} </View> + + {showFilters && ( + <View + style={[ + a.flex_row, + a.align_center, + a.justify_between, + a.gap_sm, + ]}> + <View style={[{width: 140}]}> + <SearchLanguageDropdown + value={params.lang} + onChange={params.setLang} + /> + </View> + </View> + )} </View> - )} - </CenteredView> + </Layout.Center> + </View> <View style={{ @@ -992,10 +974,7 @@ let AutocompleteResults = ({ !moderationOpts ? ( <Loader /> ) : ( - <ScrollView - style={{height: '100%'}} - // @ts-ignore web only -prf - dataSet={{stableGutters: '1'}} + <Layout.Content keyboardShouldPersistTaps="handled" keyboardDismissMode="on-drag"> <SearchLinkCard @@ -1020,7 +999,7 @@ let AutocompleteResults = ({ /> ))} <View style={{height: 200}} /> - </ScrollView> + </Layout.Content> )} </> ) @@ -1042,17 +1021,12 @@ function SearchHistory({ onRemoveItemClick: (item: string) => void onRemoveProfileClick: (profile: AppBskyActorDefs.ProfileViewBasic) => void }) { - const {isTabletOrDesktop, isMobile} = useWebMediaQueries() + const {isMobile} = useWebMediaQueries() const pal = usePalette('default') const {_} = useLingui() return ( - <CenteredView - sideBorders={isTabletOrDesktop} - // @ts-ignore web only -prf - style={{ - height: isWeb ? '100vh' : undefined, - }}> + <Layout.Content> <View style={styles.searchHistoryContainer}> {(searchHistory.length > 0 || selectedProfiles.length > 0) && ( <Text style={[pal.text, styles.searchHistoryTitle]}> @@ -1152,7 +1126,7 @@ function SearchHistory({ </View> )} </View> - </CenteredView> + </Layout.Content> ) } |