From f50f20052ae7e5c0c70554a138eccc317cc613b3 Mon Sep 17 00:00:00 2001 From: ranidspace Date: Fri, 27 Feb 2026 18:55:43 -0500 Subject: [PATCH 1/2] Change profile pronouns to closer follow MSC4247 Fixes #23 The pronouns field is an array of pronoun sets rather than the entire array representing one set. This follows MSC4247, and aligns with the way it's displayed in gomuks and Commet. For compatibility with gomuks, the value of `language` for each is set to "en". In the future this should be set manually or use the client language. Pronoun summaries are limited to 16 characters each, and truncated to that length if it is longer. When displayed as a string, or when it is set, they are comma separated. When they are displayed next to the username in a message, they're each in an individual pill, only showing the first 3. If more than 3 are there, an extra pill showing "..." is displayed. An optional `grammatical_gender` field now exists, however it is currently unused. --- .../user-profile/UserRoomProfile.tsx | 2 +- src/app/features/room/message/Message.tsx | 33 ++++++++++--------- .../settings/account/PronounEditor.tsx | 9 ++--- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/app/components/user-profile/UserRoomProfile.tsx b/src/app/components/user-profile/UserRoomProfile.tsx index 3d103ce8ab..5a32b5a974 100644 --- a/src/app/components/user-profile/UserRoomProfile.tsx +++ b/src/app/components/user-profile/UserRoomProfile.tsx @@ -63,7 +63,7 @@ function UserExtendedSection({ const clamp = (str: string, len: number) => (str.length > len ? `${str.slice(0, len)}...` : str); const [showMore, setShowMore] = useState(false); - const pronouns = profile.pronouns?.map((p: any) => clamp(p.summary, 20)).join('/'); + const pronouns = profile.pronouns?.map((p: any) => clamp(p.summary, 16)).join(', '); const timezone = profile.timezone ? clamp(profile.timezone, 64) : null; const localTime = timezone ? new Intl.DateTimeFormat([], { diff --git a/src/app/features/room/message/Message.tsx b/src/app/features/room/message/Message.tsx index ff7882aa5a..c1bc804111 100644 --- a/src/app/features/room/message/Message.tsx +++ b/src/app/features/room/message/Message.tsx @@ -249,20 +249,7 @@ function useMobileDoubleTap(callback: () => void, delay = 300) { ); } -function PronounTag({ pronouns, tagColor }: { pronouns?: any[]; tagColor: string }) { - if (!pronouns || pronouns.length === 0) return null; - - const clamp = (str: string, len: number) => (str.length > len ? `${str.slice(0, len)}...` : str); - - const display = clamp( - pronouns - .slice(0, 2) - .map((p) => clamp(p.summary, 48)) - .join('/'), - 128 - ); - const hasMore = pronouns.length > 2; - +function PronounPill({ summary, tagColor }: { summary: string; tagColor: string }) { return ( - {display} - {hasMore ? '...' : ''} + {summary} ); } +function PronounTag({ pronouns, tagColor }: { pronouns?: any[]; tagColor: string }) { + if (!pronouns || pronouns.length === 0) return null; + + const clamp = (str: string, len: number) => (str.length > len ? `${str.slice(0, len)}...` : str); + + const display = pronouns + .slice(0, 3) + .map((p) => ); + + if (pronouns.length > 3) { + display.push(); + } + return display; +} + function MessageInternal( { className, diff --git a/src/app/features/settings/account/PronounEditor.tsx b/src/app/features/settings/account/PronounEditor.tsx index 8cab2db271..b138c8f2ae 100644 --- a/src/app/features/settings/account/PronounEditor.tsx +++ b/src/app/features/settings/account/PronounEditor.tsx @@ -5,6 +5,7 @@ import { SettingTile } from '$components/setting-tile'; type PronounSet = { summary: string; language?: string; + grammatical_gender?: string; }; type PronounEditorProps = { @@ -13,7 +14,7 @@ type PronounEditorProps = { }; export function PronounEditor({ current, onSave }: PronounEditorProps) { - const initialString = current.map((p) => p.summary).join('/'); + const initialString = current.map((p) => p.summary).join(', '); const [val, setVal] = useState(initialString); useEffect(() => setVal(initialString), [initialString]); @@ -22,10 +23,10 @@ export function PronounEditor({ current, onSave }: PronounEditorProps) { if (val === initialString) return; const safeVal = val.slice(0, 128); const next = safeVal - .split('/') + .split(',') .map((s) => s.trim()) .filter(Boolean) - .map((s) => ({ summary: s.slice(0, 16) })); + .map((s) => ({ summary: s.slice(0, 16), language: "en" })); onSave(next); }; @@ -36,7 +37,7 @@ export function PronounEditor({ current, onSave }: PronounEditorProps) { return ( Date: Fri, 27 Feb 2026 20:52:20 -0500 Subject: [PATCH 2/2] Add mobile view to pronouns and refactor --- src/app/components/message/layout/Base.tsx | 4 ++ .../components/message/layout/layout.css.ts | 10 ++++ src/app/features/room/message/Message.tsx | 59 ++++++++----------- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/app/components/message/layout/Base.tsx b/src/app/components/message/layout/Base.tsx index ac196a5b77..922e704a78 100644 --- a/src/app/components/message/layout/Base.tsx +++ b/src/app/components/message/layout/Base.tsx @@ -28,6 +28,10 @@ export const UsernameBold = as<'b'>(({ as: AsUsernameBold = 'b', className, ...p )); +export const PronounPill = as<'span'>(({ as: AsPronounPill = 'span', className, ...props }, ref) => ( + +)); + export const MessageTextBody = as<'div', css.MessageTextBodyVariants & { notice?: boolean }>( ({ as: asComp = 'div', className, preWrap, jumboEmoji, emote, notice, ...props }, ref) => ( void, delay = 300) { ); } -function PronounPill({ summary, tagColor }: { summary: string; tagColor: string }) { - return ( - - - {summary} - - - ); -} - -function PronounTag({ pronouns, tagColor }: { pronouns?: any[]; tagColor: string }) { +const Pronouns = as< + 'div', + { + pronouns?: any[]; + tagColor: string; + } +>(({ pronouns, tagColor, ...props }, ref) => { if (!pronouns || pronouns.length === 0) return null; const clamp = (str: string, len: number) => (str.length > len ? `${str.slice(0, len)}...` : str); + const limit = mobileOrTablet() ? 1 : 3; - const display = pronouns - .slice(0, 3) - .map((p) => ); + const display = pronouns.slice(0, limit).map((p) => ( + + {clamp(p.summary, 16)} + + )); - if (pronouns.length > 3) { - display.push(); + if (pronouns.length > limit) { + display.push( + + ... + + ); } - return display; -} + return <>{display}; +}); function MessageInternal( { @@ -405,7 +392,7 @@ function MessageInternal( {showPronouns && ( - + )} {tagIconSrc && }