about summary refs log tree commit diff
path: root/src/components/dms/ChatEmptyPill.tsx
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2024-05-20 18:56:44 -0500
committerGitHub <noreply@github.com>2024-05-20 16:56:44 -0700
commita7b0242cc8aaf09273abe20903e88e59a4acd1a7 (patch)
tree9e3f21bcf0def435877e2a1a9c5fc8eedc6c7950 /src/components/dms/ChatEmptyPill.tsx
parent6dde48756366008a897bfffdcec6c1756df59ef4 (diff)
downloadvoidsky-a7b0242cc8aaf09273abe20903e88e59a4acd1a7.tar.zst
[🐴] Empty chat prompt (#4132)
* Add empty chat pill

* Tweak padding

* move to `components`, place inside `KeyboardStickyView`

* cleanup unused vars

* add a new animation type

* (unrelated) add haptic to long press

* adjust shrink and pop

---------

Co-authored-by: Hailey <me@haileyok.com>
Diffstat (limited to 'src/components/dms/ChatEmptyPill.tsx')
-rw-r--r--src/components/dms/ChatEmptyPill.tsx98
1 files changed, 98 insertions, 0 deletions
diff --git a/src/components/dms/ChatEmptyPill.tsx b/src/components/dms/ChatEmptyPill.tsx
new file mode 100644
index 000000000..a6c4906a6
--- /dev/null
+++ b/src/components/dms/ChatEmptyPill.tsx
@@ -0,0 +1,98 @@
+import React from 'react'
+import {Pressable, View} from 'react-native'
+import Animated, {
+  runOnJS,
+  useAnimatedStyle,
+  useSharedValue,
+  withTiming,
+} from 'react-native-reanimated'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {ScaleAndFadeIn} from 'lib/custom-animations/ScaleAndFade'
+import {ShrinkAndPop} from 'lib/custom-animations/ShrinkAndPop'
+import {useHaptics} from 'lib/haptics'
+import {isWeb} from 'platform/detection'
+import {atoms as a, useTheme} from '#/alf'
+import {Text} from '#/components/Typography'
+
+const AnimatedPressable = Animated.createAnimatedComponent(Pressable)
+
+let lastIndex = 0
+
+export function ChatEmptyPill() {
+  const t = useTheme()
+  const {_} = useLingui()
+  const playHaptic = useHaptics()
+  const [promptIndex, setPromptIndex] = React.useState(lastIndex)
+
+  const scale = useSharedValue(1)
+
+  const prompts = React.useMemo(() => {
+    return [
+      _(msg`Say hello!`),
+      _(msg`Share your favorite feed!`),
+      _(msg`Tell a joke!`),
+      _(msg`Share a fun fact!`),
+      _(msg`Share a cool story!`),
+      _(msg`Send a neat website!`),
+      _(msg`Clip 🐴 clop 🐴`),
+    ]
+  }, [_])
+
+  const onPressIn = React.useCallback(() => {
+    if (isWeb) return
+    scale.value = withTiming(1.075, {duration: 100})
+  }, [scale])
+
+  const onPressOut = React.useCallback(() => {
+    if (isWeb) return
+    scale.value = withTiming(1, {duration: 100})
+  }, [scale])
+
+  const onPress = React.useCallback(() => {
+    runOnJS(playHaptic)()
+    let randomPromptIndex = Math.floor(Math.random() * prompts.length)
+    while (randomPromptIndex === lastIndex) {
+      randomPromptIndex = Math.floor(Math.random() * prompts.length)
+    }
+    setPromptIndex(randomPromptIndex)
+    lastIndex = randomPromptIndex
+  }, [playHaptic, prompts.length])
+
+  const animatedStyle = useAnimatedStyle(() => ({
+    transform: [{scale: scale.value}],
+  }))
+
+  return (
+    <View
+      style={[
+        a.absolute,
+        a.w_full,
+        a.z_10,
+        a.align_center,
+        {
+          bottom: 70,
+        },
+      ]}>
+      <AnimatedPressable
+        style={[
+          a.px_xl,
+          a.py_md,
+          a.rounded_full,
+          t.atoms.bg_contrast_25,
+          a.align_center,
+          animatedStyle,
+        ]}
+        entering={ScaleAndFadeIn}
+        exiting={ShrinkAndPop}
+        onPress={onPress}
+        onPressIn={onPressIn}
+        onPressOut={onPressOut}>
+        <Text style={[a.font_bold, a.pointer_events_none]} selectable={false}>
+          {prompts[promptIndex]}
+        </Text>
+      </AnimatedPressable>
+    </View>
+  )
+}