about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2022-10-11 15:16:46 -0500
committerPaul Frazee <pfrazee@gmail.com>2022-10-11 15:16:46 -0500
commitc9388a3cc536d1c276d5b83c0378371356bd594c (patch)
tree3d4891d4f7f0c883493b7de00ae066baa006e12f
parentd7a75a206281b99ad38fea576aa20a0557fd3d65 (diff)
downloadvoidsky-c9388a3cc536d1c276d5b83c0378371356bd594c.tar.zst
Improve main menu (animation, aesthetics)
-rw-r--r--src/view/index.ts4
-rw-r--r--src/view/shell/mobile/MainMenu.tsx173
2 files changed, 93 insertions, 84 deletions
diff --git a/src/view/index.ts b/src/view/index.ts
index 7dc8b4cb1..fb63f5650 100644
--- a/src/view/index.ts
+++ b/src/view/index.ts
@@ -1,5 +1,6 @@
 import {library} from '@fortawesome/fontawesome-svg-core'
 
+import {faAddressCard} from '@fortawesome/free-regular-svg-icons/faAddressCard'
 import {faAngleDown} from '@fortawesome/free-solid-svg-icons/faAngleDown'
 import {faAngleLeft} from '@fortawesome/free-solid-svg-icons/faAngleLeft'
 import {faAngleRight} from '@fortawesome/free-solid-svg-icons/faAngleRight'
@@ -15,6 +16,7 @@ import {faBell as farBell} from '@fortawesome/free-regular-svg-icons/faBell'
 import {faBookmark} from '@fortawesome/free-solid-svg-icons/faBookmark'
 import {faBookmark as farBookmark} from '@fortawesome/free-regular-svg-icons/faBookmark'
 import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'
+import {faCircleUser} from '@fortawesome/free-regular-svg-icons/faCircleUser'
 import {faClone} from '@fortawesome/free-regular-svg-icons/faClone'
 import {faComment} from '@fortawesome/free-regular-svg-icons/faComment'
 import {faEllipsis} from '@fortawesome/free-solid-svg-icons/faEllipsis'
