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})