diff --git a/src/components/SubtleWebHover.tsx b/src/components/SubtleWebHover.tsx
new file mode 100644
index 0000000000..e6f427237b
--- /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 0000000000..e98251e0dd
--- /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 (
+
+ )
+}
+
+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 3c1f51249f..7aa5f494fe 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
@@ -285,7 +288,14 @@ let FeedItem = ({
onToggleAuthorsExpanded()
}
}}
- onBeforePress={onBeforePress}>
+ onBeforePress={onBeforePress}
+ onPointerEnter={() => {
+ setHover(true)
+ }}
+ onPointerLeave={() => {
+ setHover(false)
+ }}>
+
{/* 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 99950495f9..4a30cc6a90 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 (
+ ]}
+ onPointerEnter={() => {
+ setHover(true)
+ }}
+ onPointerLeave={() => {
+ setHover(false)
+ }}>
{Array.from(Array(depth - 1)).map((_, n: number) => (
{
+ setHover(true)
+ }}
+ onPointerLeave={() => {
+ setHover(false)
+ }}
style={[
a.border_t,
a.px_sm,
@@ -689,6 +703,7 @@ function PostOuterWrapper({
hideTopBorder && styles.noTopBorder,
styles.cursor,
]}>
+
{children}
)
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index ec730a5e16..c87e361e16 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 (
+ onBeforePress={onBeforePress}
+ onPointerEnter={() => {
+ setHover(true)
+ }}
+ onPointerLeave={() => {
+ setHover(false)
+ }}>
+
{showReplyLine && }
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index fc640b2ad9..049748754d 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 (
+ dataSet={{feedContext}}
+ onPointerEnter={() => {
+ setHover(true)
+ }}
+ onPointerLeave={() => {
+ setHover(false)
+ }}>
+
{isThreadChild && (
diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx
index 2ae72742d7..2cc3e30ca0 100644
--- a/src/view/com/util/Link.tsx
+++ b/src/view/com/util/Link.tsx
@@ -49,6 +49,7 @@ interface Props extends ComponentProps {
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 2844d562b7..77f5f6c951 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 (
-
-
-
-
-
- {moderation ? (
-
- ) : null}
- {richText ? (
-
- ) : null}
- {embed && }
-
-
+ {
+ setHover(true)
+ }}
+ onPointerLeave={() => {
+ setHover(false)
+ }}>
+
+
+
+
+
+
+ {moderation ? (
+
+ ) : null}
+ {richText ? (
+
+ ) : null}
+ {embed && }
+
+
+
)
}