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