From 0768f03097777c950c61cde3f6e6b96b9f1847cf Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 22 Jul 2021 17:11:23 +0200 Subject: [PATCH 01/13] Migrate ViewSourceEvent to TypeScript --- res/css/views/messages/_ViewSourceEvent.scss | 4 ++- res/css/views/rooms/_EventBubbleTile.scss | 5 +++- ...ViewSourceEvent.js => ViewSourceEvent.tsx} | 25 +++++++++++-------- 3 files changed, 21 insertions(+), 13 deletions(-) rename src/components/views/messages/{ViewSourceEvent.js => ViewSourceEvent.tsx} (87%) diff --git a/res/css/views/messages/_ViewSourceEvent.scss b/res/css/views/messages/_ViewSourceEvent.scss index 66825030e0..b0e40a5152 100644 --- a/res/css/views/messages/_ViewSourceEvent.scss +++ b/res/css/views/messages/_ViewSourceEvent.scss @@ -43,8 +43,10 @@ limitations under the License. margin-bottom: 7px; mask-image: url('$(res)/img/feather-customised/minimise.svg'); } +} - &:hover .mx_ViewSourceEvent_toggle { +.mx_EventTile:hover { + .mx_ViewSourceEvent_toggle { visibility: visible; } } diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index cac463d4db..f603042b59 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -219,13 +219,16 @@ limitations under the License. display: flex; align-items: center; - justify-content: center; .mx_EventTile_avatar { position: static; order: -1; margin-right: 5px; } + + .mx_EventTile_e2eIcon { + margin-left: 9px; + } } & ~ .mx_EventListSummary { diff --git a/src/components/views/messages/ViewSourceEvent.js b/src/components/views/messages/ViewSourceEvent.tsx similarity index 87% rename from src/components/views/messages/ViewSourceEvent.js rename to src/components/views/messages/ViewSourceEvent.tsx index 5a5c015dcf..488f8de5df 100644 --- a/src/components/views/messages/ViewSourceEvent.js +++ b/src/components/views/messages/ViewSourceEvent.tsx @@ -15,18 +15,21 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; +import { MatrixEvent } from 'matrix-js-sdk/src'; import classNames from 'classnames'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; -@replaceableComponent("views.messages.ViewSourceEvent") -export default class ViewSourceEvent extends React.PureComponent { - static propTypes = { - /* the MatrixEvent to show */ - mxEvent: PropTypes.object.isRequired, - }; +interface IProps { + mxEvent: MatrixEvent; +} +interface IState { + expanded: boolean; +} + +@replaceableComponent("views.messages.ViewSourceEvent") +export default class ViewSourceEvent extends React.PureComponent { constructor(props) { super(props); @@ -35,7 +38,7 @@ export default class ViewSourceEvent extends React.PureComponent { }; } - componentDidMount() { + public componentDidMount(): void { const { mxEvent } = this.props; const client = MatrixClientPeg.get(); @@ -46,15 +49,15 @@ export default class ViewSourceEvent extends React.PureComponent { } } - onToggle = (ev) => { + private onToggle = (ev: React.MouseEvent) => { ev.preventDefault(); const { expanded } = this.state; this.setState({ expanded: !expanded, }); - } + }; - render() { + public render(): React.ReactNode { const { mxEvent } = this.props; const { expanded } = this.state; From 010baabfe6263e7ce76e30f78548f0b951cd7ca0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 23 Jul 2021 08:46:20 +0100 Subject: [PATCH 02/13] Improve subspaces and some utilities around room/space creation --- res/css/_components.scss | 2 + .../context_menus/_IconizedContextMenu.scss | 4 + .../dialogs/_AddExistingToSpaceDialog.scss | 188 ++++++------ res/css/views/dialogs/_CreateRoomDialog.scss | 52 ---- .../views/dialogs/_CreateSubspaceDialog.scss | 75 +++++ res/css/views/dialogs/_JoinRuleDropdown.scss | 67 +++++ src/components/structures/SpaceRoomView.tsx | 38 ++- .../context_menus/IconizedContextMenu.tsx | 3 +- .../dialogs/AddExistingSubspaceDialog.tsx | 70 +++++ .../dialogs/AddExistingToSpaceDialog.tsx | 268 ++++++++++++------ .../views/dialogs/CreateRoomDialog.tsx | 33 +-- .../views/dialogs/CreateSubspaceDialog.tsx | 183 ++++++++++++ .../views/elements/JoinRuleDropdown.tsx | 68 +++++ .../views/spaces/SpaceCreateMenu.tsx | 172 ++++++----- .../views/spaces/SpaceTreeLevel.tsx | 17 ++ src/createRoom.ts | 52 +++- src/i18n/strings/en_EN.json | 26 +- src/utils/space.tsx | 36 ++- 18 files changed, 983 insertions(+), 371 deletions(-) create mode 100644 res/css/views/dialogs/_CreateSubspaceDialog.scss create mode 100644 res/css/views/dialogs/_JoinRuleDropdown.scss create mode 100644 src/components/views/dialogs/AddExistingSubspaceDialog.tsx create mode 100644 src/components/views/dialogs/CreateSubspaceDialog.tsx create mode 100644 src/components/views/elements/JoinRuleDropdown.tsx diff --git a/res/css/_components.scss b/res/css/_components.scss index f9e3ab1160..574578ccce 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -76,6 +76,7 @@ @import "./views/dialogs/_CreateCommunityPrototypeDialog.scss"; @import "./views/dialogs/_CreateGroupDialog.scss"; @import "./views/dialogs/_CreateRoomDialog.scss"; +@import "./views/dialogs/_CreateSubspaceDialog.scss"; @import "./views/dialogs/_DeactivateAccountDialog.scss"; @import "./views/dialogs/_DevtoolsDialog.scss"; @import "./views/dialogs/_EditCommunityPrototypeDialog.scss"; @@ -85,6 +86,7 @@ @import "./views/dialogs/_HostSignupDialog.scss"; @import "./views/dialogs/_IncomingSasDialog.scss"; @import "./views/dialogs/_InviteDialog.scss"; +@import "./views/dialogs/_JoinRuleDropdown.scss"; @import "./views/dialogs/_KeyboardShortcutsDialog.scss"; @import "./views/dialogs/_ManageRestrictedJoinRuleDialog.scss"; @import "./views/dialogs/_MessageEditHistoryDialog.scss"; diff --git a/res/css/views/context_menus/_IconizedContextMenu.scss b/res/css/views/context_menus/_IconizedContextMenu.scss index 204435995f..2aa43283b5 100644 --- a/res/css/views/context_menus/_IconizedContextMenu.scss +++ b/res/css/views/context_menus/_IconizedContextMenu.scss @@ -99,6 +99,10 @@ limitations under the License. .mx_IconizedContextMenu_icon + .mx_IconizedContextMenu_label { padding-left: 14px; } + + .mx_BetaCard_betaPill { + margin-left: 16px; + } } } diff --git a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss index 2776c477fc..b299198349 100644 --- a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss +++ b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss @@ -54,11 +54,16 @@ limitations under the License. display: flex; margin-top: 12px; - // we can't target .mx_BaseAvatar here as it'll break the decorated avatar styling - .mx_DecoratedRoomAvatar { + .mx_DecoratedRoomAvatar, // we can't target .mx_BaseAvatar here as it'll break the decorated avatar styling + .mx_BaseAvatar.mx_RoomAvatar_isSpaceRoom { margin-right: 12px; } + img.mx_RoomAvatar_isSpaceRoom, + .mx_RoomAvatar_isSpaceRoom img { + border-radius: 8px; + } + .mx_AddExistingToSpace_entry_name { font-size: $font-15px; line-height: 30px; @@ -73,41 +78,12 @@ limitations under the License. align-items: center; } } - } - .mx_AddExistingToSpace_section_spaces { - .mx_BaseAvatar { - margin-right: 12px; - } - - .mx_BaseAvatar_image { - border-radius: 8px; - } - } - - .mx_AddExistingToSpace_section_experimental { - position: relative; - border-radius: 8px; - margin: 12px 0; - padding: 8px 8px 8px 42px; - background-color: $header-panel-bg-color; - - font-size: $font-12px; - line-height: $font-15px; - color: $secondary-fg-color; - - &::before { - content: ''; - position: absolute; - left: 10px; - top: calc(50% - 8px); // vertical centering - height: 16px; - width: 16px; - background-color: $secondary-fg-color; - mask-repeat: no-repeat; - mask-size: contain; - mask-image: url('$(res)/img/element-icons/room/room-summary.svg'); - mask-position: center; + .mx_AccessibleButton_kind_link { + font-size: $font-12px; + line-height: $font-15px; + margin-top: 8px; + padding: 0; } } @@ -205,77 +181,77 @@ limitations under the License. min-height: 0; height: 80vh; - .mx_Dialog_title { - display: flex; - - .mx_BaseAvatar_image { - border-radius: 8px; - margin: 0; - vertical-align: unset; - } - - .mx_BaseAvatar { - display: inline-flex; - margin: auto 16px auto 5px; - vertical-align: middle; - } - - > div { - > h1 { - font-weight: $font-semi-bold; - font-size: $font-18px; - line-height: $font-22px; - margin: 0; - } - - .mx_AddExistingToSpaceDialog_onlySpace { - color: $secondary-fg-color; - font-size: $font-15px; - line-height: $font-24px; - } - } - - .mx_Dropdown_input { - border: none; - - > .mx_Dropdown_option { - padding-left: 0; - flex: unset; - height: unset; - color: $secondary-fg-color; - font-size: $font-15px; - line-height: $font-24px; - - .mx_BaseAvatar { - display: none; - } - } - - .mx_Dropdown_menu { - .mx_AddExistingToSpaceDialog_dropdownOptionActive { - color: $accent-color; - padding-right: 32px; - position: relative; - - &::before { - content: ''; - width: 20px; - height: 20px; - top: 8px; - right: 0; - position: absolute; - mask-position: center; - mask-size: contain; - mask-repeat: no-repeat; - background-color: $accent-color; - mask-image: url('$(res)/img/element-icons/roomlist/checkmark.svg'); - } - } - } - } - } - .mx_AddExistingToSpace { display: contents; } } + +.mx_SubspaceSelector { + display: flex; + + .mx_BaseAvatar_image { + border-radius: 8px; + margin: 0; + vertical-align: unset; + } + + .mx_BaseAvatar { + display: inline-flex; + margin: auto 16px auto 5px; + vertical-align: middle; + } + + > div { + > h1 { + font-weight: $font-semi-bold; + font-size: $font-18px; + line-height: $font-22px; + margin: 0; + } + } + + .mx_Dropdown_input { + border: none; + + > .mx_Dropdown_option { + padding-left: 0; + flex: unset; + height: unset; + color: $secondary-fg-color; + font-size: $font-15px; + line-height: $font-24px; + + .mx_BaseAvatar { + display: none; + } + } + + .mx_Dropdown_menu { + .mx_SubspaceSelector_dropdownOptionActive { + color: $accent-color; + padding-right: 32px; + position: relative; + + &::before { + content: ''; + width: 20px; + height: 20px; + top: 8px; + right: 0; + position: absolute; + mask-position: center; + mask-size: contain; + mask-repeat: no-repeat; + background-color: $accent-color; + mask-image: url('$(res)/img/element-icons/roomlist/checkmark.svg'); + } + } + } + } + + .mx_SubspaceSelector_onlySpace { + color: $secondary-fg-color; + font-size: $font-15px; + line-height: $font-24px; + } +} diff --git a/res/css/views/dialogs/_CreateRoomDialog.scss b/res/css/views/dialogs/_CreateRoomDialog.scss index 5321d8ff69..e7cfbf6050 100644 --- a/res/css/views/dialogs/_CreateRoomDialog.scss +++ b/res/css/views/dialogs/_CreateRoomDialog.scss @@ -109,56 +109,4 @@ limitations under the License. margin: 0 85px 0 0; font-size: $font-12px; } - - .mx_Dropdown { - margin-bottom: 8px; - font-weight: normal; - font-family: $font-family; - font-size: $font-14px; - color: $primary-fg-color; - - .mx_Dropdown_input { - border: 1px solid $input-border-color; - } - - .mx_Dropdown_option { - font-size: $font-14px; - line-height: $font-32px; - height: 32px; - min-height: 32px; - - > div { - padding-left: 30px; - position: relative; - - &::before { - content: ""; - position: absolute; - height: 16px; - width: 16px; - left: 6px; - top: 8px; - mask-repeat: no-repeat; - mask-position: center; - background-color: $secondary-fg-color; - } - } - } - - .mx_CreateRoomDialog_dropdown_invite::before { - mask-image: url('$(res)/img/element-icons/lock.svg'); - mask-size: contain; - } - - .mx_CreateRoomDialog_dropdown_public::before { - mask-image: url('$(res)/img/globe.svg'); - mask-size: 12px; - } - - .mx_CreateRoomDialog_dropdown_restricted::before { - mask-image: url('$(res)/img/element-icons/community-members.svg'); - mask-size: contain; - } - } } - diff --git a/res/css/views/dialogs/_CreateSubspaceDialog.scss b/res/css/views/dialogs/_CreateSubspaceDialog.scss new file mode 100644 index 0000000000..b898ba6d73 --- /dev/null +++ b/res/css/views/dialogs/_CreateSubspaceDialog.scss @@ -0,0 +1,75 @@ +/* +Copyright 2021 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. +*/ + +.mx_CreateSubspaceDialog_wrapper { + .mx_Dialog { + display: flex; + flex-direction: column; + } +} + +.mx_CreateSubspaceDialog { + width: 480px; + color: $primary-fg-color; + display: flex; + flex-direction: column; + flex-wrap: nowrap; + min-height: 0; + + .mx_CreateSubspaceDialog_content { + flex-grow: 1; + + .mx_CreateSubspaceDialog_betaNotice { + padding: 12px 16px; + border-radius: 8px; + background-color: $header-panel-bg-color; + + .mx_BetaCard_betaPill { + margin-right: 8px; + } + } + } + + .mx_CreateSubspaceDialog_footer { + display: flex; + margin-top: 20px; + + > span { + flex-grow: 1; + font-size: $font-12px; + line-height: $font-15px; + color: $secondary-fg-color; + + > * { + vertical-align: middle; + } + } + + .mx_AccessibleButton { + display: inline-block; + align-self: center; + } + + .mx_AccessibleButton_kind_primary { + margin-left: 16px; + padding: 8px 36px; + } + + .mx_AccessibleButton_kind_link { + padding: 0; + } + } +} diff --git a/res/css/views/dialogs/_JoinRuleDropdown.scss b/res/css/views/dialogs/_JoinRuleDropdown.scss new file mode 100644 index 0000000000..c48a79af3c --- /dev/null +++ b/res/css/views/dialogs/_JoinRuleDropdown.scss @@ -0,0 +1,67 @@ +/* +Copyright 2021 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. +*/ + +.mx_JoinRuleDropdown { + margin-bottom: 8px; + font-weight: normal; + font-family: $font-family; + font-size: $font-14px; + color: $primary-fg-color; + + .mx_Dropdown_input { + border: 1px solid $input-border-color; + } + + .mx_Dropdown_option { + font-size: $font-14px; + line-height: $font-32px; + height: 32px; + min-height: 32px; + + > div { + padding-left: 30px; + position: relative; + + &::before { + content: ""; + position: absolute; + height: 16px; + width: 16px; + left: 6px; + top: 8px; + mask-repeat: no-repeat; + mask-position: center; + background-color: $secondary-fg-color; + } + } + } + + .mx_JoinRuleDropdown_invite::before { + mask-image: url('$(res)/img/element-icons/lock.svg'); + mask-size: contain; + } + + .mx_JoinRuleDropdown_public::before { + mask-image: url('$(res)/img/globe.svg'); + mask-size: 12px; + } + + .mx_JoinRuleDropdown_restricted::before { + mask-image: url('$(res)/img/element-icons/community-members.svg'); + mask-size: contain; + } +} + diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 36b4d8d549..ec647e8ea8 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -47,13 +47,24 @@ import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; import { SetRightPanelPhasePayload } from "../../dispatcher/payloads/SetRightPanelPhasePayload"; import { useStateArray } from "../../hooks/useStateArray"; import SpacePublicShare from "../views/spaces/SpacePublicShare"; -import { shouldShowSpaceSettings, showAddExistingRooms, showCreateNewRoom, showSpaceSettings } from "../../utils/space"; +import { + shouldShowSpaceSettings, + showAddExistingRooms, + showCreateNewRoom, + showCreateNewSubspace, + showSpaceSettings, +} from "../../utils/space"; import { showRoom, SpaceHierarchy } from "./SpaceRoomDirectory"; import MemberAvatar from "../views/avatars/MemberAvatar"; import { useStateToggle } from "../../hooks/useStateToggle"; import SpaceStore from "../../stores/SpaceStore"; import FacePile from "../views/elements/FacePile"; -import { AddExistingToSpace } from "../views/dialogs/AddExistingToSpaceDialog"; +import { + AddExistingToSpace, + defaultDmsRenderer, + defaultRoomsRenderer, + defaultSpacesRenderer, +} from "../views/dialogs/AddExistingToSpaceDialog"; import { ChevronFace, ContextMenuButton, useContextMenu } from "./ContextMenu"; import IconizedContextMenu, { IconizedContextMenuOption, @@ -347,6 +358,22 @@ const SpaceLandingAddButton = ({ space, onNewRoomAdded }) => { } }} /> + { + e.preventDefault(); + e.stopPropagation(); + closeMenu(); + + const [added] = await showCreateNewSubspace(space); + if (added) { + onNewRoomAdded(); + } + }} + > + + ; } @@ -548,12 +575,13 @@ const SpaceAddExistingRooms = ({ space, onFinished }) => { { _t("Skip for now") } } + filterPlaceholder={_t("Search for rooms or spaces")} onFinished={onFinished} + roomsRenderer={defaultRoomsRenderer} + spacesRenderer={defaultSpacesRenderer} + dmsRenderer={defaultDmsRenderer} /> -
- -
; }; diff --git a/src/components/views/context_menus/IconizedContextMenu.tsx b/src/components/views/context_menus/IconizedContextMenu.tsx index 1d822fd246..c9506d7c98 100644 --- a/src/components/views/context_menus/IconizedContextMenu.tsx +++ b/src/components/views/context_menus/IconizedContextMenu.tsx @@ -90,10 +90,11 @@ export const IconizedContextMenuCheckbox: React.FC = ({ ; }; -export const IconizedContextMenuOption: React.FC = ({ label, iconClassName, ...props }) => { +export const IconizedContextMenuOption: React.FC = ({ label, iconClassName, children, ...props }) => { return { iconClassName && } { label } + { children } ; }; diff --git a/src/components/views/dialogs/AddExistingSubspaceDialog.tsx b/src/components/views/dialogs/AddExistingSubspaceDialog.tsx new file mode 100644 index 0000000000..f0e5e9241e --- /dev/null +++ b/src/components/views/dialogs/AddExistingSubspaceDialog.tsx @@ -0,0 +1,70 @@ +/* +Copyright 2021 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, { useState } from "react"; +import { Room } from "matrix-js-sdk/src/models/room"; + +import { _t } from '../../../languageHandler'; +import BaseDialog from "./BaseDialog"; +import AccessibleButton from "../elements/AccessibleButton"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import { SpaceFeedbackPrompt } from "../../structures/SpaceRoomView"; +import { AddExistingToSpace, defaultSpacesRenderer, SubspaceSelector } from "./AddExistingToSpaceDialog"; + +interface IProps { + space: Room; + onCreateSubspaceClick(): void; + onFinished(added?: boolean): void; +} + +const AddExistingSubspaceDialog: React.FC = ({ space, onCreateSubspaceClick, onFinished }) => { + const [selectedSpace, setSelectedSpace] = useState(space); + + return + )} + className="mx_AddExistingToSpaceDialog" + contentId="mx_AddExistingToSpace" + onFinished={onFinished} + fixedWidth={false} + > + + +
{ _t("Want to add a new space instead?") }
+ + { _t("Create a new subspace") } + + } + filterPlaceholder={_t("Search for spaces")} + spacesRenderer={defaultSpacesRenderer} + /> +
+ + onFinished(false)} /> +
; +}; + +export default AddExistingSubspaceDialog; + diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx index 01dc729a83..a0c2a09943 100644 --- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx +++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx @@ -18,9 +18,9 @@ import React, { ReactNode, useContext, useMemo, useState } from "react"; import classNames from "classnames"; import { Room } from "matrix-js-sdk/src/models/room"; import { sleep } from "matrix-js-sdk/src/utils"; +import { EventType } from "matrix-js-sdk/src/@types/event"; import { _t } from '../../../languageHandler'; -import { IDialogProps } from "./IDialogProps"; import BaseDialog from "./BaseDialog"; import Dropdown from "../elements/Dropdown"; import SearchBox from "../../structures/SearchBox"; @@ -42,12 +42,14 @@ import TruncatedList from "../elements/TruncatedList"; import EntityTile from "../rooms/EntityTile"; import BaseAvatar from "../avatars/BaseAvatar"; -interface IProps extends IDialogProps { +interface IProps { space: Room; - onCreateRoomClick(space: Room): void; + onCreateRoomClick(): void; + onAddSubspaceClick(): void; + onFinished(added?: boolean): void; } -const Entry = ({ room, checked, onChange }) => { +export const Entry = ({ room, checked, onChange }) => { return