feat(posts): support pseudonymityMode per-reply hiding

Hide user ID display in posts and replies when subplebbit.features.pseudonymityMode is 'per-reply'. Uses useSubplebbitField to avoid unnecessary rerenders.
This commit is contained in:
plebeius
2026-02-09 16:22:18 +08:00
parent 6192095bd4
commit c1b0d13bb7
2 changed files with 58 additions and 42 deletions
+29 -21
View File
@@ -21,6 +21,7 @@ import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
import useHide from '../../hooks/use-hide'; import useHide from '../../hooks/use-hide';
import useStateString from '../../hooks/use-state-string'; import useStateString from '../../hooks/use-state-string';
import useScrollToReply from '../../hooks/use-scroll-to-reply'; import useScrollToReply from '../../hooks/use-scroll-to-reply';
import { useSubplebbitField } from '../../hooks/use-stable-subplebbit';
import CommentContent from '../comment-content'; import CommentContent from '../comment-content';
import CommentMedia from '../comment-media'; import CommentMedia from '../comment-media';
import EditMenu from '../edit-menu/edit-menu'; import EditMenu from '../edit-menu/edit-menu';
@@ -202,6 +203,9 @@ const PostInfo = ({
const handleUserAddressClick = useAuthorAddressClick(); const handleUserAddressClick = useAuthorAddressClick();
const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length; const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length;
const pseudonymityMode = useSubplebbitField(subplebbitAddress, (sub) => sub?.features?.pseudonymityMode);
const showUserID = pseudonymityMode !== 'per-reply';
const { hidden } = useHide(post); const { hidden } = useHide(post);
const { openReplyModal } = useReplyModalStore(); const { openReplyModal } = useReplyModalStore();
@@ -265,28 +269,32 @@ const PostInfo = ({
<img src={avatarImageUrl} alt='' /> <img src={avatarImageUrl} alt='' />
</span> </span>
) : null} ) : null}
(ID:{' '} {showUserID && (
{deleted ? ( <>
t('deleted') (ID:{' '}
) : removed ? ( {deleted ? (
t('removed') t('deleted')
) : ( ) : removed ? (
<Tooltip t('removed')
children={ ) : (
<span <Tooltip
title={t('highlight_posts')} children={
className={styles.userAddress} <span
onClick={() => handleUserAddressClick(userID, postCid)} title={t('highlight_posts')}
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }} className={styles.userAddress}
> onClick={() => handleUserAddressClick(userID, postCid)}
{userID} style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
</span> >
} {userID}
content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`} </span>
showTooltip={isInPostPageView || showOmittedReplies[postCid] || (postReplyCount < 6 && !pinned)} }
/> content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`}
showTooltip={isInPostPageView || showOmittedReplies[postCid] || (postReplyCount < 6 && !pinned)}
/>
)}
){' '}
</>
)} )}
){' '}
</span> </span>
<span className={styles.dateTime}> <span className={styles.dateTime}>
{isInModQueueView && isOverThreshold ? ( {isInModQueueView && isOverThreshold ? (
+29 -21
View File
@@ -20,6 +20,7 @@ import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
import useHide from '../../hooks/use-hide'; import useHide from '../../hooks/use-hide';
import useStateString from '../../hooks/use-state-string'; import useStateString from '../../hooks/use-state-string';
import useScrollToReply from '../../hooks/use-scroll-to-reply'; import useScrollToReply from '../../hooks/use-scroll-to-reply';
import { useSubplebbitField } from '../../hooks/use-stable-subplebbit';
import CommentContent from '../comment-content'; import CommentContent from '../comment-content';
import CommentMedia from '../comment-media'; import CommentMedia from '../comment-media';
import LoadingEllipsis from '../loading-ellipsis'; import LoadingEllipsis from '../loading-ellipsis';
@@ -169,6 +170,9 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
const handleUserAddressClick = useAuthorAddressClick(); const handleUserAddressClick = useAuthorAddressClick();
const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length; const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length;
const pseudonymityMode = useSubplebbitField(subplebbitAddress, (sub) => sub?.features?.pseudonymityMode);
const showUserID = pseudonymityMode !== 'per-reply';
const userID = address && Plebbit.getShortAddress({ address }); // should not be shortened to less than 12 characters, because users can create unlimited addresses/IDs before authenticating or passing challenges, so if the ID is short enough they can spoof it to troll users with the same ID const userID = address && Plebbit.getShortAddress({ address }); // should not be shortened to less than 12 characters, because users can create unlimited addresses/IDs before authenticating or passing challenges, so if the ID is short enough they can spoof it to troll users with the same ID
const userIDBackgroundColor = hashStringToColor(userID); const userIDBackgroundColor = hashStringToColor(userID);
const userIDTextColor = getTextColorForBackground(userIDBackgroundColor); const userIDTextColor = getTextColorForBackground(userIDBackgroundColor);
@@ -231,28 +235,32 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
<img src={avatarImageUrl} alt='' /> <img src={avatarImageUrl} alt='' />
</span> </span>
) : null} ) : null}
(ID: {''} {showUserID && (
{removed ? ( <>
_.lowerCase(t('removed')) (ID: {''}
) : deleted ? ( {removed ? (
_.lowerCase(t('deleted')) _.lowerCase(t('removed'))
) : ( ) : deleted ? (
<Tooltip _.lowerCase(t('deleted'))
children={ ) : (
<span <Tooltip
title={t('highlight_posts')} children={
className={styles.userAddress} <span
onClick={() => handleUserAddressClick(userID, postCid)} title={t('highlight_posts')}
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }} className={styles.userAddress}
> onClick={() => handleUserAddressClick(userID, postCid)}
{userID} style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
</span> >
} {userID}
content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`} </span>
showTooltip={isInPostPageView || postReplyCount < 6} }
/> content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`}
showTooltip={isInPostPageView || postReplyCount < 6}
/>
)}
){' '}
</>
)} )}
){' '}
{pinned && ( {pinned && (
<span className={styles.stickyIconWrapper}> <span className={styles.stickyIconWrapper}>
<img src='assets/icons/sticky.gif' alt='' className={styles.stickyIcon} title={t('sticky')} /> <img src='assets/icons/sticky.gif' alt='' className={styles.stickyIcon} title={t('sticky')} />