Profile hovers (#3518)

* Add hover card for mentions

* Reposted by

* Fix key

* Add to composer reply to
zio/stable
Eric Bailey 2024-04-13 00:13:53 -05:00 committed by GitHub
parent a845587e1f
commit f5bb348bf5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 64 additions and 49 deletions

View File

@ -116,7 +116,10 @@ export function ProfileHoverCardInner(props: ProfileHoverCardProps) {
ref={refs.setReference}
onPointerEnter={onPointerEnterTarget}
onPointerLeave={onPointerLeaveTarget}
onMouseUp={onClickTarget}>
onMouseUp={onClickTarget}
style={{
display: props.inline ? 'inline' : 'block',
}}>
{props.children}
{hovered && (

View File

@ -3,4 +3,5 @@ import React from 'react'
export type ProfileHoverCardProps = {
children: React.ReactElement
did: string
inline?: boolean
}

View File

@ -8,6 +8,7 @@ import {isNative} from '#/platform/detection'
import {atoms as a, flatten, native, TextStyleProp, useTheme, web} from '#/alf'
import {useInteractionState} from '#/components/hooks/useInteractionState'
import {InlineLinkText, LinkProps} from '#/components/Link'
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
import {TagMenu, useTagMenuControl} from '#/components/TagMenu'
import {Text, TextProps} from '#/components/Typography'
@ -86,16 +87,17 @@ export function RichText({
!disableLinks
) {
els.push(
<InlineLinkText
selectable={selectable}
key={key}
to={`/profile/${mention.did}`}
style={[...styles, {pointerEvents: 'auto'}]}
// @ts-ignore TODO
dataSet={WORD_WRAP}
onPress={onLinkPress}>
{segment.text}
</InlineLinkText>,
<ProfileHoverCard key={key} inline did={mention.did}>
<InlineLinkText
selectable={selectable}
to={`/profile/${mention.did}`}
style={[...styles, {pointerEvents: 'auto'}]}
// @ts-ignore TODO
dataSet={WORD_WRAP}
onPress={onLinkPress}>
{segment.text}
</InlineLinkText>
</ProfileHoverCard>,
)
} else if (link && AppBskyRichtextFacet.validateLink(link).success) {
if (disableLinks) {

View File

@ -1,21 +1,22 @@
import React from 'react'
import {LayoutAnimation, Pressable, StyleSheet, View} from 'react-native'
import {Image} from 'expo-image'
import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro'
import {
AppBskyEmbedImages,
AppBskyEmbedRecord,
AppBskyEmbedRecordWithMedia,
AppBskyFeedPost,
} from '@atproto/api'
import {ComposerOptsPostRef} from 'state/shell/composer'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {usePalette} from 'lib/hooks/usePalette'
import {sanitizeDisplayName} from 'lib/strings/display-names'
import {sanitizeHandle} from 'lib/strings/handles'
import {UserAvatar} from 'view/com/util/UserAvatar'
import {Text} from 'view/com/util/text/Text'
import {ComposerOptsPostRef} from 'state/shell/composer'
import {QuoteEmbed} from 'view/com/util/post-embeds/QuoteEmbed'
import {Text} from 'view/com/util/text/Text'
import {PreviewableUserAvatar} from 'view/com/util/UserAvatar'
export function ComposerReplyTo({replyTo}: {replyTo: ComposerOptsPostRef}) {
const pal = usePalette('default')
@ -83,9 +84,11 @@ export function ComposerReplyTo({replyTo}: {replyTo: ComposerOptsPostRef}) {
accessibilityHint={_(
msg`Expand or collapse the full post you are replying to`,
)}>
<UserAvatar
avatar={replyTo.author.avatar}
<PreviewableUserAvatar
size={50}
did={replyTo.author.did}
handle={replyTo.author.handle}
avatar={replyTo.author.avatar}
moderation={replyTo.moderation?.ui('avatar')}
type={replyTo.author.associated?.labeler ? 'labeler' : 'user'}
/>
@ -216,6 +219,7 @@ function ComposerReplyToImages({
const styles = StyleSheet.create({
replyToLayout: {
flexDirection: 'row',
alignItems: 'flex-start',
borderTopWidth: 1,
paddingTop: 16,
paddingBottom: 16,

View File

@ -11,31 +11,33 @@ import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import {ReasonFeedSource, isReasonFeedSource} from 'lib/api/feed/types'
import {Link, TextLinkOnWebOnly, TextLink} from '../util/Link'
import {Text} from '../util/text/Text'
import {UserInfoText} from '../util/UserInfoText'
import {PostMeta} from '../util/PostMeta'
import {PostCtrls} from '../util/post-ctrls/PostCtrls'
import {PostEmbeds} from '../util/post-embeds'
import {ContentHider} from '#/components/moderation/ContentHider'
import {PostAlerts} from '../../../components/moderation/PostAlerts'
import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe'
import {RichText} from '#/components/RichText'
import {PreviewableUserAvatar} from '../util/UserAvatar'
import {s} from 'lib/styles'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
import {useComposerControls} from '#/state/shell/composer'
import {isReasonFeedSource, ReasonFeedSource} from 'lib/api/feed/types'
import {MAX_POST_LINES} from 'lib/constants'
import {usePalette} from 'lib/hooks/usePalette'
import {makeProfileLink} from 'lib/routes/links'
import {sanitizeDisplayName} from 'lib/strings/display-names'
import {sanitizeHandle} from 'lib/strings/handles'
import {makeProfileLink} from 'lib/routes/links'
import {MAX_POST_LINES} from 'lib/constants'
import {countLines} from 'lib/strings/helpers'
import {useComposerControls} from '#/state/shell/composer'
import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
import {FeedNameText} from '../util/FeedInfoText'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {s} from 'lib/styles'
import {atoms as a} from '#/alf'
import {ContentHider} from '#/components/moderation/ContentHider'
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
import {RichText} from '#/components/RichText'
import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe'
import {PostAlerts} from '../../../components/moderation/PostAlerts'
import {FeedNameText} from '../util/FeedInfoText'
import {Link, TextLink, TextLinkOnWebOnly} from '../util/Link'
import {PostCtrls} from '../util/post-ctrls/PostCtrls'
import {PostEmbeds} from '../util/post-embeds'
import {PostMeta} from '../util/PostMeta'
import {Text} from '../util/text/Text'
import {PreviewableUserAvatar} from '../util/UserAvatar'
import {UserInfoText} from '../util/UserInfoText'
export function FeedItem({
post,
@ -213,17 +215,20 @@ let FeedItemInner = ({
numberOfLines={1}>
<Trans>
Reposted by{' '}
<TextLinkOnWebOnly
type="sm-bold"
style={pal.textLight}
lineHeight={1.2}
numberOfLines={1}
text={sanitizeDisplayName(
reason.by.displayName || sanitizeHandle(reason.by.handle),
moderation.ui('displayName'),
)}
href={makeProfileLink(reason.by)}
/>
<ProfileHoverCard inline did={reason.by.did}>
<TextLinkOnWebOnly
type="sm-bold"
style={pal.textLight}
lineHeight={1.2}
numberOfLines={1}
text={sanitizeDisplayName(
reason.by.displayName ||
sanitizeHandle(reason.by.handle),
moderation.ui('displayName'),
)}
href={makeProfileLink(reason.by)}
/>
</ProfileHoverCard>
</Trans>
</Text>
</Link>