diff options
Diffstat (limited to 'src/view/shell')
-rw-r--r-- | src/view/shell/Composer.tsx | 5 | ||||
-rw-r--r-- | src/view/shell/Composer.web.tsx | 2 | ||||
-rw-r--r-- | src/view/shell/Drawer.tsx | 67 | ||||
-rw-r--r-- | src/view/shell/bottom-bar/BottomBar.tsx | 35 | ||||
-rw-r--r-- | src/view/shell/desktop/LeftNav.tsx | 62 | ||||
-rw-r--r-- | src/view/shell/desktop/RightNav.tsx | 20 | ||||
-rw-r--r-- | src/view/shell/desktop/Search.tsx | 8 | ||||
-rw-r--r-- | src/view/shell/index.web.tsx | 4 |
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> |