about summary refs log tree commit diff
path: root/src/view/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com')
-rw-r--r--src/view/com/feed/Feed.tsx15
-rw-r--r--src/view/com/feed/FeedItem.tsx26
-rw-r--r--src/view/com/modals/SharePost.native.tsx89
-rw-r--r--src/view/com/notifications/Feed.tsx5
-rw-r--r--src/view/com/notifications/FeedItem.tsx26
-rw-r--r--src/view/com/post-thread/PostLikedBy.tsx24
-rw-r--r--src/view/com/post-thread/PostRepostedBy.tsx18
-rw-r--r--src/view/com/post-thread/PostThread.tsx29
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx33
-rw-r--r--src/view/com/post/Post.tsx22
-rw-r--r--src/view/com/profile/ProfileFollowers.tsx20
-rw-r--r--src/view/com/profile/ProfileFollows.tsx20
-rw-r--r--src/view/com/profile/ProfileHeader.tsx7
-rw-r--r--src/view/com/util/BottomSheetCustomBackdrop.tsx36
14 files changed, 125 insertions, 245 deletions
diff --git a/src/view/com/feed/Feed.tsx b/src/view/com/feed/Feed.tsx
index 6787b51ae..7c7fea58a 100644
--- a/src/view/com/feed/Feed.tsx
+++ b/src/view/com/feed/Feed.tsx
@@ -1,18 +1,11 @@
 import React, {useRef} from 'react'
 import {observer} from 'mobx-react-lite'
 import {Text, View, FlatList} from 'react-native'
-import {OnNavigateContent} from '../../routes/types'
 import {FeedViewModel, FeedViewItemModel} from '../../../state/models/feed-view'
 import {FeedItem} from './FeedItem'
 import {ShareModal} from '../modals/SharePost'
 
