about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/view/com/util/ViewHeader.web.tsx150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/view/com/util/ViewHeader.web.tsx b/src/view/com/util/ViewHeader.web.tsx
new file mode 100644
index 000000000..0d5c99aac
--- /dev/null
+++ b/src/view/com/util/ViewHeader.web.tsx
@@ -0,0 +1,150 @@
+import React from 'react'
+import {observer} from 'mobx-react-lite'
+import {
+  ActivityIndicator,
+  StyleSheet,
+  TouchableOpacity,
+  View,
+} from 'react-native'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
+import {CenteredView} from './Views'
+import {Text} from './text/Text'
+import {useStores} from '../../../state'
+import {usePalette} from '../../lib/hooks/usePalette'
+import {colors} from '../../lib/styles'
+
+const BACK_HITSLOP = {left: 10, top: 10, right: 30, bottom: 10}
+
+export const ViewHeader = observer(function ViewHeader({
+  title,
+  subtitle,
+  canGoBack,
+}: {
+  title: string
+  subtitle?: string
+  canGoBack?: boolean
+}) {
+  const pal = usePalette('default')
+  const store = useStores()
+  const onPressBack = () => {
+    store.nav.tab.goBack()
+  }
+  const onPressReconnect = () => {
+    store.session.connect().catch(e => {
+      store.log.warn('Failed to reconnect to server', e)
+    })
+  }
+  if (typeof canGoBack === 'undefined') {
+    canGoBack = store.nav.tab.canGoBack
+  }
+  return (
+    <CenteredView style={[styles.header, pal.view]}>
+      {canGoBack ? (
+        <>
+          <TouchableOpacity
+            testID="viewHeaderBackOrMenuBtn"
+            onPress={onPressBack}
+            hitSlop={BACK_HITSLOP}
+            style={styles.backBtn}>
+            <FontAwesomeIcon
+              size={18}
+              icon="angle-left"
+              style={[styles.backIcon, pal.text]}
+            />
+          </TouchableOpacity>
+          <View style={styles.titleContainer} pointerEvents="none">
+            <Text type="title" style={[pal.text, styles.title]}>
+              {title}
+            </Text>
+            {subtitle ? (
+              <Text
+                type="title-sm"
+                style={[styles.subtitle, pal.textLight]}
+                numberOfLines={1}>
+                {subtitle}
+              </Text>
+            ) : undefined}
+          </View>
+        </>
+      ) : (
+        <View style={styles.titleContainer} pointerEvents="none">
+          <Text type="title" style={[pal.text, styles.title]}>
+            Home
+          </Text>
+        </View>
+      )}
+      {!store.session.online ? (
+        <TouchableOpacity style={styles.btn} onPress={onPressReconnect}>
+          {store.session.attemptingConnect ? (
+            <ActivityIndicator />
+          ) : (
+            <>
+              <FontAwesomeIcon
+                icon="signal"
+                style={pal.text as FontAwesomeIconStyle}
+                size={16}
+              />
+              <FontAwesomeIcon
+                icon="x"
+                style={[
+                  styles.littleXIcon,
+                  {backgroundColor: pal.colors.background},
+                ]}
+                size={8}
+              />
+            </>
+          )}
+        </TouchableOpacity>
+      ) : undefined}
+    </CenteredView>
+  )
+})
+
+const styles = StyleSheet.create({
+  header: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingHorizontal: 16,
+    paddingVertical: 12,
+  },
+
+  titleContainer: {
+    flexDirection: 'row',
+    alignItems: 'baseline',
+    marginRight: 'auto',
+  },
+  title: {
+    fontWeight: 'bold',
+  },
+  subtitle: {
+    marginLeft: 4,
+    maxWidth: 200,
+    fontWeight: 'normal',
+  },
+
+  backBtn: {
+    width: 30,
+  },
+  backIcon: {
+    position: 'relative',
+    top: -1,
+  },
+  btn: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'center',
+    width: 36,
+    height: 36,
+    borderRadius: 20,
+    marginLeft: 4,
+  },
+  littleXIcon: {
+    color: colors.red3,
+    position: 'absolute',
+    right: 7,
+    bottom: 7,
+  },
+})