From 29db02cab7bf4cbb8056e6df0ef6be6aa99e086a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Mon, 2 Dec 2024 17:11:27 -0600 Subject: [PATCH] Add new layout components --- src/components/Layout/Header/index.tsx | 160 +++++++++++++++++++++ src/components/Layout/index.tsx | 183 +++++++++++++++++++++++++ 2 files changed, 343 insertions(+) create mode 100644 src/components/Layout/Header/index.tsx create mode 100644 src/components/Layout/index.tsx diff --git a/src/components/Layout/Header/index.tsx b/src/components/Layout/Header/index.tsx new file mode 100644 index 0000000000..1cab3605d2 --- /dev/null +++ b/src/components/Layout/Header/index.tsx @@ -0,0 +1,160 @@ +import React from 'react' +import {View} from 'react-native' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useNavigation} from '@react-navigation/native' + +import {NavigationProp} from '#/lib/routes/types' +import {isIOS} from '#/platform/detection' +import {useSetDrawerOpen} from '#/state/shell' +import { + atoms as a, + useBreakpoints, + useGutterStyles, + useTheme, + ViewStyleProp, +} from '#/alf' +import {Button, ButtonIcon} from '#/components/Button' +import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft} from '#/components/icons/Arrow' +import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu' +import {Text} from '#/components/Typography' + +const BUTTON_VISUAL_ALIGNMENT_OFFSET = 3 +const BUTTON_SIZE = 34 // small button + +export function Outer({children}: {children: React.ReactNode}) { + const t = useTheme() + const gutter = useGutterStyles() + + return ( + + {children} + + ) +} + +export function Content({children}: {children: React.ReactNode}) { + return ( + + {children} + + ) +} + +export function Slot({ + children, + style, +}: {children?: React.ReactNode} & ViewStyleProp) { + return ( + + {children} + + ) +} + +export function BackButton() { + const {_} = useLingui() + const navigation = useNavigation() + + const onPressBack = React.useCallback(() => { + if (navigation.canGoBack()) { + navigation.goBack() + } else { + navigation.navigate('Home') + } + }, [navigation]) + + return ( + + + + ) +} + +export function MenuButton() { + const {_} = useLingui() + const setDrawerOpen = useSetDrawerOpen() + const {gtMobile} = useBreakpoints() + + const onPress = React.useCallback(() => { + setDrawerOpen(true) + }, [setDrawerOpen]) + + return gtMobile ? null : ( + + + + ) +} + +export function TitleText({children}: {children: React.ReactNode}) { + const {gtMobile} = useBreakpoints() + return ( + + {children} + + ) +} + +export function SubtitleText({children}: {children: React.ReactNode}) { + const t = useTheme() + return ( + + {children} + + ) +} diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx new file mode 100644 index 0000000000..26308a54c0 --- /dev/null +++ b/src/components/Layout/index.tsx @@ -0,0 +1,183 @@ +import React, {useContext, useMemo} from 'react' +import {StyleSheet, View, ViewProps, ViewStyle} from 'react-native' +import {StyleProp} from 'react-native' +import { + KeyboardAwareScrollView, + KeyboardAwareScrollViewProps, +} from 'react-native-keyboard-controller' +import Animated, {AnimatedScrollViewProps} from 'react-native-reanimated' +import {useSafeAreaInsets} from 'react-native-safe-area-context' + +import {isWeb} from '#/platform/detection' +import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' + +export * as Header from '#/components/Layout/Header' + +// Every screen should have a Layout component wrapping it. +// This component provides a default padding for the top of the screen. +// This allows certain screens to avoid the top padding if they want to. + +const LayoutContext = React.createContext({ + withinScreen: false, + topPaddingDisabled: false, + withinScrollView: false, +}) + +export type ScreenProps = React.ComponentProps & { + disableTopPadding?: boolean + style?: StyleProp +} + +/** + * Every screen should have a Layout.Screen component wrapping it. + * This component provides a default padding for the top of the screen + * and height/minHeight + */ +export const Screen = React.memo(function Screen({ + disableTopPadding = false, + style, + ...props +}: ScreenProps) { + const {top} = useSafeAreaInsets() + const context = useMemo( + () => ({ + withinScreen: true, + topPaddingDisabled: disableTopPadding, + withinScrollView: false, + }), + [disableTopPadding], + ) + return ( + + {isWeb && } + + + ) +}) + +export type ContentProps = AnimatedScrollViewProps & { + style?: StyleProp + contentContainerStyle?: StyleProp +} + +export const Content = React.memo(function Content({ + children, + style, + contentContainerStyle, + ...props +}: ContentProps) { + const context = useContext(LayoutContext) + const newContext = useMemo( + () => ({...context, withinScrollView: true}), + [context], + ) + return ( + + + {isWeb ? ( + // @ts-ignore web only -esb +
{children}
+ ) : ( + children + )} +
+
+ ) +}) + +export type KeyboardAwareContentProps = KeyboardAwareScrollViewProps & { + children: React.ReactNode + contentContainerStyle?: StyleProp +} + +export const KeyboardAwareContent = React.forwardRef(function LayoutScrollView( + {children, style, contentContainerStyle, ...props}: KeyboardAwareContentProps, + _ref: React.Ref, +) { + return ( + + {isWeb ?
{children}
: children} +
+ ) +}) + +export const WebCenterBorders = React.forwardRef(function LayoutContent() { + const t = useTheme() + const {gtMobile} = useBreakpoints() + return gtMobile ? ( + + ) : null +}) + +export const Center = React.forwardRef(function LayoutContent( + {children, style, ...props}: ViewProps, + ref: React.Ref, +) { + const {gtMobile} = useBreakpoints() + return ( + + {children} + + ) +}) + +const styles = StyleSheet.create({ + scrollViewCommonStyles: { + width: '100%', + }, + scrollViewContentContainer: { + paddingBottom: 100, + }, +})