From 1ccb3be961795c569c8c1eb64ca0617bd6548e79 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 22 Feb 2024 16:03:20 +0000 Subject: Refactor feed header components (#2964) * Move home-related files to view/com/home * Add HomeHeader in front of FeedTabBar * Move isDekstop check outside FeedsTabBar * Remove PWI logic from tabbar * Separate platform-specific layout from shared logic --- src/view/com/home/HomeHeader.tsx | 71 +++++++++++ src/view/com/home/HomeHeaderLayout.tsx | 1 + src/view/com/home/HomeHeaderLayout.web.tsx | 50 ++++++++ src/view/com/home/HomeHeaderLayoutMobile.tsx | 119 +++++++++++++++++++ src/view/com/pager/FeedsTabBar.tsx | 1 - src/view/com/pager/FeedsTabBar.web.tsx | 138 --------------------- src/view/com/pager/FeedsTabBarMobile.tsx | 171 --------------------------- src/view/screens/Home.tsx | 4 +- 8 files changed, 243 insertions(+), 312 deletions(-) create mode 100644 src/view/com/home/HomeHeader.tsx create mode 100644 src/view/com/home/HomeHeaderLayout.tsx create mode 100644 src/view/com/home/HomeHeaderLayout.web.tsx create mode 100644 src/view/com/home/HomeHeaderLayoutMobile.tsx delete mode 100644 src/view/com/pager/FeedsTabBar.tsx delete mode 100644 src/view/com/pager/FeedsTabBar.web.tsx delete mode 100644 src/view/com/pager/FeedsTabBarMobile.tsx (limited to 'src') diff --git a/src/view/com/home/HomeHeader.tsx b/src/view/com/home/HomeHeader.tsx new file mode 100644 index 000000000..5ffa31f39 --- /dev/null +++ b/src/view/com/home/HomeHeader.tsx @@ -0,0 +1,71 @@ +import React from 'react' +import {RenderTabBarFnProps} from 'view/com/pager/Pager' +import {HomeHeaderLayout} from './HomeHeaderLayout' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {usePinnedFeedsInfos} from '#/state/queries/feed' +import {useNavigation} from '@react-navigation/native' +import {NavigationProp} from 'lib/routes/types' +import {isWeb} from 'platform/detection' +import {TabBar} from '../pager/TabBar' +import {usePalette} from '#/lib/hooks/usePalette' + +export function HomeHeader( + props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, +) { + const {isDesktop} = useWebMediaQueries() + if (isDesktop) { + return null + } + return +} + +export function HomeHeaderInner( + props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, +) { + const navigation = useNavigation() + const {feeds, hasPinnedCustom} = usePinnedFeedsInfos() + const pal = usePalette('default') + + const items = React.useMemo(() => { + const pinnedNames = feeds.map(f => f.displayName) + + if (!hasPinnedCustom) { + return pinnedNames.concat('Feeds ✨') + } + return pinnedNames + }, [hasPinnedCustom, feeds]) + + const onPressFeedsLink = React.useCallback(() => { + if (isWeb) { + navigation.navigate('Feeds') + } else { + navigation.navigate('FeedsTab') + navigation.popToTop() + } + }, [navigation]) + + const onSelect = React.useCallback( + (index: number) => { + if (!hasPinnedCustom && index === items.length - 1) { + onPressFeedsLink() + } else if (props.onSelect) { + props.onSelect(index) + } + }, + [items.length, onPressFeedsLink, props, hasPinnedCustom], + ) + + return ( + + + + ) +} diff --git a/src/view/com/home/HomeHeaderLayout.tsx b/src/view/com/home/HomeHeaderLayout.tsx new file mode 100644 index 000000000..70bf064d4 --- /dev/null +++ b/src/view/com/home/HomeHeaderLayout.tsx @@ -0,0 +1 @@ +export {HomeHeaderLayoutMobile as HomeHeaderLayout} from './HomeHeaderLayoutMobile' diff --git a/src/view/com/home/HomeHeaderLayout.web.tsx b/src/view/com/home/HomeHeaderLayout.web.tsx new file mode 100644 index 000000000..47cb00235 --- /dev/null +++ b/src/view/com/home/HomeHeaderLayout.web.tsx @@ -0,0 +1,50 @@ +import React from 'react' +import {StyleSheet} from 'react-native' +import Animated from 'react-native-reanimated' +import {usePalette} from 'lib/hooks/usePalette' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {HomeHeaderLayoutMobile} from './HomeHeaderLayoutMobile' +import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' +import {useShellLayout} from '#/state/shell/shell-layout' + +export function HomeHeaderLayout({children}: {children: React.ReactNode}) { + const {isMobile} = useWebMediaQueries() + if (isMobile) { + return {children} + } else { + return {children} + } +} + +function HomeHeaderLayoutTablet({children}: {children: React.ReactNode}) { + const pal = usePalette('default') + const {headerMinimalShellTransform} = useMinimalShellMode() + const {headerHeight} = useShellLayout() + + return ( + // @ts-ignore the type signature for transform wrong here, translateX and translateY need to be in separate objects -prf + { + headerHeight.value = e.nativeEvent.layout.height + }}> + {children} + + ) +} + +const styles = StyleSheet.create({ + tabBar: { + // @ts-ignore Web only + position: 'sticky', + zIndex: 1, + // @ts-ignore Web only -prf + left: 'calc(50% - 300px)', + width: 600, + top: 0, + flexDirection: 'row', + alignItems: 'center', + borderLeftWidth: 1, + borderRightWidth: 1, + }, +}) diff --git a/src/view/com/home/HomeHeaderLayoutMobile.tsx b/src/view/com/home/HomeHeaderLayoutMobile.tsx new file mode 100644 index 000000000..0478f69a4 --- /dev/null +++ b/src/view/com/home/HomeHeaderLayoutMobile.tsx @@ -0,0 +1,119 @@ +import React from 'react' +import {StyleSheet, TouchableOpacity, View} from 'react-native' +import {usePalette} from 'lib/hooks/usePalette' +import {Link} from '../util/Link' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome' +import {HITSLOP_10} from 'lib/constants' +import Animated from 'react-native-reanimated' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' +import {useSetDrawerOpen} from '#/state/shell/drawer-open' +import {useShellLayout} from '#/state/shell/shell-layout' +import {isWeb} from 'platform/detection' +import {Logo} from '#/view/icons/Logo' + +import {IS_DEV} from '#/env' +import {atoms} from '#/alf' +import {Link as Link2} from '#/components/Link' +import {ColorPalette_Stroke2_Corner0_Rounded as ColorPalette} from '#/components/icons/ColorPalette' + +export function HomeHeaderLayoutMobile({ + children, +}: { + children: React.ReactNode +}) { + const pal = usePalette('default') + const {_} = useLingui() + const setDrawerOpen = useSetDrawerOpen() + const {headerHeight} = useShellLayout() + const {headerMinimalShellTransform} = useMinimalShellMode() + + const onPressAvi = React.useCallback(() => { + setDrawerOpen(true) + }, [setDrawerOpen]) + + return ( + { + headerHeight.value = e.nativeEvent.layout.height + }}> + + + + + + + + + + + {IS_DEV && ( + + + + )} + + + + + + {children} + + ) +} + +const styles = StyleSheet.create({ + tabBar: { + // @ts-ignore web-only + position: isWeb ? 'fixed' : 'absolute', + zIndex: 1, + left: 0, + right: 0, + top: 0, + flexDirection: 'column', + borderBottomWidth: 1, + }, + topBar: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingHorizontal: 18, + paddingVertical: 8, + width: '100%', + }, + title: { + fontSize: 21, + }, +}) diff --git a/src/view/com/pager/FeedsTabBar.tsx b/src/view/com/pager/FeedsTabBar.tsx deleted file mode 100644 index aa0ba7b24..000000000 --- a/src/view/com/pager/FeedsTabBar.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './FeedsTabBarMobile' diff --git a/src/view/com/pager/FeedsTabBar.web.tsx b/src/view/com/pager/FeedsTabBar.web.tsx deleted file mode 100644 index fb52b913a..000000000 --- a/src/view/com/pager/FeedsTabBar.web.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import React from 'react' -import {View, StyleSheet} from 'react-native' -import Animated from 'react-native-reanimated' -import {TabBar} from 'view/com/pager/TabBar' -import {RenderTabBarFnProps} from 'view/com/pager/Pager' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {FeedsTabBar as FeedsTabBarMobile} from './FeedsTabBarMobile' -import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' -import {useShellLayout} from '#/state/shell/shell-layout' -import {usePinnedFeedsInfos} from '#/state/queries/feed' -import {useSession} from '#/state/session' -import {TextLink} from '#/view/com/util/Link' -import {CenteredView} from '../util/Views' -import {isWeb} from 'platform/detection' -import {useNavigation} from '@react-navigation/native' -import {NavigationProp} from 'lib/routes/types' - -export function FeedsTabBar( - props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, -) { - const {isMobile, isTablet} = useWebMediaQueries() - const {hasSession} = useSession() - - if (isMobile) { - return - } else if (isTablet) { - if (hasSession) { - return - } else { - return - } - } else { - return null - } -} - -function FeedsTabBarPublic() { - const pal = usePalette('default') - - return ( - - - - - - ) -} - -function FeedsTabBarTablet( - props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, -) { - const {feeds, hasPinnedCustom} = usePinnedFeedsInfos() - const pal = usePalette('default') - const {hasSession} = useSession() - const navigation = useNavigation() - const {headerMinimalShellTransform} = useMinimalShellMode() - const {headerHeight} = useShellLayout() - - const items = React.useMemo(() => { - if (!hasSession) return [] - - const pinnedNames = feeds.map(f => f.displayName) - - if (!hasPinnedCustom) { - return pinnedNames.concat('Feeds ✨') - } - return pinnedNames - }, [hasSession, hasPinnedCustom, feeds]) - - const onPressDiscoverFeeds = React.useCallback(() => { - if (isWeb) { - navigation.navigate('Feeds') - } else { - navigation.navigate('FeedsTab') - navigation.popToTop() - } - }, [navigation]) - - const onSelect = React.useCallback( - (index: number) => { - if (hasSession && !hasPinnedCustom && index === items.length - 1) { - onPressDiscoverFeeds() - } else if (props.onSelect) { - props.onSelect(index) - } - }, - [items.length, onPressDiscoverFeeds, props, hasSession, hasPinnedCustom], - ) - - return ( - // @ts-ignore the type signature for transform wrong here, translateX and translateY need to be in separate objects -prf - { - headerHeight.value = e.nativeEvent.layout.height - }}> - - - ) -} - -const styles = StyleSheet.create({ - tabBar: { - // @ts-ignore Web only - position: 'sticky', - zIndex: 1, - // @ts-ignore Web only -prf - left: 'calc(50% - 300px)', - width: 600, - top: 0, - flexDirection: 'row', - alignItems: 'center', - borderLeftWidth: 1, - borderRightWidth: 1, - }, -}) diff --git a/src/view/com/pager/FeedsTabBarMobile.tsx b/src/view/com/pager/FeedsTabBarMobile.tsx deleted file mode 100644 index 4eba241ae..000000000 --- a/src/view/com/pager/FeedsTabBarMobile.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import React from 'react' -import {StyleSheet, TouchableOpacity, View} from 'react-native' -import {TabBar} from 'view/com/pager/TabBar' -import {RenderTabBarFnProps} from 'view/com/pager/Pager' -import {usePalette} from 'lib/hooks/usePalette' -import {Link} from '../util/Link' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome' -import {HITSLOP_10} from 'lib/constants' -import Animated from 'react-native-reanimated' -import {msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' -import {useSetDrawerOpen} from '#/state/shell/drawer-open' -import {useShellLayout} from '#/state/shell/shell-layout' -import {useSession} from '#/state/session' -import {usePinnedFeedsInfos} from '#/state/queries/feed' -import {isWeb} from 'platform/detection' -import {useNavigation} from '@react-navigation/native' -import {NavigationProp} from 'lib/routes/types' -import {Logo} from '#/view/icons/Logo' - -import {IS_DEV} from '#/env' -import {atoms} from '#/alf' -import {Link as Link2} from '#/components/Link' -import {ColorPalette_Stroke2_Corner0_Rounded as ColorPalette} from '#/components/icons/ColorPalette' - -export function FeedsTabBar( - props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, -) { - const pal = usePalette('default') - const {hasSession} = useSession() - const {_} = useLingui() - const setDrawerOpen = useSetDrawerOpen() - const navigation = useNavigation() - const {feeds, hasPinnedCustom} = usePinnedFeedsInfos() - const {headerHeight} = useShellLayout() - const {headerMinimalShellTransform} = useMinimalShellMode() - - const items = React.useMemo(() => { - if (!hasSession) return [] - - const pinnedNames = feeds.map(f => f.displayName) - - if (!hasPinnedCustom) { - return pinnedNames.concat('Feeds ✨') - } - return pinnedNames - }, [hasSession, hasPinnedCustom, feeds]) - - const onPressFeedsLink = React.useCallback(() => { - if (isWeb) { - navigation.navigate('Feeds') - } else { - navigation.navigate('FeedsTab') - navigation.popToTop() - } - }, [navigation]) - - const onSelect = React.useCallback( - (index: number) => { - if (hasSession && !hasPinnedCustom && index === items.length - 1) { - onPressFeedsLink() - } else if (props.onSelect) { - props.onSelect(index) - } - }, - [items.length, onPressFeedsLink, props, hasSession, hasPinnedCustom], - ) - - const onPressAvi = React.useCallback(() => { - setDrawerOpen(true) - }, [setDrawerOpen]) - - return ( - { - headerHeight.value = e.nativeEvent.layout.height - }}> - - - - - - - - - - - {IS_DEV && ( - - - - )} - - {hasSession && ( - - - - )} - - - - {items.length > 0 && ( - - )} - - ) -} - -const styles = StyleSheet.create({ - tabBar: { - // @ts-ignore web-only - position: isWeb ? 'fixed' : 'absolute', - zIndex: 1, - left: 0, - right: 0, - top: 0, - flexDirection: 'column', - borderBottomWidth: 1, - }, - topBar: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - paddingHorizontal: 18, - paddingVertical: 8, - width: '100%', - }, - title: { - fontSize: 21, - }, -}) diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index cb2abf1bc..856c237f6 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -6,7 +6,7 @@ import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed' import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState' import {FollowingEndOfFeed} from 'view/com/posts/FollowingEndOfFeed' import {CustomFeedEmptyState} from 'view/com/posts/CustomFeedEmptyState' -import {FeedsTabBar} from '../com/pager/FeedsTabBar' +import {HomeHeader} from '../com/home/HomeHeader' import {Pager, RenderTabBarFnProps, PagerRef} from 'view/com/pager/Pager' import {FeedPage} from 'view/com/feeds/FeedPage' import {HomeLoggedOutCTA} from '../com/auth/HomeLoggedOutCTA' @@ -118,7 +118,7 @@ function HomeScreenReady({ const renderTabBar = React.useCallback( (props: RenderTabBarFnProps) => { return ( -