Files
ThreadNet-Web/src/components/views/elements/Pill.tsx
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

164 lines
5.5 KiB
TypeScript
Raw Normal View History

/*
2024-09-09 14:57:16 +01:00
Copyright 2024 New Vector Ltd.
Copyright 2017-2019 , 2021 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
2024-09-09 14:57:16 +01:00
Please see LICENSE files in the repository root for full details.
*/
2022-05-05 11:13:09 +02:00
import React, { ReactElement } from "react";
import classNames from "classnames";
import { Room, RoomMember } from "matrix-js-sdk/src/matrix";
import { Tooltip } from "@vector-im/compound-web";
import { LinkIcon, UserSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
2021-10-22 17:23:32 -05:00
2021-06-29 13:11:58 +01:00
import { MatrixClientPeg } from "../../../MatrixClientPeg";
2019-12-17 17:26:12 +00:00
import MatrixClientContext from "../../../contexts/MatrixClientContext";
2023-03-08 13:06:50 +01:00
import { usePermalink } from "../../../hooks/usePermalink";
import RoomAvatar from "../avatars/RoomAvatar";
import MemberAvatar from "../avatars/MemberAvatar";
2023-03-21 10:23:20 +01:00
import { _t } from "../../../languageHandler";
2022-05-05 11:13:09 +02:00
export enum PillType {
UserMention = "TYPE_USER_MENTION",
RoomMention = "TYPE_ROOM_MENTION",
AtRoomMention = "TYPE_AT_ROOM_MENTION", // '@room' mention
2023-03-21 10:23:20 +01:00
EventInSameRoom = "TYPE_EVENT_IN_SAME_ROOM",
EventInOtherRoom = "TYPE_EVENT_IN_OTHER_ROOM",
2022-05-05 11:13:09 +02:00
}
export const pillRoomNotifPos = (text: string | null): number => {
return text?.indexOf("@room") ?? -1;
2023-03-08 13:06:50 +01:00
};
export const pillRoomNotifLen = (): number => {
return "@room".length;
};
const linkIcon = <LinkIcon className="mx_Pill_LinkIcon mx_BaseAvatar" />;
2023-03-22 13:27:24 +01:00
2023-03-21 10:23:20 +01:00
const PillRoomAvatar: React.FC<{
shouldShowPillAvatar: boolean;
room: Room | null;
}> = ({ shouldShowPillAvatar, room }) => {
if (!shouldShowPillAvatar) {
return null;
}
if (room) {
return <RoomAvatar room={room} size="16px" aria-hidden="true" />;
2023-03-21 10:23:20 +01:00
}
2023-03-22 13:27:24 +01:00
return linkIcon;
2023-03-21 10:23:20 +01:00
};
const PillMemberAvatar: React.FC<{
shouldShowPillAvatar: boolean;
member: RoomMember | null;
}> = ({ shouldShowPillAvatar, member }) => {
if (!shouldShowPillAvatar) {
return null;
}
if (member) {
return <MemberAvatar member={member} size="16px" aria-hidden="true" hideTitle />;
2023-03-21 10:23:20 +01:00
}
return <UserSolidIcon className="mx_Pill_UserIcon mx_BaseAvatar" />;
2023-03-21 10:23:20 +01:00
};
2023-03-08 13:06:50 +01:00
export interface PillProps {
2022-05-05 11:13:09 +02:00
// The Type of this Pill. If url is given, this is auto-detected.
type?: PillType;
// The URL to pillify (no validation is done)
url?: string;
2023-03-08 13:06:50 +01:00
/** Whether the pill is in a message. It will act as a link then. */
2022-05-05 11:13:09 +02:00
inMessage?: boolean;
// The room in which this pill is being rendered
room?: Room;
// Whether to include an avatar in the pill
shouldShowPillAvatar?: boolean;
}
2023-03-21 10:23:20 +01:00
export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room, shouldShowPillAvatar = true }) => {
2023-03-22 13:27:24 +01:00
const { event, member, onClick, resourceId, targetRoom, text, type } = usePermalink({
2023-03-08 13:06:50 +01:00
room,
type: propType,
url,
});
2022-05-05 11:13:09 +02:00
if (!type || !text) {
2023-03-08 13:06:50 +01:00
return null;
2020-08-29 12:14:16 +01:00
}
2023-03-08 13:06:50 +01:00
const classes = classNames("mx_Pill", {
mx_AtRoomPill: type === PillType.AtRoomMention,
mx_RoomPill: type === PillType.RoomMention,
mx_SpacePill: type === "space" || targetRoom?.isSpaceRoom(),
2023-03-08 13:06:50 +01:00
mx_UserPill: type === PillType.UserMention,
mx_UserPill_me: resourceId === MatrixClientPeg.safeGet().getUserId(),
2023-03-21 10:23:20 +01:00
mx_EventPill: type === PillType.EventInOtherRoom || type === PillType.EventInSameRoom,
2023-03-08 13:06:50 +01:00
});
2020-08-29 12:14:16 +01:00
2023-03-22 13:27:24 +01:00
let avatar: ReactElement | null = null;
let pillText: string | null = text;
switch (type) {
2023-03-21 10:23:20 +01:00
case PillType.EventInOtherRoom:
{
2023-03-22 13:27:24 +01:00
avatar = <PillRoomAvatar shouldShowPillAvatar={shouldShowPillAvatar} room={targetRoom} />;
pillText = _t("pill|permalink_other_room", {
2023-03-22 13:27:24 +01:00
room: text,
});
2023-03-21 10:23:20 +01:00
}
break;
case PillType.EventInSameRoom:
{
2023-03-22 13:27:24 +01:00
if (event) {
avatar = <PillMemberAvatar shouldShowPillAvatar={shouldShowPillAvatar} member={member} />;
pillText = _t("pill|permalink_this_room", {
2023-03-22 13:27:24 +01:00
user: text,
});
} else {
avatar = linkIcon;
pillText = _t("common|message");
2023-03-22 13:27:24 +01:00
}
2023-03-21 10:23:20 +01:00
}
break;
case PillType.AtRoomMention:
case PillType.RoomMention:
case "space":
2023-03-22 13:27:24 +01:00
avatar = <PillRoomAvatar shouldShowPillAvatar={shouldShowPillAvatar} room={targetRoom} />;
break;
case PillType.UserMention:
2023-03-22 13:27:24 +01:00
avatar = <PillMemberAvatar shouldShowPillAvatar={shouldShowPillAvatar} member={member} />;
break;
default:
return null;
}
const isAnchor = !!inMessage && !!url;
2023-03-08 13:06:50 +01:00
return (
<bdi>
<MatrixClientContext.Provider value={MatrixClientPeg.safeGet()}>
<Tooltip
description={resourceId ?? ""}
open={resourceId ? undefined : false}
2024-04-12 14:56:23 +02:00
placement="right"
isTriggerInteractive={isAnchor}
>
{isAnchor ? (
<a className={classes} href={url} onClick={onClick}>
{avatar}
<span className="mx_Pill_text">{pillText}</span>
</a>
) : (
<span className={classes}>
{avatar}
<span className="mx_Pill_text">{pillText}</span>
</span>
)}
</Tooltip>
2023-03-08 13:06:50 +01:00
</MatrixClientContext.Provider>
</bdi>
);
};