From 80c3da29aa5c3318e430860360148daa7d6ff895 Mon Sep 17 00:00:00 2001 From: nexy7574 Date: Sun, 29 Dec 2024 21:25:56 +0000 Subject: [PATCH] Add timezones and pronouns (closes #569) --- web/src/ui/rightpanel/RightPanel.css | 11 +++ web/src/ui/rightpanel/UserExtendedProfile.tsx | 74 +++++++++++++++++++ web/src/ui/rightpanel/UserInfo.tsx | 3 +- 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 web/src/ui/rightpanel/UserExtendedProfile.tsx diff --git a/web/src/ui/rightpanel/RightPanel.css b/web/src/ui/rightpanel/RightPanel.css index 76be03f..efb0b70 100644 --- a/web/src/ui/rightpanel/RightPanel.css +++ b/web/src/ui/rightpanel/RightPanel.css @@ -91,6 +91,17 @@ div.right-panel-content.user { word-break: break-word; } + div.extended-profile { + display: flex; + flex-direction: column; + gap: 0.25rem; + + div.profile-row { + display: grid; + grid-template-columns: 1fr 1fr; + } + } + hr { width: 100%; opacity: .2; diff --git a/web/src/ui/rightpanel/UserExtendedProfile.tsx b/web/src/ui/rightpanel/UserExtendedProfile.tsx new file mode 100644 index 0000000..8d03a29 --- /dev/null +++ b/web/src/ui/rightpanel/UserExtendedProfile.tsx @@ -0,0 +1,74 @@ +import { useEffect, useState } from "react" +import { UserProfile } from "@/api/types" +import { ensureArray } from "@/util/validation.ts" + +interface PronounSet { + subject: string + object: string + possessive_determiner: string + possessive_pronoun: string + reflexive: string + summary: string +} + +interface ExtendedProfileAttributes { + "us.cloke.msc4175.tz"?: string + "io.fsky.nyx.pronouns"?: PronounSet[] +} + +interface ExtendedProfileProps { + profile: UserProfile & ExtendedProfileAttributes +} + + +const currentTimeAdjusted = (tz: string) => { + const lang = navigator.language || "en-US" + const now = new Date() + return new Intl.DateTimeFormat(lang, { timeStyle: "long", timeZone: tz }).format(now) +} + +function ClockElement({ tz }: { tz: string }) { + const [time, setTime] = useState(currentTimeAdjusted(tz)) + useEffect(() => { + const interval = setInterval(() => { + setTime(currentTimeAdjusted(tz)) + }, (1000 - Date.now() % 1000)) + return () => clearInterval(interval) + }, [tz]) + return
{time}
+} + + +export default function UserExtendedProfile({ profile }: ExtendedProfileProps) { + if (!profile) return null + + const pronouns: PronounSet[] = ensureArray(profile["io.fsky.nyx.pronouns"]) as PronounSet[] + return ( +
+ { + profile["us.cloke.msc4175.tz"] && ( +
+
Time:
+ +
+ ) + } + { + pronouns.length >= 1 && ( +
+
Pronouns:
+
+ { + pronouns.map( + (pronounSet: PronounSet) => ( + pronounSet.summary || `${pronounSet.subject}/${pronounSet.object}` + ), + ).join("/") + } +
+
+ ) + } +
+ ) +} diff --git a/web/src/ui/rightpanel/UserInfo.tsx b/web/src/ui/rightpanel/UserInfo.tsx index 4e93ec7..71d530f 100644 --- a/web/src/ui/rightpanel/UserInfo.tsx +++ b/web/src/ui/rightpanel/UserInfo.tsx @@ -18,6 +18,7 @@ import { PuffLoader } from "react-spinners" import { getAvatarURL } from "@/api/media.ts" import { useRoomMember } from "@/api/statestore" import { MemberEventContent, UserID, UserProfile } from "@/api/types" +import UserExtendedProfile from "@/ui/rightpanel/UserExtendedProfile.tsx" import { getLocalpart } from "@/util/validation.ts" import ClientContext from "../ClientContext.ts" import { LightboxContext } from "../modal" @@ -46,7 +47,6 @@ const UserInfo = ({ userID }: UserInfoProps) => { err => setErrors([`${err}`]), ) }, [roomCtx, userID, client]) - const displayname = member?.displayname || globalProfile?.displayname || getLocalpart(userID) return <>
@@ -63,6 +63,7 @@ const UserInfo = ({ userID }: UserInfoProps) => {
{displayname}
{userID}
+ {globalProfile && <>
}
{userID !== client.userID && <>