about summary refs log tree commit diff
path: root/src/view/shell
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/shell')
-rw-r--r--src/view/shell/BottomBar.tsx (renamed from src/view/shell/mobile/BottomBar.tsx)90
-rw-r--r--src/view/shell/Composer.tsx (renamed from src/view/shell/mobile/Composer.tsx)5
-rw-r--r--src/view/shell/Composer.web.tsx (renamed from src/view/shell/web/Composer.tsx)11
-rw-r--r--src/view/shell/Drawer.tsx386
-rw-r--r--src/view/shell/desktop/LeftNav.tsx254
-rw-r--r--src/view/shell/desktop/RightNav.tsx46
-rw-r--r--src/view/shell/desktop/Search.tsx (renamed from src/view/shell/web/DesktopSearch.tsx)26
-rw-r--r--src/view/shell/index.tsx139
-rw-r--r--src/view/shell/index.web.tsx113
-rw-r--r--src/view/shell/mobile/Menu.tsx354
-rw-r--r--src/view/shell/mobile/index.tsx335
-rw-r--r--src/view/shell/web/DesktopHeader.tsx222
-rw-r--r--src/view/shell/web/index.tsx150
13 files changed, 994 insertions, 1137 deletions
diff --git a/src/view/shell/mobile/BottomBar.tsx b/src/view/shell/BottomBar.tsx
index 73c2501ab..18b06968f 100644
--- a/src/view/shell/mobile/BottomBar.tsx
+++ b/src/view/shell/BottomBar.tsx
@@ -6,13 +6,14 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
+import {StackActions, useNavigationState} from '@react-navigation/native'
+import {BottomTabBarProps} from '@react-navigation/bottom-tabs'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
 import {observer} from 'mobx-react-lite'
 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,
@@ -25,13 +26,24 @@ import {
 } from 'lib/icons'
 import {colors} from 'lib/styles'
 import {usePalette} from 'lib/hooks/usePalette'
+import {getTabState, TabState} from 'lib/routes/helpers'
 
