diff options
author | dan <dan.abramov@gmail.com> | 2024-10-29 21:42:37 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-29 21:42:37 +0000 |
commit | ba802eb0f24d30467dd8621f204526d6457f9613 (patch) | |
tree | cebdda251b3bbb0cb82e7052617ed2ddd90f2a7f | |
parent | c8f264b78b1dfb95f68bfb820bd012828cd5fddc (diff) | |
download | voidsky-ba802eb0f24d30467dd8621f204526d6457f9613.tar.zst |
Add subtle web hover to interactive rows (#5989)
* Add subtle web hover to interactive rows * Adjust numbers * Ignore touch devices
-rw-r--r-- | src/components/SubtleWebHover.tsx | 3 | ||||
-rw-r--r-- | src/components/SubtleWebHover.web.tsx | 48 | ||||
-rw-r--r-- | src/view/com/notifications/FeedItem.tsx | 12 | ||||
-rw-r--r-- | src/view/com/post-thread/PostThreadItem.tsx | 17 | ||||
-rw-r--r-- | src/view/com/post/Post.tsx | 11 | ||||
-rw-r--r-- | src/view/com/posts/FeedItem.tsx | 11 | ||||
-rw-r--r-- | src/view/com/util/Link.tsx | 1 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/QuoteEmbed.tsx | 92 |
8 files changed, 152 insertions, 43 deletions
diff --git a/src/components/SubtleWebHover.tsx b/src/components/SubtleWebHover.tsx new file mode 100644 index 000000000..e6f427237 --- /dev/null +++ b/src/components/SubtleWebHover.tsx @@ -0,0 +1,3 @@ +export function SubtleWebHover({}: {hover: boolean}) { + return null +} diff --git a/src/components/SubtleWebHover.web.tsx b/src/components/SubtleWebHover.web.tsx new file mode 100644 index 000000000..e98251e0d --- /dev/null +++ b/src/components/SubtleWebHover.web.tsx @@ -0,0 +1,48 @@ +import React from 'react' +import {StyleSheet, View} from 'react-native' + +import {isTouchDevice} from '#/lib/browser' +import {useTheme} from '#/alf' + +export function SubtleWebHover({hover}: {hover: boolean}) { + const t = useTheme() + if (isTouchDevice) { + return null + } + let opacity: number + switch (t.name) { + case 'dark': + opacity = 0.4 + break + case 'dim': + opacity = 0.45 + break + case 'light': + opacity = 0.5 + break + } + return ( + <View + style={[ + t.atoms.bg_contrast_25, + styles.container, + { + opacity: hover ? opacity : 0, + }, + ]} + /> + ) +} + +const styles = StyleSheet.create({ + container: { + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + top: 0, + pointerEvents: 'none', + // @ts-ignore web only + transition: '0.15s ease-in-out opacity', + }, +}) diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx index 3c1f51249..7aa5f494f 100644 --- a/src/view/com/notifications/FeedItem.tsx +++ b/src/view/com/notifications/FeedItem.tsx @@ -51,6 +51,7 @@ import {Link as NewLink} from '#/components/Link' import * as MediaPreview from '#/components/MediaPreview' import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {Notification as StarterPackCard} from '#/components/StarterPack/StarterPackCard' +import {SubtleWebHover} from '#/components/SubtleWebHover' import {FeedSourceCard} from '../feeds/FeedSourceCard' import {Post} from '../post/Post' import {Link, TextLink} from '../util/Link' @@ -129,6 +130,8 @@ let FeedItem = ({ ] }, [item, moderationOpts]) + const [hover, setHover] = React.useState(false) + if (item.subjectUri && !item.subject && item.type !== 'feedgen-like') { // don't render anything if the target post was deleted or unfindable return <View /> @@ -285,7 +288,14 @@ let FeedItem = ({ onToggleAuthorsExpanded() } }} - onBeforePress={onBeforePress}> + onBeforePress={onBeforePress} + onPointerEnter={() => { + setHover(true) + }} + onPointerLeave={() => { + setHover(false) + }}> + <SubtleWebHover hover={hover} /> <View style={[styles.layoutIcon, a.pr_sm]}> {/* TODO: Prevent conditional rendering and move toward composable notifications for clearer accessibility labeling */} diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index 99950495f..4a30cc6a9 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -31,6 +31,7 @@ import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn' import {atoms as a, useTheme} from '#/alf' import {AppModerationCause} from '#/components/Pills' import {RichText} from '#/components/RichText' +import {SubtleWebHover} from '#/components/SubtleWebHover' import {Text as NewText} from '#/components/Typography' import {ContentHider} from '../../../components/moderation/ContentHider' import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' @@ -649,6 +650,7 @@ function PostOuterWrapper({ hideTopBorder?: boolean }>) { const t = useTheme() + const [hover, setHover] = React.useState(false) if (treeView && depth > 0) { return ( <View @@ -661,7 +663,13 @@ function PostOuterWrapper({ flexDirection: 'row', borderTopWidth: depth === 1 ? a.border_t.borderTopWidth : 0, }, - ]}> + ]} + onPointerEnter={() => { + setHover(true) + }} + onPointerLeave={() => { + setHover(false) + }}> {Array.from(Array(depth - 1)).map((_, n: number) => ( <View key={`${post.uri}-padding-${n}`} @@ -681,6 +689,12 @@ function PostOuterWrapper({ } return ( <View + onPointerEnter={() => { + setHover(true) + }} + onPointerLeave={() => { + setHover(false) + }} style={[ a.border_t, a.px_sm, @@ -689,6 +703,7 @@ function PostOuterWrapper({ hideTopBorder && styles.noTopBorder, styles.cursor, ]}> + <SubtleWebHover hover={hover} /> {children} </View> ) diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index ec730a5e1..c87e361e1 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -27,6 +27,7 @@ import {AviFollowButton} from '#/view/com/posts/AviFollowButton' import {atoms as a} from '#/alf' import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {RichText} from '#/components/RichText' +import {SubtleWebHover} from '#/components/SubtleWebHover' import {ContentHider} from '../../../components/moderation/ContentHider' import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' import {PostAlerts} from '../../../components/moderation/PostAlerts' @@ -148,6 +149,7 @@ function PostInner({ const {currentAccount} = useSession() const isMe = replyAuthorDid === currentAccount?.did + const [hover, setHover] = React.useState(false) return ( <Link href={itemHref} @@ -157,7 +159,14 @@ function PostInner({ !hideTopBorder && {borderTopWidth: StyleSheet.hairlineWidth}, style, ]} - onBeforePress={onBeforePress}> + onBeforePress={onBeforePress} + onPointerEnter={() => { + setHover(true) + }} + onPointerLeave={() => { + setHover(false) + }}> + <SubtleWebHover hover={hover} /> {showReplyLine && <View style={styles.replyLine} />} <View style={styles.layout}> <View style={styles.layoutAvi}> diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index fc640b2ad..049748754 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -46,6 +46,7 @@ import {PostAlerts} from '#/components/moderation/PostAlerts' import {AppModerationCause} from '#/components/Pills' import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {RichText} from '#/components/RichText' +import {SubtleWebHover} from '#/components/SubtleWebHover' import {Link, TextLink, TextLinkOnWebOnly} from '../util/Link' import {AviFollowButton} from './AviFollowButton' @@ -237,6 +238,7 @@ let FeedItemInner = ({ ? rootPost.threadgate.record : undefined + const [hover, setHover] = useState(false) return ( <Link testID={`feedItem-by-${post.author.handle}`} @@ -245,7 +247,14 @@ let FeedItemInner = ({ noFeedback accessible={false} onBeforePress={onBeforePress} - dataSet={{feedContext}}> + dataSet={{feedContext}} + onPointerEnter={() => { + setHover(true) + }} + onPointerLeave={() => { + setHover(false) + }}> + <SubtleWebHover hover={hover} /> <View style={{flexDirection: 'row', gap: 10, paddingLeft: 8}}> <View style={{width: 42}}> {isThreadChild && ( diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx index 2ae72742d..2cc3e30ca 100644 --- a/src/view/com/util/Link.tsx +++ b/src/view/com/util/Link.tsx @@ -49,6 +49,7 @@ interface Props extends ComponentProps<typeof TouchableOpacity> { anchorNoUnderline?: boolean navigationAction?: 'push' | 'replace' | 'navigate' onPointerEnter?: () => void + onPointerLeave?: () => void onBeforePress?: () => void } diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx index 2844d562b..77f5f6c95 100644 --- a/src/view/com/util/post-embeds/QuoteEmbed.tsx +++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx @@ -35,6 +35,7 @@ import {useResolveLinkQuery} from '#/state/queries/resolve-link' import {useSession} from '#/state/session' import {atoms as a, useTheme} from '#/alf' import {RichText} from '#/components/RichText' +import {SubtleWebHover} from '#/components/SubtleWebHover' import {ContentHider} from '../../../../components/moderation/ContentHider' import {PostAlerts} from '../../../../components/moderation/PostAlerts' import {Link} from '../Link' @@ -209,46 +210,59 @@ export function QuoteEmbed({ onOpen?.() }, [queryClient, quote.author, onOpen]) + const [hover, setHover] = React.useState(false) return ( - <ContentHider - modui={moderation?.ui('contentList')} - style={[ - a.rounded_md, - a.p_md, - a.mt_sm, - a.border, - t.atoms.border_contrast_low, - style, - ]} - childContainerStyle={[a.pt_sm]}> - <Link - hoverStyle={{borderColor: pal.colors.borderLinkHover}} - href={itemHref} - title={itemTitle} - onBeforePress={onBeforePress}> - <View pointerEvents="none"> - <PostMeta - author={quote.author} - moderation={moderation} - showAvatar - postHref={itemHref} - timestamp={quote.indexedAt} - /> - </View> - {moderation ? ( - <PostAlerts modui={moderation.ui('contentView')} style={[a.py_xs]} /> - ) : null} - {richText ? ( - <RichText - value={richText} - style={a.text_md} - numberOfLines={20} - disableLinks - /> - ) : null} - {embed && <PostEmbeds embed={embed} moderation={moderation} />} - </Link> - </ContentHider> + <View + onPointerEnter={() => { + setHover(true) + }} + onPointerLeave={() => { + setHover(false) + }}> + <ContentHider + modui={moderation?.ui('contentList')} + style={[ + a.rounded_md, + a.p_md, + a.mt_sm, + a.border, + t.atoms.border_contrast_low, + style, + ]} + childContainerStyle={[a.pt_sm]}> + <SubtleWebHover hover={hover} /> + <Link + hoverStyle={{borderColor: pal.colors.borderLinkHover}} + href={itemHref} + title={itemTitle} + onBeforePress={onBeforePress}> + <View pointerEvents="none"> + <PostMeta + author={quote.author} + moderation={moderation} + showAvatar + postHref={itemHref} + timestamp={quote.indexedAt} + /> + </View> + {moderation ? ( + <PostAlerts + modui={moderation.ui('contentView')} + style={[a.py_xs]} + /> + ) : null} + {richText ? ( + <RichText + value={richText} + style={a.text_md} + numberOfLines={20} + disableLinks + /> + ) : null} + {embed && <PostEmbeds embed={embed} moderation={moderation} />} + </Link> + </ContentHider> + </View> ) } |