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>zio/stable
parent
1472bd4f17
commit
b24ba3adc9
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
]
|
||||
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,
|
||||
})),
|
||||
)
|
||||
...(item.additional?.map(
|
||||
({author: {avatar, labels, handle, displayName}}) => {
|
||||
return {
|
||||
href: `/profile/${handle}`,
|
||||
handle,
|
||||
displayName,
|
||||
avatar,
|
||||
labels,
|
||||
}
|
||||
},
|
||||
) || []),
|
||||
]
|
||||
|
||||
return (
|
||||
<Link
|
||||
|
@ -161,7 +161,6 @@ 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]} />
|
||||
|
@ -174,18 +173,14 @@ export const FeedItem = observer(function FeedItem({
|
|||
)}
|
||||
</View>
|
||||
<View style={styles.layoutContent}>
|
||||
<TouchableWithoutFeedback
|
||||
<Pressable
|
||||
onPress={authors.length > 1 ? onToggleAuthorsExpanded : () => {}}>
|
||||
<View>
|
||||
<CondensedAuthorsList
|
||||
visible={!isAuthorsExpanded}
|
||||
authors={authors}
|
||||
onToggleAuthorsExpanded={onToggleAuthorsExpanded}
|
||||
/>
|
||||
<ExpandedAuthorsList
|
||||
visible={isAuthorsExpanded}
|
||||
authors={authors}
|
||||
/>
|
||||
<ExpandedAuthorsList visible={isAuthorsExpanded} authors={authors} />
|
||||
<View style={styles.meta}>
|
||||
<TextLink
|
||||
key={authors[0].href}
|
||||
|
@ -199,8 +194,7 @@ export const FeedItem = observer(function FeedItem({
|
|||
<>
|
||||
<Text style={[styles.metaItem, pal.text]}>and</Text>
|
||||
<Text style={[styles.metaItem, pal.text, s.bold]}>
|
||||
{authors.length - 1}{' '}
|
||||
{pluralize(authors.length - 1, 'other')}
|
||||
{authors.length - 1} {pluralize(authors.length - 1, 'other')}
|
||||
</Text>
|
||||
</>
|
||||
) : undefined}
|
||||
|
@ -209,14 +203,10 @@ export const FeedItem = observer(function FeedItem({
|
|||
{ago(item.indexedAt)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</Pressable>
|
||||
{item.isLike || item.isRepost || item.isQuote ? (
|
||||
<AdditionalPostText additionalPost={item.additionalPost} />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</View>
|
||||
) : 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',
|
||||
|
|
|
@ -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}
|
||||
onPress={() => onPressItem(i)}>
|
||||
<View
|
||||
<PressableWithHover
|
||||
ref={itemRefs[i]}
|
||||
key={item}
|
||||
style={
|
||||
indicatorPosition === 'top' ? styles.itemTop : styles.itemBottom
|
||||
}
|
||||
ref={itemRefs[i]}>
|
||||
<Text type="xl-bold" style={selected ? pal.text : pal.textLight}>
|
||||
hoverStyle={pal.viewLight}
|
||||
onPress={() => onPressItem(i)}>
|
||||
<Text
|
||||
type="xl-bold"
|
||||
testID={testID ? `${testID}-${item}` : undefined}
|
||||
style={selected ? pal.text : pal.textLight}>
|
||||
{item}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</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({
|
||||
|
|
|
@ -48,7 +48,6 @@ export function ProfileCard({
|
|||
]}
|
||||
href={`/profile/${handle}`}
|
||||
title={handle}
|
||||
noFeedback
|
||||
asAnchor>
|
||||
<View style={styles.layout}>
|
||||
<View style={styles.layoutAvi}>
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
},
|
||||
)
|
|
@ -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>
|
||||
|
|
|
@ -40,7 +40,7 @@ export function ContentHider({
|
|||
}
|
||||
|
||||
if (labelPref.pref === 'hide') {
|
||||
return <></>
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -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 => (
|
||||
{autocompleteView.searchRes.map(
|
||||
({did, handle, displayName, labels, avatar}, index) => (
|
||||
<ProfileCard
|
||||
key={item.did}
|
||||
testID={`searchAutoCompleteResult-${item.handle}`}
|
||||
handle={item.handle}
|
||||
displayName={item.displayName}
|
||||
labels={item.labels}
|
||||
avatar={item.avatar}
|
||||
key={did}
|
||||
testID={`searchAutoCompleteResult-${handle}`}
|
||||
handle={handle}
|
||||
displayName={displayName}
|
||||
labels={labels}
|
||||
avatar={avatar}
|
||||
noBorder={index === 0}
|
||||
/>
|
||||
))}
|
||||
),
|
||||
)}
|
||||
</>
|
||||
) : query && !autocompleteView.searchRes.length ? (
|
||||
<View>
|
||||
|
|
|
@ -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,6 +89,9 @@ const NavItem = observer(
|
|||
const isCurrent = isTab(currentRouteName, pathName)
|
||||
|
||||
return (
|
||||
<PressableWithHover
|
||||
style={styles.navItemWrapper}
|
||||
hoverStyle={pal.viewLight}>
|
||||
<Link href={href} style={styles.navItem}>
|
||||
<View style={[styles.navItemIconWrapper]}>
|
||||
{isCurrent ? iconFilled : icon}
|
||||
|
@ -101,6 +105,7 @@ const NavItem = observer(
|
|||
{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,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue