From 107289a16c0aa9a1cc1acb2608621cc78be5ffd1 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 8 Jun 2026 17:55:32 +0100 Subject: [PATCH] Put tooltips on presence consistently Sort out duplication between presence icon code, have the MemberIconView position the presence icon rather than the presence icon trying to position itself. --- .../views/avatars/_WithPresenceIndicator.pcss | 7 ++--- .../res/css/views/rooms/_MemberTileView.pcss | 6 ++++ .../css/views/rooms/_PresenceIconView.pcss | 5 ---- .../views/avatars/WithPresenceIndicator.tsx | 21 ++------------ .../tiles/common/MemberTileView.tsx | 3 +- .../tiles/common/PresenceIconView.tsx | 28 +++++++++++++++++-- 6 files changed, 38 insertions(+), 32 deletions(-) diff --git a/apps/web/res/css/views/avatars/_WithPresenceIndicator.pcss b/apps/web/res/css/views/avatars/_WithPresenceIndicator.pcss index 9b88d0d1bd..68a0f0dbca 100644 --- a/apps/web/res/css/views/avatars/_WithPresenceIndicator.pcss +++ b/apps/web/res/css/views/avatars/_WithPresenceIndicator.pcss @@ -13,10 +13,7 @@ Please see LICENSE files in the repository root for full details. .mx_WithPresenceIndicator_icon { position: absolute; - /* PresenceIconView has its own idea of where it should be positioned which it probably shouldn't */ - top: initial; - left: initial; - right: -2px; - bottom: -2px; + right: 0px; + bottom: 2px; } } diff --git a/apps/web/res/css/views/rooms/_MemberTileView.pcss b/apps/web/res/css/views/rooms/_MemberTileView.pcss index 307625d042..ce28cbdfb8 100644 --- a/apps/web/res/css/views/rooms/_MemberTileView.pcss +++ b/apps/web/res/css/views/rooms/_MemberTileView.pcss @@ -41,4 +41,10 @@ Please see LICENSE files in the repository root for full details. height: 32px; width: 32px; } + + .mx_MemberTileView_presence { + position: absolute; + right: -2px; + bottom: 2px; + } } diff --git a/apps/web/res/css/views/rooms/_PresenceIconView.pcss b/apps/web/res/css/views/rooms/_PresenceIconView.pcss index e09fbdf2fa..585baf1928 100644 --- a/apps/web/res/css/views/rooms/_PresenceIconView.pcss +++ b/apps/web/res/css/views/rooms/_PresenceIconView.pcss @@ -6,11 +6,6 @@ Please see LICENSE files in the repository root for full details. */ .mx_PresenceIconView { - position: absolute; - top: 24px; - left: 24px; - width: 12px; - height: 12px; display: flex; justify-content: center; align-items: center; diff --git a/apps/web/src/components/views/avatars/WithPresenceIndicator.tsx b/apps/web/src/components/views/avatars/WithPresenceIndicator.tsx index c6d0d3befa..92b93adb4e 100644 --- a/apps/web/src/components/views/avatars/WithPresenceIndicator.tsx +++ b/apps/web/src/components/views/avatars/WithPresenceIndicator.tsx @@ -15,10 +15,8 @@ import { type User, UserEvent, } from "matrix-js-sdk/src/matrix"; -import { Tooltip } from "@vector-im/compound-web"; import { isPresenceEnabled } from "../../../utils/presence"; -import { _t } from "../../../languageHandler"; import DMRoomMap from "../../../utils/DMRoomMap"; import { getJoinedNonFunctionalMembers } from "../../../utils/room/getJoinedNonFunctionalMembers"; import { useEventEmitter } from "../../../hooks/useEventEmitter"; @@ -41,19 +39,6 @@ export enum Presence { Busy = "busy", } -function tooltipText(variant: Presence): string { - switch (variant) { - case Presence.Online: - return _t("presence|online"); - case Presence.Away: - return _t("presence|away"); - case Presence.Offline: - return _t("presence|offline"); - case Presence.Busy: - return _t("presence|busy"); - } -} - function getDmMember(room: Room): RoomMember | null { const otherUserId = DMRoomMap.shared().getUserIdForRoomId(room.roomId); return otherUserId ? room.getMember(otherUserId) : null; @@ -123,7 +108,7 @@ const WithPresenceIndicator: React.FC = ({ room, children }) => { let icon: JSX.Element | undefined; if (presence) { - icon = ; + icon = ; } if (!presence) return <>{children}; @@ -131,9 +116,7 @@ const WithPresenceIndicator: React.FC = ({ room, children }) => { return (
{children} - - {icon} - +
{icon}
); }; diff --git a/apps/web/src/components/views/rooms/MemberList/tiles/common/MemberTileView.tsx b/apps/web/src/components/views/rooms/MemberList/tiles/common/MemberTileView.tsx index cb0cec74d9..fad0b3f0da 100644 --- a/apps/web/src/components/views/rooms/MemberList/tiles/common/MemberTileView.tsx +++ b/apps/web/src/components/views/rooms/MemberList/tiles/common/MemberTileView.tsx @@ -51,7 +51,8 @@ export function MemberTileView(props: Props): JSX.Element { >
- {props.avatarJsx} {props.presenceJsx} + {props.avatarJsx} +
{props.presenceJsx}
{props.nameJsx}
diff --git a/apps/web/src/components/views/rooms/MemberList/tiles/common/PresenceIconView.tsx b/apps/web/src/components/views/rooms/MemberList/tiles/common/PresenceIconView.tsx index ac31084adf..8b67418536 100644 --- a/apps/web/src/components/views/rooms/MemberList/tiles/common/PresenceIconView.tsx +++ b/apps/web/src/components/views/rooms/MemberList/tiles/common/PresenceIconView.tsx @@ -6,12 +6,15 @@ Please see LICENSE files in the repository root for full details. */ import React, { type JSX } from "react"; +import classNames from "classnames"; import OnlineOrUnavailableIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-solid-8x8"; import OfflineIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-outline-8x8"; import DNDIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-strikethrough-8x8"; -import classNames from "classnames"; +import { Tooltip } from "@vector-im/compound-web"; import { UnstableValue } from "matrix-js-sdk/src/NamespacedValue"; +import { _t } from "../../../../../../languageHandler"; + interface Props { className?: string; presenceState: string; @@ -36,9 +39,30 @@ function getIconForPresenceState(state: string): JSX.Element { } } +function getTooltipText(state: string): string { + switch (state) { + case "online": + return _t("presence|online"); + case "offline": + return _t("presence|offline"); + case "unavailable": + case "io.element.unreachable": + return _t("presence|away"); + case BUSY_PRESENCE_NAME.name: + case BUSY_PRESENCE_NAME.altName: + return _t("presence|busy"); + default: + throw new Error(`Presence state "${state}" is unknown.`); + } +} + const AvatarPresenceIconView: React.FC = ({ className, presenceState }) => { const names = classNames("mx_PresenceIconView", className); - return
{getIconForPresenceState(presenceState)}
; + return ( + +
{getIconForPresenceState(presenceState)}
+
+ ); }; export default AvatarPresenceIconView;