about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/view/com/auth/withAuthRequired.tsx7
-rw-r--r--src/view/com/notifications/FeedItem.tsx132
-rw-r--r--src/view/com/pager/TabBar.tsx40
-rw-r--r--src/view/com/profile/ProfileCard.tsx1
-rw-r--r--src/view/com/profile/ProfileHeader.tsx9
-rw-r--r--src/view/com/util/PressableWithHover.tsx45
-rw-r--r--src/view/com/util/Selector.tsx11
-rw-r--r--src/view/com/util/moderation/ContentHider.tsx2
-rw-r--r--src/view/screens/SearchMobile.tsx36
-rw-r--r--src/view/shell/desktop/LeftNav.tsx43
10 files changed, 184 insertions, 142 deletions
diff --git a/src/view/com/auth/withAuthRequired.tsx b/src/view/com/auth/withAuthRequired.tsx
index 6073a4f80..a3f021277 100644
--- a/src/view/com/auth/withAuthRequired.tsx
+++ b/src/view/com/auth/withAuthRequired.tsx
@@ -1,7 +1,8 @@
 import React from 'react'
-import {ActivityIndicator, StyleSheet, View} from 'react-native'
+import {ActivityIndicator, StyleSheet} from 'react-native'
 import {observer} from 'mobx-react-lite'
 import {useStores} from 'state/index'
+import {CenteredView} from '../util/Views'
 import {LoggedOut} from './LoggedOut'
 import {Text} from '../util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
@@ -30,14 +31,14 @@ function Loading() {
   }, [setIsTakingTooLong])
 
   return (
-    <View style={[styles.loading, pal.view]}>
+    <CenteredView style={[styles.loading, pal.view]}>
       <ActivityIndicator size="large" />
       <Text type="2xl" style={[styles.loadingText, pal.textLight]}>
         {isTakingTooLong
           ? "This is taking too long. There may be a problem with your internet or with the service, but we're going to try a couple more times..."
           : 'Connecting...'}
       </Text>
-    </View>
+    </CenteredView>
   )
 }
 
diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx
index fd9f2324b..34df2a8ed 100644
--- a/src/view/com/notifications/FeedItem.tsx
+++ b/src/view/com/notifications/FeedItem.tsx
@@ -3,7 +3,7 @@ import {observer} from 'mobx-react-lite'
 import {
   Animated,
   TouchableOpacity,
-  TouchableWithoutFeedback,
+  Pressable,
   StyleSheet,
   View,
 } from 'react-native'
