diff --git a/res/css/structures/_RightPanel.scss b/res/css/structures/_RightPanel.scss index 5bf0d953f3..5515fe4060 100644 --- a/res/css/structures/_RightPanel.scss +++ b/res/css/structures/_RightPanel.scss @@ -160,3 +160,20 @@ limitations under the License. mask-position: center; } } + +.mx_RightPanel_scopeHeader { + margin: 24px; + text-align: center; + font-weight: $font-semi-bold; + font-size: $font-18px; + line-height: $font-22px; + + .mx_BaseAvatar { + margin-right: 8px; + vertical-align: middle; + } + + .mx_BaseAvatar_image { + border-radius: 8px; + } +} diff --git a/res/css/views/rooms/_MemberInfo.scss b/res/css/views/rooms/_MemberInfo.scss index 182c280217..3f7f83d334 100644 --- a/res/css/views/rooms/_MemberInfo.scss +++ b/res/css/views/rooms/_MemberInfo.scss @@ -19,6 +19,7 @@ limitations under the License. flex-direction: column; flex: 1; overflow-y: auto; + margin-top: 8px; } .mx_MemberInfo_name { diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss index 1e3506e371..631ddc484f 100644 --- a/res/css/views/rooms/_MemberList.scss +++ b/res/css/views/rooms/_MemberList.scss @@ -44,6 +44,10 @@ limitations under the License. .mx_AutoHideScrollbar { flex: 1 1 0; } + + .mx_RightPanel_scopeHeader { + margin-top: -8px; + } } .mx_GroupMemberList_query, diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index a4b5cd0fbb..eb47a56269 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -60,7 +60,9 @@ import QuestionDialog from "../dialogs/QuestionDialog"; import ConfirmUserActionDialog from "../dialogs/ConfirmUserActionDialog"; import InfoDialog from "../dialogs/InfoDialog"; import { EventType } from "matrix-js-sdk/src/@types/event"; -import {SetRightPanelPhasePayload} from "../../../dispatcher/payloads/SetRightPanelPhasePayload"; +import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload"; +import RoomAvatar from "../avatars/RoomAvatar"; +import RoomName from "../elements/RoomName"; interface IDevice { deviceId: string; @@ -302,7 +304,8 @@ const UserOptionsSection: React.FC<{ member: RoomMember; isIgnored: boolean; canInvite: boolean; -}> = ({member, isIgnored, canInvite}) => { + isSpace?: boolean; +}> = ({member, isIgnored, canInvite, isSpace}) => { const cli = useContext(MatrixClientContext); let ignoreButton = null; @@ -342,7 +345,7 @@ const UserOptionsSection: React.FC<{ ); - if (member.roomId) { + if (member.roomId && !isSpace) { const onReadReceiptButton = function() { const room = cli.getRoom(member.roomId); dis.dispatch({ @@ -434,14 +437,18 @@ const UserOptionsSection: React.FC<{ ); }; -const warnSelfDemote = async () => { +const warnSelfDemote = async (isSpace) => { const {finished} = Modal.createTrackedDialog('Demoting Self', '', QuestionDialog, { title: _t("Demote yourself?"), description:
- { _t("You will not be able to undo this change as you are demoting yourself, " + - "if you are the last privileged user in the room it will be impossible " + - "to regain privileges.") } + { isSpace + ? _t("You will not be able to undo this change as you are demoting yourself, " + + "if you are the last privileged user in the space it will be impossible " + + "to regain privileges.") + : _t("You will not be able to undo this change as you are demoting yourself, " + + "if you are the last privileged user in the room it will be impossible " + + "to regain privileges.") }
, button: _t("Demote"), }); @@ -717,7 +724,7 @@ const MuteToggleButton: React.FC = ({member, room, powerLevels, // if muting self, warn as it may be irreversible if (target === cli.getUserId()) { try { - if (!(await warnSelfDemote())) return; + if (!(await warnSelfDemote(room?.isSpaceRoom()))) return; } catch (e) { console.error("Failed to warn about self demotion: ", e); return; @@ -806,7 +813,7 @@ const RoomAdminToolsContainer: React.FC = ({ if (canAffectUser && me.powerLevel >= kickPowerLevel) { kickButton = ; } - if (me.powerLevel >= redactPowerLevel) { + if (me.powerLevel >= redactPowerLevel && !room.isSpaceRoom()) { redactButton = ( ); @@ -1085,7 +1092,7 @@ const PowerLevelEditor: React.FC<{ } else if (myUserId === target) { // If we are changing our own PL it can only ever be decreasing, which we cannot reverse. try { - if (!(await warnSelfDemote())) return; + if (!(await warnSelfDemote(room?.isSpaceRoom()))) return; } catch (e) { console.error("Failed to warn about self demotion: ", e); } @@ -1315,12 +1322,10 @@ const BasicUserInfo: React.FC<{ if (!isRoomEncrypted) { if (!cryptoEnabled) { text = _t("This client does not support end-to-end encryption."); - } else if (room) { + } else if (room && !room.isSpaceRoom()) { text = _t("Messages in this room are not end-to-end encrypted."); - } else { - // TODO what to render for GroupMember } - } else { + } else if (!room.isSpaceRoom()) { text = _t("Messages in this room are end-to-end encrypted."); } @@ -1381,7 +1386,9 @@ const BasicUserInfo: React.FC<{ + member={member} + isSpace={room?.isSpaceRoom()} + /> { adminToolsContainer } @@ -1498,7 +1505,7 @@ interface IProps { user: Member; groupId?: string; room?: Room; - phase: RightPanelPhases.RoomMemberInfo | RightPanelPhases.GroupMemberInfo; + phase: RightPanelPhases.RoomMemberInfo | RightPanelPhases.GroupMemberInfo | RightPanelPhases.SpaceMemberInfo; onClose(): void; } @@ -1542,7 +1549,9 @@ const UserInfo: React.FC = ({ previousPhase = RightPanelPhases.RoomMemberInfo; refireParams = {member: member}; } else if (room) { - previousPhase = RightPanelPhases.RoomMemberList; + previousPhase = previousPhase = room.isSpaceRoom() + ? RightPanelPhases.SpaceMemberList + : RightPanelPhases.RoomMemberList; } const onEncryptionPanelClose = () => { @@ -1557,6 +1566,7 @@ const UserInfo: React.FC = ({ switch (phase) { case RightPanelPhases.RoomMemberInfo: case RightPanelPhases.GroupMemberInfo: + case RightPanelPhases.SpaceMemberInfo: content = ( = ({ } } - const header = ; + let scopeHeader; + if (room?.isSpaceRoom()) { + scopeHeader =
+ + +
; + } + + const header = + { scopeHeader } + + ; return ); + let previousPhase = RightPanelPhases.RoomSummary; + // We have no previousPhase for when viewing a MemberList from a Space + let scopeHeader; + if (room?.isSpaceRoom()) { + previousPhase = undefined; + scopeHeader =
+ + +
; + } + return + { scopeHeader } + { inviteButton } + } footer={footer} onClose={this.props.onClose} - previousPhase={RightPanelPhases.RoomSummary} + previousPhase={previousPhase} >
+ + +
; + } + // We shamelessly rip off the MemberInfo styles here. return (
+ { scopeHeader }
).": "Start a conversation with someone using their name or username (like ).", "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here", "Go": "Go", - "Invite to this space": "Invite to this space", "Invite someone using their name, email address, username (like ) or share this room.": "Invite someone using their name, email address, username (like ) or share this room.", "Invite someone using their name, username (like ) or share this room.": "Invite someone using their name, username (like ) or share this room.", "Invite someone using their name, email address, username (like ) or share this space.": "Invite someone using their name, email address, username (like ) or share this space.",