From 662441af85c957a69d04c7c77508cf9f2bea977e Mon Sep 17 00:00:00 2001 From: vineyardbovines Date: Fri, 28 Aug 2026 14:18:28 -0400 Subject: [PATCH] Polish known likers in feeds and posts --- src/components/AvatarStack.tsx | 10 ++-- src/components/Post/KnownLikers.tsx | 51 +++++-------------- src/components/WhoCanReply.tsx | 8 +-- .../PostThread/components/LikesStat.tsx | 4 +- .../components/ThreadItemAnchor.tsx | 23 ++++----- src/state/queries/usePostThread/index.ts | 24 +++++++++ src/view/com/posts/PostFeedItem.tsx | 10 ++-- 7 files changed, 67 insertions(+), 63 deletions(-) diff --git a/src/components/AvatarStack.tsx b/src/components/AvatarStack.tsx index 8c5893ed76..486a025920 100644 --- a/src/components/AvatarStack.tsx +++ b/src/components/AvatarStack.tsx @@ -13,13 +13,17 @@ export function AvatarStack({ size = 26, numPending, backgroundColor, + borderWidth = 1, + overlap, }: { profiles: bsky.profile.AnyProfileView[] size?: number numPending?: number backgroundColor?: string + borderWidth?: number + overlap?: number }) { - const translation = size / 3 // overlap by 1/3 + const translation = overlap ?? size / 3 const t = useTheme() const moderationOpts = useModerationOpts() @@ -55,7 +59,7 @@ export function AvatarStack({ width: size, height: size, left: i * -translation, - borderWidth: 1, + borderWidth, borderColor: backgroundColor ?? t.atoms.bg.backgroundColor, borderRadius: 999, zIndex: 3 - i, @@ -63,7 +67,7 @@ export function AvatarStack({ ]}> {item.profile && ( ({ @@ -64,19 +61,13 @@ export function KnownLikers({ moderation.ui('displayName'), ), })) + const isFeed = variant === 'feed' const rowLabel = - variant === 'feed' - ? likeCount > 1 - ? l`${names[0].displayName} and ${likeCount - 1} others liked this` - : l`${names[0].displayName} liked this` - : names.length >= 2 - ? l`Liked by ${names[0].displayName} and ${names[1].displayName}` - : l`Liked by ${names[0].displayName}` - const textStyle = [ - variant === 'feed' ? a.text_xs : a.text_sm, - t.atoms.text_contrast_medium, - ] - const nameStyle = [a.text_sm, a.font_semi_bold, t.atoms.text] + names.length >= 2 + ? l`Liked by ${names[0].displayName} and ${names[1].displayName}` + : l`Liked by ${names[0].displayName}` + const textStyle = [a.text_sm, t.atoms.text_contrast_medium] + const nameStyle = [a.text_sm, a.font_medium, t.atoms.text_contrast_medium] const nameLink = (name: (typeof names)[number]) => ( @@ -92,35 +83,21 @@ export function KnownLikers({ ) return ( - + ax.metric('post:likedBy:click', {})}> - {variant === 'feed' ? ( - likeCount > 1 ? ( - - {names[0].displayName} and{' '} - {' '} - liked this - - ) : ( - - {names[0].displayName} liked this - - ) - ) : names.length >= 2 ? ( + {names.length >= 2 ? ( Liked by {nameLink(names[0])} and {nameLink(names[1])} diff --git a/src/components/WhoCanReply.tsx b/src/components/WhoCanReply.tsx index 280cbd0cbb..5f5480d9fc 100644 --- a/src/components/WhoCanReply.tsx +++ b/src/components/WhoCanReply.tsx @@ -114,7 +114,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) { style={[ a.flex_row, a.align_center, - a.gap_xs, + {gap: 3}, (hovered || focused || pressed) && native({opacity: 0.5}), style, ]}> @@ -122,16 +122,16 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) { color={ isThreadAuthor ? t.palette.primary_500 : t.palette.contrast_400 } - width={16} + width={12} settings={settings} /> {description} diff --git a/src/screens/PostThread/components/LikesStat.tsx b/src/screens/PostThread/components/LikesStat.tsx index 0b2fa30b53..28d1f95735 100644 --- a/src/screens/PostThread/components/LikesStat.tsx +++ b/src/screens/PostThread/components/LikesStat.tsx @@ -32,9 +32,9 @@ export function LikesStat({post}: {post: app.bsky.feed.defs.PostView}) { onPress={() => ax.metric('post:likedBy:click', {})}> + style={[a.text_sm, t.atoms.text_contrast_high]}> - + {formatPostStatCount(likeCount)} {' '} diff --git a/src/screens/PostThread/components/ThreadItemAnchor.tsx b/src/screens/PostThread/components/ThreadItemAnchor.tsx index 8a4f714157..350e71d210 100644 --- a/src/screens/PostThread/components/ThreadItemAnchor.tsx +++ b/src/screens/PostThread/components/ThreadItemAnchor.tsx @@ -452,7 +452,6 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ columnGap: a.gap_lg.gap, }, a.border_t, - a.border_b, a.mt_md, a.py_md, t.atoms.border_contrast_low, @@ -461,10 +460,10 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ + style={[a.text_sm, t.atoms.text_contrast_high]}> + style={[a.text_sm, a.font_semi_bold, t.atoms.text]}> {formatPostStatCount(post.repostCount)} {' '} + style={[a.text_sm, t.atoms.text_contrast_high]}> + style={[a.text_sm, a.font_semi_bold, t.atoms.text]}> {formatPostStatCount(post.quoteCount)} {' '} + style={[a.text_sm, t.atoms.text_contrast_high]}> - + {formatPostStatCount(post.bookmarkCount)} {' '} ) : null} - ) : null} + - + {niceDate(i18n, post.indexedAt, 'dot separated')} {isRootPost && ( diff --git a/src/state/queries/usePostThread/index.ts b/src/state/queries/usePostThread/index.ts index b4e217f4bd..cc42464a06 100644 --- a/src/state/queries/usePostThread/index.ts +++ b/src/state/queries/usePostThread/index.ts @@ -33,6 +33,7 @@ import {useMergeThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies import {useBreakpoints} from '#/alf' import {IS_WEB} from '#/env' import {app} from '#/lexicons' +import * as bsky from '#/types/bsky' export * from '#/state/queries/usePostThread/context' export {useUpdatePostThreadThreadgateQueryCache} from '#/state/queries/usePostThread/queryCache' @@ -73,6 +74,7 @@ export function usePostThread({anchor}: {anchor?: string}) { enabled: isThreadPreferencesLoaded && !!anchor && !!moderationOpts, queryKey: postThreadQueryKey, async queryFn(ctx) { + const placeholder = getThreadPlaceholder(qc, anchor!) const data = await client.call(app.bsky.unspecced.getPostThreadV2, { anchor: anchor! as AtUriString, branchingFactor: view === 'linear' ? LINEAR_VIEW_BF : TREE_VIEW_BF, @@ -80,6 +82,28 @@ export function usePostThread({anchor}: {anchor?: string}) { sort: sort, }) + const cachedKnownLikers = + placeholder && + bsky.isType(app.bsky.unspecced.defs.threadItemPost, placeholder.value) + ? placeholder.value.post.viewer?.knownLikers + : undefined + if (cachedKnownLikers?.actors.length) { + const anchorItem = data.thread?.find(item => item.uri === anchor) + if ( + anchorItem && + bsky.isType( + app.bsky.unspecced.defs.threadItemPost, + anchorItem.value, + ) && + !anchorItem.value.post.viewer?.knownLikers?.actors.length + ) { + anchorItem.value.post.viewer = { + ...anchorItem.value.post.viewer, + knownLikers: cachedKnownLikers, + } + } + } + /* * Initialize `ctx.meta` to track if we know we have additional replies * we could fetch once we hit the end. diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx index b2a1a4fbc4..a5c16d5a94 100644 --- a/src/view/com/posts/PostFeedItem.tsx +++ b/src/view/com/posts/PostFeedItem.tsx @@ -445,11 +445,6 @@ let FeedItemInner = ({ additionalPostAlerts={additionalPostAlerts} feedDescriptor={feedDescriptor} /> - +