@@ -48,6 +50,7 @@ import {faX} from '@fortawesome/free-solid-svg-icons/faX'
 
 export function setup() {
   library.add(
+    faAddressCard,
     faAngleDown,
     faAngleLeft,
     faAngleRight,
@@ -63,6 +66,7 @@ export function setup() {
     faBookmark,
     farBookmark,
     faCheck,
+    faCircleUser,
     faClone,
     faComment,
     faEllipsis,
diff --git a/src/view/shell/mobile/MainMenu.tsx b/src/view/shell/mobile/MainMenu.tsx
index 3efef3c28..60f7d3ce3 100644
--- a/src/view/shell/mobile/MainMenu.tsx
+++ b/src/view/shell/mobile/MainMenu.tsx
@@ -1,23 +1,45 @@
-import React from 'react'
+import React, {useEffect} from 'react'
 import {observer} from 'mobx-react-lite'
 import {
   Image,
   StyleSheet,
+  SafeAreaView,
   Text,
   TouchableOpacity,
   TouchableWithoutFeedback,
   View,
 } from 'react-native'
+import Animated, {
+  useSharedValue,
+  useAnimatedStyle,
+  withTiming,
+  interpolate,
+} from 'react-native-reanimated'
 import {IconProp} from '@fortawesome/fontawesome-svg-core'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import LinearGradient from 'react-native-linear-gradient'
+import {HomeIcon} from '../../lib/icons'
 import {useStores} from '../../../state'
-import {s, colors, gradients} from '../../lib/styles'
+import {s, colors} from '../../lib/styles'
 import {DEF_AVATER} from '../../lib/assets'
 
 export const MainMenu = observer(
   ({active, onClose}: {active: boolean; onClose: () => void}) => {
     const store = useStores()
+    const initInterp = useSharedValue<number>(0)
+
+    useEffect(() => {
+      if (active) {
+        initInterp.value = withTiming(1, {duration: 150})
+      } else {
+        initInterp.value = 0
+      }
+    }, [initInterp, active])
+    const wrapperAnimStyle = useAnimatedStyle(() => ({
+      opacity: interpolate(initInterp.value, [0, 1.0], [0, 1.0]),
+    }))
+    const menuItemsAnimStyle = useAnimatedStyle(() => ({
+      marginTop: interpolate(initInterp.value, [0, 1.0], [15, 0]),
+    }))
 
     // events
     // =
@@ -30,32 +52,30 @@ export const MainMenu = observer(
     // rendering
     // =
 
-    const FatMenuItem = ({
+    const MenuItem = ({
       icon,
       label,
       url,
-      gradient,
     }: {
       icon: IconProp
       label: string
       url: string
-      gradient: keyof typeof gradients
     }) => (
       <TouchableOpacity
-        style={[styles.fatMenuItem, styles.fatMenuItemMargin]}
+        style={[styles.menuItem, styles.menuItemMargin]}
         onPress={() => onNavigate(url)}>
-        <LinearGradient
-          style={[styles.fatMenuItemIconWrapper]}
-          colors={[gradients[gradient].start, gradients[gradient].end]}
-          start={{x: 0, y: 0}}
-          end={{x: 1, y: 1}}>
-          <FontAwesomeIcon
-            icon={icon}
-            style={styles.fatMenuItemIcon}
-            size={24}
-          />
-        </LinearGradient>
-        <Text style={styles.fatMenuItemLabel} numberOfLines={1}>
+        <View style={[styles.menuItemIconWrapper]}>
+          {icon === 'home' ? (
+            <HomeIcon style={styles.menuItemIcon} size={24} />
+          ) : (
+            <FontAwesomeIcon
+              icon={icon}
+              style={styles.menuItemIcon}
+              size={24}
+            />
+          )}
+        </View>
+        <Text style={styles.menuItemLabel} numberOfLines={1}>
           {label}
         </Text>
       </TouchableOpacity>
@@ -69,50 +89,45 @@ export const MainMenu = observer(
         <TouchableWithoutFeedback onPress={onClose}>
           <View style={styles.bg} />
         </TouchableWithoutFeedback>
-        <View style={styles.wrapper}>
-          <View style={[styles.topSection]}>
-            <TouchableOpacity
-              style={styles.profile}
-              onPress={() => onNavigate(`/profile/${store.me.name || ''}`)}>
-              <Image style={styles.profileImage} source={DEF_AVATER} />
-              <Text style={styles.profileText} numberOfLines={1}>
-                {store.me.displayName || store.me.name || 'My profile'}
-              </Text>
-            </TouchableOpacity>
-            <View style={[s.flex1]} />
-            <TouchableOpacity
-              style={styles.settings}
-              onPress={() => onNavigate(`/settings`)}>
-              <FontAwesomeIcon
-                icon="gear"
-                style={styles.settingsIcon}
-                size={24}
-              />
-            </TouchableOpacity>
-          </View>
-          <View style={[styles.section]}>
-            <View style={styles.fatMenuItems}>
-              <FatMenuItem
-                icon="house"
-                label="Feed"
-                url="/"
-                gradient="primary"
-              />
-              <FatMenuItem
-                icon="bell"
-                label="Notifications"
-                url="/notifications"
-                gradient="purple"
-              />
-              <FatMenuItem
-                icon="gear"
-                label="Settings"
-                url="/settings"
-                gradient="blue"
-              />
+        <Animated.View style={[styles.wrapper, wrapperAnimStyle]}>
+          <SafeAreaView>
+            <View style={[styles.topSection]}>
+              <TouchableOpacity
+                style={styles.profile}
+                onPress={() => onNavigate(`/profile/${store.me.name || ''}`)}>
+                <Image style={styles.profileImage} source={DEF_AVATER} />
+                <Text style={styles.profileText} numberOfLines={1}>
+                  {store.me.displayName || store.me.name || 'My profile'}
+                </Text>
+              </TouchableOpacity>
+              <View style={[s.flex1]} />
+              <TouchableOpacity
+                style={styles.settings}
+                onPress={() => onNavigate(`/settings`)}>
+                <FontAwesomeIcon
+                  icon="gear"
+                  style={styles.settingsIcon}
+                  size={24}
+                />
+              </TouchableOpacity>
             </View>
-          </View>
-        </View>
+            <View style={[styles.section]}>
+              <Animated.View style={[styles.menuItems, menuItemsAnimStyle]}>
+                <MenuItem icon="home" label="Home" url="/" />
+                <MenuItem
+                  icon={['far', 'circle-user']}
+                  label="Contacts"
+                  url="/contacts"
+                />
+                <MenuItem
+                  icon={['far', 'bell']}
+                  label="Notifications"
+                  url="/notifications"
+                />
+              </Animated.View>
+            </View>
+          </SafeAreaView>
+        </Animated.View>
       </>
     )
   },
@@ -125,23 +140,22 @@ const styles = StyleSheet.create({
     right: 0,
     bottom: 0,
     left: 0,
-    backgroundColor: '#000',
-    opacity: 0.2,
+    // backgroundColor: '#000',
+    opacity: 0,
   },
   wrapper: {
     position: 'absolute',
+    top: 0,
     bottom: 75,
     width: '100%',
     backgroundColor: '#fff',
-    borderRadius: 8,
-    opacity: 1,
-    paddingVertical: 10,
   },
 
   topSection: {
     flexDirection: 'row',
     alignItems: 'center',
     paddingHorizontal: 10,
+    paddingBottom: 10,
   },
   section: {
     paddingHorizontal: 10,
@@ -170,41 +184,32 @@ const styles = StyleSheet.create({
     marginRight: 10,
   },
 
-  fatMenuItems: {
+  menuItems: {
     flexDirection: 'row',
     marginTop: 10,
     marginBottom: 10,
   },
-  fatMenuItem: {
+  menuItem: {
     width: 80,
     alignItems: 'center',
     marginRight: 6,
   },
-  fatMenuItemMargin: {
+  menuItemMargin: {
     marginRight: 14,
   },
-  fatMenuItemIconWrapper: {
+  menuItemIconWrapper: {
     borderRadius: 6,
     width: 60,
     height: 60,
     justifyContent: 'center',
     alignItems: 'center',
     marginBottom: 5,
-    shadowColor: '#000',
-    shadowOpacity: 0.2,
-    shadowOffset: {width: 0, height: 2},
-    shadowRadius: 2,
+    backgroundColor: colors.gray1,
   },
-  fatMenuItemIcon: {
-    color: colors.white,
-  },
-  fatMenuImage: {
-    borderRadius: 30,
-    width: 60,
-    height: 60,
-    marginBottom: 5,
+  menuItemIcon: {
+    color: colors.gray5,
   },
-  fatMenuItemLabel: {
+  menuItemLabel: {
     fontSize: 13,
   },
 })