Add user status in user info right panel card (#34212)
* Add user status in user info right panel card Adds a very simple view component to do so, which will be reused in the DM room header. Also comment the other status view so the difference is clear. * Add screenshot * Add test * Rename snapshot
This commit is contained in:
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
import React, { type JSX } from "react";
|
||||
import { type User, type RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import { Heading, Tooltip, Text } from "@vector-im/compound-web";
|
||||
import { Flex } from "@element-hq/web-shared-components";
|
||||
import { Flex, StatusTextView } from "@element-hq/web-shared-components";
|
||||
|
||||
import { useUserfoHeaderViewModel } from "../../../viewmodels/right_panel/user_info/UserInfoHeaderViewModel";
|
||||
import MemberAvatar from "../../avatars/MemberAvatar";
|
||||
@@ -16,6 +16,7 @@ import { Container, type Member, type IDevice } from "../UserInfo";
|
||||
import PresenceLabel from "../../rooms/PresenceLabel";
|
||||
import CopyableText from "../../elements/CopyableText";
|
||||
import { UserInfoHeaderVerificationView } from "./UserInfoHeaderVerificationView";
|
||||
import { useUserStatus } from "../../../../hooks/useUserStatus";
|
||||
|
||||
export interface UserInfoHeaderViewProps {
|
||||
member: Member;
|
||||
@@ -33,6 +34,7 @@ export const UserInfoHeaderView: React.FC<UserInfoHeaderViewProps> = ({
|
||||
const vm = useUserfoHeaderViewModel({ member, roomId });
|
||||
const avatarUrl = (member as User).avatarUrl;
|
||||
const displayName = (member as RoomMember).rawDisplayName;
|
||||
const userStatus = useUserStatus(member.userId);
|
||||
|
||||
let presenceLabel: JSX.Element | undefined;
|
||||
|
||||
@@ -73,6 +75,7 @@ export const UserInfoHeaderView: React.FC<UserInfoHeaderViewProps> = ({
|
||||
{displayName}
|
||||
</Flex>
|
||||
</Heading>
|
||||
{userStatus && <StatusTextView status={userStatus} />}
|
||||
{presenceLabel}
|
||||
{vm.timezoneInfo && (
|
||||
<Tooltip label={vm.timezoneInfo?.timezone ?? ""}>
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -92,5 +92,6 @@ export * from "./core/i18n/I18nApi";
|
||||
export * from "./core/utils/linkify";
|
||||
export type * from "./core/userStatus.ts";
|
||||
export * from "./status/SetStatusView";
|
||||
export * from "./status/StatusTextView";
|
||||
// MVVM
|
||||
export * from "./core/viewmodel";
|
||||
|
||||
@@ -12,6 +12,10 @@ import { CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import { _t, type UserStatus } from "..";
|
||||
import styles from "./StatusPillView.module.css";
|
||||
|
||||
/**
|
||||
* Displays a user's status message in a pill format with a button that can be used
|
||||
* to clear the status.
|
||||
*/
|
||||
export const StatusPillView = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
{
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
.statusText {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--cpd-space-1x);
|
||||
|
||||
span {
|
||||
font: var(--cpd-font-body-md-medium);
|
||||
color: var(--cpd-color-text-secondary);
|
||||
}
|
||||
|
||||
.menuStatusText {
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type Meta, type StoryObj } from "@storybook/react-vite";
|
||||
|
||||
import { StatusTextView } from "./StatusTextView";
|
||||
|
||||
const meta = {
|
||||
title: "Status/StatusTextView",
|
||||
component: StatusTextView,
|
||||
tags: ["autodocs"],
|
||||
args: {
|
||||
status: { emoji: "🦩", text: "Flamboyant" },
|
||||
},
|
||||
} satisfies Meta<typeof StatusTextView>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {};
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { composeStories } from "@storybook/react-vite";
|
||||
import React from "react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { render, screen } from "@test-utils";
|
||||
|
||||
import * as stories from "./StatusTextView.stories";
|
||||
|
||||
const { Default } = composeStories(stories);
|
||||
|
||||
describe("StatusTextView", () => {
|
||||
it("should display the status text and emoji", () => {
|
||||
render(<Default />);
|
||||
expect(screen.getByText("Flamboyant")).toBeInTheDocument();
|
||||
expect(screen.getByText("🦩")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type JSX } from "react";
|
||||
import { Text } from "@vector-im/compound-web";
|
||||
|
||||
import { type UserStatus } from "..";
|
||||
import styles from "./StatusTextView.module.css";
|
||||
|
||||
/**
|
||||
* Displays a user's status message and emoji in simple text format
|
||||
*/
|
||||
export const StatusTextView = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
{
|
||||
status: UserStatus;
|
||||
} & React.HTMLAttributes<HTMLDivElement>
|
||||
>(function StatusTextView({ status, ...props }, ref): JSX.Element {
|
||||
return (
|
||||
<div ref={ref} {...props} className={styles.statusText}>
|
||||
<Text as="span" className={styles.menuStatusEmoji}>
|
||||
{status.emoji}
|
||||
</Text>
|
||||
<Text as="span" className={styles.menuStatusText}>
|
||||
{status.text}
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user