feat: presence avatar border rings (P5-18) + room emoji prefix support (P5-6)

P5-18: PresenceRingAvatar wrapper component applies a 2px box-shadow
ring to user avatars — green (online), yellow (idle/unavailable), red
(DND via status_msg='dnd'), no ring (offline). Applied to: message
timeline sender avatars, members drawer (members + knock requests),
@mention autocomplete, and inbox notification senders.

P5-6: Leading emoji in room names renders at 1.15× in the sidebar via
Unicode emoji regex detection in RoomNavItem. Emoji picker (EmojiBoard
in PopOut) added to all three room-name inputs: Create Room dialog
(converted to controlled input), Room Settings name field (shown only
when canEditName), and the "Rename for me" local rename dialog.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 21:56:19 -04:00
parent 4876c2e4ca
commit c5fbc20394
11 changed files with 326 additions and 103 deletions
+22 -19
View File
@@ -96,6 +96,7 @@ import {
} from '../../../hooks/useMemberPowerTag';
import { useRoomCreatorsTag } from '../../../hooks/useRoomCreatorsTag';
import { useRoomCreators } from '../../../hooks/useRoomCreators';
import { PresenceRingAvatar } from '../../../components/presence';
type RoomNotificationsGroup = {
roomId: string;
@@ -478,25 +479,27 @@ function RoomNotificationsGroupComp({
<ModernLayout
before={
<AvatarBase>
<Avatar size="300">
<UserAvatar
userId={event.sender}
src={
senderAvatarMxc
? (mxcUrlToHttp(
mx,
senderAvatarMxc,
useAuthentication,
48,
48,
'crop',
) ?? undefined)
: undefined
}
alt={displayName}
renderFallback={() => <Icon size="200" src={Icons.User} filled />}
/>
</Avatar>
<PresenceRingAvatar userId={event.sender}>
<Avatar size="300">
<UserAvatar
userId={event.sender}
src={
senderAvatarMxc
? (mxcUrlToHttp(
mx,
senderAvatarMxc,
useAuthentication,
48,
48,
'crop',
) ?? undefined)
: undefined
}
alt={displayName}
renderFallback={() => <Icon size="200" src={Icons.User} filled />}
/>
</Avatar>
</PresenceRingAvatar>
</AvatarBase>
}
>