From 48414c77030dbfefda75ef0b49b51051591f798c Mon Sep 17 00:00:00 2001 From: Mateusz Rostkowski Date: Sat, 6 Apr 2024 14:43:38 +0200 Subject: [PATCH 1/9] fix: properly display modal on web --- src/components/Modal.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index 0e33d720..9f138e0c 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -1,4 +1,5 @@ import { useTheme } from '@baca/hooks' +import { hex2rgba } from '@baca/utils' import { Modal as RNModal, ModalProps, @@ -48,7 +49,10 @@ export const Modal = ({ > {children} @@ -66,10 +70,10 @@ const styles = StyleSheet.create({ justifyContent: 'center', }, scroll: { - paddingHorizontal: 32, width: '100%', }, scrollContent: { justifyContent: 'center', + paddingHorizontal: 32, }, }) From ef158dc4eae6e82ce1e03b37c70a44c6eaad8a78 Mon Sep 17 00:00:00 2001 From: Mateusz Rostkowski Date: Sat, 6 Apr 2024 14:44:32 +0200 Subject: [PATCH 2/9] feat: create full screen modal component --- src/design-system/modals/FullScreenModal.tsx | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/design-system/modals/FullScreenModal.tsx diff --git a/src/design-system/modals/FullScreenModal.tsx b/src/design-system/modals/FullScreenModal.tsx new file mode 100644 index 00000000..062148fa --- /dev/null +++ b/src/design-system/modals/FullScreenModal.tsx @@ -0,0 +1,37 @@ +import { useBoolean, useImperativeHandle } from '@baca/hooks' +import { RefObject } from 'react' +import { Modal, ModalProps } from 'react-native' + +import { Box } from '../components' + +export type ModalMethods = { + present: () => void + close: () => void +} + +type Props = { + modalRef: RefObject +} & ModalProps + +export const FullScreenModal = ({ children, modalRef, ...rest }: Props) => { + const [isOpen, setIsOpen] = useBoolean(false) + + useImperativeHandle(modalRef, () => ({ + present: setIsOpen.on, + close: setIsOpen.off, + })) + + return ( + + + {children} + + + ) +} From 889bfcd6627dc5c2ca70b72b7df734bc20f30eff Mon Sep 17 00:00:00 2001 From: Mateusz Rostkowski Date: Sat, 6 Apr 2024 16:09:19 +0200 Subject: [PATCH 3/9] chore: add hooks to use full screen modal --- src/design-system/index.ts | 1 + src/design-system/modals/index.tsx | 2 ++ .../modals/useFullScreenModal.tsx | 25 +++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 src/design-system/modals/index.tsx create mode 100644 src/design-system/modals/useFullScreenModal.tsx diff --git a/src/design-system/index.ts b/src/design-system/index.ts index 23fc4f22..a730caa7 100644 --- a/src/design-system/index.ts +++ b/src/design-system/index.ts @@ -1,4 +1,5 @@ export * from './bottomSheets' export * from './components' export * from './config' +export * from './modals' export * from './utils' diff --git a/src/design-system/modals/index.tsx b/src/design-system/modals/index.tsx new file mode 100644 index 00000000..55d94e12 --- /dev/null +++ b/src/design-system/modals/index.tsx @@ -0,0 +1,2 @@ +export * from './FullScreenModal' +export * from './useFullScreenModal' diff --git a/src/design-system/modals/useFullScreenModal.tsx b/src/design-system/modals/useFullScreenModal.tsx new file mode 100644 index 00000000..f04542b1 --- /dev/null +++ b/src/design-system/modals/useFullScreenModal.tsx @@ -0,0 +1,25 @@ +import { useCallback, useRef } from 'react' + +import { FullScreenModal, ModalMethods } from './FullScreenModal' + +export const useFullScreenModal = () => { + const modalRef = useRef(null) + + const modalComponentRenderFunction = (children: JSX.Element | JSX.Element[]) => { + return {children} + } + + const presentFullScreenModal = useCallback(() => { + modalRef.current?.present?.() + }, []) + + const closeFullScreenModal = useCallback(() => { + modalRef.current?.close?.() + }, []) + + return { + modalComponentRenderFunction, + presentFullScreenModal, + closeFullScreenModal, + } +} From 06f4ab82cd9566a40504ec4af378f12c7e8c4fd3 Mon Sep 17 00:00:00 2001 From: Mateusz Rostkowski Date: Sat, 6 Apr 2024 16:10:20 +0200 Subject: [PATCH 4/9] fix: improve header on landing page --- src/components/LandingHeader.tsx | 114 ++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 33 deletions(-) diff --git a/src/components/LandingHeader.tsx b/src/components/LandingHeader.tsx index e28eb5af..3406184d 100644 --- a/src/components/LandingHeader.tsx +++ b/src/components/LandingHeader.tsx @@ -1,7 +1,9 @@ import { lightBinarLogo, darkBinarLogo } from '@baca/constants' import { useColorScheme } from '@baca/contexts' -import { Box, Button, Icon, Pressable, Spacer } from '@baca/design-system' -import { useCallback, useTheme, useTranslation } from '@baca/hooks' +import { Box, Button, Icon, Pressable, Row, Spacer, Touchable } from '@baca/design-system' +import { useFullScreenModal } from '@baca/design-system/modals/useFullScreenModal' +import { useCallback, useMemo, useTheme, useTranslation } from '@baca/hooks' +import { useWidth } from '@baca/navigation/tabNavigator/hooks' import { isSignedInAtom } from '@baca/store/auth' import { useRouter } from 'expo-router' import { useAtomValue } from 'jotai' @@ -15,43 +17,92 @@ export function LandingHeader() { const { t } = useTranslation() const { push, canGoBack, back } = useRouter() + const height = 60 + top + + const isDesktop = useWidth(768) + const isSignedIn = useAtomValue(isSignedInAtom) const navigateToLogin = useCallback(() => push('/sign-in'), [push]) const navigateToSignUp = useCallback(() => push('/sign-up'), [push]) - const height = 60 + top + const { closeFullScreenModal, modalComponentRenderFunction, presentFullScreenModal } = + useFullScreenModal() - return ( - - {canGoBack() ? ( - - - - ) : ( - - )} - {!isSignedIn ? ( - + const renderLeftMenu = useMemo(() => { + return canGoBack() ? ( + + + + ) : ( + + ) + }, [back, canGoBack, colorScheme]) + + const fullScreenModal = modalComponentRenderFunction( + + + {renderLeftMenu} + + + + + + + + + + + + ) + + const renderRightMenu = useMemo(() => { + if (isSignedIn) { + return + } + + if (isDesktop) { + return ( + - - ) : ( - - )} - + + ) + } + + return ( + + + + ) + }, [isDesktop, isSignedIn, navigateToLogin, navigateToSignUp, presentFullScreenModal, t]) + + return ( + <> + + {renderLeftMenu} + {renderRightMenu} + + {fullScreenModal} + ) } @@ -66,7 +117,4 @@ const jsStyles = StyleSheet.create({ zIndex: 10, }, logoWide: { height: 60, width: 150 }, - rowContainer: { - flexDirection: 'row', - }, }) From 00f7af1fc5987bc1bea8e4f60ece0fbce16a9b5b Mon Sep 17 00:00:00 2001 From: Mateusz Rostkowski Date: Sun, 7 Apr 2024 18:39:05 +0200 Subject: [PATCH 5/9] chore: extend react native types --- src/types/react-native.d.ts | 185 ++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/types/react-native.d.ts diff --git a/src/types/react-native.d.ts b/src/types/react-native.d.ts new file mode 100644 index 00000000..7da3fecd --- /dev/null +++ b/src/types/react-native.d.ts @@ -0,0 +1,185 @@ +// https://gist.github.com/sstur/9693aa41e95078c8c6bcf3d8f1216872 + +declare module 'react-native' { + // The following list is sourced from: + // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/types/styles.js#L76 + type CursorValue = + | 'alias' + | 'all-scroll' + | 'auto' + | 'cell' + | 'context-menu' + | 'copy' + | 'crosshair' + | 'default' + | 'grab' + | 'grabbing' + | 'help' + | 'pointer' + | 'progress' + | 'wait' + | 'text' + | 'vertical-text' + | 'move' + | 'none' + | 'no-drop' + | 'not-allowed' + | 'zoom-in' + | 'zoom-out' + | 'col-resize' + | 'e-resize' + | 'ew-resize' + | 'n-resize' + | 'ne-resize' + | 'ns-resize' + | 'nw-resize' + | 'row-resize' + | 's-resize' + | 'se-resize' + | 'sw-resize' + | 'w-resize' + | 'nesw-resize' + | 'nwse-resize' + + // This list is the combination of the following two lists: + // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/AccessibilityUtil/propsToAriaRole.js#L10 + // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/AccessibilityUtil/propsToAccessibilityComponent.js#L12 + // Plus the single hard-coded value "label" from here: + // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/modules/AccessibilityUtil/propsToAccessibilityComponent.js#L36 + type WebAccessibilityRole = + | 'adjustable' + | 'article' + | 'banner' + | 'blockquote' + | 'button' + | 'code' + | 'complementary' + | 'contentinfo' + | 'deletion' + | 'emphasis' + | 'figure' + | 'form' + | 'header' + | 'image' + | 'imagebutton' + | 'insertion' + | 'keyboardkey' + | 'label' + | 'link' + | 'list' + | 'listitem' + | 'main' + | 'navigation' + | 'none' + | 'region' + | 'search' + | 'strong' + | 'summary' + | 'text' + + interface PressableStateCallbackType { + hovered?: boolean + focused?: boolean + } + + interface ViewProps { + accessibilityRole?: WebAccessibilityRole + href?: string + hrefAttrs?: { + target?: '_blank' | '_self' | '_top' | 'blank' | 'self' | 'top' + rel?: string + download?: boolean + } + onMouseDown?: (event: React.MouseEvent) => void + onMouseUp?: (event: React.MouseEvent) => void + onMouseEnter?: (event: React.MouseEvent) => void + onMouseLeave?: (event: React.MouseEvent) => void + onClick?: (event: React.MouseEvent) => void + onFocus?: (event: React.FocusEvent) => void + onScroll?: (event: React.UIEvent) => void + // For compatibility with RNW internals + onScrollShouldSetResponder?: unknown + onScrollShouldSetResponderCapture?: unknown + onSelectionChangeShouldSetResponder?: unknown + onSelectionChangeShouldSetResponderCapture?: unknown + } + + interface TextProps { + dir?: 'ltr' | 'rtl' | 'auto' + focusable?: boolean + accessibilityRole?: WebAccessibilityRole + accessibilityState?: { + busy?: boolean + checked?: boolean | 'mixed' + disabled?: boolean + expanded?: boolean + grabbed?: boolean + hidden?: boolean + invalid?: boolean + pressed?: boolean + readonly?: boolean + required?: boolean + selected?: boolean + } + href?: string + hrefAttrs?: { + target?: '_blank' | '_self' | '_top' | 'blank' | 'self' | 'top' + rel?: string + download?: boolean + } + onMouseEnter?: (event: React.MouseEvent) => void + onMouseLeave?: (event: React.MouseEvent) => void + onClick?: (event: React.MouseEvent) => void + onFocus?: (event: React.FocusEvent) => void + // For compatibility with RNW internals + onMoveShouldSetResponder?: unknown + onMoveShouldSetResponderCapture?: unknown + onResponderEnd?: unknown + onResponderGrant?: unknown + onResponderMove?: unknown + onResponderReject?: unknown + onResponderRelease?: unknown + onResponderStart?: unknown + onResponderTerminate?: unknown + onResponderTerminationRequest?: unknown + onScrollShouldSetResponder?: unknown + onScrollShouldSetResponderCapture?: unknown + onSelectionChangeShouldSetResponder?: unknown + onSelectionChangeShouldSetResponderCapture?: unknown + onStartShouldSetResponder?: unknown + onStartShouldSetResponderCapture?: unknown + } + + interface TouchableOpacityProps { + accessibilityRole?: WebAccessibilityRole + href?: string + hrefAttrs?: { + target?: '_blank' | '_self' | '_top' | 'blank' | 'self' | 'top' + rel?: string + download?: boolean + } + nativeID?: string + onMouseEnter?: (event: React.MouseEvent) => void + onMouseLeave?: (event: React.MouseEvent) => void + } + + interface CheckBoxProps { + color?: string | null + } + + interface ViewStyle { + cursor?: CursorValue + transitionProperty?: string[] + transitionDuration?: string + transitionTimingFunction?: string + display?: 'flex' | 'inline-flex' | 'none' + } + + interface TextStyle { + // The following list is sourced from: + // - https://github.com/necolas/react-native-web/blob/0.17.5/packages/react-native-web/src/types/styles.js#L128 + userSelect?: 'all' | 'auto' | 'contain' | 'none' | 'text' + } +} + +export {} From 5f6991ffc2314fdba198033cd1990e8d4df5681a Mon Sep 17 00:00:00 2001 From: Mateusz Rostkowski Date: Sun, 7 Apr 2024 18:42:53 +0200 Subject: [PATCH 6/9] chore: add colors to tabs config --- src/navigation/tabNavigator/navigation-config.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/navigation/tabNavigator/navigation-config.ts b/src/navigation/tabNavigator/navigation-config.ts index 81ba8419..1ca342d7 100644 --- a/src/navigation/tabNavigator/navigation-config.ts +++ b/src/navigation/tabNavigator/navigation-config.ts @@ -14,8 +14,8 @@ type Tabs = Tab[] export const upperSideTabs: Tabs = [ { displayedName: 'Home', - icon: 'home-3-line', - iconFocused: 'home-3-fill', + icon: 'home-5-line', + iconFocused: 'home-5-fill', id: 'home', name: 'home', }, @@ -62,3 +62,14 @@ export const upperSideTabs: Tabs = [ export const bottomSideTabs: Tabs = [] export const bottomTabs: Tabs = [...upperSideTabs] + +export const tabsColors: { + color: ColorNames + colorFocused: ColorNames +} = { + color: 'nav.item.button.icon.fg', + colorFocused: 'Brand.600', +} + +export const getTabColor = (isFocused = false) => + isFocused ? tabsColors.colorFocused : tabsColors.color From 7ec05c5389fde094cff445b3eb157d25abd76148 Mon Sep 17 00:00:00 2001 From: Mateusz Rostkowski Date: Sun, 7 Apr 2024 18:43:37 +0200 Subject: [PATCH 7/9] chore: unify bottom tabs styles with designs; --- src/components/LandingHeader.tsx | 4 +- .../tabNavigator/components/BottomBar.tsx | 31 ++++---- .../tabNavigator/components/HeaderLogo.tsx | 14 +--- .../tabNavigator/components/SideBar.tsx | 9 ++- .../components/SideBarTabItem.tsx | 77 ++++++------------- src/navigation/tabNavigator/hooks/useWidth.ts | 6 ++ src/navigation/tabNavigator/navigator.tsx | 4 +- 7 files changed, 59 insertions(+), 86 deletions(-) diff --git a/src/components/LandingHeader.tsx b/src/components/LandingHeader.tsx index 3406184d..54e326a8 100644 --- a/src/components/LandingHeader.tsx +++ b/src/components/LandingHeader.tsx @@ -3,7 +3,7 @@ import { useColorScheme } from '@baca/contexts' import { Box, Button, Icon, Pressable, Row, Spacer, Touchable } from '@baca/design-system' import { useFullScreenModal } from '@baca/design-system/modals/useFullScreenModal' import { useCallback, useMemo, useTheme, useTranslation } from '@baca/hooks' -import { useWidth } from '@baca/navigation/tabNavigator/hooks' +import { useUniversalWidth } from '@baca/navigation/tabNavigator/hooks' import { isSignedInAtom } from '@baca/store/auth' import { useRouter } from 'expo-router' import { useAtomValue } from 'jotai' @@ -19,7 +19,7 @@ export function LandingHeader() { const height = 60 + top - const isDesktop = useWidth(768) + const isDesktop = useUniversalWidth(768) const isSignedIn = useAtomValue(isSignedInAtom) diff --git a/src/navigation/tabNavigator/components/BottomBar.tsx b/src/navigation/tabNavigator/components/BottomBar.tsx index 66ed2d21..7acce626 100644 --- a/src/navigation/tabNavigator/components/BottomBar.tsx +++ b/src/navigation/tabNavigator/components/BottomBar.tsx @@ -1,11 +1,11 @@ -import { Icon } from '@baca/design-system' +import { Column, Icon, Text } from '@baca/design-system' import { useTheme } from '@baca/hooks' import cssStyles from '@baca/styles' import { Platform, StyleSheet, View } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { TabBarItemWrapper } from './TabBarItemWrapper' -import { bottomTabs } from '../navigation-config' +import { bottomTabs, getTabColor } from '../navigation-config' import { cns } from '../utils' export function BottomBar({ visible }: { visible: boolean }) { @@ -28,21 +28,27 @@ export function BottomBar({ visible }: { visible: boolean }) { {bottomTabs.map((tab, i) => ( {({ focused, pressed, hovered }) => ( - + gap={2} + > + + {tab.displayedName} + )} ))} @@ -56,16 +62,11 @@ const jsStyles = StyleSheet.create({ alignItems: 'center', borderTopWidth: 1, flexDirection: 'row', - height: 49, + height: 56, justifyContent: 'space-around', paddingHorizontal: 16, }, - - tabIcon: { - paddingHorizontal: 8, - }, tabIconPressed: { opacity: 0.8, - transform: [{ scale: 0.9 }], }, }) diff --git a/src/navigation/tabNavigator/components/HeaderLogo.tsx b/src/navigation/tabNavigator/components/HeaderLogo.tsx index 2eebb657..4a97f325 100644 --- a/src/navigation/tabNavigator/components/HeaderLogo.tsx +++ b/src/navigation/tabNavigator/components/HeaderLogo.tsx @@ -5,12 +5,12 @@ import { Pressable } from '@bacons/react-views' import { Link } from 'expo-router' import { Platform, StyleSheet, View } from 'react-native' -import { useWidth } from '../hooks' +import { useUniversalWidth } from '../hooks' import { cns } from '../utils' export function HeaderLogo() { const { colors } = useTheme() - const isLargeHorizontal = useWidth(1264) + const isLargeHorizontal = useUniversalWidth(1264) return ( - + {({ hovered }) => ( }) { - const isLarge = useWidth(1264) - const { colors } = useTheme() + const isLarge = useUniversalWidth(1264) return ( {({ focused, hovered }) => ( - - - - - - {children} - - + + {isLarge ? ( + {children} + ) : null} + )} ) } const jsStyles = StyleSheet.create({ - sidebarIconContainer: Platform.select({ - default: { padding: 0 }, - web: { - transitionDuration: '150ms', - transitionProperty: ['transform'], - transitionTimingFunction: 'cubic-bezier(0.17, 0.17, 0, 1)', - }, - }), - sidebarItemContainer: { - alignItems: 'center', - borderRadius: 8, - flexDirection: 'row', - padding: 8, - ...Platform.select({ - web: { - transitionDuration: '200ms', - transitionProperty: ['background-color', 'box-shadow'], - }, - }), - }, - sidebarItemText: { - marginLeft: 16, - marginRight: 16, - userSelect: 'none', - }, sidebarTabItem: { paddingVertical: 4, width: '100%', diff --git a/src/navigation/tabNavigator/hooks/useWidth.ts b/src/navigation/tabNavigator/hooks/useWidth.ts index 093b9fcb..8cc9a5ba 100644 --- a/src/navigation/tabNavigator/hooks/useWidth.ts +++ b/src/navigation/tabNavigator/hooks/useWidth.ts @@ -10,3 +10,9 @@ export function useWidth(size: number): boolean { } return width >= size } + +export function useUniversalWidth(size: number): boolean { + const { width } = useWindowDimensions() + + return width >= size +} diff --git a/src/navigation/tabNavigator/navigator.tsx b/src/navigation/tabNavigator/navigator.tsx index 33a3076c..0d5390d1 100644 --- a/src/navigation/tabNavigator/navigator.tsx +++ b/src/navigation/tabNavigator/navigator.tsx @@ -4,12 +4,12 @@ import React from 'react' import { Platform, View } from 'react-native' import { AppHeader, BottomBar, SideBar } from './components' -import { useWidth } from './hooks' +import { useUniversalWidth } from './hooks' import { TabbedNavigator } from './tab-slot' import { cns } from './utils' export function ResponsiveNavigator() { - const isRowLayout = useWidth(768) + const isRowLayout = useUniversalWidth(768) return ( From 9be269738a2545949c4edc604dcc7caf19a8bd57 Mon Sep 17 00:00:00 2001 From: Mateusz Rostkowski Date: Mon, 8 Apr 2024 10:19:21 +0200 Subject: [PATCH 8/9] chore: remove not needed css styles --- src/styles/root-layout.module.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/styles/root-layout.module.scss b/src/styles/root-layout.module.scss index 6046563b..1906f0df 100644 --- a/src/styles/root-layout.module.scss +++ b/src/styles/root-layout.module.scss @@ -17,10 +17,6 @@ $ui-sidebar: 244px; padding-top: 0px; } -.headerLink { - margin-bottom: 24px; -} - .headerLogo { @media (min-width: $size-xs) and (max-width: $size-l) { padding-top: 0px; From c4a929fade555658240acfe522c6fdbb051ccfe8 Mon Sep 17 00:00:00 2001 From: Mateusz Rostkowski Date: Mon, 8 Apr 2024 14:00:54 +0200 Subject: [PATCH 9/9] fix: set properly background color to full screen modal --- src/design-system/modals/FullScreenModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/design-system/modals/FullScreenModal.tsx b/src/design-system/modals/FullScreenModal.tsx index 062148fa..e92106cb 100644 --- a/src/design-system/modals/FullScreenModal.tsx +++ b/src/design-system/modals/FullScreenModal.tsx @@ -29,7 +29,7 @@ export const FullScreenModal = ({ children, modalRef, ...rest }: Props) => { visible={isOpen} onRequestClose={setIsOpen.off} > - + {children}