about summary refs log tree commit diff
diff options
context:
space:
mode:
authordan <dan.abramov@gmail.com>2024-12-12 15:35:56 +0000
committerGitHub <noreply@github.com>2024-12-12 15:35:56 +0000
commit88166926fa64c7dd7924a3a8100056175c5f989b (patch)
tree6d20736ea725124a5e0485b45f4b6d59b7ad18b7
parent704e36c2801c4c06a3763eaef90c6a3e532a326d (diff)
downloadvoidsky-88166926fa64c7dd7924a3a8100056175c5f989b.tar.zst
Make the pager take full width (#7066)
* Wide tabs for web

* Wide tabs on mobile

* Tweak min for profile

* Driveby border fix

* Fix single tab indicator
-rw-r--r--src/screens/Hashtag.tsx2
-rw-r--r--src/view/com/pager/TabBar.tsx58
-rw-r--r--src/view/com/pager/TabBar.web.tsx21
3 files changed, 69 insertions, 12 deletions
diff --git a/src/screens/Hashtag.tsx b/src/screens/Hashtag.tsx
index a87487150..3e98f364b 100644
--- a/src/screens/Hashtag.tsx
+++ b/src/screens/Hashtag.tsx
@@ -107,7 +107,7 @@ export default function HashtagScreen({
 
   return (
     <Layout.Screen>
-      <Layout.Header.Outer>
+      <Layout.Header.Outer noBottomBorder>
         <Layout.Header.BackButton />
         <Layout.Header.Content>
           <Layout.Header.TitleText>{headerTitle}</Layout.Header.TitleText>
diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx
index b08b364c5..b257559bc 100644
--- a/src/view/com/pager/TabBar.tsx
+++ b/src/view/com/pager/TabBar.tsx
@@ -51,6 +51,7 @@ export function TabBar({
   const containerSize = useSharedValue(0)
   const scrollX = useSharedValue(0)
   const layouts = useSharedValue<{x: number; width: number}[]>([])
+  const textLayouts = useSharedValue<{width: number}[]>([])
   const itemsLength = items.length
 
   const scrollToOffsetJS = useCallback(
@@ -211,21 +212,40 @@ export function TabBar({
     [layouts],
   )
 
+  const onTextLayout = useCallback(
+    (i: number, layout: {width: number}) => {
+      'worklet'
+      textLayouts.modify(ls => {
+        ls[i] = layout
+        return ls
+      })
+    },
+    [textLayouts],
+  )
+
   const indicatorStyle = useAnimatedStyle(() => {
     if (!_WORKLET) {
       return {opacity: 0}
     }
     const layoutsValue = layouts.get()
+    const textLayoutsValue = textLayouts.get()
     if (
       layoutsValue.length !== itemsLength ||
-      layoutsValue.some(l => l === undefined)
+      textLayoutsValue.length !== itemsLength
     ) {
       return {
         opacity: 0,
       }
     }
-    if (layoutsValue.length === 1) {
-      return {opacity: 1}
+    if (textLayoutsValue.length === 1) {
+      return {
+        opacity: 1,
+        transform: [
+          {
+            scaleX: textLayoutsValue[0].width / contentSize.get(),
+          },
+        ],
+      }
     }
     return {
       opacity: 1,
@@ -240,10 +260,8 @@ export function TabBar({
         {
           scaleX: interpolate(
             dragProgress.get(),
-            layoutsValue.map((l, i) => i),
-            layoutsValue.map(
-              l => (l.width - ITEM_PADDING * 2) / contentSize.get(),
-            ),
+            textLayoutsValue.map((l, i) => i),
+            textLayoutsValue.map(l => l.width / contentSize.get()),
           ),
         },
       ],
@@ -287,7 +305,7 @@ export function TabBar({
           onLayout={e => {
             contentSize.set(e.nativeEvent.layout.width)
           }}
-          style={{flexDirection: 'row'}}>
+          style={{flexDirection: 'row', flexGrow: 1}}>
           {items.map((item, i) => {
             return (
               <TabBarItem
@@ -298,6 +316,7 @@ export function TabBar({
                 item={item}
                 onPressItem={onPressItem}
                 onItemLayout={onItemLayout}
+                onTextLayout={onTextLayout}
               />
             )
           })}
@@ -328,6 +347,7 @@ function TabBarItem({
   item,
   onPressItem,
   onItemLayout,
+  onTextLayout,
 }: {
   index: number
   testID: string | undefined
@@ -335,6 +355,7 @@ function TabBarItem({
   item: string
   onPressItem: (index: number) => void
   onItemLayout: (index: number, layout: {x: number; width: number}) => void
+  onTextLayout: (index: number, layout: {width: number}) => void
 }) {
   const t = useTheme()
   const style = useAnimatedStyle(() => {
@@ -358,8 +379,15 @@ function TabBarItem({
     [index, onItemLayout],
   )
 
+  const handleTextLayout = useCallback(
+    (e: LayoutChangeEvent) => {
+      runOnUI(onTextLayout)(index, e.nativeEvent.layout)
+    },
+    [index, onTextLayout],
+  )
+
   return (
-    <View onLayout={handleLayout}>
+    <View onLayout={handleLayout} style={{flexGrow: 1}}>
       <PressableWithHover
         testID={`${testID}-selector-${index}`}
         style={styles.item}
@@ -370,7 +398,8 @@ function TabBarItem({
           <Text
             emoji
             testID={testID ? `${testID}-${item}` : undefined}
-            style={[t.atoms.text, a.text_md, a.font_bold, {lineHeight: 20}]}>
+            style={[styles.itemText, t.atoms.text, a.text_md, a.font_bold]}
+            onLayout={handleTextLayout}>
             {item}
           </Text>
         </Animated.View>
@@ -381,19 +410,28 @@ function TabBarItem({
 
 const styles = StyleSheet.create({
   contentContainer: {
+    flexGrow: 1,
     backgroundColor: 'transparent',
     paddingHorizontal: CONTENT_PADDING,
   },
   item: {
+    flexGrow: 1,
     paddingTop: 10,
     paddingHorizontal: ITEM_PADDING,
     justifyContent: 'center',
   },
   itemInner: {
+    alignItems: 'center',
+    flexGrow: 1,
     paddingBottom: 10,
     borderBottomWidth: 3,
     borderBottomColor: 'transparent',
   },
+  itemText: {
+    lineHeight: 20,
+    minWidth: 45,
+    textAlign: 'center',
+  },
   outerBottomBorder: {
     position: 'absolute',
     left: 0,
diff --git a/src/view/com/pager/TabBar.web.tsx b/src/view/com/pager/TabBar.web.tsx
index 789f88e75..f44e03368 100644
--- a/src/view/com/pager/TabBar.web.tsx
+++ b/src/view/com/pager/TabBar.web.tsx
@@ -115,12 +115,14 @@ export function TabBar({
               hoverStyle={t.atoms.bg_contrast_25}
               onPress={() => onPressItem(i)}
               accessibilityRole="tab">
-              <View style={[styles.itemInner, selected && indicatorStyle]}>
+              <View style={styles.itemInner}>
                 <Text
                   emoji
                   testID={testID ? `${testID}-${item}` : undefined}
                   style={[
+                    styles.itemText,
                     selected ? t.atoms.text : t.atoms.text_contrast_medium,
+                    selected && indicatorStyle,
                     a.text_md,
                     a.font_bold,
                     {lineHeight: 20},
@@ -143,15 +145,23 @@ const desktopStyles = StyleSheet.create({
     width: 598,
   },
   contentContainer: {
+    flexGrow: 1,
     paddingHorizontal: 0,
     backgroundColor: 'transparent',
   },
   item: {
+    flexGrow: 1,
+    alignItems: 'stretch',
     paddingTop: 14,
     paddingHorizontal: 14,
     justifyContent: 'center',
   },
   itemInner: {
+    alignItems: 'center',
+  },
+  itemText: {
+    textAlign: 'center',
+    minWidth: 45,
     paddingBottom: 12,
     borderBottomWidth: 3,
     borderBottomColor: 'transparent',
@@ -170,15 +180,24 @@ const mobileStyles = StyleSheet.create({
     flexDirection: 'row',
   },
   contentContainer: {
+    flexGrow: 1,
     backgroundColor: 'transparent',
     paddingHorizontal: 6,
   },
   item: {
+    flexGrow: 1,
+    alignItems: 'stretch',
     paddingTop: 10,
     paddingHorizontal: 10,
     justifyContent: 'center',
   },
   itemInner: {
+    flexGrow: 1,
+    alignItems: 'center',
+  },
+  itemText: {
+    textAlign: 'center',
+    minWidth: 45,
     paddingBottom: 10,
     borderBottomWidth: 2,
     borderBottomColor: 'transparent',