diff --git a/.eslintrc.js b/.eslintrc.js index 45cd05506f..9efdd12854 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -123,7 +123,6 @@ module.exports = { "src/components/structures/UserMenu.tsx", "src/components/views/avatars/WidgetAvatar.tsx", "src/components/views/dialogs/AddExistingToSpaceDialog.tsx", - "src/components/views/dialogs/CreateSpaceFromCommunityDialog.tsx", "src/components/views/dialogs/ForwardDialog.tsx", "src/components/views/dialogs/InviteDialog.tsx", "src/components/views/dialogs/ModalWidgetDialog.tsx", diff --git a/res/css/_components.scss b/res/css/_components.scss index 779b2e9c9b..4c72550c15 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -18,18 +18,14 @@ @import "./structures/_CompatibilityPage.scss"; @import "./structures/_ContextualMenu.scss"; @import "./structures/_CreateRoom.scss"; -@import "./structures/_CustomRoomTagPanel.scss"; @import "./structures/_FileDropTarget.scss"; @import "./structures/_FilePanel.scss"; @import "./structures/_GenericErrorPage.scss"; -@import "./structures/_GroupFilterPanel.scss"; -@import "./structures/_GroupView.scss"; @import "./structures/_HeaderButtons.scss"; @import "./structures/_HomePage.scss"; @import "./structures/_LeftPanel.scss"; @import "./structures/_MainSplit.scss"; @import "./structures/_MatrixChat.scss"; -@import "./structures/_MyGroups.scss"; @import "./structures/_NonUrgentToastContainer.scss"; @import "./structures/_NotificationPanel.scss"; @import "./structures/_QuickSettingsButton.scss"; @@ -75,32 +71,24 @@ @import "./views/context_menus/_CallContextMenu.scss"; @import "./views/context_menus/_IconizedContextMenu.scss"; @import "./views/context_menus/_MessageContextMenu.scss"; -@import "./views/context_menus/_TagTileContextMenu.scss"; @import "./views/dialogs/_AddExistingToSpaceDialog.scss"; -@import "./views/dialogs/_AddressPickerDialog.scss"; @import "./views/dialogs/_Analytics.scss"; @import "./views/dialogs/_AnalyticsLearnMoreDialog.scss"; @import "./views/dialogs/_BugReportDialog.scss"; @import "./views/dialogs/_BulkRedactDialog.scss"; @import "./views/dialogs/_ChangelogDialog.scss"; @import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss"; -@import "./views/dialogs/_CommunityPrototypeInviteDialog.scss"; @import "./views/dialogs/_CompoundDialog.scss"; @import "./views/dialogs/_ConfirmSpaceUserActionDialog.scss"; @import "./views/dialogs/_ConfirmUserActionDialog.scss"; -@import "./views/dialogs/_CreateCommunityPrototypeDialog.scss"; -@import "./views/dialogs/_CreateGroupDialog.scss"; @import "./views/dialogs/_CreateRoomDialog.scss"; -@import "./views/dialogs/_CreateSpaceFromCommunityDialog.scss"; @import "./views/dialogs/_CreateSubspaceDialog.scss"; @import "./views/dialogs/_DeactivateAccountDialog.scss"; @import "./views/dialogs/_DevtoolsDialog.scss"; -@import "./views/dialogs/_EditCommunityPrototypeDialog.scss"; @import "./views/dialogs/_ExportDialog.scss"; @import "./views/dialogs/_FeedbackDialog.scss"; @import "./views/dialogs/_ForwardDialog.scss"; @import "./views/dialogs/_GenericFeatureFeedbackDialog.scss"; -@import "./views/dialogs/_GroupAddressPicker.scss"; @import "./views/dialogs/_HostSignupDialog.scss"; @import "./views/dialogs/_IncomingSasDialog.scss"; @import "./views/dialogs/_InviteDialog.scss"; @@ -186,9 +174,6 @@ @import "./views/elements/_TooltipButton.scss"; @import "./views/elements/_Validation.scss"; @import "./views/emojipicker/_EmojiPicker.scss"; -@import "./views/groups/_GroupPublicityToggle.scss"; -@import "./views/groups/_GroupRoomList.scss"; -@import "./views/groups/_GroupUserSettings.scss"; @import "./views/location/_LocationPicker.scss"; @import "./views/messages/_CallEvent.scss"; @import "./views/messages/_CreateEvent.scss"; diff --git a/res/css/structures/_CustomRoomTagPanel.scss b/res/css/structures/_CustomRoomTagPanel.scss deleted file mode 100644 index 627644f102..0000000000 --- a/res/css/structures/_CustomRoomTagPanel.scss +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright 2019 New Vector Ltd. - -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. -*/ - -// TODO: Update design for custom tags to match new designs - -.mx_CustomRoomTagPanel { - background-color: $groupFilterPanel-bg-color; - max-height: 40vh; -} - -.mx_CustomRoomTagPanel_scroller { - max-height: inherit; - display: flex; - flex-direction: column; - align-items: center; -} - -.mx_CustomRoomTagPanel .mx_AccessibleButton { - margin: 0 auto; - width: 40px; - padding: 10px 0 9px 0; - position: relative; -} - -.mx_CustomRoomTagPanel .mx_BaseAvatar_image { - box-sizing: border-box; - width: 40px; - height: 40px; -} - -.mx_CustomRoomTagPanel .mx_AccessibleButton.CustomRoomTagPanel_tileSelected::before { - content: ''; - height: 56px; - background-color: $accent-alt; - width: 5px; - position: absolute; - left: -9px; - border-radius: 0 3px 3px 0; - top: 5px; // just feels right (see comment above about designs needing to be updated) -} diff --git a/res/css/structures/_GroupFilterPanel.scss b/res/css/structures/_GroupFilterPanel.scss deleted file mode 100644 index bdbd9f7643..0000000000 --- a/res/css/structures/_GroupFilterPanel.scss +++ /dev/null @@ -1,207 +0,0 @@ -/* -Copyright 2017 New Vector Ltd. - -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. -*/ - -$groupFilterPanelWidth: 56px; // only applies in this file, used for calculations - -.mx_GroupFilterPanelContainer { - flex-grow: 0; - flex-shrink: 0; - width: $groupFilterPanelWidth; - height: 100%; - - // Create another flexbox so the GroupFilterPanel fills the container - display: flex; - flex-direction: column; - - // GroupFilterPanel handles its own CSS -} - -.mx_GroupFilterPanel { - z-index: 1; - background-color: $groupFilterPanel-bg-color; - flex: 1; - cursor: pointer; - position: relative; - - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-between; - min-height: 0; -} - -.mx_GroupFilterPanel_items_selected { - cursor: pointer; -} - -.mx_GroupFilterPanel .mx_GroupFilterPanel_divider { - height: 0px; - width: 90%; - border: none; - border-bottom: 1px solid $tertiary-content; -} - -.mx_GroupFilterPanel .mx_GroupFilterPanel_scroller { - flex-grow: 1; - width: 100%; -} - -.mx_GroupFilterPanel .mx_GroupFilterPanel_tagTileContainer { - display: flex; - flex-direction: column; - align-items: center; - - padding-top: 6px; -} -.mx_GroupFilterPanel .mx_GroupFilterPanel_tagTileContainer > div { - margin: 6px 0; -} - -.mx_GroupFilterPanel .mx_TagTile { - // opacity: 0.5; - position: relative; -} - -.mx_GroupFilterPanel .mx_TagTile.mx_TagTile_prototype { - padding: 3px; -} - -.mx_GroupFilterPanel .mx_TagTile:focus, -.mx_GroupFilterPanel .mx_TagTile:hover, -.mx_GroupFilterPanel .mx_TagTile.mx_TagTile_selected { - // opacity: 1; -} - -.mx_GroupFilterPanel .mx_TagTile.mx_TagTile_selected_prototype { - background-color: $background; - border-radius: 6px; -} - -.mx_TagTile_selected_prototype { - .mx_TagTile_homeIcon::before { - background-color: $primary-content; // dark-on-light - } -} - -.mx_TagTile:not(.mx_TagTile_selected_prototype) .mx_TagTile_homeIcon { - background-color: $roomheader-addroom-bg-color; - border-radius: 48px; - - &::before { - background-color: $roomheader-addroom-fg-color; - } -} - -.mx_TagTile_homeIcon { - width: 32px; - height: 32px; - position: relative; - - &::before { - mask-image: url('$(res)/img/element-icons/home.svg'); - mask-position: center; - mask-repeat: no-repeat; - mask-size: 21px; - content: ''; - display: inline-block; - width: 32px; - height: 32px; - position: absolute; - top: calc(50% - 16px); - left: calc(50% - 16px); - } -} - -.mx_GroupFilterPanel .mx_TagTile_plus { - margin-bottom: 12px; - height: 32px; - width: 32px; - border-radius: 20px; - background-color: $roomheader-addroom-bg-color; - position: relative; - /* overwrite mx_RoleButton inline-block */ - display: block !important; - - &::before { - background-color: $roomheader-addroom-fg-color; - mask-image: url('$(res)/img/feather-customised/plus.svg'); - mask-position: center; - mask-repeat: no-repeat; - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - } -} - -.mx_GroupFilterPanel .mx_TagTile.mx_TagTile_selected::before { - content: ''; - height: 100%; - background-color: $accent; - width: 4px; - position: absolute; - left: -12px; - border-radius: 0 3px 3px 0; -} - -.mx_GroupFilterPanel .mx_TagTile.mx_AccessibleButton:focus { - filter: none; -} - -.mx_TagTile_tooltip { - position: relative; - top: -30px; - left: 5px; -} - -.mx_TagTile_context_button { - min-width: 15px; - height: 15px; - position: absolute; - right: -5px; - top: -8px; - border-radius: 8px; - background-color: $neutral-badge-color; - color: #000; - font-weight: 600; - font-size: $font-10px; - text-align: center; - padding-top: 1px; - padding-left: 4px; - padding-right: 4px; -} - -.mx_TagTile_avatar { - position: relative; -} - -.mx_TagTile_badge { - position: absolute; - right: -4px; - top: -2px; - border-radius: 8px; - color: $accent-fg-color; - font-weight: 600; - font-size: $font-14px; - padding: 0 5px; - background-color: $muted-fg-color; -} - -.mx_TagTile_badgeHighlight { - background-color: $alert; -} diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss deleted file mode 100644 index 9cbf632cdd..0000000000 --- a/res/css/structures/_GroupView.scss +++ /dev/null @@ -1,434 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd - -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_GroupView { - display: flex; - flex-direction: column; - overflow: hidden; - flex-grow: 1; -} - -.mx_GroupView_error { - margin: auto; -} - -.mx_GroupView_header { - min-height: 52px; - align-items: center; - display: flex; - padding-bottom: 10px; - padding-left: 19px; -} - -.mx_GroupView_header_view { - border-bottom: 1px solid $primary-hairline-color; - padding-bottom: 0px; - padding-right: 8px; -} - -.mx_GroupView_header_avatar, .mx_GroupView_header_info { - display: table-cell; - vertical-align: middle; -} - -.mx_GroupHeader_button { - position: relative; - margin-left: 5px; - margin-right: 5px; - cursor: pointer; - height: 20px; - width: 20px; - - &::before { - content: ''; - position: absolute; - height: 20px; - width: 20px; - background-color: $header-panel-text-primary-color; - mask-repeat: no-repeat; - mask-size: contain; - } -} - -.mx_GroupHeader_editButton::before { - mask-image: url('$(res)/img/element-icons/settings.svg'); -} - -.mx_GroupHeader_shareButton::before { - mask-image: url('$(res)/img/element-icons/room/share.svg'); -} - -.mx_GroupView_hostingSignup img { - margin-left: 5px; -} - -.mx_GroupView_editable { - border-bottom: 1px solid $strong-input-border-color !important; - min-width: 150px; - cursor: text; -} - -.mx_GroupView_editable:focus { - border-bottom: 1px solid $accent !important; - outline: none; - box-shadow: none; -} - -.mx_GroupView_header_isUserMember .mx_GroupView_header_name:hover div:not(.mx_GroupView_editable) { - color: $accent; - cursor: pointer; -} - -.mx_GroupView_avatarPicker { - position: relative; -} - -.mx_GroupView_avatarPicker_edit { - position: absolute; - top: 50px; - left: 15px; -} - -.mx_GroupView_avatarPicker .mx_Spinner { - width: 48px; - height: 48px !important; -} - -.mx_GroupView_header_leftCol { - flex: 1; - - overflow: hidden; -} - -.mx_GroupView_header_rightCol { - display: flex; - align-items: center; -} - -.mx_GroupView_textButton { - display: inline-block; -} - -.mx_GroupView_header_groupid { - font-weight: normal; - font-size: initial; - padding-left: 10px; -} - -.mx_GroupView_header_name { - vertical-align: middle; - width: 100%; - height: 31px; - overflow: hidden; - color: $primary-content; - font-weight: bold; - font-size: $font-22px; - padding-left: 19px; - padding-right: 16px; - /* why isn't text-overflow working? */ - text-overflow: ellipsis; - border-bottom: 1px solid transparent; -} - -.mx_GroupView_header_shortDesc { - vertical-align: bottom; - float: left; - max-height: 42px; - color: $settings-grey-fg-color; - font-weight: 300; - font-size: $font-13px; - padding-left: 19px; - margin-right: 16px; - overflow: hidden; - text-overflow: ellipsis; - border-bottom: 1px solid transparent; -} - -.mx_GroupView_avatarPicker_label { - cursor: pointer; -} - -.mx_GroupView_cancelButton { - padding-left: 8px; -} - -.mx_GroupView_cancelButton img { - position: relative; - top: 5px; -} - -.mx_GroupView input[type='radio'] { - margin: 10px 10px 0px 10px; -} - -.mx_GroupView_label_text { - display: inline-block; - max-width: 80%; - vertical-align: 0.1em; - line-height: 2em; -} - -.mx_GroupView_body { - flex-grow: 1; - margin: 0 24px; -} - -.mx_GroupView_rooms { - flex-grow: 1; - display: flex; - flex-direction: column; - min-height: 200px; - user-select: none; -} - -.mx_GroupView h3 { - text-transform: uppercase; - color: $h3-color; - font-weight: 600; - font-size: $font-13px; - margin-bottom: 10px; -} - -.mx_GroupView_rooms_header .mx_AccessibleButton { - padding-left: 14px; - margin-bottom: 14px; - height: 24px; -} - -.mx_GroupView_group { - border-top: 1px solid $primary-hairline-color; -} - -.mx_GroupView_group_disabled { - opacity: 0.3; - pointer-events: none; -} - -.mx_GroupView_rooms_header_addRow_button { - display: inline-block; -} - -.mx_GroupView_rooms_header_addRow_button object { - pointer-events: none; -} - -.mx_GroupView_rooms_header_addRow_label { - display: inline-block; - vertical-align: top; - line-height: $font-24px; - padding-left: 28px; - color: $accent; -} - -.mx_GroupView_rooms .mx_RoomDetailList { - flex-grow: 1; - border-top: 1px solid $primary-hairline-color; - padding-top: 10px; - word-break: break-word; -} - -.mx_GroupView .mx_RoomView_messageListWrapper { - justify-content: flex-start; -} - -.mx_GroupView_membershipSection { - color: $info-plinth-fg-color; - margin-top: 10px; -} - -.mx_GroupView_membershipSubSection { - justify-content: space-between; - display: flex; - padding-bottom: 8px; -} - -.mx_GroupView_membershipSubSection .mx_Spinner { - justify-content: flex-end; -} - -.mx_GroupView_membershipSection_description { - /* To match textButton */ - line-height: $font-34px; -} - -.mx_GroupView_membershipSection_description .mx_BaseAvatar { - margin-right: 10px; -} - -.mx_GroupView_membershipSection .mx_GroupView_textButton { - margin-right: 0px; - margin-top: 0px; - margin-left: 8px; -} - -.mx_GroupView_memberSettings_toggle label { - cursor: pointer; - user-select: none; -} - -.mx_GroupView_memberSettings input { - margin-right: 6px; -} - -.mx_GroupView_featuredThings { - margin-top: 20px; -} - -.mx_GroupView_featuredThings_header { - font-weight: bold; - font-size: 120%; - margin-bottom: 20px; -} - -.mx_GroupView_featuredThings_category { - font-weight: bold; - font-size: 110%; - margin-top: 10px; -} - -.mx_GroupView_featuredThings_container { - display: flex; -} - -.mx_GroupView_featuredThings_addButton, -.mx_GroupView_featuredThing { - display: table-cell; - text-align: center; - - width: 100px; - margin: 0px 20px; -} - -.mx_GroupView_featuredThing { - position: relative; -} - -.mx_GroupView_featuredThing .mx_GroupView_featuredThing_deleteButton { - position: absolute; - top: -7px; - right: 11px; - opacity: 0.4; -} - -.mx_GroupView_featuredThing .mx_BaseAvatar { - /* To prevent misalignment with img (in addButton) */ - vertical-align: initial; -} - -.mx_GroupView_featuredThings_addButton object { - pointer-events: none; -} - -.mx_GroupView_featuredThing_name { - word-wrap: break-word; -} - -.mx_GroupView_uploadInput { - display: none; -} - -.mx_GroupView_body .mx_AutoHideScrollbar > * { - margin: 11px 50px 50px 68px; -} - -.mx_GroupView_groupDesc textarea { - width: 100%; - max-width: 100%; - height: 150px; -} - -.mx_GroupView_groupDesc_placeholder, -.mx_GroupView_changeDelayWarning { - background-color: $info-plinth-bg-color; - color: $info-plinth-fg-color; - border-radius: 10px; - text-align: center; - - margin: 20px 0px; -} - -.mx_GroupView_groupDesc_placeholder { - padding: 100px 20px; - cursor: pointer; -} - -.mx_GroupView_changeDelayWarning { - padding: 40px 20px; -} - -.mx_GroupView_spaceUpgradePrompt { - padding: 16px 50px; - background-color: $header-panel-bg-color; - border-radius: 8px; - max-width: 632px; - font-size: $font-15px; - line-height: $font-24px; - margin-top: 24px; - position: relative; - - > h2 { - font-size: inherit; - font-weight: $font-semi-bold; - } - - > p, h2 { - margin: 0; - } - - &::before { - content: ""; - position: absolute; - height: $font-24px; - width: 20px; - left: 18px; - mask-repeat: no-repeat; - mask-position: center; - mask-size: contain; - mask-image: url('$(res)/img/element-icons/room/room-summary.svg'); - background-color: $secondary-content; - } - - .mx_AccessibleButton_kind_link { - padding: 0; - } - - .mx_GroupView_spaceUpgradePrompt_close { - width: 16px; - height: 16px; - border-radius: 8px; - background-color: $input-darker-bg-color; - position: absolute; - top: 16px; - right: 16px; - - &::before { - content: ""; - position: absolute; - width: inherit; - height: inherit; - mask-repeat: no-repeat; - mask-position: center; - mask-size: 8px; - mask-image: url('$(res)/img/image-view/close.svg'); - background-color: $secondary-content; - } - } -} - -.mx_GroupView .mx_MemberInfo .mx_AutoHideScrollbar > :not(.mx_MemberInfo_avatar) { - padding-left: 16px; - padding-right: 16px; -} diff --git a/res/css/structures/_HomePage.scss b/res/css/structures/_HomePage.scss index 77da167099..b9d1834fd6 100644 --- a/res/css/structures/_HomePage.scss +++ b/res/css/structures/_HomePage.scss @@ -98,9 +98,6 @@ limitations under the License. &.mx_HomePage_button_explore::before { mask-image: url('$(res)/img/element-icons/roomlist/explore.svg'); } - &.mx_HomePage_button_createGroup::before { - mask-image: url('$(res)/img/element-icons/community-members.svg'); - } } } } diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index 4186beab25..18ef247b5f 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -53,9 +53,8 @@ $roomListCollapsedWidth: 68px; .mx_LeftPanel { background-color: $roomlist-bg-color; - // TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel - // Create a row-based flexbox for the GroupFilterPanel and the room list + // Create a row-based flexbox for the space panel and the room list display: flex; contain: content; position: relative; @@ -119,11 +118,6 @@ $roomListCollapsedWidth: 68px; display: flex; align-items: center; - .mx_UserMenu { - // mini-mode for when Space Panel is disabled - margin-right: 12px; - } - & + .mx_RoomListHeader { margin-top: 12px; } diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index d0ee7d92eb..0523e67761 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -62,7 +62,7 @@ limitations under the License. transform: translateX(-50%); } -/* not the left panel, and not the resize handle, so the roomview/groupview/... */ +/* not the left panel, and not the resize handle, so the roomview and friends */ .mx_MatrixChat > :not(.mx_LeftPanel):not(.mx_SpacePanel):not(.mx_ResizeHandle):not(.mx_LeftPanel_outerWrapper) { background-color: $background; diff --git a/res/css/structures/_MyGroups.scss b/res/css/structures/_MyGroups.scss deleted file mode 100644 index 9c0062b72d..0000000000 --- a/res/css/structures/_MyGroups.scss +++ /dev/null @@ -1,172 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd - -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_MyGroups { - display: flex; - flex-direction: column; - - .mx_BetaCard { - margin: 0 72px; - max-width: 760px; - } -} - -.mx_MyGroups .mx_RoomHeader_simpleHeader { - margin-left: 0px; -} - -.mx_MyGroups_header { - /* Keep mid-point of create button aligned with icon in page header */ - margin-left: 2px; - display: flex; - flex-wrap: wrap; -} - -.mx_MyGroups > :not(.mx_RoomHeader):not(.mx_BetaCard) { - max-width: 960px; - margin: 40px; -} - -.mx_MyGroups_headerCard { - flex: 1 0 50%; - margin-bottom: 30px; - min-width: 400px; - display: flex; - align-items: center; -} - -.mx_MyGroups_headerCard .mx_MyGroups_headerCard_button { - flex: 0 0 auto; - margin-right: 13px; - height: 40px; - width: 40px; - border-radius: 20px; - background-color: $roomheader-addroom-bg-color; - position: relative; - - &::before { - background-color: $roomheader-addroom-fg-color; - mask: url('$(res)/img/icons-create-room.svg'); - mask-repeat: no-repeat; - mask-position: center; - mask-size: 80%; - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - } -} - -.mx_MyGroups_headerCard_header { - font-weight: bold; - margin-bottom: 10px; -} - -.mx_MyGroups_headerCard_content { - padding-right: 15px; -} - -/* Until the button is wired up */ -.mx_MyGroups_joinBox { - visibility: hidden; - - /* When joinBox wraps onto its own row, it should take up zero height so - that there isn't an awkward gap between MyGroups_createBox and - MyGroups_content. - */ - height: 0px; - margin: 0px; -} - -.mx_MyGroups_content { - margin-left: 2px; - - flex: 1 0 0; - - display: flex; - flex-direction: column; - overflow-y: auto; -} - -.mx_MyGroups_scrollable { - overflow-y: inherit; -} - -.mx_MyGroups_placeholder { - background-color: $info-plinth-bg-color; - color: $info-plinth-fg-color; - line-height: $font-400px; - border-radius: 10px; - text-align: center; -} - -.mx_MyGroups_joinedGroups { - border-top: 1px solid $primary-hairline-color; - overflow-x: hidden; - - display: flex; - flex-flow: row wrap; - align-content: flex-start; -} - -.mx_MyGroups_joinedGroups .mx_GroupTile { - min-width: 300px; - max-width: 33%; - flex: 1 0 300px; - height: 75px; - margin: 10px 0px; - display: flex; - align-items: flex-start; - cursor: pointer; -} - -.mx_GroupTile_avatar { - cursor: grab, -webkit-grab; -} - -.mx_GroupTile_profile { - margin-left: 10px; - display: flex; - flex-direction: column; - justify-content: center; -} - -.mx_GroupTile_profile .mx_GroupTile_name, -.mx_GroupTile_profile .mx_GroupTile_groupId, -.mx_GroupTile_profile .mx_GroupTile_desc { - padding-right: 10px; -} - -.mx_GroupTile_profile .mx_GroupTile_name { - margin: 0px; - font-size: $font-15px; -} - -.mx_GroupTile_profile .mx_GroupTile_groupId { - font-size: $font-13px; - opacity: 0.7; -} - -.mx_GroupTile_profile .mx_GroupTile_desc { - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - font-size: $font-13px; - max-height: 36px; - overflow: hidden; -} diff --git a/res/css/structures/_RightPanel.scss b/res/css/structures/_RightPanel.scss index 5fb57d1999..916f14b4e8 100644 --- a/res/css/structures/_RightPanel.scss +++ b/res/css/structures/_RightPanel.scss @@ -93,16 +93,6 @@ limitations under the License. mask-position: center; } -.mx_RightPanel_groupMembersButton::before { - mask-image: url('$(res)/img/element-icons/community-members.svg'); - mask-position: center; -} - -.mx_RightPanel_roomsButton::before { - mask-image: url('$(res)/img/element-icons/community-rooms.svg'); - mask-position: center; -} - $dot-size: 7px; $pulse-color: $alert; @@ -234,7 +224,6 @@ $pulse-color: $alert; .mx_RightPanel .mx_MemberList, .mx_RightPanel .mx_MemberInfo, -.mx_RightPanel .mx_GroupRoomList, .mx_RightPanel_blank { order: 2; flex: 1 1 0; diff --git a/res/css/structures/_SpaceHierarchy.scss b/res/css/structures/_SpaceHierarchy.scss index 71368e4016..cdcd0164de 100644 --- a/res/css/structures/_SpaceHierarchy.scss +++ b/res/css/structures/_SpaceHierarchy.scss @@ -258,7 +258,7 @@ limitations under the License. } &:hover, &:focus-within { - background-color: $groupFilterPanel-bg-color; + background-color: $spacePanel-bg-color; .mx_AccessibleButton { visibility: visible; @@ -280,7 +280,7 @@ limitations under the License. &::before { content: ""; position: absolute; - background-color: $groupFilterPanel-bg-color; + background-color: $spacePanel-bg-color; width: 1px; height: 100%; left: 6px; diff --git a/res/css/structures/_SpacePanel.scss b/res/css/structures/_SpacePanel.scss index d999ff89b8..74d30bf59a 100644 --- a/res/css/structures/_SpacePanel.scss +++ b/res/css/structures/_SpacePanel.scss @@ -23,7 +23,7 @@ $activeBackgroundColor: $panel-actions; $activeBorderColor: $primary-content; .mx_SpacePanel { - background-color: $groupFilterPanel-bg-color; + background-color: $spacePanel-bg-color; flex: 0 0 auto; padding: 0; margin: 0; @@ -309,13 +309,13 @@ $activeBorderColor: $primary-content; .mx_NotificationBadge_dot { // make the smaller dot occupy the same width for centering margin: 0 -1px 0 0; - border: 3px solid $groupFilterPanel-bg-color; + border: 3px solid $spacePanel-bg-color; } .mx_NotificationBadge_2char, .mx_NotificationBadge_3char { margin: -5px -5px 0 0; - border: 2px solid $groupFilterPanel-bg-color; + border: 2px solid $spacePanel-bg-color; } } diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss index b0166fa152..d695bb7557 100644 --- a/res/css/structures/_SpaceRoomView.scss +++ b/res/css/structures/_SpaceRoomView.scss @@ -184,18 +184,6 @@ $SpaceRoomViewInnerWidth: 428px; } } - .mx_SpaceRoomView_preview_migratedCommunity { - margin-bottom: 16px; - padding: 8px 12px; - border-radius: 8px; - border: 1px solid $input-border-color; - width: max-content; - - .mx_BaseAvatar { - margin-right: 4px; - } - } - .mx_SpaceRoomView_preview_inviter { display: flex; align-items: center; diff --git a/res/css/views/context_menus/_TagTileContextMenu.scss b/res/css/views/context_menus/_TagTileContextMenu.scss deleted file mode 100644 index 14f5ec817e..0000000000 --- a/res/css/views/context_menus/_TagTileContextMenu.scss +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright 2018 New Vector Ltd - -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_TagTileContextMenu_item { - padding: 8px; - padding-right: 20px; - cursor: pointer; - white-space: nowrap; - display: flex; - align-items: center; - line-height: $font-16px; -} - -.mx_TagTileContextMenu_item::before { - content: ''; - height: 15px; - width: 15px; - background-color: currentColor; - mask-repeat: no-repeat; - mask-size: contain; - margin-right: 8px; -} - -.mx_TagTileContextMenu_viewCommunity::before { - mask-image: url('$(res)/img/element-icons/view-community.svg'); -} - -.mx_TagTileContextMenu_moveUp::before { - transform: rotate(180deg); - mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); -} - -.mx_TagTileContextMenu_moveDown::before { - mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); -} - -.mx_TagTileContextMenu_hideCommunity::before { - mask-image: url('$(res)/img/element-icons/hide.svg'); -} - -.mx_TagTileContextMenu_createSpace::before { - mask-image: url('$(res)/img/element-icons/message/fwd.svg'); -} - -.mx_TagTileContextMenu_separator { - margin-top: 0; - margin-bottom: 0; - border-bottom-style: none; - border-left-style: none; - border-right-style: none; - border-top-style: solid; - border-top-width: 1px; - border-color: $menu-border-color; -} diff --git a/res/css/views/dialogs/_AddressPickerDialog.scss b/res/css/views/dialogs/_AddressPickerDialog.scss deleted file mode 100644 index 44e9f94c5f..0000000000 --- a/res/css/views/dialogs/_AddressPickerDialog.scss +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2016 OpenMarket Ltd -Copyright 2019 New Vector Ltd -Copyright 2019 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_AddressPickerDialog { - a:link, - a:hover, - a:visited { - @mixin mx_Dialog_link; - } -} - -/* Using a textarea for this element, to circumvent autofill */ -.mx_AddressPickerDialog_input, -.mx_AddressPickerDialog_input:focus { - height: 26px; - font-size: $font-14px; - padding-left: 12px; - padding-right: 12px; - margin: 0 !important; - border: 0 !important; - outline: 0 !important; - width: 1000%; /* Pretend that this is an "input type=text" */ - resize: none; - overflow: hidden; - vertical-align: middle; - box-sizing: border-box; - word-wrap: nowrap; -} - -.mx_AddressPickerDialog .mx_Dialog_content { - min-height: 50px; -} - -.mx_AddressPickerDialog_inputContainer { - border-radius: 3px; - border: solid 1px $input-border-color; - line-height: $font-36px; - padding-left: 4px; - padding-right: 4px; - padding-top: 1px; - padding-bottom: 1px; - max-height: 150px; - overflow-x: hidden; - overflow-y: auto; -} - -.mx_AddressPickerDialog_error { - margin-top: 10px; - color: $alert; -} - -.mx_AddressPickerDialog_cancel { - position: absolute; - right: 11px; - top: 13px; - cursor: pointer; -} - -.mx_AddressPickerDialog_cancel object { - pointer-events: none; -} - -.mx_AddressPickerDialog_identityServer { - margin-top: 1em; -} diff --git a/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss b/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss deleted file mode 100644 index 5d6c817b14..0000000000 --- a/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2020 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_CommunityPrototypeInviteDialog { - &.mx_Dialog_fixedWidth { - width: 360px; - } - - .mx_Dialog_content { - margin-bottom: 0; - - .mx_CommunityPrototypeInviteDialog_people { - position: relative; - margin-bottom: 4px; - - .mx_AccessibleButton { - display: inline-block; - background-color: $focus-bg-color; // XXX: Abuse of variables - border-radius: 4px; - padding: 3px 5px; - font-size: $font-12px; - float: right; - } - } - - .mx_CommunityPrototypeInviteDialog_morePeople { - margin-top: 8px; - } - - .mx_CommunityPrototypeInviteDialog_person { - position: relative; - margin-top: 4px; - - & > * { - vertical-align: middle; - } - - .mx_Checkbox { - position: absolute; - right: 0; - top: calc(50% - 8px); // checkbox is 16px high - width: 16px; // to force a square - } - - .mx_CommunityPrototypeInviteDialog_personIdentifiers { - display: inline-block; - - & > * { - display: block; - } - - .mx_CommunityPrototypeInviteDialog_personName { - font-weight: 600; - font-size: $font-14px; - color: $primary-content; - margin-left: 7px; - } - - .mx_CommunityPrototypeInviteDialog_personId { - font-size: $font-12px; - color: $muted-fg-color; - margin-left: 7px; - } - } - } - - .mx_CommunityPrototypeInviteDialog_primaryButton { - display: block; - font-size: $font-13px; - line-height: 20px; - height: 20px; - margin-top: 24px; - } - } -} diff --git a/res/css/views/dialogs/_CreateCommunityPrototypeDialog.scss b/res/css/views/dialogs/_CreateCommunityPrototypeDialog.scss deleted file mode 100644 index a2378115a8..0000000000 --- a/res/css/views/dialogs/_CreateCommunityPrototypeDialog.scss +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright 2020 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_CreateCommunityPrototypeDialog { - .mx_Dialog_content { - display: flex; - flex-direction: row; - margin-bottom: 12px; - - .mx_CreateCommunityPrototypeDialog_colName { - flex-basis: 66.66%; - padding-right: 100px; - - .mx_Field input { - font-size: $font-16px; - line-height: $font-20px; - } - - .mx_CreateCommunityPrototypeDialog_subtext { - display: block; - color: $muted-fg-color; - margin-bottom: 16px; - - &:last-child { - margin-top: 16px; - } - - &.mx_CreateCommunityPrototypeDialog_subtext_error { - color: $alert; - } - } - - .mx_CreateCommunityPrototypeDialog_communityId { - position: relative; - - .mx_InfoTooltip { - float: right; - } - } - - .mx_AccessibleButton { - display: block; - height: 32px; - font-size: $font-16px; - line-height: 32px; - } - } - - .mx_CreateCommunityPrototypeDialog_colAvatar { - flex-basis: 33.33%; - - .mx_CreateCommunityPrototypeDialog_avatarContainer { - margin-top: 12px; - margin-bottom: 20px; - - .mx_CreateCommunityPrototypeDialog_avatar, - .mx_CreateCommunityPrototypeDialog_placeholderAvatar { - width: 96px; - height: 96px; - border-radius: 96px; - } - - .mx_CreateCommunityPrototypeDialog_placeholderAvatar { - background-color: #368bd6; // hardcoded for both themes - - &::before { - display: inline-block; - background-color: #fff; // hardcoded because the background is - mask-repeat: no-repeat; - mask-size: 96px; - width: 96px; - height: 96px; - mask-position: center; - content: ''; - vertical-align: middle; - mask-image: url('$(res)/img/element-icons/add-photo.svg'); - } - } - } - - .mx_CreateCommunityPrototypeDialog_tip { - & > b, & > span { - display: block; - color: $muted-fg-color; - } - } - } - } -} diff --git a/res/css/views/dialogs/_CreateGroupDialog.scss b/res/css/views/dialogs/_CreateGroupDialog.scss deleted file mode 100644 index ef9c2b73d4..0000000000 --- a/res/css/views/dialogs/_CreateGroupDialog.scss +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd - -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_CreateGroupDialog_inputRow { - margin-top: 10px; - margin-bottom: 10px; -} - -.mx_CreateGroupDialog_label { - text-align: left; - padding-bottom: 12px; -} - -.mx_CreateGroupDialog_input { - font-size: $font-15px; - border-radius: 3px; - border: 1px solid $input-border-color; - padding: 9px; - color: $primary-content; - background-color: $background; -} - -.mx_CreateGroupDialog_input_hasPrefixAndSuffix { - border-radius: 0px; -} - -.mx_CreateGroupDialog_input_group { - display: flex; -} - -.mx_CreateGroupDialog_prefix, -.mx_CreateGroupDialog_suffix { - padding: 0px 5px; - line-height: $font-37px; - background-color: $input-darker-bg-color; - border: 1px solid $input-border-color; - text-align: center; -} - -.mx_CreateGroupDialog_prefix { - border-right: 0px; - border-radius: 3px 0px 0px 3px; -} - -.mx_CreateGroupDialog_suffix { - border-left: 0px; - border-radius: 0px 3px 3px 0px; -} diff --git a/res/css/views/dialogs/_CreateSpaceFromCommunityDialog.scss b/res/css/views/dialogs/_CreateSpaceFromCommunityDialog.scss deleted file mode 100644 index 72c2d13ae3..0000000000 --- a/res/css/views/dialogs/_CreateSpaceFromCommunityDialog.scss +++ /dev/null @@ -1,188 +0,0 @@ -/* -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_CreateSpaceFromCommunityDialog_wrapper { - .mx_Dialog { - display: flex; - flex-direction: column; - } -} - -.mx_CreateSpaceFromCommunityDialog { - width: 480px; - color: $primary-content; - display: flex; - flex-direction: column; - flex-wrap: nowrap; - min-height: 0; - - .mx_CreateSpaceFromCommunityDialog_content { - > p { - font-size: $font-15px; - line-height: $font-24px; - - &:first-of-type { - margin-top: 0; - } - - &.mx_CreateSpaceFromCommunityDialog_flairNotice { - font-size: $font-12px; - line-height: $font-15px; - } - } - - .mx_SpaceBasicSettings { - > p { - font-size: $font-12px; - line-height: $font-15px; - margin: 16px 0; - } - - .mx_Field_textarea { - margin-bottom: 0; - } - } - - .mx_JoinRuleDropdown .mx_Dropdown_menu { - width: auto !important; // override fixed width - } - - .mx_CreateSpaceFromCommunityDialog_nonPublicSpacer { - height: 63px; // balance the height of the missing room alias field to prevent modal bouncing - } - } - - .mx_CreateSpaceFromCommunityDialog_footer { - display: flex; - margin-top: 20px; - - > span { - flex-grow: 1; - font-size: $font-12px; - line-height: $font-15px; - color: $secondary-content; - margin-top: -13px; // match height of buttons to prevent height changing - - .mx_ProgressBar { - height: 8px; - width: 100%; - - @mixin ProgressBarBorderRadius 8px; - } - - .mx_CreateSpaceFromCommunityDialog_progressText { - margin-top: 8px; - font-size: $font-15px; - line-height: $font-24px; - color: $primary-content; - } - - > * { - vertical-align: middle; - } - } - - .mx_CreateSpaceFromCommunityDialog_error { - padding-left: 12px; - - > img { - align-self: center; - } - - .mx_CreateSpaceFromCommunityDialog_errorHeading { - font-weight: $font-semi-bold; - font-size: $font-15px; - line-height: $font-18px; - color: $alert; - } - - .mx_CreateSpaceFromCommunityDialog_errorCaption { - margin-top: 4px; - font-size: $font-12px; - line-height: $font-15px; - color: $primary-content; - } - } - - .mx_AccessibleButton { - display: inline-block; - align-self: center; - } - - .mx_AccessibleButton_kind_primary { - padding: 8px 36px; - margin-left: 24px; - } - - .mx_AccessibleButton_kind_primary_outline { - margin-left: auto; - } - - .mx_CreateSpaceFromCommunityDialog_retryButton { - margin-left: 12px; - padding-left: 24px; - position: relative; - - &::before { - content: ''; - position: absolute; - background-color: $primary-content; - mask-repeat: no-repeat; - mask-position: center; - mask-size: contain; - mask-image: url('$(res)/img/element-icons/retry.svg'); - width: 18px; - height: 18px; - left: 0; - } - } - - .mx_AccessibleButton_kind_link { - padding: 0; - } - } -} - -.mx_CreateSpaceFromCommunityDialog_SuccessInfoDialog { - .mx_InfoDialog { - max-width: 500px; - } - - .mx_AccessibleButton_kind_link { - padding: 0; - } - - .mx_CreateSpaceFromCommunityDialog_SuccessInfoDialog_checkmark { - position: relative; - border-radius: 50%; - border: 3px solid $accent; - width: 68px; - height: 68px; - margin: 12px auto 32px; - - &::before { - width: inherit; - height: inherit; - content: ''; - position: absolute; - background-color: $accent; - mask-repeat: no-repeat; - mask-position: center; - mask-image: url('$(res)/img/element-icons/roomlist/checkmark.svg'); - mask-size: 48px; - } - } -} diff --git a/res/css/views/dialogs/_EditCommunityPrototypeDialog.scss b/res/css/views/dialogs/_EditCommunityPrototypeDialog.scss deleted file mode 100644 index 75a56bf6b3..0000000000 --- a/res/css/views/dialogs/_EditCommunityPrototypeDialog.scss +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2020 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. -*/ - -// XXX: many of these styles are shared with the create dialog -.mx_EditCommunityPrototypeDialog { - &.mx_Dialog_fixedWidth { - width: 360px; - } - - .mx_Dialog_content { - margin-bottom: 12px; - - .mx_AccessibleButton.mx_AccessibleButton_kind_primary { - display: block; - height: 32px; - font-size: $font-16px; - line-height: 32px; - } - - .mx_EditCommunityPrototypeDialog_rowAvatar { - display: flex; - flex-direction: row; - align-items: center; - } - - .mx_EditCommunityPrototypeDialog_avatarContainer { - margin-top: 20px; - margin-bottom: 20px; - - .mx_EditCommunityPrototypeDialog_avatar, - .mx_EditCommunityPrototypeDialog_placeholderAvatar { - width: 96px; - height: 96px; - border-radius: 96px; - } - - .mx_EditCommunityPrototypeDialog_placeholderAvatar { - background-color: #368bd6; // hardcoded for both themes - - &::before { - display: inline-block; - background-color: #fff; // hardcoded because the background is - mask-repeat: no-repeat; - mask-size: 96px; - width: 96px; - height: 96px; - mask-position: center; - content: ''; - vertical-align: middle; - mask-image: url('$(res)/img/element-icons/add-photo.svg'); - } - } - } - - .mx_EditCommunityPrototypeDialog_tip { - margin-left: 20px; - - & > b, & > span { - display: block; - color: $muted-fg-color; - } - } - } -} diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 205aaaa202..ad7bf9a816 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -93,7 +93,7 @@ limitations under the License. border-radius: 8px; &:hover { - background-color: $groupFilterPanel-bg-color; + background-color: $spacePanel-bg-color; } .mx_ForwardList_roomButton { diff --git a/res/css/views/dialogs/_GroupAddressPicker.scss b/res/css/views/dialogs/_GroupAddressPicker.scss deleted file mode 100644 index 5fa18931f0..0000000000 --- a/res/css/views/dialogs/_GroupAddressPicker.scss +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2017 New Vector Ltd - -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_GroupAddressPicker_checkboxContainer { - margin-top: 10px; - display: flex; -} diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss index 7ed3f59de1..af64862992 100644 --- a/res/css/views/dialogs/_InviteDialog.scss +++ b/res/css/views/dialogs/_InviteDialog.scss @@ -43,7 +43,7 @@ limitations under the License. min-width: max-content; // prevent manipulation by flexbox } - // Mostly copied from AddressPickerDialog; overrides bunch of our default text input styles + // overrides bunch of our default text input styles > input[type="text"] { margin: 6px 0 !important; height: 24px; @@ -96,13 +96,6 @@ limitations under the License. > span { color: $primary-content; } - - .mx_InviteDialog_subname { - margin-bottom: 10px; - margin-top: -10px; // HACK: Positioning with margins is bad - font-size: $font-12px; - color: $muted-fg-color; - } } .mx_InviteDialog_section_hidden_suggestions_disclaimer { @@ -447,3 +440,7 @@ limitations under the License. } } } + +.mx_InviteDialog_identityServer { + margin-top: 1em; +} diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss index b013b4998a..79cacb5c50 100644 --- a/res/css/views/dialogs/_UserSettingsDialog.scss +++ b/res/css/views/dialogs/_UserSettingsDialog.scss @@ -60,7 +60,3 @@ limitations under the License. .mx_UserSettingsDialog_mjolnirIcon::before { mask-image: url('$(res)/img/element-icons/room/composer/emoji.svg'); } - -.mx_UserSettingsDialog_flairIcon::before { - mask-image: url('$(res)/img/element-icons/settings/flair.svg'); -} diff --git a/res/css/views/elements/_FacePile.scss b/res/css/views/elements/_FacePile.scss index 68a2f72b11..fcde5eab83 100644 --- a/res/css/views/elements/_FacePile.scss +++ b/res/css/views/elements/_FacePile.scss @@ -37,7 +37,7 @@ limitations under the License. border-radius: 100%; width: 30px; height: 30px; - background-color: $groupFilterPanel-bg-color; + background-color: $spacePanel-bg-color; &::before { content: ""; diff --git a/res/css/views/elements/_RichText.scss b/res/css/views/elements/_RichText.scss index 852097762e..221fc54a05 100644 --- a/res/css/views/elements/_RichText.scss +++ b/res/css/views/elements/_RichText.scss @@ -4,7 +4,6 @@ .mx_UserPill, .mx_RoomPill, -.mx_GroupPill, .mx_AtRoomPill { display: inline-flex; align-items: center; @@ -28,13 +27,6 @@ a.mx_Pill { line-height: $font-17px; } -/* More specific to override `.markdown-body a` color */ -.mx_EventTile_content .markdown-body a.mx_GroupPill, -.mx_GroupPill { - color: $accent-fg-color; - background-color: $rte-room-pill-color; -} - /* More specific to override `.markdown-body a` text-decoration */ .mx_EventTile_content .markdown-body a.mx_Pill { text-decoration: none; @@ -62,22 +54,18 @@ a.mx_Pill { /* More specific to override `.markdown-body a` color */ .mx_EventTile_content .markdown-body a.mx_RoomPill, -.mx_EventTile_content .markdown-body a.mx_GroupPill, -.mx_RoomPill, -.mx_GroupPill { +.mx_RoomPill { color: $accent-fg-color; background-color: $rte-room-pill-color; } .mx_EventTile_body .mx_UserPill, -.mx_EventTile_body .mx_RoomPill, -.mx_EventTile_body .mx_GroupPill { +.mx_EventTile_body .mx_RoomPill { cursor: pointer; } .mx_UserPill .mx_BaseAvatar, .mx_RoomPill .mx_BaseAvatar, -.mx_GroupPill .mx_BaseAvatar, .mx_AtRoomPill .mx_BaseAvatar { position: relative; display: inline-flex; diff --git a/res/css/views/groups/_GroupPublicityToggle.scss b/res/css/views/groups/_GroupPublicityToggle.scss deleted file mode 100644 index b8be2711ca..0000000000 --- a/res/css/views/groups/_GroupPublicityToggle.scss +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2017 New Vector Ltd - -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_GroupPublicity_toggle { - display: flex; - align-items: center; - margin: 8px; -} - -.mx_GroupPublicity_toggle .mx_GroupTile { - display: flex; - align-items: flex-start; - cursor: pointer; - box-sizing: border-box; - width: 100%; -} - -.mx_GroupPublicity_toggle .mx_ToggleSwitch { - float: right; -} diff --git a/res/css/views/groups/_GroupRoomList.scss b/res/css/views/groups/_GroupRoomList.scss deleted file mode 100644 index 2f6559f7c4..0000000000 --- a/res/css/views/groups/_GroupRoomList.scss +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 2017 New Vector Ltd - -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_GroupRoomTile { - position: relative; - color: $primary-content; - cursor: pointer; - display: flex; - align-items: center; -} - -.mx_GroupRoomList_wrapper { - padding: 10px; -} diff --git a/res/css/views/groups/_GroupUserSettings.scss b/res/css/views/groups/_GroupUserSettings.scss deleted file mode 100644 index b207aa2958..0000000000 --- a/res/css/views/groups/_GroupUserSettings.scss +++ /dev/null @@ -1,22 +0,0 @@ -/* -Copyright 2017 New Vector Ltd - -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_GroupUserSettings_groupPublicity_scrollbox { - height: 200px; - border: 1px solid $primary-hairline-color; - border-radius: 3px; - overflow: hidden; -} diff --git a/res/css/views/rooms/_EntityTile.scss b/res/css/views/rooms/_EntityTile.scss index 10c8799413..b8d71a4cc0 100644 --- a/res/css/views/rooms/_EntityTile.scss +++ b/res/css/views/rooms/_EntityTile.scss @@ -61,8 +61,7 @@ limitations under the License. width: 26px; } -.mx_EntityTile_avatar, -.mx_GroupRoomTile_avatar { +.mx_EntityTile_avatar { padding-left: 3px; padding-right: 12px; padding-top: 4px; @@ -70,8 +69,7 @@ limitations under the License. position: relative; } -.mx_EntityTile_name, -.mx_GroupRoomTile_name { +.mx_EntityTile_name { flex: 1 1 0; overflow: hidden; font-size: $font-14px; diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 89ad3b40a0..3282ac455b 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -126,21 +126,6 @@ $left-gutter: 64px; max-width: calc(100% - $left-gutter); } - .mx_DisambiguatedProfile .mx_Flair { - opacity: 0.7; - margin-left: 5px; - display: inline-block; - vertical-align: top; - overflow: hidden; - user-select: none; - - img { - vertical-align: -2px; - margin-right: 2px; - border-radius: 8px; - } - } - .mx_DisambiguatedProfile { color: $primary-content; font-size: $font-14px; diff --git a/res/css/views/rooms/_IRCLayout.scss b/res/css/views/rooms/_IRCLayout.scss index 1189bbd05b..b0401a447c 100644 --- a/res/css/views/rooms/_IRCLayout.scss +++ b/res/css/views/rooms/_IRCLayout.scss @@ -252,10 +252,4 @@ $irc-line-height: $font-18px; cursor: col-resize; z-index: 100; } - - // Need to use important to override the js provided height and width values. - .mx_Flair > img { - height: $font-14px !important; - width: $font-14px !important; - } } diff --git a/res/css/views/rooms/_MemberInfo.scss b/res/css/views/rooms/_MemberInfo.scss index 1e7a777d54..c29bb28689 100644 --- a/res/css/views/rooms/_MemberInfo.scss +++ b/res/css/views/rooms/_MemberInfo.scss @@ -71,7 +71,7 @@ limitations under the License. } .mx_MemberInfo_avatar { - background: $groupFilterPanel-bg-color; + background: $spacePanel-bg-color; margin-bottom: 16px; } diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss index b84beea89b..41f394ff84 100644 --- a/res/css/views/rooms/_MemberList.scss +++ b/res/css/views/rooms/_MemberList.scss @@ -14,9 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_MemberList, -.mx_GroupMemberList, -.mx_GroupRoomList { +.mx_MemberList { flex: 1; display: flex; flex-direction: column; @@ -52,11 +50,6 @@ limitations under the License. } } -.mx_GroupMemberList_query, -.mx_GroupRoomList_query { - flex: 0 0 auto; -} - .mx_MemberList_chevron { position: absolute; right: 35px; @@ -117,11 +110,3 @@ limitations under the License. margin-right: 5px; } } - -.mx_MemberList_inviteCommunity span::before { - mask-image: url('$(res)/img/icon-invite-people.svg'); -} - -.mx_MemberList_addRoomToCommunity span::before { - mask-image: url('$(res)/img/icons-room-add.svg'); -} diff --git a/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss index b5791560c7..58a2f0b1f1 100644 --- a/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss @@ -38,25 +38,4 @@ limitations under the License. font-size: inherit; } } - - .mx_PreferencesUserSettingsTab_CommunityMigrator { - margin-right: 200px; - - > div { - font-weight: $font-semi-bold; - font-size: $font-15px; - line-height: $font-18px; - color: $primary-content; - margin: 16px 0; - - .mx_BaseAvatar { - margin-right: 12px; - vertical-align: middle; - } - - .mx_AccessibleButton { - float: right; - } - } - } } diff --git a/res/img/element-icons/settings/flair.svg b/res/img/element-icons/settings/flair.svg deleted file mode 100644 index e1ae44f386..0000000000 --- a/res/img/element-icons/settings/flair.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/icons-groups.svg b/res/img/icons-groups.svg deleted file mode 100644 index 8f89ba83c4..0000000000 --- a/res/img/icons-groups.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index ae881f2357..37e3be485c 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -45,7 +45,7 @@ $info-plinth-bg-color: $header-panel-bg-color; $event-selected-color: $system; $topleftmenu-color: $primary-content; $roomtopic-color: $text-secondary-color; -$groupFilterPanel-bg-color: rgba(38, 39, 43, 0.82); +$spacePanel-bg-color: rgba(38, 39, 43, 0.82); $panel-gradient: rgba(34, 38, 46, 0), rgba(34, 38, 46, 1); $h3-color: $primary-content; $event-highlight-bg-color: #25271F; @@ -54,7 +54,7 @@ $header-panel-text-primary-color: $text-secondary-color; // Tooltip // ******************** -$tooltip-timeline-bg-color: $groupFilterPanel-bg-color; +$tooltip-timeline-bg-color: $spacePanel-bg-color; $tooltip-timeline-fg-color: $primary-content; // ******************** diff --git a/res/themes/legacy-dark/css/_legacy-dark.scss b/res/themes/legacy-dark/css/_legacy-dark.scss index e14b6985ad..887139e867 100644 --- a/res/themes/legacy-dark/css/_legacy-dark.scss +++ b/res/themes/legacy-dark/css/_legacy-dark.scss @@ -33,8 +33,8 @@ $rte-room-pill-color: $room-highlight-color; $info-plinth-bg-color: $header-panel-bg-color; $info-plinth-fg-color: #888; -$groupFilterPanel-bg-color: $base-color; -$inverted-bg-color: $groupFilterPanel-bg-color; +$spacePanel-bg-color: $base-color; +$inverted-bg-color: $spacePanel-bg-color; // used by AddressSelector $selected-color: $room-highlight-color; @@ -120,7 +120,7 @@ $roomlist-bg-color: $header-panel-bg-color; $roomsublist-skeleton-ui-bg: linear-gradient(180deg, #3e444c 0%, #3e444c00 100%); -$groupFilterPanel-divider-color: $tertiary-content; +$spacePanel-divider-color: $tertiary-content; $roomtile-default-badge-bg-color: #61708b; $roomtile-selected-bg-color: #1A1D23; @@ -166,7 +166,7 @@ $reaction-row-button-selected-bg-color: #1f6954; $kbd-border-color: #000000; -$tooltip-timeline-bg-color: $groupFilterPanel-bg-color; +$tooltip-timeline-bg-color: $spacePanel-bg-color; $tooltip-timeline-fg-color: #ffffff; $breadcrumb-placeholder-bg-color: #272c35; diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss index fc9aeddff6..311e2ab4db 100644 --- a/res/themes/legacy-light/css/_legacy-light.scss +++ b/res/themes/legacy-light/css/_legacy-light.scss @@ -46,8 +46,8 @@ $info-plinth-fg-color: #888; // left-panel style muted accent color $secondary-accent-color: #f2f5f8; -$groupFilterPanel-bg-color: #27303a; -$inverted-bg-color: $groupFilterPanel-bg-color; +$spacePanel-bg-color: #27303a; +$inverted-bg-color: $spacePanel-bg-color; // used by RoomDropTarget $droptarget-bg-color: rgba(255, 255, 255, 0.5); @@ -255,7 +255,7 @@ $reaction-row-button-selected-bg-color: #e9fff9; $kbd-border-color: $message-action-bar-border-color; -$tooltip-timeline-bg-color: $groupFilterPanel-bg-color; +$tooltip-timeline-bg-color: $spacePanel-bg-color; $tooltip-timeline-fg-color: #ffffff; $breadcrumb-placeholder-bg-color: #e8eef5; @@ -282,7 +282,7 @@ $eventbubble-reply-color: #C1C6CD; // pinned events indicator $pinned-color: $tertiary-content; -$groupFilterPanel-divider-color: $tertiary-content; +$spacePanel-divider-color: $tertiary-content; // Location sharing // ******************** diff --git a/res/themes/light-custom/css/_custom.scss b/res/themes/light-custom/css/_custom.scss index 81b7fa62b8..88f29f89cd 100644 --- a/res/themes/light-custom/css/_custom.scss +++ b/res/themes/light-custom/css/_custom.scss @@ -55,7 +55,7 @@ $roomheader-bg-color: var(--timeline-background-color); $panel-actions: var(--roomlist-highlights-color); // // --sidebar-color -$groupFilterPanel-bg-color: var(--sidebar-color); +$spacePanel-bg-color: var(--sidebar-color); $tooltip-timeline-bg-color: var(--sidebar-color); $dialog-backdrop-color: var(--sidebar-color-50pct); // diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 7019ef2c56..6ba458301b 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -78,7 +78,7 @@ $info-plinth-bg-color: #f7f7f7; $event-selected-color: #f6f7f8; $topleftmenu-color: #212121; $roomtopic-color: #9e9e9e; -$groupFilterPanel-bg-color: rgba(232, 232, 232, 0.77); +$spacePanel-bg-color: rgba(232, 232, 232, 0.77); $panel-gradient: rgba(242, 245, 248, 0), rgba(242, 245, 248, 1); $h3-color: #3d3b39; $event-highlight-bg-color: $yellow-background; diff --git a/src/@types/groups.ts b/src/@types/groups.ts deleted file mode 100644 index d3a7455e2f..0000000000 --- a/src/@types/groups.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* -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. -*/ - -export const CreateEventField = "io.element.migrated_from_community"; - -export interface IGroupRoom { - displayname: string; - name?: string; - roomId: string; - canonicalAlias?: string; - avatarUrl?: string; - topic?: string; - numJoinedMembers?: number; - worldReadable?: boolean; - guestCanJoin?: boolean; - isPublic?: boolean; -} - -/* eslint-disable camelcase */ -export interface IGroupSummary { - profile: { - avatar_url?: string; - is_openly_joinable?: boolean; - is_public?: boolean; - long_description: string; - name: string; - short_description: string; - }; - rooms_section: { - rooms: unknown[]; - categories: Record; - total_room_count_estimate: number; - }; - user: { - is_privileged: boolean; - is_public: boolean; - is_publicised: boolean; - membership: string; - }; - users_section: { - users: unknown[]; - roles: Record; - total_user_count_estimate: number; - }; -} -/* eslint-enable camelcase */ diff --git a/src/Analytics.tsx b/src/Analytics.tsx index af85bf9755..23b278929a 100644 --- a/src/Analytics.tsx +++ b/src/Analytics.tsx @@ -27,6 +27,7 @@ import * as sdk from './index'; import { SnakedObject } from "./utils/SnakedObject"; import { IConfigOptions } from "./IConfigOptions"; +// Note: we keep the analytics redaction on groups in case people have old links. const hashRegex = /#\/(groups?|room|user|settings|register|login|forgot_password|home|directory)/; const hashVarRegex = /#\/(group|room|user)\/.*$/; @@ -447,7 +448,7 @@ export class Analytics {
{ _t('Where this page includes identifiable information, such as a room, ' - + 'user or group ID, that data is removed before being sent to the server.') } + + 'user ID, that data is removed before being sent to the server.') }
, }); diff --git a/src/Avatar.ts b/src/Avatar.ts index 310fec5f4c..5d4d463dd8 100644 --- a/src/Avatar.ts +++ b/src/Avatar.ts @@ -22,7 +22,6 @@ import { split } from "lodash"; import DMRoomMap from './utils/DMRoomMap'; import { mediaFromMxc } from "./customisations/Media"; -import SpaceStore from "./stores/spaces/SpaceStore"; // Not to be used for BaseAvatar urls as that has similar default avatar fallback already export function avatarUrlForMember( @@ -140,7 +139,7 @@ export function avatarUrlForRoom(room: Room, width: number, height: number, resi } // space rooms cannot be DMs so skip the rest - if (SpaceStore.spacesEnabled && room.isSpaceRoom()) return null; + if (room.isSpaceRoom()) return null; // If the room is not a DM don't fallback to a member avatar if (!DMRoomMap.shared().getUserIdForRoomId(room.roomId)) return null; diff --git a/src/GroupAddressPicker.js b/src/GroupAddressPicker.js deleted file mode 100644 index 6430090819..0000000000 --- a/src/GroupAddressPicker.js +++ /dev/null @@ -1,162 +0,0 @@ -/* -Copyright 2017 New Vector Ltd - -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 Modal from './Modal'; -import * as sdk from './'; -import MultiInviter from './utils/MultiInviter'; -import { _t } from './languageHandler'; -import { MatrixClientPeg } from './MatrixClientPeg'; -import GroupStore from './stores/GroupStore'; -import StyledCheckbox from './components/views/elements/StyledCheckbox'; - -export function showGroupInviteDialog(groupId) { - return new Promise((resolve, reject) => { - const description =
-
{ _t("Who would you like to add to this community?") }
-
- { _t( - "Warning: any person you add to a community will be publicly "+ - "visible to anyone who knows the community ID", - ) } -
-
; - - const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog"); - Modal.createTrackedDialog('Group Invite', '', AddressPickerDialog, { - title: _t("Invite new community members"), - description: description, - placeholder: _t("Name or Matrix ID"), - button: _t("Invite to Community"), - validAddressTypes: ['mx-user-id'], - onFinished: (success, addrs) => { - if (!success) return; - - _onGroupInviteFinished(groupId, addrs).then(resolve, reject); - }, - }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); - }); -} - -export function showGroupAddRoomDialog(groupId) { - return new Promise((resolve, reject) => { - let addRoomsPublicly = false; - const onCheckboxClicked = (e) => { - addRoomsPublicly = e.target.checked; - }; - const description =
-
{ _t("Which rooms would you like to add to this community?") }
-
; - - const checkboxContainer = - { _t("Show these rooms to non-members on the community page and room list?") } - ; - - const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog"); - Modal.createTrackedDialog('Add Rooms to Group', '', AddressPickerDialog, { - title: _t("Add rooms to the community"), - description: description, - extraNode: checkboxContainer, - placeholder: _t("Room name or address"), - button: _t("Add to community"), - pickerType: 'room', - validAddressTypes: ['mx-room-id'], - onFinished: (success, addrs) => { - if (!success) return; - - _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly).then(resolve, reject); - }, - }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); - }); -} - -function _onGroupInviteFinished(groupId, addrs) { - const multiInviter = new MultiInviter(groupId); - - const addrTexts = addrs.map((addr) => addr.address); - - return multiInviter.invite(addrTexts).then((completionStates) => { - // Show user any errors - const errorList = []; - for (const addr of Object.keys(completionStates)) { - if (addrs[addr] === "error") { - errorList.push(addr); - } - } - - if (errorList.length > 0) { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Failed to invite the following users to the group', '', ErrorDialog, { - title: _t("Failed to invite the following users to %(groupId)s:", { groupId: groupId }), - description: errorList.join(", "), - }); - } - }).catch((err) => { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Failed to invite users to group', '', ErrorDialog, { - title: _t("Failed to invite users to community"), - description: _t("Failed to invite users to %(groupId)s", { groupId: groupId }), - }); - }); -} - -function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) { - const matrixClient = MatrixClientPeg.get(); - const errorList = []; - return Promise.allSettled(addrs.map((addr) => { - return GroupStore - .addRoomToGroup(groupId, addr.address, addRoomsPublicly) - .catch(() => { errorList.push(addr.address); }) - .then(() => { - const roomId = addr.address; - const room = matrixClient.getRoom(roomId); - // Can the user change related groups? - if (!room || !room.currentState.mayClientSendStateEvent("m.room.related_groups", matrixClient)) { - return; - } - // Get the related groups - const relatedGroupsEvent = room.currentState.getStateEvents('m.room.related_groups', ''); - const groups = relatedGroupsEvent ? relatedGroupsEvent.getContent().groups || [] : []; - - // Add this group as related - if (!groups.includes(groupId)) { - groups.push(groupId); - return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.related_groups', { groups }, ''); - } - }); - })).then(() => { - if (errorList.length === 0) { - return; - } - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog( - 'Failed to add the following room to the group', - '', - ErrorDialog, - { - title: _t( - "Failed to add the following rooms to %(groupId)s:", - { groupId }, - ), - description: errorList.join(", "), - }, - ); - }); -} diff --git a/src/IConfigOptions.ts b/src/IConfigOptions.ts index 76c0901df3..cfaeecb75e 100644 --- a/src/IConfigOptions.ts +++ b/src/IConfigOptions.ts @@ -178,6 +178,9 @@ export interface IConfigOptions { sync_timeline_limit?: number; dangerously_allow_unsafe_and_insecure_passwords?: boolean; // developer option + + // XXX: Undocumented URL for the "Learn more about spaces" link in the "Communities don't exist" messaging. + spaces_learn_more_url?: string; } export interface ISsoRedirectOptions { diff --git a/src/PageTypes.ts b/src/PageTypes.ts index 0e4944efc9..fb0424f6e0 100644 --- a/src/PageTypes.ts +++ b/src/PageTypes.ts @@ -20,8 +20,7 @@ enum PageType { HomePage = "home_page", RoomView = "room_view", UserView = "user_view", - GroupView = "group_view", - MyGroups = "my_groups", + LegacyGroupView = "legacy_group_view", } export default PageType; diff --git a/src/PosthogAnalytics.ts b/src/PosthogAnalytics.ts index 27c6396891..4187088253 100644 --- a/src/PosthogAnalytics.ts +++ b/src/PosthogAnalytics.ts @@ -58,7 +58,7 @@ export enum Anonymity { const whitelistedScreens = new Set([ "register", "login", "forgot_password", "soft_logout", "new", "settings", "welcome", "home", "start", "directory", - "start_sso", "start_cas", "groups", "complete_security", "post_registration", "room", "user", "group", + "start_sso", "start_cas", "complete_security", "post_registration", "room", "user", ]); export function getRedactedCurrentLocation( diff --git a/src/PosthogTrackers.ts b/src/PosthogTrackers.ts index b07ba5569c..434d142c8c 100644 --- a/src/PosthogTrackers.ts +++ b/src/PosthogTrackers.ts @@ -40,8 +40,7 @@ const loggedInPageTypeMap: Record = { [PageType.HomePage]: "Home", [PageType.RoomView]: "Room", [PageType.UserView]: "User", - [PageType.GroupView]: "Group", - [PageType.MyGroups]: "MyGroups", + [PageType.LegacyGroupView]: "Group", }; export default class PosthogTrackers { diff --git a/src/RoomInvite.tsx b/src/RoomInvite.tsx index a6eefaeb81..fae3f5dfeb 100644 --- a/src/RoomInvite.tsx +++ b/src/RoomInvite.tsx @@ -25,8 +25,6 @@ import MultiInviter, { CompletionStates } from './utils/MultiInviter'; import Modal from './Modal'; import { _t } from './languageHandler'; import InviteDialog, { KIND_DM, KIND_INVITE, Member } from "./components/views/dialogs/InviteDialog"; -import CommunityPrototypeInviteDialog from "./components/views/dialogs/CommunityPrototypeInviteDialog"; -import { CommunityPrototypeStore } from "./stores/CommunityPrototypeStore"; import BaseAvatar from "./components/views/avatars/BaseAvatar"; import { mediaFromMxc } from "./customisations/Media"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; @@ -78,23 +76,6 @@ export function showRoomInviteDialog(roomId: string, initialText = ""): void { ); } -export function showCommunityRoomInviteDialog(roomId: string, communityName: string): void { - Modal.createTrackedDialog( - 'Invite Users to Community', '', CommunityPrototypeInviteDialog, { communityName, roomId }, - /*className=*/null, /*isPriority=*/false, /*isStatic=*/true, - ); -} - -export function showCommunityInviteDialog(communityId: string): void { - const chat = CommunityPrototypeStore.instance.getGeneralChat(communityId); - if (chat) { - const name = CommunityPrototypeStore.instance.getCommunityName(communityId); - showCommunityRoomInviteDialog(chat.roomId, name); - } else { - throw new Error("Failed to locate appropriate room to start an invite in"); - } -} - /** * Checks if the given MatrixEvent is a valid 3rd party user invite. * @param {MatrixEvent} event The event to check diff --git a/src/SdkConfig.ts b/src/SdkConfig.ts index c610c0bf14..66188e240f 100644 --- a/src/SdkConfig.ts +++ b/src/SdkConfig.ts @@ -40,6 +40,7 @@ export const DEFAULTS: Partial = { logo: require("../res/img/element-desktop-logo.svg").default, url: "https://element.io/get-started", }, + spaces_learn_more_url: "https://element.io/blog/spaces-blast-out-of-beta/", }; export default class SdkConfig { diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index b79de50352..2fb3702133 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -639,7 +639,7 @@ export const Commands = [ return reject(this.getUsage()); } - // If for some reason someone wanted to join a group or user, we should + // If for some reason someone wanted to join a user, we should // stop them now. if (!permalinkParts.roomIdOrAlias) { return reject(this.getUsage()); diff --git a/src/TextForEvent.tsx b/src/TextForEvent.tsx index 5b76eb6f20..998ed20b74 100644 --- a/src/TextForEvent.tsx +++ b/src/TextForEvent.tsx @@ -274,36 +274,6 @@ function textForGuestAccessEvent(ev: MatrixEvent): () => string | null { } } -function textForRelatedGroupsEvent(ev: MatrixEvent): () => string | null { - const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); - const groups = ev.getContent().groups || []; - const prevGroups = ev.getPrevContent().groups || []; - const added = groups.filter((g) => !prevGroups.includes(g)); - const removed = prevGroups.filter((g) => !groups.includes(g)); - - if (added.length && !removed.length) { - return () => _t('%(senderDisplayName)s enabled flair for %(groups)s in this room.', { - senderDisplayName, - groups: added.join(', '), - }); - } else if (!added.length && removed.length) { - return () => _t('%(senderDisplayName)s disabled flair for %(groups)s in this room.', { - senderDisplayName, - groups: removed.join(', '), - }); - } else if (added.length && removed.length) { - return () => _t('%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for ' + - '%(oldGroups)s in this room.', { - senderDisplayName, - newGroups: added.join(', '), - oldGroups: removed.join(', '), - }); - } else { - // Don't bother rendering this change (because there were no changes) - return null; - } -} - function textForServerACLEvent(ev: MatrixEvent): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); const prevContent = ev.getPrevContent(); @@ -800,7 +770,6 @@ const stateHandlers: IHandlers = { [EventType.RoomTombstone]: textForTombstoneEvent, [EventType.RoomJoinRules]: textForJoinRulesEvent, [EventType.RoomGuestAccess]: textForGuestAccessEvent, - 'm.room.related_groups': textForRelatedGroupsEvent, // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) 'im.vector.modular.widgets': textForWidgetEvent, diff --git a/src/actions/GroupActions.ts b/src/actions/GroupActions.ts deleted file mode 100644 index 44776f0a25..0000000000 --- a/src/actions/GroupActions.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* -Copyright 2017 New Vector Ltd -Copyright 2020 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 { MatrixClient } from "matrix-js-sdk/src/client"; - -import { asyncAction } from './actionCreators'; -import { AsyncActionPayload } from "../dispatcher/payloads"; - -export default class GroupActions { - /** - * Creates an action thunk that will do an asynchronous request to fetch - * the groups to which a user is joined. - * - * @param {MatrixClient} matrixClient the matrix client to query. - * @returns {AsyncActionPayload} An async action payload. - * @see asyncAction - */ - public static fetchJoinedGroups(matrixClient: MatrixClient): AsyncActionPayload { - return asyncAction('GroupActions.fetchJoinedGroups', () => matrixClient.getJoinedGroups(), null); - } -} diff --git a/src/actions/TagOrderActions.ts b/src/actions/TagOrderActions.ts deleted file mode 100644 index 4ae600472e..0000000000 --- a/src/actions/TagOrderActions.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright 2017 New Vector Ltd -Copyright 2020 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 { MatrixClient } from "matrix-js-sdk/src/client"; - -import Analytics from '../Analytics'; -import { asyncAction } from './actionCreators'; -import GroupFilterOrderStore from '../stores/GroupFilterOrderStore'; -import { AsyncActionPayload } from "../dispatcher/payloads"; - -export default class TagOrderActions { - /** - * Creates an action thunk that will do an asynchronous request to - * move a tag in GroupFilterOrderStore to destinationIx. - * - * @param {MatrixClient} matrixClient the matrix client to set the - * account data on. - * @param {string} tag the tag to move. - * @param {number} destinationIx the new position of the tag. - * @returns {AsyncActionPayload} an async action payload that will - * dispatch actions indicating the status of the request. - * @see asyncAction - */ - public static moveTag(matrixClient: MatrixClient, tag: string, destinationIx: number): AsyncActionPayload { - // Only commit tags if the state is ready, i.e. not null - let tags = GroupFilterOrderStore.getOrderedTags(); - let removedTags = GroupFilterOrderStore.getRemovedTagsAccountData() || []; - if (!tags) { - return; - } - - tags = tags.filter((t) => t !== tag); - tags = [...tags.slice(0, destinationIx), tag, ...tags.slice(destinationIx)]; - - removedTags = removedTags.filter((t) => t !== tag); - - const storeId = GroupFilterOrderStore.getStoreId(); - - return asyncAction('TagOrderActions.moveTag', () => { - Analytics.trackEvent('TagOrderActions', 'commitTagOrdering'); - return matrixClient.setAccountData( - 'im.vector.web.tag_ordering', - { tags, removedTags, _storeId: storeId }, - ); - }, () => { - // For an optimistic update - return { tags, removedTags }; - }); - } - - /** - * Creates an action thunk that will do an asynchronous request to - * label a tag as removed in im.vector.web.tag_ordering account data. - * - * The reason this is implemented with new state `removedTags` is that - * we incrementally and initially populate `tags` with groups that - * have been joined. If we remove a group from `tags`, it will just - * get added (as it looks like a group we've recently joined). - * - * NB: If we ever support adding of tags (which is planned), we should - * take special care to remove the tag from `removedTags` when we add - * it. - * - * @param {MatrixClient} matrixClient the matrix client to set the - * account data on. - * @param {string} tag the tag to remove. - * @returns {function} an async action payload that will dispatch - * actions indicating the status of the request. - * @see asyncAction - */ - public static removeTag(matrixClient: MatrixClient, tag: string): AsyncActionPayload { - // Don't change tags, just removedTags - const tags = GroupFilterOrderStore.getOrderedTags(); - const removedTags = GroupFilterOrderStore.getRemovedTagsAccountData() || []; - - if (removedTags.includes(tag)) { - // Return a thunk that doesn't do anything, we don't even need - // an asynchronous action here, the tag is already removed. - return new AsyncActionPayload(() => {}); - } - - removedTags.push(tag); - - const storeId = GroupFilterOrderStore.getStoreId(); - - return asyncAction('TagOrderActions.removeTag', () => { - Analytics.trackEvent('TagOrderActions', 'removeTag'); - return matrixClient.setAccountData( - 'im.vector.web.tag_ordering', - { tags, removedTags, _storeId: storeId }, - ); - }, () => { - // For an optimistic update - return { removedTags }; - }); - } -} diff --git a/src/autocomplete/Autocompleter.ts b/src/autocomplete/Autocompleter.ts index aeee335e04..880f4e6873 100644 --- a/src/autocomplete/Autocompleter.ts +++ b/src/autocomplete/Autocompleter.ts @@ -19,7 +19,6 @@ import { ReactElement } from 'react'; import { Room } from 'matrix-js-sdk/src/models/room'; import CommandProvider from './CommandProvider'; -import CommunityProvider from './CommunityProvider'; import RoomProvider from './RoomProvider'; import UserProvider from './UserProvider'; import EmojiProvider from './EmojiProvider'; @@ -27,7 +26,6 @@ import NotifProvider from './NotifProvider'; import { timeout } from "../utils/promise"; import AutocompleteProvider, { ICommand } from "./AutocompleteProvider"; import SpaceProvider from "./SpaceProvider"; -import SpaceStore from "../stores/spaces/SpaceStore"; import { TimelineRenderingType } from '../contexts/RoomContext'; export interface ISelectionRange { @@ -55,14 +53,9 @@ const PROVIDERS = [ EmojiProvider, NotifProvider, CommandProvider, + SpaceProvider, ]; -if (SpaceStore.spacesEnabled) { - PROVIDERS.push(SpaceProvider); -} else { - PROVIDERS.push(CommunityProvider); -} - // Providers will get rejected if they take longer than this. const PROVIDER_COMPLETION_TIMEOUT = 3000; diff --git a/src/autocomplete/CommunityProvider.tsx b/src/autocomplete/CommunityProvider.tsx deleted file mode 100644 index b3a4079f94..0000000000 --- a/src/autocomplete/CommunityProvider.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/* -Copyright 2018 New Vector Ltd -Copyright 2018 Michael Telatynski <7t3chguy@gmail.com> - -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 Group from "matrix-js-sdk/src/models/group"; -import { sortBy } from "lodash"; -import { Room } from 'matrix-js-sdk/src/models/room'; - -import { _t } from '../languageHandler'; -import AutocompleteProvider from './AutocompleteProvider'; -import { MatrixClientPeg } from '../MatrixClientPeg'; -import QueryMatcher from './QueryMatcher'; -import { PillCompletion } from './Components'; -import { makeGroupPermalink } from "../utils/permalinks/Permalinks"; -import { ICompletion, ISelectionRange } from "./Autocompleter"; -import FlairStore from "../stores/FlairStore"; -import { mediaFromMxc } from "../customisations/Media"; -import BaseAvatar from '../components/views/avatars/BaseAvatar'; -import { TimelineRenderingType } from '../contexts/RoomContext'; - -const COMMUNITY_REGEX = /\B\+\S*/g; - -function score(query, space) { - const index = space.indexOf(query); - if (index === -1) { - return Infinity; - } else { - return index; - } -} - -export default class CommunityProvider extends AutocompleteProvider { - matcher: QueryMatcher; - - constructor(room: Room, renderingType?: TimelineRenderingType) { - super({ commandRegex: COMMUNITY_REGEX, renderingType }); - this.matcher = new QueryMatcher([], { - keys: ['groupId', 'name', 'shortDescription'], - }); - } - - async getCompletions( - query: string, - selection: ISelectionRange, - force = false, - limit = -1, - ): Promise { - // Disable autocompletions when composing commands because of various issues - // (see https://github.com/vector-im/element-web/issues/4762) - if (/^(\/join|\/leave)/.test(query)) { - return []; - } - - const cli = MatrixClientPeg.get(); - let completions = []; - const { command, range } = this.getCurrentCommand(query, selection, force); - if (command) { - const joinedGroups = cli.getGroups().filter(({ myMembership }) => myMembership === 'join'); - - const groups = (await Promise.all(joinedGroups.map(async ({ groupId }) => { - try { - return FlairStore.getGroupProfileCached(cli, groupId); - } catch (e) { // if FlairStore failed, fall back to just groupId - return Promise.resolve({ - name: '', - groupId, - avatarUrl: '', - shortDescription: '', - }); - } - }))); - - this.matcher.setObjects(groups); - - const matchedString = command[0]; - completions = this.matcher.match(matchedString, limit); - completions = sortBy(completions, [ - (c) => score(matchedString, c.groupId), - (c) => c.groupId.length, - ]).map(({ avatarUrl, groupId, name }) => ({ - completion: groupId, - suffix: ' ', - type: "community", - href: makeGroupPermalink(groupId), - component: ( - - - - ), - range, - })).slice(0, 4); - } - return completions; - } - - getName() { - return '💬 ' + _t('Communities'); - } - - renderCompletions(completions: React.ReactNode[]): React.ReactNode { - return ( -
- { completions } -
- ); - } -} diff --git a/src/autocomplete/RoomProvider.tsx b/src/autocomplete/RoomProvider.tsx index 1879c85fe3..cac3531813 100644 --- a/src/autocomplete/RoomProvider.tsx +++ b/src/autocomplete/RoomProvider.tsx @@ -17,7 +17,7 @@ limitations under the License. */ import React from "react"; -import { uniqBy, sortBy } from "lodash"; +import { sortBy, uniqBy } from "lodash"; import { Room } from "matrix-js-sdk/src/models/room"; import { _t } from '../languageHandler'; @@ -28,7 +28,6 @@ import { PillCompletion } from './Components'; import { makeRoomPermalink } from "../utils/permalinks/Permalinks"; import { ICompletion, ISelectionRange } from "./Autocompleter"; import RoomAvatar from '../components/views/avatars/RoomAvatar'; -import SpaceStore from "../stores/spaces/SpaceStore"; import { TimelineRenderingType } from "../contexts/RoomContext"; const ROOM_REGEX = /\B#\S*/g; @@ -58,14 +57,9 @@ export default class RoomProvider extends AutocompleteProvider { protected getRooms() { const cli = MatrixClientPeg.get(); - let rooms = cli.getVisibleRooms(); - // if spaces are enabled then filter them out here as they get their own autocomplete provider - if (SpaceStore.spacesEnabled) { - rooms = rooms.filter(r => !r.isSpaceRoom()); - } - - return rooms; + // filter out spaces here as they get their own autocomplete provider + return cli.getVisibleRooms().filter(r => !r.isSpaceRoom()); } async getCompletions( diff --git a/src/components/structures/CustomRoomTagPanel.js b/src/components/structures/CustomRoomTagPanel.js deleted file mode 100644 index 365b30bb0e..0000000000 --- a/src/components/structures/CustomRoomTagPanel.js +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright 2019 New Vector Ltd. - -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 classNames from 'classnames'; - -import CustomRoomTagStore from '../../stores/CustomRoomTagStore'; -import AutoHideScrollbar from './AutoHideScrollbar'; -import * as sdk from '../../index'; -import dis from '../../dispatcher/dispatcher'; -import * as FormattingUtils from '../../utils/FormattingUtils'; -import { replaceableComponent } from "../../utils/replaceableComponent"; - -@replaceableComponent("structures.CustomRoomTagPanel") -class CustomRoomTagPanel extends React.Component { - constructor(props) { - super(props); - this.state = { - tags: CustomRoomTagStore.getSortedTags(), - }; - } - - componentDidMount() { - this._tagStoreToken = CustomRoomTagStore.addListener(() => { - this.setState({ tags: CustomRoomTagStore.getSortedTags() }); - }); - } - - componentWillUnmount() { - if (this._tagStoreToken) { - this._tagStoreToken.remove(); - } - } - - render() { - const tags = this.state.tags.map((tag) => { - return (); - }); - - const classes = classNames('mx_CustomRoomTagPanel', { - mx_CustomRoomTagPanel_empty: this.state.tags.length === 0, - }); - - return (
-
- - { tags } - -
); - } -} - -class CustomRoomTagTile extends React.Component { - onClick = () => { - dis.dispatch({ action: 'select_custom_room_tag', tag: this.props.tag.name }); - }; - - render() { - const BaseAvatar = sdk.getComponent('avatars.BaseAvatar'); - const AccessibleTooltipButton = sdk.getComponent('elements.AccessibleTooltipButton'); - - const tag = this.props.tag; - const avatarHeight = 40; - const className = classNames({ - "CustomRoomTagPanel_tileSelected": tag.selected, - }); - const name = tag.name; - const badgeNotifState = tag.badgeNotifState; - let badgeElement; - if (badgeNotifState) { - const badgeClasses = classNames({ - "mx_TagTile_badge": true, - "mx_TagTile_badgeHighlight": badgeNotifState.hasMentions, - }); - badgeElement = (
{ FormattingUtils.formatCount(badgeNotifState.count) }
); - } - - return ( - -
- - { badgeElement } -
-
- ); - } -} - -export default CustomRoomTagPanel; diff --git a/src/components/structures/GroupFilterPanel.tsx b/src/components/structures/GroupFilterPanel.tsx deleted file mode 100644 index c86e243fa9..0000000000 --- a/src/components/structures/GroupFilterPanel.tsx +++ /dev/null @@ -1,182 +0,0 @@ -/* -Copyright 2017, 2018 New Vector Ltd. -Copyright 2020 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 classNames from 'classnames'; -import { ClientEvent } from "matrix-js-sdk/src/client"; - -import type { EventSubscription } from "fbemitter"; -import GroupFilterOrderStore from '../../stores/GroupFilterOrderStore'; -import GroupActions from '../../actions/GroupActions'; -import dis from '../../dispatcher/dispatcher'; -import { _t } from '../../languageHandler'; -import MatrixClientContext from "../../contexts/MatrixClientContext"; -import AutoHideScrollbar from "./AutoHideScrollbar"; -import SettingsStore from "../../settings/SettingsStore"; -import UserTagTile from "../views/elements/UserTagTile"; -import { replaceableComponent } from "../../utils/replaceableComponent"; -import UIStore from "../../stores/UIStore"; -import DNDTagTile from "../views/elements/DNDTagTile"; -import ActionButton from "../views/elements/ActionButton"; - -interface IGroupFilterPanelProps { - -} - -// FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript -type OrderedTagsTemporaryType = Array<{}>; -// FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript -type SelectedTagsTemporaryType = Array<{}>; - -interface IGroupFilterPanelState { - // FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript - orderedTags: OrderedTagsTemporaryType; - // FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript - selectedTags: SelectedTagsTemporaryType; -} - -@replaceableComponent("structures.GroupFilterPanel") -class GroupFilterPanel extends React.Component { - public static contextType = MatrixClientContext; - public context!: React.ContextType; - - public state = { - orderedTags: [], - selectedTags: [], - }; - - private ref = React.createRef(); - private unmounted = false; - private groupFilterOrderStoreToken?: EventSubscription; - - public componentDidMount() { - this.unmounted = false; - this.context.on(ClientEvent.GroupMyMembership, this.onGroupMyMembership); - this.context.on(ClientEvent.Sync, this.onClientSync); - - this.groupFilterOrderStoreToken = GroupFilterOrderStore.addListener(() => { - if (this.unmounted) { - return; - } - this.setState({ - orderedTags: GroupFilterOrderStore.getOrderedTags() || [], - selectedTags: GroupFilterOrderStore.getSelectedTags(), - }); - }); - // This could be done by anything with a matrix client - dis.dispatch(GroupActions.fetchJoinedGroups(this.context)); - UIStore.instance.trackElementDimensions("GroupPanel", this.ref.current); - } - - public componentWillUnmount() { - this.unmounted = true; - this.context.removeListener(ClientEvent.GroupMyMembership, this.onGroupMyMembership); - this.context.removeListener(ClientEvent.Sync, this.onClientSync); - if (this.groupFilterOrderStoreToken) { - this.groupFilterOrderStoreToken.remove(); - } - UIStore.instance.stopTrackingElementDimensions("GroupPanel"); - } - - private onGroupMyMembership = () => { - if (this.unmounted) return; - dis.dispatch(GroupActions.fetchJoinedGroups(this.context)); - }; - - private onClientSync = (syncState, prevState) => { - // Consider the client reconnected if there is no error with syncing. - // This means the state could be RECONNECTING, SYNCING, PREPARED or CATCHUP. - const reconnected = syncState !== "ERROR" && prevState !== syncState; - if (reconnected) { - // Load joined groups - dis.dispatch(GroupActions.fetchJoinedGroups(this.context)); - } - }; - - private onClick = e => { - // only dispatch if its not a no-op - if (this.state.selectedTags.length > 0) { - dis.dispatch({ action: 'deselect_tags' }); - } - }; - - private onClearFilterClick = ev => { - dis.dispatch({ action: 'deselect_tags' }); - }; - - private renderGlobalIcon() { - if (!SettingsStore.getValue("feature_communities_v2_prototypes")) return null; - - return ( -
- -
-
- ); - } - - public render() { - const tags = this.state.orderedTags.map((tag, index) => { - return ; - }); - - const itemsSelected = this.state.selectedTags.length > 0; - const classes = classNames('mx_GroupFilterPanel', { - mx_GroupFilterPanel_items_selected: itemsSelected, - }); - - let createButton = ( - - ); - - if (SettingsStore.getValue("feature_communities_v2_prototypes")) { - createButton = ( - - ); - } - - return
- -
- { this.renderGlobalIcon() } - { tags } -
- { createButton } -
-
-
-
; - } -} -export default GroupFilterPanel; diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js deleted file mode 100644 index d5da40b86a..0000000000 --- a/src/components/structures/GroupView.js +++ /dev/null @@ -1,1424 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd. -Copyright 2017, 2018 New Vector Ltd. -Copyright 2019 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 PropTypes from 'prop-types'; -import classnames from 'classnames'; -import { Group } from "matrix-js-sdk/src/models/group"; -import { sleep } from "matrix-js-sdk/src/utils"; -import { logger } from "matrix-js-sdk/src/logger"; - -import { MatrixClientPeg } from '../../MatrixClientPeg'; -import * as sdk from '../../index'; -import dis from '../../dispatcher/dispatcher'; -import { getHostingLink } from '../../utils/HostingLink'; -import { sanitizedHtmlNode } from '../../HtmlUtils'; -import { _t, _td } from '../../languageHandler'; -import AccessibleButton from '../views/elements/AccessibleButton'; -import GroupHeaderButtons from '../views/right_panel/GroupHeaderButtons'; -import MainSplit from './MainSplit'; -import RightPanel from './RightPanel'; -import Modal from '../../Modal'; -import GroupStore from '../../stores/GroupStore'; -import FlairStore from '../../stores/FlairStore'; -import { showGroupAddRoomDialog } from '../../GroupAddressPicker'; -import { makeGroupPermalink, makeUserPermalink } from "../../utils/permalinks/Permalinks"; -import RightPanelStore from "../../stores/right-panel/RightPanelStore"; -import AutoHideScrollbar from "./AutoHideScrollbar"; -import { mediaFromMxc } from "../../customisations/Media"; -import { replaceableComponent } from "../../utils/replaceableComponent"; -import { createSpaceFromCommunity } from "../../utils/space"; -import { Action } from "../../dispatcher/actions"; -import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases"; -import { UPDATE_EVENT } from "../../stores/AsyncStore"; - -const LONG_DESC_PLACEHOLDER = _td( - `

HTML for your community's page

-

- Use the long description to introduce new members to the community, or distribute - some important links -

-

- You can even add images with Matrix URLs -

-`); - -const RoomSummaryType = PropTypes.shape({ - room_id: PropTypes.string.isRequired, - profile: PropTypes.shape({ - name: PropTypes.string, - avatar_url: PropTypes.string, - canonical_alias: PropTypes.string, - }).isRequired, -}); - -const UserSummaryType = PropTypes.shape({ - summaryInfo: PropTypes.shape({ - user_id: PropTypes.string.isRequired, - role_id: PropTypes.string, - avatar_url: PropTypes.string, - displayname: PropTypes.string, - }).isRequired, -}); - -class CategoryRoomList extends React.Component { - static propTypes = { - rooms: PropTypes.arrayOf(RoomSummaryType).isRequired, - category: PropTypes.shape({ - profile: PropTypes.shape({ - name: PropTypes.string, - }).isRequired, - }), - groupId: PropTypes.string.isRequired, - - // Whether the list should be editable - editing: PropTypes.bool.isRequired, - }; - - onAddRoomsToSummaryClicked = (ev) => { - ev.preventDefault(); - const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog"); - Modal.createTrackedDialog('Add Rooms to Group Summary', '', AddressPickerDialog, { - title: _t('Add rooms to the community summary'), - description: _t("Which rooms would you like to add to this summary?"), - placeholder: _t("Room name or address"), - button: _t("Add to summary"), - pickerType: 'room', - validAddressTypes: ['mx-room-id'], - groupId: this.props.groupId, - onFinished: (success, addrs) => { - if (!success) return; - const errorList = []; - Promise.allSettled(addrs.map((addr) => { - return GroupStore - .addRoomToGroupSummary(this.props.groupId, addr.address) - .catch(() => { errorList.push(addr.address); }); - })).then(() => { - if (errorList.length === 0) { - return; - } - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog( - 'Failed to add the following room to the group summary', - '', - ErrorDialog, - { - title: _t( - "Failed to add the following rooms to the summary of %(groupId)s:", - { groupId: this.props.groupId }, - ), - description: errorList.join(", "), - }, - ); - }); - }, - }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); - }; - - render() { - const addButton = this.props.editing ? - ( - -
- { _t('Add a Room') } -
-
) :
; - - const roomNodes = this.props.rooms.map((r) => { - return ; - }); - - let catHeader =
; - if (this.props.category && this.props.category.profile) { - catHeader =
- { this.props.category.profile.name } -
; - } - return
- { catHeader } - { roomNodes } - { addButton } -
; - } -} - -class FeaturedRoom extends React.Component { - static propTypes = { - summaryInfo: RoomSummaryType.isRequired, - editing: PropTypes.bool.isRequired, - groupId: PropTypes.string.isRequired, - }; - - onClick = (e) => { - e.preventDefault(); - e.stopPropagation(); - - dis.dispatch({ - action: Action.ViewRoom, - room_alias: this.props.summaryInfo.profile.canonical_alias, - room_id: this.props.summaryInfo.room_id, - }); - }; - - onDeleteClicked = (e) => { - e.preventDefault(); - e.stopPropagation(); - GroupStore.removeRoomFromGroupSummary( - this.props.groupId, - this.props.summaryInfo.room_id, - ).catch((err) => { - logger.error('Error whilst removing room from group summary', err); - const roomName = this.props.summaryInfo.name || - this.props.summaryInfo.canonical_alias || - this.props.summaryInfo.room_id; - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog( - 'Failed to remove room from group summary', - '', ErrorDialog, - { - title: _t( - "Failed to remove the room from the summary of %(groupId)s", - { groupId: this.props.groupId }, - ), - description: _t("The room '%(roomName)s' could not be removed from the summary.", { roomName }), - }, - ); - }); - }; - - render() { - const RoomAvatar = sdk.getComponent("avatars.RoomAvatar"); - - const roomName = this.props.summaryInfo.profile.name || - this.props.summaryInfo.profile.canonical_alias || - _t("Unnamed Room"); - - const oobData = { - roomId: this.props.summaryInfo.room_id, - avatarUrl: this.props.summaryInfo.profile.avatar_url, - name: roomName, - }; - - let permalink = null; - if (this.props.summaryInfo.profile && this.props.summaryInfo.profile.canonical_alias) { - permalink = makeGroupPermalink(this.props.summaryInfo.profile.canonical_alias); - } - - let roomNameNode = null; - if (permalink) { - roomNameNode = { roomName }; - } else { - roomNameNode = { roomName }; - } - - const deleteButton = this.props.editing ? - Delete - :
; - - return - -
{ roomNameNode }
- { deleteButton } -
; - } -} - -class RoleUserList extends React.Component { - static propTypes = { - users: PropTypes.arrayOf(UserSummaryType).isRequired, - role: PropTypes.shape({ - profile: PropTypes.shape({ - name: PropTypes.string, - }).isRequired, - }), - groupId: PropTypes.string.isRequired, - - // Whether the list should be editable - editing: PropTypes.bool.isRequired, - }; - - onAddUsersClicked = (ev) => { - ev.preventDefault(); - const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog"); - Modal.createTrackedDialog('Add Users to Group Summary', '', AddressPickerDialog, { - title: _t('Add users to the community summary'), - description: _t("Who would you like to add to this summary?"), - placeholder: _t("Name or Matrix ID"), - button: _t("Add to summary"), - validAddressTypes: ['mx-user-id'], - groupId: this.props.groupId, - shouldOmitSelf: false, - onFinished: (success, addrs) => { - if (!success) return; - const errorList = []; - Promise.allSettled(addrs.map((addr) => { - return GroupStore - .addUserToGroupSummary(addr.address) - .catch(() => { errorList.push(addr.address); }); - })).then(() => { - if (errorList.length === 0) { - return; - } - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog( - 'Failed to add the following users to the community summary', - '', ErrorDialog, - { - title: _t( - "Failed to add the following users to the summary of %(groupId)s:", - { groupId: this.props.groupId }, - ), - description: errorList.join(", "), - }, - ); - }); - }, - }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); - }; - - render() { - const addButton = this.props.editing ? - ( - -
- { _t('Add a User') } -
-
) :
; - const userNodes = this.props.users.map((u) => { - return ; - }); - let roleHeader =
; - if (this.props.role && this.props.role.profile) { - roleHeader =
{ this.props.role.profile.name }
; - } - return
- { roleHeader } - { userNodes } - { addButton } -
; - } -} - -class FeaturedUser extends React.Component { - static propTypes = { - summaryInfo: UserSummaryType.isRequired, - editing: PropTypes.bool.isRequired, - groupId: PropTypes.string.isRequired, - }; - - onClick = (e) => { - e.preventDefault(); - e.stopPropagation(); - - dis.dispatch({ - action: Action.ViewStartChatOrReuse, - user_id: this.props.summaryInfo.user_id, - }); - }; - - onDeleteClicked = (e) => { - e.preventDefault(); - e.stopPropagation(); - GroupStore.removeUserFromGroupSummary( - this.props.groupId, - this.props.summaryInfo.user_id, - ).catch((err) => { - logger.error('Error whilst removing user from group summary', err); - const displayName = this.props.summaryInfo.displayname || this.props.summaryInfo.user_id; - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog( - 'Failed to remove user from community summary', - '', - ErrorDialog, - { - title: _t( - "Failed to remove a user from the summary of %(groupId)s", - { groupId: this.props.groupId }, - ), - description: _t( - "The user '%(displayName)s' could not be removed from the summary.", - { displayName }, - ), - }, - ); - }); - }; - - render() { - const BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); - const name = this.props.summaryInfo.displayname || this.props.summaryInfo.user_id; - - const permalink = makeUserPermalink(this.props.summaryInfo.user_id); - const userNameNode = { name }; - const httpUrl = mediaFromMxc(this.props.summaryInfo.avatar_url).getSquareThumbnailHttp(64); - - const deleteButton = this.props.editing ? - Delete - :
; - - return - -
{ userNameNode }
- { deleteButton } -
; - } -} - -const GROUP_JOINPOLICY_OPEN = "open"; -const GROUP_JOINPOLICY_INVITE = "invite"; - -const UPGRADE_NOTICE_LS_KEY = "mx_hide_community_upgrade_notice"; - -@replaceableComponent("structures.GroupView") -export default class GroupView extends React.Component { - static propTypes = { - groupId: PropTypes.string.isRequired, - // Whether this is the first time the group admin is viewing the group - groupIsNew: PropTypes.bool, - }; - - state = { - summary: null, - isGroupPublicised: null, - isUserPrivileged: null, - groupRooms: null, - groupRoomsLoading: null, - error: null, - editing: false, - saving: false, - uploadingAvatar: false, - avatarChanged: false, - membershipBusy: false, - publicityBusy: false, - inviterProfile: null, - showRightPanel: RightPanelStore.instance.isOpenForGroup, - showUpgradeNotice: !localStorage.getItem(UPGRADE_NOTICE_LS_KEY), - }; - - componentDidMount() { - this._unmounted = false; - this._matrixClient = MatrixClientPeg.get(); - this._matrixClient.on("Group.myMembership", this._onGroupMyMembership); - - this._initGroupStore(this.props.groupId, true); - - this._dispatcherRef = dis.register(this._onAction); - RightPanelStore.instance.on(UPDATE_EVENT, this._onRightPanelStoreUpdate); - } - - componentWillUnmount() { - this._unmounted = true; - this._matrixClient.removeListener("Group.myMembership", this._onGroupMyMembership); - dis.unregister(this._dispatcherRef); - - RightPanelStore.instance.off(UPDATE_EVENT, this._onRightPanelStoreUpdate); - } - - // TODO: [REACT-WARNING] Replace with appropriate lifecycle event - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(newProps) { - if (this.props.groupId !== newProps.groupId) { - this.setState({ - summary: null, - error: null, - }, () => { - this._initGroupStore(newProps.groupId); - }); - } - } - - _onRightPanelStoreUpdate = () => { - this.setState({ - showRightPanel: RightPanelStore.instance.isOpenForGroup, - }); - }; - - _onGroupMyMembership = (group) => { - if (this._unmounted || group.groupId !== this.props.groupId) return; - if (group.myMembership === 'leave') { - // Leave settings - the user might have clicked the "Leave" button - this._closeSettings(); - } - this.setState({ membershipBusy: false }); - }; - - _initGroupStore(groupId, firstInit) { - const group = this._matrixClient.getGroup(groupId); - if (group && group.inviter && group.inviter.userId) { - this._fetchInviterProfile(group.inviter.userId); - } - GroupStore.registerListener(groupId, this.onGroupStoreUpdated.bind(this, firstInit)); - let willDoOnboarding = false; - // XXX: This should be more fluxy - let's get the error from GroupStore .getError or something - GroupStore.on('error', (err, errorGroupId, stateKey) => { - if (this._unmounted || groupId !== errorGroupId) return; - if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN' && !willDoOnboarding) { - dis.dispatch({ - action: Action.DoAfterSyncPrepared, - deferred_action: { - action: 'view_group', - group_id: groupId, - }, - }); - dis.dispatch({ action: 'require_registration', screen_after: { screen: `group/${groupId}` } }); - willDoOnboarding = true; - } - if (stateKey === GroupStore.STATE_KEY.Summary) { - this.setState({ - summary: null, - error: err, - editing: false, - }); - } - }); - } - - onGroupStoreUpdated = (firstInit) => { - if (this._unmounted) return; - const summary = GroupStore.getSummary(this.props.groupId); - if (summary.profile) { - // Default profile fields should be "" for later sending to the server (which - // requires that the fields are strings, not null) - ["avatar_url", "long_description", "name", "short_description"].forEach((k) => { - summary.profile[k] = summary.profile[k] || ""; - }); - } - this.setState({ - summary, - summaryLoading: !GroupStore.isStateReady(this.props.groupId, GroupStore.STATE_KEY.Summary), - isGroupPublicised: GroupStore.getGroupPublicity(this.props.groupId), - isUserPrivileged: GroupStore.isUserPrivileged(this.props.groupId), - groupRooms: GroupStore.getGroupRooms(this.props.groupId), - groupRoomsLoading: !GroupStore.isStateReady(this.props.groupId, GroupStore.STATE_KEY.GroupRooms), - isUserMember: GroupStore.getGroupMembers(this.props.groupId).some( - (m) => m.userId === this._matrixClient.credentials.userId, - ), - }); - // XXX: This might not work but this.props.groupIsNew unused anyway - if (this.props.groupIsNew && firstInit) { - this._onEditClick(); - } - }; - - _fetchInviterProfile(userId) { - this.setState({ - inviterProfileBusy: true, - }); - this._matrixClient.getProfileInfo(userId).then((resp) => { - if (this._unmounted) return; - this.setState({ - inviterProfile: { - avatarUrl: resp.avatar_url, - displayName: resp.displayname, - }, - }); - }).catch((e) => { - logger.error('Error getting group inviter profile', e); - }).finally(() => { - if (this._unmounted) return; - this.setState({ - inviterProfileBusy: false, - }); - }); - } - - _onEditClick = () => { - this.setState({ - editing: true, - profileForm: Object.assign({}, this.state.summary.profile), - joinableForm: { - policyType: - this.state.summary.profile.is_openly_joinable ? - GROUP_JOINPOLICY_OPEN : - GROUP_JOINPOLICY_INVITE, - }, - }); - }; - - _onShareClick = () => { - const ShareDialog = sdk.getComponent("dialogs.ShareDialog"); - Modal.createTrackedDialog('share community dialog', '', ShareDialog, { - target: this._matrixClient.getGroup(this.props.groupId) || new Group(this.props.groupId), - }); - }; - - _onCancelClick = () => { - this._closeSettings(); - }; - - _onAction = (payload) => { - switch (payload.action) { - // NOTE: close_settings is an app-wide dispatch; as it is dispatched from MatrixChat - case 'close_settings': - this.setState({ - editing: false, - profileForm: null, - }); - break; - default: - break; - } - }; - - _closeSettings = () => { - dis.dispatch({ action: 'close_settings' }); - }; - - _onNameChange = (value) => { - const newProfileForm = Object.assign(this.state.profileForm, { name: value }); - this.setState({ - profileForm: newProfileForm, - }); - }; - - _onShortDescChange = (value) => { - const newProfileForm = Object.assign(this.state.profileForm, { short_description: value }); - this.setState({ - profileForm: newProfileForm, - }); - }; - - _onLongDescChange = (e) => { - const newProfileForm = Object.assign(this.state.profileForm, { long_description: e.target.value }); - this.setState({ - profileForm: newProfileForm, - }); - }; - - _onAvatarSelected = ev => { - const file = ev.target.files[0]; - if (!file) return; - - this.setState({ uploadingAvatar: true }); - this._matrixClient.uploadContent(file).then((url) => { - const newProfileForm = Object.assign(this.state.profileForm, { avatar_url: url }); - this.setState({ - uploadingAvatar: false, - profileForm: newProfileForm, - - // Indicate that FlairStore needs to be poked to show this change - // in TagTile (GroupFilterPanel), Flair and GroupTile (MyGroups). - avatarChanged: true, - }); - }).catch((e) => { - this.setState({ uploadingAvatar: false }); - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - logger.error("Failed to upload avatar image", e); - Modal.createTrackedDialog('Failed to upload image', '', ErrorDialog, { - title: _t('Error'), - description: _t('Failed to upload image'), - }); - }); - }; - - _onJoinableChange = ev => { - this.setState({ - joinableForm: { policyType: ev.target.value }, - }); - }; - - _onSaveClick = () => { - this.setState({ saving: true }); - const savePromise = this.state.isUserPrivileged ? this._saveGroup() : Promise.resolve(); - savePromise.then((result) => { - this.setState({ - saving: false, - editing: false, - summary: null, - }); - this._initGroupStore(this.props.groupId); - - if (this.state.avatarChanged) { - // XXX: Evil - poking a store should be done from an async action - FlairStore.refreshGroupProfile(this._matrixClient, this.props.groupId); - } - }).catch((e) => { - this.setState({ - saving: false, - }); - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - logger.error("Failed to save community profile", e); - Modal.createTrackedDialog('Failed to update group', '', ErrorDialog, { - title: _t('Error'), - description: _t('Failed to update community'), - }); - }).finally(() => { - this.setState({ - avatarChanged: false, - }); - }); - }; - - async _saveGroup() { - await this._matrixClient.setGroupProfile(this.props.groupId, this.state.profileForm); - await this._matrixClient.setGroupJoinPolicy(this.props.groupId, { - type: this.state.joinableForm.policyType, - }); - } - - _onAcceptInviteClick = async () => { - this.setState({ membershipBusy: true }); - - // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the - // spinner disappearing after we have fetched new group data. - await sleep(500); - - GroupStore.acceptGroupInvite(this.props.groupId).then(() => { - // don't reset membershipBusy here: wait for the membership change to come down the sync - }).catch((e) => { - this.setState({ membershipBusy: false }); - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Error accepting invite', '', ErrorDialog, { - title: _t("Error"), - description: _t("Unable to accept invite"), - }); - }); - }; - - _onRejectInviteClick = async () => { - this.setState({ membershipBusy: true }); - - // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the - // spinner disappearing after we have fetched new group data. - await sleep(500); - - GroupStore.leaveGroup(this.props.groupId).then(() => { - // don't reset membershipBusy here: wait for the membership change to come down the sync - }).catch((e) => { - this.setState({ membershipBusy: false }); - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Error rejecting invite', '', ErrorDialog, { - title: _t("Error"), - description: _t("Unable to reject invite"), - }); - }); - }; - - _onJoinClick = async () => { - if (this._matrixClient.isGuest()) { - dis.dispatch({ action: 'require_registration', screen_after: { screen: `group/${this.props.groupId}` } }); - return; - } - - this.setState({ membershipBusy: true }); - - // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the - // spinner disappearing after we have fetched new group data. - await sleep(500); - - GroupStore.joinGroup(this.props.groupId).then(() => { - // don't reset membershipBusy here: wait for the membership change to come down the sync - }).catch((e) => { - this.setState({ membershipBusy: false }); - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Error joining room', '', ErrorDialog, { - title: _t("Error"), - description: _t("Unable to join community"), - }); - }); - }; - - _leaveGroupWarnings() { - const warnings = []; - - if (this.state.isUserPrivileged) { - warnings.push(( - - { " " /* Whitespace, otherwise the sentences get smashed together */ } - { _t("You are an administrator of this community. You will not be " + - "able to rejoin without an invite from another administrator.") } - - )); - } - - return warnings; - } - - _onLeaveClick = () => { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); - const warnings = this._leaveGroupWarnings(); - - Modal.createTrackedDialog('Leave Group', '', QuestionDialog, { - title: _t("Leave Community"), - description: ( - - { _t("Leave %(groupName)s?", { groupName: this.props.groupId }) } - { warnings } - - ), - button: _t("Leave"), - danger: this.state.isUserPrivileged, - onFinished: async (confirmed) => { - if (!confirmed) return; - - this.setState({ membershipBusy: true }); - - // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the - // spinner disappearing after we have fetched new group data. - await sleep(500); - - GroupStore.leaveGroup(this.props.groupId).then(() => { - // don't reset membershipBusy here: wait for the membership change to come down the sync - }).catch((e) => { - this.setState({ membershipBusy: false }); - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Error leaving community', '', ErrorDialog, { - title: _t("Error"), - description: _t("Unable to leave community"), - }); - }); - }, - }); - }; - - _onAddRoomsClick = () => { - showGroupAddRoomDialog(this.props.groupId); - }; - - _dismissUpgradeNotice = () => { - localStorage.setItem(UPGRADE_NOTICE_LS_KEY, "true"); - this.setState({ showUpgradeNotice: false }); - }; - - _onCreateSpaceClick = () => { - createSpaceFromCommunity(this._matrixClient, this.props.groupId); - }; - - _onAdminsLinkClick = () => { - RightPanelStore.instance.setCard({ phase: RightPanelPhases.GroupMemberList }); - }; - - _getGroupSection() { - const groupSettingsSectionClasses = classnames({ - "mx_GroupView_group": this.state.editing, - "mx_GroupView_group_disabled": this.state.editing && !this.state.isUserPrivileged, - }); - - const header = this.state.editing ?

{ _t('Community Settings') }

:
; - - const hostingSignupLink = getHostingLink('community-settings'); - let hostingSignup = null; - if (hostingSignupLink && this.state.isUserPrivileged) { - hostingSignup =
- { _t( - "Want more than a community? Get your own server", {}, - { - a: sub => { sub }, - }, - ) } - - - -
; - } - - const changeDelayWarning = this.state.editing && this.state.isUserPrivileged ? -
- { _t( - 'Changes made to your community name and avatar ' + - 'might not be seen by other users for up to 30 minutes.', - {}, - { - 'bold1': (sub) => { sub } , - 'bold2': (sub) => { sub } , - }, - ) } -
:
; - - let communitiesUpgradeNotice; - if (this.state.showUpgradeNotice) { - let text; - if (this.state.isUserPrivileged) { - text = _t("You can create a Space from this community here.", {}, { - a: sub => - { sub } - , - }); - } else { - text = _t("Ask the admins of this community to make it into a Space " + - "and keep a look out for the invite.", {}, { - a: sub => - { sub } - , - }); - } - - communitiesUpgradeNotice =
-

{ _t("Communities can now be made into Spaces") }

-

- { _t("Spaces are a new way to make a community, with new features coming.") } -   - { text } -   - { _t("Communities won't receive further updates.") } -

- -
; - } - - return
- { header } - { hostingSignup } - { changeDelayWarning } - { communitiesUpgradeNotice } - { this._getJoinableNode() } - { this._getLongDescriptionNode() } - { this._getRoomsNode() } -
; - } - - _getRoomsNode() { - const RoomDetailList = sdk.getComponent('rooms.RoomDetailList'); - const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - const Spinner = sdk.getComponent('elements.Spinner'); - const TooltipButton = sdk.getComponent('elements.TooltipButton'); - - const roomsHelpNode = this.state.editing ? :
; - - const addRoomRow = this.state.editing ? - ( -
- -
-
- { _t('Add rooms to this community') } -
-
) :
; - - return
-
-

- { _t('Rooms') } - { roomsHelpNode } -

- { addRoomRow } -
- { this.state.groupRoomsLoading ? - : - - } -
; - } - - _getFeaturedRoomsNode() { - const summary = this.state.summary; - - const defaultCategoryRooms = []; - const categoryRooms = {}; - summary.rooms_section.rooms.forEach((r) => { - if (r.category_id === null) { - defaultCategoryRooms.push(r); - } else { - let list = categoryRooms[r.category_id]; - if (list === undefined) { - list = []; - categoryRooms[r.category_id] = list; - } - list.push(r); - } - }); - - const defaultCategoryNode = ; - const categoryRoomNodes = Object.keys(categoryRooms).map((catId) => { - const cat = summary.rooms_section.categories[catId]; - return ; - }); - - return
-
- { _t('Featured Rooms:') } -
- { defaultCategoryNode } - { categoryRoomNodes } -
; - } - - _getFeaturedUsersNode() { - const summary = this.state.summary; - - const noRoleUsers = []; - const roleUsers = {}; - summary.users_section.users.forEach((u) => { - if (u.role_id === null) { - noRoleUsers.push(u); - } else { - let list = roleUsers[u.role_id]; - if (list === undefined) { - list = []; - roleUsers[u.role_id] = list; - } - list.push(u); - } - }); - - const noRoleNode = ; - const roleUserNodes = Object.keys(roleUsers).map((roleId) => { - const role = summary.users_section.roles[roleId]; - return ; - }); - - return
-
- { _t('Featured Users:') } -
- { noRoleNode } - { roleUserNodes } -
; - } - - _getMembershipSection() { - const Spinner = sdk.getComponent("elements.Spinner"); - const BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); - - const group = this._matrixClient.getGroup(this.props.groupId); - - if (group && group.myMembership === 'invite') { - if (this.state.membershipBusy || this.state.inviterProfileBusy) { - return
- -
; - } - const httpInviterAvatar = this.state.inviterProfile && this.state.inviterProfile.avatarUrl - ? mediaFromMxc(this.state.inviterProfile.avatarUrl).getSquareThumbnailHttp(36) - : null; - - const inviter = group.inviter || {}; - let inviterName = inviter.userId; - if (this.state.inviterProfile) { - inviterName = this.state.inviterProfile.displayName || inviter.userId; - } - return
-
-
- - { _t("%(inviter)s has invited you to join this community", { - inviter: inviterName || _t("Someone"), - }) } -
-
- - { _t("Accept") } - - - { _t("Decline") } - -
-
-
; - } - - let membershipContainerExtraClasses; - let membershipButtonExtraClasses; - let membershipButtonTooltip; - let membershipButtonText; - let membershipButtonOnClick; - - // User is not in the group - if ((!group || group.myMembership === 'leave') && - this.state.summary && - this.state.summary.profile && - Boolean(this.state.summary.profile.is_openly_joinable) - ) { - membershipButtonText = _t("Join this community"); - membershipButtonOnClick = this._onJoinClick; - - membershipButtonExtraClasses = 'mx_GroupView_joinButton'; - membershipContainerExtraClasses = 'mx_GroupView_membershipSection_leave'; - } else if ( - group && - group.myMembership === 'join' && - this.state.editing - ) { - membershipButtonText = _t("Leave this community"); - membershipButtonOnClick = this._onLeaveClick; - membershipButtonTooltip = this.state.isUserPrivileged ? - _t("You are an administrator of this community") : - _t("You are a member of this community"); - - membershipButtonExtraClasses = { - 'mx_GroupView_leaveButton': true, - 'mx_RoomHeader_textButton_danger': this.state.isUserPrivileged, - }; - membershipContainerExtraClasses = 'mx_GroupView_membershipSection_joined'; - } else { - return null; - } - - const membershipButtonClasses = classnames( - [ - 'mx_RoomHeader_textButton', - 'mx_GroupView_textButton', - ], - membershipButtonExtraClasses, - ); - - const membershipContainerClasses = classnames( - 'mx_GroupView_membershipSection', - membershipContainerExtraClasses, - ); - - return
-
- { /* The
is for flex alignment */ } - { this.state.membershipBusy ? :
} -
- - { membershipButtonText } - -
-
-
; - } - - _getJoinableNode() { - const InlineSpinner = sdk.getComponent('elements.InlineSpinner'); - return this.state.editing ?
-

- { _t('Who can join this community?') } - { this.state.groupJoinableLoading ? - :
- } -

-
- -
-
- -
-
: null; - } - - _getLongDescriptionNode() { - const summary = this.state.summary; - let description = null; - if (summary.profile && summary.profile.long_description) { - description = sanitizedHtmlNode(summary.profile.long_description); - } else if (this.state.isUserPrivileged) { - description =
- { _t( - 'Your community hasn\'t got a Long Description, a HTML page to show to community members.
' + - 'Click here to open settings and give it one!', - {}, - { 'br':
}, - ) } -
; - } - const groupDescEditingClasses = classnames({ - "mx_GroupView_groupDesc": true, - "mx_GroupView_groupDesc_disabled": !this.state.isUserPrivileged, - }); - - return this.state.editing ? -
-

{ _t("Long Description (HTML)") }

-