mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react' 2import {StyleSheet, TouchableOpacity, View} from 'react-native' 3import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 4import {useNavigation} from '@react-navigation/native' 5import {CenteredView} from './Views' 6import {Text} from './text/Text' 7import {usePalette} from 'lib/hooks/usePalette' 8import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' 9import {useAnalytics} from 'lib/analytics/analytics' 10import {NavigationProp} from 'lib/routes/types' 11import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' 12import Animated from 'react-native-reanimated' 13import {useSetDrawerOpen} from '#/state/shell' 14import {msg} from '@lingui/macro' 15import {useLingui} from '@lingui/react' 16import {useTheme} from '#/alf' 17 18const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20} 19 20export function ViewHeader({ 21 title, 22 subtitle, 23 canGoBack, 24 showBackButton = true, 25 hideOnScroll, 26 showOnDesktop, 27 showBorder, 28 renderButton, 29}: { 30 title: string 31 subtitle?: string 32 canGoBack?: boolean 33 showBackButton?: boolean 34 hideOnScroll?: boolean 35 showOnDesktop?: boolean 36 showBorder?: boolean 37 renderButton?: () => JSX.Element 38}) { 39 const pal = usePalette('default') 40 const {_} = useLingui() 41 const setDrawerOpen = useSetDrawerOpen() 42 const navigation = useNavigation<NavigationProp>() 43 const {track} = useAnalytics() 44 const {isDesktop, isTablet} = useWebMediaQueries() 45 const t = useTheme() 46 47 const onPressBack = React.useCallback(() => { 48 if (navigation.canGoBack()) { 49 navigation.goBack() 50 } else { 51 navigation.navigate('Home') 52 } 53 }, [navigation]) 54 55 const onPressMenu = React.useCallback(() => { 56 track('ViewHeader:MenuButtonClicked') 57 setDrawerOpen(true) 58 }, [track, setDrawerOpen]) 59 60 if (isDesktop) { 61 if (showOnDesktop) { 62 return ( 63 <DesktopWebHeader 64 title={title} 65 renderButton={renderButton} 66 showBorder={showBorder} 67 /> 68 ) 69 } 70 return null 71 } else { 72 if (typeof canGoBack === 'undefined') { 73 canGoBack = navigation.canGoBack() 74 } 75 76 return ( 77 <Container hideOnScroll={hideOnScroll || false} showBorder={showBorder}> 78 <View style={{flex: 1}}> 79 <View style={{flexDirection: 'row', alignItems: 'center'}}> 80 {showBackButton ? ( 81 <TouchableOpacity 82 testID="viewHeaderDrawerBtn" 83 onPress={canGoBack ? onPressBack : onPressMenu} 84 hitSlop={BACK_HITSLOP} 85 style={canGoBack ? styles.backBtn : styles.backBtnWide} 86 accessibilityRole="button" 87 accessibilityLabel={canGoBack ? _(msg`Back`) : _(msg`Menu`)} 88 accessibilityHint={ 89 canGoBack ? '' : _(msg`Access navigation links and settings`) 90 }> 91 {canGoBack ? ( 92 <FontAwesomeIcon 93 size={18} 94 icon="angle-left" 95 style={[styles.backIcon, pal.text]} 96 /> 97 ) : !isTablet ? ( 98 <FontAwesomeIcon 99 size={18} 100 icon="bars" 101 style={[styles.backIcon, pal.textLight]} 102 /> 103 ) : null} 104 </TouchableOpacity> 105 ) : null} 106 <View style={styles.titleContainer} pointerEvents="none"> 107 <Text type="title" style={[pal.text, styles.title]}> 108 {title} 109 </Text> 110 </View> 111 {renderButton ? ( 112 renderButton() 113 ) : showBackButton ? ( 114 <View style={canGoBack ? styles.backBtn : styles.backBtnWide} /> 115 ) : null} 116 </View> 117 {subtitle ? ( 118 <View 119 style={[styles.titleContainer, {marginTop: -3}]} 120 pointerEvents="none"> 121 <Text 122 style={[ 123 pal.text, 124 styles.subtitle, 125 t.atoms.text_contrast_medium, 126 ]}> 127 {subtitle} 128 </Text> 129 </View> 130 ) : undefined} 131 </View> 132 </Container> 133 ) 134 } 135} 136 137function DesktopWebHeader({ 138 title, 139 renderButton, 140 showBorder = true, 141}: { 142 title: string 143 renderButton?: () => JSX.Element 144 showBorder?: boolean 145}) { 146 const pal = usePalette('default') 147 return ( 148 <CenteredView 149 style={[ 150 styles.header, 151 styles.desktopHeader, 152 pal.border, 153 { 154 borderBottomWidth: showBorder ? 1 : 0, 155 }, 156 ]}> 157 <View style={styles.titleContainer} pointerEvents="none"> 158 <Text type="title-lg" style={[pal.text, styles.title]}> 159 {title} 160 </Text> 161 </View> 162 {renderButton?.()} 163 </CenteredView> 164 ) 165} 166 167function Container({ 168 children, 169 hideOnScroll, 170 showBorder, 171}: { 172 children: React.ReactNode 173 hideOnScroll: boolean 174 showBorder?: boolean 175}) { 176 const pal = usePalette('default') 177 const {headerMinimalShellTransform} = useMinimalShellMode() 178 179 if (!hideOnScroll) { 180 return ( 181 <View 182 style={[ 183 styles.header, 184 pal.view, 185 pal.border, 186 showBorder && styles.border, 187 ]}> 188 {children} 189 </View> 190 ) 191 } 192 return ( 193 <Animated.View 194 style={[ 195 styles.header, 196 styles.headerFloating, 197 pal.view, 198 pal.border, 199 headerMinimalShellTransform, 200 showBorder && styles.border, 201 ]}> 202 {children} 203 </Animated.View> 204 ) 205} 206 207const styles = StyleSheet.create({ 208 header: { 209 flexDirection: 'row', 210 paddingHorizontal: 12, 211 paddingVertical: 6, 212 width: '100%', 213 }, 214 headerFloating: { 215 position: 'absolute', 216 top: 0, 217 width: '100%', 218 }, 219 desktopHeader: { 220 paddingVertical: 12, 221 maxWidth: 600, 222 marginLeft: 'auto', 223 marginRight: 'auto', 224 }, 225 border: { 226 borderBottomWidth: 1, 227 }, 228 titleContainer: { 229 marginLeft: 'auto', 230 marginRight: 'auto', 231 alignItems: 'center', 232 }, 233 title: { 234 fontWeight: 'bold', 235 }, 236 subtitle: { 237 fontSize: 13, 238 }, 239 backBtn: { 240 width: 30, 241 height: 30, 242 }, 243 backBtnWide: { 244 width: 30, 245 height: 30, 246 paddingHorizontal: 6, 247 }, 248 backIcon: { 249 marginTop: 6, 250 }, 251})