-export const BottomBar = observer(() => {
+export const BottomBar = observer(({navigation}: BottomTabBarProps) => {
   const store = useStores()
   const pal = usePalette('default')
   const minimalShellInterp = useAnimatedValue(0)
   const safeAreaInsets = useSafeAreaInsets()
   const {track} = useAnalytics()
+  const {isAtHome, isAtSearch, isAtNotifications} = useNavigationState(
+    state => {
+      return {
+        isAtHome: getTabState(state, 'Home') !== TabState.Outside,
+        isAtSearch: getTabState(state, 'Search') !== TabState.Outside,
+        isAtNotifications:
+          getTabState(state, 'Notifications') !== TabState.Outside,
+      }
+    },
+  )
 
   React.useEffect(() => {
     if (store.shell.minimalShellMode) {
@@ -54,62 +66,34 @@ export const BottomBar = observer(() => {
     transform: [{translateY: Animated.multiply(minimalShellInterp, 100)}],
   }
 
-  const onPressHome = React.useCallback(() => {
-    track('MobileShell:HomeButtonPressed')
-    if (store.nav.tab.fixedTabPurpose === TabPurpose.Default) {
-      if (!store.nav.tab.canGoBack) {
+  const onPressTab = React.useCallback(
+    (tab: string) => {
+      track(`MobileShell:${tab}ButtonPressed`)
+      const state = navigation.getState()
+      const tabState = getTabState(state, tab)
+      if (tabState === TabState.InsideAtRoot) {
         store.emitScreenSoftReset()
+      } else if (tabState === TabState.Inside) {
+        navigation.dispatch(StackActions.popToTop())
       } else {
-        store.nav.tab.fixedTabReset()
-      }
-    } else {
-      store.nav.switchTo(TabPurpose.Default, false)
-      if (store.nav.tab.index === 0) {
-        store.nav.tab.fixedTabReset()
+        navigation.navigate(`${tab}Tab`)
       }
-    }
-  }, [store, track])
-  const onPressSearch = React.useCallback(() => {
-    track('MobileShell:SearchButtonPressed')
-    if (store.nav.tab.fixedTabPurpose === TabPurpose.Search) {
-      if (!store.nav.tab.canGoBack) {
-        store.emitScreenSoftReset()
-      } else {
-        store.nav.tab.fixedTabReset()
-      }
-    } else {
-      store.nav.switchTo(TabPurpose.Search, false)
-      if (store.nav.tab.index === 0) {
-        store.nav.tab.fixedTabReset()
-      }
-    }
-  }, [store, track])
-  const onPressNotifications = React.useCallback(() => {
-    track('MobileShell:NotificationsButtonPressed')
-    if (store.nav.tab.fixedTabPurpose === TabPurpose.Notifs) {
-      if (!store.nav.tab.canGoBack) {
-        store.emitScreenSoftReset()
-      } else {
-        store.nav.tab.fixedTabReset()
-      }
-    } else {
-      store.nav.switchTo(TabPurpose.Notifs, false)
-      if (store.nav.tab.index === 0) {
-        store.nav.tab.fixedTabReset()
-      }
-    }
-  }, [store, track])
+    },
+    [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('MobileShell:ProfileButtonPressed')
-    store.nav.navigate(`/profile/${store.me.handle}`)
-  }, [store, track])
-
-  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]
+    navigation.navigate('Profile', {name: store.me.handle})
+  }, [navigation, track, store.me.handle])
 
   return (
     <Animated.View
diff --git a/src/view/shell/mobile/Composer.tsx b/src/view/shell/Composer.tsx
index 5fca118bd..2ab01c656 100644
--- a/src/view/shell/mobile/Composer.tsx
+++ b/src/view/shell/Composer.tsx
@@ -1,7 +1,7 @@
 import React, {useEffect} from 'react'
 import {observer} from 'mobx-react-lite'
 import {Animated, Easing, Platform, StyleSheet, View} from 'react-native'
-import {ComposePost} from '../../com/composer/ComposePost'
+import {ComposePost} from '../com/composer/Composer'
 import {ComposerOpts} from 'state/models/shell-ui'
 import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
 import {usePalette} from 'lib/hooks/usePalette'
@@ -11,7 +11,6 @@ export const Composer = observer(
     active,
     winHeight,
     replyTo,
-    imagesOpen,
     onPost,
     onClose,
     quote,
@@ -19,7 +18,6 @@ export const Composer = observer(
     active: boolean
     winHeight: number
     replyTo?: ComposerOpts['replyTo']
-    imagesOpen?: ComposerOpts['imagesOpen']
     onPost?: ComposerOpts['onPost']
     onClose: () => void
     quote?: ComposerOpts['quote']
@@ -61,7 +59,6 @@ export const Composer = observer(
       <Animated.View style={[styles.wrapper, pal.view, wrapperAnimStyle]}>
         <ComposePost
           replyTo={replyTo}
-          imagesOpen={imagesOpen}
           onPost={onPost}
           onClose={onClose}
           quote={quote}
diff --git a/src/view/shell/web/Composer.tsx b/src/view/shell/Composer.web.tsx
index 0d8484262..465b475fb 100644
--- a/src/view/shell/web/Composer.tsx
+++ b/src/view/shell/Composer.web.tsx
@@ -1,7 +1,7 @@
 import React from 'react'
 import {observer} from 'mobx-react-lite'
 import {StyleSheet, View} from 'react-native'
-import {ComposePost} from '../../com/composer/ComposePost'
+import {ComposePost} from '../com/composer/Composer'
 import {ComposerOpts} from 'state/models/shell-ui'
 import {usePalette} from 'lib/hooks/usePalette'
 
@@ -9,14 +9,12 @@ export const Composer = observer(
   ({
     active,
     replyTo,
-    imagesOpen,
     onPost,
     onClose,
   }: {
     active: boolean
     winHeight: number
     replyTo?: ComposerOpts['replyTo']
-    imagesOpen?: ComposerOpts['imagesOpen']
     onPost?: ComposerOpts['onPost']
     onClose: () => void
   }) => {
@@ -32,12 +30,7 @@ export const Composer = observer(
     return (
       <View style={styles.mask}>
         <View style={[styles.container, pal.view]}>
-          <ComposePost
-            replyTo={replyTo}
-            imagesOpen={imagesOpen}
-            onPost={onPost}
-            onClose={onClose}
-          />
+          <ComposePost replyTo={replyTo} onPost={onPost} onClose={onClose} />
         </View>
       </View>
     )
diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx
new file mode 100644
index 000000000..80944e10a
--- /dev/null
+++ b/src/view/shell/Drawer.tsx
@@ -0,0 +1,386 @@
+import React from 'react'
+import {
+  Linking,
+  SafeAreaView,
+  StyleProp,
+  StyleSheet,
+  TouchableOpacity,
+  View,
+  ViewStyle,
+} from 'react-native'
+import {
+  useNavigation,
+  useNavigationState,
+  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'
+import {getCurrentRoute, isTab, getTabState, TabState} from 'lib/routes/helpers'
+import {NavigationProp} from 'lib/routes/types'
+
+export const DrawerContent = observer(() => {
+  const theme = useTheme()
+  const pal = usePalette('default')
+  const store = useStores()
+  const navigation = useNavigation<NavigationProp>()
+  const {track} = useAnalytics()
+  const {isAtHome, isAtSearch, isAtNotifications} = useNavigationState(
+    state => {
+      const currentRoute = state ? getCurrentRoute(state) : false
+      return {
+        isAtHome: currentRoute ? isTab(currentRoute.name, 'Home') : true,
+        isAtSearch: currentRoute ? isTab(currentRoute.name, 'Search') : false,
+        isAtNotifications: currentRoute
+          ? isTab(currentRoute.name, 'Notifications')
+          : false,
+      }
+    },
+  )
+
+  // events
+  // =
+
+  const onPressTab = React.useCallback(
+    (tab: string) => {
+      track('Menu:ItemClicked', {url: tab})
+      const state = navigation.getState()
+      store.shell.closeDrawer()
+      const tabState = getTabState(state, tab)
+      if (tabState === TabState.InsideAtRoot) {
+        store.emitScreenSoftReset()
+      } else if (tabState === TabState.Inside) {
+        navigation.dispatch(StackActions.popToTop())
+      } else {
+        // @ts-ignore must be Home, Search, or Notifications
+        navigation.navigate(`${tab}Tab`)
+      }
+    },
+    [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})
+    store.shell.closeDrawer()
+  }, [navigation, track, store.me.handle, store.shell])
+
+  const onPressSettings = React.useCallback(() => {
+    track('Menu:ItemClicked', {url: 'Settings'})
+    navigation.navigate('Settings')
+    store.shell.closeDrawer()
+  }, [navigation, track, store.shell])
+
+  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
+  }) => (
+    <TouchableOpacity
+      testID={`menuItemButton-${label}`}
+      style={styles.menuItem}
+      onPress={onPress}>
+      <View style={[styles.menuItemIconWrapper]}>
+        {icon}
+        {count ? (
+          <View style={styles.menuItemCount}>
+            <Text style={styles.menuItemCountLabel}>{count}</Text>
+          </View>
+        ) : undefined}
+      </View>
+      <Text
+        type={bold ? '2xl-bold' : '2xl'}
+        style={[pal.text, s.flex1]}
+        numberOfLines={1}>
+        {label}
+      </Text>
+    </TouchableOpacity>
+  )
+
+  const onDarkmodePress = () => {
+    track('Menu:ItemClicked', {url: '/darkmode'})
+    store.shell.setDarkMode(!store.shell.darkMode)
+  }
+
+  return (
+    <View
+      testID="menuView"
+      style={[
+        styles.view,
+        theme.colorScheme === 'light' ? pal.view : styles.viewDarkMode,
+      ]}>
+      <SafeAreaView style={s.flex1}>
+        <TouchableOpacity testID="profileCardButton" onPress={onPressProfile}>
+          <UserAvatar size={80} avatar={store.me.avatar} />
+          <Text
+            type="title-lg"
+            style={[pal.text, s.bold, styles.profileCardDisplayName]}>
+            {store.me.displayName || store.me.handle}
+          </Text>
+          <Text type="2xl" style={[pal.textLight, styles.profileCardHandle]}>
+            @{store.me.handle}
+          </Text>
+          <Text type="xl" style={[pal.textLight, styles.profileCardFollowers]}>
+            <Text type="xl-medium" style={pal.text}>
+              {store.me.followersCount || 0}
+            </Text>{' '}
+            {pluralize(store.me.followersCount || 0, 'follower')} &middot;{' '}
+            <Text type="xl-medium" style={pal.text}>
+              {store.me.followsCount || 0}
+            </Text>{' '}
+            following
+          </Text>
+        </TouchableOpacity>
+        <View style={s.flex1} />
+        <View>
+          <MenuItem
+            icon={
+              isAtSearch ? (
+                <MagnifyingGlassIcon2Solid
+                  style={pal.text as StyleProp<ViewStyle>}
+                  size={24}
+                  strokeWidth={1.7}
+                />
+              ) : (
+                <MagnifyingGlassIcon2
+                  style={pal.text as StyleProp<ViewStyle>}
+                  size={24}
+                  strokeWidth={1.7}
+                />
+              )
+            }
+            label="Search"
+            bold={isAtSearch}
+            onPress={onPressSearch}
+          />
+          <MenuItem
+            icon={
+              isAtHome ? (
+                <HomeIconSolid
+                  style={pal.text as StyleProp<ViewStyle>}
+                  size="24"
+                  strokeWidth={3.25}
+                />
+              ) : (
+                <HomeIcon
+                  style={pal.text as StyleProp<ViewStyle>}
+                  size="24"
+                  strokeWidth={3.25}
+                />
+              )
+            }
+            label="Home"
+            bold={isAtHome}
+            onPress={onPressHome}
+          />
+          <MenuItem
+            icon={
+              isAtNotifications ? (
+                <BellIconSolid
+                  style={pal.text as StyleProp<ViewStyle>}
+                  size="24"
+                  strokeWidth={1.7}
+                />
+              ) : (
+                <BellIcon
+                  style={pal.text as StyleProp<ViewStyle>}
+                  size="24"
+                  strokeWidth={1.7}
+                />
+              )
+            }
+            label="Notifications"
+            count={store.me.notifications.unreadCount}
+            bold={isAtNotifications}
+            onPress={onPressNotifications}
+          />
+          <MenuItem
+            icon={
+              <UserIcon
+                style={pal.text as StyleProp<ViewStyle>}
+                size="26"
+                strokeWidth={1.5}
+              />
+            }
+            label="Profile"
+            onPress={onPressProfile}
+          />
+          <MenuItem
+            icon={
+              <CogIcon
+                style={pal.text as StyleProp<ViewStyle>}
+                size="26"
+                strokeWidth={1.75}
+              />
+            }
+            label="Settings"
+            onPress={onPressSettings}
+          />
+        </View>
+        <View style={s.flex1} />
+        <View style={styles.footer}>
+          <TouchableOpacity
+            onPress={onDarkmodePress}
+            style={[
+              styles.footerBtn,
+              theme.colorScheme === 'light'
+                ? pal.btn
+                : styles.footerBtnDarkMode,
+            ]}>
+            <MoonIcon
+              size={22}
+              style={pal.text as StyleProp<ViewStyle>}
+              strokeWidth={2}
+            />
+          </TouchableOpacity>
+          <TouchableOpacity
+            onPress={onPressFeedback}
+            style={[
+              styles.footerBtn,
+              styles.footerBtnFeedback,
+              theme.colorScheme === 'light'
+                ? styles.footerBtnFeedbackLight
+                : styles.footerBtnFeedbackDark,
+            ]}>
+            <FontAwesomeIcon
+              style={pal.link as FontAwesomeIconStyle}
+              size={19}
+              icon={['far', 'message']}
+            />
+            <Text type="2xl-medium" style={[pal.link, s.pl10]}>
+              Feedback
+            </Text>
+          </TouchableOpacity>
+        </View>
+      </SafeAreaView>
+    </View>
+  )
+})
+
+const styles = StyleSheet.create({
+  view: {
+    flex: 1,
+    paddingTop: 20,
+    paddingBottom: 50,
+    paddingLeft: 20,
+  },
+  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/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
new file mode 100644
index 000000000..46c77178b
--- /dev/null
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -0,0 +1,254 @@
+import React from 'react'
+import {observer} from 'mobx-react-lite'
+import {StyleSheet, TouchableOpacity, View} from 'react-native'
+import {useNavigation, useNavigationState} from '@react-navigation/native'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
+import {Text} from 'view/com/util/text/Text'
+import {UserAvatar} from 'view/com/util/UserAvatar'
+import {Link} from 'view/com/util/Link'
+import {usePalette} from 'lib/hooks/usePalette'
+import {useStores} from 'state/index'
+import {s, colors} from 'lib/styles'
+import {
+  HomeIcon,
+  HomeIconSolid,
+  MagnifyingGlassIcon2,
+  MagnifyingGlassIcon2Solid,
+  BellIcon,
+  BellIconSolid,
+  UserIcon,
+  UserIconSolid,
+  CogIcon,
+  CogIconSolid,
+  ComposeIcon2,
+} from 'lib/icons'
+import {getCurrentRoute, isTab, isStateAtTabRoot} from 'lib/routes/helpers'
+import {NavigationProp} from 'lib/routes/types'
+import {router} from '../../../routes'
+
+const ProfileCard = observer(() => {
+  const store = useStores()
+  return (
+    <Link href={`/profile/${store.me.handle}`} style={styles.profileCard}>
+      <UserAvatar avatar={store.me.avatar} size={64} />
+    </Link>
+  )
+})
+
+function BackBtn() {
+  const pal = usePalette('default')
+  const navigation = useNavigation<NavigationProp>()
+  const shouldShow = useNavigationState(state => !isStateAtTabRoot(state))
+
+  const onPressBack = React.useCallback(() => {
+    if (navigation.canGoBack()) {
+      navigation.goBack()
+    } else {
+      navigation.navigate('Home')
+    }
+  }, [navigation])
+
+  if (!shouldShow) {
+    return <></>
+  }
+  return (
+    <TouchableOpacity
+      testID="viewHeaderBackOrMenuBtn"
+      onPress={onPressBack}
+      style={styles.backBtn}>
+      <FontAwesomeIcon
+        size={24}
+        icon="angle-left"
+        style={pal.text as FontAwesomeIconStyle}
+      />
+    </TouchableOpacity>
+  )
+}
+
+interface NavItemProps {
+  count?: number
+  href: string
+  icon: JSX.Element
+  iconFilled: JSX.Element
+  label: string
+}
+const NavItem = observer(
+  ({count, href, icon, iconFilled, label}: NavItemProps) => {
+    const pal = usePalette('default')
+    const [pathName] = React.useMemo(() => router.matchPath(href), [href])
+    const currentRouteName = useNavigationState(state => {
+      if (!state) {
+        return 'Home'
+      }
+      return getCurrentRoute(state).name
+    })
+    const isCurrent = isTab(currentRouteName, pathName)
+
+    return (
+      <Link href={href} style={styles.navItem}>
+        <View style={[styles.navItemIconWrapper]}>
+          {isCurrent ? iconFilled : icon}
+          {typeof count === 'number' && count > 0 && (
+            <Text type="button" style={styles.navItemCount}>
+              {count}
+            </Text>
+          )}
+        </View>
+        <Text type="title" style={[isCurrent ? s.bold : s.normal, pal.text]}>
+          {label}
+        </Text>
+      </Link>
+    )
+  },
+)
+
+function ComposeBtn() {
+  const store = useStores()
+  const onPressCompose = () => store.shell.openComposer({})
+
+  return (
+    <TouchableOpacity style={[styles.newPostBtn]} onPress={onPressCompose}>
+      <View style={styles.newPostBtnIconWrapper}>
+        <ComposeIcon2
+          size={19}
+          strokeWidth={2}
+          style={styles.newPostBtnLabel}
+        />
+      </View>
+      <Text type="button" style={styles.newPostBtnLabel}>
+        New Post
+      </Text>
+    </TouchableOpacity>
+  )
+}
+
+export const DesktopLeftNav = observer(function DesktopLeftNav() {
+  const store = useStores()
+  const pal = usePalette('default')
+
+  return (
+    <View style={styles.leftNav}>
+      <ProfileCard />
+      <BackBtn />
+      <NavItem
+        href="/"
+        icon={<HomeIcon size={24} style={pal.text} />}
+        iconFilled={
+          <HomeIconSolid strokeWidth={4} size={24} style={pal.text} />
+        }
+        label="Home"
+      />
+      <NavItem
+        href="/search"
+        icon={
+          <MagnifyingGlassIcon2 strokeWidth={2} size={24} style={pal.text} />
+        }
+        iconFilled={
+          <MagnifyingGlassIcon2Solid
+            strokeWidth={2}
+            size={24}
+            style={pal.text}
+          />
+        }
+        label="Search"
+      />
+      <NavItem
+        href="/notifications"
+        count={store.me.notifications.unreadCount}
+        icon={<BellIcon strokeWidth={2} size={24} style={pal.text} />}
+        iconFilled={
+          <BellIconSolid strokeWidth={1.5} size={24} style={pal.text} />
+        }
+        label="Notifications"
+      />
+      <NavItem
+        href={`/profile/${store.me.handle}`}
+        icon={<UserIcon strokeWidth={1.75} size={28} style={pal.text} />}
+        iconFilled={
+          <UserIconSolid strokeWidth={1.75} size={28} style={pal.text} />
+        }
+        label="Profile"
+      />
+      <NavItem
+        href="/settings"
+        icon={<CogIcon strokeWidth={1.75} size={28} style={pal.text} />}
+        iconFilled={
+          <CogIconSolid strokeWidth={1.5} size={28} style={pal.text} />
+        }
+        label="Settings"
+      />
+      <ComposeBtn />
+    </View>
+  )
+})
+
+const styles = StyleSheet.create({
+  leftNav: {
+    position: 'absolute',
+    top: 10,
+    right: 'calc(50vw + 300px)',
+    width: 220,
+  },
+
+  profileCard: {
+    marginVertical: 10,
+    width: 60,
+  },
+
+  backBtn: {
+    position: 'absolute',
+    top: 12,
+    right: 12,
+    width: 30,
+    height: 30,
+  },
+
+  navItem: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingTop: 14,
+    paddingBottom: 10,
+  },
+  navItemIconWrapper: {
+    alignItems: 'center',
+    justifyContent: 'center',
+    width: 28,
+    height: 28,
+    marginRight: 10,
+    marginTop: 2,
+  },
+  navItemCount: {
+    position: 'absolute',
+    top: 0,
+    left: 15,
+    backgroundColor: colors.blue3,
+    color: colors.white,
+    fontSize: 12,
+    fontWeight: 'bold',
+    paddingHorizontal: 4,
+    borderRadius: 6,
+  },
+
+  newPostBtn: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'center',
+    width: 136,
+    borderRadius: 24,
+    paddingVertical: 10,
+    paddingHorizontal: 16,
+    backgroundColor: colors.blue3,
+    marginTop: 20,
+  },
+  newPostBtnIconWrapper: {
+    marginRight: 8,
+  },
+  newPostBtnLabel: {
+    color: colors.white,
+    fontSize: 16,
+    fontWeight: 'bold',
+  },
+})
diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx
new file mode 100644
index 000000000..a196951af
--- /dev/null
+++ b/src/view/shell/desktop/RightNav.tsx
@@ -0,0 +1,46 @@
+import React from 'react'
+import {observer} from 'mobx-react-lite'
+import {StyleSheet, View} from 'react-native'
+import {usePalette} from 'lib/hooks/usePalette'
+import {DesktopSearch} from './Search'
+import {Text} from 'view/com/util/text/Text'
+import {TextLink} from 'view/com/util/Link'
+import {FEEDBACK_FORM_URL} from 'lib/constants'
+
+export const DesktopRightNav = observer(function DesktopRightNav() {
+  const pal = usePalette('default')
+  return (
+    <View style={[styles.rightNav, pal.view]}>
+      <DesktopSearch />
+      <View style={styles.message}>
+        <Text type="md" style={[pal.textLight, styles.messageLine]}>
+          Welcome to Bluesky! This is a beta application that's still in
+          development.
+        </Text>
+        <TextLink
+          type="md"
+          style={pal.link}
+          href={FEEDBACK_FORM_URL}
+          text="Send feedback"
+        />
+      </View>
+    </View>
+  )
+})
+
+const styles = StyleSheet.create({
+  rightNav: {
+    position: 'absolute',
+    top: 20,
+    left: 'calc(50vw + 330px)',
+    width: 300,
+  },
+
+  message: {
+    marginTop: 20,
+    paddingHorizontal: 10,
+  },
+  messageLine: {
+    marginBottom: 10,
+  },
+})
diff --git a/src/view/shell/web/DesktopSearch.tsx b/src/view/shell/desktop/Search.tsx
index 43f13ca2b..7c96dbac2 100644
--- a/src/view/shell/web/DesktopSearch.tsx
+++ b/src/view/shell/desktop/Search.tsx
@@ -1,11 +1,12 @@
 import React from 'react'
-import {TextInput, View, StyleSheet, TouchableOpacity, Text} from 'react-native'
+import {TextInput, View, StyleSheet, TouchableOpacity} from 'react-native'
 import {UserAutocompleteViewModel} from 'state/models/user-autocomplete-view'
 import {observer} from 'mobx-react-lite'
 import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
-import {MagnifyingGlassIcon} from 'lib/icons'
-import {ProfileCard} from '../../com/profile/ProfileCard'
+import {MagnifyingGlassIcon2} from 'lib/icons'
+import {ProfileCard} from 'view/com/profile/ProfileCard'
+import {Text} from 'view/com/util/text/Text'
 
 export const DesktopSearch = observer(function DesktopSearch() {
   const store = useStores()
@@ -35,9 +36,10 @@ export const DesktopSearch = observer(function DesktopSearch() {
 
   return (
     <View style={styles.container}>
-      <View style={[pal.borderDark, pal.view, styles.search]}>
+      <View
+        style={[{backgroundColor: pal.colors.backgroundLight}, styles.search]}>
         <View style={[styles.inputContainer]}>
-          <MagnifyingGlassIcon
+          <MagnifyingGlassIcon2
             size={18}
             style={[pal.textLight, styles.iconWrapper]}
           />
@@ -57,7 +59,9 @@ export const DesktopSearch = observer(function DesktopSearch() {
           {query ? (
             <View style={styles.cancelBtn}>
               <TouchableOpacity onPress={onPressCancelSearch}>
-                <Text style={[pal.link]}>Cancel</Text>
+                <Text type="lg" style={[pal.link]}>
+                  Cancel
+                </Text>
               </TouchableOpacity>
             </View>
           ) : undefined}
@@ -97,21 +101,23 @@ const styles = StyleSheet.create({
     width: 300,
   },
   search: {
-    paddingHorizontal: 10,
+    paddingHorizontal: 16,
+    paddingVertical: 2,
     width: 300,
     borderRadius: 20,
-    borderWidth: 1,
   },
   inputContainer: {
     flexDirection: 'row',
   },
   iconWrapper: {
+    position: 'relative',
+    top: 2,
     paddingVertical: 7,
-    marginRight: 4,
+    marginRight: 8,
   },
   input: {
     flex: 1,
-    fontSize: 16,
+    fontSize: 18,
     width: '100%',
     paddingTop: 7,
     paddingBottom: 7,
diff --git a/src/view/shell/index.tsx b/src/view/shell/index.tsx
new file mode 100644
index 000000000..116915ff4
--- /dev/null
+++ b/src/view/shell/index.tsx
@@ -0,0 +1,139 @@
+import React from 'react'
+import {observer} from 'mobx-react-lite'
+import {StatusBar, StyleSheet, useWindowDimensions, View} from 'react-native'
+import {useSafeAreaInsets} from 'react-native-safe-area-context'
+import {Drawer} from 'react-native-drawer-layout'
+import {useNavigationState} from '@react-navigation/native'
+import {useStores} from 'state/index'
+import {Login} from 'view/screens/Login'
+import {ModalsContainer} from 'view/com/modals/Modal'
+import {Lightbox} from 'view/com/lightbox/Lightbox'
+import {Text} from 'view/com/util/text/Text'
+import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
+import {DrawerContent} from './Drawer'
+import {Composer} from './Composer'
+import {s} from 'lib/styles'
+import {useTheme} from 'lib/ThemeContext'
+import {usePalette} from 'lib/hooks/usePalette'
+import {RoutesContainer, TabsNavigator} from '../../Navigation'
+import {isStateAtTabRoot} from 'lib/routes/helpers'
+
+const ShellInner = observer(() => {
+  const store = useStores()
+  const winDim = useWindowDimensions()
+  const safeAreaInsets = useSafeAreaInsets()
+  const containerPadding = React.useMemo(
+    () => ({height: '100%', paddingTop: safeAreaInsets.top}),
+    [safeAreaInsets],
+  )
+  const renderDrawerContent = React.useCallback(() => <DrawerContent />, [])
+  const onOpenDrawer = React.useCallback(
+    () => store.shell.openDrawer(),
+    [store],
+  )
+  const onCloseDrawer = React.useCallback(
+    () => store.shell.closeDrawer(),
+    [store],
+  )
+  const canGoBack = useNavigationState(state => !isStateAtTabRoot(state))
+
+  return (
+    <>
+      <View style={containerPadding}>
+        <ErrorBoundary>
+          <Drawer
+            renderDrawerContent={renderDrawerContent}
+            open={store.shell.isDrawerOpen}
+            onOpen={onOpenDrawer}
+            onClose={onCloseDrawer}
+            swipeEdgeWidth={winDim.width}
+            swipeEnabled={!canGoBack}>
+            <TabsNavigator />
+          </Drawer>
+        </ErrorBoundary>
+      </View>
+      <ModalsContainer />
+      <Lightbox />
+      <Composer
+        active={store.shell.isComposerActive}
+        onClose={() => store.shell.closeComposer()}
+        winHeight={winDim.height}
+        replyTo={store.shell.composerOpts?.replyTo}
+        onPost={store.shell.composerOpts?.onPost}
+        quote={store.shell.composerOpts?.quote}
+      />
+    </>
+  )
+})
+
+export const Shell: React.FC = observer(() => {
+  const theme = useTheme()
+  const pal = usePalette('default')
+  const store = useStores()
+
+  if (store.hackUpgradeNeeded) {
+    return (
+      <View style={styles.outerContainer}>
+        <View style={[s.flexCol, s.p20, s.h100pct]}>
+          <View style={s.flex1} />
+          <View>
+            <Text type="title-2xl" style={s.pb10}>
+              Update required
+            </Text>
+            <Text style={[s.pb20, s.bold]}>
+              Please update your app to the latest version. If no update is
+              available yet, please check the App Store in a day or so.
+            </Text>
+            <Text type="title" style={s.pb10}>
+              What's happening?
+            </Text>
+            <Text style={s.pb10}>
+              We're in the final stages of the AT Protocol's v1 development. To
+              make sure everything works as well as possible, we're making final
+              breaking changes to the APIs.
+            </Text>
+            <Text>
+              If we didn't botch this process, a new version of the app should
+              be available now.
+            </Text>
+          </View>
+          <View style={s.flex1} />
+          <View style={s.footerSpacer} />
+        </View>
+      </View>
+    )
+  }
+
+  if (!store.session.hasSession) {
+    return (
+      <View style={styles.outerContainer}>
+        <StatusBar
+          barStyle={
+            theme.colorScheme === 'dark' ? 'light-content' : 'dark-content'
+          }
+        />
+        <Login />
+        <ModalsContainer />
+      </View>
+    )
+  }
+
+  return (
+    <View testID="mobileShellView" style={[styles.outerContainer, pal.view]}>
+      <StatusBar
+        barStyle={
+          theme.colorScheme === 'dark' ? 'light-content' : 'dark-content'
+        }
+      />
+      <RoutesContainer>
+        <ShellInner />
+      </RoutesContainer>
+    </View>
+  )
+})
+
+const styles = StyleSheet.create({
+  outerContainer: {
+    height: '100%',
+  },
+})
diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx
new file mode 100644
index 000000000..9a97505e8
--- /dev/null
+++ b/src/view/shell/index.web.tsx
@@ -0,0 +1,113 @@
+import React from 'react'
+import {observer} from 'mobx-react-lite'
+import {View, StyleSheet} from 'react-native'
+import {useStores} from 'state/index'
+import {DesktopLeftNav} from './desktop/LeftNav'
+import {DesktopRightNav} from './desktop/RightNav'
+import {Login} from '../screens/Login'
+import {ErrorBoundary} from '../com/util/ErrorBoundary'
+import {Lightbox} from '../com/lightbox/Lightbox'
+import {ModalsContainer} from '../com/modals/Modal'
+import {Text} from 'view/com/util/text/Text'
+import {Composer} from './Composer.web'
+import {usePalette} from 'lib/hooks/usePalette'
+import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
+import {s, colors} from 'lib/styles'
+import {isMobileWeb} from 'platform/detection'
+import {RoutesContainer, FlatNavigator} from '../../Navigation'
+
+const ShellInner = observer(() => {
+  const store = useStores()
+
+  return (
+    <>
+      <View style={s.hContentRegion}>
+        <ErrorBoundary>
+          <FlatNavigator />
+        </ErrorBoundary>
+      </View>
+      <DesktopLeftNav />
+      <DesktopRightNav />
+      <View style={[styles.viewBorder, styles.viewBorderLeft]} />
+      <View style={[styles.viewBorder, styles.viewBorderRight]} />
+      <Composer
+        active={store.shell.isComposerActive}
+        onClose={() => store.shell.closeComposer()}
+        winHeight={0}
+        replyTo={store.shell.composerOpts?.replyTo}
+        onPost={store.shell.composerOpts?.onPost}
+      />
+      <ModalsContainer />
+      <Lightbox />
+    </>
+  )
+})
+
+export const Shell: React.FC = observer(() => {
+  const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark)
+  const store = useStores()
+
+  if (isMobileWeb) {
+    return <NoMobileWeb />
+  }
+
+  if (!store.session.hasSession) {
+    return (
+      <View style={[s.hContentRegion, pageBg]}>
+        <Login />
+        <ModalsContainer />
+      </View>
+    )
+  }
+
+  return (
+    <View style={[s.hContentRegion, pageBg]}>
+      <RoutesContainer>
+        <ShellInner />
+      </RoutesContainer>
+    </View>
+  )
+})
+
+function NoMobileWeb() {
+  const pal = usePalette('default')
+  return (
+    <View style={[pal.view, styles.noMobileWeb]}>
+      <Text type="title-2xl" style={s.pb20}>
+        We're so sorry!
+      </Text>
+      <Text type="lg">
+        This app is not available for mobile Web yet. Please open it on your
+        desktop or download the iOS app.
+      </Text>
+    </View>
+  )
+}
+
+const styles = StyleSheet.create({
+  bgLight: {
+    backgroundColor: colors.white,
+  },
+  bgDark: {
+    backgroundColor: colors.black, // TODO
+  },
+  viewBorder: {
+    position: 'absolute',
+    width: 1,
+    height: '100%',
+    borderLeftWidth: 1,
+    borderLeftColor: colors.gray2,
+  },
+  viewBorderLeft: {
+    left: 'calc(50vw - 300px)',
+  },
+  viewBorderRight: {
+    left: 'calc(50vw + 300px)',
+  },
+  noMobileWeb: {
+    height: '100%',
+    justifyContent: 'center',
+    paddingHorizontal: 20,
+    paddingBottom: 40,
+  },
+})
diff --git a/src/view/shell/mobile/Menu.tsx b/src/view/shell/mobile/Menu.tsx
deleted file mode 100644
index 927e712e1..000000000
--- 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
-  }) => (
-    <TouchableOpacity
-      testID={`menuItemButton-${label}`}
-      style={styles.menuItem}
-      onPress={onPress ? onPress : () => onNavigate(url || '/')}>
-      <View style={[styles.menuItemIconWrapper]}>
-        {icon}
-        {count ? (
-          <View style={styles.menuItemCount}>
-            <Text style={styles.menuItemCountLabel}>{count}</Text>
-          </View>
-        ) : undefined}
-      </View>
-      <Text
-        type={bold ? '2xl-bold' : '2xl'}
-        style={[pal.text, s.flex1]}
-        numberOfLines={1}>
-        {label}
-      </Text>
-    </TouchableOpacity>
-  )
-
-  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 (
-    <View
-      testID="menuView"
-      style={[
-        styles.view,
-        theme.colorScheme === 'light' ? pal.view : styles.viewDarkMode,
-      ]}>
-      <TouchableOpacity
-        testID="profileCardButton"
-        onPress={() => onNavigate(`/profile/${store.me.handle}`)}>
-        <UserAvatar
-          size={80}
-          displayName={store.me.displayName}
-          handle={store.me.handle}
-          avatar={store.me.avatar}
-        />
-        <Text
-          type="title-lg"
-          style={[pal.text, s.bold, styles.profileCardDisplayName]}>
-          {store.me.displayName || store.me.handle}
-        </Text>
-        <Text type="2xl" style={[pal.textLight, styles.profileCardHandle]}>
-          @{store.me.handle}
-        </Text>
-        <Text type="xl" style={[pal.textLight, styles.profileCardFollowers]}>
-          <Text type="xl-medium" style={pal.text}>
-            {store.me.followersCount || 0}
-          </Text>{' '}
-          {pluralize(store.me.followersCount || 0, 'follower')} &middot;{' '}
-          <Text type="xl-medium" style={pal.text}>
-            {store.me.followsCount || 0}
-          </Text>{' '}
-          following
-        </Text>
-      </TouchableOpacity>
-      <View style={s.flex1} />
-      <View>
-        <MenuItem
-          icon={
-            isAtSearch ? (
-              <MagnifyingGlassIcon2Solid
-                style={pal.text as StyleProp<ViewStyle>}
-                size={24}
-                strokeWidth={1.7}
-              />
-            ) : (
-              <MagnifyingGlassIcon2
-                style={pal.text as StyleProp<ViewStyle>}
-                size={24}
-                strokeWidth={1.7}
-              />
-            )
-          }
-          label="Search"
-          url="/search"
-          bold={isAtSearch}
-        />
-        <MenuItem
-          icon={
-            isAtHome ? (
-              <HomeIconSolid
-                style={pal.text as StyleProp<ViewStyle>}
-                size="24"
-                strokeWidth={3.25}
-                fillOpacity={1}
-              />
-            ) : (
-              <HomeIcon
-                style={pal.text as StyleProp<ViewStyle>}
-                size="24"
-                strokeWidth={3.25}
-              />
-            )
-          }
-          label="Home"
-          url="/"
-          bold={isAtHome}
-        />
-        <MenuItem
-          icon={
-            isAtNotifications ? (
-              <BellIconSolid
-                style={pal.text as StyleProp<ViewStyle>}
-                size="24"
-                strokeWidth={1.7}
-                fillOpacity={1}
-              />
-            ) : (
-              <BellIcon
-                style={pal.text as StyleProp<ViewStyle>}
-                size="24"
-                strokeWidth={1.7}
-              />
-            )
-          }
-          label="Notifications"
-          url="/notifications"
-          count={store.me.notifications.unreadCount}
-          bold={isAtNotifications}
-        />
-        <MenuItem
-          icon={
-            <UserIcon
-              style={pal.text as StyleProp<ViewStyle>}
-              size="26"
-              strokeWidth={1.5}
-            />
-          }
-          label="Profile"
-          url={`/profile/${store.me.handle}`}
-        />
-        <MenuItem
-          icon={
-            <CogIcon
-              style={pal.text as StyleProp<ViewStyle>}
-              size="26"
-              strokeWidth={1.75}
-            />
-          }
-          label="Settings"
-          url="/settings"
-        />
-      </View>
-      <View style={s.flex1} />
-      <View style={styles.footer}>
-        <TouchableOpacity
-          onPress={onDarkmodePress}
-          style={[
-            styles.footerBtn,
-            theme.colorScheme === 'light' ? pal.btn : styles.footerBtnDarkMode,
-          ]}>
-          <MoonIcon
-            size={22}
-            style={pal.text as StyleProp<ViewStyle>}
-            strokeWidth={2}
-          />
-        </TouchableOpacity>
-        <TouchableOpacity
-          onPress={onPressFeedback}
-          style={[
-            styles.footerBtn,
-            styles.footerBtnFeedback,
-            theme.colorScheme === 'light'
-              ? styles.footerBtnFeedbackLight
-              : styles.footerBtnFeedbackDark,
-          ]}>
-          <FontAwesomeIcon
-            style={pal.link as FontAwesomeIconStyle}
-            size={19}
-            icon={['far', 'message']}
-          />
-          <Text type="2xl-medium" style={[pal.link, s.pl10]}>
-            Feedback
-          </Text>
-        </TouchableOpacity>
-      </View>
-    </View>
-  )
-})
-
-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,
-  },
-})
diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx
deleted file mode 100644
index 01df6c165..000000000
--- a/src/view/shell/mobile/index.tsx
+++ /dev/null
@@ -1,335 +0,0 @@
-import React, {useState} from 'react'
-import {observer} from 'mobx-react-lite'
-import {
-  Animated,
-  StatusBar,
-  StyleSheet,
-  TouchableWithoutFeedback,
-  useWindowDimensions,
-  View,
-} from 'react-native'
-import {ScreenContainer, Screen} from 'react-native-screens'
-import {useSafeAreaInsets} from 'react-native-safe-area-context'
-import {IconProp} from '@fortawesome/fontawesome-svg-core'
-import {useStores} from 'state/index'
-import {NavigationModel} from 'state/models/navigation'
-import {match, MatchResult} from '../../routes'
-import {Login} from '../../screens/Login'
-import {Menu} from './Menu'
-import {BottomBar} from './BottomBar'
-import {HorzSwipe} from '../../com/util/gestures/HorzSwipe'
-import {ModalsContainer} from '../../com/modals/Modal'
-import {Lightbox} from '../../com/lightbox/Lightbox'
-import {Text} from '../../com/util/text/Text'
-import {ErrorBoundary} from '../../com/util/ErrorBoundary'
-import {Composer} from './Composer'
-import {s, colors} from 'lib/styles'
-import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
-import {useTheme} from 'lib/ThemeContext'
-import {usePalette} from 'lib/hooks/usePalette'
-
-export const MobileShell: React.FC = observer(() => {
-  const theme = useTheme()
-  const pal = usePalette('default')
-  const store = useStores()
-  const winDim = useWindowDimensions()
-  const [menuSwipingDirection, setMenuSwipingDirection] = useState(0)
-  const swipeGestureInterp = useAnimatedValue(0)
-  const safeAreaInsets = useSafeAreaInsets()
-  const screenRenderDesc = constructScreenRenderDesc(store.nav)
-
-  // navigation swipes
-  // =
-  const isMenuActive = store.shell.isMainMenuOpen
-  const canSwipeLeft = store.nav.tab.canGoBack || !isMenuActive
-  const canSwipeRight = isMenuActive
-  const onNavSwipeStartDirection = (dx: number) => {
-    if (dx < 0 && !store.nav.tab.canGoBack) {
-      setMenuSwipingDirection(dx)
-    } else if (dx > 0 && isMenuActive) {
-      setMenuSwipingDirection(dx)
-    } else {
-      setMenuSwipingDirection(0)
-    }
-  }
-  const onNavSwipeEnd = (dx: number) => {
-    if (dx < 0) {
-      if (store.nav.tab.canGoBack) {
-        store.nav.tab.goBack()
-      } else {
-        store.shell.setMainMenuOpen(true)
-      }
-    } else if (dx > 0) {
-      if (isMenuActive) {
-        store.shell.setMainMenuOpen(false)
-      }
-    }
-    setMenuSwipingDirection(0)
-  }
-  const swipeTranslateX = Animated.multiply(
-    swipeGestureInterp,
-    winDim.width * -1,
-  )
-  const swipeTransform = store.nav.tab.canGoBack
-    ? {transform: [{translateX: swipeTranslateX}]}
-    : undefined
-  let shouldRenderMenu = false
-  let menuTranslateX
-  const menuDrawerWidth = winDim.width - 100
-  if (isMenuActive) {
-    // menu is active, interpret swipes as closes
-    menuTranslateX = Animated.multiply(swipeGestureInterp, menuDrawerWidth * -1)
-    shouldRenderMenu = true
-  } else if (!store.nav.tab.canGoBack) {
-    // at back of history, interpret swipes as opens
-    menuTranslateX = Animated.subtract(
-      menuDrawerWidth * -1,
-      Animated.multiply(swipeGestureInterp, menuDrawerWidth),
-    )
-    shouldRenderMenu = true
-  }
-  const menuSwipeTransform = menuTranslateX
-    ? {
-        transform: [{translateX: menuTranslateX}],
-      }
-    : undefined
-  const swipeOpacity = {
-    opacity: swipeGestureInterp.interpolate({
-      inputRange: [-1, 0, 1],
-      outputRange: [0, 0.6, 0],
-    }),
-  }
-  const menuSwipeOpacity =
-    menuSwipingDirection !== 0
-      ? {
-          opacity: swipeGestureInterp.interpolate({
-            inputRange: menuSwipingDirection > 0 ? [0, 1] : [-1, 0],
-            outputRange: [0.6, 0],
-          }),
-        }
-      : undefined
-
-  if (store.hackUpgradeNeeded) {
-    return (
-      <View style={styles.outerContainer}>
-        <View style={[s.flexCol, s.p20, s.h100pct]}>
-          <View style={s.flex1} />
-          <View>
-            <Text type="title-2xl" style={s.pb10}>
-              Update required
-            </Text>
-            <Text style={[s.pb20, s.bold]}>
-              Please update your app to the latest version. If no update is
-              available yet, please check the App Store in a day or so.
-            </Text>
-            <Text type="title" style={s.pb10}>
-              What's happening?
-            </Text>
-            <Text style={s.pb10}>
-              We're in the final stages of the AT Protocol's v1 development. To
-              make sure everything works as well as possible, we're making final
-              breaking changes to the APIs.
-            </Text>
-            <Text>
-              If we didn't botch this process, a new version of the app should
-              be available now.
-            </Text>
-          </View>
-          <View style={s.flex1} />
-          <View style={s.footerSpacer} />
-        </View>
-      </View>
-    )
-  }
-
-  if (!store.session.hasSession) {
-    return (
-      <View style={styles.outerContainer}>
-        <StatusBar
-          barStyle={
-            theme.colorScheme === 'dark' ? 'light-content' : 'dark-content'
-          }
-        />
-        <Login />
-        <ModalsContainer />
-      </View>
-    )
-  }
-
-  const screenBg = {
-    backgroundColor: theme.colorScheme === 'dark' ? colors.black : colors.gray1,
-  }
-  return (
-    <View testID="mobileShellView" style={[styles.outerContainer, pal.view]}>
-      <StatusBar
-        barStyle={
-          theme.colorScheme === 'dark' ? 'light-content' : 'dark-content'
-        }
-      />
-      <View style={[styles.innerContainer, {paddingTop: safeAreaInsets.top}]}>
-        <HorzSwipe
-          distThresholdDivisor={2.5}
-          useNativeDriver
-          panX={swipeGestureInterp}
-          swipeEnabled
-          canSwipeLeft={canSwipeLeft}
-          canSwipeRight={canSwipeRight}
-          onSwipeStartDirection={onNavSwipeStartDirection}
-          onSwipeEnd={onNavSwipeEnd}>
-          <ScreenContainer style={styles.screenContainer}>
-            {screenRenderDesc.screens.map(
-              ({Com, navIdx, params, key, current, previous}) => {
-                if (isMenuActive) {
-                  // HACK menu is active, treat current as previous
-                  if (previous) {
-                    previous = false
-                  } else if (current) {
-                    current = false
-                    previous = true
-                  }
-                }
-                return (
-                  <Screen
-                    key={key}
-                    style={[StyleSheet.absoluteFill]}
-                    activityState={current ? 2 : previous ? 1 : 0}>
-                    <Animated.View
-                      style={
-                        current ? [styles.screenMask, swipeOpacity] : undefined
-                      }
-                    />
-                    <Animated.View
-                      style={[
-                        s.h100pct,
-                        screenBg,
-                        current ? [swipeTransform] : undefined,
-                      ]}>
-                      <ErrorBoundary>
-                        <Com
-                          params={params}
-                          navIdx={navIdx}
-                          visible={current}
-                        />
-                      </ErrorBoundary>
-                    </Animated.View>
-                  </Screen>
-                )
-              },
-            )}
-          </ScreenContainer>
-          <BottomBar />
-          {isMenuActive || menuSwipingDirection !== 0 ? (
-            <TouchableWithoutFeedback
-              onPress={() => store.shell.setMainMenuOpen(false)}>
-              <Animated.View style={[styles.screenMask, menuSwipeOpacity]} />
-            </TouchableWithoutFeedback>
-          ) : undefined}
-          {shouldRenderMenu && (
-            <Animated.View style={[styles.menuDrawer, menuSwipeTransform]}>
-              <Menu onClose={() => store.shell.setMainMenuOpen(false)} />
-            </Animated.View>
-          )}
-        </HorzSwipe>
-      </View>
-      <ModalsContainer />
-      <Lightbox />
-      <Composer
-        active={store.shell.isComposerActive}
-        onClose={() => store.shell.closeComposer()}
-        winHeight={winDim.height}
-        replyTo={store.shell.composerOpts?.replyTo}
-        imagesOpen={store.shell.composerOpts?.imagesOpen}
-        onPost={store.shell.composerOpts?.onPost}
-        quote={store.shell.composerOpts?.quote}
-      />
-    </View>
-  )
-})
-
-/**
- * This method produces the information needed by the shell to
- * render the current screens with screen-caching behaviors.
- */
-type ScreenRenderDesc = MatchResult & {
-  key: string
-  navIdx: string
-  current: boolean
-  previous: boolean
-  isNewTab: boolean
-}
-function constructScreenRenderDesc(nav: NavigationModel): {
-  icon: IconProp
-  hasNewTab: boolean
-  screens: ScreenRenderDesc[]
-} {
-  let hasNewTab = false
-  let icon: IconProp = 'magnifying-glass'
-  let screens: ScreenRenderDesc[] = []
-  for (const tab of nav.tabs) {
-    const tabScreens = [
-      ...tab.getBackList(5),
-      Object.assign({}, tab.current, {index: tab.index}),
-    ]
-    const parsedTabScreens = tabScreens.map(screen => {
-      const isCurrent = nav.isCurrentScreen(tab.id, screen.index)
-      const isPrevious = nav.isCurrentScreen(tab.id, screen.index + 1)
-      const matchRes = match(screen.url)
-      if (isCurrent) {
-        icon = matchRes.icon
-      }
-      hasNewTab = hasNewTab || tab.isNewTab
-      return Object.assign(matchRes, {
-        key: `t${tab.id}-s${screen.index}`,
-        navIdx: `${tab.id}-${screen.id}`,
-        current: isCurrent,
-        previous: isPrevious,
-        isNewTab: tab.isNewTab,
-      }) as ScreenRenderDesc
-    })
-    screens = screens.concat(parsedTabScreens)
-  }
-  return {
-    icon,
-    hasNewTab,
-    screens,
-  }
-}
-
-const styles = StyleSheet.create({
-  outerContainer: {
-    height: '100%',
-  },
-  innerContainer: {
-    height: '100%',
-  },
-  screenContainer: {
-    height: '100%',
-  },
-  screenMask: {
-    position: 'absolute',
-    top: 0,
-    bottom: 0,
-    left: 0,
-    right: 0,
-    backgroundColor: '#000',
-    opacity: 0.6,
-  },
-  menuDrawer: {
-    position: 'absolute',
-    top: 0,
-    bottom: 0,
-    left: 0,
-    right: 100,
-  },
-  topBarProtector: {
-    position: 'absolute',
-    top: 0,
-    left: 0,
-    right: 0,
-    height: 50, // will be overwritten by insets
-    backgroundColor: colors.white,
-  },
-  topBarProtectorDark: {
-    backgroundColor: colors.black,
-  },
-})
diff --git a/src/view/shell/web/DesktopHeader.tsx b/src/view/shell/web/DesktopHeader.tsx
deleted file mode 100644
index 8748ebbde..000000000
--- a/src/view/shell/web/DesktopHeader.tsx
+++ /dev/null
@@ -1,222 +0,0 @@
-import React from 'react'
-import {observer} from 'mobx-react-lite'
-import {Pressable, StyleSheet, TouchableOpacity, View} from 'react-native'
-import {Text} from 'view/com/util/text/Text'
-import {UserAvatar} from 'view/com/util/UserAvatar'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
-import {useStores} from 'state/index'
-import {colors} from 'lib/styles'
-import {
-  ComposeIcon,
-  HomeIcon,
-  HomeIconSolid,
-  BellIcon,
-  BellIconSolid,
-  MagnifyingGlassIcon,
-  CogIcon,
-} from 'lib/icons'
-import {DesktopSearch} from './DesktopSearch'
-
-interface NavItemProps {
-  count?: number
-  href: string
-  icon: JSX.Element
-  iconFilled: JSX.Element
-  isProfile?: boolean
-}
-export const NavItem = observer(
-  ({count, href, icon, iconFilled}: NavItemProps) => {
-    const store = useStores()
-    const hoverBg = useColorSchemeStyle(
-      styles.navItemHoverBgLight,
-      styles.navItemHoverBgDark,
-    )
-    const isCurrent = store.nav.tab.current.url === href
-    const onPress = () => store.nav.navigate(href)
-    return (
-      <Pressable
-        style={state => [
-          styles.navItem,
-          // @ts-ignore Pressable state differs for RNW -prf
-          (state.hovered || isCurrent) && hoverBg,
-        ]}
-        onPress={onPress}>
-        <View style={[styles.navItemIconWrapper]}>
-          {isCurrent ? iconFilled : icon}
-          {typeof count === 'number' && count > 0 && (
-            <Text type="button" style={styles.navItemCount}>
-              {count}
-            </Text>
-          )}
-        </View>
-      </Pressable>
-    )
-  },
-)
-
-export const ProfileItem = observer(() => {
-  const store = useStores()
-  const hoverBg = useColorSchemeStyle(
-    styles.navItemHoverBgLight,
-    styles.navItemHoverBgDark,
-  )
-  const href = `/profile/${store.me.handle}`
-  const isCurrent = store.nav.tab.current.url === href
-  const onPress = () => store.nav.navigate(href)
-  return (
-    <Pressable
-      style={state => [
-        styles.navItem,
-        // @ts-ignore Pressable state differs for RNW -prf
-        (state.hovered || isCurrent) && hoverBg,
-      ]}
-      onPress={onPress}>
-      <View style={[styles.navItemIconWrapper]}>
-        <UserAvatar
-          handle={store.me.handle}
-          displayName={store.me.displayName}
-          avatar={store.me.avatar}
-          size={28}
-        />
-      </View>
-    </Pressable>
-  )
-})
-
-export const DesktopHeader = observer(function DesktopHeader({}: {
-  canGoBack?: boolean
-}) {
-  const store = useStores()
-  const pal = usePalette('default')
-  const onPressCompose = () => store.shell.openComposer({})
-
-  return (
-    <View style={[styles.header, pal.borderDark, pal.view]}>
-      <Text type="title-xl" style={[pal.text, styles.title]}>
-        Bluesky
-      </Text>
-      <View style={styles.space30} />
-      <NavItem
-        href="/"
-        icon={<HomeIcon size={24} />}
-        iconFilled={<HomeIconSolid size={24} />}
-      />
-      <View style={styles.space15} />
-      <NavItem
-        href="/search"
-        icon={<MagnifyingGlassIcon size={24} />}
-        iconFilled={<MagnifyingGlassIcon strokeWidth={3} size={24} />}
-      />
-      <View style={styles.space15} />
-      <NavItem
-        href="/notifications"
-        count={store.me.notifications.unreadCount}
-        icon={<BellIcon size={24} />}
-        iconFilled={<BellIconSolid size={24} />}
-      />
-      <View style={styles.spaceFlex} />
-      <TouchableOpacity style={[styles.newPostBtn]} onPress={onPressCompose}>
-        <View style={styles.newPostBtnIconWrapper}>
-          <ComposeIcon
-            size={16}
-            strokeWidth={2}
-            style={styles.newPostBtnLabel}
-          />
-        </View>
-        <Text type="md" style={styles.newPostBtnLabel}>
-          New Post
-        </Text>
-      </TouchableOpacity>
-      <View style={styles.space20} />
-      <DesktopSearch />
-      <View style={styles.space15} />
-      <ProfileItem />
-      <NavItem
-        href="/settings"
-        icon={<CogIcon strokeWidth={2} size={28} />}
-        iconFilled={<CogIcon strokeWidth={2.5} size={28} />}
-      />
-    </View>
-  )
-})
-
-const styles = StyleSheet.create({
-  header: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    // paddingTop: 18,
-    // paddingBottom: 18,
-    paddingLeft: 30,
-    paddingRight: 40,
-    borderBottomWidth: 1,
-    zIndex: 1,
-  },
-
-  spaceFlex: {
-    flex: 1,
-  },
-  space15: {
-    width: 15,
-  },
-  space20: {
-    width: 20,
-  },
-  space30: {
-    width: 30,
-  },
-
-  title: {},
-
-  navItem: {
-    paddingTop: 14,
-    paddingBottom: 10,
-    paddingHorizontal: 10,
-    alignItems: 'center',
-    borderBottomWidth: 2,
-    borderBottomColor: 'transparent',
-  },
-  navItemHoverBgLight: {
-    borderBottomWidth: 2,
-    borderBottomColor: colors.blue3,
-  },
-  navItemHoverBgDark: {
-    borderBottomWidth: 2,
-    backgroundColor: colors.blue3,
-  },
-  navItemIconWrapper: {
-    alignItems: 'center',
-    justifyContent: 'center',
-    width: 28,
-    height: 28,
-    marginBottom: 2,
-  },
-  navItemCount: {
-    position: 'absolute',
-    top: 0,
-    left: 15,
-    backgroundColor: colors.red3,
-    color: colors.white,
-    fontSize: 12,
-    fontWeight: 'bold',
-    paddingHorizontal: 4,
-    borderRadius: 6,
-  },
-
-  newPostBtn: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'center',
-    borderRadius: 24,
-    paddingTop: 8,
-    paddingBottom: 8,
-    paddingHorizontal: 18,
-    backgroundColor: colors.blue3,
-  },
-  newPostBtnIconWrapper: {
-    marginRight: 8,
-  },
-  newPostBtnLabel: {
-    color: colors.white,
-  },
-})
diff --git a/src/view/shell/web/index.tsx b/src/view/shell/web/index.tsx
deleted file mode 100644
index a76ae8060..000000000
--- a/src/view/shell/web/index.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-import React from 'react'
-import {observer} from 'mobx-react-lite'
-import {View, StyleSheet} from 'react-native'
-import {IconProp} from '@fortawesome/fontawesome-svg-core'
-import {useStores} from 'state/index'
-import {NavigationModel} from 'state/models/navigation'
-import {match, MatchResult} from '../../routes'
-import {DesktopHeader} from './DesktopHeader'
-import {Login} from '../../screens/Login'
-import {ErrorBoundary} from '../../com/util/ErrorBoundary'
-import {Lightbox} from '../../com/lightbox/Lightbox'
-import {ModalsContainer} from '../../com/modals/Modal'
-import {Text} from 'view/com/util/text/Text'
-import {Composer} from './Composer'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
-import {s, colors} from 'lib/styles'
-import {isMobileWeb} from 'platform/detection'
-
-export const WebShell: React.FC = observer(() => {
-  const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark)
-  const store = useStores()
-  const screenRenderDesc = constructScreenRenderDesc(store.nav)
-
-  if (isMobileWeb) {
-    return <NoMobileWeb />
-  }
-
-  if (!store.session.hasSession) {
-    return (
-      <View style={styles.outerContainer}>
-        <Login />
-        <ModalsContainer />
-      </View>
-    )
-  }
-
-  return (
-    <View style={[styles.outerContainer, pageBg]}>
-      <DesktopHeader />
-      {screenRenderDesc.screens.map(({Com, navIdx, params, key, current}) => (
-        <View
-          key={key}
-          style={[s.hContentRegion, current ? styles.visible : styles.hidden]}>
-          <ErrorBoundary>
-            <Com params={params} navIdx={navIdx} visible={current} />
-          </ErrorBoundary>
-        </View>
-      ))}
-      <Composer
-        active={store.shell.isComposerActive}
-        onClose={() => store.shell.closeComposer()}
-        winHeight={0}
-        replyTo={store.shell.composerOpts?.replyTo}
-        imagesOpen={store.shell.composerOpts?.imagesOpen}
-        onPost={store.shell.composerOpts?.onPost}
-      />
-      <ModalsContainer />
-      <Lightbox />
-    </View>
-  )
-})
-
-/**
- * This method produces the information needed by the shell to
- * render the current screens with screen-caching behaviors.
- */
-type ScreenRenderDesc = MatchResult & {
-  key: string
-  navIdx: string
-  current: boolean
-  previous: boolean
-  isNewTab: boolean
-}
-function constructScreenRenderDesc(nav: NavigationModel): {
-  icon: IconProp
-  hasNewTab: boolean
-  screens: ScreenRenderDesc[]
-} {
-  let hasNewTab = false
-  let icon: IconProp = 'magnifying-glass'
-  let screens: ScreenRenderDesc[] = []
-  for (const tab of nav.tabs) {
-    const tabScreens = [
-      ...tab.getBackList(5),
-      Object.assign({}, tab.current, {index: tab.index}),
-    ]
-    const parsedTabScreens = tabScreens.map(screen => {
-      const isCurrent = nav.isCurrentScreen(tab.id, screen.index)
-      const isPrevious = nav.isCurrentScreen(tab.id, screen.index + 1)
-      const matchRes = match(screen.url)
-      if (isCurrent) {
-        icon = matchRes.icon
-      }
-      hasNewTab = hasNewTab || tab.isNewTab
-      return Object.assign(matchRes, {
-        key: `t${tab.id}-s${screen.index}`,
-        navIdx: `${tab.id}-${screen.id}`,
-        current: isCurrent,
-        previous: isPrevious,
-        isNewTab: tab.isNewTab,
-      }) as ScreenRenderDesc
-    })
-    screens = screens.concat(parsedTabScreens)
-  }
-  return {
-    icon,
-    hasNewTab,
-    screens,
-  }
-}
-
-function NoMobileWeb() {
-  const pal = usePalette('default')
-  return (
-    <View style={[pal.view, styles.noMobileWeb]}>
-      <Text type="title-2xl" style={s.pb20}>
-        We're so sorry!
-      </Text>
-      <Text type="lg">
-        This app is not available for mobile Web yet. Please open it on your
-        desktop or download the iOS app.
-      </Text>
-    </View>
-  )
-}
-
-const styles = StyleSheet.create({
-  outerContainer: {
-    height: '100%',
-  },
-  bgLight: {
-    backgroundColor: colors.white,
-  },
-  bgDark: {
-    backgroundColor: colors.black, // TODO
-  },
-  visible: {
-    display: 'flex',
-  },
-  hidden: {
-    display: 'none',
-  },
-  noMobileWeb: {
-    height: '100%',
-    justifyContent: 'center',
-    paddingHorizontal: 20,
-    paddingBottom: 40,
-  },
-})