Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Implement event permalink pills
Browse files Browse the repository at this point in the history
  • Loading branch information
weeman1337 committed Mar 16, 2023
1 parent b373ef8 commit e6864a2
Show file tree
Hide file tree
Showing 16 changed files with 686 additions and 234 deletions.
2 changes: 1 addition & 1 deletion cypress/e2e/regression-tests/pills-click-in-app.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe("Pills", () => {

// go back to the message room and try to click on the pill text, as a user would
cy.viewRoomByName(messageRoom);
cy.get(".mx_EventTile_body .mx_Pill .mx_Pill_linkText")
cy.get(".mx_EventTile_body .mx_Pill .mx_Pill_content")
.should("have.css", "pointer-events", "none")
.click({ force: true }); // force is to ensure we bypass pointer-events
cy.url().should("contain", localUrl);
Expand Down
29 changes: 25 additions & 4 deletions res/css/views/elements/_Pill.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,17 @@ limitations under the License.
min-width: $font-16px; /* ensure the avatar is not compressed */
}

.mx_Pill_linkText {
white-space: nowrap; /* enforce the pill text to be a single line */
overflow: hidden;
text-overflow: ellipsis;
&.mx_EventPill .mx_BaseAvatar {
/* Event pill avatars are inside the text. */
margin-inline-start: 0.2em;
margin-inline-end: 0.2em;
}

.mx_Pill_content {
overflow: hidden;
pointer-events: none; /* ensure clicks on the pills go through the anchor */
text-overflow: ellipsis;
white-space: nowrap;
}

a& {
Expand All @@ -69,4 +74,20 @@ limitations under the License.
overflow: hidden;
text-decoration: none !important; /* To override .markdown-body */
}

.mx_Pill_LinkIcon {
background-color: $link-external;
box-sizing: border-box;
color: $background;
height: 16px;
padding: 1px;
width: 16px;
}

.mx_Pill_UserIcon {
box-sizing: border-box;
color: $secondary-content;
height: 16px;
width: 16px;
}
}
7 changes: 7 additions & 0 deletions res/img/compound/user.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions res/themes/legacy-dark/css/_legacy-dark.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ $room-icon-unread-color: #fff;
$accent: #0dbd8b;
$alert: #ff5b55;
$links: #0086e6;
$link-external: #0467dd;
$primary-content: $primary-fg-color;
$secondary-content: $secondary-fg-color;
$tertiary-content: $tertiary-fg-color;
Expand Down
1 change: 1 addition & 0 deletions res/themes/legacy-light/css/_legacy-light.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ $presence-busy: #ff5b55;
$accent: #0dbd8b;
$alert: #ff5b55;
$links: #0086e6;
$link-external: #0467dd;
$primary-content: $primary-fg-color;
$secondary-content: $secondary-fg-color;
$tertiary-content: $tertiary-fg-color;
Expand Down
1 change: 1 addition & 0 deletions res/themes/light/css/_light.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ $space-nav: rgba($tertiary-content, 0.15);
$accent: #0dbd8b;
$alert: #ff5b55;
$links: #0086e6;
$link-external: #0467dd;

$username-variant1-color: #368bd6;
$username-variant2-color: #ac3ba8;
Expand Down
86 changes: 74 additions & 12 deletions src/components/views/elements/Pill.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,24 @@ limitations under the License.
import React, { ReactElement, useState } from "react";
import classNames from "classnames";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/matrix";

import { MatrixClientPeg } from "../../../MatrixClientPeg";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import Tooltip, { Alignment } from "../elements/Tooltip";
import { usePermalink } from "../../../hooks/usePermalink";
import RoomAvatar from "../avatars/RoomAvatar";
import MemberAvatar from "../avatars/MemberAvatar";
import { _t } from "../../../languageHandler";
import { Icon as LinkIcon } from "../../../../res/img/element-icons/room/composer/link.svg";
import { Icon as UserIcon } from "../../../../res/img/compound/user.svg";

export enum PillType {
UserMention = "TYPE_USER_MENTION",
RoomMention = "TYPE_ROOM_MENTION",
AtRoomMention = "TYPE_AT_ROOM_MENTION", // '@room' mention
EventInSameRoom = "TYPE_EVENT_IN_SAME_ROOM",
EventInOtherRoom = "TYPE_EVENT_IN_OTHER_ROOM",
}

export const pillRoomNotifPos = (text: string): number => {
Expand All @@ -39,6 +45,34 @@ export const pillRoomNotifLen = (): number => {
return "@room".length;
};

const PillRoomAvatar: React.FC<{
shouldShowPillAvatar: boolean;
room: Room | null;
}> = ({ shouldShowPillAvatar, room }) => {
if (!shouldShowPillAvatar) {
return null;
}

if (room) {
return <RoomAvatar room={room} width={16} height={16} aria-hidden="true" />;
}
return <LinkIcon className="mx_Pill_LinkIcon mx_BaseAvatar mx_BaseAvatar_image" />;
};

const PillMemberAvatar: React.FC<{
shouldShowPillAvatar: boolean;
member: RoomMember | null;
}> = ({ shouldShowPillAvatar, member }) => {
if (!shouldShowPillAvatar) {
return null;
}

if (member) {
return <MemberAvatar member={member} width={16} height={16} aria-hidden="true" hideTitle />;
}
return <UserIcon className="mx_Pill_UserIcon mx_BaseAvatar mx_BaseAvatar_image" />;
};

export interface PillProps {
// The Type of this Pill. If url is given, this is auto-detected.
type?: PillType;
Expand Down Expand Up @@ -70,6 +104,7 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
mx_SpacePill: type === "space",
mx_UserPill: type === PillType.UserMention,
mx_UserPill_me: resourceId === MatrixClientPeg.get().getUserId(),
mx_EventPill: type === PillType.EventInOtherRoom || type === PillType.EventInSameRoom,
});

const onMouseOver = (): void => {
Expand All @@ -81,28 +116,55 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
};

const tip = hover && resourceId ? <Tooltip label={resourceId} alignment={Alignment.Right} /> : null;
let avatar: ReactElement | null = null;
let content: ReactElement | null = null;

switch (type) {
case PillType.EventInOtherRoom:
{
const avatar = <PillRoomAvatar shouldShowPillAvatar={shouldShowPillAvatar} room={targetRoom} />;
content = (
<>
{_t("Message in")}
{avatar || " "}
{text}
</>
);
}
break;
case PillType.EventInSameRoom:
{
const avatar = <PillMemberAvatar shouldShowPillAvatar={shouldShowPillAvatar} member={member} />;
content = (
<>
{_t("Message from")}
{avatar || " "}
{text}
</>
);
}
break;
case PillType.AtRoomMention:
case PillType.RoomMention:
case "space":
avatar = targetRoom ? <RoomAvatar room={targetRoom} width={16} height={16} aria-hidden="true" /> : null;
content = (
<>
<PillRoomAvatar shouldShowPillAvatar={shouldShowPillAvatar} room={targetRoom} />
{text}
</>
);
break;
case PillType.UserMention:
avatar = <MemberAvatar member={member} width={16} height={16} aria-hidden="true" hideTitle />;
content = (
<>
<PillMemberAvatar shouldShowPillAvatar={shouldShowPillAvatar} member={member} />
{text}
</>
);
break;
default:
return null;
}

const content = (
<>
{shouldShowPillAvatar && avatar}
<span className="mx_Pill_linkText">{text}</span>
</>
);

return (
<bdi>
<MatrixClientContext.Provider value={MatrixClientPeg.get()}>
Expand All @@ -114,12 +176,12 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
onMouseOver={onMouseOver}
onMouseLeave={onMouseLeave}
>
{content}
<span className="mx_Pill_content">{content}</span>
{tip}
</a>
) : (
<span className={classes} onMouseOver={onMouseOver} onMouseLeave={onMouseLeave}>
{content}
<span className="mx_Pill_content">{content}</span>
{tip}
</span>
)}
Expand Down
Loading

0 comments on commit e6864a2

Please sign in to comment.