-export const Feed = observer(function Feed({
-  feed,
-  onNavigateContent,
-}: {
-  feed: FeedViewModel
-  onNavigateContent: OnNavigateContent
-}) {
+export const Feed = observer(function Feed({feed}: {feed: FeedViewModel}) {
   const shareSheetRef = useRef<{open: (_uri: string) => void}>()
 
   const onPressShare = (uri: string) => {
@@ -23,11 +16,7 @@ export const Feed = observer(function Feed({
   //   renderItem function renders components that follow React performance best practices
   //   like PureComponent, shouldComponentUpdate, etc
   const renderItem = ({item}: {item: FeedViewItemModel}) => (
-    <FeedItem
-      item={item}
-      onNavigateContent={onNavigateContent}
-      onPressShare={onPressShare}
-    />
+    <FeedItem item={item} onPressShare={onPressShare} />
   )
   const onRefresh = () => {
     feed.refresh().catch(err => console.error('Failed to refresh', err))
diff --git a/src/view/com/feed/FeedItem.tsx b/src/view/com/feed/FeedItem.tsx
index e79c15326..a63fb7a2c 100644
--- a/src/view/com/feed/FeedItem.tsx
+++ b/src/view/com/feed/FeedItem.tsx
@@ -3,39 +3,31 @@ import {observer} from 'mobx-react-lite'
 import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
 import {bsky, AdxUri} from '@adxp/mock-api'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {OnNavigateContent} from '../../routes/types'
 import {FeedViewItemModel} from '../../../state/models/feed-view'
 import {s} from '../../lib/styles'
 import {ago} from '../../lib/strings'
 import {AVIS} from '../../lib/assets'
+import {useStores} from '../../../state'
 
 export const FeedItem = observer(function FeedItem({
   item,
-  onNavigateContent,
   onPressShare,
 }: {
   item: FeedViewItemModel
-  onNavigateContent: OnNavigateContent
   onPressShare: (_uri: string) => void
 }) {
+  const store = useStores()
   const record = item.record as unknown as bsky.Post.Record
 
   const onPressOuter = () => {
     const urip = new AdxUri(item.uri)
-    onNavigateContent('PostThread', {
-      name: item.author.name,
-      recordKey: urip.recordKey,
-    })
+    store.nav.navigate(`/profile/${item.author.name}/post/${urip.recordKey}`)
   }
   const onPressAuthor = () => {
-    onNavigateContent('Profile', {
-      name: item.author.name,
-    })
+    store.nav.navigate(`/profile/${item.author.name}`)
   }
   const onPressReply = () => {
-    onNavigateContent('Composer', {
-      replyTo: item.uri,
-    })
+    store.nav.navigate('/composer')
   }
   const onPressToggleRepost = () => {
     item
@@ -137,8 +129,11 @@ export const FeedItem = observer(function FeedItem({
 
 const styles = StyleSheet.create({
   outer: {
-    borderTopWidth: 1,
-    borderTopColor: '#e8e8e8',
+    // borderWidth: 1,
+    // borderColor: '#e8e8e8',
+    borderRadius: 10,
+    margin: 2,
+    marginBottom: 0,
     backgroundColor: '#fff',
     padding: 10,
   },
@@ -175,6 +170,7 @@ const styles = StyleSheet.create({
   },
   postText: {
     paddingBottom: 5,
+    fontFamily: 'Helvetica Neue',
   },
   ctrls: {
     flexDirection: 'row',
diff --git a/src/view/com/modals/SharePost.native.tsx b/src/view/com/modals/SharePost.native.tsx
index 0e99bd4d1..6fc1d1adf 100644
--- a/src/view/com/modals/SharePost.native.tsx
+++ b/src/view/com/modals/SharePost.native.tsx
@@ -1,27 +1,10 @@
-import React, {
-  forwardRef,
-  useState,
-  useMemo,
-  useImperativeHandle,
-  useRef,
-} from 'react'
-import {
-  Button,
-  StyleSheet,
-  Text,
-  TouchableOpacity,
-  TouchableWithoutFeedback,
-  View,
-} from 'react-native'
-import BottomSheet, {BottomSheetBackdropProps} from '@gorhom/bottom-sheet'
-import Animated, {
-  Extrapolate,
-  interpolate,
-  useAnimatedStyle,
-} from 'react-native-reanimated'
+import React, {forwardRef, useState, useImperativeHandle, useRef} from 'react'
+import {Button, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
+import BottomSheet from '@gorhom/bottom-sheet'
 import Toast from '../util/Toast'
 import Clipboard from '@react-native-clipboard/clipboard'
 import {s} from '../../lib/styles'
+import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
 
 export const ShareModal = forwardRef(function ShareModal({}: {}, ref) {
   const [isOpen, setIsOpen] = useState<boolean>(false)
@@ -33,14 +16,13 @@ export const ShareModal = forwardRef(function ShareModal({}: {}, ref) {
       console.log('sharing', uri)
       setUri(uri)
       setIsOpen(true)
+      bottomSheetRef.current?.expand()
     },
   }))
 
   const onPressCopy = () => {
     Clipboard.setString(uri)
     console.log('showing')
-    console.log(Toast)
-    console.log(Toast.show)
     Toast.show('Link copied', {
       position: Toast.positions.TOP,
     })
@@ -55,50 +37,25 @@ export const ShareModal = forwardRef(function ShareModal({}: {}, ref) {
     bottomSheetRef.current?.close()
   }
 
-  const CustomBackdrop = ({animatedIndex, style}: BottomSheetBackdropProps) => {
-    // animated variables
-    const opacity = useAnimatedStyle(() => ({
-      opacity: interpolate(
-        animatedIndex.value, // current snap index
-        [-1, 0], // input range
-        [0, 0.5], // output range
-        Extrapolate.CLAMP,
-      ),
-    }))
-
-    const containerStyle = useMemo(
-      () => [style, {backgroundColor: '#000'}, opacity],
-      [style, opacity],
-    )
-
-    return (
-      <TouchableWithoutFeedback onPress={onClose}>
-        <Animated.View style={containerStyle} />
-      </TouchableWithoutFeedback>
-    )
-  }
   return (
-    <>
-      {isOpen && (
-        <BottomSheet
-          ref={bottomSheetRef}
-          snapPoints={['50%']}
-          enablePanDownToClose
-          backdropComponent={CustomBackdrop}
-          onChange={onShareBottomSheetChange}>
-          <View>
-            <Text style={[s.textCenter, s.bold, s.mb10]}>Share this post</Text>
-            <Text style={[s.textCenter, s.mb10]}>{uri}</Text>
-            <Button title="Copy to clipboard" onPress={onPressCopy} />
-            <View style={s.p10}>
-              <TouchableOpacity onPress={onClose} style={styles.closeBtn}>
-                <Text style={s.textCenter}>Close</Text>
-              </TouchableOpacity>
-            </View>
-          </View>
-        </BottomSheet>
-      )}
-    </>
+    <BottomSheet
+      ref={bottomSheetRef}
+      index={-1}
+      snapPoints={['50%']}
+      enablePanDownToClose
+      backdropComponent={isOpen ? createCustomBackdrop(onClose) : undefined}
+      onChange={onShareBottomSheetChange}>
+      <View>
+        <Text style={[s.textCenter, s.bold, s.mb10]}>Share this post</Text>
+        <Text style={[s.textCenter, s.mb10]}>{uri}</Text>
+        <Button title="Copy to clipboard" onPress={onPressCopy} />
+        <View style={s.p10}>
+          <TouchableOpacity onPress={onClose} style={styles.closeBtn}>
+            <Text style={s.textCenter}>Close</Text>
+          </TouchableOpacity>
+        </View>
+      </View>
+    </BottomSheet>
   )
 })
 
diff --git a/src/view/com/notifications/Feed.tsx b/src/view/com/notifications/Feed.tsx
index 7c95003c7..493412e7b 100644
--- a/src/view/com/notifications/Feed.tsx
+++ b/src/view/com/notifications/Feed.tsx
@@ -1,7 +1,6 @@
 import React from 'react'
 import {observer} from 'mobx-react-lite'
 import {Text, View, FlatList} from 'react-native'
-import {OnNavigateContent} from '../../routes/types'
 import {
   NotificationsViewModel,
   NotificationsViewItemModel,
@@ -10,17 +9,15 @@ import {FeedItem} from './FeedItem'
 
 export const Feed = observer(function Feed({
   view,
-  onNavigateContent,
 }: {
   view: NotificationsViewModel
-  onNavigateContent: OnNavigateContent
 }) {
   // TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
   //   VirtualizedList: You have a large list that is slow to update - make sure your
   //   renderItem function renders components that follow React performance best practices
   //   like PureComponent, shouldComponentUpdate, etc
   const renderItem = ({item}: {item: NotificationsViewItemModel}) => (
-    <FeedItem item={item} onNavigateContent={onNavigateContent} />
+    <FeedItem item={item} />
   )
   const onRefresh = () => {
     view.refresh().catch(err => console.error('Failed to refresh', err))
diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx
index 1e0e47811..00bf6f48a 100644
--- a/src/view/com/notifications/FeedItem.tsx
+++ b/src/view/com/notifications/FeedItem.tsx
@@ -3,44 +3,34 @@ import {observer} from 'mobx-react-lite'
 import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
 import {AdxUri} from '@adxp/mock-api'
 import {FontAwesomeIcon, Props} from '@fortawesome/react-native-fontawesome'
-import {OnNavigateContent} from '../../routes/types'
 import {NotificationsViewItemModel} from '../../../state/models/notifications-view'
 import {s} from '../../lib/styles'
 import {ago} from '../../lib/strings'
 import {AVIS} from '../../lib/assets'
 import {PostText} from '../post/PostText'
 import {Post} from '../post/Post'
+import {useStores} from '../../../state'
 
 export const FeedItem = observer(function FeedItem({
   item,
-  onNavigateContent,
 }: {
   item: NotificationsViewItemModel
-  onNavigateContent: OnNavigateContent
 }) {
+  const store = useStores()
+
   const onPressOuter = () => {
     if (item.isLike || item.isRepost) {
       const urip = new AdxUri(item.subjectUri)
-      onNavigateContent('PostThread', {
-        name: urip.host,
-        recordKey: urip.recordKey,
-      })
+      store.nav.navigate(`/profile/${urip.host}/post/${urip.recordKey}`)
     } else if (item.isFollow) {
-      onNavigateContent('Profile', {
-        name: item.author.name,
-      })
+      store.nav.navigate(`/profile/${item.author.name}`)
     } else if (item.isReply) {
       const urip = new AdxUri(item.uri)
-      onNavigateContent('PostThread', {
-        name: urip.host,
-        recordKey: urip.recordKey,
-      })
+      store.nav.navigate(`/profile/${urip.host}/post/${urip.recordKey}`)
     }
   }
   const onPressAuthor = () => {
-    onNavigateContent('Profile', {
-      name: item.author.name,
-    })
+    store.nav.navigate(`/profile/${item.author.name}`)
   }
 
   let action = ''
@@ -92,7 +82,7 @@ export const FeedItem = observer(function FeedItem({
       </View>
       {item.isReply ? (
         <View style={s.pt5}>
-          <Post uri={item.uri} onNavigateContent={onNavigateContent} />
+          <Post uri={item.uri} />
         </View>
       ) : (
         <></>
diff --git a/src/view/com/post-thread/PostLikedBy.tsx b/src/view/com/post-thread/PostLikedBy.tsx
index 678e069f6..9b5810b3b 100644
--- a/src/view/com/post-thread/PostLikedBy.tsx
+++ b/src/view/com/post-thread/PostLikedBy.tsx
@@ -9,7 +9,6 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {OnNavigateContent} from '../../routes/types'
 import {
   LikedByViewModel,
   LikedByViewItemModel,
@@ -18,13 +17,7 @@ import {useStores} from '../../../state'
 import {s} from '../../lib/styles'
 import {AVIS} from '../../lib/assets'
 
-export const PostLikedBy = observer(function PostLikedBy({
-  uri,
-  onNavigateContent,
-}: {
-  uri: string
-  onNavigateContent: OnNavigateContent
-}) {
+export const PostLikedBy = observer(function PostLikedBy({uri}: {uri: string}) {
   const store = useStores()
   const [view, setView] = useState<LikedByViewModel | undefined>()
 
@@ -66,7 +59,7 @@ export const PostLikedBy = observer(function PostLikedBy({
   // loaded
   // =
   const renderItem = ({item}: {item: LikedByViewItemModel}) => (
-    <LikedByItem item={item} onNavigateContent={onNavigateContent} />
+    <LikedByItem item={item} />
   )
   return (
     <View>
@@ -79,17 +72,10 @@ export const PostLikedBy = observer(function PostLikedBy({
   )
 })
 
-const LikedByItem = ({
-  item,
-  onNavigateContent,
-}: {
-  item: LikedByViewItemModel
-  onNavigateContent: OnNavigateContent
-}) => {
+const LikedByItem = ({item}: {item: LikedByViewItemModel}) => {
+  const store = useStores()
   const onPressOuter = () => {
-    onNavigateContent('Profile', {
-      name: item.name,
-    })
+    store.nav.navigate(`/profile/${item.name}`)
   }
   return (
     <TouchableOpacity style={styles.outer} onPress={onPressOuter}>
diff --git a/src/view/com/post-thread/PostRepostedBy.tsx b/src/view/com/post-thread/PostRepostedBy.tsx
index 98c24ef86..967e03940 100644
--- a/src/view/com/post-thread/PostRepostedBy.tsx
+++ b/src/view/com/post-thread/PostRepostedBy.tsx
@@ -9,7 +9,6 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {OnNavigateContent} from '../../routes/types'
 import {
   RepostedByViewModel,
   RepostedByViewItemModel,
@@ -20,10 +19,8 @@ import {AVIS} from '../../lib/assets'
 
 export const PostRepostedBy = observer(function PostRepostedBy({
   uri,
-  onNavigateContent,
 }: {
   uri: string
-  onNavigateContent: OnNavigateContent
 }) {
   const store = useStores()
   const [view, setView] = useState<RepostedByViewModel | undefined>()
@@ -68,7 +65,7 @@ export const PostRepostedBy = observer(function PostRepostedBy({
   // loaded
   // =
   const renderItem = ({item}: {item: RepostedByViewItemModel}) => (
-    <RepostedByItem item={item} onNavigateContent={onNavigateContent} />
+    <RepostedByItem item={item} />
   )
   return (
     <View>
@@ -81,17 +78,10 @@ export const PostRepostedBy = observer(function PostRepostedBy({
   )
 })
 
-const RepostedByItem = ({
-  item,
-  onNavigateContent,
-}: {
-  item: RepostedByViewItemModel
-  onNavigateContent: OnNavigateContent
-}) => {
+const RepostedByItem = ({item}: {item: RepostedByViewItemModel}) => {
+  const store = useStores()
   const onPressOuter = () => {
-    onNavigateContent('Profile', {
-      name: item.name,
-    })
+    store.nav.navigate(`/profile/${item.name}`)
   }
   return (
     <TouchableOpacity style={styles.outer} onPress={onPressOuter}>
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index 6191875c7..f7044b741 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -1,8 +1,6 @@
 import React, {useState, useEffect, useRef} from 'react'
 import {observer} from 'mobx-react-lite'
 import {ActivityIndicator, FlatList, Text, View} from 'react-native'
-import {useFocusEffect} from '@react-navigation/native'
-import {OnNavigateContent} from '../../routes/types'
 import {
   PostThreadViewModel,
   PostThreadViewPostModel,
@@ -14,13 +12,7 @@ import {s} from '../../lib/styles'
 
 const UPDATE_DELAY = 2e3 // wait 2s before refetching the thread for updates
 
-export const PostThread = observer(function PostThread({
-  uri,
-  onNavigateContent,
-}: {
-  uri: string
-  onNavigateContent: OnNavigateContent
-}) {
+export const PostThread = observer(function PostThread({uri}: {uri: string}) {
   const store = useStores()
   const [view, setView] = useState<PostThreadViewModel | undefined>()
   const [lastUpdate, setLastUpdate] = useState<number>(Date.now())
@@ -37,12 +29,13 @@ export const PostThread = observer(function PostThread({
     newView.setup().catch(err => console.error('Failed to fetch thread', err))
   }, [uri, view?.params.uri, store])
 
-  useFocusEffect(() => {
-    if (Date.now() - lastUpdate > UPDATE_DELAY) {
-      view?.update()
-      setLastUpdate(Date.now())
-    }
-  })
+  // TODO
+  // useFocusEffect(() => {
+  //   if (Date.now() - lastUpdate > UPDATE_DELAY) {
+  //     view?.update()
+  //     setLastUpdate(Date.now())
+  //   }
+  // })
 
   const onPressShare = (uri: string) => {
     shareSheetRef.current?.open(uri)
@@ -79,11 +72,7 @@ export const PostThread = observer(function PostThread({
   // =
   const posts = view.thread ? Array.from(flattenThread(view.thread)) : []
   const renderItem = ({item}: {item: PostThreadViewPostModel}) => (
-    <PostThreadItem
-      item={item}
-      onNavigateContent={onNavigateContent}
-      onPressShare={onPressShare}
-    />
+    <PostThreadItem item={item} onPressShare={onPressShare} />
   )
   return (
     <View style={s.h100pct}>
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 981aab092..5430c8ef5 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -3,11 +3,11 @@ import {observer} from 'mobx-react-lite'
 import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
 import {bsky, AdxUri} from '@adxp/mock-api'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {OnNavigateContent} from '../../routes/types'
 import {PostThreadViewPostModel} from '../../../state/models/post-thread-view'
 import {s} from '../../lib/styles'
 import {ago, pluralize} from '../../lib/strings'
 import {AVIS} from '../../lib/assets'
+import {useStores} from '../../../state'
 
 function iter<T>(n: number, fn: (_i: number) => T): Array<T> {
   const arr: T[] = []
@@ -19,46 +19,36 @@ function iter<T>(n: number, fn: (_i: number) => T): Array<T> {
 
 export const PostThreadItem = observer(function PostThreadItem({
   item,
-  onNavigateContent,
   onPressShare,
 }: {
   item: PostThreadViewPostModel
-  onNavigateContent: OnNavigateContent
   onPressShare: (_uri: string) => void
 }) {
+  const store = useStores()
   const record = item.record as unknown as bsky.Post.Record
   const hasEngagement = item.likeCount || item.repostCount
 
   const onPressOuter = () => {
     const urip = new AdxUri(item.uri)
-    onNavigateContent('PostThread', {
-      name: item.author.name,
-      recordKey: urip.recordKey,
-    })
+    store.nav.navigate(`/profile/${item.author.name}/post/${urip.recordKey}`)
   }
   const onPressAuthor = () => {
-    onNavigateContent('Profile', {
-      name: item.author.name,
-    })
+    store.nav.navigate(`/profile/${item.author.name}`)
   }
   const onPressLikes = () => {
     const urip = new AdxUri(item.uri)
-    onNavigateContent('PostLikedBy', {
-      name: item.author.name,
-      recordKey: urip.recordKey,
-    })
+    store.nav.navigate(
+      `/profile/${item.author.name}/post/${urip.recordKey}/liked-by`,
+    )
   }
   const onPressReposts = () => {
     const urip = new AdxUri(item.uri)
-    onNavigateContent('PostRepostedBy', {
-      name: item.author.name,
-      recordKey: urip.recordKey,
-    })
+    store.nav.navigate(
+      `/profile/${item.author.name}/post/${urip.recordKey}/reposted-by`,
+    )
   }
   const onPressReply = () => {
-    onNavigateContent('Composer', {
-      replyTo: item.uri,
-    })
+    store.nav.navigate(`/composer?replyTo=${item.uri}`)
   }
   const onPressToggleRepost = () => {
     item
@@ -227,6 +217,7 @@ const styles = StyleSheet.create({
   },
   postText: {
     paddingBottom: 5,
+    fontFamily: 'Helvetica Neue',
   },
   expandedInfo: {
     flexDirection: 'row',
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index 3cfb6a1a1..3369db518 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -10,20 +10,13 @@ import {
   View,
 } from 'react-native'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {OnNavigateContent} from '../../routes/types'
 import {PostThreadViewModel} from '../../../state/models/post-thread-view'
 import {useStores} from '../../../state'
 import {s} from '../../lib/styles'
 import {ago} from '../../lib/strings'
 import {AVIS} from '../../lib/assets'
 
-export const Post = observer(function Post({
-  uri,
-  onNavigateContent,
-}: {
-  uri: string
-  onNavigateContent: OnNavigateContent
-}) {
+export const Post = observer(function Post({uri}: {uri: string}) {
   const store = useStores()
   const [view, setView] = useState<PostThreadViewModel | undefined>()
 
@@ -63,20 +56,13 @@ export const Post = observer(function Post({
 
   const onPressOuter = () => {
     const urip = new AdxUri(item.uri)
-    onNavigateContent('PostThread', {
-      name: item.author.name,
-      recordKey: urip.recordKey,
-    })
+    store.nav.navigate(`/profile/${item.author.name}/post/${urip.recordKey}`)
   }
   const onPressAuthor = () => {
-    onNavigateContent('Profile', {
-      name: item.author.name,
-    })
+    store.nav.navigate(`/profile/${item.author.name}`)
   }
   const onPressReply = () => {
-    onNavigateContent('Composer', {
-      replyTo: item.uri,
-    })
+    store.nav.navigate(`/composer?replyTo=${item.uri}`)
   }
   const onPressToggleRepost = () => {
     item
diff --git a/src/view/com/profile/ProfileFollowers.tsx b/src/view/com/profile/ProfileFollowers.tsx
index 06cc0c14d..33d0c8d55 100644
--- a/src/view/com/profile/ProfileFollowers.tsx
+++ b/src/view/com/profile/ProfileFollowers.tsx
@@ -9,7 +9,6 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {OnNavigateContent} from '../../routes/types'
 import {
   UserFollowersViewModel,
   FollowerItem,
@@ -20,10 +19,8 @@ import {AVIS} from '../../lib/assets'
 
 export const ProfileFollowers = observer(function ProfileFollowers({
   name,
-  onNavigateContent,
 }: {
   name: string
-  onNavigateContent: OnNavigateContent
 }) {
   const store = useStores()
   const [view, setView] = useState<UserFollowersViewModel | undefined>()
@@ -67,9 +64,7 @@ export const ProfileFollowers = observer(function ProfileFollowers({
 
   // loaded
   // =
-  const renderItem = ({item}: {item: FollowerItem}) => (
-    <User item={item} onNavigateContent={onNavigateContent} />
-  )
+  const renderItem = ({item}: {item: FollowerItem}) => <User item={item} />
   return (
     <View>
       <FlatList
@@ -81,17 +76,10 @@ export const ProfileFollowers = observer(function ProfileFollowers({
   )
 })
 
-const User = ({
-  item,
-  onNavigateContent,
-}: {
-  item: FollowerItem
-  onNavigateContent: OnNavigateContent
-}) => {
+const User = ({item}: {item: FollowerItem}) => {
+  const store = useStores()
   const onPressOuter = () => {
-    onNavigateContent('Profile', {
-      name: item.name,
-    })
+    store.nav.navigate(`/profile/${item.name}`)
   }
   return (
     <TouchableOpacity style={styles.outer} onPress={onPressOuter}>
diff --git a/src/view/com/profile/ProfileFollows.tsx b/src/view/com/profile/ProfileFollows.tsx
index bb5859852..62ed7f1c3 100644
--- a/src/view/com/profile/ProfileFollows.tsx
+++ b/src/view/com/profile/ProfileFollows.tsx
@@ -9,7 +9,6 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {OnNavigateContent} from '../../routes/types'
 import {
   UserFollowsViewModel,
   FollowItem,
@@ -20,10 +19,8 @@ import {AVIS} from '../../lib/assets'
 
 export const ProfileFollows = observer(function ProfileFollows({
   name,
-  onNavigateContent,
 }: {
   name: string
-  onNavigateContent: OnNavigateContent
 }) {
   const store = useStores()
   const [view, setView] = useState<UserFollowsViewModel | undefined>()
@@ -67,9 +64,7 @@ export const ProfileFollows = observer(function ProfileFollows({
 
   // loaded
   // =
-  const renderItem = ({item}: {item: FollowItem}) => (
-    <User item={item} onNavigateContent={onNavigateContent} />
-  )
+  const renderItem = ({item}: {item: FollowItem}) => <User item={item} />
   return (
     <View>
       <FlatList
@@ -81,17 +76,10 @@ export const ProfileFollows = observer(function ProfileFollows({
   )
 })
 
-const User = ({
-  item,
-  onNavigateContent,
-}: {
-  item: FollowItem
-  onNavigateContent: OnNavigateContent
-}) => {
+const User = ({item}: {item: FollowItem}) => {
+  const store = useStores()
   const onPressOuter = () => {
-    onNavigateContent('Profile', {
-      name: item.name,
-    })
+    store.nav.navigate(`/profile/${item.name}`)
   }
   return (
     <TouchableOpacity style={styles.outer} onPress={onPressOuter}>
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index 6a6d04140..0769a0077 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -9,7 +9,6 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {OnNavigateContent} from '../../routes/types'
 import {ProfileViewModel} from '../../../state/models/profile-view'
 import {useStores} from '../../../state'
 import {pluralize} from '../../lib/strings'
@@ -19,10 +18,8 @@ import Toast from '../util/Toast'
 
 export const ProfileHeader = observer(function ProfileHeader({
   user,
-  onNavigateContent,
 }: {
   user: string
-  onNavigateContent: OnNavigateContent
 }) {
   const store = useStores()
   const [view, setView] = useState<ProfileViewModel | undefined>()
@@ -55,10 +52,10 @@ export const ProfileHeader = observer(function ProfileHeader({
     )
   }
   const onPressFollowers = () => {
-    onNavigateContent('ProfileFollowers', {name: user})
+    store.nav.navigate(`/profile/${user}/followers`)
   }
   const onPressFollows = () => {
-    onNavigateContent('ProfileFollows', {name: user})
+    store.nav.navigate(`/profile/${user}/follows`)
   }
 
   // loading
diff --git a/src/view/com/util/BottomSheetCustomBackdrop.tsx b/src/view/com/util/BottomSheetCustomBackdrop.tsx
new file mode 100644
index 000000000..e175b33a5
--- /dev/null
+++ b/src/view/com/util/BottomSheetCustomBackdrop.tsx
@@ -0,0 +1,36 @@
+import React, {useMemo} from 'react'
+import {GestureResponderEvent, TouchableWithoutFeedback} from 'react-native'
+import {BottomSheetBackdropProps} from '@gorhom/bottom-sheet'
+import Animated, {
+  Extrapolate,
+  interpolate,
+  useAnimatedStyle,
+} from 'react-native-reanimated'
+
+export function createCustomBackdrop(
+  onClose?: ((event: GestureResponderEvent) => void) | undefined,
+): React.FC<BottomSheetBackdropProps> {
+  const CustomBackdrop = ({animatedIndex, style}: BottomSheetBackdropProps) => {
+    // animated variables
+    const opacity = useAnimatedStyle(() => ({
+      opacity: interpolate(
+        animatedIndex.value, // current snap index
+        [-1, 0], // input range
+        [0, 0.5], // output range
+        Extrapolate.CLAMP,
+      ),
+    }))
+
+    const containerStyle = useMemo(
+      () => [style, {backgroundColor: '#000'}, opacity],
+      [style, opacity],
+    )
+
+    return (
+      <TouchableWithoutFeedback onPress={onClose}>
+        <Animated.View style={containerStyle} />
+      </TouchableWithoutFeedback>
+    )
+  }
+  return CustomBackdrop
+}