about summary refs log tree commit diff
path: root/src/view/com/util/Toast.web.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/util/Toast.web.tsx')
-rw-r--r--src/view/com/util/Toast.web.tsx118
1 files changed, 97 insertions, 21 deletions
diff --git a/src/view/com/util/Toast.web.tsx b/src/view/com/util/Toast.web.tsx
index d3b7bda33..6b99b30bf 100644
--- a/src/view/com/util/Toast.web.tsx
+++ b/src/view/com/util/Toast.web.tsx
@@ -4,17 +4,23 @@
 
 import {useEffect, useState} from 'react'
 import {Pressable, StyleSheet, Text, View} from 'react-native'
+
 import {
-  FontAwesomeIcon,
-  type FontAwesomeIconStyle,
-  type Props as FontAwesomeProps,
-} from '@fortawesome/react-native-fontawesome'
+  convertLegacyToastType,
+  getToastTypeStyles,
+  getToastWebAnimationStyles,
+  type LegacyToastType,
+  TOAST_TYPE_TO_ICON,
+  TOAST_WEB_KEYFRAMES,
+  type ToastType,
+} from '#/view/com/util/Toast.style'
+import {atoms as a, useTheme} from '#/alf'
 
 const DURATION = 3500
 
 interface ActiveToast {
   text: string
-  icon: FontAwesomeProps['icon']
+  type: ToastType
 }
 type GlobalSetActiveToast = (_activeToast: ActiveToast | undefined) => void
 
@@ -28,21 +34,82 @@ let toastTimeout: NodeJS.Timeout | undefined
 type ToastContainerProps = {}
 export const ToastContainer: React.FC<ToastContainerProps> = ({}) => {
   const [activeToast, setActiveToast] = useState<ActiveToast | undefined>()
+  const [isExiting, setIsExiting] = useState(false)
+
   useEffect(() => {
     globalSetActiveToast = (t: ActiveToast | undefined) => {
-      setActiveToast(t)
+      if (!t && activeToast) {
+        setIsExiting(true)
+        setTimeout(() => {
+          setActiveToast(t)
+          setIsExiting(false)
+        }, 200)
+      } else {
+        setActiveToast(t)
+        setIsExiting(false)
+      }
+    }
+  }, [activeToast])
+
+  useEffect(() => {
+    const styleId = 'toast-animations'
+    if (!document.getElementById(styleId)) {
+      const style = document.createElement('style')
+      style.id = styleId
+      style.textContent = TOAST_WEB_KEYFRAMES
+      document.head.appendChild(style)
     }
-  })
+  }, [])
+
+  const t = useTheme()
+
+  const toastTypeStyles = getToastTypeStyles(t)
+  const toastStyles = activeToast
+    ? toastTypeStyles[activeToast.type]
+    : toastTypeStyles.default
+
+  const IconComponent = activeToast
+    ? TOAST_TYPE_TO_ICON[activeToast.type]
+    : TOAST_TYPE_TO_ICON.default
+
+  const animationStyles = getToastWebAnimationStyles()
+
   return (
     <>
       {activeToast && (
-        <View style={styles.container}>
-          <FontAwesomeIcon
-            icon={activeToast.icon}
-            size={20}
-            style={styles.icon as FontAwesomeIconStyle}
-          />
-          <Text style={styles.text}>{activeToast.text}</Text>
+        <View
+          style={[
+            styles.container,
+            {
+              backgroundColor: toastStyles.backgroundColor,
+              borderColor: toastStyles.borderColor,
+              ...(isExiting
+                ? animationStyles.exiting
+                : animationStyles.entering),
+            },
+          ]}>
+          <View
+            style={[
+              styles.iconContainer,
+              {
+                backgroundColor: 'transparent',
+              },
+            ]}>
+            <IconComponent
+              fill={toastStyles.iconColor}
+              size="sm"
+              style={styles.icon}
+            />
+          </View>
+          <Text
+            style={[
+              styles.text,
+              a.text_sm,
+              a.font_bold,
+              {color: toastStyles.textColor},
+            ]}>
+            {activeToast.text}
+          </Text>
           <Pressable
             style={styles.dismissBackdrop}
             accessibilityLabel="Dismiss"
@@ -60,11 +127,15 @@ export const ToastContainer: React.FC<ToastContainerProps> = ({}) => {
 // methods
 // =
 
-export function show(text: string, icon: FontAwesomeProps['icon'] = 'check') {
+export function show(
+  text: string,
+  type: ToastType | LegacyToastType = 'default',
+) {
   if (toastTimeout) {
     clearTimeout(toastTimeout)
   }
-  globalSetActiveToast?.({text, icon})
+
+  globalSetActiveToast?.({text, type: convertLegacyToastType(type)})
   toastTimeout = setTimeout(() => {
     globalSetActiveToast?.(undefined)
   }, DURATION)
@@ -78,12 +149,12 @@ const styles = StyleSheet.create({
     bottom: 20,
     // @ts-ignore web only
     width: 'calc(100% - 40px)',
-    maxWidth: 350,
+    maxWidth: 380,
     padding: 20,
     flexDirection: 'row',
     alignItems: 'center',
-    backgroundColor: '#000c',
     borderRadius: 10,
+    borderWidth: 1,
   },
   dismissBackdrop: {
     position: 'absolute',
@@ -92,13 +163,18 @@ const styles = StyleSheet.create({
     bottom: 0,
     right: 0,
   },
+  iconContainer: {
+    width: 32,
+    height: 32,
+    borderRadius: 16,
+    alignItems: 'center',
+    justifyContent: 'center',
+    flexShrink: 0,
+  },
   icon: {
-    color: '#fff',
     flexShrink: 0,
   },
   text: {
-    color: '#fff',
-    fontSize: 18,
     marginLeft: 10,
   },
 })