diff --git a/src/view/shell/mobile/history-menu.tsx b/src/view/shell/mobile/HistoryMenu.tsx
similarity index 100%
rename from src/view/shell/mobile/history-menu.tsx
rename to src/view/shell/mobile/HistoryMenu.tsx
diff --git a/src/view/shell/mobile/location-navigator.tsx b/src/view/shell/mobile/LocationNavigator.tsx
similarity index 100%
rename from src/view/shell/mobile/location-navigator.tsx
rename to 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 0000000000..bf18f76456
--- /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
+ }) => (
+ onNavigate(url)}>
+
+
+
+
+ {label}
+
+
+ )
+ if (!active) {
+ return
+ }
+
+ return (
+ <>
+
+
+
+
+
+ onNavigate(`/profile/${store.me.name || ''}`)}>
+
+
+ {store.me.displayName || store.me.name || 'My profile'}
+
+
+
+ onNavigate(`/settings`)}>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+ },
+)
+
+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 0000000000..8e3fba41aa
--- /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(
+ undefined,
+ )
+ const closeInterp = useSharedValue(0)
+ const tabsRef = useRef(null)
+ const tabRefs = useMemo(
+ () =>
+ Array.from({length: store.nav.tabs.length}).map(() =>
+ createRef(),
+ ),
+ [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
+ }) => (
+ onNavigate(url)}>
+
+
+
+
+ {label}
+
+
+ )
+
+ const renderSwipeActions = () => {
+ return
+ }
+
+ 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
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ Share
+
+
+
+
+
+
+
+ Clone tab
+
+
+
+
+
+
+
+ New tab
+
+
+
+
+
+
+ {store.nav.tabs.map((tab, tabIndex) => {
+ const {icon} = match(tab.current.url)
+ const isActive = tabIndex === currentTabIndex
+ const isClosing = closingTabIndex === tabIndex
+ return (
+ onCloseTab(tabIndex)}>
+
+
+ onPressChangeTab(tabIndex)}>
+
+
+
+
+
+ {tab.current.title || tab.current.url}
+
+
+
+ onCloseTab(tabIndex)}>
+
+
+
+
+
+
+
+ )
+ })}
+
+
+
+
+ >
+ )
+ },
+)
+
+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 ec0e6bf409..0000000000
--- 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(
- (
- <>
-
-
-
-
- onPressItem(0)}>
-
- Alice
-
- onPressItem(0)}>
-
- New Account
-
- {
- sibling.destroy()
- onPressLogout()
- }}>
-
- Log out
-
-
- >
- ),
- )
- 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 90f7470ac1..b7c13f35cf 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 (
-
- {title ? (
-
- ) : (
-
- )}
-
- {title || 'Search'}
-
-
- )
-}
-
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(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 (
- {/*
-
-
-
-
-
-
-
- */}
@@ -255,21 +200,32 @@ export const MobileShell: React.FC = observer(() => {
onPress={onPressBack}
onLongPress={onLongPressBack}
/>
-
+ />*/
+ }
+
-
+
+ setMainMenuActive(false)}
+ />
+ setTabsSelectorActive(false)}
+ />
{isLocationMenuActive && (
{
- sibling.destroy()
- }
- const onOuterPress = () => sibling.destroy()
- const sibling = new RootSiblings(
- (
- <>
-
-
-
-
- onPressItem(0)}>
-
- Share
-
- onPressItem(0)}>
-
- Copy Link
-
- onPressItem(0)}>
-
- Duplicate Tab
-
-
- >
- ),
- )
- 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,
- },
-})