about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHailey <me@haileyok.com>2024-05-30 21:32:54 -0700
committerGitHub <noreply@github.com>2024-05-31 05:32:54 +0100
commit89c9fd3be16ea96182842544d76ce019cb8e1403 (patch)
tree746f4319830142ba1bdac47fef8608f05e744c56
parent8569e2e389e756ec2df6c547e894689500d1c111 (diff)
downloadvoidsky-89c9fd3be16ea96182842544d76ce019cb8e1403.tar.zst
Change many border widths from `1` to `hairlineWidth` (#4294)
* feed items

* update some more

* moar

* profile card

* composer and notifications

* settings screen

* remove border from first item in feeds

* remove border from first item in feeds

* more removal of top border

* fix flatlist rendering

* oops

* scroll to top fab

* a.border

* centeredview/list

* placeholder

* web sidebar

* search posts

* feeds list

* user lists

* list header

* account list width 1

* hide top border feedgens

* same for lists

* fix tab bar web desktop

* wait...

* show the border on desktop web

* fix lists

* fix lists

* round
-rw-r--r--src/alf/atoms.ts13
-rw-r--r--src/components/AccountList.tsx4
-rw-r--r--src/view/com/composer/Composer.tsx5
-rw-r--r--src/view/com/composer/Prompt.tsx16
-rw-r--r--src/view/com/feeds/FeedSourceCard.tsx16
-rw-r--r--src/view/com/feeds/ProfileFeedgens.tsx4
-rw-r--r--src/view/com/lists/ListCard.tsx22
-rw-r--r--src/view/com/lists/MyLists.tsx18
-rw-r--r--src/view/com/lists/ProfileLists.tsx8
-rw-r--r--src/view/com/notifications/Feed.tsx33
-rw-r--r--src/view/com/notifications/FeedItem.tsx5
-rw-r--r--src/view/com/pager/PagerWithHeader.tsx4
-rw-r--r--src/view/com/pager/TabBar.tsx3
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx11
-rw-r--r--src/view/com/post/Post.tsx3
-rw-r--r--src/view/com/posts/Feed.tsx21
-rw-r--r--src/view/com/posts/FeedItem.tsx11
-rw-r--r--src/view/com/posts/FeedSlice.tsx10
-rw-r--r--src/view/com/profile/ProfileCard.tsx3
-rw-r--r--src/view/com/profile/ProfileSubpageHeader.tsx28
-rw-r--r--src/view/com/util/LoadingPlaceholder.tsx3
-rw-r--r--src/view/com/util/ViewHeader.tsx5
-rw-r--r--src/view/com/util/Views.web.tsx9
-rw-r--r--src/view/com/util/load-latest/LoadLatestBtn.tsx3
-rw-r--r--src/view/com/util/post-embeds/QuoteEmbed.tsx5
-rw-r--r--src/view/com/util/post-embeds/index.tsx3
-rw-r--r--src/view/screens/Feeds.tsx5
-rw-r--r--src/view/screens/Lists.tsx31
-rw-r--r--src/view/screens/Notifications.tsx51
-rw-r--r--src/view/screens/ProfileList.tsx5
-rw-r--r--src/view/screens/Settings/index.tsx3
-rw-r--r--src/view/shell/bottom-bar/BottomBarStyles.tsx3
-rw-r--r--src/view/shell/desktop/RightNav.tsx5
33 files changed, 226 insertions, 143 deletions
diff --git a/src/alf/atoms.ts b/src/alf/atoms.ts
index eb130f3ae..1ccb0460c 100644
--- a/src/alf/atoms.ts
+++ b/src/alf/atoms.ts
@@ -1,7 +1,8 @@
-import {Platform} from 'react-native'
+import {Platform, StyleSheet} from 'react-native'
 
 import * as tokens from '#/alf/tokens'
 import {native, web} from '#/alf/util/platform'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export const atoms = {
   /*
@@ -277,19 +278,19 @@ export const atoms = {
     borderWidth: 0,
   },
   border: {
-    borderWidth: 1,
+    borderWidth: hairlineWidth,
   },
   border_t: {
-    borderTopWidth: 1,
+    borderTopWidth: hairlineWidth,
   },
   border_b: {
-    borderBottomWidth: 1,
+    borderBottomWidth: hairlineWidth,
   },
   border_l: {
-    borderLeftWidth: 1,
+    borderLeftWidth: hairlineWidth,
   },
   border_r: {
-    borderRightWidth: 1,
+    borderRightWidth: hairlineWidth,
   },
 
   /*
diff --git a/src/components/AccountList.tsx b/src/components/AccountList.tsx
index 7d696801e..883c06c14 100644
--- a/src/components/AccountList.tsx
+++ b/src/components/AccountList.tsx
@@ -37,7 +37,7 @@ export function AccountList({
       style={[
         a.rounded_md,
         a.overflow_hidden,
-        a.border,
+        {borderWidth: 1},
         t.atoms.border_contrast_low,
       ]}>
       {accounts.map(account => (
@@ -48,7 +48,7 @@ export function AccountList({
             isCurrentAccount={account.did === currentAccount?.did}
             isPendingAccount={account.did === pendingDid}
           />
-          <View style={[a.border_b, t.atoms.border_contrast_low]} />
+          <View style={[{borderBottomWidth: 1}, t.atoms.border_contrast_low]} />
         </React.Fragment>
       ))}
       <Button
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index 2618c51a3..c8bb8d726 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -90,6 +90,7 @@ import {SuggestedLanguage} from './select-language/SuggestedLanguage'
 import {TextInput, TextInputRef} from './text-input/TextInput'
 import {ThreadgateBtn} from './threadgate/ThreadgateBtn'
 import {useExternalLinkFetch} from './useExternalLinkFetch'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 type CancelRef = {
   onPressCancel: () => void
@@ -657,7 +658,7 @@ const styles = StyleSheet.create({
     marginBottom: 6,
   },
   errorIcon: {
-    borderWidth: 1,
+    borderWidth: hairlineWidth,
     borderColor: colors.red4,
     color: colors.red4,
     borderRadius: 30,
@@ -692,6 +693,6 @@ const styles = StyleSheet.create({
     paddingLeft: 15,
     paddingRight: 20,
     alignItems: 'center',
-    borderTopWidth: 1,
+    borderTopWidth: hairlineWidth,
   },
 })
diff --git a/src/view/com/composer/Prompt.tsx b/src/view/com/composer/Prompt.tsx
index 16d1b6fb9..54defb101 100644
--- a/src/view/com/composer/Prompt.tsx
+++ b/src/view/com/composer/Prompt.tsx
@@ -1,13 +1,15 @@
 import React from 'react'
 import {StyleSheet, TouchableOpacity} from 'react-native'
-import {UserAvatar} from '../util/UserAvatar'
-import {Text} from '../util/text/Text'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {Trans, msg} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
-import {useSession} from '#/state/session'
+
 import {useProfileQuery} from '#/state/queries/profile'
+import {useSession} from '#/state/session'
+import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {Text} from '../util/text/Text'
+import {UserAvatar} from '../util/UserAvatar'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
   const {currentAccount} = useSession()
@@ -47,7 +49,7 @@ const styles = StyleSheet.create({
     paddingBottom: 10,
     flexDirection: 'row',
     alignItems: 'center',
-    borderTopWidth: 1,
+    borderTopWidth: hairlineWidth,
   },
   labelMobile: {
     paddingLeft: 12,
diff --git a/src/view/com/feeds/FeedSourceCard.tsx b/src/view/com/feeds/FeedSourceCard.tsx
index b89a3946e..589f674b4 100644
--- a/src/view/com/feeds/FeedSourceCard.tsx
+++ b/src/view/com/feeds/FeedSourceCard.tsx
@@ -25,6 +25,7 @@ import * as Prompt from '#/components/Prompt'
 import {RichText} from '#/components/RichText'
 import {Text} from '../util/text/Text'
 import {UserAvatar} from '../util/UserAvatar'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export function FeedSourceCard({
   feedUri,
@@ -34,6 +35,7 @@ export function FeedSourceCard({
   showLikes = false,
   pinOnSave = false,
   showMinimalPlaceholder,
+  hideTopBorder,
 }: {
   feedUri: string
   style?: StyleProp<ViewStyle>
@@ -42,6 +44,7 @@ export function FeedSourceCard({
   showLikes?: boolean
   pinOnSave?: boolean
   showMinimalPlaceholder?: boolean
+  hideTopBorder?: boolean
 }) {
   const {data: preferences} = usePreferencesQuery()
   const {data: feed} = useFeedSourceInfoQuery({uri: feedUri})
@@ -57,6 +60,7 @@ export function FeedSourceCard({
       showLikes={showLikes}
       pinOnSave={pinOnSave}
       showMinimalPlaceholder={showMinimalPlaceholder}
+      hideTopBorder={hideTopBorder}
     />
   )
 }
@@ -71,6 +75,7 @@ export function FeedSourceCardLoaded({
   showLikes = false,
   pinOnSave = false,
   showMinimalPlaceholder,
+  hideTopBorder,
 }: {
   feedUri: string
   feed?: FeedSourceInfo
@@ -81,6 +86,7 @@ export function FeedSourceCardLoaded({
   showLikes?: boolean
   pinOnSave?: boolean
   showMinimalPlaceholder?: boolean
+  hideTopBorder?: boolean
 }) {
   const t = useTheme()
   const pal = usePalette('default')
@@ -149,7 +155,7 @@ export function FeedSourceCardLoaded({
         style={[
           pal.border,
           {
-            borderTopWidth: showMinimalPlaceholder ? 0 : 1,
+            borderTopWidth: showMinimalPlaceholder || hideTopBorder ? 0 : 1,
             flexDirection: 'row',
             alignItems: 'center',
             flex: 1,
@@ -191,7 +197,12 @@ export function FeedSourceCardLoaded({
       <Pressable
         testID={`feed-${feed.displayName}`}
         accessibilityRole="button"
-        style={[styles.container, pal.border, style]}
+        style={[
+          styles.container,
+          pal.border,
+          style,
+          {borderTopWidth: hideTopBorder ? 0 : hairlineWidth},
+        ]}
         onPress={() => {
           if (feed.type === 'feed') {
             navigation.push('ProfileFeed', {
@@ -295,7 +306,6 @@ const styles = StyleSheet.create({
     paddingVertical: 20,
     flexDirection: 'column',
     flex: 1,
-    borderTopWidth: 1,
     gap: 14,
   },
   headerContainer: {
diff --git a/src/view/com/feeds/ProfileFeedgens.tsx b/src/view/com/feeds/ProfileFeedgens.tsx
index a006b11c0..670cd3e11 100644
--- a/src/view/com/feeds/ProfileFeedgens.tsx
+++ b/src/view/com/feeds/ProfileFeedgens.tsx
@@ -1,6 +1,7 @@
 import React from 'react'
 import {
   findNodeHandle,
+  ListRenderItemInfo,
   StyleProp,
   StyleSheet,
   View,
@@ -134,7 +135,7 @@ export const ProfileFeedgens = React.forwardRef<
   // =
 
   const renderItemInner = React.useCallback(
-    ({item}: {item: any}) => {
+    ({item, index}: ListRenderItemInfo<any>) => {
       if (item === EMPTY) {
         return (
           <View
@@ -169,6 +170,7 @@ export const ProfileFeedgens = React.forwardRef<
             preferences={preferences}
             style={styles.item}
             showLikes
+            hideTopBorder={index === 0}
           />
         )
       }
diff --git a/src/view/com/lists/ListCard.tsx b/src/view/com/lists/ListCard.tsx
index 19842eb54..3adf5c09d 100644
--- a/src/view/com/lists/ListCard.tsx
+++ b/src/view/com/lists/ListCard.tsx
@@ -1,18 +1,20 @@
 import React from 'react'
 import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
-import {AtUri, AppBskyGraphDefs, RichText} from '@atproto/api'
-import {Link} from '../util/Link'
-import {Text} from '../util/text/Text'
-import {RichText as RichTextCom} from '#/components/RichText'
-import {UserAvatar} from '../util/UserAvatar'
-import {s} from 'lib/styles'
-import {usePalette} from 'lib/hooks/usePalette'
+import {AppBskyGraphDefs, AtUri, RichText} from '@atproto/api'
+import {Trans} from '@lingui/macro'
+
 import {useSession} from '#/state/session'
+import {usePalette} from 'lib/hooks/usePalette'
+import {makeProfileLink} from 'lib/routes/links'
 import {sanitizeDisplayName} from 'lib/strings/display-names'
 import {sanitizeHandle} from 'lib/strings/handles'
-import {makeProfileLink} from 'lib/routes/links'
-import {Trans} from '@lingui/macro'
+import {s} from 'lib/styles'
 import {atoms as a} from '#/alf'
+import {RichText as RichTextCom} from '#/components/RichText'
+import {Link} from '../util/Link'
+import {Text} from '../util/text/Text'
+import {UserAvatar} from '../util/UserAvatar'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export const ListCard = ({
   testID,
@@ -132,7 +134,7 @@ export const ListCard = ({
 
 const styles = StyleSheet.create({
   outer: {
-    borderTopWidth: 1,
+    borderTopWidth: hairlineWidth,
     paddingHorizontal: 6,
   },
   outerNoBorder: {
diff --git a/src/view/com/lists/MyLists.tsx b/src/view/com/lists/MyLists.tsx
index e9d2e4f0f..5ea95971c 100644
--- a/src/view/com/lists/MyLists.tsx
+++ b/src/view/com/lists/MyLists.tsx
@@ -9,17 +9,19 @@ import {
   ViewStyle,
 } from 'react-native'
 import {AppBskyGraphDefs as GraphDefs} from '@atproto/api'
-import {ListCard} from './ListCard'
+import {Trans} from '@lingui/macro'
+
+import {cleanError} from '#/lib/strings/errors'
+import {logger} from '#/logger'
 import {MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists'
-import {ErrorMessage} from '../util/error/ErrorMessage'
-import {Text} from '../util/text/Text'
 import {useAnalytics} from 'lib/analytics/analytics'
 import {usePalette} from 'lib/hooks/usePalette'
-import {List} from '../util/List'
 import {s} from 'lib/styles'
-import {logger} from '#/logger'
-import {Trans} from '@lingui/macro'
-import {cleanError} from '#/lib/strings/errors'
+import {ErrorMessage} from '../util/error/ErrorMessage'
+import {List} from '../util/List'
+import {Text} from '../util/text/Text'
+import {ListCard} from './ListCard'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 const LOADING = {_reactKey: '__loading__'}
 const EMPTY = {_reactKey: '__empty__'}
@@ -84,7 +86,7 @@ export function MyLists({
           <View
             key={item._reactKey}
             testID="listsEmpty"
-            style={[{padding: 18, borderTopWidth: 1}, pal.border]}>
+            style={[{padding: 18, borderTopWidth: hairlineWidth}, pal.border]}>
             <Text style={pal.textLight}>
               <Trans>You have no lists.</Trans>
             </Text>
diff --git a/src/view/com/lists/ProfileLists.tsx b/src/view/com/lists/ProfileLists.tsx
index 003d1c60e..d1ef05f12 100644
--- a/src/view/com/lists/ProfileLists.tsx
+++ b/src/view/com/lists/ProfileLists.tsx
@@ -1,6 +1,7 @@
 import React from 'react'
 import {
   findNodeHandle,
+  ListRenderItemInfo,
   StyleProp,
   StyleSheet,
   View,
@@ -138,12 +139,10 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
     // =
 
     const renderItemInner = React.useCallback(
-      ({item}: {item: any}) => {
+      ({item, index}: ListRenderItemInfo<any>) => {
         if (item === EMPTY) {
           return (
-            <View
-              testID="listsEmpty"
-              style={[{padding: 18, borderTopWidth: 1}, pal.border]}>
+            <View testID="listsEmpty" style={[{padding: 18}, pal.border]}>
               <Text style={pal.textLight}>
                 <Trans>You have no lists.</Trans>
               </Text>
@@ -173,6 +172,7 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
             list={item}
             testID={`list-${item.name}`}
             style={styles.item}
+            noBorder={index === 0}
           />
         )
       },
diff --git a/src/view/com/notifications/Feed.tsx b/src/view/com/notifications/Feed.tsx
index 15c103bed..e12b63733 100644
--- a/src/view/com/notifications/Feed.tsx
+++ b/src/view/com/notifications/Feed.tsx
@@ -1,5 +1,10 @@
 import React from 'react'
-import {ActivityIndicator, StyleSheet, View} from 'react-native'
+import {
+  ActivityIndicator,
+  ListRenderItemInfo,
+  StyleSheet,
+  View,
+} from 'react-native'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
@@ -17,6 +22,9 @@ import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
 import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
 import {CenteredView} from '../util/Views'
 import {FeedItem} from './FeedItem'
+import hairlineWidth = StyleSheet.hairlineWidth
+import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 
 const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
 const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
@@ -33,8 +41,11 @@ export function Feed({
   onScrolledDownChange: (isScrolledDown: boolean) => void
   ListHeaderComponent?: () => JSX.Element
 }) {
+  const initialNumToRender = useInitialNumToRender()
+
   const [isPTRing, setIsPTRing] = React.useState(false)
   const pal = usePalette('default')
+  const {isTabletOrMobile} = useWebMediaQueries()
 
   const {_} = useLingui()
   const moderationOpts = useModerationOpts()
@@ -97,12 +108,8 @@ export function Feed({
     fetchNextPage()
   }, [fetchNextPage])
 
-  // 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 = React.useCallback(
-    ({item}: {item: any}) => {
+    ({item, index}: ListRenderItemInfo<any>) => {
       if (item === EMPTY_FEED_ITEM) {
         return (
           <EmptyState
@@ -122,14 +129,20 @@ export function Feed({
         )
       } else if (item === LOADING_ITEM) {
         return (
-          <View style={[pal.border, {borderTopWidth: 1}]}>
+          <View style={[pal.border, {borderTopWidth: hairlineWidth}]}>
             <NotificationFeedLoadingPlaceholder />
           </View>
         )
       }
-      return <FeedItem item={item} moderationOpts={moderationOpts!} />
+      return (
+        <FeedItem
+          item={item}
+          moderationOpts={moderationOpts!}
+          hideTopBorder={index === 0 && isTabletOrMobile}
+        />
+      )
     },
-    [onPressRetryLoadMore, moderationOpts, _, pal.border],
+    [moderationOpts, isTabletOrMobile, _, onPressRetryLoadMore, pal.border],
   )
 
   const FeedFooter = React.useCallback(
@@ -170,6 +183,8 @@ export function Feed({
         contentContainerStyle={s.contentContainer}
         // @ts-ignore our .web version only -prf
         desktopFixedHeight
+        initialNumToRender={initialNumToRender}
+        windowSize={11}
       />
     </View>
   )
diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx
index c20a8e9ee..4fe557f40 100644
--- a/src/view/com/notifications/FeedItem.tsx
+++ b/src/view/com/notifications/FeedItem.tsx
@@ -47,6 +47,7 @@ import {formatCount} from '../util/numeric/format'
 import {Text} from '../util/text/Text'
 import {TimeElapsed} from '../util/TimeElapsed'
 import {PreviewableUserAvatar, UserAvatar} from '../util/UserAvatar'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 const MAX_AUTHORS = 5
 
@@ -61,9 +62,11 @@ interface Author {
 let FeedItem = ({
   item,
   moderationOpts,
+  hideTopBorder,
 }: {
   item: FeedNotification
   moderationOpts: ModerationOpts
+  hideTopBorder?: boolean
 }): React.ReactNode => {
   const queryClient = useQueryClient()
   const pal = usePalette('default')
@@ -188,6 +191,7 @@ let FeedItem = ({
               backgroundColor: pal.colors.unreadNotifBg,
               borderColor: pal.colors.unreadNotifBorder,
             },
+        {borderTopWidth: hideTopBorder ? 0 : hairlineWidth},
       ]}
       href={itemHref}
       noFeedback
@@ -480,7 +484,6 @@ const styles = StyleSheet.create({
   outer: {
     padding: 10,
     paddingRight: 15,
-    borderTopWidth: 1,
     flexDirection: 'row',
   },
   layoutIcon: {
diff --git a/src/view/com/pager/PagerWithHeader.tsx b/src/view/com/pager/PagerWithHeader.tsx
index 61e2a4096..7b1d8b78f 100644
--- a/src/view/com/pager/PagerWithHeader.tsx
+++ b/src/view/com/pager/PagerWithHeader.tsx
@@ -67,13 +67,13 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
       const height = evt.nativeEvent.layout.height
       if (height > 0) {
         // The rounding is necessary to prevent jumps on iOS
-        setTabBarHeight(Math.round(height))
+        setTabBarHeight(Math.round(height * 2) / 2)
       }
     })
     const onHeaderOnlyLayout = useNonReactiveCallback((height: number) => {
       if (height > 0) {
         // The rounding is necessary to prevent jumps on iOS
-        setHeaderOnlyHeight(Math.round(height))
+        setHeaderOnlyHeight(Math.round(height * 2) / 2)
       }
     })
 
diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx
index 5791e26a9..e81d7d44d 100644
--- a/src/view/com/pager/TabBar.tsx
+++ b/src/view/com/pager/TabBar.tsx
@@ -7,6 +7,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {PressableWithHover} from '../util/PressableWithHover'
 import {Text} from '../util/text/Text'
 import {DraggableScrollView} from './DraggableScrollView'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export interface TabBarProps {
   testID?: string
@@ -207,6 +208,6 @@ const mobileStyles = StyleSheet.create({
     left: 0,
     right: 0,
     bottom: -1,
-    borderBottomWidth: 1,
+    borderBottomWidth: hairlineWidth,
   },
 })
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 981b4e72f..096305a23 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -50,6 +50,7 @@ import {PostEmbeds} from '../util/post-embeds'
 import {PostMeta} from '../util/PostMeta'
 import {Text} from '../util/text/Text'
 import {PreviewableUserAvatar} from '../util/UserAvatar'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export function PostThreadItem({
   post,
@@ -623,7 +624,7 @@ function PostOuterWrapper({
           {
             flexDirection: 'row',
             paddingHorizontal: isMobile ? 10 : 6,
-            borderTopWidth: depth === 1 ? 1 : 0,
+            borderTopWidth: depth === 1 ? hairlineWidth : 0,
           },
         ]}>
         {Array.from(Array(depth - 1)).map((_, n: number) => (
@@ -704,7 +705,7 @@ function ExpandedPostDetails({
 
 const styles = StyleSheet.create({
   outer: {
-    borderTopWidth: 1,
+    borderTopWidth: hairlineWidth,
     paddingLeft: 8,
   },
   outerHighlighted: {
@@ -714,7 +715,7 @@ const styles = StyleSheet.create({
     paddingRight: 8,
   },
   outerHighlightedRoot: {
-    borderTopWidth: 1,
+    borderTopWidth: hairlineWidth,
     paddingTop: 16,
   },
   noTopBorder: {
@@ -766,8 +767,8 @@ const styles = StyleSheet.create({
   expandedInfo: {
     flexDirection: 'row',
     padding: 10,
-    borderTopWidth: 1,
-    borderBottomWidth: 1,
+    borderTopWidth: hairlineWidth,
+    borderBottomWidth: hairlineWidth,
     marginTop: 5,
     marginBottom: 10,
   },
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index f666e2968..a7ccf0be2 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -36,6 +36,7 @@ import {PostMeta} from '../util/PostMeta'
 import {Text} from '../util/text/Text'
 import {PreviewableUserAvatar} from '../util/UserAvatar'
 import {UserInfoText} from '../util/UserInfoText'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export function Post({
   post,
@@ -242,7 +243,7 @@ const styles = StyleSheet.create({
     paddingRight: 15,
     paddingBottom: 5,
     paddingLeft: 10,
-    borderTopWidth: 1,
+    borderTopWidth: hairlineWidth,
     // @ts-ignore web only -prf
     cursor: 'pointer',
   },
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index 12171dc3b..681670cf7 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -3,6 +3,7 @@ import {
   ActivityIndicator,
   AppState,
   Dimensions,
+  ListRenderItemInfo,
   StyleProp,
   StyleSheet,
   View,
@@ -31,6 +32,7 @@ import {
 import {useSession} from '#/state/session'
 import {useAnalytics} from 'lib/analytics/analytics'
 import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {useTheme} from 'lib/ThemeContext'
 import {List, ListRef} from '../util/List'
 import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
@@ -100,6 +102,7 @@ let Feed = ({
   const checkForNewRef = React.useRef<(() => void) | null>(null)
   const lastFetchRef = React.useRef<number>(Date.now())
   const [feedType, feedUri] = feed.split('|')
+  const {isTabletOrMobile} = useWebMediaQueries()
 
   const opts = React.useMemo(
     () => ({enabled, ignoreFilterFor}),
@@ -279,7 +282,7 @@ let Feed = ({
   // =
 
   const renderItem = React.useCallback(
-    ({item}: {item: any}) => {
+    ({item, index}: ListRenderItemInfo<any>) => {
       if (item === EMPTY_FEED_ITEM) {
         return renderEmptyState()
       } else if (item === ERROR_ITEM) {
@@ -311,17 +314,23 @@ let Feed = ({
         // -prf
         return <DiscoverFallbackHeader />
       }
-      return <FeedSlice slice={item} />
+      return (
+        <FeedSlice
+          slice={item}
+          hideTopBorder={index === 0 && isTabletOrMobile}
+        />
+      )
     },
     [
+      isTabletOrMobile,
+      renderEmptyState,
       feed,
-      feedUri,
       error,
       onPressTryAgain,
-      onPressRetryLoadMore,
-      renderEmptyState,
-      _,
       savedFeedConfig,
+      _,
+      onPressRetryLoadMore,
+      feedUri,
     ],
   )
 
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index b10ffe19f..72c8b8757 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -42,6 +42,7 @@ import {PostMeta} from '../util/PostMeta'
 import {Text} from '../util/text/Text'
 import {PreviewableUserAvatar} from '../util/UserAvatar'
 import {AviFollowButton} from './AviFollowButton'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 interface FeedItemProps {
   record: AppBskyFeedPost.Record
@@ -53,6 +54,7 @@ interface FeedItemProps {
   isThreadLastChild?: boolean
   isThreadParent?: boolean
   feedContext: string | undefined
+  hideTopBorder?: boolean
 }
 
 export function FeedItem({
@@ -66,6 +68,7 @@ export function FeedItem({
   isThreadChild,
   isThreadLastChild,
   isThreadParent,
+  hideTopBorder,
 }: FeedItemProps & {post: AppBskyFeedDefs.PostView}): React.ReactNode {
   const postShadowed = usePostShadow(post)
   const richText = useMemo(
@@ -95,6 +98,7 @@ export function FeedItem({
         isThreadChild={isThreadChild}
         isThreadLastChild={isThreadLastChild}
         isThreadParent={isThreadParent}
+        hideTopBorder={hideTopBorder}
       />
     )
   }
@@ -113,6 +117,7 @@ let FeedItemInner = ({
   isThreadChild,
   isThreadLastChild,
   isThreadParent,
+  hideTopBorder,
 }: FeedItemProps & {
   richText: RichTextAPI
   post: Shadow<AppBskyFeedDefs.PostView>
@@ -186,8 +191,8 @@ let FeedItemInner = ({
         isThreadLastChild || (!isThreadChild && !isThreadParent)
           ? 8
           : undefined,
+      borderTopWidth: hideTopBorder || isThreadChild ? 0 : hairlineWidth,
     },
-    isThreadChild ? styles.outerSmallTop : undefined,
   ]
 
   return (
@@ -445,16 +450,12 @@ function ReplyToLabel({profile}: {profile: AppBskyActorDefs.ProfileViewBasic}) {
 
 const styles = StyleSheet.create({
   outer: {
-    borderTopWidth: 1,
     paddingLeft: 10,
     paddingRight: 15,
     // @ts-ignore web only -prf
     cursor: 'pointer',
     overflow: 'hidden',
   },
-  outerSmallTop: {
-    borderTopWidth: 0,
-  },
   replyLine: {
     width: 2,
     marginLeft: 'auto',
diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx
index 6d8f038b4..aeb24e8bb 100644
--- a/src/view/com/posts/FeedSlice.tsx
+++ b/src/view/com/posts/FeedSlice.tsx
@@ -11,7 +11,13 @@ import {Link} from '../util/Link'
 import {Text} from '../util/text/Text'
 import {FeedItem} from './FeedItem'
 
-let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
+let FeedSlice = ({
+  slice,
+  hideTopBorder,
+}: {
+  slice: FeedPostSlice
+  hideTopBorder?: boolean
+}): React.ReactNode => {
   if (slice.isThread && slice.items.length > 3) {
     const last = slice.items.length - 1
     return (
@@ -27,6 +33,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
           moderation={slice.items[0].moderation}
           isThreadParent={isThreadParentAt(slice.items, 0)}
           isThreadChild={isThreadChildAt(slice.items, 0)}
+          hideTopBorder={hideTopBorder}
         />
         <FeedItem
           key={slice.items[1]._reactKey}
@@ -75,6 +82,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
           isThreadLastChild={
             isThreadChildAt(slice.items, i) && slice.items.length === i + 1
           }
+          hideTopBorder={hideTopBorder && i === 0}
         />
       ))}
     </>
diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx
index 6c8978946..2b0790002 100644
--- a/src/view/com/profile/ProfileCard.tsx
+++ b/src/view/com/profile/ProfileCard.tsx
@@ -25,6 +25,7 @@ import {Link} from '../util/Link'
 import {Text} from '../util/text/Text'
 import {PreviewableUserAvatar} from '../util/UserAvatar'
 import {FollowButton} from './FollowButton'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export function ProfileCard({
   testID,
@@ -280,7 +281,7 @@ export function ProfileCardWithFollowBtn({
 
 const styles = StyleSheet.create({
   outer: {
-    borderTopWidth: 1,
+    borderTopWidth: hairlineWidth,
     paddingHorizontal: 6,
     paddingVertical: 4,
   },
diff --git a/src/view/com/profile/ProfileSubpageHeader.tsx b/src/view/com/profile/ProfileSubpageHeader.tsx
index eaf00f3e6..549fc5151 100644
--- a/src/view/com/profile/ProfileSubpageHeader.tsx
+++ b/src/view/com/profile/ProfileSubpageHeader.tsx
@@ -1,24 +1,26 @@
 import React from 'react'
 import {Pressable, StyleSheet, View} from 'react-native'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 import {useNavigation} from '@react-navigation/native'
+
+import {emitSoftReset} from '#/state/events'
+import {ImagesLightbox, useLightboxControls} from '#/state/lightbox'
+import {useSetDrawerOpen} from '#/state/shell'
+import {BACK_HITSLOP} from 'lib/constants'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {Text} from '../util/text/Text'
-import {TextLink} from '../util/Link'
-import {UserAvatar, UserAvatarType} from '../util/UserAvatar'
-import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
-import {CenteredView} from '../util/Views'
-import {sanitizeHandle} from 'lib/strings/handles'
 import {makeProfileLink} from 'lib/routes/links'
 import {NavigationProp} from 'lib/routes/types'
-import {BACK_HITSLOP} from 'lib/constants'
+import {sanitizeHandle} from 'lib/strings/handles'
 import {isNative} from 'platform/detection'
-import {useLightboxControls, ImagesLightbox} from '#/state/lightbox'
-import {useLingui} from '@lingui/react'
-import {Trans, msg} from '@lingui/macro'
-import {useSetDrawerOpen} from '#/state/shell'
-import {emitSoftReset} from '#/state/events'
+import {TextLink} from '../util/Link'
+import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
+import {Text} from '../util/text/Text'
+import {UserAvatar, UserAvatarType} from '../util/UserAvatar'
+import {CenteredView} from '../util/Views'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export function ProfileSubpageHeader({
   isLoading,
@@ -79,7 +81,7 @@ export function ProfileSubpageHeader({
             {
               flexDirection: 'row',
               alignItems: 'center',
-              borderBottomWidth: 1,
+              borderBottomWidth: hairlineWidth,
               paddingTop: isNative ? 0 : 8,
               paddingBottom: 8,
               paddingHorizontal: isMobile ? 12 : 14,
diff --git a/src/view/com/util/LoadingPlaceholder.tsx b/src/view/com/util/LoadingPlaceholder.tsx
index 33a59be6d..be67d10cb 100644
--- a/src/view/com/util/LoadingPlaceholder.tsx
+++ b/src/view/com/util/LoadingPlaceholder.tsx
@@ -15,6 +15,7 @@ import {useTheme as useTheme_NEW} from '#/alf'
 import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '#/components/icons/Bubble'
 import {Heart2_Stroke2_Corner0_Rounded as HeartIconOutline} from '#/components/icons/Heart2'
 import {Repost_Stroke2_Corner2_Rounded as Repost} from '#/components/icons/Repost'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export function LoadingPlaceholder({
   width,
@@ -233,7 +234,7 @@ export function FeedLoadingPlaceholder({
         {
           paddingHorizontal: 12,
           paddingVertical: 18,
-          borderTopWidth: showTopBorder ? 1 : 0,
+          borderTopWidth: showTopBorder ? hairlineWidth : 0,
         },
         pal.border,
         style,
diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx
index 63a2b3de3..4c0f0e3e5 100644
--- a/src/view/com/util/ViewHeader.tsx
+++ b/src/view/com/util/ViewHeader.tsx
@@ -15,6 +15,7 @@ import {NavigationProp} from 'lib/routes/types'
 import {useTheme} from '#/alf'
 import {Text} from './text/Text'
 import {CenteredView} from './Views'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20}
 
@@ -156,7 +157,7 @@ function DesktopWebHeader({
         styles.desktopHeader,
         pal.border,
         {
-          borderBottomWidth: showBorder ? 1 : 0,
+          borderBottomWidth: showBorder ? hairlineWidth : 0,
         },
         {display: 'flex', flexDirection: 'column'},
       ]}>
@@ -245,7 +246,7 @@ const styles = StyleSheet.create({
     marginRight: 'auto',
   },
   border: {
-    borderBottomWidth: 1,
+    borderBottomWidth: hairlineWidth,
   },
   titleContainer: {
     marginLeft: 'auto',
diff --git a/src/view/com/util/Views.web.tsx b/src/view/com/util/Views.web.tsx
index 0ebd986cb..ffea9fe2e 100644
--- a/src/view/com/util/Views.web.tsx
+++ b/src/view/com/util/Views.web.tsx
@@ -26,6 +26,7 @@ import Animated from 'react-native-reanimated'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {addStyle} from 'lib/styles'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 interface AddedProps {
   desktopFixedHeight?: boolean | number
@@ -46,8 +47,8 @@ export const CenteredView = React.forwardRef(function CenteredView({
   }
   if (sideBorders) {
     style = addStyle(style, {
-      borderLeftWidth: 1,
-      borderRightWidth: 1,
+      borderLeftWidth: hairlineWidth,
+      borderRightWidth: hairlineWidth,
     })
     style = addStyle(style, pal.border)
   }
@@ -159,8 +160,8 @@ export const ScrollView = React.forwardRef(function ScrollViewImpl(
 
 const styles = StyleSheet.create({
   contentContainer: {
-    borderLeftWidth: 1,
-    borderRightWidth: 1,
+    borderLeftWidth: hairlineWidth,
+    borderRightWidth: hairlineWidth,
     // @ts-ignore web only
     minHeight: '100vh',
   },
diff --git a/src/view/com/util/load-latest/LoadLatestBtn.tsx b/src/view/com/util/load-latest/LoadLatestBtn.tsx
index 7e85e670f..a6b40f9f5 100644
--- a/src/view/com/util/load-latest/LoadLatestBtn.tsx
+++ b/src/view/com/util/load-latest/LoadLatestBtn.tsx
@@ -13,6 +13,7 @@ import {clamp} from '#/lib/numbers'
 import {colors} from '#/lib/styles'
 import {isWeb} from '#/platform/detection'
 import {useSession} from '#/state/session'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 const AnimatedTouchableOpacity =
   Animated.createAnimatedComponent(TouchableOpacity)
@@ -73,7 +74,7 @@ const styles = StyleSheet.create({
     // @ts-ignore 'fixed' is web only -prf
     position: isWeb ? 'fixed' : 'absolute',
     left: 18,
-    borderWidth: 1,
+    borderWidth: hairlineWidth,
     width: 52,
     height: 52,
     borderRadius: 26,
diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx
index 57f1d28ba..019216eca 100644
--- a/src/view/com/util/post-embeds/QuoteEmbed.tsx
+++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx
@@ -39,6 +39,7 @@ import {Link} from '../Link'
 import {PostMeta} from '../PostMeta'
 import {Text} from '../text/Text'
 import {PostEmbeds} from '.'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export function MaybeQuoteEmbed({
   embed,
@@ -247,7 +248,7 @@ const styles = StyleSheet.create({
     marginTop: 8,
     paddingVertical: 12,
     paddingHorizontal: 12,
-    borderWidth: 1,
+    borderWidth: hairlineWidth,
   },
   quotePost: {
     flex: 1,
@@ -262,7 +263,7 @@ const styles = StyleSheet.create({
     marginTop: 8,
     paddingVertical: 14,
     paddingHorizontal: 14,
-    borderWidth: 1,
+    borderWidth: hairlineWidth,
   },
   alert: {
     marginBottom: 6,
diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx
index 0fc829625..d8ef6e6ab 100644
--- a/src/view/com/util/post-embeds/index.tsx
+++ b/src/view/com/util/post-embeds/index.tsx
@@ -27,6 +27,7 @@ import {ImageLayoutGrid} from '../images/ImageLayoutGrid'
 import {ExternalLinkEmbed} from './ExternalLinkEmbed'
 import {ListEmbed} from './ListEmbed'
 import {MaybeQuoteEmbed} from './QuoteEmbed'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 type Embed =
   | AppBskyEmbedRecord.View
@@ -187,7 +188,7 @@ const styles = StyleSheet.create({
     fontWeight: 'bold',
   },
   customFeedOuter: {
-    borderWidth: 1,
+    borderWidth: hairlineWidth,
     borderRadius: 8,
     marginTop: 4,
     paddingHorizontal: 12,
diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx
index 826f997dd..837e58195 100644
--- a/src/view/screens/Feeds.tsx
+++ b/src/view/screens/Feeds.tsx
@@ -52,6 +52,7 @@ import {IconCircle} from '#/components/IconCircle'
 import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline'
 import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass'
 import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
 
@@ -856,13 +857,13 @@ const styles = StyleSheet.create({
     paddingHorizontal: 16,
     paddingVertical: 14,
     gap: 12,
-    borderBottomWidth: 1,
+    borderBottomWidth: hairlineWidth,
   },
   savedFeedMobile: {
     paddingVertical: 10,
   },
   offlineSlug: {
-    borderWidth: 1,
+    borderWidth: hairlineWidth,
     borderRadius: 4,
     paddingHorizontal: 4,
     paddingVertical: 2,
diff --git a/src/view/screens/Lists.tsx b/src/view/screens/Lists.tsx
index bdd5dd9b7..0dd2febcb 100644
--- a/src/view/screens/Lists.tsx
+++ b/src/view/screens/Lists.tsx
@@ -1,20 +1,22 @@
 import React from 'react'
-import {View} from 'react-native'
-import {useFocusEffect, useNavigation} from '@react-navigation/native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {StyleSheet, View} from 'react-native'
 import {AtUri} from '@atproto/api'
-import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
-import {MyLists} from '#/view/com/lists/MyLists'
-import {Text} from 'view/com/util/text/Text'
-import {Button} from 'view/com/util/forms/Button'
-import {NavigationProp} from 'lib/routes/types'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {Trans} from '@lingui/macro'
+import {useFocusEffect, useNavigation} from '@react-navigation/native'
+
+import {useModalControls} from '#/state/modals'
+import {useSetMinimalShellMode} from '#/state/shell'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {SimpleViewHeader} from 'view/com/util/SimpleViewHeader'
+import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
+import {NavigationProp} from 'lib/routes/types'
 import {s} from 'lib/styles'
-import {useSetMinimalShellMode} from '#/state/shell'
-import {useModalControls} from '#/state/modals'
-import {Trans} from '@lingui/macro'
+import {MyLists} from '#/view/com/lists/MyLists'
+import {Button} from 'view/com/util/forms/Button'
+import {SimpleViewHeader} from 'view/com/util/SimpleViewHeader'
+import {Text} from 'view/com/util/text/Text'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'>
 export function ListsScreen({}: Props) {
@@ -51,7 +53,10 @@ export function ListsScreen({}: Props) {
       <SimpleViewHeader
         showBackButton={isMobile}
         style={
-          !isMobile && [pal.border, {borderLeftWidth: 1, borderRightWidth: 1}]
+          !isMobile && [
+            pal.border,
+            {borderLeftWidth: hairlineWidth, borderRightWidth: hairlineWidth},
+          ]
         }>
         <View style={{flex: 1}}>
           <Text type="title-lg" style={[pal.text, {fontWeight: 'bold'}]}>
diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx
index 48c834a28..7e2fc68b3 100644
--- a/src/view/screens/Notifications.tsx
+++ b/src/view/screens/Notifications.tsx
@@ -1,37 +1,38 @@
 import React from 'react'
 import {View} from 'react-native'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 import {useFocusEffect, useIsFocused} from '@react-navigation/native'
 import {useQueryClient} from '@tanstack/react-query'
+
+import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
+import {logger} from '#/logger'
+import {isNative} from '#/platform/detection'
+import {emitSoftReset, listenSoftReset} from '#/state/events'
+import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
+import {
+  useUnreadNotifications,
+  useUnreadNotificationsApi,
+} from '#/state/queries/notifications/unread'
+import {truncateAndInvalidate} from '#/state/queries/util'
+import {useSetMinimalShellMode} from '#/state/shell'
+import {useComposerControls} from '#/state/shell/composer'
+import {useAnalytics} from 'lib/analytics/analytics'
+import {usePalette} from 'lib/hooks/usePalette'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {ComposeIcon2} from 'lib/icons'
 import {
   NativeStackScreenProps,
   NotificationsTabNavigatorParams,
 } from 'lib/routes/types'
-import {ViewHeader} from '../com/util/ViewHeader'
-import {Feed} from '../com/notifications/Feed'
+import {colors, s} from 'lib/styles'
 import {TextLink} from 'view/com/util/Link'
 import {ListMethods} from 'view/com/util/List'
 import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
-import {MainScrollProvider} from '../com/util/MainScrollProvider'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {s, colors} from 'lib/styles'
-import {useAnalytics} from 'lib/analytics/analytics'
-import {logger} from '#/logger'
-import {useSetMinimalShellMode} from '#/state/shell'
-import {Trans, msg} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import {
-  useUnreadNotifications,
-  useUnreadNotificationsApi,
-} from '#/state/queries/notifications/unread'
-import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
-import {listenSoftReset, emitSoftReset} from '#/state/events'
-import {truncateAndInvalidate} from '#/state/queries/util'
-import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
-import {isNative} from '#/platform/detection'
+import {Feed} from '../com/notifications/Feed'
 import {FAB} from '../com/util/fab/FAB'
-import {ComposeIcon2} from 'lib/icons'
-import {useComposerControls} from '#/state/shell/composer'
+import {MainScrollProvider} from '../com/util/MainScrollProvider'
+import {ViewHeader} from '../com/util/ViewHeader'
 
 type Props = NativeStackScreenProps<
   NotificationsTabNavigatorParams,
@@ -145,7 +146,11 @@ export function NotificationsScreen({}: Props) {
 
   return (
     <View testID="notificationsScreen" style={s.hContentRegion}>
-      <ViewHeader title={_(msg`Notifications`)} canGoBack={false} />
+      <ViewHeader
+        title={_(msg`Notifications`)}
+        canGoBack={false}
+        showBorder={true}
+      />
       <MainScrollProvider>
         <Feed
           onScrolledDownChange={setIsScrolledDown}
diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx
index de3c01ea3..0c2cecbfc 100644
--- a/src/view/screens/ProfileList.tsx
+++ b/src/view/screens/ProfileList.tsx
@@ -65,6 +65,7 @@ import {useDialogControl} from '#/components/Dialog'
 import * as Prompt from '#/components/Prompt'
 import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
 import {RichText} from '#/components/RichText'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 const SECTION_TITLES_CURATE = ['Posts', 'About']
 const SECTION_TITLES_MOD = ['About']
@@ -802,7 +803,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
           <View
             style={[
               {
-                borderTopWidth: 1,
+                borderTopWidth: hairlineWidth,
                 padding: isMobile ? 14 : 20,
                 gap: 12,
               },
@@ -953,7 +954,7 @@ function ErrorScreen({error}: {error: string}) {
           marginTop: 10,
           paddingHorizontal: 18,
           paddingVertical: 14,
-          borderTopWidth: 1,
+          borderTopWidth: hairlineWidth,
         },
       ]}>
       <Text type="title-lg" style={[pal.text, s.mb10]}>
diff --git a/src/view/screens/Settings/index.tsx b/src/view/screens/Settings/index.tsx
index 078ebedab..49702ae47 100644
--- a/src/view/screens/Settings/index.tsx
+++ b/src/view/screens/Settings/index.tsx
@@ -66,6 +66,7 @@ import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
 import {navigate, resetToTab} from '#/Navigation'
 import {Email2FAToggle} from './Email2FAToggle'
 import {ExportCarDialog} from './ExportCarDialog'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 function SettingsAccountCard({
   account,
@@ -317,7 +318,7 @@ export function SettingsScreen({}: Props) {
         showBackButton={isMobile}
         style={[
           pal.border,
-          {borderBottomWidth: 1},
+          {borderBottomWidth: hairlineWidth},
           !isMobile && {borderLeftWidth: 1, borderRightWidth: 1},
         ]}>
         <View style={{flex: 1}}>
diff --git a/src/view/shell/bottom-bar/BottomBarStyles.tsx b/src/view/shell/bottom-bar/BottomBarStyles.tsx
index 367c204e8..ba8743474 100644
--- a/src/view/shell/bottom-bar/BottomBarStyles.tsx
+++ b/src/view/shell/bottom-bar/BottomBarStyles.tsx
@@ -1,6 +1,7 @@
 import {StyleSheet} from 'react-native'
 
 import {colors} from 'lib/styles'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export const styles = StyleSheet.create({
   bottomBar: {
@@ -9,7 +10,7 @@ export const styles = StyleSheet.create({
     left: 0,
     right: 0,
     flexDirection: 'row',
-    borderTopWidth: 1,
+    borderTopWidth: hairlineWidth,
     paddingLeft: 5,
     paddingRight: 10,
   },
diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx
index f0cd4f59a..633f04932 100644
--- a/src/view/shell/desktop/RightNav.tsx
+++ b/src/view/shell/desktop/RightNav.tsx
@@ -13,6 +13,7 @@ import {TextLink} from 'view/com/util/Link'
 import {Text} from 'view/com/util/text/Text'
 import {DesktopFeeds} from './Feeds'
 import {DesktopSearch} from './Search'
+import hairlineWidth = StyleSheet.hairlineWidth
 
 export function DesktopRightNav({routeName}: {routeName: string}) {
   const pal = usePalette('default')
@@ -130,8 +131,8 @@ const styles = StyleSheet.create({
     marginBottom: 10,
   },
   desktopFeedsContainer: {
-    borderTopWidth: 1,
-    borderBottomWidth: 1,
+    borderTopWidth: hairlineWidth,
+    borderBottomWidth: hairlineWidth,
     marginTop: 18,
     marginBottom: 18,
   },