A React component library for rendering common AT Protocol records for applications such as Bluesky and Leaflet.

reorder bluesky icon to show on oldest parent rather than most recent child in threads

Changed files
+86 -12
lib
src
+77 -5
lib/components/BlueskyPost.tsx
···
*/
authorHandle: string;
/**
+
* The author's display name from their profile.
+
*/
+
authorDisplayName?: string;
+
/**
* The DID that owns the post record.
*/
authorDid: string;
···
const avatar = profile?.avatar;
const avatarCdnUrl = isBlobWithCdn(avatar) ? avatar.cdnUrl : undefined;
const avatarCid = avatarCdnUrl ? undefined : getAvatarCid(profile);
+
const authorDisplayName = profile?.displayName;
const {
record: fetchedRecord,
···
<Comp
{...props}
authorHandle={authorHandle}
+
authorDisplayName={authorDisplayName}
authorDid={repoIdentifier}
avatarUrl={avatarUrl}
iconPlacement={iconPlacement}
···
avatarCid,
avatarCdnUrl,
authorHandle,
+
authorDisplayName,
iconPlacement,
showIcon,
atUri,
showParent,
]);
+
const WrappedWithoutIcon = useMemo(() => {
+
const WrappedComponent: React.FC<{
+
record: FeedPostRecord;
+
loading: boolean;
+
error?: Error;
+
}> = (props) => {
+
const { url: avatarUrlFromBlob } = useBlob(
+
repoIdentifier,
+
avatarCid,
+
);
+
const avatarUrl = avatarCdnUrl || avatarUrlFromBlob;
+
return (
+
<Comp
+
{...props}
+
authorHandle={authorHandle}
+
authorDisplayName={authorDisplayName}
+
authorDid={repoIdentifier}
+
avatarUrl={avatarUrl}
+
iconPlacement={iconPlacement}
+
showIcon={false}
+
atUri={atUri}
+
isInThread
+
threadDepth={showParent ? 1 : 0}
+
showThreadBorder={!showParent && !!props.record?.reply?.parent}
+
/>
+
);
+
};
+
WrappedComponent.displayName = "BlueskyPostWrappedRendererWithoutIcon";
+
return WrappedComponent;
+
}, [
+
Comp,
+
repoIdentifier,
+
avatarCid,
+
avatarCdnUrl,
+
authorHandle,
+
authorDisplayName,
+
iconPlacement,
+
atUri,
+
showParent,
+
]);
+
if (!displayHandle && resolvingIdentity) {
return <div style={{ padding: 8 }}>Resolving handle…</div>;
}
···
);
};
+
const renderMainPostWithoutIcon = (mainRecord?: FeedPostRecord) => {
+
if (mainRecord !== undefined) {
+
return (
+
<AtProtoRecord<FeedPostRecord>
+
record={mainRecord}
+
renderer={WrappedWithoutIcon}
+
fallback={fallback}
+
loadingIndicator={loadingIndicator}
+
/>
+
);
+
}
+
+
return (
+
<AtProtoRecord<FeedPostRecord>
+
did={repoIdentifier}
+
collection={BLUESKY_POST_COLLECTION}
+
rkey={rkey}
+
renderer={WrappedWithoutIcon}
+
fallback={fallback}
+
loadingIndicator={loadingIndicator}
+
/>
+
);
+
};
+
if (showParent) {
if (currentLoading || (parentLoading && !parentRecord)) {
return (
···
record={parentRecord}
showParent={true}
recursiveParent={true}
-
showIcon={false}
-
iconPlacement="cardBottomRight"
+
showIcon={showIcon}
+
iconPlacement={iconPlacement}
/>
) : (
<BlueskyPost
did={parentDid}
rkey={parentRkey}
record={parentRecord}
-
showIcon={false}
-
iconPlacement="cardBottomRight"
+
showIcon={showIcon}
+
iconPlacement={iconPlacement}
/>
)}
</div>
<div style={replyPostStyle}>
-
{renderMainPost(record || currentRecord)}
+
{renderMainPostWithoutIcon(record || currentRecord)}
</div>
</div>
);
+7 -5
lib/renderers/BlueskyPostRenderer.tsx
···
gap: inline ? 8 : 0,
}}
>
-
<strong style={{ fontSize: 14 }}>{primaryName}</strong>
-
{authorDisplayName && authorHandle && (
+
<strong style={{ fontSize: 14 }}>{authorDisplayName || primaryName}</strong>
+
{authorHandle && (
<span
style={{
...baseStyles.handle,
···
))}
</div>
)}
+
{resolvedEmbed && (
+
<div style={baseStyles.embedContainer}>{resolvedEmbed}</div>
+
)}
<div style={baseStyles.timestampRow}>
<time
style={{
···
</span>
)}
</div>
-
{resolvedEmbed && (
-
<div style={baseStyles.embedContainer}>{resolvedEmbed}</div>
-
)}
</div>
);
···
marginTop: 12,
padding: 8,
borderRadius: 12,
+
border: `1px solid var(--atproto-color-border)`,
+
background: `var(--atproto-color-bg-elevated)`,
display: "flex",
flexDirection: "column",
gap: 8,
+2 -2
src/App.tsx
···
Reply Post Demo
</h3>
<BlueskyPost
-
did="nekomimi.pet"
-
rkey="3m36jkng6nk22"
+
did="did:plc:xwhsmuozq3mlsp56dyd7copv"
+
rkey="3m3je5ydg4s2o"
showParent={true}
recursiveParent={true}
/>