@@ -124,7 +124,7 @@ export const FeedItem = observer(function FeedItem({
     return <></>
   }
 
-  let authors: Author[] = [
+  const authors: Author[] = [
     {
       href: `/profile/${item.author.handle}`,
       handle: item.author.handle,
@@ -132,18 +132,18 @@ export const FeedItem = observer(function FeedItem({
       avatar: item.author.avatar,
       labels: item.author.labels,
     },
+    ...(item.additional?.map(
+      ({author: {avatar, labels, handle, displayName}}) => {
+        return {
+          href: `/profile/${handle}`,
+          handle,
+          displayName,
+          avatar,
+          labels,
+        }
+      },
+    ) || []),
   ]
-  if (item.additional?.length) {
-    authors = authors.concat(
-      item.additional.map(item2 => ({
-        href: `/profile/${item2.author.handle}`,
-        handle: item2.author.handle,
-        displayName: item2.author.displayName,
-        avatar: item2.author.avatar,
-        labels: item2.author.labels,
-      })),
-    )
-  }
 
   return (
     <Link
@@ -161,62 +161,52 @@ export const FeedItem = observer(function FeedItem({
       href={itemHref}
       title={itemTitle}
       noFeedback>
-      <View style={styles.layout}>
-        <View style={styles.layoutIcon}>
-          {icon === 'HeartIconSolid' ? (
-            <HeartIconSolid size={28} style={[styles.icon, ...iconStyle]} />
-          ) : (
-            <FontAwesomeIcon
-              icon={icon}
-              size={24}
-              style={[styles.icon, ...iconStyle]}
+      <View style={styles.layoutIcon}>
+        {icon === 'HeartIconSolid' ? (
+          <HeartIconSolid size={28} style={[styles.icon, ...iconStyle]} />
+        ) : (
+          <FontAwesomeIcon
+            icon={icon}
+            size={24}
+            style={[styles.icon, ...iconStyle]}
+          />
+        )}
+      </View>
+      <View style={styles.layoutContent}>
+        <Pressable
+          onPress={authors.length > 1 ? onToggleAuthorsExpanded : () => {}}>
+          <CondensedAuthorsList
+            visible={!isAuthorsExpanded}
+            authors={authors}
+            onToggleAuthorsExpanded={onToggleAuthorsExpanded}
+          />
+          <ExpandedAuthorsList visible={isAuthorsExpanded} authors={authors} />
+          <View style={styles.meta}>
+            <TextLink
+              key={authors[0].href}
+              style={[pal.text, s.bold, styles.metaItem]}
+              href={authors[0].href}
+              text={sanitizeDisplayName(
+                authors[0].displayName || authors[0].handle,
+              )}
             />
-          )}
-        </View>
-        <View style={styles.layoutContent}>
-          <TouchableWithoutFeedback
-            onPress={authors.length > 1 ? onToggleAuthorsExpanded : () => {}}>
-            <View>
-              <CondensedAuthorsList
-                visible={!isAuthorsExpanded}
-                authors={authors}
-                onToggleAuthorsExpanded={onToggleAuthorsExpanded}
-              />
-              <ExpandedAuthorsList
-                visible={isAuthorsExpanded}
-                authors={authors}
-              />
-              <View style={styles.meta}>
-                <TextLink
-                  key={authors[0].href}
-                  style={[pal.text, s.bold, styles.metaItem]}
-                  href={authors[0].href}
-                  text={sanitizeDisplayName(
-                    authors[0].displayName || authors[0].handle,
-                  )}
-                />
-                {authors.length > 1 ? (
-                  <>
-                    <Text style={[styles.metaItem, pal.text]}>and</Text>
-                    <Text style={[styles.metaItem, pal.text, s.bold]}>
-                      {authors.length - 1}{' '}
-                      {pluralize(authors.length - 1, 'other')}
-                    </Text>
-                  </>
-                ) : undefined}
-                <Text style={[styles.metaItem, pal.text]}>{action}</Text>
-                <Text style={[styles.metaItem, pal.textLight]}>
-                  {ago(item.indexedAt)}
+            {authors.length > 1 ? (
+              <>
+                <Text style={[styles.metaItem, pal.text]}>and</Text>
+                <Text style={[styles.metaItem, pal.text, s.bold]}>
+                  {authors.length - 1} {pluralize(authors.length - 1, 'other')}
                 </Text>
-              </View>
-            </View>
-          </TouchableWithoutFeedback>
-          {item.isLike || item.isRepost || item.isQuote ? (
-            <AdditionalPostText additionalPost={item.additionalPost} />
-          ) : (
-            <></>
-          )}
-        </View>
+              </>
+            ) : undefined}
+            <Text style={[styles.metaItem, pal.text]}>{action}</Text>
+            <Text style={[styles.metaItem, pal.textLight]}>
+              {ago(item.indexedAt)}
+            </Text>
+          </View>
+        </Pressable>
+        {item.isLike || item.isRepost || item.isQuote ? (
+          <AdditionalPostText additionalPost={item.additionalPost} />
+        ) : null}
       </View>
     </Link>
   )
@@ -392,8 +382,6 @@ const styles = StyleSheet.create({
     padding: 10,
     paddingRight: 15,
     borderTopWidth: 1,
-  },
-  layout: {
     flexDirection: 'row',
   },
   layoutIcon: {
@@ -405,6 +393,9 @@ const styles = StyleSheet.create({
     marginRight: 10,
     marginTop: 4,
   },
+  layoutContent: {
+    flex: 1,
+  },
   avis: {
     flexDirection: 'row',
     alignItems: 'center',
@@ -413,9 +404,6 @@ const styles = StyleSheet.create({
     fontWeight: 'bold',
     paddingLeft: 6,
   },
-  layoutContent: {
-    flex: 1,
-  },
   meta: {
     flexDirection: 'row',
     flexWrap: 'wrap',
diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx
index 8f3951e7b..628128e8f 100644
--- a/src/view/com/pager/TabBar.tsx
+++ b/src/view/com/pager/TabBar.tsx
@@ -1,11 +1,7 @@
 import React, {createRef, useState, useMemo, useRef} from 'react'
-import {
-  Animated,
-  StyleSheet,
-  TouchableWithoutFeedback,
-  View,
-} from 'react-native'
+import {Animated, StyleSheet, View} from 'react-native'
 import {Text} from '../util/text/Text'
+import {PressableWithHover} from '../util/PressableWithHover'
 import {usePalette} from 'lib/hooks/usePalette'
 import {isDesktopWeb} from 'platform/detection'
 
@@ -109,20 +105,21 @@ export function TabBar({
       {items.map((item, i) => {
         const selected = i === selectedPage
         return (
-          <TouchableWithoutFeedback
-            key={i}
-            testID={testID ? `${testID}-${item}` : undefined}
+          <PressableWithHover
+            ref={itemRefs[i]}
+            key={item}
+            style={
+              indicatorPosition === 'top' ? styles.itemTop : styles.itemBottom
+            }
+            hoverStyle={pal.viewLight}
             onPress={() => onPressItem(i)}>
-            <View
-              style={
-                indicatorPosition === 'top' ? styles.itemTop : styles.itemBottom
-              }
-              ref={itemRefs[i]}>
-              <Text type="xl-bold" style={selected ? pal.text : pal.textLight}>
-                {item}
-              </Text>
-            </View>
-          </TouchableWithoutFeedback>
+            <Text
+              type="xl-bold"
+              testID={testID ? `${testID}-${item}` : undefined}
+              style={selected ? pal.text : pal.textLight}>
+              {item}
+            </Text>
+          </PressableWithHover>
         )
       })}
     </View>
@@ -138,18 +135,19 @@ const styles = isDesktopWeb
       itemTop: {
         paddingTop: 16,
         paddingBottom: 14,
-        marginRight: 24,
+        paddingHorizontal: 12,
       },
       itemBottom: {
         paddingTop: 14,
         paddingBottom: 16,
-        marginRight: 24,
+        paddingHorizontal: 12,
       },
       indicator: {
         position: 'absolute',
         left: 0,
         width: 1,
         height: 3,
+        zIndex: 1,
       },
     })
   : StyleSheet.create({
diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx
index d14d5e16d..07bf4e291 100644
--- a/src/view/com/profile/ProfileCard.tsx
+++ b/src/view/com/profile/ProfileCard.tsx
@@ -48,7 +48,6 @@ export function ProfileCard({
       ]}
       href={`/profile/${handle}`}
       title={handle}
-      noFeedback
       asAnchor>
       <View style={styles.layout}>
         <View style={styles.layoutAvi}>
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index 101b6b833..4c232a13a 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -64,7 +64,7 @@ export const ProfileHeader = observer(
             <View style={[styles.buttonsLine]}>
               <LoadingPlaceholder width={100} height={31} style={styles.br50} />
             </View>
-            <View style={styles.displayNameLine}>
+            <View>
               <Text type="title-2xl" style={[pal.text, styles.title]}>
                 {sanitizeDisplayName(view.displayName || view.handle)}
               </Text>
@@ -273,7 +273,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoaded({
             </DropdownButton>
           ) : undefined}
         </View>
-        <View style={styles.displayNameLine}>
+        <View>
           <Text
             testID="profileHeaderDisplayName"
             type="title-2xl"
@@ -431,11 +431,6 @@ const styles = StyleSheet.create({
     borderRadius: 50,
     marginLeft: 6,
   },
-
-  displayNameLine: {
-    // paddingLeft: 86,
-    // marginBottom: 14,
-  },
   title: {lineHeight: 38},
 
   handleLine: {
diff --git a/src/view/com/util/PressableWithHover.tsx b/src/view/com/util/PressableWithHover.tsx
new file mode 100644
index 000000000..09ccb6a2d
--- /dev/null
+++ b/src/view/com/util/PressableWithHover.tsx
@@ -0,0 +1,45 @@
+import React, {
+  useState,
+  useCallback,
+  PropsWithChildren,
+  forwardRef,
+  Ref,
+} from 'react'
+import {Pressable, PressableProps, StyleProp, ViewStyle} from 'react-native'
+import {addStyle} from 'lib/styles'
+
+interface PressableWithHover extends PressableProps {
+  hoverStyle: StyleProp<ViewStyle>
+}
+
+export const PressableWithHover = forwardRef(
+  (
+    {
+      children,
+      style,
+      hoverStyle,
+      ...props
+    }: PropsWithChildren<PressableWithHover>,
+    ref: Ref<any>,
+  ) => {
+    const [isHovering, setIsHovering] = useState(false)
+
+    const onHoverIn = useCallback(() => setIsHovering(true), [setIsHovering])
+    const onHoverOut = useCallback(() => setIsHovering(false), [setIsHovering])
+    style =
+      typeof style !== 'function' && isHovering
+        ? addStyle(style, hoverStyle)
+        : style
+
+    return (
+      <Pressable
+        {...props}
+        style={style}
+        onHoverIn={onHoverIn}
+        onHoverOut={onHoverOut}
+        ref={ref}>
+        {children}
+      </Pressable>
+    )
+  },
+)
diff --git a/src/view/com/util/Selector.tsx b/src/view/com/util/Selector.tsx
index 03db13bd1..872b78184 100644
--- a/src/view/com/util/Selector.tsx
+++ b/src/view/com/util/Selector.tsx
@@ -1,10 +1,5 @@
 import React, {createRef, useState, useMemo, useRef} from 'react'
-import {
-  Animated,
-  StyleSheet,
-  TouchableWithoutFeedback,
-  View,
-} from 'react-native'
+import {Animated, Pressable, StyleSheet, View} from 'react-native'
 import {Text} from './text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
 
@@ -99,7 +94,7 @@ export function Selector({
       {items.map((item, i) => {
         const selected = i === selectedIndex
         return (
-          <TouchableWithoutFeedback key={i} onPress={() => onPressItem(i)}>
+          <Pressable key={item} onPress={() => onPressItem(i)}>
             <View style={styles.item} ref={itemRefs[i]}>
               <Text
                 style={
@@ -110,7 +105,7 @@ export function Selector({
                 {item}
               </Text>
             </View>
-          </TouchableWithoutFeedback>
+          </Pressable>
         )
       })}
     </View>
diff --git a/src/view/com/util/moderation/ContentHider.tsx b/src/view/com/util/moderation/ContentHider.tsx
index c1512171d..42a97cd34 100644
--- a/src/view/com/util/moderation/ContentHider.tsx
+++ b/src/view/com/util/moderation/ContentHider.tsx
@@ -40,7 +40,7 @@ export function ContentHider({
   }
 
   if (labelPref.pref === 'hide') {
-    return <></>
+    return null
   }
 
   return (
diff --git a/src/view/screens/SearchMobile.tsx b/src/view/screens/SearchMobile.tsx
index 679fb07c2..de64b2d67 100644
--- a/src/view/screens/SearchMobile.tsx
+++ b/src/view/screens/SearchMobile.tsx
@@ -1,8 +1,8 @@
-import React from 'react'
+import React, {useCallback} from 'react'
 import {
-  Keyboard,
   StyleSheet,
   TouchableWithoutFeedback,
+  Keyboard,
   View,
 } from 'react-native'
 import {useFocusEffect} from '@react-navigation/native'
@@ -26,6 +26,7 @@ import {s} from 'lib/styles'
 import {ProfileCard} from 'view/com/profile/ProfileCard'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useOnMainScroll} from 'lib/hooks/useOnMainScroll'
+import {isAndroid, isIOS} from 'platform/detection'
 
 type Props = NativeStackScreenProps<SearchTabNavigatorParams, 'Search'>
 export const SearchScreen = withAuthRequired(
@@ -110,8 +111,14 @@ export const SearchScreen = withAuthRequired(
       }, [store, autocompleteView, foafs, suggestedActors, onSoftReset]),
     )
 
+    const onPress = useCallback(() => {
+      if (isIOS || isAndroid) {
+        Keyboard.dismiss()
+      }
+    }, [])
+
     return (
-      <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
+      <TouchableWithoutFeedback onPress={onPress}>
         <View style={[pal.view, styles.container]}>
           <HeaderWithInput
             isInputFocused={isInputFocused}
@@ -139,16 +146,19 @@ export const SearchScreen = withAuthRequired(
               scrollEventThrottle={100}>
               {query && autocompleteView.searchRes.length ? (
                 <>
-                  {autocompleteView.searchRes.map(item => (
-                    <ProfileCard
-                      key={item.did}
-                      testID={`searchAutoCompleteResult-${item.handle}`}
-                      handle={item.handle}
-                      displayName={item.displayName}
-                      labels={item.labels}
-                      avatar={item.avatar}
-                    />
-                  ))}
+                  {autocompleteView.searchRes.map(
+                    ({did, handle, displayName, labels, avatar}, index) => (
+                      <ProfileCard
+                        key={did}
+                        testID={`searchAutoCompleteResult-${handle}`}
+                        handle={handle}
+                        displayName={displayName}
+                        labels={labels}
+                        avatar={avatar}
+                        noBorder={index === 0}
+                      />
+                    ),
+                  )}
                 </>
               ) : query && !autocompleteView.searchRes.length ? (
                 <View>
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index e9a631b23..c5486a8fe 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -1,6 +1,7 @@
 import React from 'react'
 import {observer} from 'mobx-react-lite'
 import {StyleSheet, TouchableOpacity, View} from 'react-native'
+import {PressableWithHover} from 'view/com/util/PressableWithHover'
 import {useNavigation, useNavigationState} from '@react-navigation/native'
 import {
   FontAwesomeIcon,
@@ -88,19 +89,23 @@ const NavItem = observer(
     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>
+      <PressableWithHover
+        style={styles.navItemWrapper}
+        hoverStyle={pal.viewLight}>
+        <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>
+      </PressableWithHover>
     )
   },
 )
@@ -193,13 +198,14 @@ const styles = StyleSheet.create({
   leftNav: {
     position: 'absolute',
     top: 10,
-    right: 'calc(50vw + 300px)',
+    right: 'calc(50vw + 312px)',
     width: 220,
   },
 
   profileCard: {
     marginVertical: 10,
     width: 60,
+    paddingLeft: 12,
   },
 
   backBtn: {
@@ -210,11 +216,15 @@ const styles = StyleSheet.create({
     height: 30,
   },
 
+  navItemWrapper: {
+    paddingHorizontal: 12,
+    borderRadius: 8,
+  },
   navItem: {
     flexDirection: 'row',
     alignItems: 'center',
-    paddingTop: 14,
-    paddingBottom: 10,
+    paddingTop: 12,
+    paddingBottom: 12,
   },
   navItemIconWrapper: {
     alignItems: 'center',
@@ -245,6 +255,7 @@ const styles = StyleSheet.create({
     paddingVertical: 10,
     paddingHorizontal: 16,
     backgroundColor: colors.blue3,
+    marginLeft: 12,
     marginTop: 20,
     marginBottom: 10,
   },