about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2022-10-10 21:13:25 -0500
committerPaul Frazee <pfrazee@gmail.com>2022-10-10 21:13:25 -0500
commitba6580101e5b8f2f994d37be14ae61fd4c3ef1ee (patch)
treeed0d720d27183cd3a679da71871dadc2894387ae
parent287f2992fa6400fbac520bf7b9693bd5dcc6e7db (diff)
downloadvoidsky-ba6580101e5b8f2f994d37be14ae61fd4c3ef1ee.tar.zst
Rework footer controls
-rw-r--r--src/view/shell/mobile/HistoryMenu.tsx (renamed from src/view/shell/mobile/history-menu.tsx)0
-rw-r--r--src/view/shell/mobile/LocationNavigator.tsx (renamed from src/view/shell/mobile/location-navigator.tsx)0
-rw-r--r--src/view/shell/mobile/MainMenu.tsx210
-rw-r--r--src/view/shell/mobile/TabsSelector.tsx383
-rw-r--r--src/view/shell/mobile/accounts-menu.tsx108
-rw-r--r--src/view/shell/mobile/index.tsx94
-rw-r--r--src/view/shell/mobile/location-menu.tsx89
7 files changed, 618 insertions, 266 deletions
diff --git a/src/view/shell/mobile/history-menu.tsx b/src/view/shell/mobile/HistoryMenu.tsx
index d0b9b9751..d0b9b9751 100644
--- a/src/view/shell/mobile/history-menu.tsx
+++ b/src/view/shell/mobile/HistoryMenu.tsx
diff --git a/src/view/shell/mobile/location-navigator.tsx b/src/view/shell/mobile/LocationNavigator.tsx
index 28ca23101..28ca23101 100644
--- a/src/view/shell/mobile/location-navigator.tsx
+++ b/src/view/shell/mobile/LocationNavigator.tsx
diff --git a/src/view/shell/mobile/MainMenu.tsx b/src/view/shell/mobile/MainMenu.tsx
new file mode 100644
index 000000000..bf18f7645
--- /dev/null
+++ b/src/view/shell/mobile/MainMenu.tsx
@@ -0,0 +1,210 @@
+import React from 'react'
+import {observer} from 'mobx-react-lite'
+import {
+  Image,
+  StyleSheet,
+  Text,
+  TouchableOpacity,
+  TouchableWithoutFeedback,
+  View,
+} from 'react-native'
+import {IconProp} from '@fortawesome/fontawesome-svg-core'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import LinearGradient from 'react-native-linear-gradient'
+import {useStores} from '../../../state'
+import {s, colors, gradients} from '../../lib/styles'
+import {DEF_AVATER} from '../../lib/assets'
+
+export const MainMenu = observer(
+  ({active, onClose}: {active: boolean; onClose: () => void}) => {
+    const store = useStores()
+
+    // events
+    // =
+
+    const onNavigate = (url: string) => {
+      store.nav.navigate(url)
+      onClose()
+    }
+
+    // rendering
+    // =
+
+    const FatMenuItem = ({
+      icon,
+      label,
+      url,
+      gradient,
+    }: {
+      icon: IconProp
+      label: string
+      url: string
+      gradient: keyof typeof gradients
+    }) => (
+      <TouchableOpacity
+        style={[styles.fatMenuItem, styles.fatMenuItemMargin]}
+        onPress={() => onNavigate(url)}>
+        <LinearGradient
+          style={[styles.fatMenuItemIconWrapper]}
+          colors={[gradients[gradient].start, gradients[gradient].end]}
+          start={{x: 0, y: 0}}
+          end={{x: 1, y: 1}}>
+          <FontAwesomeIcon
+            icon={icon}
+            style={styles.fatMenuItemIcon}
+            size={24}
+          />
+        </LinearGradient>
+        <Text style={styles.fatMenuItemLabel} numberOfLines={1}>
+          {label}
+        </Text>
+      </TouchableOpacity>
+    )
+    if (!active) {
+      return <View />
+    }
+
+    return (
+      <>
+        <TouchableWithoutFeedback onPress={onClose}>
+          <View style={styles.bg} />
+        </TouchableWithoutFeedback>
+        <View style={styles.wrapper}>
+          <View style={[styles.topSection]}>
+            <TouchableOpacity
+              style={styles.profile}
+              onPress={() => onNavigate(`/profile/${store.me.name || ''}`)}>
+              <Image style={styles.profileImage} source={DEF_AVATER} />
+              <Text style={styles.profileText} numberOfLines={1}>
+                {store.me.displayName || store.me.name || 'My profile'}
+              </Text>
+            </TouchableOpacity>
+            <View style={[s.flex1]} />
+            <TouchableOpacity
+              style={styles.settings}
+              onPress={() => onNavigate(`/settings`)}>
+              <FontAwesomeIcon
+                icon="gear"
+                style={styles.settingsIcon}
+                size={24}
+              />
+            </TouchableOpacity>
+          </View>
+          <View style={[styles.section]}>
+            <View style={styles.fatMenuItems}>
+              <FatMenuItem
+                icon="house"
+                label="Feed"
+                url="/"
+                gradient="primary"
+              />
+              <FatMenuItem
+                icon="bell"
+                label="Notifications"
+                url="/notifications"
+                gradient="purple"
+              />
+              <FatMenuItem
+                icon="gear"
+                label="Settings"
+                url="/settings"
+                gradient="blue"
+              />
+            </View>
+          </View>
+        </View>
+      </>
+    )
+  },
+)
+
+const styles = StyleSheet.create({
+  bg: {
+    position: 'absolute',
+    top: 0,
+    right: 0,
+    bottom: 0,
+    left: 0,
+    backgroundColor: '#000',
+    opacity: 0.2,
+  },
+  wrapper: {
+    position: 'absolute',
+    bottom: 75,
+    width: '100%',
+    backgroundColor: '#fff',
+    borderRadius: 8,
+    opacity: 1,
+    paddingVertical: 10,
+  },
+
+  topSection: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingHorizontal: 10,
+  },
+  section: {
+    paddingHorizontal: 10,
+  },
+
+  profile: {
+    paddingVertical: 10,
+    paddingHorizontal: 10,
+    flexDirection: 'row',
+    alignItems: 'center',
+  },
+  profileImage: {
+    borderRadius: 15,
+    width: 30,
+    height: 30,
+    marginRight: 5,
+  },
+  profileText: {
+    fontSize: 15,
+    fontWeight: 'bold',
+  },
+
+  settings: {},
+  settingsIcon: {
+    color: colors.gray5,
+    marginRight: 10,
+  },
+
+  fatMenuItems: {
+    flexDirection: 'row',
+    marginTop: 10,
+    marginBottom: 10,
+  },
+  fatMenuItem: {
+    width: 80,
+    alignItems: 'center',
+    marginRight: 6,
+  },
+  fatMenuItemMargin: {
+    marginRight: 14,
+  },
+  fatMenuItemIconWrapper: {
+    borderRadius: 6,
+    width: 60,
+    height: 60,
+    justifyContent: 'center',
+    alignItems: 'center',
+    marginBottom: 5,
+    shadowColor: '#000',
+    shadowOpacity: 0.2,
+    shadowOffset: {width: 0, height: 2},
+    shadowRadius: 2,
+  },
+  fatMenuItemIcon: {
+    color: colors.white,
+  },
+  fatMenuImage: {
+    borderRadius: 30,
+    width: 60,
+    height: 60,
+    marginBottom: 5,
+  },
+  fatMenuItemLabel: {
+    fontSize: 13,
+  },
+})
diff --git a/src/view/shell/mobile/TabsSelector.tsx b/src/view/shell/mobile/TabsSelector.tsx
new file mode 100644
index 000000000..8e3fba41a
--- /dev/null
+++ b/src/view/shell/mobile/TabsSelector.tsx
@@ -0,0 +1,383 @@
+import React, {createRef, useRef, useMemo, useState} from 'react'
+import {observer} from 'mobx-react-lite'
+import {
+  Image,
+  ScrollView,
+  StyleSheet,
+  Text,
+  TouchableOpacity,
+  TouchableWithoutFeedback,
+  View,
+} from 'react-native'
+import Animated, {
+  useSharedValue,
+  useAnimatedStyle,
+  withTiming,
+  runOnJS,
+} from 'react-native-reanimated'
+import {IconProp} from '@fortawesome/fontawesome-svg-core'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import Swipeable from 'react-native-gesture-handler/Swipeable'
+import LinearGradient from 'react-native-linear-gradient'
+import {useStores} from '../../../state'
+import {s, colors, gradients} from '../../lib/styles'
+import {DEF_AVATER} from '../../lib/assets'
+import {match} from '../../routes'
+import {LinkActionsModel} from '../../../state/models/shell'
+
+const TAB_HEIGHT = 42
+
+export const TabsSelector = observer(
+  ({active, onClose}: {active: boolean; onClose: () => void}) => {
+    const store = useStores()
+    const [closingTabIndex, setClosingTabIndex] = useState<number | undefined>(
+      undefined,
+    )
+    const closeInterp = useSharedValue<number>(0)
+    const tabsRef = useRef<ScrollView>(null)
+    const tabRefs = useMemo(
+      () =>
+        Array.from({length: store.nav.tabs.length}).map(() =>
+          createRef<Animated.View>(),
+        ),
+      [store.nav.tabs.length],
+    )
+
+    // events
+    // =
+
+    const onPressNewTab = () => {
+      store.nav.newTab('/')
+      onClose()
+    }
+    const onPressCloneTab = () => {
+      store.nav.newTab(store.nav.tab.current.url)
+      onClose()
+    }
+    const onPressShareTab = () => {
+      onClose()
+      store.shell.openModal(
+        new LinkActionsModel(
+          store.nav.tab.current.url,
+          store.nav.tab.current.title || 'This Page',
+          {newTab: false},
+        ),
+      )
+    }
+    const onPressChangeTab = (tabIndex: number) => {
+      store.nav.setActiveTab(tabIndex)
+      onClose()
+    }
+    const doCloseTab = (index: number) => store.nav.closeTab(index)
+    const onCloseTab = (tabIndex: number) => {
+      setClosingTabIndex(tabIndex)
+      closeInterp.value = 0
+      closeInterp.value = withTiming(1, {duration: 300}, () => {
+        runOnJS(setClosingTabIndex)(undefined)
+        runOnJS(doCloseTab)(tabIndex)
+      })
+    }
+    const onNavigate = (url: string) => {
+      store.nav.navigate(url)
+      onClose()
+    }
+    const onLayout = () => {
+      // focus the current tab
+      const targetTab = tabRefs[store.nav.tabIndex]
+      if (tabsRef.current && targetTab.current) {
+        targetTab.current.measureLayout?.(
+          tabsRef.current,
+          (_left: number, top: number) => {
+            tabsRef.current?.scrollTo({y: top, animated: false})
+          },
+          () => {},
+        )
+      }
+    }
+
+    // rendering
+    // =
+
+    const FatMenuItem = ({
+      icon,
+      label,
+      url,
+      gradient,
+    }: {
+      icon: IconProp
+      label: string
+      url: string
+      gradient: keyof typeof gradients
+    }) => (
+      <TouchableOpacity
+        style={[styles.fatMenuItem, styles.fatMenuItemMargin]}
+        onPress={() => onNavigate(url)}>
+        <LinearGradient
+          style={[styles.fatMenuItemIconWrapper]}
+          colors={[gradients[gradient].start, gradients[gradient].end]}
+          start={{x: 0, y: 0}}
+          end={{x: 1, y: 1}}>
+          <FontAwesomeIcon
+            icon={icon}
+            style={styles.fatMenuItemIcon}
+            size={24}
+          />
+        </LinearGradient>
+        <Text style={styles.fatMenuItemLabel} numberOfLines={1}>
+          {label}
+        </Text>
+      </TouchableOpacity>
+    )
+
+    const renderSwipeActions = () => {
+      return <View style={[s.p2]} />
+    }
+
+    const currentTabIndex = store.nav.tabIndex
+    const closingTabAnimStyle = useAnimatedStyle(() => ({
+      height: TAB_HEIGHT * (1 - closeInterp.value),
+      opacity: 1 - closeInterp.value,
+      marginBottom: 4 * (1 - closeInterp.value),
+    }))
+
+    if (!active) {
+      return <View />
+    }
+
+    return (
+      <>
+        <TouchableWithoutFeedback onPress={onClose}>
+          <View style={styles.bg} />
+        </TouchableWithoutFeedback>
+        <View style={styles.wrapper}>
+          <View onLayout={onLayout}>
+            <View style={[s.p10, styles.section]}>
+              <View style={styles.btns}>
+                <TouchableWithoutFeedback onPress={onPressShareTab}>
+                  <View style={[styles.btn]}>
+                    <View style={styles.btnIcon}>
+                      <FontAwesomeIcon size={16} icon="share" />
+                    </View>
+                    <Text style={styles.btnText}>Share</Text>
+                  </View>
+                </TouchableWithoutFeedback>
+                <TouchableWithoutFeedback onPress={onPressCloneTab}>
+                  <View style={[styles.btn]}>
+                    <View style={styles.btnIcon}>
+                      <FontAwesomeIcon size={16} icon={['far', 'clone']} />
+                    </View>
+                    <Text style={styles.btnText}>Clone tab</Text>
+                  </View>
+                </TouchableWithoutFeedback>
+                <TouchableWithoutFeedback onPress={onPressNewTab}>
+                  <View style={[styles.btn]}>
+                    <View style={styles.btnIcon}>
+                      <FontAwesomeIcon size={16} icon="plus" />
+                    </View>
+                    <Text style={styles.btnText}>New tab</Text>
+                  </View>
+                </TouchableWithoutFeedback>
+              </View>
+            </View>
+            <View style={[s.p10, styles.section, styles.sectionGrayBg]}>
+              <ScrollView ref={tabsRef} style={styles.tabs}>
+                {store.nav.tabs.map((tab, tabIndex) => {
+                  const {icon} = match(tab.current.url)
+                  const isActive = tabIndex === currentTabIndex
+                  const isClosing = closingTabIndex === tabIndex
+                  return (
+                    <Swipeable
+                      key={tab.id}
+                      renderLeftActions={renderSwipeActions}
+                      renderRightActions={renderSwipeActions}
+                      leftThreshold={100}
+                      rightThreshold={100}
+                      onSwipeableWillOpen={() => onCloseTab(tabIndex)}>
+                      <Animated.View
+                        style={[
+                          styles.tabOuter,
+                          isClosing ? closingTabAnimStyle : undefined,
+                        ]}>
+                        <Animated.View
+                          ref={tabRefs[tabIndex]}
+                          style={[
+                            styles.tab,
+                            styles.existing,
+                            isActive && styles.active,
+                          ]}>
+                          <TouchableWithoutFeedback
+                            onPress={() => onPressChangeTab(tabIndex)}>
+                            <View style={styles.tabInner}>
+                              <View style={styles.tabIcon}>
+                                <FontAwesomeIcon size={20} icon={icon} />
+                              </View>
+                              <Text
+                                ellipsizeMode="tail"
+                                numberOfLines={1}
+                                suppressHighlighting={true}
+                                style={[
+                                  styles.tabText,
+                                  isActive && styles.tabTextActive,
+                                ]}>
+                                {tab.current.title || tab.current.url}
+                              </Text>
+                            </View>
+                          </TouchableWithoutFeedback>
+                          <TouchableWithoutFeedback
+                            onPress={() => onCloseTab(tabIndex)}>
+                            <View style={styles.tabClose}>
+                              <FontAwesomeIcon
+                                size={14}
+                                icon="x"
+                                style={styles.tabCloseIcon}
+                              />
+                            </View>
+                          </TouchableWithoutFeedback>
+                        </Animated.View>
+                      </Animated.View>
+                    </Swipeable>
+                  )
+                })}
+              </ScrollView>
+            </View>
+          </View>
+        </View>
+      </>
+    )
+  },
+)
+
+const styles = StyleSheet.create({
+  bg: {
+    position: 'absolute',
+    top: 0,
+    right: 0,
+    bottom: 0,
+    left: 0,
+    backgroundColor: '#000',
+    opacity: 0.2,
+  },
+  wrapper: {
+    position: 'absolute',
+    bottom: 75,
+    width: '100%',
+    backgroundColor: '#fff',
+    borderRadius: 8,
+    opacity: 1,
+  },
+  section: {
+    borderBottomColor: colors.gray2,
+    borderBottomWidth: 1,
+  },
+  sectionGrayBg: {
+    backgroundColor: colors.gray1,
+    borderBottomLeftRadius: 8,
+    borderBottomRightRadius: 8,
+  },
+  fatMenuItems: {
+    flexDirection: 'row',
+    marginTop: 10,
+    marginBottom: 10,
+  },
+  fatMenuItem: {
+    width: 80,
+    alignItems: 'center',
+    marginRight: 6,
+  },
+  fatMenuItemMargin: {
+    marginRight: 14,
+  },
+  fatMenuItemIconWrapper: {
+    borderRadius: 6,
+    width: 60,
+    height: 60,
+    justifyContent: 'center',
+    alignItems: 'center',
+    marginBottom: 5,
+    shadowColor: '#000',
+    shadowOpacity: 0.2,
+    shadowOffset: {width: 0, height: 2},
+    shadowRadius: 2,
+  },
+  fatMenuItemIcon: {
+    color: colors.white,
+  },
+  fatMenuImage: {
+    borderRadius: 30,
+    width: 60,
+    height: 60,
+    marginBottom: 5,
+  },
+  fatMenuItemLabel: {
+    fontSize: 13,
+  },
+  tabs: {
+    height: 240,
+  },
+  tabOuter: {
+    height: TAB_HEIGHT + 4,
+    overflow: 'hidden',
+  },
+  tab: {
+    flexDirection: 'row',
+    height: TAB_HEIGHT,
+    backgroundColor: colors.gray1,
+    alignItems: 'center',
+    borderRadius: 4,
+  },
+  tabInner: {
+    flexDirection: 'row',
+    flex: 1,
+    alignItems: 'center',
+    paddingLeft: 12,
+    paddingVertical: 12,
+  },
+  existing: {
+    borderColor: colors.gray4,
+    borderWidth: 1,
+  },
+  active: {
+    backgroundColor: colors.white,
+    borderColor: colors.black,
+    borderWidth: 1,
+  },
+  tabIcon: {},
+  tabText: {
+    flex: 1,
+    paddingHorizontal: 10,
+    fontSize: 16,
+  },
+  tabTextActive: {
+    fontWeight: '500',
+  },
+  tabClose: {
+    paddingVertical: 16,
+    paddingRight: 16,
+  },
+  tabCloseIcon: {
+    color: '#655',
+  },
+  btns: {
+    flexDirection: 'row',
+    paddingTop: 2,
+  },
+  btn: {
+    flexDirection: 'row',
+    flex: 1,
+    alignItems: 'center',
+    justifyContent: 'center',
+    backgroundColor: colors.gray1,
+    borderRadius: 4,
+    marginRight: 5,
+    paddingLeft: 12,
+    paddingRight: 16,
+    paddingVertical: 10,
+  },
+  btnIcon: {
+    marginRight: 8,
+  },
+  btnText: {
+    fontWeight: '500',
+    fontSize: 16,
+  },
+})
diff --git a/src/view/shell/mobile/accounts-menu.tsx b/src/view/shell/mobile/accounts-menu.tsx
deleted file mode 100644
index ec0e6bf40..000000000
--- a/src/view/shell/mobile/accounts-menu.tsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import React from 'react'
-import {
-  Image,
-  StyleSheet,
-  Text,
-  TouchableOpacity,
-  TouchableWithoutFeedback,
-  View,
-} from 'react-native'
-import RootSiblings from 'react-native-root-siblings'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {DEF_AVATER} from '../../lib/assets'
-import {s, colors} from '../../lib/styles'
-
-export function createAccountsMenu({
-  debug_onPressItem,
-  onPressLogout,
-}: {
-  debug_onPressItem: () => void
-  onPressLogout: () => void
-}): RootSiblings {
-  const onPressItem = (_index: number) => {
-    sibling.destroy()
-    debug_onPressItem() // TODO
-  }
-  const onOuterPress = () => sibling.destroy()
-  const sibling = new RootSiblings(
-    (
-      <>
-        <TouchableWithoutFeedback onPress={onOuterPress}>
-          <View style={styles.bg} />
-        </TouchableWithoutFeedback>
-        <View style={[styles.menu]}>
-          <TouchableOpacity
-            style={[styles.menuItem]}
-            onPress={() => onPressItem(0)}>
-            <Image style={styles.avi} source={DEF_AVATER} />
-            <Text style={[styles.label, s.bold]}>Alice</Text>
-          </TouchableOpacity>
-          <TouchableOpacity
-            style={[styles.menuItem, styles.menuItemBorder]}
-            onPress={() => onPressItem(0)}>
-            <FontAwesomeIcon style={styles.icon} icon="plus" />
-            <Text style={styles.label}>New Account</Text>
-          </TouchableOpacity>
-          <TouchableOpacity
-            style={[styles.menuItem, styles.menuItemBorder]}
-            onPress={() => {
-              sibling.destroy()
-              onPressLogout()
-            }}>
-            <FontAwesomeIcon
-              style={styles.icon}
-              icon="arrow-right-from-bracket"
-            />
-            <Text style={styles.label}>Log out</Text>
-          </TouchableOpacity>
-        </View>
-      </>
-    ),
-  )
-  return sibling
-}
-
-const styles = StyleSheet.create({
-  bg: {
-    position: 'absolute',
-    top: 0,
-    right: 0,
-    bottom: 0,
-    left: 0,
-    backgroundColor: '#000',
-    opacity: 0.1,
-  },
-  menu: {
-    position: 'absolute',
-    left: 4,
-    top: 70,
-    backgroundColor: '#fff',
-    borderRadius: 14,
-    opacity: 1,
-    paddingVertical: 2,
-  },
-  menuItem: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    paddingVertical: 8,
-    paddingLeft: 10,
-    paddingRight: 30,
-  },
-  menuItemBorder: {
-    borderTopWidth: 1,
-    borderTopColor: colors.gray1,
-  },
-  avi: {
-    width: 28,
-    height: 28,
-    marginRight: 8,
-    borderRadius: 14,
-  },
-  icon: {
-    marginLeft: 6,
-    marginRight: 6,
-  },
-  label: {
-    fontSize: 16,
-  },
-})
diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx
index 90f7470ac..b7c13f35c 100644
--- a/src/view/shell/mobile/index.tsx
+++ b/src/view/shell/mobile/index.tsx
@@ -28,53 +28,16 @@ import {TabsSelectorModel} from '../../../state/models/shell'
 import {match, MatchResult} from '../../routes'
 import {Login} from '../../screens/Login'
 import {Modal} from '../../com/modals/Modal'
