about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHailey <me@haileyok.com>2024-09-25 08:32:58 -0700
committerGitHub <noreply@github.com>2024-09-25 08:32:58 -0700
commitbe3c6ab93a5e3f573ceb8909df068d8a87f86474 (patch)
tree3f0038e7526e468f719821124f57a35ac2d0c877
parent2296ea338e8f7b4906a928e802267837c06754cc (diff)
downloadvoidsky-be3c6ab93a5e3f573ceb8909df068d8a87f86474.tar.zst
Improve style of reply bar (#5447)
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
-rw-r--r--src/lib/custom-animations/PressableScale.tsx53
-rw-r--r--src/view/com/post-thread/PostThreadComposePrompt.tsx95
2 files changed, 107 insertions, 41 deletions
diff --git a/src/lib/custom-animations/PressableScale.tsx b/src/lib/custom-animations/PressableScale.tsx
new file mode 100644
index 000000000..68315a978
--- /dev/null
+++ b/src/lib/custom-animations/PressableScale.tsx
@@ -0,0 +1,53 @@
+import React from 'react'
+import {Pressable, PressableProps} from 'react-native'
+import Animated, {
+  cancelAnimation,
+  runOnJS,
+  useAnimatedStyle,
+  useSharedValue,
+  withTiming,
+} from 'react-native-reanimated'
+
+import {isTouchDevice} from '#/lib/browser'
+import {isNative} from '#/platform/detection'
+
+const DEFAULT_TARGET_SCALE = isNative || isTouchDevice ? 0.98 : 1
+
+export function PressableScale({
+  targetScale = DEFAULT_TARGET_SCALE,
+  children,
+  ...rest
+}: {targetScale?: number} & Exclude<
+  PressableProps,
+  'onPressIn' | 'onPressOut'
+>) {
+  const scale = useSharedValue(1)
+
+  const style = useAnimatedStyle(() => ({
+    transform: [{scale: scale.value}],
+  }))
+
+  return (
+    <Pressable
+      accessibilityRole="button"
+      onPressIn={e => {
+        'worklet'
+        if (rest.onPressIn) {
+          runOnJS(rest.onPressIn)(e)
+        }
+        cancelAnimation(scale)
+        scale.value = withTiming(targetScale, {duration: 100})
+      }}
+      onPressOut={e => {
+        'worklet'
+        if (rest.onPressOut) {
+          runOnJS(rest.onPressOut)(e)
+        }
+        cancelAnimation(scale)
+        scale.value = withTiming(1, {duration: 100})
+      }}
+      {...rest}>
+      <Animated.View style={style}>{children as React.ReactNode}</Animated.View>
+    </Pressable>
+  )
+}
diff --git a/src/view/com/post-thread/PostThreadComposePrompt.tsx b/src/view/com/post-thread/PostThreadComposePrompt.tsx
index 62b28cc75..7586bd976 100644
--- a/src/view/com/post-thread/PostThreadComposePrompt.tsx
+++ b/src/view/com/post-thread/PostThreadComposePrompt.tsx
@@ -1,14 +1,17 @@
 import React from 'react'
-import {StyleSheet, TouchableOpacity} from 'react-native'
+import {View} from 'react-native'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
+import {PressableScale} from '#/lib/custom-animations/PressableScale'
+import {useHaptics} from '#/lib/haptics'
+import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
+import {useHapticsDisabled} from '#/state/preferences'
 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 {UserAvatar} from '#/view/com/util/UserAvatar'
+import {atoms as a, useTheme} from '#/alf'
+import {Text} from '#/components/Typography'
 
 export function PostThreadComposePrompt({
   onPressCompose,
@@ -17,47 +20,57 @@ export function PostThreadComposePrompt({
 }) {
   const {currentAccount} = useSession()
   const {data: profile} = useProfileQuery({did: currentAccount?.did})
-  const pal = usePalette('default')
   const {_} = useLingui()
-  const {isDesktop} = useWebMediaQueries()
+  const {isTabletOrDesktop} = useWebMediaQueries()
+  const t = useTheme()
+  const playHaptics = useHaptics()
+  const isHapticsDisabled = useHapticsDisabled()
+
+  const onPress = () => {
+    playHaptics('Light')
+    setTimeout(
+      () => {
+        onPressCompose()
+      },
+      isHapticsDisabled ? 0 : 75,
+    )
+  }
+
   return (
-    <TouchableOpacity
-      testID="replyPromptBtn"
-      style={[pal.view, pal.border, styles.prompt]}
-      onPress={() => onPressCompose()}
+    <PressableScale
       accessibilityRole="button"
       accessibilityLabel={_(msg`Compose reply`)}
-      accessibilityHint={_(msg`Opens composer`)}>
-      <UserAvatar
-        avatar={profile?.avatar}
-        size={38}
-        type={profile?.associated?.labeler ? 'labeler' : 'user'}
-      />
-      <Text
-        type="xl"
+      accessibilityHint={_(msg`Opens composer`)}
+      style={[
+        {paddingTop: 8, paddingBottom: isTabletOrDesktop ? 8 : 11},
+        a.px_sm,
+        a.border_t,
+        t.atoms.border_contrast_low,
+        t.atoms.bg,
+      ]}
+      onPress={onPress}>
+      <View
         style={[
-          pal.text,
-          isDesktop ? styles.labelDesktopWeb : styles.labelMobile,
+          a.flex_row,
+          a.align_center,
+          a.p_sm,
+          a.gap_sm,
+          a.rounded_full,
+          t.atoms.bg_contrast_25,
         ]}>
-        <Trans>Write your reply</Trans>
-      </Text>
-    </TouchableOpacity>
+        <UserAvatar
+          size={22}
+          avatar={profile?.avatar}
+          type={profile?.associated?.labeler ? 'labeler' : 'user'}
+        />
+        <Text
+          style={[
+            isTabletOrDesktop ? a.text_md : a.text_sm,
+            t.atoms.text_contrast_medium,
+          ]}>
+          <Trans>Write your reply</Trans>
+        </Text>
+      </View>
+    </PressableScale>
   )
 }
-
-const styles = StyleSheet.create({
-  prompt: {
-    paddingHorizontal: 16,
-    paddingTop: 10,
-    paddingBottom: 10,
-    flexDirection: 'row',
-    alignItems: 'center',
-    borderTopWidth: StyleSheet.hairlineWidth,
-  },
-  labelMobile: {
-    paddingLeft: 12,
-  },
-  labelDesktopWeb: {
-    paddingLeft: 12,
-  },
-})