diff options
author | Ollie Hsieh <renahlee@outlook.com> | 2023-04-19 18:05:10 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-19 20:05:10 -0500 |
commit | b24ba3adc93cf940eb936309ae73a2c205eaef24 (patch) | |
tree | 373337a5f364fd1d83010c33bae3d878437d4ca7 /src/view | |
parent | 1472bd4f173a483e5f1a91514244fecaec23808f (diff) | |
download | voidsky-b24ba3adc93cf940eb936309ae73a2c205eaef24.tar.zst |
Add cursor to clickable elements (#491)
* Add cursor to clickable elements * Add cursor to clickable elements * Update per comments * Fix word wrap in notifications * Center the web login-load screen * Add hover states on web * Fix lint --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Diffstat (limited to 'src/view')
-rw-r--r-- | src/view/com/auth/withAuthRequired.tsx | 7 | ||||
-rw-r--r-- | src/view/com/notifications/FeedItem.tsx | 132 | ||||
-rw-r--r-- | src/view/com/pager/TabBar.tsx | 40 | ||||
-rw-r--r-- | src/view/com/profile/ProfileCard.tsx | 1 | ||||
-rw-r--r-- | src/view/com/profile/ProfileHeader.tsx | 9 | ||||
-rw-r--r-- | src/view/com/util/PressableWithHover.tsx | 45 | ||||
-rw-r--r-- | src/view/com/util/Selector.tsx | 11 | ||||
-rw-r--r-- | src/view/com/util/moderation/ContentHider.tsx | 2 | ||||
-rw-r--r-- | src/view/screens/SearchMobile.tsx | 36 | ||||
-rw-r--r-- | src/view/shell/desktop/LeftNav.tsx | 43 |
10 files changed, 184 insertions, 142 deletions
diff --git a/src/view/com/auth/withAuthRequired.tsx b/src/view/com/auth/withAuthRequired.tsx index 6073a4f80..a3f021277 100644 --- a/src/view/com/auth/withAuthRequired.tsx +++ b/src/view/com/auth/withAuthRequired.tsx @@ -1,7 +1,8 @@ import React from 'react' -import {ActivityIndicator, StyleSheet, View} from 'react-native' +import {ActivityIndicator, StyleSheet} from 'react-native' import {observer} from 'mobx-react-lite' import {useStores} from 'state/index' +import {CenteredView} from '../util/Views' import {LoggedOut} from './LoggedOut' import {Text} from '../util/text/Text' import {usePalette} from 'lib/hooks/usePalette' @@ -30,14 +31,14 @@ function Loading() { }, [setIsTakingTooLong]) return ( - <View style={[styles.loading, pal.view]}> + <CenteredView style={[styles.loading, pal.view]}> <ActivityIndicator size="large" /> <Text type="2xl" style={[styles.loadingText, pal.textLight]}> {isTakingTooLong ? "This is taking too long. There may be a problem with your internet or with the service, but we're going to try a couple more times..." : 'Connecting...'} </Text> - </View> + </CenteredView> ) } diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx index fd9f2324b..34df2a8ed 100644 --- a/src/view/com/notifications/FeedItem.tsx +++ b/src/view/com/notifications/FeedItem.tsx @@ -3,7 +3,7 @@ import {observer} from 'mobx-react-lite' import { Animated, TouchableOpacity, - TouchableWithoutFeedback, + Pressable, StyleSheet, View, } from 'react-native' @@ -124,7 +124,7 @@ export const FeedItem = observer(function FeedItem({ return <></> } - let authors: Author[] = [ + const authors: Author[] = [ { href: `/profile/${item.author.handle}`, handle: item.author.handle, @@ -132,18 +132,18 @@ export const FeedItem = observer(function FeedItem({ avatar: item.author.avatar, labels: item.author.labels, }, + ...(item.additional?.map( + ({author: {avatar, labels, handle, displayName}}) => { + return { + href: `/profile/${handle}`, + handle, + displayName, + avatar, + labels, + } + }, + ) || []), ] - if (item.additional?.length) { - authors = authors.concat( - item.additional.map(item2 => ({ - href: `/profile/${item2.author.handle}`, - handle: item2.author.handle, - displayName: item2.author.displayName, - avatar: item2.author.avatar, - labels: item2.author.labels, - })), - ) - } return ( <Link @@ -161,62 +161,52 @@ export const FeedItem = observer(function FeedItem({ href={itemHref} title={itemTitle} noFeedback> - <View style={styles.layout}> - <View style={styles.layoutIcon}> - {icon === 'HeartIconSolid' ? ( - <HeartIconSolid size={28} style={[styles.icon, ...iconStyle]} /> - ) : ( - <FontAwesomeIcon - icon={icon} - size={24} - style={[styles.icon, ...iconStyle]} + <View style={styles.layoutIcon}> + {icon === 'HeartIconSolid' ? ( + <HeartIconSolid size={28} style={[styles.icon, ...iconStyle]} /> + ) : ( + <FontAwesomeIcon + icon={icon} + size={24} + style={[styles.icon, ...iconStyle]} + /> + )} + </View> + <View style={styles.layoutContent}> + <Pressable + onPress={authors.length > 1 ? onToggleAuthorsExpanded : () => {}}> + <CondensedAuthorsList + visible={!isAuthorsExpanded} + authors={authors} + onToggleAuthorsExpanded={onToggleAuthorsExpanded} + /> + <ExpandedAuthorsList visible={isAuthorsExpanded} authors={authors} /> + <View style={styles.meta}> + <TextLink + key={authors[0].href} + style={[pal.text, s.bold, styles.metaItem]} + href={authors[0].href} + text={sanitizeDisplayName( + authors[0].displayName || authors[0].handle, + )} /> - )} - </View> - <View style={styles.layoutContent}> - <TouchableWithoutFeedback - onPress={authors.length > 1 ? onToggleAuthorsExpanded : () => {}}> - <View> - <CondensedAuthorsList - visible={!isAuthorsExpanded} - authors={authors} - onToggleAuthorsExpanded={onToggleAuthorsExpanded} - /> - <ExpandedAuthorsList - visible={isAuthorsExpanded} - authors={authors} - /> - <View style={styles.meta}> - <TextLink - key={authors[0].href} - style={[pal.text, s.bold, styles.metaItem]} - href={authors[0].href} - text={sanitizeDisplayName( - authors[0].displayName || authors[0].handle, - )} - /> - {authors.length > 1 ? ( - <> - <Text style={[styles.metaItem, pal.text]}>and</Text> - <Text style={[styles.metaItem, pal.text, s.bold]}> - {authors.length - 1}{' '} - {pluralize(authors.length - 1, 'other')} - </Text> - </> - ) : undefined} - <Text style={[styles.metaItem, pal.text]}>{action}</Text> - <Text style={[styles.metaItem, pal.textLight]}> - {ago(item.indexedAt)} + {authors.length > 1 ? ( + <> + <Text style={[styles.metaItem, pal.text]}>and</Text> + <Text style={[styles.metaItem, pal.text, s.bold]}> + {authors.length - 1} {pluralize(authors.length - 1, 'other')} </Text> - </View> - </View> - </TouchableWithoutFeedback> - {item.isLike || item.isRepost || item.isQuote ? ( - <AdditionalPostText additionalPost={item.additionalPost} /> - ) : ( - <></> - )} - </View> + </> + ) : undefined} + <Text style={[styles.metaItem, pal.text]}>{action}</Text> + <Text style={[styles.metaItem, pal.textLight]}> + {ago(item.indexedAt)} + </Text> + </View> + </Pressable> + {item.isLike || item.isRepost || item.isQuote ? ( + <AdditionalPostText additionalPost={item.additionalPost} /> + ) : null} </View> </Link> ) @@ -392,8 +382,6 @@ const styles = StyleSheet.create({ padding: 10, paddingRight: 15, borderTopWidth: 1, - }, - layout: { flexDirection: 'row', }, layoutIcon: { @@ -405,6 +393,9 @@ const styles = StyleSheet.create({ marginRight: 10, marginTop: 4, }, + layoutContent: { + flex: 1, + }, avis: { flexDirection: 'row', alignItems: 'center', @@ -413,9 +404,6 @@ const styles = StyleSheet.create({ fontWeight: 'bold', paddingLeft: 6, }, - layoutContent: { - flex: 1, - }, meta: { flexDirection: 'row', flexWrap: 'wrap', diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx index 8f3951e7b..628128e8f 100644 --- a/src/view/com/pager/TabBar.tsx +++ b/src/view/com/pager/TabBar.tsx @@ -1,11 +1,7 @@ import React, {createRef, useState, useMemo, useRef} from 'react' -import { - Animated, - StyleSheet, - TouchableWithoutFeedback, - View, -} from 'react-native' +import {Animated, StyleSheet, View} from 'react-native' import {Text} from '../util/text/Text' +import {PressableWithHover} from '../util/PressableWithHover' import {usePalette} from 'lib/hooks/usePalette' import {isDesktopWeb} from 'platform/detection' @@ -109,20 +105,21 @@ export function TabBar({ {items.map((item, i) => { const selected = i === selectedPage return ( - <TouchableWithoutFeedback - key={i} - testID={testID ? `${testID}-${item}` : undefined} + <PressableWithHover + ref={itemRefs[i]} + key={item} + style={ + indicatorPosition === 'top' ? styles.itemTop : styles.itemBottom + } + hoverStyle={pal.viewLight} onPress={() => onPressItem(i)}> - <View - style={ - indicatorPosition === 'top' ? styles.itemTop : styles.itemBottom - } - ref={itemRefs[i]}> - <Text type="xl-bold" style={selected ? pal.text : pal.textLight}> - {item} - </Text> - </View> - </TouchableWithoutFeedback> + <Text + type="xl-bold" + testID={testID ? `${testID}-${item}` : undefined} + style={selected ? pal.text : pal.textLight}> + {item} + </Text> + </PressableWithHover> ) })} </View> @@ -138,18 +135,19 @@ const styles = isDesktopWeb itemTop: { paddingTop: 16, paddingBottom: 14, - marginRight: 24, + paddingHorizontal: 12, }, itemBottom: { paddingTop: 14, paddingBottom: 16, - marginRight: 24, + paddingHorizontal: 12, }, indicator: { position: 'absolute', left: 0, width: 1, height: 3, + zIndex: 1, }, }) : StyleSheet.create({ diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index d14d5e16d..07bf4e291 100644 --- a/src/view/com/profile/ProfileCard.tsx +++ b/src/view/com/profile/ProfileCard.tsx @@ -48,7 +48,6 @@ export function ProfileCard({ ]} href={`/profile/${handle}`} title={handle} - noFeedback asAnchor> <View style={styles.layout}> <View style={styles.layoutAvi}> diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 101b6b833..4c232a13a 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -64,7 +64,7 @@ export const ProfileHeader = observer( <View style={[styles.buttonsLine]}> <LoadingPlaceholder width={100} height={31} style={styles.br50} /> </View> - <View style={styles.displayNameLine}> + <View> <Text type="title-2xl" style={[pal.text, styles.title]}> {sanitizeDisplayName(view.displayName || view.handle)} </Text> @@ -273,7 +273,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoaded({ </DropdownButton> ) : undefined} </View> - <View style={styles.displayNameLine}> + <View> <Text testID="profileHeaderDisplayName" type="title-2xl" @@ -431,11 +431,6 @@ const styles = StyleSheet.create({ borderRadius: 50, marginLeft: 6, }, - - displayNameLine: { - // paddingLeft: 86, - // marginBottom: 14, - }, title: {lineHeight: 38}, handleLine: { diff --git a/src/view/com/util/PressableWithHover.tsx b/src/view/com/util/PressableWithHover.tsx new file mode 100644 index 000000000..09ccb6a2d --- /dev/null +++ b/src/view/com/util/PressableWithHover.tsx @@ -0,0 +1,45 @@ +import React, { + useState, + useCallback, + PropsWithChildren, + forwardRef, + Ref, +} from 'react' +import {Pressable, PressableProps, StyleProp, ViewStyle} from 'react-native' +import {addStyle} from 'lib/styles' + +interface PressableWithHover extends PressableProps { + hoverStyle: StyleProp<ViewStyle> +} + +export const PressableWithHover = forwardRef( + ( + { + children, + style, + hoverStyle, + ...props + }: PropsWithChildren<PressableWithHover>, + ref: Ref<any>, + ) => { + const [isHovering, setIsHovering] = useState(false) + + const onHoverIn = useCallback(() => setIsHovering(true), [setIsHovering]) + const onHoverOut = useCallback(() => setIsHovering(false), [setIsHovering]) + style = + typeof style !== 'function' && isHovering + ? addStyle(style, hoverStyle) + : style + + return ( + <Pressable + {...props} + style={style} + onHoverIn={onHoverIn} + onHoverOut={onHoverOut} + ref={ref}> + {children} + </Pressable> + ) + }, +) diff --git a/src/view/com/util/Selector.tsx b/src/view/com/util/Selector.tsx index 03db13bd1..872b78184 100644 --- a/src/view/com/util/Selector.tsx +++ b/src/view/com/util/Selector.tsx @@ -1,10 +1,5 @@ import React, {createRef, useState, useMemo, useRef} from 'react' -import { - Animated, - StyleSheet, - TouchableWithoutFeedback, - View, -} from 'react-native' +import {Animated, Pressable, StyleSheet, View} from 'react-native' import {Text} from './text/Text' import {usePalette} from 'lib/hooks/usePalette' @@ -99,7 +94,7 @@ export function Selector({ {items.map((item, i) => { const selected = i === selectedIndex return ( - <TouchableWithoutFeedback key={i} onPress={() => onPressItem(i)}> + <Pressable key={item} onPress={() => onPressItem(i)}> <View style={styles.item} ref={itemRefs[i]}> <Text style={ @@ -110,7 +105,7 @@ export function Selector({ {item} </Text> </View> - </TouchableWithoutFeedback> + </Pressable> ) })} </View> diff --git a/src/view/com/util/moderation/ContentHider.tsx b/src/view/com/util/moderation/ContentHider.tsx index c1512171d..42a97cd34 100644 --- a/src/view/com/util/moderation/ContentHider.tsx +++ b/src/view/com/util/moderation/ContentHider.tsx @@ -40,7 +40,7 @@ export function ContentHider({ } if (labelPref.pref === 'hide') { - return <></> + return null } return ( diff --git a/src/view/screens/SearchMobile.tsx b/src/view/screens/SearchMobile.tsx index 679fb07c2..de64b2d67 100644 --- a/src/view/screens/SearchMobile.tsx +++ b/src/view/screens/SearchMobile.tsx @@ -1,8 +1,8 @@ -import React from 'react' +import React, {useCallback} from 'react' import { - Keyboard, StyleSheet, TouchableWithoutFeedback, + Keyboard, View, } from 'react-native' import {useFocusEffect} from '@react-navigation/native' @@ -26,6 +26,7 @@ import {s} from 'lib/styles' import {ProfileCard} from 'view/com/profile/ProfileCard' import {usePalette} from 'lib/hooks/usePalette' import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' +import {isAndroid, isIOS} from 'platform/detection' type Props = NativeStackScreenProps<SearchTabNavigatorParams, 'Search'> export const SearchScreen = withAuthRequired( @@ -110,8 +111,14 @@ export const SearchScreen = withAuthRequired( }, [store, autocompleteView, foafs, suggestedActors, onSoftReset]), ) + const onPress = useCallback(() => { + if (isIOS || isAndroid) { + Keyboard.dismiss() + } + }, []) + return ( - <TouchableWithoutFeedback onPress={Keyboard.dismiss}> + <TouchableWithoutFeedback onPress={onPress}> <View style={[pal.view, styles.container]}> <HeaderWithInput isInputFocused={isInputFocused} @@ -139,16 +146,19 @@ export const SearchScreen = withAuthRequired( scrollEventThrottle={100}> {query && autocompleteView.searchRes.length ? ( <> - {autocompleteView.searchRes.map(item => ( - <ProfileCard - key={item.did} - testID={`searchAutoCompleteResult-${item.handle}`} - handle={item.handle} - displayName={item.displayName} - labels={item.labels} - avatar={item.avatar} - /> - ))} + {autocompleteView.searchRes.map( + ({did, handle, displayName, labels, avatar}, index) => ( + <ProfileCard + key={did} + testID={`searchAutoCompleteResult-${handle}`} + handle={handle} + displayName={displayName} + labels={labels} + avatar={avatar} + noBorder={index === 0} + /> + ), + )} </> ) : query && !autocompleteView.searchRes.length ? ( <View> diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx index e9a631b23..c5486a8fe 100644 --- a/src/view/shell/desktop/LeftNav.tsx +++ b/src/view/shell/desktop/LeftNav.tsx @@ -1,6 +1,7 @@ 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 { FontAwesomeIcon, @@ -88,19 +89,23 @@ const NavItem = observer( const isCurrent = isTab(currentRouteName, pathName) return ( - <Link href={href} style={styles.navItem}> - <View style={[styles.navItemIconWrapper]}> - {isCurrent ? iconFilled : icon} - {typeof count === 'number' && count > 0 && ( - <Text type="button" style={styles.navItemCount}> - {count} - </Text> - )} - </View> - <Text type="title" style={[isCurrent ? s.bold : s.normal, pal.text]}> - {label} - </Text> - </Link> + <PressableWithHover + style={styles.navItemWrapper} + hoverStyle={pal.viewLight}> + <Link href={href} style={styles.navItem}> + <View style={[styles.navItemIconWrapper]}> + {isCurrent ? iconFilled : icon} + {typeof count === 'number' && count > 0 && ( + <Text type="button" style={styles.navItemCount}> + {count} + </Text> + )} + </View> + <Text type="title" style={[isCurrent ? s.bold : s.normal, pal.text]}> + {label} + </Text> + </Link> + </PressableWithHover> ) }, ) @@ -193,13 +198,14 @@ const styles = StyleSheet.create({ leftNav: { position: 'absolute', top: 10, - right: 'calc(50vw + 300px)', + right: 'calc(50vw + 312px)', width: 220, }, profileCard: { marginVertical: 10, width: 60, + paddingLeft: 12, }, backBtn: { @@ -210,11 +216,15 @@ const styles = StyleSheet.create({ height: 30, }, + navItemWrapper: { + paddingHorizontal: 12, + borderRadius: 8, + }, navItem: { flexDirection: 'row', alignItems: 'center', - paddingTop: 14, - paddingBottom: 10, + paddingTop: 12, + paddingBottom: 12, }, navItemIconWrapper: { alignItems: 'center', @@ -245,6 +255,7 @@ const styles = StyleSheet.create({ paddingVertical: 10, paddingHorizontal: 16, backgroundColor: colors.blue3, + marginLeft: 12, marginTop: 20, marginBottom: 10, }, |