From 221623f55aa6c1bbe699c8d409832da110923c76 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Thu, 14 Aug 2025 13:14:18 +0300 Subject: Improve "replied to a post" component (#8602) * unify component * change bottom padding from 2px to 4px --- ...owCornerDownRight_stroke2_rounded_2_rounded.svg | 1 + src/components/Post/PostRepliedTo.tsx | 63 ++++++++++++++++ src/components/icons/ArrowCornerDownRight.tsx | 7 ++ src/view/com/post/Post.tsx | 45 ++---------- src/view/com/posts/PostFeedItem.tsx | 84 ++-------------------- src/view/com/util/UserInfoText.tsx | 68 ++++++++---------- 6 files changed, 110 insertions(+), 158 deletions(-) create mode 100644 assets/icons/arrowCornerDownRight_stroke2_rounded_2_rounded.svg create mode 100644 src/components/Post/PostRepliedTo.tsx create mode 100644 src/components/icons/ArrowCornerDownRight.tsx diff --git a/assets/icons/arrowCornerDownRight_stroke2_rounded_2_rounded.svg b/assets/icons/arrowCornerDownRight_stroke2_rounded_2_rounded.svg new file mode 100644 index 000000000..fa21c9824 --- /dev/null +++ b/assets/icons/arrowCornerDownRight_stroke2_rounded_2_rounded.svg @@ -0,0 +1 @@ + diff --git a/src/components/Post/PostRepliedTo.tsx b/src/components/Post/PostRepliedTo.tsx new file mode 100644 index 000000000..3085826c2 --- /dev/null +++ b/src/components/Post/PostRepliedTo.tsx @@ -0,0 +1,63 @@ +import {View} from 'react-native' +import {Trans} from '@lingui/macro' + +import {useSession} from '#/state/session' +import {UserInfoText} from '#/view/com/util/UserInfoText' +import {atoms as a, useTheme} from '#/alf' +import {ArrowCornerDownRight_Stroke2_Corner2_Rounded as ArrowCornerDownRightIcon} from '#/components/icons/ArrowCornerDownRight' +import {ProfileHoverCard} from '#/components/ProfileHoverCard' +import {Text} from '#/components/Typography' +import type * as bsky from '#/types/bsky' + +export function PostRepliedTo({ + parentAuthor, + isParentBlocked, + isParentNotFound, +}: { + parentAuthor: string | bsky.profile.AnyProfileView | undefined + isParentBlocked?: boolean + isParentNotFound?: boolean +}) { + const t = useTheme() + const {currentAccount} = useSession() + + const textStyle = [a.text_sm, t.atoms.text_contrast_medium, a.leading_snug] + + let label + if (isParentBlocked) { + label = Replied to a blocked post + } else if (isParentNotFound) { + label = Replied to a post + } else if (parentAuthor) { + const did = + typeof parentAuthor === 'string' ? parentAuthor : parentAuthor.did + const isMe = currentAccount?.did === did + if (isMe) { + label = Replied to you + } else { + label = ( + + Replied to{' '} + + + + + ) + } + } + + if (!label) { + // Should not happen. + return null + } + + return ( + + + {label} + + ) +} diff --git a/src/components/icons/ArrowCornerDownRight.tsx b/src/components/icons/ArrowCornerDownRight.tsx new file mode 100644 index 000000000..86dde7015 --- /dev/null +++ b/src/components/icons/ArrowCornerDownRight.tsx @@ -0,0 +1,7 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const ArrowCornerDownRight_Stroke2_Corner2_Rounded = createSinglePathSVG( + { + path: 'M15.793 10.293a1 1 0 0 1 1.338-.068l.076.068 3.293 3.293a2 2 0 0 1 .138 2.677l-.138.151-3.293 3.293a1 1 0 1 1-1.414-1.414L18.086 16H8a5 5 0 0 1-5-5V5a1 1 0 0 1 2 0v6a3 3 0 0 0 3 3h10.086l-2.293-2.293-.068-.076a1 1 0 0 1 .068-1.338Z', + }, +) diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index 6079f5c10..a8e32268e 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -8,8 +8,6 @@ import { type ModerationDecision, RichText as RichTextAPI, } from '@atproto/api' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {Trans} from '@lingui/macro' import {useQueryClient} from '@tanstack/react-query' import {MAX_POST_LINES} from '#/lib/constants' @@ -17,28 +15,25 @@ import {useOpenComposer} from '#/lib/hooks/useOpenComposer' import {usePalette} from '#/lib/hooks/usePalette' import {makeProfileLink} from '#/lib/routes/links' import {countLines} from '#/lib/strings/helpers' -import {colors, s} from '#/lib/styles' +import {colors} from '#/lib/styles' import { POST_TOMBSTONE, type Shadow, usePostShadow, } from '#/state/cache/post-shadow' import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {precacheProfile} from '#/state/queries/profile' -import {useSession} from '#/state/session' +import {unstableCacheProfileView} from '#/state/queries/profile' import {Link} from '#/view/com/util/Link' import {PostMeta} from '#/view/com/util/PostMeta' -import {Text} from '#/view/com/util/text/Text' import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' -import {UserInfoText} from '#/view/com/util/UserInfoText' import {atoms as a} from '#/alf' import {ContentHider} from '#/components/moderation/ContentHider' import {LabelsOnMyPost} from '#/components/moderation/LabelsOnMe' import {PostAlerts} from '#/components/moderation/PostAlerts' import {Embed, PostEmbedViewContext} from '#/components/Post/Embed' +import {PostRepliedTo} from '#/components/Post/PostRepliedTo' import {ShowMoreTextButton} from '#/components/Post/ShowMoreTextButton' import {PostControls} from '#/components/PostControls' -import {ProfileHoverCard} from '#/components/ProfileHoverCard' import {RichText} from '#/components/RichText' import {SubtleWebHover} from '#/components/SubtleWebHover' import * as bsky from '#/types/bsky' @@ -145,12 +140,9 @@ function PostInner({ }, [setLimitLines]) const onBeforePress = useCallback(() => { - precacheProfile(queryClient, post.author) + unstableCacheProfileView(queryClient, post.author) }, [queryClient, post.author]) - const {currentAccount} = useSession() - const isMe = replyAuthorDid === currentAccount?.did - const [hover, setHover] = useState(false) return ( {replyAuthorDid !== '' && ( - - - - {isMe ? ( - Reply to you - ) : ( - - Reply to{' '} - - - - - )} - - + )} {showReplyTo && (parentAuthor || isParentBlocked || isParentNotFound) && ( - )} @@ -576,80 +572,10 @@ let PostContent = ({ } PostContent = memo(PostContent) -function ReplyToLabel({ - profile, - blocked, - notFound, -}: { - profile: AppBskyActorDefs.ProfileViewBasic | undefined - blocked?: boolean - notFound?: boolean -}) { - const pal = usePalette('default') - const {currentAccount} = useSession() - - let label - if (blocked) { - label = Reply to a blocked post - } else if (notFound) { - label = Reply to a post - } else if (profile != null) { - const isMe = profile.did === currentAccount?.did - if (isMe) { - label = Reply to you - } else { - label = ( - - Reply to{' '} - - - {profile.displayName - ? sanitizeDisplayName(profile.displayName) - : sanitizeHandle(profile.handle)} - - } - /> - - - ) - } - } - - if (!label) { - // Should not happen. - return null - } - - return ( - - - - {label} - - - ) -} - const styles = StyleSheet.create({ outer: { paddingLeft: 10, paddingRight: 15, - // @ts-ignore web only -prf cursor: 'pointer', }, replyLine: { diff --git a/src/view/com/util/UserInfoText.tsx b/src/view/com/util/UserInfoText.tsx index 64aa37ff2..028b85d38 100644 --- a/src/view/com/util/UserInfoText.tsx +++ b/src/view/com/util/UserInfoText.tsx @@ -1,27 +1,25 @@ -import {StyleProp, StyleSheet, TextStyle} from 'react-native' -import {AppBskyActorGetProfile as GetProfile} from '@atproto/api' +import {type StyleProp, type TextStyle} from 'react-native' +import {type AppBskyActorGetProfile} from '@atproto/api' import {makeProfileLink} from '#/lib/routes/links' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' -import {TypographyVariant} from '#/lib/ThemeContext' import {STALE} from '#/state/queries' import {useProfileQuery} from '#/state/queries/profile' -import {TextLinkOnWebOnly} from './Link' +import {atoms as a} from '#/alf' +import {InlineLinkText} from '#/components/Link' +import {Text} from '#/components/Typography' import {LoadingPlaceholder} from './LoadingPlaceholder' -import {Text} from './text/Text' export function UserInfoText({ - type = 'md', did, attr, failed, prefix, style, }: { - type?: TypographyVariant did: string - attr?: keyof GetProfile.OutputSchema + attr?: keyof AppBskyActorGetProfile.OutputSchema loading?: string failed?: string prefix?: string @@ -35,45 +33,37 @@ export function UserInfoText({ staleTime: STALE.INFINITY, }) - let inner if (isError) { - inner = ( - + return ( + {failed} ) } else if (profile) { - inner = ( - - {`${prefix || ''}${sanitizeDisplayName( - typeof profile[attr] === 'string' && profile[attr] - ? (profile[attr] as string) - : sanitizeHandle(profile.handle), - )}`} - - } - /> - ) - } else { - inner = ( - + to={makeProfileLink(profile)}> + + {text} + + ) } - return inner + // eslint-disable-next-line bsky-internal/avoid-unwrapped-text + return ( + + ) } - -const styles = StyleSheet.create({ - loadingPlaceholder: {position: 'relative', top: 1, left: 2}, -}) -- cgit 1.4.1