refactor: prioritize handles across the interface
141 unmodified linesExpand all14214314414514614714814915015115215315415515615715815916016114614714814943 unmodified lines141 unmodified linesExpand all marginBottom: 'auto', paddingBottom: space.sm,});
export const nameRow = style({ display: 'flex', flexDirection: 'row', alignItems: 'center', maxWidth: '100%',});
export const badges = style({ flexShrink: 0, paddingLeft: space.xs,
':empty': { display: 'none', },});
export const identity = style({ display: 'flex', flexDirection: 'column', gap: space.xs,43 unmodified lines15 unmodified lines16171819202021222331 unmodified lines555657586059606162639 unmodified lines7374757678798081828384858687888977787980813 unmodified lines858687881018990919293144 unmodified linesExpand all15 unmodified lines
import { BlockLink } from '#/components/BlockLink';import * as Dialog from '#/components/Dialog';import * as css from '#/components/FeedInterstitials.css';import { ProfileBadges } from '#/components/ProfileBadges';import { SuggestedFollowsDialog } from '#/components/SuggestedFollowsDialog';import { Text } from '#/components/Text';import * as ProfileCard from '#/components/web/ProfileCard';import * as Skeleton from '#/components/web/Skeleton';31 unmodified lines return ( <BlockLink className={clsx(css.cardBase, css.cardLink)} label={m['common.profile.a11y.viewNamed']({ name: profile.displayName || profile.handle, name: profile.handle, })} to={profileTarget(profile.did)} > <div>9 unmodified lines )} <div className={css.body}> <ProfileCard.Avatar disabledPreview moderationOpts={moderationOpts} profile={profile} size={88} /> <div className={css.identity}> <div className={css.nameRow}> <ProfileCard.Name color="text" moderationOpts={moderationOpts} profile={profile} size="lg" weight="semiBold" /> <div className={css.badges}> <ProfileBadges profile={profile} size="md" /> </div> </div> <ProfileCard.Handle profile={profile} /> <div className={css.description}> <ProfileCard.Description align="center" color="textContrastMedium"3 unmodified lines /> </div> </div> </div> <ProfileCard.FollowButton moderationOpts={moderationOpts} profile={profile} variant="text-only" /> <ProfileCard.FollowButton profile={profile} variant="text-only" /> </div> </BlockLink> );}144 unmodified linesExpand all1223465697891050 unmodified lines61626364686566677273747576777879686970717235 unmodified linesimport type { AppBskyActorDefs } from '@atcute/bluesky';import { DisplayContext, getDisplayRestrictions, moderateProfile } from '@atcute/bluesky-moderation';
import { differenceInSeconds } from '@mary/date-fns';
import { sanitizeDisplayName } from '#/lib/display-names';import { useConstant } from '#/lib/hooks/use-constant';
import { useModerationOpts } from '#/state/moderation/moderation-opts';import { useSession } from '#/state/session';
import { relativeMessageParts } from '#/locale/intl/timeAgo';
50 unmodified lines createdAt: string; now: Date; onClose: () => void;}) { const moderationOpts = useModerationOpts(); const { currentAccount } = useSession(); const isMe = profile.did === currentAccount?.did;
let profileName = profile.displayName || profile.handle; if (moderationOpts) { const moderation = moderateProfile(profile, moderationOpts); profileName = sanitizeDisplayName( profile.displayName || profile.handle, getDisplayRestrictions(moderation, DisplayContext.ProfileBio), ); } const profileName = profile.handle;
const getJoinMessage = () => { const parts = relativeMessageParts(createdAt, now);
35 unmodified lines3 unmodified lines4567889101132 unmodified lines4445464749484950515250 unmodified lines3 unmodified linesimport { useQueryClient } from '@tanstack/react-query';import { assignInlineVars } from '@vanilla-extract/dynamic';
import { IS_TOUCH_DEVICE } from '#/lib/browser/platform';import { sanitizeDisplayName } from '#/lib/display-names';import { profileTarget } from '#/lib/routes/targets';
import { unstableCacheProfileView } from '#/state/queries/unstable-profile-cache';
32 unmodified lines const queryClient = useQueryClient(); const status = useActorStatus(profile); const liveHandle = Dialog.useDialogHandle();
const name = sanitizeDisplayName(profile.displayName || profile.handle); const name = profile.handle; const circular = props.type !== 'algo' && props.type !== 'list'; const radius = circular ? '50%' : props.size > 32 ? '8px' : '3px';
const avatarEl = (50 unmodified lines29 unmodified lines3031323334343536353637383940414229 unmodified lines <span className={styles.text}> <Text numberOfLines={1} weight="medium"> {row.profile.handle} </Text> {row.profile.displayName ? ( <Text color="textContrastMedium" numberOfLines={1} size="md_sub"> {row.profile.displayName || row.profile.handle} </Text> <Text color="textContrastMedium" numberOfLines={1} size="md_sub"> {row.profile.displayName} </Text> ) : null} </span> </Autocomplete.Item> );}39 unmodified lines404142434444454645464748495051525 unmodified lines39 unmodified lines <span className={styles.text}> <Text numberOfLines={1} weight="medium"> {row.profile.handle} </Text> {row.profile.displayName ? ( <Text color="textContrastMedium" numberOfLines={1} size="md_sub"> {row.profile.displayName || row.profile.handle} </Text> <Text color="textContrastMedium" numberOfLines={1} size="md_sub"> {row.profile.displayName} </Text> ) : null} </span> </Autocomplete.Item> <RecentRemoveButton label={m['components.web.search.recent.removeA11y']({ query: row.profile.handle })}5 unmodified lines1 unmodified line2345678910140 unmodified linesExpand all15115215315415515615715815910 unmodified lines170171172173172174175176177178176177178179180181182183184185186112 unmodified linesExpand all1 unmodified line
import { Drawer as BaseDrawer } from '@base-ui/react/drawer';import { clsx } from 'clsx';
import { sanitizeDisplayName } from '#/lib/display-names';import { profileTarget } from '#/lib/routes/targets';
import { useProfileQuery, useProfilesQuery } from '#/state/queries/profile';import { type SessionAccount, useSession } from '#/state/session';140 unmodified linesExpand all onPressProfile: () => void;}) { const { data: profile } = useProfileQuery({ did: account.did }); const { isActive: live } = useActorStatus(profile); const displayName = profile?.displayName ? sanitizeDisplayName(profile.displayName) : '';
return ( <div className={styles.profileCardWrap}> <button10 unmodified lines /> <div> <div className={styles.profileNameRow}> <Text numberOfLines={1} size="xl" weight="bold"> {profile?.displayName || account.handle} {account.handle} </Text> {profile && <ProfileBadges profile={profile} size="lg" />} </div> {displayName ? ( <Text color="textContrastMedium" numberOfLines={1} size="md"> {`@${account.handle}`} </Text> <Text color="textContrastMedium" numberOfLines={1} size="md"> {displayName} </Text> ) : null} </div> <Text color="textContrastMedium" size="md"> <Trans inputs={{112 unmodified linesExpand all12345456710 unmodified lines1819202124222324252619 unmodified linesimport type { AnyProfileView } from '@atcute/bluesky';import type { ModerationOptions } from '@atcute/bluesky-moderation';
import { profileDisplayName } from '#/lib/display-names';
import { SubscribeProfileDialog } from '#/components/activity-notifications/SubscribeProfileDialog';import * as Dialog from '#/components/Dialog';import { Button, ButtonIcon } from '#/components/web/Button';
10 unmodified lines profile: AnyProfileView;}) { const handle = Dialog.useDialogHandle();
const name = profileDisplayName(profile, { bareHandle: true }); const name = profile.handle; const isSubscribed = profile.viewer?.activitySubscription?.post || profile.viewer?.activitySubscription?.reply; const Icon = isSubscribed ? BellRingingIcon : BellPlusIcon;
19 unmodified lines3 unmodified lines4567889101174 unmodified lines8687888991909192939460 unmodified lines155156157158160159160161162163316 unmodified linesExpand all48048148248348548648748848948448548648748852 unmodified lines54154254354455054554654754854947 unmodified lines3 unmodified lines
import { useQueryClient } from '@tanstack/react-query';import { clsx } from 'clsx';
import { profileDisplayName } from '#/lib/display-names';import { isBlockedOrBlocking } from '#/lib/moderation/blocked-and-muted';import { isOnlyEmoji } from '#/lib/utils/emoji';
import { useMaybeProfileShadow } from '#/state/cache/profile-shadow';74 unmodified lines const onPressReplyTo = replyToMessageId ? () => scrollToMessage(replyToMessageId) : undefined;
const isPending = item.type === 'pendingMessage';
const displayName = profile ? profileDisplayName(profile) : null; const displayName = profile?.handle ?? null;
const isFromSelf = message.sender?.did != null && message.sender.did === currentAccount?.did;
const visibleReactions = filterBlockedReactions(message.reactions, relatedProfiles);60 unmodified lines const senderDid = reaction.sender.did; const memberSender = relatedProfiles.get(senderDid); if (memberSender) { reactionsLabel = m['components.dms.reaction.reactedBy']({ name: profileDisplayName(memberSender), name: memberSender.handle, reaction: reaction.value, }); } else { reactionsLabel = m['components.dms.update.someoneReacted']({ value: reaction.value });316 unmodified linesExpand all replyTo.$type === 'chat.bsky.convo.defs#deletedMessageView' ) { const originalSenderIsSelf = replyTo.sender.did === currentAccount?.did; const originalProfile = relatedProfiles.get(replyTo.sender.did); const originalName = originalSenderIsSelf ? null : originalProfile ? profileDisplayName(originalProfile) : null; const originalName = originalSenderIsSelf ? null : originalProfile ? originalProfile.handle : null; caption = isFromSelf ? originalSenderIsSelf ? m['components.dms.update.youRepliedToYourself']() : originalName52 unmodified lines const senderProfile = useMaybeProfileShadow(senderDid ? relatedProfiles.get(senderDid) : undefined); // Hide the quoted content if we block, or are blocked by, the original // sender - mirroring how the message bubble itself is hidden. const isBlocked = senderProfile ? isBlockedOrBlocking(senderProfile) : false; const senderName = senderProfile && !isBlocked ? profileDisplayName(senderProfile) : null; const senderName = senderProfile && !isBlocked ? senderProfile.handle : null;
const tintColor = isFromSelf ? 'white' : 'text'; const subtleColor = isFromSelf ? 'white' : 'textContrastHigh'; const borderColor = isFromSelf ? 'rgba(255, 255, 255, 0.5)' : colors.borderContrastHigh;47 unmodified lines123345649 unmodified lines5657585961606162636446 unmodified linesimport type { AnyProfileView, ChatBskyActorDefs, ChatBskyConvoDefs } from '@atcute/bluesky';
import { profileDisplayName } from '#/lib/display-names';import { isBlockedOrBlocking } from '#/lib/moderation/blocked-and-muted';import { recordUriToShareUrl } from '#/lib/routes/app-links';import { toShortUrl } from '#/lib/utils/url';
49 unmodified lines const lastMessage = convo.lastMessage; const isFromMe = lastMessage.sender?.did === currentAccountDid; const senderDid = lastMessage.sender?.did; const sender = convo.members.find((mem) => mem.did === senderDid); const name = sender ? profileDisplayName(sender) : null; const name = sender?.handle ?? null; const isGroup = convo.kind?.$type === 'chat.bsky.convo.defs#groupConvo';
const reportableMessage = isFromMe ? undefined : lastMessage; const isBlockedMessage = isDidBlockedInConvo({46 unmodified lines1234345619 unmodified lines2627282932303132333429 unmodified linesimport type { AnyProfileView, ChatBskyConvoDefs } from '@atcute/bluesky';
import { profileDisplayName } from '#/lib/display-names';
import { isDidBlockedInConvo } from '#/components/dms/getMessageInfo';
import { m } from '#/paraglide/messages';
19 unmodified lines const { reaction, message: reactedTo } = convo.lastReaction; const isFromMe = reaction.sender.did === currentAccountDid; const senderDid = reaction.sender.did; const sender = convo.members.find((member) => member.did === senderDid); const name = sender ? profileDisplayName(sender) : null; const name = sender?.handle ?? null;
// Hide the preview when either the reactor or the author of the reacted-to message is blocked — // otherwise a blocked reactor's name or a blocked sender's message text would leak into the chat list. const isBlocked =29 unmodified lines12345656785 unmodified lines1415161720181920212212 unmodified lines353637384139404142437 unmodified lines5152535457585556575859604 unmodified lines6566676871726970717273744 unmodified lines7980818285868384858687884 unmodified lines939495969910097989910010110251 unmodified linesimport type { ComponentType, SVGProps } from 'react';
import type { ChatBskyActorDefs, ChatBskyConvoDefs } from '@atcute/bluesky';
import { profileDisplayName } from '#/lib/display-names';
import LeaveIcon from '#/icons/central/ArrowBoxLeft_round_outlined_radius1_stroke2.svg';import JoinIcon from '#/icons/central/ArrowBoxRight_round_outlined_radius1_stroke2.svg';import ChainLinkBrokenIcon from '#/icons/central/BrokenChainLink3_round_outlined_radius1_stroke2.svg';import ChainLinkIcon from '#/icons/central/ChainLink3_round_outlined_radius1_stroke2.svg';5 unmodified linesexport type SystemMessageAction = | { kind: 'profile'; profile: ChatBskyActorDefs.ProfileViewBasic; displayName: string; handle: string; } | { kind: 'inviteLink' };
export type SystemMessageInfo = {12 unmodified lines } return { kind: 'profile', profile, displayName: profileDisplayName(profile), handle: profile.handle, };}
export function getSystemMessageInfo(7 unmodified lines return { Icon: JoinIcon, message: action ? opts.short ? m['components.dms.update.added']({ name: action.displayName }) : m['components.dms.update.addedToGroup']({ name: action.displayName }) ? m['components.dms.update.added']({ name: action.handle }) : m['components.dms.update.addedToGroup']({ name: action.handle }) : opts.short ? m['components.dms.update.someoneAdded']() : m['components.dms.update.someoneAddedToGroup'](), action: action ?? undefined,4 unmodified lines return { Icon: LeaveIcon, message: action ? opts.short ? m['components.dms.update.removed']({ name: action.displayName }) : m['components.dms.update.removedFromGroup']({ name: action.displayName }) ? m['components.dms.update.removed']({ name: action.handle }) : m['components.dms.update.removedFromGroup']({ name: action.handle }) : opts.short ? m['components.dms.update.someoneRemoved']() : m['components.dms.update.someoneRemovedFromGroup'](), action: action ?? undefined,4 unmodified lines return { Icon: JoinIcon, message: action ? opts.short ? m['components.dms.update.joined']({ name: action.displayName }) : m['components.dms.update.joinedGroup']({ name: action.displayName }) ? m['components.dms.update.joined']({ name: action.handle }) : m['components.dms.update.joinedGroup']({ name: action.handle }) : opts.short ? m['components.dms.update.someoneJoined']() : m['components.dms.update.someoneJoinedGroup'](), action: action ?? undefined,4 unmodified lines return { Icon: LeaveIcon, message: action ? opts.short ? m['components.dms.update.left']({ name: action.displayName }) : m['components.dms.update.leftGroup']({ name: action.displayName }) ? m['components.dms.update.left']({ name: action.handle }) : m['components.dms.update.leftGroup']({ name: action.handle }) : opts.short ? m['components.dms.update.someoneLeft']() : m['components.dms.update.someoneLeftGroup'](), action: action ?? undefined,51 unmodified lines1234345675 unmodified lines8283848588868788899025 unmodified linesimport type { AnyProfileView } from '@atcute/bluesky';
import { profileDisplayName } from '#/lib/display-names';
import { useSession } from '#/state/session';
import { Trans } from '#/locale/Trans';
75 unmodified linesfunction DialogInner({ handle, profile }: { handle: Dialog.DialogHandle; profile: AnyProfileView }) { const { currentAccount } = useSession();
const isSelf = profile.did === currentAccount?.did; const name = profileDisplayName(profile); const name = profile.handle; const label = isSelf ? m['components.verification.trustedVerifier.youStatus']() : m['components.verification.trustedVerifier.userStatus']({ name });
25 unmodified lines235 unmodified linesExpand all23623723823924024124024124224324494 unmodified lines33934034134234434534634734834935035135234334434534634744 unmodified lines235 unmodified linesExpand all <ProfileCard.Link profile={item}> <ProfileCard.Avatar disabledPreview moderationOpts={moderationOpts} profile={item} size={44} /> </ProfileCard.Link> <div> <ProfileCard.Name moderationOpts={moderationOpts} profile={item} /> <ProfileCard.Handle profile={item} /> <ProfileCard.NameAndHandle moderationOpts={moderationOpts} profile={item} /> <div className={css.knownFollowers}> <KnownFollowers moderationOpts={moderationOpts} profile={item} showIfEmpty variant="compact" /> </div> <div className={css.actions}>94 unmodified lines ) : ( list )} {showFooter ? footer : null} {owner && moderationOpts && ( <InviteLinkDialog convo={convo} handle={inviteLinkHandle} owner={owner} isOwner={isOwner} moderationOpts={moderationOpts} /> )} {owner && <InviteLinkDialog convo={convo} handle={inviteLinkHandle} isOwner={isOwner} owner={owner} />} </> );}
44 unmodified lines