diff options
Diffstat (limited to 'src/view/com/util/PostMeta.tsx')
-rw-r--r-- | src/view/com/util/PostMeta.tsx | 175 |
1 files changed, 106 insertions, 69 deletions
diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx index 30180b889..d5af32236 100644 --- a/src/view/com/util/PostMeta.tsx +++ b/src/view/com/util/PostMeta.tsx @@ -1,9 +1,10 @@ -import React, {memo, useCallback} from 'react' -import {StyleProp, View, ViewStyle} from 'react-native' -import {AppBskyActorDefs, ModerationDecision} from '@atproto/api' +import {memo, useCallback} from 'react' +import {type StyleProp, View, type ViewStyle} from 'react-native' +import {type AppBskyActorDefs, type ModerationDecision} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useQueryClient} from '@tanstack/react-query' +import type React from 'react' import {makeProfileLink} from '#/lib/routes/links' import {forceLTR} from '#/lib/strings/bidi' @@ -12,11 +13,14 @@ import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {niceDate} from '#/lib/strings/time' import {isAndroid} from '#/platform/detection' +import {useProfileShadow} from '#/state/cache/profile-shadow' import {precacheProfile} from '#/state/queries/profile' -import {atoms as a, useTheme, web} from '#/alf' +import {atoms as a, platform, useTheme, web} from '#/alf' import {WebOnlyInlineLinkText} from '#/components/Link' import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {Text} from '#/components/Typography' +import {useSimpleVerificationState} from '#/components/verification' +import {VerificationCheck} from '#/components/verification/VerificationCheck' import {TimeElapsed} from './TimeElapsed' import {PreviewableUserAvatar} from './UserAvatar' @@ -35,20 +39,22 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => { const t = useTheme() const {i18n, _} = useLingui() - const displayName = opts.author.displayName || opts.author.handle - const handle = opts.author.handle - const profileLink = makeProfileLink(opts.author) + const author = useProfileShadow(opts.author) + const displayName = author.displayName || author.handle + const handle = author.handle + const profileLink = makeProfileLink(author) const queryClient = useQueryClient() const onOpenAuthor = opts.onOpenAuthor const onBeforePressAuthor = useCallback(() => { - precacheProfile(queryClient, opts.author) + precacheProfile(queryClient, author) onOpenAuthor?.() - }, [queryClient, opts.author, onOpenAuthor]) + }, [queryClient, author, onOpenAuthor]) const onBeforePressPost = useCallback(() => { - precacheProfile(queryClient, opts.author) - }, [queryClient, opts.author]) + precacheProfile(queryClient, author) + }, [queryClient, author]) const timestampLabel = niceDate(i18n, opts.timestamp) + const verification = useSimpleVerificationState({profile: author}) return ( <View @@ -56,83 +62,114 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => { a.flex_1, a.flex_row, a.align_center, - a.pb_2xs, + a.pb_xs, a.gap_xs, - a.z_10, + a.z_20, opts.style, ]}> {opts.showAvatar && ( <View style={[a.self_center, a.mr_2xs]}> <PreviewableUserAvatar size={opts.avatarSize || 16} - profile={opts.author} + profile={author} moderation={opts.moderation?.ui('avatar')} - type={opts.author.associated?.labeler ? 'labeler' : 'user'} + type={author.associated?.labeler ? 'labeler' : 'user'} /> </View> )} - <ProfileHoverCard inline did={opts.author.did}> - <Text numberOfLines={1} style={[isAndroid ? a.flex_1 : a.flex_shrink]}> - <WebOnlyInlineLinkText - to={profileLink} - label={_(msg`View profile`)} - disableMismatchWarning - onPress={onBeforePressAuthor} - style={[t.atoms.text]}> - <Text emoji style={[a.text_md, a.font_bold, a.leading_snug]}> + <View style={[a.flex_row, a.align_end, a.flex_shrink]}> + <ProfileHoverCard inline did={author.did}> + <View style={[a.flex_row, a.align_end, a.flex_shrink]}> + <WebOnlyInlineLinkText + emoji + numberOfLines={1} + to={profileLink} + label={_(msg`View profile`)} + disableMismatchWarning + onPress={onBeforePressAuthor} + style={[ + a.text_md, + a.font_bold, + t.atoms.text, + a.leading_tight, + {maxWidth: '70%', flexShrink: 0}, + ]}> {forceLTR( sanitizeDisplayName( displayName, opts.moderation?.ui('displayName'), ), )} - </Text> - </WebOnlyInlineLinkText> - <WebOnlyInlineLinkText - to={profileLink} - label={_(msg`View profile`)} - disableMismatchWarning - disableUnderline - onPress={onBeforePressAuthor} - style={[a.text_md, t.atoms.text_contrast_medium, a.leading_snug]}> - <Text - emoji - style={[a.text_md, t.atoms.text_contrast_medium, a.leading_snug]}> + </WebOnlyInlineLinkText> + {verification.showBadge && ( + <View + style={[ + a.pl_2xs, + a.self_center, + { + marginTop: platform({web: -1, ios: -1, android: -2}), + }, + ]}> + <VerificationCheck + width={14} + verifier={verification.role === 'verifier'} + /> + </View> + )} + <WebOnlyInlineLinkText + numberOfLines={1} + to={profileLink} + label={_(msg`View profile`)} + disableMismatchWarning + disableUnderline + onPress={onBeforePressAuthor} + style={[ + a.text_md, + t.atoms.text_contrast_medium, + a.leading_tight, + {flexShrink: 10}, + ]}> {NON_BREAKING_SPACE + sanitizeHandle(handle, '@')} - </Text> - </WebOnlyInlineLinkText> - </Text> - </ProfileHoverCard> + </WebOnlyInlineLinkText> + </View> + </ProfileHoverCard> - {!isAndroid && ( - <Text - style={[a.text_md, t.atoms.text_contrast_medium]} - accessible={false}> - · - </Text> - )} - - <TimeElapsed timestamp={opts.timestamp}> - {({timeElapsed}) => ( - <WebOnlyInlineLinkText - to={opts.postHref} - label={timestampLabel} - title={timestampLabel} - disableMismatchWarning - disableUnderline - onPress={onBeforePressPost} - style={[ - a.text_md, - t.atoms.text_contrast_medium, - a.leading_snug, - web({ - whiteSpace: 'nowrap', - }), - ]}> - {timeElapsed} - </WebOnlyInlineLinkText> - )} - </TimeElapsed> + <TimeElapsed timestamp={opts.timestamp}> + {({timeElapsed}) => ( + <WebOnlyInlineLinkText + to={opts.postHref} + label={timestampLabel} + title={timestampLabel} + disableMismatchWarning + disableUnderline + onPress={onBeforePressPost} + style={[ + a.pl_xs, + a.text_md, + a.leading_tight, + isAndroid && a.flex_grow, + a.text_right, + t.atoms.text_contrast_medium, + web({ + whiteSpace: 'nowrap', + }), + ]}> + {!isAndroid && ( + <Text + style={[ + a.text_md, + a.leading_tight, + t.atoms.text_contrast_medium, + ]} + accessible={false}> + ·{' '} + </Text> + )} + {timeElapsed} + </WebOnlyInlineLinkText> + )} + </TimeElapsed> + </View> </View> ) } |