diff options
Diffstat (limited to 'src/view/com/home')
-rw-r--r-- | src/view/com/home/HomeHeader.tsx | 71 | ||||
-rw-r--r-- | src/view/com/home/HomeHeaderLayout.tsx | 1 | ||||
-rw-r--r-- | src/view/com/home/HomeHeaderLayout.web.tsx | 50 | ||||
-rw-r--r-- | src/view/com/home/HomeHeaderLayoutMobile.tsx | 119 |
4 files changed, 241 insertions, 0 deletions
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 <HomeHeaderInner {...props} /> +} + +export function HomeHeaderInner( + props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, +) { + const navigation = useNavigation<NavigationProp>() + 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 ( + <HomeHeaderLayout> + <TabBar + key={items.join(',')} + onPressSelected={props.onPressSelected} + selectedPage={props.selectedPage} + onSelect={onSelect} + testID={props.testID} + items={items} + indicatorColor={pal.colors.link} + /> + </HomeHeaderLayout> + ) +} 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 <HomeHeaderLayoutMobile>{children}</HomeHeaderLayoutMobile> + } else { + return <HomeHeaderLayoutTablet>{children}</HomeHeaderLayoutTablet> + } +} + +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 + <Animated.View + style={[pal.view, pal.border, styles.tabBar, headerMinimalShellTransform]} + onLayout={e => { + headerHeight.value = e.nativeEvent.layout.height + }}> + {children} + </Animated.View> + ) +} + +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 ( + <Animated.View + style={[pal.view, pal.border, styles.tabBar, headerMinimalShellTransform]} + onLayout={e => { + headerHeight.value = e.nativeEvent.layout.height + }}> + <View style={[pal.view, styles.topBar]}> + <View style={[pal.view, {width: 100}]}> + <TouchableOpacity + testID="viewHeaderDrawerBtn" + onPress={onPressAvi} + accessibilityRole="button" + accessibilityLabel={_(msg`Open navigation`)} + accessibilityHint={_( + msg`Access profile and other navigation links`, + )} + hitSlop={HITSLOP_10}> + <FontAwesomeIcon + icon="bars" + size={18} + color={pal.colors.textLight} + /> + </TouchableOpacity> + </View> + <View> + <Logo width={30} /> + </View> + <View + style={[ + atoms.flex_row, + atoms.justify_end, + atoms.align_center, + atoms.gap_md, + pal.view, + {width: 100}, + ]}> + {IS_DEV && ( + <Link2 to="/sys/debug"> + <ColorPalette size="md" /> + </Link2> + )} + <Link + testID="viewHeaderHomeFeedPrefsBtn" + href="/settings/home-feed" + hitSlop={HITSLOP_10} + accessibilityRole="button" + accessibilityLabel={_(msg`Home Feed Preferences`)} + accessibilityHint=""> + <FontAwesomeIcon + icon="sliders" + style={pal.textLight as FontAwesomeIconStyle} + /> + </Link> + </View> + </View> + {children} + </Animated.View> + ) +} + +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, + }, +}) |