-import {LocationNavigator} from './location-navigator'
-import {createBackMenu, createForwardMenu} from './history-menu'
-import {createAccountsMenu} from './accounts-menu'
-import {createLocationMenu} from './location-menu'
+import {LocationNavigator} from './LocationNavigator'
+import {createBackMenu, createForwardMenu} from './HistoryMenu'
+import {MainMenu} from './MainMenu'
+import {TabsSelector} from './TabsSelector'
 import {s, colors} from '../../lib/styles'
 import {GridIcon, HomeIcon} from '../../lib/icons'
-import {DEF_AVATER} from '../../lib/assets'
 
-const locationIconNeedsNudgeUp = (icon: IconProp) => icon === 'house'
 const SWIPE_GESTURE_DIST_TRIGGER = 0.5
 const SWIPE_GESTURE_VEL_TRIGGER = 2500
 
-const Location = ({
-  icon,
-  title,
-  onPress,
-}: {
-  icon: IconProp
-  title?: string
-  onPress?: (event: GestureResponderEvent) => void
-}) => {
-  const nudgeUp = locationIconNeedsNudgeUp(icon)
-  return (
-    <TouchableOpacity style={styles.location} onPress={onPress}>
-      {title ? (
-        <FontAwesomeIcon
-          size={12}
-          style={[
-            styles.locationIcon,
-            nudgeUp ? styles.locationIconNudgeUp : undefined,
-          ]}
-          icon={icon}
-        />
-      ) : (
-        <FontAwesomeIcon
-          size={12}
-          style={styles.locationIconLight}
-          icon="magnifying-glass"
-        />
-      )}
-      <Text style={title ? styles.locationText : styles.locationTextLight}>
-        {title || 'Search'}
-      </Text>
-    </TouchableOpacity>
-  )
-}
-
 const Btn = ({
   icon,
   inactive,
@@ -89,7 +52,7 @@ const Btn = ({
   onLongPress?: (event: GestureResponderEvent) => void
 }) => {
   let IconEl
-  if (icon === 'bars') {
+  if (icon === 'menu') {
     IconEl = GridIcon
   } else if (icon === 'house') {
     IconEl = HomeIcon
@@ -131,18 +94,12 @@ const Btn = ({
 export const MobileShell: React.FC = observer(() => {
   const store = useStores()
   const [isLocationMenuActive, setLocationMenuActive] = useState(false)
+  const [isMainMenuActive, setMainMenuActive] = useState(false)
+  const [isTabsSelectorActive, setTabsSelectorActive] = useState(false)
   const winDim = useWindowDimensions()
   const swipeGestureInterp = useSharedValue<number>(0)
   const screenRenderDesc = constructScreenRenderDesc(store.nav)
 
-  const onPressAvi = () =>
-    createAccountsMenu({
-      debug_onPressItem: () => store.nav.navigate('/profile/alice.test'),
-      onPressLogout: () => store.session.logout(),
-    })
-  const onPressLocation = () => setLocationMenuActive(true)
-  const onPressEllipsis = () => createLocationMenu()
-
   const onNavigateLocation = (url: string) => {
     setLocationMenuActive(false)
     store.nav.navigate(url)
@@ -150,13 +107,14 @@ export const MobileShell: React.FC = observer(() => {
   const onDismissLocationNavigator = () => setLocationMenuActive(false)
 
   const onPressBack = () => store.nav.tab.goBack()
-  const onPressForward = () => store.nav.tab.goForward()
+  // const onPressForward = () => store.nav.tab.goForward()
   const onPressHome = () => store.nav.navigate('/')
+  const onPressMenu = () => setMainMenuActive(true)
   const onPressNotifications = () => store.nav.navigate('/notifications')
-  const onPressTabs = () => store.shell.openModal(new TabsSelectorModel())
+  const onPressTabs = () => setTabsSelectorActive(true) //store.shell.openModal(new TabsSelectorModel())
 
   const onLongPressBack = () => createBackMenu(store.nav.tab)
-  const onLongPressForward = () => createForwardMenu(store.nav.tab)
+  // const onLongPressForward = () => createForwardMenu(store.nav.tab)
 
   const goBack = () => store.nav.tab.goBack()
   const swipeGesture = Gesture.Pan()
@@ -205,19 +163,6 @@ export const MobileShell: React.FC = observer(() => {
 
   return (
     <View style={styles.outerContainer}>
-      {/* <View style={styles.topBar}>
-        <TouchableOpacity onPress={onPressAvi}>
-          <Image style={styles.avi} source={DEF_AVATER} />
-        </TouchableOpacity>
-        <Location
-          icon={screenRenderDesc.icon}
-          title={store.nav.tab.current.title}
-          onPress={onPressLocation}
-        />
-        <TouchableOpacity style={styles.topBarBtn} onPress={onPressEllipsis}>
-          <FontAwesomeIcon icon="ellipsis" />
-        </TouchableOpacity>
-      </View> */}
       <SafeAreaView style={styles.innerContainer}>
         <GestureDetector gesture={swipeGesture}>
           <ScreenContainer style={styles.screenContainer}>
@@ -255,21 +200,32 @@ export const MobileShell: React.FC = observer(() => {
           onPress={onPressBack}
           onLongPress={onLongPressBack}
         />
-        <Btn
+        {
+          undefined /*<Btn
           icon="angle-right"
           inactive={!store.nav.tab.canGoForward}
           onPress={onPressForward}
           onLongPress={onLongPressForward}
-        />
+        />*/
+        }
         <Btn icon="house" onPress={onPressHome} />
+        <Btn icon="menu" onPress={onPressMenu} />
         <Btn
           icon={['far', 'bell']}
           onPress={onPressNotifications}
           notificationCount={store.me.notificationCount}
         />
-        <Btn icon="bars" onPress={onPressTabs} />
+        <Btn icon={['far', 'clone']} onPress={onPressTabs} />
       </View>
       <Modal />
+      <MainMenu
+        active={isMainMenuActive}
+        onClose={() => setMainMenuActive(false)}
+      />
+      <TabsSelector
+        active={isTabsSelectorActive}
+        onClose={() => setTabsSelectorActive(false)}
+      />
       {isLocationMenuActive && (
         <LocationNavigator
           url={store.nav.tab.current.url}
diff --git a/src/view/shell/mobile/location-menu.tsx b/src/view/shell/mobile/location-menu.tsx
deleted file mode 100644
index 598d82c3e..000000000
--- a/src/view/shell/mobile/location-menu.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import React from 'react'
-import {
-  StyleSheet,
-  Text,
-  TouchableOpacity,
-  TouchableWithoutFeedback,
-  View,
-} from 'react-native'
-import RootSiblings from 'react-native-root-siblings'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {colors} from '../../lib/styles'
-
-export function createLocationMenu(): RootSiblings {
-  const onPressItem = (_index: number) => {
-    sibling.destroy()
-  }
-  const onOuterPress = () => sibling.destroy()
-  const sibling = new RootSiblings(
-    (
-      <>
-        <TouchableWithoutFeedback onPress={onOuterPress}>
-          <View style={styles.bg} />
-        </TouchableWithoutFeedback>
-        <View style={[styles.menu]}>
-          <TouchableOpacity
-            style={[styles.menuItem]}
-            onPress={() => onPressItem(0)}>
-            <FontAwesomeIcon style={styles.icon} icon="share" />
-            <Text style={styles.label}>Share</Text>
-          </TouchableOpacity>
-          <TouchableOpacity
-            style={[styles.menuItem]}
-            onPress={() => onPressItem(0)}>
-            <FontAwesomeIcon style={styles.icon} icon="link" />
-            <Text style={styles.label}>Copy Link</Text>
-          </TouchableOpacity>
-          <TouchableOpacity
-            style={[styles.menuItem, styles.menuItemBorder]}
-            onPress={() => onPressItem(0)}>
-            <FontAwesomeIcon style={styles.icon} icon={['far', 'clone']} />
-            <Text style={styles.label}>Duplicate Tab</Text>
-          </TouchableOpacity>
-        </View>
-      </>
-    ),
-  )
-  return sibling
-}
-
-const styles = StyleSheet.create({
-  bg: {
-    position: 'absolute',
-    top: 0,
-    right: 0,
-    bottom: 0,
-    left: 0,
-    backgroundColor: '#000',
-    opacity: 0.1,
-  },
-  menu: {
-    position: 'absolute',
-    right: 4,
-    top: 70,
-    backgroundColor: '#fff',
-    borderRadius: 14,
-    opacity: 1,
-    paddingVertical: 6,
-  },
-  menuItem: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    paddingVertical: 6,
-    paddingLeft: 10,
-    paddingRight: 30,
-  },
-  menuItemBorder: {
-    borderTopWidth: 1,
-    borderTopColor: colors.gray1,
-    marginTop: 4,
-    paddingTop: 12,
-  },
-  icon: {
-    marginLeft: 6,
-    marginRight: 8,
-  },
-  label: {
-    fontSize: 15,
-  },
-})