feat: custom status message — display + editor with emoji picker

- MembersDrawer: show presence.status as small muted text below
  username in every member row (live via useUserPresence)
- UserHero/UserHeroName: accept optional status prop; render below
  the @username handle in user profile popouts
- UserRoomProfile: pass presence?.status down to UserHeroName
- Profile settings: new ProfileStatus tile below Display Name
  * Input with inline emoji picker (lazy-loaded EmojiBoard)
  * Cursor-aware emoji insertion (preserves caret position)
  * Save via mx.setPresence({ status_msg }) / Clear button
  * Pre-fills from current presence; syncs on remote update

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 12:39:51 -04:00
parent bb2e25de2d
commit 46da4458ff
4 changed files with 186 additions and 3 deletions
+9 -1
View File
@@ -95,8 +95,9 @@ export function UserHero({ userId, avatarUrl, presence }: UserHeroProps) {
type UserHeroNameProps = {
displayName?: string;
userId: string;
status?: string;
};
export function UserHeroName({ displayName, userId }: UserHeroNameProps) {
export function UserHeroName({ displayName, userId, status }: UserHeroNameProps) {
const username = getMxIdLocalPart(userId);
return (
@@ -115,6 +116,13 @@ export function UserHeroName({ displayName, userId }: UserHeroNameProps) {
@{username}
</Text>
</Box>
{status && (
<Box alignItems="Center" gap="100" wrap="Wrap" style={{ marginTop: '2px' }}>
<Text size="T200" className={classNames(BreakWord, LineClamp3)} style={{ opacity: 0.75 }}>
{status}
</Text>
</Box>
)}
</Box>
);
}
@@ -237,7 +237,7 @@ export function UserRoomProfile({ userId }: UserRoomProfileProps) {
<Box direction="Column" gap="500" style={{ padding: config.space.S400 }}>
<Box direction="Column" gap="400">
<Box gap="400" alignItems="Center">
<UserHeroName displayName={displayName} userId={userId} />
<UserHeroName displayName={displayName} userId={userId} status={presence?.status} />
{showEncryption && <MemberVerificationBadge userId={userId} />}
{userId !== myUserId && (
<Box shrink="No">