mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-15 20:54:59 +08:00
Use styled mxids in member list (#6328)
* Add DisambiguatedProfile Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Give DisambiguatedProfile some nice options Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Delint Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Use DisambiguatedProfile in member tile Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Basic handling of text overflow Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Use name instead of rawDisplayName Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * This seems to make more sense Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Reodred Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * rethemedex Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Fix import Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Fix color Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Appease the linter * Re-apply UserIdentifier patch Co-authored-by: Matthew Hodgson <matthew@matrix.org> Co-authored-by: Travis Ralston <travisr@matrix.org>
This commit is contained in:
parent
e55136cede
commit
5d28e0533d
@ -192,6 +192,7 @@
|
||||
@import "./views/messages/_CallEvent.scss";
|
||||
@import "./views/messages/_CreateEvent.scss";
|
||||
@import "./views/messages/_DateSeparator.scss";
|
||||
@import "./views/messages/_DisambiguatedProfile.scss";
|
||||
@import "./views/messages/_EventTileBubble.scss";
|
||||
@import "./views/messages/_HiddenBody.scss";
|
||||
@import "./views/messages/_JumpToDatePicker.scss";
|
||||
@ -214,7 +215,6 @@
|
||||
@import "./views/messages/_ReactionsRowButton.scss";
|
||||
@import "./views/messages/_RedactedBody.scss";
|
||||
@import "./views/messages/_RoomAvatarEvent.scss";
|
||||
@import "./views/messages/_SenderProfile.scss";
|
||||
@import "./views/messages/_TextualEvent.scss";
|
||||
@import "./views/messages/_UnknownBody.scss";
|
||||
@import "./views/messages/_ViewSourceEvent.scss";
|
||||
|
@ -93,7 +93,7 @@ limitations under the License.
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mx_FilePanel .mx_EventTile .mx_SenderProfile {
|
||||
.mx_FilePanel .mx_EventTile .mx_DisambiguatedProfile {
|
||||
flex: 1 1 auto;
|
||||
line-height: initial;
|
||||
padding: 0px;
|
||||
|
@ -77,7 +77,7 @@ limitations under the License.
|
||||
display: none; // we don't need this in this view
|
||||
}
|
||||
|
||||
.mx_NotificationPanel .mx_EventTile .mx_SenderProfile,
|
||||
.mx_NotificationPanel .mx_EventTile .mx_DisambiguatedProfile,
|
||||
.mx_NotificationPanel .mx_EventTile .mx_MessageTimestamp {
|
||||
color: $primary-content;
|
||||
font-size: $font-12px;
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -14,13 +15,18 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_SenderProfile_displayName {
|
||||
font-weight: 600;
|
||||
}
|
||||
.mx_DisambiguatedProfile {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
.mx_SenderProfile_mxid {
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
margin-left: 5px;
|
||||
opacity: 0.5; // Match mx_TextualEvent
|
||||
.mx_DisambiguatedProfile_displayName {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mx_DisambiguatedProfile_mxid {
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
margin-left: 5px;
|
||||
opacity: 0.5; // Match mx_TextualEvent
|
||||
}
|
||||
}
|
@ -126,7 +126,7 @@ $left-gutter: 64px;
|
||||
max-width: calc(100% - $left-gutter);
|
||||
}
|
||||
|
||||
.mx_SenderProfile .mx_Flair {
|
||||
.mx_DisambiguatedProfile .mx_Flair {
|
||||
opacity: 0.7;
|
||||
margin-left: 5px;
|
||||
display: inline-block;
|
||||
@ -141,6 +141,21 @@ $left-gutter: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_DisambiguatedProfile {
|
||||
color: $primary-content;
|
||||
font-size: $font-14px;
|
||||
display: inline-block; /* anti-zalgo, with overflow hidden */
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
padding-bottom: 0px;
|
||||
padding-top: 0px;
|
||||
margin: 0px;
|
||||
/* the next three lines, along with overflow hidden, truncate long display names */
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc(100% - $left-gutter);
|
||||
}
|
||||
|
||||
&.mx_EventTile_isEditing .mx_MessageTimestamp {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ $left-gutter: 64px;
|
||||
|
||||
.mx_GroupLayout {
|
||||
.mx_EventTile {
|
||||
> .mx_SenderProfile {
|
||||
> .mx_DisambiguatedProfile {
|
||||
line-height: $font-20px;
|
||||
margin-left: $left-gutter;
|
||||
}
|
||||
@ -65,7 +65,7 @@ $left-gutter: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SenderProfile {
|
||||
.mx_DisambiguatedProfile {
|
||||
font-size: $font-13px;
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ $irc-line-height: $font-18px;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.mx_SenderProfile {
|
||||
.mx_DisambiguatedProfile {
|
||||
width: var(--name-width);
|
||||
display: flex;
|
||||
order: 2;
|
||||
@ -181,14 +181,14 @@ $irc-line-height: $font-18px;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
|
||||
> .mx_SenderProfile_displayName {
|
||||
> .mx_DisambiguatedProfile_displayName {
|
||||
width: 100%;
|
||||
text-align: end;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
> .mx_SenderProfile_mxid {
|
||||
> .mx_DisambiguatedProfile_mxid {
|
||||
visibility: collapse;
|
||||
// Override the inherited margin.
|
||||
margin-left: 0;
|
||||
@ -196,11 +196,11 @@ $irc-line-height: $font-18px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SenderProfile:hover {
|
||||
.mx_DisambiguatedProfile:hover {
|
||||
overflow: visible;
|
||||
z-index: 10;
|
||||
|
||||
> .mx_SenderProfile_displayName {
|
||||
> .mx_DisambiguatedProfile_displayName {
|
||||
overflow: visible;
|
||||
display: inline;
|
||||
background-color: $event-selected-color;
|
||||
@ -208,7 +208,7 @@ $irc-line-height: $font-18px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
> .mx_SenderProfile_mxid {
|
||||
> .mx_DisambiguatedProfile_mxid {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
background-color: $event-selected-color;
|
||||
@ -217,7 +217,7 @@ $irc-line-height: $font-18px;
|
||||
|
||||
.mx_ReplyChain {
|
||||
margin: 0;
|
||||
.mx_SenderProfile {
|
||||
.mx_DisambiguatedProfile {
|
||||
order: unset;
|
||||
max-width: unset;
|
||||
width: unset;
|
||||
|
71
src/components/views/messages/DisambiguatedProfile.tsx
Normal file
71
src/components/views/messages/DisambiguatedProfile.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { RoomMember } from 'matrix-js-sdk/src/models/room-member';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { getUserNameColorClass } from '../../../utils/FormattingUtils';
|
||||
import UserIdentifier from "../../../customisations/UserIdentifier";
|
||||
|
||||
interface IProps {
|
||||
member?: RoomMember;
|
||||
fallbackName: string;
|
||||
flair?: JSX.Element;
|
||||
onClick?(): void;
|
||||
colored?: boolean;
|
||||
emphasizeDisplayName?: boolean;
|
||||
}
|
||||
|
||||
export default class DisambiguatedProfile extends React.Component<IProps> {
|
||||
render() {
|
||||
const { fallbackName, member, flair, colored, emphasizeDisplayName, onClick } = this.props;
|
||||
const rawDisplayName = member?.rawDisplayName || fallbackName;
|
||||
const mxid = member?.userId;
|
||||
|
||||
let colorClass;
|
||||
if (colored) {
|
||||
colorClass = getUserNameColorClass(fallbackName);
|
||||
}
|
||||
|
||||
let mxidElement;
|
||||
if (member?.disambiguate && mxid) {
|
||||
mxidElement = (
|
||||
<span className="mx_DisambiguatedProfile_mxid">
|
||||
{ UserIdentifier.getDisplayUserIdentifier(
|
||||
mxid, { withDisplayName: true, roomId: member.roomId },
|
||||
) }
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const displayNameClasses = classNames({
|
||||
"mx_DisambiguatedProfile_displayName": emphasizeDisplayName,
|
||||
[colorClass]: true,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mx_DisambiguatedProfile" dir="auto" onClick={onClick}>
|
||||
<span className={displayNameClasses}>
|
||||
{ rawDisplayName }
|
||||
</span>
|
||||
{ mxidElement }
|
||||
{ flair }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -21,10 +21,9 @@ import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
||||
|
||||
import Flair from '../elements/Flair';
|
||||
import FlairStore from '../../../stores/FlairStore';
|
||||
import { getUserNameColorClass } from '../../../utils/FormattingUtils';
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import UserIdentifier from '../../../customisations/UserIdentifier';
|
||||
import DisambiguatedProfile from "./DisambiguatedProfile";
|
||||
import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContext';
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
@ -106,9 +105,8 @@ export default class SenderProfile extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { mxEvent } = this.props;
|
||||
const colorClass = getUserNameColorClass(mxEvent.getSender());
|
||||
const { msgtype } = mxEvent.getContent();
|
||||
const { mxEvent, onClick } = this.props;
|
||||
const msgtype = mxEvent.getContent().msgtype;
|
||||
|
||||
let member = mxEvent.sender;
|
||||
if (SettingsStore.getValue("feature_use_only_current_profiles")) {
|
||||
@ -118,10 +116,6 @@ export default class SenderProfile extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
const disambiguate = member?.disambiguate || mxEvent.sender?.disambiguate;
|
||||
const displayName = member?.rawDisplayName || mxEvent.getSender() || "";
|
||||
const mxid = member?.userId || mxEvent.getSender() || "";
|
||||
|
||||
return <RoomContext.Consumer>
|
||||
{ roomContext => {
|
||||
if (msgtype === MsgType.Emote &&
|
||||
@ -130,17 +124,6 @@ export default class SenderProfile extends React.Component<IProps, IState> {
|
||||
return null; // emote message must include the name so don't duplicate it
|
||||
}
|
||||
|
||||
let mxidElement;
|
||||
if (disambiguate) {
|
||||
mxidElement = (
|
||||
<span className="mx_SenderProfile_mxid">
|
||||
{ UserIdentifier.getDisplayUserIdentifier(
|
||||
mxid, { withDisplayName: true, roomId: mxEvent.getRoomId() },
|
||||
) }
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
let flair;
|
||||
if (this.props.enableFlair) {
|
||||
const displayedGroups = this.getDisplayedGroups(
|
||||
@ -151,13 +134,14 @@ export default class SenderProfile extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_SenderProfile" dir="auto" onClick={this.props.onClick}>
|
||||
<span className={`mx_SenderProfile_displayName ${colorClass}`}>
|
||||
{ displayName }
|
||||
</span>
|
||||
{ mxidElement }
|
||||
{ flair }
|
||||
</div>
|
||||
<DisambiguatedProfile
|
||||
fallbackName={mxEvent.getSender() || ""}
|
||||
flair={flair}
|
||||
onClick={onClick}
|
||||
member={member}
|
||||
colored={true}
|
||||
emphasizeDisplayName={true}
|
||||
/>
|
||||
);
|
||||
} }
|
||||
</RoomContext.Consumer>;
|
||||
|
@ -64,6 +64,7 @@ function presenceClassForMember(presenceState: string, lastActiveAgo: number, sh
|
||||
|
||||
interface IProps {
|
||||
name?: string;
|
||||
nameJSX?: JSX.Element;
|
||||
title?: string;
|
||||
avatarJsx?: JSX.Element; // <BaseAvatar />
|
||||
className?: string;
|
||||
@ -117,7 +118,7 @@ export default class EntityTile extends React.PureComponent<IProps, IState> {
|
||||
mainClassNames[presenceClass] = true;
|
||||
|
||||
let nameEl;
|
||||
const { name } = this.props;
|
||||
const name = this.props.nameJSX || this.props.name;
|
||||
|
||||
if (!this.props.suppressOnHover) {
|
||||
const activeAgo = this.props.presenceLastActiveAgo ?
|
||||
|
@ -33,6 +33,7 @@ import { Action } from "../../../dispatcher/actions";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import EntityTile, { PowerStatus } from "./EntityTile";
|
||||
import MemberAvatar from "./../avatars/MemberAvatar";
|
||||
import DisambiguatedProfile from "../messages/DisambiguatedProfile";
|
||||
import UserIdentifierCustomisations from '../../../customisations/UserIdentifier';
|
||||
|
||||
interface IProps {
|
||||
@ -258,6 +259,13 @@ export default class MemberTile extends React.Component<IProps, IState> {
|
||||
e2eStatus = this.state.e2eStatus;
|
||||
}
|
||||
|
||||
const nameJSX = (
|
||||
<DisambiguatedProfile
|
||||
member={member}
|
||||
fallbackName={name || ""}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<EntityTile
|
||||
{...this.props}
|
||||
@ -268,6 +276,7 @@ export default class MemberTile extends React.Component<IProps, IState> {
|
||||
avatarJsx={av}
|
||||
title={this.getPowerLabel()}
|
||||
name={name}
|
||||
nameJSX={nameJSX}
|
||||
powerStatus={powerStatus}
|
||||
showPresence={this.props.showPresence}
|
||||
subtextLabel={statusMessage}
|
||||
|
@ -132,7 +132,7 @@ function getAllEventTiles(session: ElementSession): Promise<ElementHandle[]> {
|
||||
}
|
||||
|
||||
async function getMessageFromEventTile(eventTile: ElementHandle): Promise<Message> {
|
||||
const senderElement = await eventTile.$(".mx_SenderProfile_displayName");
|
||||
const senderElement = await eventTile.$(".mx_DisambiguatedProfile_displayName");
|
||||
const className: string = await (await eventTile.getProperty("className")).jsonValue();
|
||||
const classNames = className.split(" ");
|
||||
const bodyElement = await eventTile.$(".mx_EventTile_body");
|
||||
|
Loading…
Reference in New Issue
Block a user