about summary refs log tree commit diff
path: root/src/view/com/util/Toast.tsx
diff options
context:
space:
mode:
authorAna <anastasiyauraleva@gmail.com>2025-07-29 18:15:32 -0700
committerAna <anastasiyauraleva@gmail.com>2025-07-29 22:12:36 -0700
commit34ea6e8f3499eeeb1013dfbf7c4dcd3bdcf149a3 (patch)
tree462207a6246da0dc24cce08ab8c3fba2e7c2c951 /src/view/com/util/Toast.tsx
parent890dee3eef38700c8ebf850c37e1bf79c54aec2e (diff)
downloadvoidsky-34ea6e8f3499eeeb1013dfbf7c4dcd3bdcf149a3.tar.zst
update: toast styles that reuse consistent style
Diffstat (limited to 'src/view/com/util/Toast.tsx')
-rw-r--r--src/view/com/util/Toast.tsx182
1 files changed, 62 insertions, 120 deletions
diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx
index fc9bdf672..2f8888bef 100644
--- a/src/view/com/util/Toast.tsx
+++ b/src/view/com/util/Toast.tsx
@@ -6,8 +6,8 @@ import {
   GestureHandlerRootView,
 } from 'react-native-gesture-handler'
 import Animated, {
-  FadeInUp,
-  FadeOutUp,
+  FadeIn,
+  FadeOut,
   runOnJS,
   useAnimatedReaction,
   useAnimatedStyle,
@@ -17,53 +17,36 @@ import Animated, {
 } from 'react-native-reanimated'
 import RootSiblings from 'react-native-root-siblings'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
-import {
-  FontAwesomeIcon,
-  type Props as FontAwesomeProps,
-} from '@fortawesome/react-native-fontawesome'
 import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
-import {isWeb} from '#/platform/detection'
 import {atoms as a, useTheme} from '#/alf'
 import {Text} from '#/components/Typography'
+import {
+  type ToastType,
+  TOAST_TYPE_TO_ICON,
+  getToastTypeStyles,
+  TOAST_ANIMATION_CONFIG,
+} from './Toast.style'
 
 const TIMEOUT = 2e3
 
-export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info'
-
-const TOAST_TYPE_TO_ICON: Record<ToastType, FontAwesomeProps['icon']> = {
-  default: 'check',
-  success: 'check',
-  error: 'exclamation',
-  warning: 'circle-exclamation',
-  info: 'info',
-}
-
-export function show(
-  message: string,
-  type: ToastType | FontAwesomeProps['icon'] = 'default',
-) {
+export function show(message: string, type: ToastType = 'default') {
   if (process.env.NODE_ENV === 'test') {
     return
   }
 
-  const icon =
-    typeof type === 'string' && type in TOAST_TYPE_TO_ICON
-      ? TOAST_TYPE_TO_ICON[type as ToastType]
-      : (type as FontAwesomeProps['icon'])
-
   AccessibilityInfo.announceForAccessibility(message)
   const item = new RootSiblings(
-    <Toast message={message} icon={icon} destroy={() => item.destroy()} />,
+    <Toast message={message} type={type} destroy={() => item.destroy()} />,
   )
 }
 
 function Toast({
   message,
-  icon,
+  type,
   destroy,
 }: {
   message: string
-  icon: FontAwesomeProps['icon']
+  type: ToastType
   destroy: () => void
 }) {
   const t = useTheme()
@@ -72,6 +55,10 @@ function Toast({
   const dismissSwipeTranslateY = useSharedValue(0)
   const [cardHeight, setCardHeight] = useState(0)
 
+  const toastStyles = getToastTypeStyles(t)
+  const colors = toastStyles[type]
+  const IconComponent = TOAST_TYPE_TO_ICON[type]
+
   // for the exit animation to work on iOS the animated component
   // must not be the root component
   // so we need to wrap it in a view and unmount the toast ahead of time
@@ -169,103 +156,58 @@ function Toast({
     }
   })
 
-  // Web-specific styles for better compatibility
-  const webContainerStyle = isWeb
-    ? {
-        position: 'absolute' as const,
-        top: topOffset,
-        left: 16,
-        right: 16,
-        zIndex: 9999,
-        pointerEvents: 'auto' as const,
-      }
-    : {}
-
-  const webToastStyle = isWeb
-    ? {
-        backgroundColor:
-          t.name === 'dark' ? t.palette.contrast_25 : t.palette.white,
-        shadowColor: '#000',
-        shadowOffset: {width: 0, height: 10},
-        shadowOpacity: 0.1,
-        shadowRadius: 15,
-        elevation: 10,
-        borderColor: t.palette.contrast_300,
-        borderWidth: 1,
-        borderRadius: 8,
-        minHeight: 60,
-      }
-    : {}
-
   return (
     <GestureHandlerRootView
-      style={[
-        a.absolute,
-        {top: topOffset, left: 16, right: 16},
-        isWeb && webContainerStyle,
-      ]}
+      style={[a.absolute, {top: topOffset, left: 16, right: 16}]}
       pointerEvents="box-none">
       {alive && (
         <Animated.View
-          entering={FadeInUp}
-          exiting={FadeOutUp}
-          style={[a.flex_1]}>
-          <Animated.View
-            onLayout={evt => setCardHeight(evt.nativeEvent.layout.height)}
-            accessibilityRole="alert"
-            accessible={true}
-            accessibilityLabel={message}
-            accessibilityHint=""
-            onAccessibilityEscape={hideAndDestroyImmediately}
-            style={[
-              a.flex_1,
-              isWeb
-                ? webToastStyle
-                : [
-                    t.name === 'dark' ? t.atoms.bg_contrast_25 : t.atoms.bg,
-                    a.shadow_lg,
-                    t.atoms.border_contrast_medium,
-                    a.rounded_sm,
-                    a.border,
-                  ],
-              !isWeb && animatedStyle,
-            ]}>
-            <GestureDetector gesture={panGesture}>
-              <View style={[a.flex_1, a.px_md, a.py_lg, a.flex_row, a.gap_md]}>
-                <View
-                  style={[
-                    a.flex_shrink_0,
-                    a.rounded_full,
-                    {width: 32, height: 32},
-                    a.align_center,
-                    a.justify_center,
-                    {
-                      backgroundColor:
-                        t.name === 'dark'
-                          ? t.palette.black
-                          : t.palette.primary_50,
-                    },
-                  ]}>
-                  <FontAwesomeIcon
-                    icon={icon}
-                    size={16}
-                    style={t.atoms.text_contrast_medium}
-                  />
-                </View>
-                <View
-                  style={[
-                    a.h_full,
-                    a.justify_center,
-                    a.flex_1,
-                    a.justify_center,
-                  ]}>
-                  <Text style={a.text_md} emoji>
-                    {message}
-                  </Text>
-                </View>
+          entering={FadeIn.duration(TOAST_ANIMATION_CONFIG.duration)}
+          exiting={FadeOut.duration(TOAST_ANIMATION_CONFIG.duration * 0.7)}
+          onLayout={evt => setCardHeight(evt.nativeEvent.layout.height)}
+          accessibilityRole="alert"
+          accessible={true}
+          accessibilityLabel={message}
+          accessibilityHint=""
+          onAccessibilityEscape={hideAndDestroyImmediately}
+          style={[
+            a.flex_1,
+            {backgroundColor: colors.backgroundColor},
+            a.shadow_sm,
+            {borderColor: colors.borderColor, borderWidth: 1},
+            a.rounded_sm,
+            animatedStyle,
+          ]}>
+          <GestureDetector gesture={panGesture}>
+            <View style={[a.flex_1, a.px_md, a.py_lg, a.flex_row, a.gap_md]}>
+              <View
+                style={[
+                  a.flex_shrink_0,
+                  a.rounded_full,
+                  {width: 32, height: 32},
+                  a.align_center,
+                  a.justify_center,
+                  {
+                    backgroundColor: colors.backgroundColor,
+                  },
+                ]}>
+                <IconComponent fill={colors.iconColor} size="sm" />
+              </View>
+              <View
+                style={[
+                  a.h_full,
+                  a.justify_center,
+                  a.flex_1,
+                  a.justify_center,
+                ]}>
+                <Text
+                  style={[a.text_md, a.font_bold, {color: colors.textColor}]}
+                  emoji>
+                  {message}
+                </Text>
               </View>
-            </GestureDetector>
-          </Animated.View>
+            </View>
+          </GestureDetector>
         </Animated.View>
       )}
     </GestureHandlerRootView>