about summary refs log tree commit diff
path: root/src/view/shell
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/shell')
-rw-r--r--src/view/shell/Composer.tsx5
-rw-r--r--src/view/shell/Composer.web.tsx2
-rw-r--r--src/view/shell/Drawer.tsx67
-rw-r--r--src/view/shell/bottom-bar/BottomBar.tsx35
-rw-r--r--src/view/shell/desktop/LeftNav.tsx62
-rw-r--r--src/view/shell/desktop/RightNav.tsx20
-rw-r--r--src/view/shell/desktop/Search.tsx8
-rw-r--r--src/view/shell/index.web.tsx4
8 files changed, 151 insertions, 52 deletions
diff --git a/src/view/shell/Composer.tsx b/src/view/shell/Composer.tsx
index e0a75090d..e87fea647 100644
--- a/src/view/shell/Composer.tsx
+++ b/src/view/shell/Composer.tsx
@@ -56,7 +56,10 @@ export const Composer = observer(
     }
 
     return (
-      <Animated.View style={[styles.wrapper, pal.view, wrapperAnimStyle]}>
+      <Animated.View
+        style={[styles.wrapper, pal.view, wrapperAnimStyle]}
+        aria-modal
+        accessibilityViewIsModal>
         <ComposePost
           replyTo={replyTo}
           onPost={onPost}
diff --git a/src/view/shell/Composer.web.tsx b/src/view/shell/Composer.web.tsx
index 0e5b82423..1f458472c 100644
--- a/src/view/shell/Composer.web.tsx
+++ b/src/view/shell/Composer.web.tsx
@@ -31,7 +31,7 @@ export const Composer = observer(
     }
 
     return (
-      <View style={styles.mask}>
+      <View style={styles.mask} aria-modal accessibilityViewIsModal>
         <View style={[styles.container, pal.view, pal.border]}>
           <ComposePost
             replyTo={replyTo}
diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx
index 81ee005c8..404374b95 100644
--- a/src/view/shell/Drawer.tsx
+++ b/src/view/shell/Drawer.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, {ComponentProps} from 'react'
 import {
   Linking,
   SafeAreaView,
@@ -50,6 +50,8 @@ export const DrawerContent = observer(() => {
   const {isAtHome, isAtSearch, isAtNotifications, isAtMyProfile} =
     useNavigationTabState()
 
+  const {notifications} = store.me
+
   // events
   // =
 
@@ -120,7 +122,11 @@ export const DrawerContent = observer(() => {
       ]}>
       <SafeAreaView style={s.flex1}>
         <View style={styles.main}>
-          <TouchableOpacity testID="profileCardButton" onPress={onPressProfile}>
+          <TouchableOpacity
+            testID="profileCardButton"
+            accessibilityLabel="Profile"
+            accessibilityHint="Navigates to your profile"
+            onPress={onPressProfile}>
             <UserAvatar size={80} avatar={store.me.avatar} />
             <Text
               type="title-lg"
@@ -164,6 +170,8 @@ export const DrawerContent = observer(() => {
               )
             }
             label="Search"
+            accessibilityLabel="Search"
+            accessibilityHint="Search through users and posts"
             bold={isAtSearch}
             onPress={onPressSearch}
           />
@@ -184,6 +192,8 @@ export const DrawerContent = observer(() => {
               )
             }
             label="Home"
+            accessibilityLabel="Home"
+            accessibilityHint="Navigates to default feed"
             bold={isAtHome}
             onPress={onPressHome}
           />
@@ -204,7 +214,13 @@ export const DrawerContent = observer(() => {
               )
             }
             label="Notifications"
-            count={store.me.notifications.unreadCountLabel}
+            accessibilityLabel={
+              notifications.unreadCountLabel === '1'
+                ? 'Notifications: 1 unread notification'
+                : `Notifications: ${notifications.unreadCountLabel} unread notifications`
+            }
+            accessibilityHint="Opens notification feed"
+            count={notifications.unreadCountLabel}
             bold={isAtNotifications}
             onPress={onPressNotifications}
           />
@@ -225,6 +241,8 @@ export const DrawerContent = observer(() => {
               )
             }
             label="Profile"
+            accessibilityLabel="Profile"
+            accessibilityHint="See profile display name, avatar, description, and other profile items"
             onPress={onPressProfile}
           />
           <MenuItem
@@ -236,6 +254,8 @@ export const DrawerContent = observer(() => {
               />
             }
             label="Settings"
+            accessibilityLabel="Settings"
+            accessibilityHint="Manage settings for your account, like handle, content moderation, and app passwords"
             onPress={onPressSettings}
           />
         </View>
@@ -243,6 +263,13 @@ export const DrawerContent = observer(() => {
         <View style={styles.footer}>
           {!isWeb && (
             <TouchableOpacity
+              accessibilityRole="button"
+              accessibilityLabel="Toggle dark mode"
+              accessibilityHint={
+                theme.colorScheme === 'dark'
+                  ? 'Sets display to light mode'
+                  : 'Sets display to dark mode'
+              }
               onPress={onDarkmodePress}
               style={[
                 styles.footerBtn,
@@ -258,6 +285,9 @@ export const DrawerContent = observer(() => {
             </TouchableOpacity>
           )}
           <TouchableOpacity
+            accessibilityRole="link"
+            accessibilityLabel="Send feedback"
+            accessibilityHint="Opens Google Forms feedback link"
             onPress={onPressFeedback}
             style={[
               styles.footerBtn,
@@ -281,25 +311,30 @@ export const DrawerContent = observer(() => {
   )
 })
 
+interface MenuItemProps extends ComponentProps<typeof TouchableOpacity> {
+  icon: JSX.Element
+  label: string
+  count?: string
+  bold?: boolean
+}
+
 function MenuItem({
   icon,
   label,
+  accessibilityLabel,
   count,
   bold,
   onPress,
-}: {
-  icon: JSX.Element
-  label: string
-  count?: string
-  bold?: boolean
-  onPress: () => void
-}) {
+}: MenuItemProps) {
   const pal = usePalette('default')
   return (
     <TouchableOpacity
       testID={`menuItemButton-${label}`}
       style={styles.menuItem}
-      onPress={onPress}>
+      onPress={onPress}
+      accessibilityRole="menuitem"
+      accessibilityLabel={accessibilityLabel}
+      accessibilityHint="">
       <View style={[styles.menuItemIconWrapper]}>
         {icon}
         {count ? (
@@ -332,6 +367,7 @@ const InviteCodes = observer(() => {
   const {track} = useAnalytics()
   const store = useStores()
   const pal = usePalette('default')
+  const {invitesAvailable} = store.me
   const onPress = React.useCallback(() => {
     track('Menu:ItemClicked', {url: '#invite-codes'})
     store.shell.closeDrawer()
@@ -341,7 +377,14 @@ const InviteCodes = observer(() => {
     <TouchableOpacity
       testID="menuItemInviteCodes"
       style={[styles.inviteCodes]}
-      onPress={onPress}>
+      onPress={onPress}
+      accessibilityRole="button"
+      accessibilityLabel={
+        invitesAvailable === 1
+          ? 'Invite codes: 1 available'
+          : `Invite codes: ${invitesAvailable} available`
+      }
+      accessibilityHint="Opens list of invite codes">
       <FontAwesomeIcon
         icon="ticket"
         style={[
diff --git a/src/view/shell/bottom-bar/BottomBar.tsx b/src/view/shell/bottom-bar/BottomBar.tsx
index a7d11d81d..b32072d5a 100644
--- a/src/view/shell/bottom-bar/BottomBar.tsx
+++ b/src/view/shell/bottom-bar/BottomBar.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, {ComponentProps} from 'react'
 import {
   Animated,
   GestureResponderEvent,
@@ -94,6 +94,8 @@ export const BottomBar = observer(({navigation}: BottomTabBarProps) => {
           )
         }
         onPress={onPressHome}
+        accessibilityLabel="Go home"
+        accessibilityHint="Navigates to feed home"
       />
       <Btn
         testID="bottomBarSearchBtn"
@@ -113,6 +115,7 @@ export const BottomBar = observer(({navigation}: BottomTabBarProps) => {
           )
         }
         onPress={onPressSearch}
+        accessibilityRole="search"
       />
       <Btn
         testID="bottomBarNotificationsBtn"
@@ -133,6 +136,8 @@ export const BottomBar = observer(({navigation}: BottomTabBarProps) => {
         }
         onPress={onPressNotifications}
         notificationCount={store.me.notifications.unreadCountLabel}
+        accessibilityLabel="Notifications"
+        accessibilityHint="Navigates to notifications"
       />
       <Btn
         testID="bottomBarProfileBtn"
@@ -154,31 +159,43 @@ export const BottomBar = observer(({navigation}: BottomTabBarProps) => {
           </View>
         }
         onPress={onPressProfile}
+        accessibilityLabel="Profile"
+        accessibilityHint="Navigates to profile"
       />
     </Animated.View>
   )
 })
 
+interface BtnProps
+  extends Pick<
+    ComponentProps<typeof TouchableOpacity>,
+    'accessibilityRole' | 'accessibilityHint' | 'accessibilityLabel'
+  > {
+  testID?: string
+  icon: JSX.Element
+  notificationCount?: string
+  onPress?: (event: GestureResponderEvent) => void
+  onLongPress?: (event: GestureResponderEvent) => void
+}
+
 function Btn({
   testID,
   icon,
   notificationCount,
   onPress,
   onLongPress,
-}: {
-  testID?: string
-  icon: JSX.Element
-  notificationCount?: string
-  onPress?: (event: GestureResponderEvent) => void
-  onLongPress?: (event: GestureResponderEvent) => void
-}) {
+  accessibilityHint,
+  accessibilityLabel,
+}: BtnProps) {
   return (
     <TouchableOpacity
       testID={testID}
       style={styles.ctrl}
       onPress={onLongPress ? onPress : undefined}
       onPressIn={onLongPress ? undefined : onPress}
-      onLongPress={onLongPress}>
+      onLongPress={onLongPress}
+      accessibilityLabel={accessibilityLabel}
+      accessibilityHint={accessibilityHint}>
       {notificationCount ? (
         <View style={[styles.notificationCount]}>
           <Text style={styles.notificationCountLabel}>{notificationCount}</Text>
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index b4b219023..86f1a3ef3 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -2,7 +2,11 @@ import React from 'react'
 import {observer} from 'mobx-react-lite'
 import {StyleSheet, TouchableOpacity, View} from 'react-native'
 import {PressableWithHover} from 'view/com/util/PressableWithHover'
-import {useNavigation, useNavigationState} from '@react-navigation/native'
+import {
+  useLinkProps,
+  useNavigation,
+  useNavigationState,
+} from '@react-navigation/native'
 import {
   FontAwesomeIcon,
   FontAwesomeIconStyle,
@@ -59,7 +63,10 @@ function BackBtn() {
     <TouchableOpacity
       testID="viewHeaderBackOrMenuBtn"
       onPress={onPressBack}
-      style={styles.backBtn}>
+      style={styles.backBtn}
+      accessibilityRole="button"
+      accessibilityLabel="Go back"
+      accessibilityHint="Navigates to the previous screen">
       <FontAwesomeIcon
         size={24}
         icon="angle-left"
@@ -86,25 +93,28 @@ const NavItem = observer(
       }
       return getCurrentRoute(state).name
     })
+
     const isCurrent = isTab(currentRouteName, pathName)
+    const {onPress} = useLinkProps({to: href})
 
     return (
       <PressableWithHover
         style={styles.navItemWrapper}
-        hoverStyle={pal.viewLight}>
-        <Link href={href} style={styles.navItem}>
-          <View style={[styles.navItemIconWrapper]}>
-            {isCurrent ? iconFilled : icon}
-            {typeof count === 'string' && count ? (
-              <Text type="button" style={styles.navItemCount}>
-                {count}
-              </Text>
-            ) : null}
-          </View>
-          <Text type="title" style={[isCurrent ? s.bold : s.normal, pal.text]}>
-            {label}
-          </Text>
-        </Link>
+        hoverStyle={pal.viewLight}
+        onPress={onPress}
+        accessibilityLabel={label}
+        accessibilityHint={`Navigates to ${label}`}>
+        <View style={[styles.navItemIconWrapper]}>
+          {isCurrent ? iconFilled : icon}
+          {typeof count === 'string' && count ? (
+            <Text type="button" style={styles.navItemCount}>
+              {count}
+            </Text>
+          ) : null}
+        </View>
+        <Text type="title" style={[isCurrent ? s.bold : s.normal, pal.text]}>
+          {label}
+        </Text>
       </PressableWithHover>
     )
   },
@@ -115,7 +125,12 @@ function ComposeBtn() {
   const onPressCompose = () => store.shell.openComposer({})
 
   return (
-    <TouchableOpacity style={[styles.newPostBtn]} onPress={onPressCompose}>
+    <TouchableOpacity
+      style={[styles.newPostBtn]}
+      onPress={onPressCompose}
+      accessibilityRole="button"
+      accessibilityLabel="New post"
+      accessibilityHint="Opens post composer">
       <View style={styles.newPostBtnIconWrapper}>
         <ComposeIcon2
           size={19}
@@ -202,7 +217,7 @@ const styles = StyleSheet.create({
 
   profileCard: {
     marginVertical: 10,
-    width: 60,
+    width: 90,
     paddingLeft: 12,
   },
 
@@ -215,21 +230,18 @@ const styles = StyleSheet.create({
   },
 
   navItemWrapper: {
-    paddingHorizontal: 12,
-    borderRadius: 8,
-  },
-  navItem: {
     flexDirection: 'row',
     alignItems: 'center',
-    paddingTop: 12,
-    paddingBottom: 12,
+    paddingHorizontal: 12,
+    padding: 12,
+    borderRadius: 8,
+    gap: 10,
   },
   navItemIconWrapper: {
     alignItems: 'center',
     justifyContent: 'center',
     width: 28,
     height: 28,
-    marginRight: 10,
     marginTop: 2,
   },
   navItemCount: {
diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx
index 7a3388f88..142f01163 100644
--- a/src/view/shell/desktop/RightNav.tsx
+++ b/src/view/shell/desktop/RightNav.tsx
@@ -61,7 +61,14 @@ export const DesktopRightNav = observer(function DesktopRightNav() {
       <View>
         <TouchableOpacity
           style={[styles.darkModeToggle]}
-          onPress={onDarkmodePress}>
+          onPress={onDarkmodePress}
+          accessibilityRole="button"
+          accessibilityLabel="Toggle dark mode"
+          accessibilityHint={
+            mode === 'Dark'
+              ? 'Sets display to light mode'
+              : 'Sets display to dark mode'
+          }>
           <View style={[pal.viewLight, styles.darkModeToggleIcon]}>
             <MoonIcon size={18} style={pal.textLight} />
           </View>
@@ -78,13 +85,22 @@ const InviteCodes = observer(() => {
   const store = useStores()
   const pal = usePalette('default')
 
+  const {invitesAvailable} = store.me
+
   const onPress = React.useCallback(() => {
     store.shell.openModal({name: 'invite-codes'})
   }, [store])
   return (
     <TouchableOpacity
       style={[styles.inviteCodes, pal.border]}
-      onPress={onPress}>
+      onPress={onPress}
+      accessibilityRole="button"
+      accessibilityLabel={
+        invitesAvailable === 1
+          ? 'Invite codes: 1 available'
+          : `Invite codes: ${invitesAvailable} available`
+      }
+      accessibilityHint="Opens list of invite codes">
       <FontAwesomeIcon
         icon="ticket"
         style={[
diff --git a/src/view/shell/desktop/Search.tsx b/src/view/shell/desktop/Search.tsx
index 5504e9415..a58a68fbf 100644
--- a/src/view/shell/desktop/Search.tsx
+++ b/src/view/shell/desktop/Search.tsx
@@ -67,10 +67,16 @@ export const DesktopSearch = observer(function DesktopSearch() {
             onBlur={() => setIsInputFocused(false)}
             onChangeText={onChangeQuery}
             onSubmitEditing={onSubmit}
+            accessibilityRole="search"
           />
           {query ? (
             <View style={styles.cancelBtn}>
-              <TouchableOpacity onPress={onPressCancelSearch}>
+              <TouchableOpacity
+                onPress={onPressCancelSearch}
+                accessibilityRole="button"
+                accessibilityLabel="Cancel search"
+                accessibilityHint="Exits inputting search query"
+                onAccessibilityEscape={onPressCancelSearch}>
                 <Text type="lg" style={[pal.link]}>
                   Cancel
                 </Text>
diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx
index 3d790febc..349376436 100644
--- a/src/view/shell/index.web.tsx
+++ b/src/view/shell/index.web.tsx
@@ -46,7 +46,9 @@ const ShellInner = observer(() => {
       {!isDesktop && store.shell.isDrawerOpen && (
         <TouchableOpacity
           onPress={() => store.shell.closeDrawer()}
-          style={styles.drawerMask}>
+          style={styles.drawerMask}
+          accessibilityLabel="Close navigation footer"
+          accessibilityHint="Closes bottom navigation bar">
           <View style={styles.drawerContainer}>
             <DrawerContent />
           </View>