diff --git a/src/view/screens.tsx b/src/view/screens.tsx
index 3d49b8eabe..da9fbedb2d 100644
--- a/src/view/screens.tsx
+++ b/src/view/screens.tsx
@@ -1,5 +1,4 @@
import * as React from 'react'
-import {View, Text} from 'react-native'
import {NavigationContainer} from '@react-navigation/native'
import {createNativeStackNavigator} from '@react-navigation/native-stack'
import {createDrawerNavigator} from '@react-navigation/drawer'
@@ -12,6 +11,7 @@ import {
State,
} from 'lib/routes/types'
+import {Drawer} from './shell/Drawer'
import {BottomBar} from './shell/BottomBar'
import {HomeScreen} from './screens/Home'
@@ -137,15 +137,6 @@ function buildStateObject(stack: string, route: string, params: RouteParams) {
}
}
-function DrawerContent() {
- // TODO
- return (
-
- Drawer
-
- )
-}
-
function commonScreens(Stack: ReturnType) {
return (
<>
@@ -166,9 +157,10 @@ function commonScreens(Stack: ReturnType) {
}
function HomeDrawerNavigator() {
+ const drawerContent = React.useCallback(props => , [])
return (
@@ -190,9 +182,10 @@ function HomeStackNavigator() {
}
function NotificationsDrawerNavigator() {
+ const drawerContent = React.useCallback(props => , [])
return (
, [])
return (
diff --git a/src/view/shell/BottomBar.tsx b/src/view/shell/BottomBar.tsx
index 100866f747..273eb01879 100644
--- a/src/view/shell/BottomBar.tsx
+++ b/src/view/shell/BottomBar.tsx
@@ -14,7 +14,6 @@ import {Text} from 'view/com/util/text/Text'
import {useStores} from 'state/index'
import {useAnalytics} from 'lib/analytics'
import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
-import {TabPurpose, TabPurposeMainPath} from 'state/models/navigation'
import {clamp} from 'lib/numbers'
import {
HomeIcon,
@@ -28,6 +27,7 @@ import {
import {colors} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette'
+// TODO move to lib
function currentRoute(state) {
let node = state.routes[state.index]
while (node.state?.routes && typeof node.state?.index === 'number') {
diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx
new file mode 100644
index 0000000000..6eae9a38bc
--- /dev/null
+++ b/src/view/shell/Drawer.tsx
@@ -0,0 +1,408 @@
+import React from 'react'
+import {
+ Linking,
+ SafeAreaView,
+ StyleProp,
+ StyleSheet,
+ TouchableOpacity,
+ View,
+ ViewStyle,
+} from 'react-native'
+import {
+ DrawerContentComponentProps,
+ useDrawerStatus,
+} from '@react-navigation/drawer'
+import {StackActions} from '@react-navigation/native'
+import {observer} from 'mobx-react-lite'
+import {
+ FontAwesomeIcon,
+ FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
+import {s, colors} from 'lib/styles'
+import {FEEDBACK_FORM_URL} from 'lib/constants'
+import {useStores} from 'state/index'
+import {
+ HomeIcon,
+ HomeIconSolid,
+ BellIcon,
+ BellIconSolid,
+ UserIcon,
+ CogIcon,
+ MagnifyingGlassIcon2,
+ MagnifyingGlassIcon2Solid,
+ MoonIcon,
+} from 'lib/icons'
+import {UserAvatar} from 'view/com/util/UserAvatar'
+import {Text} from 'view/com/util/text/Text'
+import {useTheme} from 'lib/ThemeContext'
+import {usePalette} from 'lib/hooks/usePalette'
+import {useAnalytics} from 'lib/analytics'
+import {pluralize} from 'lib/strings/helpers'
+
+// TODO move to lib
+function currentRoute(state) {
+ let node = state.routes[state.index]
+ while (node.state?.routes && typeof node.state?.index === 'number') {
+ node = node.state?.routes[node.state?.index]
+ }
+ return node
+}
+
+export const Drawer = observer(
+ ({state, navigation}: DrawerContentComponentProps) => {
+ const theme = useTheme()
+ const pal = usePalette('default')
+ const store = useStores()
+ const {track} = useAnalytics()
+ const isDrawerOpen = useDrawerStatus() === 'open'
+
+ // events
+ // =
+
+ React.useEffect(() => {
+ console.log(
+ 'Drawer',
+ isDrawerOpen ? 'minimizing' : 'unminimizing',
+ 'shell',
+ )
+ store.shell.setMinimalShellMode(isDrawerOpen)
+ }, [isDrawerOpen, store])
+
+ const onPressTab = React.useCallback(
+ (tab: string) => {
+ track('Menu:ItemClicked', {url: tab})
+ const state = navigation.getState()
+ const curr = currentRoute(state).name
+ if (curr === tab || curr === `${tab}Stack`) {
+ store.emitScreenSoftReset()
+ } else if (state.routes[state.index].name === `${tab}Stack`) {
+ navigation.dispatch(StackActions.popToTop())
+ } else {
+ navigation.navigate(`${tab}Stack`)
+ }
+ },
+ [store, track, navigation],
+ )
+
+ const onPressHome = React.useCallback(
+ () => onPressTab('Home'),
+ [onPressTab],
+ )
+
+ const onPressSearch = React.useCallback(
+ () => onPressTab('Search'),
+ [onPressTab],
+ )
+
+ const onPressNotifications = React.useCallback(
+ () => onPressTab('Notifications'),
+ [onPressTab],
+ )
+
+ const onPressProfile = React.useCallback(() => {
+ track('Menu:ItemClicked', {url: 'Profile'})
+ navigation.navigate('Profile', {name: store.me.handle})
+ }, [navigation, track, store.me.handle])
+
+ const onPressSettings = React.useCallback(() => {
+ track('Menu:ItemClicked', {url: 'Settings'})
+ navigation.navigate('Settings')
+ }, [navigation, track])
+
+ const onPressFeedback = () => {
+ track('Menu:FeedbackClicked')
+ Linking.openURL(FEEDBACK_FORM_URL)
+ }
+
+ // rendering
+ // =
+
+ const MenuItem = ({
+ icon,
+ label,
+ count,
+ bold,
+ onPress,
+ }: {
+ icon: JSX.Element
+ label: string
+ count?: number
+ bold?: boolean
+ onPress: () => void
+ }) => (
+
+
+ {icon}
+ {count ? (
+
+ {count}
+
+ ) : undefined}
+
+
+ {label}
+
+
+ )
+
+ const onDarkmodePress = () => {
+ track('Menu:ItemClicked', {url: '/darkmode'})
+ store.shell.setDarkMode(!store.shell.darkMode)
+ }
+
+ const curr = currentRoute(navigation.getState()).name
+ const isAtHome = curr === 'HomeStack' || curr === 'Home'
+ const isAtSearch = curr === 'SearchStack' || curr === 'Search'
+ const isAtNotifications =
+ curr === 'NotificationsStack' || curr === 'Notifications'
+
+ return (
+
+
+ onNavigate(`/profile/${store.me.handle}`)}>
+
+
+ {store.me.displayName || store.me.handle}
+
+
+ @{store.me.handle}
+
+
+
+ {store.me.followersCount || 0}
+ {' '}
+ {pluralize(store.me.followersCount || 0, 'follower')} ·{' '}
+
+ {store.me.followsCount || 0}
+ {' '}
+ following
+
+
+
+
+
+
+
+
+ }
+ strokeWidth={2}
+ />
+
+
+
+
+ Feedback
+
+
+
+
+
+ )
+ },
+)
+
+const styles = StyleSheet.create({
+ view: {
+ flex: 1,
+ paddingTop: 20,
+ paddingBottom: 50,
+ paddingLeft: 30,
+ },
+ viewDarkMode: {
+ backgroundColor: '#1B1919',
+ },
+
+ profileCardDisplayName: {
+ marginTop: 20,
+ paddingRight: 30,
+ },
+ profileCardHandle: {
+ marginTop: 4,
+ paddingRight: 30,
+ },
+ profileCardFollowers: {
+ marginTop: 16,
+ paddingRight: 30,
+ },
+
+ menuItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingVertical: 16,
+ paddingRight: 10,
+ },
+ menuItemIconWrapper: {
+ width: 24,
+ height: 24,
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginRight: 12,
+ },
+ menuItemCount: {
+ position: 'absolute',
+ right: -6,
+ top: -2,
+ backgroundColor: colors.red3,
+ paddingHorizontal: 4,
+ paddingBottom: 1,
+ borderRadius: 6,
+ },
+ menuItemCountLabel: {
+ fontSize: 12,
+ fontWeight: 'bold',
+ color: colors.white,
+ },
+
+ footer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ paddingRight: 30,
+ paddingTop: 80,
+ },
+ footerBtn: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ padding: 10,
+ borderRadius: 25,
+ },
+ footerBtnDarkMode: {
+ backgroundColor: colors.black,
+ },
+ footerBtnFeedback: {
+ paddingHorizontal: 24,
+ },
+ footerBtnFeedbackLight: {
+ backgroundColor: '#DDEFFF',
+ },
+ footerBtnFeedbackDark: {
+ backgroundColor: colors.blue6,
+ },
+})
diff --git a/src/view/shell/mobile/Menu.tsx b/src/view/shell/mobile/Menu.tsx
deleted file mode 100644
index 927e712e11..0000000000
--- a/src/view/shell/mobile/Menu.tsx
+++ /dev/null
@@ -1,354 +0,0 @@
-import React from 'react'
-import {
- Linking,
- StyleProp,
- StyleSheet,
- TouchableOpacity,
- View,
- ViewStyle,
-} from 'react-native'
-import {observer} from 'mobx-react-lite'
-import {
- FontAwesomeIcon,
- FontAwesomeIconStyle,
-} from '@fortawesome/react-native-fontawesome'
-import {s, colors} from 'lib/styles'
-import {FEEDBACK_FORM_URL} from 'lib/constants'
-import {useStores} from 'state/index'
-import {
- HomeIcon,
- HomeIconSolid,
- BellIcon,
- BellIconSolid,
- UserIcon,
- CogIcon,
- MagnifyingGlassIcon2,
- MagnifyingGlassIcon2Solid,
- MoonIcon,
-} from 'lib/icons'
-import {TabPurpose, TabPurposeMainPath} from 'state/models/navigation'
-import {UserAvatar} from '../../com/util/UserAvatar'
-import {Text} from '../../com/util/text/Text'
-import {useTheme} from 'lib/ThemeContext'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useAnalytics} from 'lib/analytics'
-import {pluralize} from 'lib/strings/helpers'
-
-export const Menu = observer(({onClose}: {onClose: () => void}) => {
- const theme = useTheme()
- const pal = usePalette('default')
- const store = useStores()
- const {track} = useAnalytics()
-
- // events
- // =
-
- const onNavigate = (url: string) => {
- track('Menu:ItemClicked', {url})
-
- onClose()
- if (url === TabPurposeMainPath[TabPurpose.Notifs]) {
- store.nav.switchTo(TabPurpose.Notifs, true)
- } else if (url === TabPurposeMainPath[TabPurpose.Search]) {
- store.nav.switchTo(TabPurpose.Search, true)
- } else {
- store.nav.switchTo(TabPurpose.Default, true)
- if (url !== '/') {
- store.nav.navigate(url)
- }
- }
- }
-
- const onPressFeedback = () => {
- track('Menu:FeedbackClicked')
- Linking.openURL(FEEDBACK_FORM_URL)
- }
-
- // rendering
- // =
-
- const MenuItem = ({
- icon,
- label,
- count,
- url,
- bold,
- onPress,
- }: {
- icon: JSX.Element
- label: string
- count?: number
- url?: string
- bold?: boolean
- onPress?: () => void
- }) => (
- onNavigate(url || '/')}>
-
- {icon}
- {count ? (
-
- {count}
-
- ) : undefined}
-
-
- {label}
-
-
- )
-
- const onDarkmodePress = () => {
- track('Menu:ItemClicked', {url: '/darkmode'})
- store.shell.setDarkMode(!store.shell.darkMode)
- }
-
- const isAtHome =
- store.nav.tab.current.url === TabPurposeMainPath[TabPurpose.Default]
- const isAtSearch =
- store.nav.tab.current.url === TabPurposeMainPath[TabPurpose.Search]
- const isAtNotifications =
- store.nav.tab.current.url === TabPurposeMainPath[TabPurpose.Notifs]
-
- return (
-
- onNavigate(`/profile/${store.me.handle}`)}>
-
-
- {store.me.displayName || store.me.handle}
-
-
- @{store.me.handle}
-
-
-
- {store.me.followersCount || 0}
- {' '}
- {pluralize(store.me.followersCount || 0, 'follower')} ·{' '}
-
- {store.me.followsCount || 0}
- {' '}
- following
-
-
-
-
- }
- size={24}
- strokeWidth={1.7}
- />
- ) : (
- }
- size={24}
- strokeWidth={1.7}
- />
- )
- }
- label="Search"
- url="/search"
- bold={isAtSearch}
- />
- }
- size="24"
- strokeWidth={3.25}
- fillOpacity={1}
- />
- ) : (
- }
- size="24"
- strokeWidth={3.25}
- />
- )
- }
- label="Home"
- url="/"
- bold={isAtHome}
- />
- }
- size="24"
- strokeWidth={1.7}
- fillOpacity={1}
- />
- ) : (
- }
- size="24"
- strokeWidth={1.7}
- />
- )
- }
- label="Notifications"
- url="/notifications"
- count={store.me.notifications.unreadCount}
- bold={isAtNotifications}
- />
- }
- size="26"
- strokeWidth={1.5}
- />
- }
- label="Profile"
- url={`/profile/${store.me.handle}`}
- />
- }
- size="26"
- strokeWidth={1.75}
- />
- }
- label="Settings"
- url="/settings"
- />
-
-
-
-
- }
- strokeWidth={2}
- />
-
-
-
-
- Feedback
-
-
-
-
- )
-})
-
-const styles = StyleSheet.create({
- view: {
- flex: 1,
- paddingTop: 20,
- paddingBottom: 50,
- paddingLeft: 30,
- },
- viewDarkMode: {
- backgroundColor: '#1B1919',
- },
-
- profileCardDisplayName: {
- marginTop: 20,
- paddingRight: 20,
- },
- profileCardHandle: {
- marginTop: 4,
- paddingRight: 20,
- },
- profileCardFollowers: {
- marginTop: 16,
- paddingRight: 20,
- },
-
- menuItem: {
- flexDirection: 'row',
- alignItems: 'center',
- paddingVertical: 16,
- paddingRight: 10,
- },
- menuItemIconWrapper: {
- width: 24,
- height: 24,
- alignItems: 'center',
- justifyContent: 'center',
- marginRight: 12,
- },
- menuItemCount: {
- position: 'absolute',
- right: -6,
- top: -2,
- backgroundColor: colors.red3,
- paddingHorizontal: 4,
- paddingBottom: 1,
- borderRadius: 6,
- },
- menuItemCountLabel: {
- fontSize: 12,
- fontWeight: 'bold',
- color: colors.white,
- },
-
- footer: {
- flexDirection: 'row',
- justifyContent: 'space-between',
- paddingRight: 30,
- paddingTop: 80,
- },
- footerBtn: {
- flexDirection: 'row',
- alignItems: 'center',
- padding: 10,
- borderRadius: 25,
- },
- footerBtnDarkMode: {
- backgroundColor: colors.black,
- },
- footerBtnFeedback: {
- paddingHorizontal: 24,
- },
- footerBtnFeedbackLight: {
- backgroundColor: '#DDEFFF',
- },
- footerBtnFeedbackDark: {
- backgroundColor: colors.blue6,
- },
-})