From ae5cd9d7ac058f051454ace44b3d114908537e66 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 17 Jun 2021 14:11:44 +0100 Subject: [PATCH 01/29] Add new layout switcher UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Quirin Götz --- .../tabs/user/AppearanceUserSettingsTab.tsx | 110 ++++++++++++++++-- src/settings/Layout.ts | 4 +- src/settings/Settings.tsx | 8 ++ .../NewLayoutSwitcherController.ts | 26 +++++ 4 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 src/settings/controllers/NewLayoutSwitcherController.ts diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx index 9e27ed968e..bc31f750c3 100644 --- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx @@ -37,6 +37,8 @@ import StyledRadioGroup from "../../../elements/StyledRadioGroup"; import { SettingLevel } from "../../../../../settings/SettingLevel"; import { UIFeature } from "../../../../../settings/UIFeature"; import { Layout } from "../../../../../settings/Layout"; +import classNames from 'classnames'; +import StyledRadioButton from '../../../elements/StyledRadioButton'; import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import { compare } from "../../../../../utils/strings"; @@ -235,6 +237,19 @@ export default class AppearanceUserSettingsTab extends React.Component): void => { + let layout; + switch (e.target.value) { + case "irc": layout = Layout.IRC; break; + case "group": layout = Layout.Group; break; + case "bubble": layout = Layout.Bubble; break; + } + + this.setState({ layout: layout }); + + SettingsStore.setValue("layout", null, SettingLevel.DEVICE, layout); + }; + private onIRCLayoutChange = (enabled: boolean) => { if (enabled) { this.setState({layout: Layout.IRC}); @@ -367,6 +382,77 @@ export default class AppearanceUserSettingsTab extends React.Component; } + private renderLayoutSection = () => { + return
+ { _t("Message layout") } + +
+
+ + + { "IRC" } + +
+
+
+ + + {_t("Modern")} + +
+
+
+ + + {_t("Message bubbles")} + +
+
+
; + } + private renderAdvancedSection() { if (!SettingsStore.getValue(UIFeature.AdvancedSettings)) return null; @@ -390,14 +476,17 @@ export default class AppearanceUserSettingsTab extends React.Component - this.onIRCLayoutChange(ev.target.checked)} - > - {_t("Enable experimental, compact IRC style layout")} - + + { !SettingsStore.getValue("feature_new_layout_switcher") ? + this.onIRCLayoutChange(ev.target.checked)} + > + {_t("Enable experimental, compact IRC style layout")} + : null + } {_t("Appearance Settings only affect this %(brand)s session.", { brand })}
- {this.renderThemeSection()} - {this.renderFontSection()} - {this.renderAdvancedSection()} + { this.renderThemeSection() } + { SettingsStore.getValue("feature_new_layout_switcher") ? this.renderLayoutSection() : null } + { this.renderFontSection() } + { this.renderAdvancedSection() }
); } diff --git a/src/settings/Layout.ts b/src/settings/Layout.ts index 3a42b2b510..d4e1f06c0a 100644 --- a/src/settings/Layout.ts +++ b/src/settings/Layout.ts @@ -1,5 +1,6 @@ /* Copyright 2021 Šimon Brandner +Copyright 2021 Quirin Götz Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,7 +20,8 @@ import PropTypes from 'prop-types'; /* TODO: This should be later reworked into something more generic */ export enum Layout { IRC = "irc", - Group = "group" + Group = "group", + Bubble = "bubble", } /* We need this because multiple components are still using JavaScript */ diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 155d039572..87edf886e0 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -41,6 +41,7 @@ import { Layout } from "./Layout"; import ReducedMotionController from './controllers/ReducedMotionController'; import IncompatibleController from "./controllers/IncompatibleController"; import SdkConfig from "../SdkConfig"; +import NewLayoutSwitcherController from './controllers/NewLayoutSwitcherController'; // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times const LEVELS_ROOM_SETTINGS = [ @@ -285,6 +286,13 @@ export const SETTINGS: {[setting: string]: ISetting} = { displayName: _td("Show info about bridges in room settings"), default: false, }, + "feature_new_layout_switcher": { + isFeature: true, + supportedLevels: LEVELS_FEATURE, + displayName: _td("Explore new ways switching layouts (including a new bubble layout)"), + default: false, + controller: new NewLayoutSwitcherController(), + }, "RoomList.backgroundImage": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, default: null, diff --git a/src/settings/controllers/NewLayoutSwitcherController.ts b/src/settings/controllers/NewLayoutSwitcherController.ts new file mode 100644 index 0000000000..b1d6cac55e --- /dev/null +++ b/src/settings/controllers/NewLayoutSwitcherController.ts @@ -0,0 +1,26 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import SettingController from "./SettingController"; +import { SettingLevel } from "../SettingLevel"; +import SettingsStore from "../SettingsStore"; +import { Layout } from "../Layout"; + +export default class NewLayoutSwitcherController extends SettingController { + public onChange(level: SettingLevel, roomId: string, newValue: any) { + // On disabling switch back to Layout.Group if Layout.Bubble + if (!newValue && SettingsStore.getValue("layout") == Layout.Bubble) { + SettingsStore.setValue("layout", null, SettingLevel.DEVICE, Layout.Group); + } + } +} From 6271c5c3d8344e1c135f8f0736089e5d9945f39d Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 18 Jun 2021 18:59:22 +0100 Subject: [PATCH 02/29] first iteration for message bubble layout --- res/css/_components.scss | 1 + res/css/views/messages/_MImageBody.scss | 1 - res/css/views/messages/_ReactionsRow.scss | 1 + res/css/views/rooms/_EventBubbleTile.scss | 149 ++++ res/css/views/rooms/_EventTile.scss | 769 +++++++++--------- .../views/elements/EventListSummary.tsx | 8 +- src/components/views/messages/UnknownBody.js | 3 +- src/components/views/rooms/EventTile.tsx | 17 +- 8 files changed, 559 insertions(+), 390 deletions(-) create mode 100644 res/css/views/rooms/_EventBubbleTile.scss diff --git a/res/css/_components.scss b/res/css/_components.scss index 56403ea190..67831e4a60 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -194,6 +194,7 @@ @import "./views/rooms/_EditMessageComposer.scss"; @import "./views/rooms/_EntityTile.scss"; @import "./views/rooms/_EventTile.scss"; +@import "./views/rooms/_EventBubbleTile.scss"; @import "./views/rooms/_GroupLayout.scss"; @import "./views/rooms/_IRCLayout.scss"; @import "./views/rooms/_JumpToBottomButton.scss"; diff --git a/res/css/views/messages/_MImageBody.scss b/res/css/views/messages/_MImageBody.scss index 1c773c2f06..6ac6767ffa 100644 --- a/res/css/views/messages/_MImageBody.scss +++ b/res/css/views/messages/_MImageBody.scss @@ -16,7 +16,6 @@ limitations under the License. .mx_MImageBody { display: block; - margin-right: 34px; } .mx_MImageBody_thumbnail { diff --git a/res/css/views/messages/_ReactionsRow.scss b/res/css/views/messages/_ReactionsRow.scss index e05065eb02..b2bca6dfb3 100644 --- a/res/css/views/messages/_ReactionsRow.scss +++ b/res/css/views/messages/_ReactionsRow.scss @@ -26,6 +26,7 @@ limitations under the License. height: 24px; vertical-align: middle; margin-left: 4px; + margin-right: 4px; &::before { content: ''; diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss new file mode 100644 index 0000000000..28dce730ff --- /dev/null +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -0,0 +1,149 @@ +/* +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_EventTile[data-layout=bubble] { + + --avatarSize: 32px; + --gutterSize: 7px; + --cornerRadius: 5px; + + --maxWidth: 70%; + + position: relative; + margin-top: var(--gutterSize); + margin-left: var(--avatarSize); + margin-right: var(--avatarSize); + padding: 2px 0; + + &:hover { + background: rgb(242, 242, 242); + } + + .mx_SenderProfile, + .mx_EventTile_line { + width: fit-content; + max-width: 70%; + background: var(--backgroundColor); + } + + .mx_SenderProfile { + display: none; + padding: var(--gutterSize) var(--gutterSize) 0 var(--gutterSize); + border-top-left-radius: var(--cornerRadius); + border-top-right-radius: var(--cornerRadius); + } + + .mx_EventTile_line { + padding: var(--gutterSize); + border-radius: var(--cornerRadius); + } + + /* + .mx_SenderProfile + .mx_EventTile_line { + padding-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + */ + + .mx_EventTile_avatar { + position: absolute; + top: 0; + img { + border: 2px solid #fff; + border-radius: 50%; + } + } + + &[data-self=true] { + .mx_EventTile_line { + float: right; + } + .mx_ReactionsRow { + float: right; + clear: right; + display: flex; + + /* Moving the "add reaction button" before the reactions */ + > :last-child { + order: -1; + } + } + .mx_EventTile_avatar { + right: calc(-1 * var(--avatarSize)); + } + --backgroundColor: #F8FDFC; + } + + &:not([data-self=true]) { + .mx_EventTile_avatar { + left: calc(-1 * var(--avatarSize)); + } + --backgroundColor: #F7F8F9; + } + + &.mx_EventTile_bubbleContainer, + &.mx_EventTile_info, + & ~ .mx_EventListSummary[data-expanded=false] { + + --backgroundColor: transparent; + + display: flex; + align-items: center; + justify-content: center; + + .mx_EventTile_avatar { + position: static; + order: -1; + } + } + + & ~ .mx_EventListSummary { + --maxWidth: 95%; + .mx_EventListSummary_toggle { + float: none; + margin: 0; + order: 9; + } + } + + & + .mx_EventListSummary { + .mx_EventTile { + margin-top: 0; + padding: 0; + } + } + + .mx_EventListSummary_toggle { + margin-right: 55px; + } + + .mx_EventTile_line { + display: flex; + gap: var(--gutterSize); + > a { + order: 999; /* always display the timestamp as the last item */ + align-self: flex-end; + } + } + + .mx_EventTile_readAvatars { + position: absolute; + right: 0; + bottom: 0; + } + +} diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 3af266caee..303118d57c 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -1,6 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd -Copyright 2020 The Matrix.org Foundation C.I.C. +Copyright 2020-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. @@ -18,101 +18,382 @@ limitations under the License. $left-gutter: 64px; $hover-select-border: 4px; -.mx_EventTile { +.mx_EventTile:not([data-layout=bubble]) { max-width: 100%; clear: both; padding-top: 18px; font-size: $font-14px; position: relative; -} -.mx_EventTile.mx_EventTile_info { - padding-top: 1px; -} - -.mx_EventTile_avatar { - top: 14px; - left: 8px; - cursor: pointer; - user-select: none; -} - -.mx_EventTile.mx_EventTile_info .mx_EventTile_avatar { - top: $font-6px; - left: $left-gutter; -} - -.mx_EventTile_continuation { - padding-top: 0px !important; - - &.mx_EventTile_isEditing { - padding-top: 5px !important; - margin-top: -5px; + .mx_EventTile.mx_EventTile_info { + padding-top: 1px; } -} -.mx_EventTile_isEditing { - background-color: $header-panel-bg-color; -} + .mx_EventTile_avatar { + top: 14px; + left: 8px; + cursor: pointer; + user-select: none; + } -.mx_EventTile .mx_SenderProfile { - color: $primary-fg-color; - font-size: $font-14px; - display: inline-block; /* anti-zalgo, with overflow hidden */ - overflow: hidden; - cursor: pointer; - padding-bottom: 0px; - padding-top: 0px; - margin: 0px; - /* the next three lines, along with overflow hidden, truncate long display names */ - white-space: nowrap; - text-overflow: ellipsis; - max-width: calc(100% - $left-gutter); -} + .mx_EventTile.mx_EventTile_info .mx_EventTile_avatar { + top: $font-6px; + left: $left-gutter; + } -.mx_EventTile .mx_SenderProfile .mx_Flair { - opacity: 0.7; - margin-left: 5px; - display: inline-block; - vertical-align: top; - overflow: hidden; - user-select: none; + .mx_EventTile_continuation { + padding-top: 0px !important; - img { - vertical-align: -2px; - margin-right: 2px; + &.mx_EventTile_isEditing { + padding-top: 5px !important; + margin-top: -5px; + } + } + + .mx_EventTile_isEditing { + background-color: $header-panel-bg-color; + } + + .mx_EventTile .mx_SenderProfile { + color: $primary-fg-color; + font-size: $font-14px; + display: inline-block; /* anti-zalgo, with overflow hidden */ + overflow: hidden; + cursor: pointer; + padding-bottom: 0px; + padding-top: 0px; + margin: 0px; + /* the next three lines, along with overflow hidden, truncate long display names */ + white-space: nowrap; + text-overflow: ellipsis; + max-width: calc(100% - $left-gutter); + } + + .mx_EventTile .mx_SenderProfile .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_EventTile_isEditing .mx_MessageTimestamp { + visibility: hidden; + } + + .mx_EventTile .mx_MessageTimestamp { + display: block; + white-space: nowrap; + left: 0px; + text-align: center; + user-select: none; + } + + .mx_EventTile_continuation .mx_EventTile_line { + clear: both; + } + + .mx_EventTile_line, .mx_EventTile_reply { + position: relative; + padding-left: $left-gutter; border-radius: 8px; } -} -.mx_EventTile_isEditing .mx_MessageTimestamp { - visibility: hidden; -} + .mx_RoomView_timeline_rr_enabled, + // on ELS we need the margin to allow interaction with the expand/collapse button which is normally in the RR gutter + .mx_EventListSummary { + .mx_EventTile_line { + /* ideally should be 100px, but 95px gives us a max thumbnail size of 800x600, which is nice */ + margin-right: 110px; + } + } -.mx_EventTile .mx_MessageTimestamp { - display: block; - white-space: nowrap; - left: 0px; - text-align: center; - user-select: none; -} + .mx_EventTile_reply { + margin-right: 10px; + } -.mx_EventTile_continuation .mx_EventTile_line { - clear: both; -} + .mx_EventTile_selected > div > a > .mx_MessageTimestamp { + left: calc(-$hover-select-border); + } -.mx_EventTile_line, .mx_EventTile_reply { - position: relative; - padding-left: $left-gutter; - border-radius: 8px; -} + .mx_EventTile:hover .mx_MessageActionBar, + .mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar, + [data-whatinput='keyboard'] .mx_EventTile:focus-within .mx_MessageActionBar, + .mx_EventTile.focus-visible:focus-within .mx_MessageActionBar { + visibility: visible; + } -.mx_RoomView_timeline_rr_enabled, -// on ELS we need the margin to allow interaction with the expand/collapse button which is normally in the RR gutter -.mx_EventListSummary { - .mx_EventTile_line { - /* ideally should be 100px, but 95px gives us a max thumbnail size of 800x600, which is nice */ - margin-right: 110px; + /* this is used for the tile for the event which is selected via the URL. + * TODO: ultimately we probably want some transition on here. + */ + .mx_EventTile_selected > .mx_EventTile_line { + border-left: $accent-color 4px solid; + padding-left: calc($left-gutter - $hover-select-border); + background-color: $event-selected-color; + } + + .mx_EventTile_highlight, + .mx_EventTile_highlight .markdown-body { + color: $event-highlight-fg-color; + + .mx_EventTile_line { + background-color: $event-highlight-bg-color; + } + } + + .mx_EventTile_info .mx_EventTile_line { + padding-left: calc($left-gutter + 18px); + } + + .mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line { + padding-left: calc($left-gutter + 18px - $hover-select-border); + } + + .mx_EventTile:hover .mx_EventTile_line, + .mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line, + .mx_EventTile.focus-visible:focus-within .mx_EventTile_line { + background-color: $event-selected-color; + } + + .mx_EventTile_searchHighlight { + background-color: $accent-color; + color: $accent-fg-color; + border-radius: 5px; + padding-left: 2px; + padding-right: 2px; + cursor: pointer; + } + + .mx_EventTile_searchHighlight a { + background-color: $accent-color; + color: $accent-fg-color; + } + + .mx_EventTile_receiptSent, + .mx_EventTile_receiptSending { + // We don't use `position: relative` on the element because then it won't line + // up with the other read receipts + + &::before { + background-color: $tertiary-fg-color; + mask-repeat: no-repeat; + mask-position: center; + mask-size: 14px; + width: 14px; + height: 14px; + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + } + } + .mx_EventTile_receiptSent::before { + mask-image: url('$(res)/img/element-icons/circle-sent.svg'); + } + .mx_EventTile_receiptSending::before { + mask-image: url('$(res)/img/element-icons/circle-sending.svg'); + } + + .mx_EventTile_contextual { + opacity: 0.4; + } + + .mx_EventTile_msgOption { + float: right; + text-align: right; + position: relative; + width: 90px; + + /* Hack to stop the height of this pushing the messages apart. + Replaces margin-top: -6px. This interacts better with a read + marker being in between. Content overflows. */ + height: 1px; + + margin-right: 10px; + } + + .mx_EventTile_msgOption a { + text-decoration: none; + } + + /* all the overflow-y: hidden; are to trap Zalgos - + but they introduce an implicit overflow-x: auto. + so make that explicitly hidden too to avoid random + horizontal scrollbars occasionally appearing, like in + https://github.com/vector-im/vector-web/issues/1154 + */ + .mx_EventTile_content { + display: block; + overflow-y: hidden; + overflow-x: hidden; + margin-right: 34px; + } + + /* De-zalgoing */ + .mx_EventTile_body { + overflow-y: hidden; + } + + /* Spoiler stuff */ + .mx_EventTile_spoiler { + cursor: pointer; + } + + .mx_EventTile_spoiler_reason { + color: $event-timestamp-color; + font-size: $font-11px; + } + + .mx_EventTile_spoiler_content { + filter: blur(5px) saturate(0.1) sepia(1); + transition-duration: 0.5s; + } + + .mx_EventTile_spoiler.visible > .mx_EventTile_spoiler_content { + filter: none; + } + + .mx_EventTile_e2eIcon { + position: absolute; + top: 6px; + left: 44px; + width: 14px; + height: 14px; + display: block; + bottom: 0; + right: 0; + opacity: 0.2; + background-repeat: no-repeat; + background-size: contain; + + &::before, &::after { + content: ""; + display: block; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + + &::before { + background-color: #ffffff; + mask-image: url('$(res)/img/e2e/normal.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: 90%; + } + } + + .mx_EventTile_e2eIcon_undecryptable, .mx_EventTile_e2eIcon_unverified { + &::after { + mask-image: url('$(res)/img/e2e/warning.svg'); + background-color: $notice-primary-color; + } + opacity: 1; + } + + .mx_EventTile_e2eIcon_unknown { + &::after { + mask-image: url('$(res)/img/e2e/warning.svg'); + background-color: $notice-primary-color; + } + opacity: 1; + } + + .mx_EventTile_e2eIcon_unencrypted { + &::after { + mask-image: url('$(res)/img/e2e/warning.svg'); + background-color: $notice-primary-color; + } + opacity: 1; + } + + .mx_EventTile_e2eIcon_unauthenticated { + &::after { + mask-image: url('$(res)/img/e2e/normal.svg'); + background-color: $composer-e2e-icon-color; + } + opacity: 1; + } + + .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line, + .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line, + .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line { + padding-left: calc($left-gutter - $hover-select-border); + } + + .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line { + border-left: $e2e-verified-color $EventTile_e2e_state_indicator_width solid; + } + + .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line { + border-left: $e2e-unverified-color $EventTile_e2e_state_indicator_width solid; + } + + .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line { + border-left: $e2e-unknown-color $EventTile_e2e_state_indicator_width solid; + } + + .mx_EventTile:hover.mx_EventTile_verified.mx_EventTile_info .mx_EventTile_line, + .mx_EventTile:hover.mx_EventTile_unverified.mx_EventTile_info .mx_EventTile_line, + .mx_EventTile:hover.mx_EventTile_unknown.mx_EventTile_info .mx_EventTile_line { + padding-left: calc($left-gutter + 18px - $hover-select-border); + } + + /* End to end encryption stuff */ + .mx_EventTile:hover .mx_EventTile_e2eIcon { + opacity: 1; + } + + // Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies) + .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line > a > .mx_MessageTimestamp, + .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line > a > .mx_MessageTimestamp, + .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line > a > .mx_MessageTimestamp { + left: calc(-$hover-select-border); + } + + // Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies) + .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line > .mx_EventTile_e2eIcon, + .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line > .mx_EventTile_e2eIcon, + .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line > .mx_EventTile_e2eIcon { + display: block; + left: 41px; + } + + .mx_EventTile_tileError { + color: red; + text-align: center; + + // Remove some of the default tile padding so that the error is centered + margin-right: 0; + .mx_EventTile_line { + padding-left: 0; + margin-right: 0; + } + + .mx_EventTile_line span { + padding: 4px 8px; + } + + a { + margin-left: 1em; + } + } + + .mx_MImageBody { + margin-right: 34px; } } @@ -132,121 +413,6 @@ $hover-select-border: 4px; } } -.mx_EventTile_reply { - margin-right: 10px; -} - -/* HACK to override line-height which is already marked important elsewhere */ -.mx_EventTile_bigEmoji.mx_EventTile_bigEmoji { - font-size: 48px !important; - line-height: 57px !important; -} - -.mx_EventTile_selected > div > a > .mx_MessageTimestamp { - left: calc(-$hover-select-border); -} - -.mx_EventTile:hover .mx_MessageActionBar, -.mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar, -[data-whatinput='keyboard'] .mx_EventTile:focus-within .mx_MessageActionBar, -.mx_EventTile.focus-visible:focus-within .mx_MessageActionBar { - visibility: visible; -} - -/* this is used for the tile for the event which is selected via the URL. - * TODO: ultimately we probably want some transition on here. - */ -.mx_EventTile_selected > .mx_EventTile_line { - border-left: $accent-color 4px solid; - padding-left: calc($left-gutter - $hover-select-border); - background-color: $event-selected-color; -} - -.mx_EventTile_highlight, -.mx_EventTile_highlight .markdown-body { - color: $event-highlight-fg-color; - - .mx_EventTile_line { - background-color: $event-highlight-bg-color; - } -} - -.mx_EventTile_info .mx_EventTile_line { - padding-left: calc($left-gutter + 18px); -} - -.mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line { - padding-left: calc($left-gutter + 18px - $hover-select-border); -} - -.mx_EventTile:hover .mx_EventTile_line, -.mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line, -.mx_EventTile.focus-visible:focus-within .mx_EventTile_line { - background-color: $event-selected-color; -} - -.mx_EventTile_searchHighlight { - background-color: $accent-color; - color: $accent-fg-color; - border-radius: 5px; - padding-left: 2px; - padding-right: 2px; - cursor: pointer; -} - -.mx_EventTile_searchHighlight a { - background-color: $accent-color; - color: $accent-fg-color; -} - -.mx_EventTile_receiptSent, -.mx_EventTile_receiptSending { - // We don't use `position: relative` on the element because then it won't line - // up with the other read receipts - - &::before { - background-color: $tertiary-fg-color; - mask-repeat: no-repeat; - mask-position: center; - mask-size: 14px; - width: 14px; - height: 14px; - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - } -} -.mx_EventTile_receiptSent::before { - mask-image: url('$(res)/img/element-icons/circle-sent.svg'); -} -.mx_EventTile_receiptSending::before { - mask-image: url('$(res)/img/element-icons/circle-sending.svg'); -} - -.mx_EventTile_contextual { - opacity: 0.4; -} - -.mx_EventTile_msgOption { - float: right; - text-align: right; - position: relative; - width: 90px; - - /* Hack to stop the height of this pushing the messages apart. - Replaces margin-top: -6px. This interacts better with a read - marker being in between. Content overflows. */ - height: 1px; - - margin-right: 10px; -} - -.mx_EventTile_msgOption a { - text-decoration: none; -} - .mx_EventTile_readAvatars { position: relative; display: inline-block; @@ -277,180 +443,10 @@ $hover-select-border: 4px; position: absolute; } -/* all the overflow-y: hidden; are to trap Zalgos - - but they introduce an implicit overflow-x: auto. - so make that explicitly hidden too to avoid random - horizontal scrollbars occasionally appearing, like in - https://github.com/vector-im/vector-web/issues/1154 - */ -.mx_EventTile_content { - display: block; - overflow-y: hidden; - overflow-x: hidden; - margin-right: 34px; -} - -/* De-zalgoing */ -.mx_EventTile_body { - overflow-y: hidden; -} - -/* Spoiler stuff */ -.mx_EventTile_spoiler { - cursor: pointer; -} - -.mx_EventTile_spoiler_reason { - color: $event-timestamp-color; - font-size: $font-11px; -} - -.mx_EventTile_spoiler_content { - filter: blur(5px) saturate(0.1) sepia(1); - transition-duration: 0.5s; -} - -.mx_EventTile_spoiler.visible > .mx_EventTile_spoiler_content { - filter: none; -} - -.mx_EventTile_e2eIcon { - position: absolute; - top: 6px; - left: 44px; - width: 14px; - height: 14px; - display: block; - bottom: 0; - right: 0; - opacity: 0.2; - background-repeat: no-repeat; - background-size: contain; - - &::before, &::after { - content: ""; - display: block; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - mask-repeat: no-repeat; - mask-position: center; - mask-size: contain; - } - - &::before { - background-color: #ffffff; - mask-image: url('$(res)/img/e2e/normal.svg'); - mask-repeat: no-repeat; - mask-position: center; - mask-size: 90%; - } -} - -.mx_EventTile_e2eIcon_undecryptable, .mx_EventTile_e2eIcon_unverified { - &::after { - mask-image: url('$(res)/img/e2e/warning.svg'); - background-color: $notice-primary-color; - } - opacity: 1; -} - -.mx_EventTile_e2eIcon_unknown { - &::after { - mask-image: url('$(res)/img/e2e/warning.svg'); - background-color: $notice-primary-color; - } - opacity: 1; -} - -.mx_EventTile_e2eIcon_unencrypted { - &::after { - mask-image: url('$(res)/img/e2e/warning.svg'); - background-color: $notice-primary-color; - } - opacity: 1; -} - -.mx_EventTile_e2eIcon_unauthenticated { - &::after { - mask-image: url('$(res)/img/e2e/normal.svg'); - background-color: $composer-e2e-icon-color; - } - opacity: 1; -} - -.mx_EventTile_keyRequestInfo { - font-size: $font-12px; -} - -.mx_EventTile_keyRequestInfo_text { - opacity: 0.5; -} - -.mx_EventTile_keyRequestInfo_text a { - color: $primary-fg-color; - text-decoration: underline; - cursor: pointer; -} - -.mx_EventTile_keyRequestInfo_tooltip_contents p { - text-align: auto; - margin-left: 3px; - margin-right: 3px; -} - -.mx_EventTile_keyRequestInfo_tooltip_contents p:first-child { - margin-top: 0px; -} - -.mx_EventTile_keyRequestInfo_tooltip_contents p:last-child { - margin-bottom: 0px; -} - -.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line, -.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line, -.mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line { - padding-left: calc($left-gutter - $hover-select-border); -} - -.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line { - border-left: $e2e-verified-color $EventTile_e2e_state_indicator_width solid; -} - -.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line { - border-left: $e2e-unverified-color $EventTile_e2e_state_indicator_width solid; -} - -.mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line { - border-left: $e2e-unknown-color $EventTile_e2e_state_indicator_width solid; -} - -.mx_EventTile:hover.mx_EventTile_verified.mx_EventTile_info .mx_EventTile_line, -.mx_EventTile:hover.mx_EventTile_unverified.mx_EventTile_info .mx_EventTile_line, -.mx_EventTile:hover.mx_EventTile_unknown.mx_EventTile_info .mx_EventTile_line { - padding-left: calc($left-gutter + 18px - $hover-select-border); -} - -/* End to end encryption stuff */ -.mx_EventTile:hover .mx_EventTile_e2eIcon { - opacity: 1; -} - -// Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies) -.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line > a > .mx_MessageTimestamp, -.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line > a > .mx_MessageTimestamp, -.mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line > a > .mx_MessageTimestamp { - left: calc(-$hover-select-border); -} - -// Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies) -.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line > .mx_EventTile_e2eIcon, -.mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line > .mx_EventTile_e2eIcon, -.mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line > .mx_EventTile_e2eIcon { - display: block; - left: 41px; +/* HACK to override line-height which is already marked important elsewhere */ +.mx_EventTile_bigEmoji.mx_EventTile_bigEmoji { + font-size: 48px !important; + line-height: 57px !important; } .mx_EventTile_content .mx_EventTile_edited { @@ -601,24 +597,33 @@ $hover-select-border: 4px; /* end of overrides */ -.mx_EventTile_tileError { - color: red; - text-align: center; - // Remove some of the default tile padding so that the error is centered - margin-right: 0; - .mx_EventTile_line { - padding-left: 0; - margin-right: 0; - } +.mx_EventTile_keyRequestInfo { + font-size: $font-12px; +} - .mx_EventTile_line span { - padding: 4px 8px; - } +.mx_EventTile_keyRequestInfo_text { + opacity: 0.5; +} - a { - margin-left: 1em; - } +.mx_EventTile_keyRequestInfo_text a { + color: $primary-fg-color; + text-decoration: underline; + cursor: pointer; +} + +.mx_EventTile_keyRequestInfo_tooltip_contents p { + text-align: auto; + margin-left: 3px; + margin-right: 3px; +} + +.mx_EventTile_keyRequestInfo_tooltip_contents p:first-child { + margin-top: 0px; +} + +.mx_EventTile_keyRequestInfo_tooltip_contents p:last-child { + margin-bottom: 0px; } @media only screen and (max-width: 480px) { diff --git a/src/components/views/elements/EventListSummary.tsx b/src/components/views/elements/EventListSummary.tsx index 86d3e082ad..3c64337367 100644 --- a/src/components/views/elements/EventListSummary.tsx +++ b/src/components/views/elements/EventListSummary.tsx @@ -63,7 +63,7 @@ const EventListSummary: React.FC = ({ // If we are only given few events then just pass them through if (events.length < threshold) { return ( -
  • +
  • { children }
  • ); @@ -92,7 +92,7 @@ const EventListSummary: React.FC = ({ } return ( -
  • +
  • { expanded ? _t('collapse') : _t('expand') } @@ -101,4 +101,8 @@ const EventListSummary: React.FC = ({ ); }; +EventListSummary.defaultProps = { + startExpanded: false, +}; + export default EventListSummary; diff --git a/src/components/views/messages/UnknownBody.js b/src/components/views/messages/UnknownBody.js index 786facc340..fdf0387a69 100644 --- a/src/components/views/messages/UnknownBody.js +++ b/src/components/views/messages/UnknownBody.js @@ -17,11 +17,12 @@ limitations under the License. import React, {forwardRef} from "react"; -export default forwardRef(({mxEvent}, ref) => { +export default forwardRef(({mxEvent, children}, ref) => { const text = mxEvent.getContent().body; return ( { text } + { children } ); }); diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 85b9cac2c4..a76cc04660 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -29,7 +29,7 @@ import { hasText } from "../../../TextForEvent"; import * as sdk from "../../../index"; import dis from '../../../dispatcher/dispatcher'; import SettingsStore from "../../../settings/SettingsStore"; -import {Layout} from "../../../settings/Layout"; +import { Layout } from "../../../settings/Layout"; import {formatTime} from "../../../DateUtils"; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {ALL_RULE_TYPES} from "../../../mjolnir/BanList"; @@ -988,8 +988,13 @@ export default class EventTile extends React.Component { onFocusChange={this.onActionBarFocusChange} /> : undefined; - const showTimestamp = this.props.mxEvent.getTs() && - (this.props.alwaysShowTimestamps || this.props.last || this.state.hover || this.state.actionBarFocused); + const showTimestamp = this.props.mxEvent.getTs() + && (this.props.alwaysShowTimestamps + || this.props.last + || this.state.hover + || this.state.actionBarFocused) + || this.props.layout === Layout.Bubble; + const timestamp = showTimestamp ? : null; @@ -1168,6 +1173,8 @@ export default class EventTile extends React.Component { this.props.alwaysShowTimestamps || this.state.hover, ); + const isOwnEvent = this.props.mxEvent.sender.userId === MatrixClientPeg.get().getUserId(); + // tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers return ( React.createElement(this.props.as || "li", { @@ -1177,6 +1184,8 @@ export default class EventTile extends React.Component { "aria-live": ariaLive, "aria-atomic": "true", "data-scroll-tokens": scrollToken, + "data-layout": this.props.layout, + "data-self": isOwnEvent, "onMouseEnter": () => this.setState({ hover: true }), "onMouseLeave": () => this.setState({ hover: false }), }, [ @@ -1198,9 +1207,9 @@ export default class EventTile extends React.Component { onHeightChanged={this.props.onHeightChanged} /> { keyRequestInfo } - { reactionsRow } { actionBar } , + reactionsRow, msgOption, avatar, From 6b9dfa37c5170ed4229eaf382b4bea1499d37f53 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 30 Jun 2021 09:00:14 +0100 Subject: [PATCH 03/29] Migrate UnknownBody to TypeScript --- .../views/messages/{UnknownBody.js => UnknownBody.tsx} | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) rename src/components/views/messages/{UnknownBody.js => UnknownBody.tsx} (78%) diff --git a/src/components/views/messages/UnknownBody.js b/src/components/views/messages/UnknownBody.tsx similarity index 78% rename from src/components/views/messages/UnknownBody.js rename to src/components/views/messages/UnknownBody.tsx index 78a1846b68..b09afa54e9 100644 --- a/src/components/views/messages/UnknownBody.js +++ b/src/components/views/messages/UnknownBody.tsx @@ -16,8 +16,14 @@ limitations under the License. */ import React, { forwardRef } from "react"; +import { MatrixEvent } from "matrix-js-sdk/src"; -export default forwardRef(({ mxEvent, children }, ref) => { +interface IProps { + mxEvent: MatrixEvent; + children?: React.ReactNode; +} + +export default forwardRef(({ mxEvent, children }: IProps, ref: React.RefObject) => { const text = mxEvent.getContent().body; return ( From d1c6cfe6b95c903c517cc52c31664a979d70153b Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 30 Jun 2021 12:06:16 +0100 Subject: [PATCH 04/29] Improved message bubble layout (no reply) --- res/css/views/avatars/_BaseAvatar.scss | 1 + res/css/views/rooms/_EventBubbleTile.scss | 51 +++++++++++++++++------ res/css/views/rooms/_EventTile.scss | 40 +++++++++--------- src/components/views/rooms/EventTile.tsx | 7 +++- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/res/css/views/avatars/_BaseAvatar.scss b/res/css/views/avatars/_BaseAvatar.scss index cbddd97e18..65e4493f19 100644 --- a/res/css/views/avatars/_BaseAvatar.scss +++ b/res/css/views/avatars/_BaseAvatar.scss @@ -27,6 +27,7 @@ limitations under the License. // https://bugzilla.mozilla.org/show_bug.cgi?id=255139 display: inline-block; user-select: none; + line-height: 1; } .mx_BaseAvatar_initial { diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 28dce730ff..2009e7dcd8 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -36,34 +36,24 @@ limitations under the License. .mx_EventTile_line { width: fit-content; max-width: 70%; - background: var(--backgroundColor); } .mx_SenderProfile { - display: none; padding: var(--gutterSize) var(--gutterSize) 0 var(--gutterSize); - border-top-left-radius: var(--cornerRadius); - border-top-right-radius: var(--cornerRadius); } .mx_EventTile_line { padding: var(--gutterSize); border-radius: var(--cornerRadius); + background: var(--backgroundColor); } - /* - .mx_SenderProfile + .mx_EventTile_line { - padding-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; - } - */ - .mx_EventTile_avatar { position: absolute; top: 0; + line-height: 1; img { - border: 2px solid #fff; + box-shadow: 0 0 0 2px #fff; border-radius: 50%; } } @@ -72,6 +62,9 @@ limitations under the License. .mx_EventTile_line { float: right; } + .mx_SenderProfile { + display: none; + } .mx_ReactionsRow { float: right; clear: right; @@ -88,6 +81,22 @@ limitations under the License. --backgroundColor: #F8FDFC; } + &[data-has-reply=true] { + > .mx_EventTile_line { + flex-direction: column; + + > a { + margin-top: -12px; + } + } + + .mx_ReplyThread_show { + order: 99999; + background: white; + box-shadow: 0 0 0 var(--gutterSize) white; + } + } + &:not([data-self=true]) { .mx_EventTile_avatar { left: calc(-1 * var(--avatarSize)); @@ -100,6 +109,7 @@ limitations under the License. & ~ .mx_EventListSummary[data-expanded=false] { --backgroundColor: transparent; + --gutterSize: 0; display: flex; align-items: center; @@ -140,10 +150,25 @@ limitations under the License. } } + /* Special layout scenario for "Unable To Decrypt (UTD)" events */ + &.mx_EventTile_bad > .mx_EventTile_line { + flex-direction: column; + > a { + position: absolute; + bottom: var(--gutterSize); + } + } + + .mx_EventTile_readAvatars { position: absolute; right: 0; bottom: 0; } + .mx_MTextBody { + /* 30px equates to the width of the timestamp */ + max-width: calc(100% - 35px - var(--gutterSize)); + } + } diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 1052b87b0d..11b9f5e959 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -372,26 +372,6 @@ $hover-select-border: 4px; left: 41px; } - .mx_EventTile_tileError { - color: red; - text-align: center; - - // Remove some of the default tile padding so that the error is centered - margin-right: 0; - .mx_EventTile_line { - padding-left: 0; - margin-right: 0; - } - - .mx_EventTile_line span { - padding: 4px 8px; - } - - a { - margin-left: 1em; - } - } - .mx_MImageBody { margin-right: 34px; } @@ -626,6 +606,26 @@ $hover-select-border: 4px; margin-bottom: 0px; } +.mx_EventTile_tileError { + color: red; + text-align: center; + + // Remove some of the default tile padding so that the error is centered + margin-right: 0; + .mx_EventTile_line { + padding-left: 0; + margin-right: 0; + } + + .mx_EventTile_line span { + padding: 4px 8px; + } + + a { + margin-left: 1em; + } +} + @media only screen and (max-width: 480px) { .mx_EventTile_line, .mx_EventTile_reply { padding-left: 0; diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 6a8748883b..6040e1962f 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -163,8 +163,6 @@ export function getHandlerTile(ev) { return eventTileTypes[type]; } -const MAX_READ_AVATARS = 5; - // Our component structure for EventTiles on the timeline is: // // .-EventTile------------------------------------------------. @@ -649,6 +647,10 @@ export default class EventTile extends React.Component { return ; } + const MAX_READ_AVATARS = this.props.layout == Layout.Bubble + ? 2 + : 5; + // return early if there are no read receipts if (!this.props.readReceipts || this.props.readReceipts.length === 0) { // We currently must include `mx_EventTile_readAvatars` in the DOM @@ -1194,6 +1196,7 @@ export default class EventTile extends React.Component { "data-scroll-tokens": scrollToken, "data-layout": this.props.layout, "data-self": isOwnEvent, + "data-has-reply": !!thread, "onMouseEnter": () => this.setState({ hover: true }), "onMouseLeave": () => this.setState({ hover: false }), }, [ From 209344d443853f345552b62eb734dca862012259 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 30 Jun 2021 17:04:07 +0100 Subject: [PATCH 05/29] improvements to bubble layout --- res/css/views/rooms/_EventBubbleTile.scss | 60 +++++++++++++---------- res/css/views/rooms/_EventTile.scss | 14 +++--- src/components/views/rooms/EventTile.tsx | 3 +- src/i18n/strings/en_EN.json | 4 ++ 4 files changed, 47 insertions(+), 34 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 2009e7dcd8..284f9bb70f 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -15,17 +15,15 @@ limitations under the License. */ .mx_EventTile[data-layout=bubble] { - --avatarSize: 32px; --gutterSize: 7px; - --cornerRadius: 5px; - + --cornerRadius: 12px; --maxWidth: 70%; position: relative; margin-top: var(--gutterSize); - margin-left: var(--avatarSize); - margin-right: var(--avatarSize); + margin-left: calc(var(--avatarSize) + var(--gutterSize)); + margin-right: calc(var(--gutterSize) + var(--avatarSize)); padding: 2px 0; &:hover { @@ -46,6 +44,12 @@ limitations under the License. padding: var(--gutterSize); border-radius: var(--cornerRadius); background: var(--backgroundColor); + display: flex; + gap: var(--gutterSize); + > a { + position: absolute; + left: -33px; + } } .mx_EventTile_avatar { @@ -78,16 +82,13 @@ limitations under the License. .mx_EventTile_avatar { right: calc(-1 * var(--avatarSize)); } + --backgroundColor: #F8FDFC; } &[data-has-reply=true] { > .mx_EventTile_line { flex-direction: column; - - > a { - margin-top: -12px; - } } .mx_ReplyThread_show { @@ -95,19 +96,41 @@ limitations under the License. background: white; box-shadow: 0 0 0 var(--gutterSize) white; } + + .mx_ReplyThread { + margin: 0 calc(-1 * var(--gutterSize)); + + .mx_EventTile_reply { + padding: 0; + > a { + display: none !important; + } + } + + .mx_EventTile { + display: flex; + gap: var(--gutterSize); + .mx_EventTile_avatar { + position: static; + } + .mx_SenderProfile { + display: none; + } + } + } } &:not([data-self=true]) { .mx_EventTile_avatar { left: calc(-1 * var(--avatarSize)); } + --backgroundColor: #F7F8F9; } &.mx_EventTile_bubbleContainer, &.mx_EventTile_info, & ~ .mx_EventListSummary[data-expanded=false] { - --backgroundColor: transparent; --gutterSize: 0; @@ -141,34 +164,21 @@ limitations under the License. margin-right: 55px; } - .mx_EventTile_line { - display: flex; - gap: var(--gutterSize); - > a { - order: 999; /* always display the timestamp as the last item */ - align-self: flex-end; - } - } - /* Special layout scenario for "Unable To Decrypt (UTD)" events */ &.mx_EventTile_bad > .mx_EventTile_line { flex-direction: column; - > a { - position: absolute; - bottom: var(--gutterSize); - } } .mx_EventTile_readAvatars { position: absolute; - right: 0; + right: -45px; bottom: 0; + top: auto; } .mx_MTextBody { /* 30px equates to the width of the timestamp */ max-width: calc(100% - 35px - var(--gutterSize)); } - } diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 11b9f5e959..446c524e81 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -287,14 +287,14 @@ $hover-select-border: 4px; mask-size: contain; } - &::before { - background-color: #ffffff; - mask-image: url('$(res)/img/e2e/normal.svg'); - mask-repeat: no-repeat; - mask-position: center; - mask-size: 80%; + &::before { + background-color: #ffffff; + mask-image: url('$(res)/img/e2e/normal.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: 80%; + } } -} .mx_EventTile_e2eIcon_undecryptable, .mx_EventTile_e2eIcon_unverified { &::after { diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 6040e1962f..b560209d14 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -1002,8 +1002,7 @@ export default class EventTile extends React.Component { && (this.props.alwaysShowTimestamps || this.props.last || this.state.hover - || this.state.actionBarFocused) - || this.props.layout === Layout.Bubble; + || this.state.actionBarFocused); const timestamp = showTimestamp ? : null; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index f0599c7e49..6253ae7d69 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -819,6 +819,7 @@ "Offline encrypted messaging using dehydrated devices": "Offline encrypted messaging using dehydrated devices", "Enable advanced debugging for the room list": "Enable advanced debugging for the room list", "Show info about bridges in room settings": "Show info about bridges in room settings", + "Explore new ways switching layouts (including a new bubble layout)": "Explore new ways switching layouts (including a new bubble layout)", "Font size": "Font size", "Use custom size": "Use custom size", "Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing", @@ -1259,6 +1260,9 @@ "Custom theme URL": "Custom theme URL", "Add theme": "Add theme", "Theme": "Theme", + "Message layout": "Message layout", + "Modern": "Modern", + "Message bubbles": "Message bubbles", "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Set the name of a font installed on your system & %(brand)s will attempt to use it.", "Enable experimental, compact IRC style layout": "Enable experimental, compact IRC style layout", "Customise your appearance": "Customise your appearance", From 223b40c9d62963f60e5a4fc83c40055b7f411f15 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 1 Jul 2021 14:23:00 +0100 Subject: [PATCH 06/29] Add dark theme support --- res/css/views/rooms/_EventBubbleTile.scss | 21 ++++++++++++------- res/themes/dark/css/_dark.scss | 6 ++++++ .../legacy-light/css/_legacy-light.scss | 6 ++++++ res/themes/light/css/_light.scss | 6 ++++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 284f9bb70f..6d11992e48 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -26,8 +26,13 @@ limitations under the License. margin-right: calc(var(--gutterSize) + var(--avatarSize)); padding: 2px 0; + /* For replies */ + .mx_EventTile { + padding-top: 0; + } + &:hover { - background: rgb(242, 242, 242); + background: $eventbubble-bg-hover; } .mx_SenderProfile, @@ -37,7 +42,7 @@ limitations under the License. } .mx_SenderProfile { - padding: var(--gutterSize) var(--gutterSize) 0 var(--gutterSize); + padding: 0 var(--gutterSize); } .mx_EventTile_line { @@ -57,7 +62,7 @@ limitations under the License. top: 0; line-height: 1; img { - box-shadow: 0 0 0 2px #fff; + box-shadow: 0 0 0 2px $eventbubble-avatar-outline; border-radius: 50%; } } @@ -83,7 +88,7 @@ limitations under the License. right: calc(-1 * var(--avatarSize)); } - --backgroundColor: #F8FDFC; + --backgroundColor: $eventbubble-self-bg; } &[data-has-reply=true] { @@ -93,8 +98,8 @@ limitations under the License. .mx_ReplyThread_show { order: 99999; - background: white; - box-shadow: 0 0 0 var(--gutterSize) white; + /* background: white; + box-shadow: 0 0 0 var(--gutterSize) white; */ } .mx_ReplyThread { @@ -120,12 +125,12 @@ limitations under the License. } } - &:not([data-self=true]) { + &[data-self=false] { .mx_EventTile_avatar { left: calc(-1 * var(--avatarSize)); } - --backgroundColor: #F7F8F9; + --backgroundColor: $eventbubble-others-bg; } &.mx_EventTile_bubbleContainer, diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 8b5fde3bd1..e2ea8478d2 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -231,6 +231,12 @@ $groupFilterPanel-background-blur-amount: 30px; $composer-shadow-color: rgba(0, 0, 0, 0.28); +// Bubble tiles +$eventbubble-self-bg: rgba(141, 151, 165, 0.3); +$eventbubble-others-bg: rgba(141, 151, 165, 0.3); +$eventbubble-bg-hover: rgba(141, 151, 165, 0.1); +$eventbubble-avatar-outline: #15191E; + // ***** Mixins! ***** @define-mixin mx_DialogButton { diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss index a6b180bab4..6bfdad9e12 100644 --- a/res/themes/legacy-light/css/_legacy-light.scss +++ b/res/themes/legacy-light/css/_legacy-light.scss @@ -346,6 +346,12 @@ $appearance-tab-border-color: $input-darker-bg-color; $composer-shadow-color: tranparent; +// Bubble tiles +$eventbubble-self-bg: #F8FDFC; +$eventbubble-others-bg: #F7F8F9; +$eventbubble-bg-hover: rgb(242, 242, 242); +$eventbubble-avatar-outline: #fff; + // ***** Mixins! ***** @define-mixin mx_DialogButton { diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index d8dab9c9c4..4b1c56bd51 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -351,6 +351,12 @@ $groupFilterPanel-background-blur-amount: 20px; $composer-shadow-color: rgba(0, 0, 0, 0.04); +// Bubble tiles +$eventbubble-self-bg: #F8FDFC; +$eventbubble-others-bg: #F7F8F9; +$eventbubble-bg-hover: rgb(242, 242, 242); +$eventbubble-avatar-outline: #fff; + // ***** Mixins! ***** @define-mixin mx_DialogButton { From d90d1ca8dbf5de3c81fb8b939a67490f679ed076 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 1 Jul 2021 14:56:34 +0100 Subject: [PATCH 07/29] event list summary alignment in bubble layout --- res/css/views/rooms/_EventBubbleTile.scss | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 6d11992e48..0c204a19ae 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -14,11 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_EventTile[data-layout=bubble] { +.mx_EventTile[data-layout=bubble], +.mx_EventTile[data-layout=bubble] ~ .mx_EventListSummary { --avatarSize: 32px; --gutterSize: 7px; --cornerRadius: 12px; --maxWidth: 70%; +} + +.mx_EventTile[data-layout=bubble] { position: relative; margin-top: var(--gutterSize); @@ -146,15 +150,22 @@ limitations under the License. .mx_EventTile_avatar { position: static; order: -1; + margin-right: 5px; } } & ~ .mx_EventListSummary { - --maxWidth: 95%; + --maxWidth: 80%; + margin-left: calc(var(--avatarSize) + var(--gutterSize)); + margin-right: calc(var(--gutterSize) + var(--avatarSize)); .mx_EventListSummary_toggle { float: none; margin: 0; order: 9; + margin-left: 5px; + } + .mx_EventListSummary_avatars { + padding-top: 0; } } From d804df84a7bffc331440ff7379f4cd865d513835 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 1 Jul 2021 15:16:47 +0100 Subject: [PATCH 08/29] Allow missing sender in event --- src/components/views/rooms/EventTile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index b560209d14..d2c6bf0ab9 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -1182,7 +1182,7 @@ export default class EventTile extends React.Component { this.props.alwaysShowTimestamps || this.state.hover, ); - const isOwnEvent = this.props.mxEvent.sender.userId === MatrixClientPeg.get().getUserId(); + const isOwnEvent = this.props.mxEvent?.sender?.userId === MatrixClientPeg.get().getUserId(); // tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers return ( From 19bc44e3fbbc675b7cc897d4445b7b88e47ae27f Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 1 Jul 2021 16:17:09 +0100 Subject: [PATCH 09/29] fix branch matching for element-web --- scripts/fetchdep.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/fetchdep.sh b/scripts/fetchdep.sh index 0990af70ce..07efee69e6 100755 --- a/scripts/fetchdep.sh +++ b/scripts/fetchdep.sh @@ -46,12 +46,7 @@ BRANCH_ARRAY=(${head//:/ }) if [[ "${#BRANCH_ARRAY[@]}" == "1" ]]; then if [ -n "$GITHUB_HEAD_REF" ]; then - if [[ "$GITHUB_REPOSITORY" == "$deforg"* ]]; then - clone $deforg $defrepo $GITHUB_HEAD_REF - else - REPO_ARRAY=(${GITHUB_REPOSITORY//\// }) - clone $REPO_ARRAY[0] $defrepo $GITHUB_HEAD_REF - fi + clone $deforg $defrepo $GITHUB_HEAD_REF else clone $deforg $defrepo $BUILDKITE_BRANCH fi From de875bbe1d39286c8a164520a3a1dd0c76aae52c Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 5 Jul 2021 16:22:18 +0200 Subject: [PATCH 10/29] fix avatar position and outline --- res/css/views/rooms/_EventBubbleTile.scss | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 0c204a19ae..c548bfae56 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -17,7 +17,7 @@ limitations under the License. .mx_EventTile[data-layout=bubble], .mx_EventTile[data-layout=bubble] ~ .mx_EventListSummary { --avatarSize: 32px; - --gutterSize: 7px; + --gutterSize: 11px; --cornerRadius: 12px; --maxWidth: 70%; } @@ -55,9 +55,10 @@ limitations under the License. background: var(--backgroundColor); display: flex; gap: var(--gutterSize); + margin: 0 calc(-2 * var(--gutterSize)); > a { position: absolute; - left: -33px; + left: -50px; } } @@ -66,7 +67,7 @@ limitations under the License. top: 0; line-height: 1; img { - box-shadow: 0 0 0 2px $eventbubble-avatar-outline; + box-shadow: 0 0 0 3px $eventbubble-avatar-outline; border-radius: 50%; } } @@ -89,6 +90,7 @@ limitations under the License. } } .mx_EventTile_avatar { + top: -19px; // height of the sender block right: calc(-1 * var(--avatarSize)); } From b0a1fc7b9785814aa205047e2956ff40e393a244 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 7 Jul 2021 11:23:38 +0200 Subject: [PATCH 11/29] Updated color scheme and spacing --- res/css/views/rooms/_EventBubbleTile.scss | 37 +++++++++++++++++------ res/themes/dark/css/_dark.scss | 8 ++--- res/themes/light/css/_light.scss | 4 +-- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index c548bfae56..936092db7a 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -26,9 +26,12 @@ limitations under the License. position: relative; margin-top: var(--gutterSize); - margin-left: calc(var(--avatarSize) + var(--gutterSize)); - margin-right: calc(var(--gutterSize) + var(--avatarSize)); - padding: 2px 0; + margin-left: 50px; + margin-right: 50px; + + &.mx_EventTile_continuation { + margin-top: 2px; + } /* For replies */ .mx_EventTile { @@ -36,7 +39,23 @@ limitations under the License. } &:hover { - background: $eventbubble-bg-hover; + &::before { + content: ''; + position: absolute; + top: -1px; + bottom: -1px; + left: -60px; + right: -65px; + z-index: -1; + background: $eventbubble-bg-hover; + border-radius: 4px; + } + + .mx_EventTile_avatar { + img { + box-shadow: 0 0 0 3px $eventbubble-bg-hover; + } + } } .mx_SenderProfile, @@ -55,10 +74,10 @@ limitations under the License. background: var(--backgroundColor); display: flex; gap: var(--gutterSize); - margin: 0 calc(-2 * var(--gutterSize)); + margin: 0 -12px 0 -22px; > a { position: absolute; - left: -50px; + left: -57px; } } @@ -91,7 +110,7 @@ limitations under the License. } .mx_EventTile_avatar { top: -19px; // height of the sender block - right: calc(-1 * var(--avatarSize)); + right: -45px; } --backgroundColor: $eventbubble-self-bg; @@ -104,8 +123,6 @@ limitations under the License. .mx_ReplyThread_show { order: 99999; - /* background: white; - box-shadow: 0 0 0 var(--gutterSize) white; */ } .mx_ReplyThread { @@ -190,7 +207,7 @@ limitations under the License. .mx_EventTile_readAvatars { position: absolute; - right: -45px; + right: -60px; bottom: 0; top: auto; } diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index e2ea8478d2..5ded90230b 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -232,10 +232,10 @@ $groupFilterPanel-background-blur-amount: 30px; $composer-shadow-color: rgba(0, 0, 0, 0.28); // Bubble tiles -$eventbubble-self-bg: rgba(141, 151, 165, 0.3); -$eventbubble-others-bg: rgba(141, 151, 165, 0.3); -$eventbubble-bg-hover: rgba(141, 151, 165, 0.1); -$eventbubble-avatar-outline: #15191E; +$eventbubble-self-bg: #143A34; +$eventbubble-others-bg: #394049; +$eventbubble-bg-hover: #433C23; +$eventbubble-avatar-outline: $bg-color; // ***** Mixins! ***** diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 4b1c56bd51..c84126909e 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -354,8 +354,8 @@ $composer-shadow-color: rgba(0, 0, 0, 0.04); // Bubble tiles $eventbubble-self-bg: #F8FDFC; $eventbubble-others-bg: #F7F8F9; -$eventbubble-bg-hover: rgb(242, 242, 242); -$eventbubble-avatar-outline: #fff; +$eventbubble-bg-hover: #FEFCF5; +$eventbubble-avatar-outline: $primary-bg-color; // ***** Mixins! ***** From 7d946ee0db5f7f1579df3955ce70403bfede0388 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 7 Jul 2021 12:04:28 +0200 Subject: [PATCH 12/29] Restore action bar --- res/css/views/rooms/_EventBubbleTile.scss | 27 ++++++++++++++++++++-- res/css/views/rooms/_EventTile.scss | 14 +++++------ src/components/structures/MessagePanel.tsx | 4 +++- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 936092db7a..aa59f53b72 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -69,18 +69,32 @@ limitations under the License. } .mx_EventTile_line { + position: relative; padding: var(--gutterSize); - border-radius: var(--cornerRadius); + border-top-left-radius: var(--cornerRadius); + border-top-right-radius: var(--cornerRadius); + border-bottom-right-radius: var(--cornerRadius); background: var(--backgroundColor); display: flex; gap: var(--gutterSize); margin: 0 -12px 0 -22px; > a { position: absolute; - left: -57px; + left: -35px; } } + &.mx_EventTile_continuation .mx_EventTile_line { + border-top-left-radius: 0; + } + + &.mx_EventTile_lastInSection .mx_EventTile_line { + border-bottom-left-radius: var(--cornerRadius); + } + + + + .mx_EventTile_avatar { position: absolute; top: 0; @@ -94,6 +108,10 @@ limitations under the License. &[data-self=true] { .mx_EventTile_line { float: right; + > a { + left: auto; + right: -35px; + } } .mx_SenderProfile { display: none; @@ -153,6 +171,11 @@ limitations under the License. left: calc(-1 * var(--avatarSize)); } + .mx_MessageActionBar { + right: 0; + transform: translate3d(50%, 50%, 0); + } + --backgroundColor: $eventbubble-others-bg; } diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 446c524e81..548a852190 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -123,13 +123,6 @@ $hover-select-border: 4px; left: calc(-$hover-select-border); } - .mx_EventTile:hover .mx_MessageActionBar, - .mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar, - [data-whatinput='keyboard'] .mx_EventTile:focus-within .mx_MessageActionBar, - .mx_EventTile.focus-visible:focus-within .mx_MessageActionBar { - visibility: visible; - } - /* this is used for the tile for the event which is selected via the URL. * TODO: ultimately we probably want some transition on here. */ @@ -626,6 +619,13 @@ $hover-select-border: 4px; } } +.mx_EventTile:hover .mx_MessageActionBar, +.mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar, +[data-whatinput='keyboard'] .mx_EventTile:focus-within .mx_MessageActionBar, +.mx_EventTile.focus-visible:focus-within .mx_MessageActionBar { + visibility: visible; +} + @media only screen and (max-width: 480px) { .mx_EventTile_line, .mx_EventTile_reply { padding-left: 0; diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index a0a1ac9b10..e811a8c1ce 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -644,8 +644,10 @@ export default class MessagePanel extends React.Component { } let willWantDateSeparator = false; + let lastInSection = true; if (nextEvent) { willWantDateSeparator = this.wantsDateSeparator(mxEv, nextEvent.getDate() || new Date()); + lastInSection = willWantDateSeparator || mxEv.getSender() !== nextEvent.getSender(); } // is this a continuation of the previous message? @@ -702,7 +704,7 @@ export default class MessagePanel extends React.Component { isTwelveHour={this.props.isTwelveHour} permalinkCreator={this.props.permalinkCreator} last={last} - lastInSection={willWantDateSeparator} + lastInSection={lastInSection} lastSuccessful={isLastSuccessful} isSelectedEvent={highlight} getRelationsForEvent={this.props.getRelationsForEvent} From 870857f3213332c82d257f61e286a5ec52eac502 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 7 Jul 2021 13:00:31 +0200 Subject: [PATCH 13/29] Right hand side border radius --- res/css/views/rooms/_EventBubbleTile.scss | 25 +++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index aa59f53b72..4d189f78a3 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -68,12 +68,22 @@ limitations under the License. padding: 0 var(--gutterSize); } + &[data-self=false] { + .mx_EventTile_line { + border-bottom-right-radius: var(--cornerRadius); + } + } + &[data-self=true] { + .mx_EventTile_line { + border-bottom-left-radius: var(--cornerRadius); + } + } + .mx_EventTile_line { position: relative; padding: var(--gutterSize); border-top-left-radius: var(--cornerRadius); border-top-right-radius: var(--cornerRadius); - border-bottom-right-radius: var(--cornerRadius); background: var(--backgroundColor); display: flex; gap: var(--gutterSize); @@ -84,16 +94,19 @@ limitations under the License. } } - &.mx_EventTile_continuation .mx_EventTile_line { + &.mx_EventTile_continuation[data-self=false] .mx_EventTile_line { border-top-left-radius: 0; } - - &.mx_EventTile_lastInSection .mx_EventTile_line { + &.mx_EventTile_lastInSection[data-self=false] .mx_EventTile_line { border-bottom-left-radius: var(--cornerRadius); } - - + &.mx_EventTile_continuation[data-self=true] .mx_EventTile_line { + border-top-right-radius: 0; + } + &.mx_EventTile_lastInSection[data-self=true] .mx_EventTile_line { + border-bottom-right-radius: var(--cornerRadius); + } .mx_EventTile_avatar { position: absolute; From 6a03ab825f2478595930dd5d3d73a9b13b4dbb89 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 7 Jul 2021 13:15:25 +0200 Subject: [PATCH 14/29] Fix style linting --- res/css/views/rooms/_EventBubbleTile.scss | 76 ++++++++++------------- 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 4d189f78a3..d78210a154 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -72,11 +72,45 @@ limitations under the License. .mx_EventTile_line { border-bottom-right-radius: var(--cornerRadius); } + .mx_EventTile_avatar { + left: calc(-1 * var(--avatarSize)); + } + + .mx_MessageActionBar { + right: 0; + transform: translate3d(50%, 50%, 0); + } + + --backgroundColor: $eventbubble-others-bg; } &[data-self=true] { .mx_EventTile_line { border-bottom-left-radius: var(--cornerRadius); + float: right; + > a { + left: auto; + right: -35px; + } } + .mx_SenderProfile { + display: none; + } + .mx_ReactionsRow { + float: right; + clear: right; + display: flex; + + /* Moving the "add reaction button" before the reactions */ + > :last-child { + order: -1; + } + } + .mx_EventTile_avatar { + top: -19px; // height of the sender block + right: -45px; + } + + --backgroundColor: $eventbubble-self-bg; } .mx_EventTile_line { @@ -118,35 +152,6 @@ limitations under the License. } } - &[data-self=true] { - .mx_EventTile_line { - float: right; - > a { - left: auto; - right: -35px; - } - } - .mx_SenderProfile { - display: none; - } - .mx_ReactionsRow { - float: right; - clear: right; - display: flex; - - /* Moving the "add reaction button" before the reactions */ - > :last-child { - order: -1; - } - } - .mx_EventTile_avatar { - top: -19px; // height of the sender block - right: -45px; - } - - --backgroundColor: $eventbubble-self-bg; - } - &[data-has-reply=true] { > .mx_EventTile_line { flex-direction: column; @@ -179,19 +184,6 @@ limitations under the License. } } - &[data-self=false] { - .mx_EventTile_avatar { - left: calc(-1 * var(--avatarSize)); - } - - .mx_MessageActionBar { - right: 0; - transform: translate3d(50%, 50%, 0); - } - - --backgroundColor: $eventbubble-others-bg; - } - &.mx_EventTile_bubbleContainer, &.mx_EventTile_info, & ~ .mx_EventListSummary[data-expanded=false] { From 55896223aa23b48c18472880ea338b8b7c8ea7ef Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 7 Jul 2021 15:13:58 +0200 Subject: [PATCH 15/29] unbubble some type of events --- res/css/views/rooms/_EventBubbleTile.scss | 58 +++++++-- res/css/views/rooms/_EventTile.scss | 139 +++++++++++---------- src/components/structures/MessagePanel.tsx | 1 + src/components/views/rooms/EventTile.tsx | 5 +- 4 files changed, 127 insertions(+), 76 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index d78210a154..313027bde6 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -27,7 +27,7 @@ limitations under the License. position: relative; margin-top: var(--gutterSize); margin-left: 50px; - margin-right: 50px; + margin-right: 100px; &.mx_EventTile_continuation { margin-top: 2px; @@ -45,7 +45,7 @@ limitations under the License. top: -1px; bottom: -1px; left: -60px; - right: -65px; + right: -60px; z-index: -1; background: $eventbubble-bg-hover; border-radius: 4px; @@ -65,7 +65,9 @@ limitations under the License. } .mx_SenderProfile { - padding: 0 var(--gutterSize); + position: relative; + top: -2px; + left: calc(-1 * var(--gutterSize)); } &[data-self=false] { @@ -73,7 +75,7 @@ limitations under the License. border-bottom-right-radius: var(--cornerRadius); } .mx_EventTile_avatar { - left: calc(-1 * var(--avatarSize)); + left: -48px; } .mx_MessageActionBar { @@ -107,7 +109,7 @@ limitations under the License. } .mx_EventTile_avatar { top: -19px; // height of the sender block - right: -45px; + right: -35px; } --backgroundColor: $eventbubble-self-bg; @@ -120,7 +122,7 @@ limitations under the License. border-top-right-radius: var(--cornerRadius); background: var(--backgroundColor); display: flex; - gap: var(--gutterSize); + gap: 5px; margin: 0 -12px 0 -22px; > a { position: absolute; @@ -214,6 +216,29 @@ limitations under the License. .mx_EventListSummary_avatars { padding-top: 0; } + + &::after { + content: ""; + clear: both; + } + + .mx_EventTile { + margin: 0 58px; + } + } + + /* events that do not require bubble layout */ + & ~ .mx_EventListSummary, + &.mx_EventTile_bad { + .mx_EventTile_line { + background: transparent; + } + + &:hover { + &::before { + background: transparent; + } + } } & + .mx_EventListSummary { @@ -229,13 +254,30 @@ limitations under the License. /* Special layout scenario for "Unable To Decrypt (UTD)" events */ &.mx_EventTile_bad > .mx_EventTile_line { - flex-direction: column; + display: grid; + grid-template: + "reply reply" auto + "shield body" auto + "shield link" auto + / auto 1fr; + .mx_EventTile_e2eIcon { + grid-area: shield; + } + .mx_UnknownBody { + grid-area: body; + } + .mx_EventTile_keyRequestInfo { + grid-area: link; + } + .mx_ReplyThread_wrapper { + grid-area: reply; + } } .mx_EventTile_readAvatars { position: absolute; - right: -60px; + right: -110px; bottom: 0; top: auto; } diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 548a852190..ca94ce86c8 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -254,73 +254,6 @@ $hover-select-border: 4px; filter: none; } - .mx_EventTile_e2eIcon { - position: absolute; - top: 6px; - left: 44px; - width: 14px; - height: 14px; - display: block; - bottom: 0; - right: 0; - opacity: 0.2; - background-repeat: no-repeat; - background-size: contain; - - &::before, &::after { - content: ""; - display: block; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - mask-repeat: no-repeat; - mask-position: center; - mask-size: contain; - } - - &::before { - background-color: #ffffff; - mask-image: url('$(res)/img/e2e/normal.svg'); - mask-repeat: no-repeat; - mask-position: center; - mask-size: 80%; - } - } - - .mx_EventTile_e2eIcon_undecryptable, .mx_EventTile_e2eIcon_unverified { - &::after { - mask-image: url('$(res)/img/e2e/warning.svg'); - background-color: $notice-primary-color; - } - opacity: 1; - } - - .mx_EventTile_e2eIcon_unknown { - &::after { - mask-image: url('$(res)/img/e2e/warning.svg'); - background-color: $notice-primary-color; - } - opacity: 1; - } - - .mx_EventTile_e2eIcon_unencrypted { - &::after { - mask-image: url('$(res)/img/e2e/warning.svg'); - background-color: $notice-primary-color; - } - opacity: 1; - } - - .mx_EventTile_e2eIcon_unauthenticated { - &::after { - mask-image: url('$(res)/img/e2e/normal.svg'); - background-color: $composer-e2e-icon-color; - } - opacity: 1; - } - .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line, .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line, .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line { @@ -368,6 +301,14 @@ $hover-select-border: 4px; .mx_MImageBody { margin-right: 34px; } + + .mx_EventTile_e2eIcon { + position: absolute; + top: 6px; + left: 44px; + bottom: 0; + right: 0; + } } .mx_EventTile_bubbleContainer { @@ -431,6 +372,70 @@ $hover-select-border: 4px; cursor: pointer; } + +.mx_EventTile_e2eIcon { + position: relative; + width: 14px; + height: 14px; + display: block; + opacity: 0.2; + background-repeat: no-repeat; + background-size: contain; + + &::before, &::after { + content: ""; + display: block; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + } + + &::before { + background-color: #ffffff; + mask-image: url('$(res)/img/e2e/normal.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: 80%; + } +} + +.mx_EventTile_e2eIcon_undecryptable, .mx_EventTile_e2eIcon_unverified { + &::after { + mask-image: url('$(res)/img/e2e/warning.svg'); + background-color: $notice-primary-color; + } + opacity: 1; +} + +.mx_EventTile_e2eIcon_unknown { + &::after { + mask-image: url('$(res)/img/e2e/warning.svg'); + background-color: $notice-primary-color; + } + opacity: 1; +} + +.mx_EventTile_e2eIcon_unencrypted { + &::after { + mask-image: url('$(res)/img/e2e/warning.svg'); + background-color: $notice-primary-color; + } + opacity: 1; +} + +.mx_EventTile_e2eIcon_unauthenticated { + &::after { + mask-image: url('$(res)/img/e2e/normal.svg'); + background-color: $composer-e2e-icon-color; + } + opacity: 1; +} + /* Various markdown overrides */ .mx_EventTile_body pre { diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index e811a8c1ce..cee6011e4a 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -712,6 +712,7 @@ export default class MessagePanel extends React.Component { layout={this.props.layout} enableFlair={this.props.enableFlair} showReadReceipts={this.props.showReadReceipts} + hideSender={this.props.room.getMembers().length <= 2} /> , ); diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index a474686333..6db32a1ad5 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -289,6 +289,9 @@ interface IProps { // whether or not to always show timestamps alwaysShowTimestamps?: boolean; + + // whether or not to display the sender + hideSender?: boolean; } interface IState { @@ -978,7 +981,7 @@ export default class EventTile extends React.Component { ); } - if (needsSenderProfile) { + if (needsSenderProfile && this.props.hideSender !== true) { if (!this.props.tileShape || this.props.tileShape === 'reply' || this.props.tileShape === 'reply_preview') { sender = Date: Tue, 13 Jul 2021 10:15:12 +0200 Subject: [PATCH 16/29] Fix layout regressions in message bubbles --- res/css/views/rooms/_EventBubbleTile.scss | 44 ++++++++++++++++--- res/themes/dark/css/_dark.scss | 1 + .../legacy-light/css/_legacy-light.scss | 1 + res/themes/light/css/_light.scss | 1 + 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 313027bde6..48011951cc 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -67,7 +67,7 @@ limitations under the License. .mx_SenderProfile { position: relative; top: -2px; - left: calc(-1 * var(--gutterSize)); + left: 2px; } &[data-self=false] { @@ -75,7 +75,7 @@ limitations under the License. border-bottom-right-radius: var(--cornerRadius); } .mx_EventTile_avatar { - left: -48px; + left: -34px; } .mx_MessageActionBar { @@ -91,7 +91,7 @@ limitations under the License. float: right; > a { left: auto; - right: -35px; + right: -48px; } } .mx_SenderProfile { @@ -123,10 +123,10 @@ limitations under the License. background: var(--backgroundColor); display: flex; gap: 5px; - margin: 0 -12px 0 -22px; + margin: 0 -12px 0 -9px; > a { position: absolute; - left: -35px; + left: -48px; } } @@ -167,6 +167,7 @@ limitations under the License. margin: 0 calc(-1 * var(--gutterSize)); .mx_EventTile_reply { + max-width: 90%; padding: 0; > a { display: none !important; @@ -186,6 +187,23 @@ limitations under the License. } } + .mx_EditMessageComposer_buttons { + position: static; + padding: 0; + margin: 0; + background: transparent; + } + + .mx_ReactionsRow { + margin-right: -18px; + margin-left: -9px; + } + + .mx_ReplyThread { + border-left-width: 2px; + border-left-color: $eventbubble-reply-color; + } + &.mx_EventTile_bubbleContainer, &.mx_EventTile_info, & ~ .mx_EventListSummary[data-expanded=false] { @@ -225,6 +243,19 @@ limitations under the License. .mx_EventTile { margin: 0 58px; } + + .mx_EventTile_line { + margin: 0 5px; + > a { + left: auto; + right: 0; + transform: translateX(calc(100% + 5px)); + } + } + + .mx_MessageActionBar { + transform: translate3d(50%, 0, 0); + } } /* events that do not require bubble layout */ @@ -283,7 +314,6 @@ limitations under the License. } .mx_MTextBody { - /* 30px equates to the width of the timestamp */ - max-width: calc(100% - 35px - var(--gutterSize)); + max-width: 100%; } } diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 0b3444c95b..a43936c46e 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -234,6 +234,7 @@ $eventbubble-self-bg: #143A34; $eventbubble-others-bg: #394049; $eventbubble-bg-hover: #433C23; $eventbubble-avatar-outline: $bg-color; +$eventbubble-reply-color: #C1C6CD; // ***** Mixins! ***** diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss index e485028774..f349a804a8 100644 --- a/res/themes/legacy-light/css/_legacy-light.scss +++ b/res/themes/legacy-light/css/_legacy-light.scss @@ -352,6 +352,7 @@ $eventbubble-self-bg: #F8FDFC; $eventbubble-others-bg: #F7F8F9; $eventbubble-bg-hover: rgb(242, 242, 242); $eventbubble-avatar-outline: #fff; +$eventbubble-reply-color: #C1C6CD; // ***** Mixins! ***** diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 6f0bcadaf7..ef5f4d8c86 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -354,6 +354,7 @@ $eventbubble-self-bg: #F8FDFC; $eventbubble-others-bg: #F7F8F9; $eventbubble-bg-hover: #FEFCF5; $eventbubble-avatar-outline: $primary-bg-color; +$eventbubble-reply-color: #C1C6CD; // ***** Mixins! ***** From 290174b0313cf42391525d6b2798fa4ac1a287c7 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Tue, 13 Jul 2021 10:36:35 +0200 Subject: [PATCH 17/29] fix group layout and IRC layout regressions --- res/css/views/rooms/_EventTile.scss | 70 ++++++++++++++--------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index bd5b8113a9..e9d71d557c 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -25,7 +25,7 @@ $hover-select-border: 4px; font-size: $font-14px; position: relative; - .mx_EventTile.mx_EventTile_info { + &.mx_EventTile_info { padding-top: 1px; } @@ -36,12 +36,12 @@ $hover-select-border: 4px; user-select: none; } - .mx_EventTile.mx_EventTile_info .mx_EventTile_avatar { + &.mx_EventTile_info .mx_EventTile_avatar { top: $font-6px; left: $left-gutter; } - .mx_EventTile_continuation { + &.mx_EventTile_continuation { padding-top: 0px !important; &.mx_EventTile_isEditing { @@ -50,11 +50,11 @@ $hover-select-border: 4px; } } - .mx_EventTile_isEditing { + &.mx_EventTile_isEditing { background-color: $header-panel-bg-color; } - .mx_EventTile .mx_SenderProfile { + .mx_SenderProfile { color: $primary-fg-color; font-size: $font-14px; display: inline-block; /* anti-zalgo, with overflow hidden */ @@ -69,7 +69,7 @@ $hover-select-border: 4px; max-width: calc(100% - $left-gutter); } - .mx_EventTile .mx_SenderProfile .mx_Flair { + .mx_SenderProfile .mx_Flair { opacity: 0.7; margin-left: 5px; display: inline-block; @@ -84,11 +84,11 @@ $hover-select-border: 4px; } } - .mx_EventTile_isEditing .mx_MessageTimestamp { + &.mx_EventTile_isEditing .mx_MessageTimestamp { visibility: hidden; } - .mx_EventTile .mx_MessageTimestamp { + .mx_MessageTimestamp { display: block; white-space: nowrap; left: 0px; @@ -96,7 +96,7 @@ $hover-select-border: 4px; user-select: none; } - .mx_EventTile_continuation .mx_EventTile_line { + &.mx_EventTile_continuation .mx_EventTile_line { clear: both; } @@ -119,21 +119,21 @@ $hover-select-border: 4px; margin-right: 10px; } - .mx_EventTile_selected > div > a > .mx_MessageTimestamp { + &.mx_EventTile_selected > div > a > .mx_MessageTimestamp { left: calc(-$hover-select-border); } /* this is used for the tile for the event which is selected via the URL. * TODO: ultimately we probably want some transition on here. */ - .mx_EventTile_selected > .mx_EventTile_line { + &.mx_EventTile_selected > .mx_EventTile_line { border-left: $accent-color 4px solid; padding-left: calc($left-gutter - $hover-select-border); background-color: $event-selected-color; } - .mx_EventTile_highlight, - .mx_EventTile_highlight .markdown-body { + &.mx_EventTile_highlight, + &.mx_EventTile_highlight .markdown-body { color: $event-highlight-fg-color; .mx_EventTile_line { @@ -141,17 +141,17 @@ $hover-select-border: 4px; } } - .mx_EventTile_info .mx_EventTile_line { + &.mx_EventTile_info .mx_EventTile_line { padding-left: calc($left-gutter + 18px); } - .mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line { + &.mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line { padding-left: calc($left-gutter + 18px - $hover-select-border); } - .mx_EventTile:hover .mx_EventTile_line, - .mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line, - .mx_EventTile.focus-visible:focus-within .mx_EventTile_line { + &.mx_EventTile:hover .mx_EventTile_line, + &.mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line, + &.mx_EventTile.focus-visible:focus-within .mx_EventTile_line { background-color: $event-selected-color; } @@ -195,7 +195,7 @@ $hover-select-border: 4px; mask-image: url('$(res)/img/element-icons/circle-sending.svg'); } - .mx_EventTile_contextual { + &.mx_EventTile_contextual { opacity: 0.4; } @@ -254,46 +254,46 @@ $hover-select-border: 4px; filter: none; } - .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line, - .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line, - .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line { + &:hover.mx_EventTile_verified .mx_EventTile_line, + &:hover.mx_EventTile_unverified .mx_EventTile_line, + &:hover.mx_EventTile_unknown .mx_EventTile_line { padding-left: calc($left-gutter - $hover-select-border); } - .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line { + &:hover.mx_EventTile_verified .mx_EventTile_line { border-left: $e2e-verified-color $EventTile_e2e_state_indicator_width solid; } - .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line { + &:hover.mx_EventTile_unverified .mx_EventTile_line { border-left: $e2e-unverified-color $EventTile_e2e_state_indicator_width solid; } - .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line { + &:hover.mx_EventTile_unknown .mx_EventTile_line { border-left: $e2e-unknown-color $EventTile_e2e_state_indicator_width solid; } - .mx_EventTile:hover.mx_EventTile_verified.mx_EventTile_info .mx_EventTile_line, - .mx_EventTile:hover.mx_EventTile_unverified.mx_EventTile_info .mx_EventTile_line, - .mx_EventTile:hover.mx_EventTile_unknown.mx_EventTile_info .mx_EventTile_line { + &:hover.mx_EventTile_verified.mx_EventTile_info .mx_EventTile_line, + &:hover.mx_EventTile_unverified.mx_EventTile_info .mx_EventTile_line, + &:hover.mx_EventTile_unknown.mx_EventTile_info .mx_EventTile_line { padding-left: calc($left-gutter + 18px - $hover-select-border); } /* End to end encryption stuff */ - .mx_EventTile:hover .mx_EventTile_e2eIcon { + &:hover .mx_EventTile_e2eIcon { opacity: 1; } // Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies) - .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line > a > .mx_MessageTimestamp, - .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line > a > .mx_MessageTimestamp, - .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line > a > .mx_MessageTimestamp { + &:hover.mx_EventTile_verified .mx_EventTile_line > a > .mx_MessageTimestamp, + &:hover.mx_EventTile_unverified .mx_EventTile_line > a > .mx_MessageTimestamp, + &:hover.mx_EventTile_unknown .mx_EventTile_line > a > .mx_MessageTimestamp { left: calc(-$hover-select-border); } // Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies) - .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line > .mx_EventTile_e2eIcon, - .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line > .mx_EventTile_e2eIcon, - .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line > .mx_EventTile_e2eIcon { + &:hover.mx_EventTile_verified .mx_EventTile_line > .mx_EventTile_e2eIcon, + &:hover.mx_EventTile_unverified .mx_EventTile_line > .mx_EventTile_e2eIcon, + &:hover.mx_EventTile_unknown .mx_EventTile_line > .mx_EventTile_e2eIcon { display: block; left: 41px; } From fc270b435cd559972cff5ece78613de2dc869433 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 14 Jul 2021 15:32:35 +0200 Subject: [PATCH 18/29] fix group layout --- res/css/views/rooms/_EventBubbleTile.scss | 6 +++++- res/css/views/rooms/_EventTile.scss | 26 +++++++++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index 48011951cc..c66f635ffe 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -241,7 +241,7 @@ limitations under the License. } .mx_EventTile { - margin: 0 58px; + margin: 0 6px; } .mx_EventTile_line { @@ -258,6 +258,10 @@ limitations under the License. } } + & ~ .mx_EventListSummary[data-expanded=false] { + padding: 0 34px; + } + /* events that do not require bubble layout */ & ~ .mx_EventListSummary, &.mx_EventTile_bad { diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index e9d71d557c..d6ad37f6bb 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -106,15 +106,6 @@ $hover-select-border: 4px; border-radius: 8px; } - .mx_RoomView_timeline_rr_enabled, - // on ELS we need the margin to allow interaction with the expand/collapse button which is normally in the RR gutter - .mx_EventListSummary { - .mx_EventTile_line { - /* ideally should be 100px, but 95px gives us a max thumbnail size of 800x600, which is nice */ - margin-right: 110px; - } - } - .mx_EventTile_reply { margin-right: 10px; } @@ -309,6 +300,23 @@ $hover-select-border: 4px; bottom: 0; right: 0; } + + .mx_ReactionsRow { + margin: 0; + padding: 6px 60px; + } +} + +.mx_RoomView_timeline_rr_enabled { + + .mx_EventTile:not([data-layout=bubble]) { + .mx_EventTile_line { + /* ideally should be 100px, but 95px gives us a max thumbnail size of 800x600, which is nice */ + margin-right: 110px; + } + } + + // on ELS we need the margin to allow interaction with the expand/collapse button which is normally in the RR gutter } .mx_EventTile_bubbleContainer { From f4dfe9832bce35ebb15287eaba39e9c0c24d44e6 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 14 Jul 2021 16:20:25 +0200 Subject: [PATCH 19/29] change labs flag wording --- src/i18n/strings/en_EN.json | 2 +- src/settings/Settings.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4c113aae18..0839c7eec4 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -820,7 +820,7 @@ "Offline encrypted messaging using dehydrated devices": "Offline encrypted messaging using dehydrated devices", "Enable advanced debugging for the room list": "Enable advanced debugging for the room list", "Show info about bridges in room settings": "Show info about bridges in room settings", - "Explore new ways switching layouts (including a new bubble layout)": "Explore new ways switching layouts (including a new bubble layout)", + "New layout switcher (with message bubbles)": "New layout switcher (with message bubbles)", "Font size": "Font size", "Use custom size": "Use custom size", "Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index a3a184b908..c15ec684ad 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -325,7 +325,7 @@ export const SETTINGS: {[setting: string]: ISetting} = { "feature_new_layout_switcher": { isFeature: true, supportedLevels: LEVELS_FEATURE, - displayName: _td("Explore new ways switching layouts (including a new bubble layout)"), + displayName: _td("New layout switcher (with message bubbles)"), default: false, controller: new NewLayoutSwitcherController(), }, From a6120ef3b780a586e148dd21237e30c26a57f363 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 14 Jul 2021 16:32:29 +0200 Subject: [PATCH 20/29] Revert fetchdep script diff --- scripts/fetchdep.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/fetchdep.sh b/scripts/fetchdep.sh index 07efee69e6..0990af70ce 100755 --- a/scripts/fetchdep.sh +++ b/scripts/fetchdep.sh @@ -46,7 +46,12 @@ BRANCH_ARRAY=(${head//:/ }) if [[ "${#BRANCH_ARRAY[@]}" == "1" ]]; then if [ -n "$GITHUB_HEAD_REF" ]; then - clone $deforg $defrepo $GITHUB_HEAD_REF + if [[ "$GITHUB_REPOSITORY" == "$deforg"* ]]; then + clone $deforg $defrepo $GITHUB_HEAD_REF + else + REPO_ARRAY=(${GITHUB_REPOSITORY//\// }) + clone $REPO_ARRAY[0] $defrepo $GITHUB_HEAD_REF + fi else clone $deforg $defrepo $BUILDKITE_BRANCH fi From dde58d449dd22410b9d2fabf8359c2781d020b34 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 14 Jul 2021 17:16:13 +0200 Subject: [PATCH 21/29] Only hide sender when in bubble mode --- src/components/structures/MessagePanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index cee6011e4a..bf5a47cff3 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -712,7 +712,7 @@ export default class MessagePanel extends React.Component { layout={this.props.layout} enableFlair={this.props.enableFlair} showReadReceipts={this.props.showReadReceipts} - hideSender={this.props.room.getMembers().length <= 2} + hideSender={this.props.room.getMembers().length <= 2 && this.props.layout === Layout.Bubble} /> , ); From ce78cdf4add2091862cbc466e5058846f010a79b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 19 Jul 2021 22:43:11 +0100 Subject: [PATCH 22/29] Conform to new react and typescript eslint rules --- package.json | 1 + src/@types/global.d.ts | 4 + src/Analytics.tsx | 16 +-- src/CallHandler.tsx | 22 ++-- src/ContentMessages.tsx | 4 +- src/DeviceListener.ts | 87 ++++++------- src/IdentityAuthClient.js | 10 +- src/MatrixClientPeg.ts | 4 +- src/Modal.tsx | 6 +- src/SlashCommands.tsx | 8 +- src/accessibility/KeyboardShortcuts.tsx | 4 +- src/accessibility/Toolbar.tsx | 4 +- .../eventindex/DisableEventIndexDialog.js | 4 +- .../eventindex/ManageEventIndexDialog.tsx | 16 +-- .../dialogs/security/CreateKeyBackupDialog.js | 68 +++++----- .../security/CreateSecretStorageDialog.js | 78 ++++++------ .../security/NewRecoveryMethodDialog.js | 24 ++-- .../security/RecoveryMethodRemovedDialog.js | 14 +- src/autocomplete/UserProvider.tsx | 4 +- .../structures/CustomRoomTagPanel.js | 4 +- src/components/structures/EmbeddedPage.js | 6 +- src/components/structures/FilePanel.tsx | 6 +- src/components/structures/GenericErrorPage.js | 4 +- src/components/structures/GroupView.js | 8 +- src/components/structures/LeftPanel.tsx | 14 +- src/components/structures/LeftPanelWidget.tsx | 6 +- src/components/structures/LoggedInView.tsx | 86 ++++++------- src/components/structures/MatrixChat.tsx | 16 +-- src/components/structures/MyGroups.js | 4 +- .../structures/NonUrgentToastContainer.tsx | 4 +- .../structures/NotificationPanel.tsx | 4 +- src/components/structures/RightPanel.tsx | 5 +- src/components/structures/RoomDirectory.tsx | 20 +-- src/components/structures/RoomSearch.tsx | 6 +- src/components/structures/RoomStatusBar.js | 14 +- src/components/structures/RoomView.tsx | 26 ++-- src/components/structures/SearchBox.js | 12 +- .../structures/SpaceRoomDirectory.tsx | 6 +- src/components/structures/SpaceRoomView.tsx | 18 +-- src/components/structures/TabbedView.tsx | 24 ++-- src/components/structures/TimelinePanel.tsx | 6 +- src/components/structures/ToastContainer.tsx | 14 +- src/components/structures/UploadBar.tsx | 2 +- src/components/structures/UserMenu.tsx | 68 +++++----- src/components/structures/ViewSource.js | 32 ++--- .../structures/auth/CompleteSecurity.tsx | 4 +- .../structures/auth/ForgotPassword.tsx | 26 ++-- src/components/structures/auth/Login.tsx | 24 ++-- .../structures/auth/Registration.tsx | 36 +++--- .../structures/auth/SetupEncryptionBody.tsx | 32 ++--- src/components/structures/auth/SoftLogout.tsx | 30 ++--- .../views/audio_messages/AudioPlayer.tsx | 4 +- src/components/views/audio_messages/Clock.tsx | 2 +- .../views/audio_messages/Waveform.tsx | 4 +- src/components/views/auth/AuthPage.js | 2 +- src/components/views/auth/CaptchaForm.js | 4 +- .../auth/InteractiveAuthEntryComponents.tsx | 20 +-- src/components/views/auth/PasswordLogin.tsx | 14 +- .../views/auth/RegistrationForm.tsx | 10 +- .../views/avatars/DecoratedRoomAvatar.tsx | 4 +- .../avatars/MemberStatusMessageAvatar.js | 2 +- .../views/context_menus/CallContextMenu.tsx | 6 +- .../context_menus/IconizedContextMenu.tsx | 12 +- .../context_menus/MessageContextMenu.tsx | 8 +- .../context_menus/StatusMessageContextMenu.js | 10 +- .../dialogs/AddExistingToSpaceDialog.tsx | 2 +- .../views/dialogs/AddressPickerDialog.js | 18 +-- .../views/dialogs/AskInviteAnywayDialog.tsx | 4 +- src/components/views/dialogs/BaseDialog.js | 2 +- .../views/dialogs/BetaFeedbackDialog.tsx | 2 +- .../views/dialogs/BugReportDialog.tsx | 10 +- .../views/dialogs/ChangelogDialog.tsx | 8 +- .../CommunityPrototypeInviteDialog.tsx | 20 +-- .../views/dialogs/ConfirmWipeDeviceDialog.tsx | 4 +- .../CreateCommunityPrototypeDialog.tsx | 24 ++-- .../views/dialogs/CreateGroupDialog.tsx | 4 +- .../views/dialogs/CreateRoomDialog.tsx | 12 +- .../views/dialogs/DeactivateAccountDialog.tsx | 12 +- .../views/dialogs/DevtoolsDialog.tsx | 120 +++++++++--------- .../dialogs/EditCommunityPrototypeDialog.tsx | 8 +- .../views/dialogs/FeedbackDialog.js | 14 +- .../views/dialogs/HostSignupDialog.tsx | 28 ++-- .../views/dialogs/IncomingSasDialog.js | 28 ++-- .../dialogs/IntegrationsDisabledDialog.js | 2 +- .../dialogs/IntegrationsImpossibleDialog.js | 4 +- .../views/dialogs/InteractiveAuthDialog.js | 2 +- src/components/views/dialogs/InviteDialog.tsx | 112 ++++++++-------- .../dialogs/KeySignatureUploadFailedDialog.js | 18 +-- .../dialogs/LazyLoadingDisabledDialog.js | 2 +- .../views/dialogs/LazyLoadingResyncDialog.js | 2 +- src/components/views/dialogs/LogoutDialog.js | 14 +- .../views/dialogs/MessageEditHistoryDialog.js | 14 +- .../views/dialogs/ModalWidgetDialog.tsx | 4 +- .../dialogs/RegistrationEmailPromptDialog.tsx | 6 +- .../views/dialogs/ReportEventDialog.tsx | 114 ++++++++--------- .../views/dialogs/RoomUpgradeDialog.js | 14 +- .../views/dialogs/RoomUpgradeWarningDialog.js | 26 ++-- .../views/dialogs/ServerOfflineDialog.tsx | 40 +++--- .../views/dialogs/ServerPickerDialog.tsx | 14 +- .../views/dialogs/SeshatResetDialog.tsx | 6 +- .../views/dialogs/SlashCommandHelpDialog.js | 10 +- .../views/dialogs/StorageEvictedDialog.js | 10 +- .../dialogs/TabbedIntegrationManagerDialog.js | 6 +- src/components/views/dialogs/TermsDialog.tsx | 28 ++-- .../views/dialogs/UntrustedDeviceDialog.tsx | 8 +- .../views/dialogs/UploadConfirmDialog.tsx | 10 +- .../views/dialogs/UploadFailureDialog.js | 12 +- .../views/dialogs/UserSettingsDialog.tsx | 4 +- .../WidgetCapabilitiesPromptDialog.tsx | 10 +- .../dialogs/WidgetOpenIDPermissionsDialog.js | 6 +- .../security/AccessSecretStorageDialog.tsx | 36 +++--- .../ConfirmDestroyCrossSigningDialog.tsx | 4 +- .../security/CreateCrossSigningDialog.tsx | 4 +- .../security/RestoreKeyBackupDialog.js | 60 ++++----- .../views/directory/NetworkDropdown.tsx | 14 +- .../views/elements/AppPermission.js | 30 ++--- src/components/views/elements/AppTile.js | 6 +- src/components/views/elements/DNDTagTile.js | 2 +- .../views/elements/DesktopBuildsNotice.tsx | 14 +- .../elements/DesktopCapturerSourcePicker.tsx | 6 +- .../views/elements/DialogButtons.js | 2 +- .../views/elements/DirectorySearchBox.js | 2 +- .../views/elements/EditableItemList.tsx | 12 +- .../views/elements/ErrorBoundary.tsx | 14 +- src/components/views/elements/FacePile.tsx | 2 +- src/components/views/elements/Field.tsx | 14 +- src/components/views/elements/ImageView.tsx | 6 +- src/components/views/elements/InfoTooltip.tsx | 4 +- .../views/elements/InlineSpinner.tsx | 2 +- .../views/elements/InviteReason.tsx | 4 +- .../views/elements/LabelledToggleSwitch.tsx | 4 +- .../views/elements/PersistedElement.js | 4 +- .../views/elements/PowerSelector.js | 2 +- .../views/elements/RoomAliasField.tsx | 2 +- .../views/elements/ServerPicker.tsx | 10 +- .../views/elements/SettingsFlag.tsx | 4 +- src/components/views/elements/Slider.tsx | 4 +- .../elements/SpellCheckLanguagesDropdown.tsx | 10 +- src/components/views/elements/Spoiler.js | 2 +- .../views/elements/StyledCheckbox.tsx | 2 +- .../views/elements/StyledRadioButton.tsx | 10 +- .../views/elements/StyledRadioGroup.tsx | 4 +- src/components/views/elements/TagTile.js | 8 +- .../views/elements/TextWithTooltip.js | 6 +- src/components/views/elements/Validation.tsx | 12 +- src/components/views/emojipicker/Category.tsx | 2 +- src/components/views/emojipicker/Emoji.tsx | 2 +- .../views/emojipicker/EmojiPicker.tsx | 6 +- src/components/views/emojipicker/Header.tsx | 4 +- src/components/views/emojipicker/Preview.tsx | 6 +- .../views/emojipicker/QuickReactions.tsx | 10 +- src/components/views/emojipicker/Search.tsx | 2 +- .../views/groups/GroupInviteTile.js | 2 +- .../views/groups/GroupMemberList.js | 2 +- .../views/host_signup/HostSignupContainer.tsx | 2 +- .../views/messages/EditHistoryMessage.js | 14 +- src/components/views/messages/MFileBody.js | 10 +- src/components/views/messages/MImageBody.tsx | 11 +- .../messages/MKeyVerificationRequest.tsx | 8 +- .../views/messages/MessageActionBar.js | 2 +- .../views/messages/MessageTimestamp.tsx | 2 +- src/components/views/messages/MjolnirBody.js | 6 +- .../views/messages/ReactionsRow.tsx | 2 +- .../views/messages/ReactionsRowButton.tsx | 6 +- .../messages/ReactionsRowButtonTooltip.tsx | 8 +- src/components/views/messages/RoomCreate.js | 2 +- src/components/views/messages/TextualBody.tsx | 10 +- .../views/messages/TileErrorBoundary.tsx | 4 +- .../views/messages/ViewSourceEvent.js | 6 +- src/components/views/right_panel/BaseCard.tsx | 4 +- .../views/right_panel/EncryptionInfo.tsx | 22 ++-- .../views/right_panel/EncryptionPanel.tsx | 10 +- .../views/right_panel/HeaderButtons.tsx | 2 +- .../views/right_panel/RoomSummaryCard.tsx | 12 +- src/components/views/right_panel/UserInfo.tsx | 30 ++--- .../views/right_panel/VerificationPanel.tsx | 60 ++++----- .../views/room_settings/AliasSettings.tsx | 12 +- .../room_settings/RelatedGroupSettings.js | 2 +- .../room_settings/RoomProfileSettings.js | 4 +- src/components/views/rooms/AuxPanel.tsx | 4 +- src/components/views/rooms/EntityTile.tsx | 10 +- src/components/views/rooms/EventTile.tsx | 10 +- src/components/views/rooms/ExtraTile.tsx | 8 +- .../views/rooms/JumpToBottomButton.js | 2 +- src/components/views/rooms/MemberList.tsx | 6 +- .../views/rooms/MessageComposer.tsx | 6 +- src/components/views/rooms/NewRoomIntro.tsx | 20 +-- .../views/rooms/NotificationBadge.tsx | 4 +- .../views/rooms/RoomBreadcrumbs.tsx | 4 +- src/components/views/rooms/RoomHeader.tsx | 8 +- src/components/views/rooms/RoomList.tsx | 22 ++-- src/components/views/rooms/RoomPreviewBar.js | 10 +- src/components/views/rooms/RoomSublist.tsx | 56 ++++---- src/components/views/rooms/RoomTile.tsx | 26 ++-- .../views/rooms/RoomUpgradeWarningBar.js | 28 ++-- src/components/views/rooms/SearchBar.tsx | 6 +- .../views/rooms/SendMessageComposer.tsx | 2 +- .../views/rooms/ThirdPartyMemberInfo.tsx | 10 +- .../views/rooms/VoiceRecordComposerTile.tsx | 14 +- .../views/rooms/WhoIsTypingTile.tsx | 8 +- .../views/settings/AvatarSetting.js | 10 +- src/components/views/settings/BridgeTile.tsx | 34 ++--- .../views/settings/ChangePassword.js | 2 +- .../views/settings/CrossSigningPanel.js | 56 ++++---- src/components/views/settings/DevicesPanel.js | 2 +- .../views/settings/E2eAdvancedPanel.tsx | 6 +- .../views/settings/EventIndexPanel.tsx | 38 +++--- .../views/settings/IntegrationManager.js | 6 +- .../views/settings/ProfileSettings.js | 16 +-- .../views/settings/SecureBackupPanel.js | 88 ++++++------- src/components/views/settings/SetIdServer.tsx | 56 ++++---- .../views/settings/SetIntegrationManager.tsx | 12 +- .../views/settings/SpellCheckSettings.tsx | 28 ++-- .../views/settings/UpdateCheckButton.tsx | 8 +- .../views/settings/account/EmailAddresses.js | 20 +-- .../views/settings/account/PhoneNumbers.js | 24 ++-- .../settings/discovery/EmailAddresses.js | 16 +-- .../views/settings/discovery/PhoneNumbers.js | 16 +-- .../tabs/room/AdvancedRoomSettingsTab.tsx | 4 +- .../settings/tabs/room/BridgeSettingsTab.tsx | 16 +-- .../tabs/room/GeneralRoomSettingsTab.js | 12 +- .../tabs/room/NotificationSettingsTab.js | 18 +-- .../tabs/room/RolesRoomSettingsTab.tsx | 32 ++--- .../tabs/room/SecurityRoomSettingsTab.tsx | 36 +++--- .../tabs/user/AppearanceUserSettingsTab.tsx | 36 +++--- .../tabs/user/FlairUserSettingsTab.js | 2 +- .../tabs/user/GeneralUserSettingsTab.js | 60 ++++----- .../tabs/user/HelpUserSettingsTab.tsx | 66 +++++----- .../settings/tabs/user/LabsUserSettingsTab.js | 6 +- .../tabs/user/MjolnirUserSettingsTab.tsx | 74 +++++------ .../tabs/user/NotificationUserSettingsTab.tsx | 2 +- .../tabs/user/PreferencesUserSettingsTab.tsx | 42 +++--- .../tabs/user/SecurityUserSettingsTab.js | 80 ++++++------ .../tabs/user/VoiceUserSettingsTab.tsx | 8 +- src/components/views/spaces/SpacePanel.tsx | 12 +- .../views/spaces/SpaceSettingsGeneralTab.tsx | 2 +- .../spaces/SpaceSettingsVisibilityTab.tsx | 2 +- .../views/spaces/SpaceTreeLevel.tsx | 4 +- .../views/terms/InlineTermsAgreement.tsx | 12 +- src/components/views/toasts/GenericToast.tsx | 8 +- .../toasts/NonUrgentEchoFailureToast.tsx | 6 +- .../views/toasts/VerificationRequestToast.tsx | 8 +- .../verification/VerificationCancelled.tsx | 4 +- .../verification/VerificationComplete.tsx | 8 +- .../verification/VerificationShowSas.tsx | 24 ++-- src/components/views/voip/CallView.tsx | 64 +++++----- src/components/views/voip/DialPad.tsx | 6 +- src/components/views/voip/DialPadModal.tsx | 2 +- src/components/views/voip/IncomingCallBox.tsx | 8 +- src/createRoom.ts | 7 +- src/editor/parts.ts | 6 +- src/languageHandler.tsx | 6 +- src/mjolnir/Mjolnir.ts | 55 ++++---- src/rageshake/submit-rageshake.ts | 6 +- src/stores/GroupFilterOrderStore.js | 2 +- src/stores/LifecycleStore.ts | 2 +- src/stores/RightPanelStore.ts | 2 +- src/stores/RoomViewStore.tsx | 6 +- src/stores/room-list/MessagePreviewStore.ts | 2 +- src/toasts/ServerLimitToast.tsx | 2 +- src/toasts/UpdateToast.tsx | 2 +- src/utils/AutoDiscoveryUtils.tsx | 6 +- src/utils/ErrorUtils.tsx | 8 +- src/widgets/CapabilityText.tsx | 20 +-- test/accessibility/RovingTabIndex-test.js | 12 +- test/createRoom-test.js | 8 +- 266 files changed, 1992 insertions(+), 2000 deletions(-) diff --git a/package.json b/package.json index 6e10bafaea..4e2e933a52 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "start:build": "babel src -w -s -d lib --verbose --extensions \".ts,.js\"", "lint": "yarn lint:types && yarn lint:js && yarn lint:style", "lint:js": "eslint --max-warnings 0 src test", + "lint:js-fix": "eslint --fix src test", "lint:types": "tsc --noEmit --jsx react", "lint:style": "stylelint 'res/css/**/*.scss'", "test": "jest", diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 7192eb81cc..051e865464 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -50,6 +50,8 @@ import UIStore from "../stores/UIStore"; import { SetupEncryptionStore } from "../stores/SetupEncryptionStore"; import { RoomScrollStateStore } from "../stores/RoomScrollStateStore"; +/* eslint-disable @typescript-eslint/naming-convention */ + declare global { interface Window { matrixChat: ReturnType; @@ -186,3 +188,5 @@ declare global { } ); } + +/* eslint-enable @typescript-eslint/naming-convention */ diff --git a/src/Analytics.tsx b/src/Analytics.tsx index ce8287de56..fc4664039f 100644 --- a/src/Analytics.tsx +++ b/src/Analytics.tsx @@ -270,7 +270,7 @@ export class Analytics { localStorage.removeItem(LAST_VISIT_TS_KEY); } - private async _track(data: IData) { + private async track(data: IData) { if (this.disabled) return; const now = new Date(); @@ -304,7 +304,7 @@ export class Analytics { } public ping() { - this._track({ + this.track({ ping: "1", }); localStorage.setItem(LAST_VISIT_TS_KEY, String(new Date().getTime())); // update last visit ts @@ -324,14 +324,14 @@ export class Analytics { // But continue anyway because we still want to track the change } - this._track({ + this.track({ gt_ms: String(generationTimeMs), }); } public trackEvent(category: string, action: string, name?: string, value?: string) { if (this.disabled) return; - this._track({ + this.track({ e_c: category, e_a: action, e_n: name, @@ -395,17 +395,17 @@ export class Analytics { Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, { title: _t('Analytics'), description:
    -
    {_t('The information being sent to us to help make %(brand)s better includes:', { +
    { _t('The information being sent to us to help make %(brand)s better includes:', { brand: SdkConfig.get().brand, - })}
    + }) }
    { rows.map((row) => - + ) } { row[1] !== undefined && } ) } { otherVariables.map((item, index) => diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index f90854ee64..489d28e26b 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -615,23 +615,23 @@ export default class CallHandler extends EventEmitter { private showICEFallbackPrompt() { const cli = MatrixClientPeg.get(); - const code = sub => {sub}; + const code = sub => { sub }; Modal.createTrackedDialog('No TURN servers', '', QuestionDialog, { title: _t("Call failed due to misconfigured server"), description:
    -

    {_t( +

    { _t( "Please ask the administrator of your homeserver " + "(%(homeserverDomain)s) to configure a TURN server in " + "order for calls to work reliably.", { homeserverDomain: cli.getDomain() }, { code }, - )}

    -

    {_t( + ) }

    +

    { _t( "Alternatively, you can try to use the public server at " + "turn.matrix.org, but this will not be as reliable, and " + "it will share your IP address with that server. You can also manage " + "this in Settings.", null, { code }, - )}

    + ) }

    , button: _t('Try using turn.matrix.org'), cancelButton: _t('OK'), @@ -649,19 +649,19 @@ export default class CallHandler extends EventEmitter { if (call.type === CallType.Voice) { title = _t("Unable to access microphone"); description =
    - {_t( + { _t( "Call failed because microphone could not be accessed. " + "Check that a microphone is plugged in and set up correctly.", - )} + ) }
    ; } else if (call.type === CallType.Video) { title = _t("Unable to access webcam / microphone"); description =
    - {_t("Call failed because webcam or microphone could not be accessed. Check that:")} + { _t("Call failed because webcam or microphone could not be accessed. Check that:") }
      -
    • {_t("A microphone and webcam are plugged in and set up correctly")}
    • -
    • {_t("Permission is granted to use the webcam")}
    • -
    • {_t("No other application is using the webcam")}
    • +
    • { _t("A microphone and webcam are plugged in and set up correctly") }
    • +
    • { _t("Permission is granted to use the webcam") }
    • +
    • { _t("No other application is using the webcam") }
    ; } diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx index 0c65a7bd35..c5bcb226ff 100644 --- a/src/ContentMessages.tsx +++ b/src/ContentMessages.tsx @@ -425,10 +425,10 @@ export default class ContentMessages { const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Reply Warning', '', QuestionDialog, { title: _t('Replying With Files'), description: ( -
    {_t( +
    { _t( 'At this time it is not possible to reply with a file. ' + 'Would you like to upload this file without replying?', - )}
    + ) }
    ), hasCancelButton: true, button: _t("Continue"), diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index d033063677..51c624e3c3 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -33,6 +33,7 @@ import { isSecretStorageBeingAccessed, accessSecretStorage } from "./SecurityMan import { isSecureBackupRequired } from './utils/WellKnownUtils'; import { isLoggedIn } from './components/structures/MatrixChat'; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { ActionPayload } from "./dispatcher/payloads"; const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000; @@ -58,28 +59,28 @@ export default class DeviceListener { } start() { - MatrixClientPeg.get().on('crypto.willUpdateDevices', this._onWillUpdateDevices); - MatrixClientPeg.get().on('crypto.devicesUpdated', this._onDevicesUpdated); - MatrixClientPeg.get().on('deviceVerificationChanged', this._onDeviceVerificationChanged); - MatrixClientPeg.get().on('userTrustStatusChanged', this._onUserTrustStatusChanged); - MatrixClientPeg.get().on('crossSigning.keysChanged', this._onCrossSingingKeysChanged); - MatrixClientPeg.get().on('accountData', this._onAccountData); - MatrixClientPeg.get().on('sync', this._onSync); - MatrixClientPeg.get().on('RoomState.events', this._onRoomStateEvents); - this.dispatcherRef = dis.register(this._onAction); - this._recheck(); + MatrixClientPeg.get().on('crypto.willUpdateDevices', this.onWillUpdateDevices); + MatrixClientPeg.get().on('crypto.devicesUpdated', this.onDevicesUpdated); + MatrixClientPeg.get().on('deviceVerificationChanged', this.onDeviceVerificationChanged); + MatrixClientPeg.get().on('userTrustStatusChanged', this.onUserTrustStatusChanged); + MatrixClientPeg.get().on('crossSigning.keysChanged', this.onCrossSingingKeysChanged); + MatrixClientPeg.get().on('accountData', this.onAccountData); + MatrixClientPeg.get().on('sync', this.onSync); + MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents); + this.dispatcherRef = dis.register(this.onAction); + this.recheck(); } stop() { if (MatrixClientPeg.get()) { - MatrixClientPeg.get().removeListener('crypto.willUpdateDevices', this._onWillUpdateDevices); - MatrixClientPeg.get().removeListener('crypto.devicesUpdated', this._onDevicesUpdated); - MatrixClientPeg.get().removeListener('deviceVerificationChanged', this._onDeviceVerificationChanged); - MatrixClientPeg.get().removeListener('userTrustStatusChanged', this._onUserTrustStatusChanged); - MatrixClientPeg.get().removeListener('crossSigning.keysChanged', this._onCrossSingingKeysChanged); - MatrixClientPeg.get().removeListener('accountData', this._onAccountData); - MatrixClientPeg.get().removeListener('sync', this._onSync); - MatrixClientPeg.get().removeListener('RoomState.events', this._onRoomStateEvents); + MatrixClientPeg.get().removeListener('crypto.willUpdateDevices', this.onWillUpdateDevices); + MatrixClientPeg.get().removeListener('crypto.devicesUpdated', this.onDevicesUpdated); + MatrixClientPeg.get().removeListener('deviceVerificationChanged', this.onDeviceVerificationChanged); + MatrixClientPeg.get().removeListener('userTrustStatusChanged', this.onUserTrustStatusChanged); + MatrixClientPeg.get().removeListener('crossSigning.keysChanged', this.onCrossSingingKeysChanged); + MatrixClientPeg.get().removeListener('accountData', this.onAccountData); + MatrixClientPeg.get().removeListener('sync', this.onSync); + MatrixClientPeg.get().removeListener('RoomState.events', this.onRoomStateEvents); } if (this.dispatcherRef) { dis.unregister(this.dispatcherRef); @@ -103,15 +104,15 @@ export default class DeviceListener { this.dismissed.add(d); } - this._recheck(); + this.recheck(); } dismissEncryptionSetup() { this.dismissedThisDeviceToast = true; - this._recheck(); + this.recheck(); } - _ensureDeviceIdsAtStartPopulated() { + private ensureDeviceIdsAtStartPopulated() { if (this.ourDeviceIdsAtStart === null) { const cli = MatrixClientPeg.get(); this.ourDeviceIdsAtStart = new Set( @@ -120,39 +121,39 @@ export default class DeviceListener { } } - _onWillUpdateDevices = async (users: string[], initialFetch?: boolean) => { + private onWillUpdateDevices = async (users: string[], initialFetch?: boolean) => { // If we didn't know about *any* devices before (ie. it's fresh login), // then they are all pre-existing devices, so ignore this and set the // devicesAtStart list to the devices that we see after the fetch. if (initialFetch) return; const myUserId = MatrixClientPeg.get().getUserId(); - if (users.includes(myUserId)) this._ensureDeviceIdsAtStartPopulated(); + if (users.includes(myUserId)) this.ensureDeviceIdsAtStartPopulated(); // No need to do a recheck here: we just need to get a snapshot of our devices // before we download any new ones. }; - _onDevicesUpdated = (users: string[]) => { + private onDevicesUpdated = (users: string[]) => { if (!users.includes(MatrixClientPeg.get().getUserId())) return; - this._recheck(); + this.recheck(); }; - _onDeviceVerificationChanged = (userId: string) => { + private onDeviceVerificationChanged = (userId: string) => { if (userId !== MatrixClientPeg.get().getUserId()) return; - this._recheck(); + this.recheck(); }; - _onUserTrustStatusChanged = (userId: string) => { + private onUserTrustStatusChanged = (userId: string) => { if (userId !== MatrixClientPeg.get().getUserId()) return; - this._recheck(); + this.recheck(); }; - _onCrossSingingKeysChanged = () => { - this._recheck(); + private onCrossSingingKeysChanged = () => { + this.recheck(); }; - _onAccountData = (ev) => { + private onAccountData = (ev: MatrixEvent) => { // User may have: // * migrated SSSS to symmetric // * uploaded keys to secret storage @@ -163,32 +164,32 @@ export default class DeviceListener { ev.getType().startsWith('m.cross_signing.') || ev.getType() === 'm.megolm_backup.v1' ) { - this._recheck(); + this.recheck(); } }; - _onSync = (state, prevState) => { - if (state === 'PREPARED' && prevState === null) this._recheck(); + private onSync = (state, prevState) => { + if (state === 'PREPARED' && prevState === null) this.recheck(); }; - _onRoomStateEvents = (ev: MatrixEvent) => { + private onRoomStateEvents = (ev: MatrixEvent) => { if (ev.getType() !== "m.room.encryption") { return; } // If a room changes to encrypted, re-check as it may be our first // encrypted room. This also catches encrypted room creation as well. - this._recheck(); + this.recheck(); }; - _onAction = ({ action }) => { + private onAction = ({ action }: ActionPayload) => { if (action !== "on_logged_in") return; - this._recheck(); + this.recheck(); }; // The server doesn't tell us when key backup is set up, so we poll // & cache the result - async _getKeyBackupInfo() { + private async getKeyBackupInfo() { const now = (new Date()).getTime(); if (!this.keyBackupInfo || this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) { this.keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); @@ -206,7 +207,7 @@ export default class DeviceListener { return cli && cli.getRooms().some(r => cli.isRoomEncrypted(r.roomId)); } - async _recheck() { + private async recheck() { const cli = MatrixClientPeg.get(); if (!await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) return; @@ -235,7 +236,7 @@ export default class DeviceListener { // Cross-signing on account but this device doesn't trust the master key (verify this session) showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION); } else { - const backupInfo = await this._getKeyBackupInfo(); + const backupInfo = await this.getKeyBackupInfo(); if (backupInfo) { // No cross-signing on account but key backup available (upgrade encryption) showSetupEncryptionToast(SetupKind.UPGRADE_ENCRYPTION); @@ -256,7 +257,7 @@ export default class DeviceListener { // This needs to be done after awaiting on downloadKeys() above, so // we make sure we get the devices after the fetch is done. - this._ensureDeviceIdsAtStartPopulated(); + this.ensureDeviceIdsAtStartPopulated(); // Unverified devices that were there last time the app ran // (technically could just be a boolean: we don't actually diff --git a/src/IdentityAuthClient.js b/src/IdentityAuthClient.js index 447c5edd30..e91e1d72cf 100644 --- a/src/IdentityAuthClient.js +++ b/src/IdentityAuthClient.js @@ -149,17 +149,17 @@ export default class IdentityAuthClient { title: _t("Identity server has no terms of service"), description: (
    -

    {_t( +

    { _t( "This action requires accessing the default identity server " + " to validate an email address or phone number, " + "but the server does not have any terms of service.", {}, { - server: () => {abbreviateUrl(identityServerUrl)}, + server: () => { abbreviateUrl(identityServerUrl) }, }, - )}

    -

    {_t( + ) }

    +

    { _t( "Only continue if you trust the owner of the server.", - )}

    + ) }

    ), button: _t("Trust"), diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index e9364b1b47..f43351aab2 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -105,7 +105,7 @@ export interface IMatrixClientPeg { * This module provides a singleton instance of this class so the 'current' * Matrix Client object is available easily. */ -class _MatrixClientPeg implements IMatrixClientPeg { +class MatrixClientPegClass implements IMatrixClientPeg { // These are the default options used when when the // client is started in 'start'. These can be altered // at any time up to after the 'will_start_client' @@ -300,7 +300,7 @@ class _MatrixClientPeg implements IMatrixClientPeg { } if (!window.mxMatrixClientPeg) { - window.mxMatrixClientPeg = new _MatrixClientPeg(); + window.mxMatrixClientPeg = new MatrixClientPegClass(); } export const MatrixClientPeg = window.mxMatrixClientPeg; diff --git a/src/Modal.tsx b/src/Modal.tsx index 55fc871d67..da4c8ae732 100644 --- a/src/Modal.tsx +++ b/src/Modal.tsx @@ -122,14 +122,14 @@ export class ModalManager { } public createDialog( - Element: React.ComponentType, + Element: React.ComponentType, // eslint-disable-line @typescript-eslint/naming-convention ...rest: ParametersWithoutFirst ) { return this.createDialogAsync(Promise.resolve(Element), ...rest); } public appendDialog( - Element: React.ComponentType, + Element: React.ComponentType, // eslint-disable-line @typescript-eslint/naming-convention ...rest: ParametersWithoutFirst ) { return this.appendDialogAsync(Promise.resolve(Element), ...rest); @@ -378,7 +378,7 @@ export class ModalManager { const dialog = (
    - {modal.elem} + { modal.elem }
    diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index 7753ff6f75..9f5ac83a56 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -480,14 +480,14 @@ export const Commands = [ 'Identity server', QuestionDialog, { title: _t("Use an identity server"), - description:

    {_t( + description:

    { _t( "Use an identity server to invite by email. " + "Click continue to use the default identity server " + "(%(defaultIdentityServerName)s) or manage in Settings.", { defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl), }, - )}

    , + ) }

    , button: _t("Continue"), }, ); @@ -522,7 +522,7 @@ export const Commands = [ aliases: ['j', 'goto'], args: '', description: _td('Joins room with given address'), - runFn: function(_, args) { + runFn: function(roomId, args) { if (args) { // Note: we support 2 versions of this command. The first is // the public-facing one for most users and the other is a @@ -1069,7 +1069,7 @@ export const Commands = [ command: "msg", description: _td("Sends a message to the given user"), args: " ", - runFn: function(_, args) { + runFn: function(roomId, args) { if (args) { // matches the first whitespace delimited group and then the rest of the string const matches = args.match(/^(\S+?)(?: +(.*))?$/s); diff --git a/src/accessibility/KeyboardShortcuts.tsx b/src/accessibility/KeyboardShortcuts.tsx index c5cf85facd..9cc7b60c99 100644 --- a/src/accessibility/KeyboardShortcuts.tsx +++ b/src/accessibility/KeyboardShortcuts.tsx @@ -370,8 +370,8 @@ export const toggleDialog = () => { const sections = categoryOrder.map(category => { const list = shortcuts[category]; return
    -

    {_t(category)}

    -
    {list.map(shortcut => )}
    +

    { _t(category) }

    +
    { list.map(shortcut => ) }
    ; }); diff --git a/src/accessibility/Toolbar.tsx b/src/accessibility/Toolbar.tsx index 8d882fadea..90538760bb 100644 --- a/src/accessibility/Toolbar.tsx +++ b/src/accessibility/Toolbar.tsx @@ -62,9 +62,9 @@ const Toolbar: React.FC = ({ children, ...props }) => { }; return - {({ onKeyDownHandler }) =>
    + { ({ onKeyDownHandler }) =>
    { children } -
    } +
    }
    ; }; diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index a19494c753..e1c2b7b202 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -59,8 +59,8 @@ export default class DisableEventIndexDialog extends React.Component { return ( - {_t("If disabled, messages from encrypted rooms won't appear in search results.")} - {this.state.disabling ? :
    } + { _t("If disabled, messages from encrypted rooms won't appear in search results.") } + { this.state.disabling ? :
    } - {_t( + { _t( "%(brand)s is securely caching encrypted messages locally for them " + "to appear in search results:", { brand }, - )} + ) }
    - {crawlerState}
    - {_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}
    - {_t("Indexed messages:")} {formatCountLong(this.state.eventCount)}
    - {_t("Indexed rooms:")} {_t("%(doneRooms)s out of %(totalRooms)s", { + { crawlerState }
    + { _t("Space used:") } { formatBytes(this.state.eventIndexSize, 0) }
    + { _t("Indexed messages:") } { formatCountLong(this.state.eventCount) }
    + { _t("Indexed rooms:") } { _t("%(doneRooms)s out of %(totalRooms)s", { doneRooms: formatCountLong(doneRooms), totalRooms: formatCountLong(this.state.roomCount), - })}
    + }) }
    - {eventIndexingSettings} + { eventIndexingSettings } -

    {_t( +

    { _t( "Warning: You should only set up key backup from a trusted computer.", {}, - { b: sub => {sub} }, - )}

    -

    {_t( + { b: sub => { sub } }, + ) }

    +

    { _t( "We'll store an encrypted copy of your keys on our server. " + "Secure your backup with a Security Phrase.", - )}

    -

    {_t("For maximum security, this should be different from your account password.")}

    + ) }

    +

    { _t("For maximum security, this should be different from your account password.") }

    @@ -268,9 +268,9 @@ export default class CreateKeyBackupDialog extends React.PureComponent { />
    - {_t("Advanced")} + { _t("Advanced") } - {_t("Set up with a Security Key")} + { _t("Set up with a Security Key") }
    ; @@ -299,19 +299,19 @@ export default class CreateKeyBackupDialog extends React.PureComponent { let passPhraseMatch = null; if (matchText) { passPhraseMatch =
    -
    {matchText}
    +
    { matchText }
    - {changeText} + { changeText }
    ; } const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return
    -

    {_t( +

    { _t( "Enter your Security Phrase a second time to confirm it.", - )}

    + ) }

    @@ -323,7 +323,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent { autoFocus={true} />
    - {passPhraseMatch} + { passPhraseMatch }
    -

    {_t( +

    { _t( "Your Security Key is a safety net - you can use it to restore " + "access to your encrypted messages if you forget your Security Phrase.", - )}

    -

    {_t( + ) }

    +

    { _t( "Keep a copy of it somewhere secure, like a password manager or even a safe.", - )}

    + ) }

    - {_t("Your Security Key")} + { _t("Your Security Key") }
    - {this._keyBackupInfo.recovery_key} + { this._keyBackupInfo.recovery_key }
    @@ -370,26 +370,26 @@ export default class CreateKeyBackupDialog extends React.PureComponent { if (this.state.copied) { introText = _t( "Your Security Key has been copied to your clipboard, paste it to:", - {}, { b: s => {s} }, + {}, { b: s => { s } }, ); } else if (this.state.downloaded) { introText = _t( "Your Security Key is in your Downloads folder.", - {}, { b: s => {s} }, + {}, { b: s => { s } }, ); } const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return
    - {introText} + { introText }
      -
    • {_t("Print it and store it somewhere safe", {}, { b: s => {s} })}
    • -
    • {_t("Save it on a USB key or backup drive", {}, { b: s => {s} })}
    • -
    • {_t("Copy it to your personal cloud storage", {}, { b: s => {s} })}
    • +
    • { _t("Print it and store it somewhere safe", {}, { b: s => { s } }) }
    • +
    • { _t("Save it on a USB key or backup drive", {}, { b: s => { s } }) }
    • +
    • { _t("Copy it to your personal cloud storage", {}, { b: s => { s } }) }
    - +
    ; } @@ -404,9 +404,9 @@ export default class CreateKeyBackupDialog extends React.PureComponent { _renderPhaseDone() { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return
    -

    {_t( +

    { _t( "Your keys are being backed up (the first backup could take a few minutes).", - )}

    + ) }

    - {_t( + { _t( "Without setting up Secure Message Recovery, you won't be able to restore your " + "encrypted message history if you log out or use another session.", - )} + ) } -

    {_t("Unable to create key backup")}

    +

    { _t("Unable to create key backup") }

    - {content} + { content }
    ); diff --git a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.js index e1254929db..aa78d68830 100644 --- a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.js +++ b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.js @@ -475,9 +475,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent { >
    - {_t("Generate a Security Key")} + { _t("Generate a Security Key") }
    -
    {_t("We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.")}
    +
    { _t("We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.") }
    ); } @@ -494,9 +494,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent { >
    - {_t("Enter a Security Phrase")} + { _t("Enter a Security Phrase") }
    -
    {_t("Use a secret phrase only you know, and optionally save a Security Key to use for backup.")}
    +
    { _t("Use a secret phrase only you know, and optionally save a Security Key to use for backup.") }
    ); } @@ -507,13 +507,13 @@ export default class CreateSecretStorageDialog extends React.PureComponent { const optionPassphrase = setupMethods.includes("passphrase") ? this._renderOptionPassphrase() : null; return -

    {_t( +

    { _t( "Safeguard against losing access to encrypted messages & data by " + "backing up encryption keys on your server.", - )}

    + ) }

    - {optionKey} - {optionPassphrase} + { optionKey } + { optionPassphrase }
    -
    {_t("Enter your account password to confirm the upgrade:")}
    +
    { _t("Enter your account password to confirm the upgrade:") }
    ; } else if (!this.state.backupSigStatus.usable) { authPrompt =
    -
    {_t("Restore your key backup to upgrade your encryption")}
    +
    { _t("Restore your key backup to upgrade your encryption") }
    ; nextCaption = _t("Restore"); } else { authPrompt =

    - {_t("You'll need to authenticate with the server to confirm the upgrade.")} + { _t("You'll need to authenticate with the server to confirm the upgrade.") }

    ; } return -

    {_t( +

    { _t( "Upgrade this session to allow it to verify other sessions, " + "granting them access to encrypted messages and marking them " + "as trusted for other users.", - )}

    -
    {authPrompt}
    + ) }

    +
    { authPrompt }
    ; @@ -579,10 +579,10 @@ export default class CreateSecretStorageDialog extends React.PureComponent { _renderPhasePassPhrase() { return
    -

    {_t( +

    { _t( "Enter a security phrase only you know, as it’s used to safeguard your data. " + "To be secure, you shouldn’t re-use your account password.", - )}

    + ) }

    {_t("Cancel")} + >{ _t("Cancel") } ; } @@ -637,18 +637,18 @@ export default class CreateSecretStorageDialog extends React.PureComponent { let passPhraseMatch = null; if (matchText) { passPhraseMatch =
    -
    {matchText}
    +
    { matchText }
    - {changeText} + { changeText }
    ; } return
    -

    {_t( +

    { _t( "Enter your Security Phrase a second time to confirm it.", - )}

    + ) }

    - {passPhraseMatch} + { passPhraseMatch }
    {_t("Skip")} + >{ _t("Skip") } ; } @@ -691,35 +691,35 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
    ; } return
    -

    {_t( +

    { _t( "Store your Security Key somewhere safe, like a password manager or a safe, " + "as it’s used to safeguard your encrypted data.", - )}

    + ) }

    - {this._recoveryKey.encodedPrivateKey} + { this._recoveryKey.encodedPrivateKey }
    - {_t("Download")} + { _t("Download") } - {_t("or")} + { _t("or") } - {this.state.copied ? _t("Copied!") : _t("Copy")} + { this.state.copied ? _t("Copied!") : _t("Copy") }
    - {continueButton} + { continueButton }
    ; } @@ -732,7 +732,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { _renderPhaseLoadError() { return
    -

    {_t("Unable to query secret storage status")}

    +

    { _t("Unable to query secret storage status") }

    -

    {_t( +

    { _t( "If you cancel now, you may lose encrypted messages & data if you lose access to your logins.", - )}

    -

    {_t( + ) }

    +

    { _t( "You can also set up Secure Backup & manage your keys in Settings.", - )}

    + ) }

    - +
    ; } @@ -787,7 +787,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { let content; if (this.state.error) { content =
    -

    {_t("Unable to set up secret storage")}

    +

    { _t("Unable to set up secret storage") }

    - {content} + { content }
    ); diff --git a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.js b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.js index 4a0aa37da0..263d25c98c 100644 --- a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.js +++ b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.js @@ -54,28 +54,28 @@ export default class NewRecoveryMethodDialog extends React.PureComponent { const DialogButtons = sdk.getComponent("views.elements.DialogButtons"); const title = - {_t("New Recovery Method")} + { _t("New Recovery Method") } ; - const newMethodDetected =

    {_t( + const newMethodDetected =

    { _t( "A new Security Phrase and key for Secure Messages have been detected.", - )}

    ; + ) }

    ; - const hackWarning =

    {_t( + const hackWarning =

    { _t( "If you didn't set the new recovery method, an " + "attacker may be trying to access your account. " + "Change your account password and set a new recovery " + "method immediately in Settings.", - )}

    ; + ) }

    ; let content; if (MatrixClientPeg.get().getKeyBackupEnabled()) { content =
    - {newMethodDetected} -

    {_t( + { newMethodDetected } +

    { _t( "This session is encrypting history using the new recovery method.", - )}

    - {hackWarning} + ) }

    + { hackWarning } ; } else { content =
    - {newMethodDetected} - {hackWarning} + { newMethodDetected } + { hackWarning } - {content} + { content } ); } diff --git a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.js b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.js index f0f8a5273b..f586c9430a 100644 --- a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.js +++ b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.js @@ -46,7 +46,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent { const DialogButtons = sdk.getComponent("views.elements.DialogButtons"); const title = - {_t("Recovery Method Removed")} + { _t("Recovery Method Removed") } ; return ( @@ -55,21 +55,21 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent { title={title} >
    -

    {_t( +

    { _t( "This session has detected that your Security Phrase and key " + "for Secure Messages have been removed.", - )}

    -

    {_t( + ) }

    +

    { _t( "If you did this accidentally, you can setup Secure Messages on " + "this session which will re-encrypt this session's message " + "history with a new recovery method.", - )}

    -

    {_t( + ) }

    +

    { _t( "If you didn't remove the recovery method, an " + "attacker may be trying to access your account. " + "Change your account password and set a new recovery " + "method immediately in Settings.", - )}

    + ) }

    { // lazy-load user list into matcher - if (!this.users) this._makeUsers(); + if (!this.users) this.makeUsers(); let completions = []; const { command, range } = this.getCurrentCommand(rawQuery, selection, force); @@ -147,7 +147,7 @@ export default class UserProvider extends AutocompleteProvider { return _t('Users'); } - _makeUsers() { + private makeUsers() { const events = this.room.getLiveTimeline().getEvents(); const lastSpoken = {}; diff --git a/src/components/structures/CustomRoomTagPanel.js b/src/components/structures/CustomRoomTagPanel.js index 037d7c251c..5e31048207 100644 --- a/src/components/structures/CustomRoomTagPanel.js +++ b/src/components/structures/CustomRoomTagPanel.js @@ -56,7 +56,7 @@ class CustomRoomTagPanel extends React.Component { return (
    - {tags} + { tags }
    ); } @@ -84,7 +84,7 @@ class CustomRoomTagTile extends React.Component { "mx_TagTile_badge": true, "mx_TagTile_badgeHighlight": badgeNotifState.hasMentions, }); - badgeElement = (
    {FormattingUtils.formatCount(badgeNotifState.count)}
    ); + badgeElement = (
    { FormattingUtils.formatCount(badgeNotifState.count) }
    ); } return ( diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js index 628c16f322..6e15e74ad8 100644 --- a/src/components/structures/EmbeddedPage.js +++ b/src/components/structures/EmbeddedPage.js @@ -44,7 +44,7 @@ export default class EmbeddedPage extends React.PureComponent { constructor(props, context) { super(props, context); - this._dispatcherRef = null; + this.dispatcherRef = null; this.state = { page: '', @@ -125,11 +125,11 @@ export default class EmbeddedPage extends React.PureComponent { if (this.props.scrollbar) { return - {content} + { content } ; } else { return
    - {content} + { content }
    ; } } diff --git a/src/components/structures/FilePanel.tsx b/src/components/structures/FilePanel.tsx index 36f774a130..c6d72d04bb 100644 --- a/src/components/structures/FilePanel.tsx +++ b/src/components/structures/FilePanel.tsx @@ -241,8 +241,8 @@ class FilePanel extends React.Component { // wrap a TimelinePanel with the jump-to-event bits turned off. const emptyState = (
    -

    {_t('No files visible in this room')}

    -

    {_t('Attach files from chat or just drag and drop them anywhere in a room.')}

    +

    { _t('No files visible in this room') }

    +

    { _t('Attach files from chat or just drag and drop them anywhere in a room.') }

    ); const isRoomEncrypted = this.noRoom ? false : MatrixClientPeg.get().isRoomEncrypted(this.props.roomId); @@ -262,7 +262,7 @@ class FilePanel extends React.Component { manageReadReceipts={false} manageReadMarkers={false} timelineSet={this.state.timelineSet} - showUrlPreview = {false} + showUrlPreview={false} onPaginationRequest={this.onPaginationRequest} tileShape={TileShape.FileGrid} resizeNotifier={this.props.resizeNotifier} diff --git a/src/components/structures/GenericErrorPage.js b/src/components/structures/GenericErrorPage.js index c9ed4ae622..017d365273 100644 --- a/src/components/structures/GenericErrorPage.js +++ b/src/components/structures/GenericErrorPage.js @@ -28,8 +28,8 @@ export default class GenericErrorPage extends React.PureComponent { render() { return
    -

    {this.props.title}

    -

    {this.props.message}

    +

    { this.props.title }

    +

    { this.props.message }

    ; } diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index f31f302b29..55a159e77d 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -431,7 +431,7 @@ export default class GroupView extends React.Component { this._initGroupStore(this.props.groupId, true); - this._dispatcherRef = dis.register(this._onAction); + this.dispatcherRef = dis.register(this._onAction); this._rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this._onRightPanelStoreUpdate); } @@ -819,12 +819,12 @@ export default class GroupView extends React.Component { let hostingSignup = null; if (hostingSignupLink && this.state.isUserPrivileged) { hostingSignup =
    - {_t( + { _t( "Want more than a community? Get your own server", {}, { - a: sub => {sub}, + a: sub => { sub }, }, - )} + ) } diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 3d5e386b00..3bd2c68c6c 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -429,7 +429,7 @@ export default class LeftPanel extends React.Component { onSelectRoom={this.selectRoom} /> - {dialPadButton} + { dialPadButton } { leftLeftPanel = (
    - {SettingsStore.getValue("feature_custom_tags") ? : null} + { SettingsStore.getValue("feature_custom_tags") ? : null }
    ); } @@ -476,11 +476,11 @@ export default class LeftPanel extends React.Component { return (
    - {leftLeftPanel} + { leftLeftPanel }
    diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 6c086ed17c..d496c4ad21 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -17,8 +17,8 @@ limitations under the License. */ import * as React from 'react'; -import * as PropTypes from 'prop-types'; import { MatrixClient } from 'matrix-js-sdk/src/client'; +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { Key } from '../../Keyboard'; import PageTypes from '../../PageTypes'; @@ -79,6 +79,8 @@ function canElementReceiveInput(el) { interface IProps { matrixClient: MatrixClient; + // Called with the credentials of a registered user (if they were a ROU that + // transitioned to PWLU) onRegistered: (credentials: IMatrixClientCreds) => Promise; hideToSRUsers: boolean; resizeNotifier: ResizeNotifier; @@ -140,18 +142,6 @@ interface IState { class LoggedInView extends React.Component { static displayName = 'LoggedInView'; - static propTypes = { - matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, - page_type: PropTypes.string.isRequired, - onRoomCreated: PropTypes.func, - - // Called with the credentials of a registered user (if they were a ROU that - // transitioned to PWLU) - onRegistered: PropTypes.func, - - // and lots and lots of other stuff. - }; - protected readonly _matrixClient: MatrixClient; protected readonly _roomView: React.RefObject; protected readonly _resizeContainer: React.RefObject; @@ -181,10 +171,10 @@ class LoggedInView extends React.Component { } componentDidMount() { - document.addEventListener('keydown', this._onNativeKeyDown, false); + document.addEventListener('keydown', this.onNativeKeyDown, false); CallHandler.sharedInstance().addListener(CallHandlerEvent.CallsChanged, this.onCallsChanged); - this._updateServerNoticeEvents(); + this.updateServerNoticeEvents(); this._matrixClient.on("accountData", this.onAccountData); this._matrixClient.on("sync", this.onSync); @@ -200,13 +190,13 @@ class LoggedInView extends React.Component { "useCompactLayout", null, this.onCompactLayoutChanged, ); - this.resizer = this._createResizer(); + this.resizer = this.createResizer(); this.resizer.attach(); - this._loadResizerPreferences(); + this.loadResizerPreferences(); } componentWillUnmount() { - document.removeEventListener('keydown', this._onNativeKeyDown, false); + document.removeEventListener('keydown', this.onNativeKeyDown, false); CallHandler.sharedInstance().removeListener(CallHandlerEvent.CallsChanged, this.onCallsChanged); this._matrixClient.removeListener("accountData", this.onAccountData); this._matrixClient.removeListener("sync", this.onSync); @@ -221,37 +211,37 @@ class LoggedInView extends React.Component { }); }; - canResetTimelineInRoom = (roomId) => { + public canResetTimelineInRoom = (roomId: string) => { if (!this._roomView.current) { return true; } return this._roomView.current.canResetTimeline(); }; - _createResizer() { - let size; - let collapsed; + private createResizer() { + let panelSize; + let panelCollapsed; const collapseConfig: ICollapseConfig = { // TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel toggleSize: 206 - 50, - onCollapsed: (_collapsed) => { - collapsed = _collapsed; - if (_collapsed) { + onCollapsed: (collapsed) => { + panelCollapsed = collapsed; + if (collapsed) { dis.dispatch({ action: "hide_left_panel" }); window.localStorage.setItem("mx_lhs_size", '0'); } else { dis.dispatch({ action: "show_left_panel" }); } }, - onResized: (_size) => { - size = _size; + onResized: (size) => { + panelSize = size; this.props.resizeNotifier.notifyLeftHandleResized(); }, onResizeStart: () => { this.props.resizeNotifier.startResizing(); }, onResizeStop: () => { - if (!collapsed) window.localStorage.setItem("mx_lhs_size", '' + size); + if (!panelCollapsed) window.localStorage.setItem("mx_lhs_size", '' + panelSize); this.props.resizeNotifier.stopResizing(); }, isItemCollapsed: domNode => { @@ -267,7 +257,7 @@ class LoggedInView extends React.Component { return resizer; } - _loadResizerPreferences() { + private loadResizerPreferences() { let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10); if (isNaN(lhsSize)) { lhsSize = 350; @@ -275,7 +265,7 @@ class LoggedInView extends React.Component { this.resizer.forHandleAt(0).resize(lhsSize); } - onAccountData = (event) => { + private onAccountData = (event: MatrixEvent) => { if (event.getType() === "m.ignored_user_list") { dis.dispatch({ action: "ignore_state_changed" }); } @@ -307,16 +297,16 @@ class LoggedInView extends React.Component { } if (oldSyncState === 'PREPARED' && syncState === 'SYNCING') { - this._updateServerNoticeEvents(); + this.updateServerNoticeEvents(); } else { - this._calculateServerLimitToast(this.state.syncErrorData, this.state.usageLimitEventContent); + this.calculateServerLimitToast(this.state.syncErrorData, this.state.usageLimitEventContent); } }; onRoomStateEvents = (ev, state) => { const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice]; if (serverNoticeList && serverNoticeList.some(r => r.roomId === ev.getRoomId())) { - this._updateServerNoticeEvents(); + this.updateServerNoticeEvents(); } }; @@ -326,7 +316,7 @@ class LoggedInView extends React.Component { }); }; - _calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) { + private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) { const error = syncError && syncError.error && syncError.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED"; if (error) { usageLimitEventContent = syncError.error.data; @@ -346,7 +336,7 @@ class LoggedInView extends React.Component { } } - _updateServerNoticeEvents = async () => { + private updateServerNoticeEvents = async () => { const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice]; if (!serverNoticeList) return []; @@ -378,7 +368,7 @@ class LoggedInView extends React.Component { ); }); const usageLimitEventContent = usageLimitEvent && usageLimitEvent.getContent(); - this._calculateServerLimitToast(this.state.syncErrorData, usageLimitEventContent); + this.calculateServerLimitToast(this.state.syncErrorData, usageLimitEventContent); this.setState({ usageLimitEventContent, usageLimitEventTs: pinnedEventTs, @@ -387,7 +377,7 @@ class LoggedInView extends React.Component { }); }; - _onPaste = (ev) => { + private onPaste = (ev) => { let canReceiveInput = false; let element = ev.target; // test for all parents because the target can be a child of a contenteditable element @@ -425,22 +415,22 @@ class LoggedInView extends React.Component { We also listen with a native listener on the document to get keydown events when no element is focused. Bubbling is irrelevant here as the target is the body element. */ - _onReactKeyDown = (ev) => { + private onReactKeyDown = (ev) => { // events caught while bubbling up on the root element // of this component, so something must be focused. - this._onKeyDown(ev); + this.onKeyDown(ev); }; - _onNativeKeyDown = (ev) => { + private onNativeKeyDown = (ev) => { // only pass this if there is no focused element. - // if there is, _onKeyDown will be called by the + // if there is, onKeyDown will be called by the // react keydown handler that respects the react bubbling order. if (ev.target === document.body) { - this._onKeyDown(ev); + this.onKeyDown(ev); } }; - _onKeyDown = (ev) => { + private onKeyDown = (ev) => { let handled = false; const roomAction = getKeyBindingsManager().getRoomAction(ev); @@ -450,7 +440,7 @@ class LoggedInView extends React.Component { case RoomAction.JumpToFirstMessage: case RoomAction.JumpToLatestMessage: // pass the event down to the scroll panel - this._onScrollKeyPressed(ev); + this.onScrollKeyPressed(ev); handled = true; break; case RoomAction.FocusSearch: @@ -565,7 +555,7 @@ class LoggedInView extends React.Component { * dispatch a page-up/page-down/etc to the appropriate component * @param {Object} ev The key event */ - _onScrollKeyPressed = (ev) => { + private onScrollKeyPressed = (ev) => { if (this._roomView.current) { this._roomView.current.handleScrollKey(ev); } @@ -625,8 +615,8 @@ class LoggedInView extends React.Component { return (
    @@ -644,7 +634,7 @@ class LoggedInView extends React.Component { - {audioFeedArraysForCalls} + { audioFeedArraysForCalls } ); } diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 785838ffca..0c982311e2 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -431,7 +431,7 @@ export default class MatrixChat extends React.PureComponent { } // TODO: [REACT-WARNING] Replace with appropriate lifecycle stage - // eslint-disable-next-line camelcase + // eslint-disable-next-line UNSAFE_componentWillUpdate(props, state) { if (this.shouldTrackPageChange(this.state, state)) { this.startPageChangeTimer(); @@ -1112,7 +1112,7 @@ export default class MatrixChat extends React.PureComponent { if (memberCount === 1) { warnings.push(( - {' '/* Whitespace, otherwise the sentences get smashed together */ } + { ' '/* Whitespace, otherwise the sentences get smashed together */ } { _t("You are the only person here. " + "If you leave, no one will be able to join in the future, including you.") } @@ -1127,7 +1127,7 @@ export default class MatrixChat extends React.PureComponent { if (rule !== "public") { warnings.push(( - {' '/* Whitespace, otherwise the sentences get smashed together */ } + { ' '/* Whitespace, otherwise the sentences get smashed together */ } { isSpace ? _t("This space is not public. You will not be able to rejoin without an invite.") : _t("This room is not public. You will not be able to rejoin without an invite.") } @@ -1155,7 +1155,7 @@ export default class MatrixChat extends React.PureComponent { : _t( "Are you sure you want to leave the room '%(roomName)s'?", { roomName: roomToLeave.name }, - )} + ) } { warnings } ), @@ -2053,15 +2053,15 @@ export default class MatrixChat extends React.PureComponent { let errorBox; if (this.state.syncError && !isStoreError) { errorBox =
    - {messageForSyncError(this.state.syncError)} + { messageForSyncError(this.state.syncError) }
    ; } view = (
    - {errorBox} + { errorBox } - {_t('Logout')} + { _t('Logout') }
    ); @@ -2124,7 +2124,7 @@ export default class MatrixChat extends React.PureComponent { } return - {view} + { view } ; } } diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index 87447b6aba..fca5613ede 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -121,7 +121,7 @@ export default class MyGroups extends React.Component { ) }
    - {/*
    + { /*
    @@ -137,7 +137,7 @@ export default class MyGroups extends React.Component { { 'i': (sub) => { sub } }) }
    -
    */} +
    */ }
    diff --git a/src/components/structures/NonUrgentToastContainer.tsx b/src/components/structures/NonUrgentToastContainer.tsx index a2d419b4ba..6e914c40fb 100644 --- a/src/components/structures/NonUrgentToastContainer.tsx +++ b/src/components/structures/NonUrgentToastContainer.tsx @@ -51,14 +51,14 @@ export default class NonUrgentToastContainer extends React.PureComponent { return (
    - {React.createElement(t, {})} + { React.createElement(t, {}) }
    ); }); return (
    - {toasts} + { toasts }
    ); } diff --git a/src/components/structures/NotificationPanel.tsx b/src/components/structures/NotificationPanel.tsx index 8c8fab7ece..8abc161bab 100644 --- a/src/components/structures/NotificationPanel.tsx +++ b/src/components/structures/NotificationPanel.tsx @@ -35,8 +35,8 @@ interface IProps { export default class NotificationPanel extends React.PureComponent { render() { const emptyState = (
    -

    {_t('You’re all caught up')}

    -

    {_t('You have no visible notifications.')}

    +

    { _t('You’re all caught up') }

    +

    { _t('You have no visible notifications.') }

    ); let content; diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx index 2a3448b017..95d70e913a 100644 --- a/src/components/structures/RightPanel.tsx +++ b/src/components/structures/RightPanel.tsx @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import { Room } from "matrix-js-sdk/src/models/room"; +import { RoomState } from "matrix-js-sdk/src/models/room-state"; import { User } from "matrix-js-sdk/src/models/user"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; @@ -152,7 +153,7 @@ export default class RightPanel extends React.Component { } // TODO: [REACT-WARNING] Replace with appropriate lifecycle event - UNSAFE_componentWillReceiveProps(newProps) { // eslint-disable-line camelcase + UNSAFE_componentWillReceiveProps(newProps) { // eslint-disable-line if (newProps.groupId !== this.props.groupId) { this.unregisterGroupStore(); this.initGroupStore(newProps.groupId); @@ -174,7 +175,7 @@ export default class RightPanel extends React.Component { }); }; - private onRoomStateMember = (ev: MatrixEvent, _, member: RoomMember) => { + private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember) => { if (!this.props.room || member.roomId !== this.props.room.roomId) { return; } diff --git a/src/components/structures/RoomDirectory.tsx b/src/components/structures/RoomDirectory.tsx index aa5baaf8c2..84e8de8221 100644 --- a/src/components/structures/RoomDirectory.tsx +++ b/src/components/structures/RoomDirectory.tsx @@ -589,7 +589,7 @@ export default class RoomDirectory extends React.Component { // We use onMouseDown instead of onClick, so that we can avoid text getting selected return [
    this.onRoomClicked(room, ev)} className="mx_RoomDirectory_roomAvatar" > @@ -603,7 +603,7 @@ export default class RoomDirectory extends React.Component { />
    ,
    this.onRoomClicked(room, ev)} className="mx_RoomDirectory_roomDescription" > @@ -626,14 +626,14 @@ export default class RoomDirectory extends React.Component {
    ,
    this.onRoomClicked(room, ev)} className="mx_RoomDirectory_roomMemberCount" > { room.num_joined_members }
    ,
    this.onRoomClicked(room, ev)} // cancel onMouseDown otherwise shift-clicking highlights text className="mx_RoomDirectory_preview" @@ -641,7 +641,7 @@ export default class RoomDirectory extends React.Component { { previewButton }
    ,
    this.onRoomClicked(room, ev)} className="mx_RoomDirectory_join" > @@ -796,7 +796,7 @@ export default class RoomDirectory extends React.Component { showJoinButton={showJoinButton} initialText={this.props.initialText} /> - {dropdown} + { dropdown }
    ; } const explanation = @@ -814,16 +814,16 @@ export default class RoomDirectory extends React.Component { }) : _t("Explore rooms"); return (
    - {explanation} + { explanation }
    - {listHeader} - {content} + { listHeader } + { content }
    diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index e8080b4f7b..9acfb7bb8e 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -209,9 +209,9 @@ export default class RoomSearch extends React.PureComponent { return (
    - {icon} - {input} - {clearButton} + { icon } + { input } + { clearButton }
    ); } diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js index 80ea26c3f2..ac4d197346 100644 --- a/src/components/structures/RoomStatusBar.js +++ b/src/components/structures/RoomStatusBar.js @@ -222,17 +222,17 @@ export default class RoomStatusBar extends React.PureComponent { let buttonRow = <> - {_t("Delete all")} + { _t("Delete all") } - {_t("Retry all")} + { _t("Retry all") } ; if (this.state.isResending) { buttonRow = <> - {/* span for css */} - {_t("Sending")} + { /* span for css */ } + { _t("Sending") } ; } @@ -253,7 +253,7 @@ export default class RoomStatusBar extends React.PureComponent {
    - {buttonRow} + { buttonRow }
    @@ -270,10 +270,10 @@ export default class RoomStatusBar extends React.PureComponent { height="24" title="/!\ " alt="/!\ " />
    - {_t('Connectivity to the server has been lost.')} + { _t('Connectivity to the server has been lost.') }
    - {_t('Sent messages will be stored until your connection has returned.')} + { _t('Sent messages will be stored until your connection has returned.') }
    diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 0c10a2aeca..7860e65362 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -1892,10 +1892,10 @@ export default class RoomView extends React.Component { className="mx_RoomView_auxPanel_hiddenHighlights" onClick={this.onHiddenHighlightsClick} > - {_t( + { _t( "You have %(count)s unread notifications in a prior version of this room.", { count: hiddenHighlightCount }, - )} + ) } ); } @@ -2007,7 +2007,7 @@ export default class RoomView extends React.Component { onScroll={this.onMessageListScroll} onUserScroll={this.onUserScroll} onReadMarkerUpdated={this.updateTopUnreadMessagesBar} - showUrlPreview = {this.state.showUrlPreview} + showUrlPreview={this.state.showUrlPreview} className={messagePanelClassNames} membersLoaded={this.state.membersLoaded} permalinkCreator={this.getPermalinkCreatorForRoom(this.state.room)} @@ -2057,7 +2057,7 @@ export default class RoomView extends React.Component { return (
    - {showChatEffects && this.roomView.current && + { showChatEffects && this.roomView.current && } @@ -2076,22 +2076,22 @@ export default class RoomView extends React.Component { />
    - {auxPanel} + { auxPanel }
    - {fileDropTarget} - {topUnreadMessagesBar} - {jumpToBottom} - {messagePanel} - {searchResultsPanel} + { fileDropTarget } + { topUnreadMessagesBar } + { jumpToBottom } + { messagePanel } + { searchResultsPanel }
    - {statusBar} + { statusBar }
    - {previewBar} - {messageComposer} + { previewBar } + { messageComposer }
    diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index 5c966d2d3a..3cf4b9b593 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -136,7 +136,7 @@ export default class SearchBox extends React.Component { key="button" tabIndex={-1} className="mx_SearchBox_closeButton" - onClick={ () => {this._clearSearch("button"); } }> + onClick={() => {this._clearSearch("button"); }}> ) : undefined; // show a shorter placeholder when blurred, if requested @@ -153,12 +153,12 @@ export default class SearchBox extends React.Component { type="text" ref={this._search} className={"mx_textinput_icon mx_textinput_search " + className} - value={ this.state.searchTerm } - onFocus={ this._onFocus } - onChange={ this.onChange } - onKeyDown={ this._onKeyDown } + value={this.state.searchTerm} + onFocus={this._onFocus} + onChange={this.onChange} + onKeyDown={this._onKeyDown} onBlur={this._onBlur} - placeholder={ placeholder } + placeholder={placeholder} autoComplete="off" autoFocus={this.props.autoFocus} /> diff --git a/src/components/structures/SpaceRoomDirectory.tsx b/src/components/structures/SpaceRoomDirectory.tsx index 27539a5c3c..038c1df514 100644 --- a/src/components/structures/SpaceRoomDirectory.tsx +++ b/src/components/structures/SpaceRoomDirectory.tsx @@ -404,7 +404,7 @@ export const SpaceHierarchy: React.FC = ({ const [saving, setSaving] = useState(false); if (summaryError) { - return

    {_t("Your server does not support showing space hierarchies.")}

    ; + return

    { _t("Your server does not support showing space hierarchies.") }

    ; } let content; @@ -569,7 +569,7 @@ export const SpaceHierarchy: React.FC = ({ return <> = ({ space, onFinished, initialText } { _t("If you can't find the room you're looking for, ask for an invite or create a new room.", null, { a: sub => { - return {sub}; + return { sub }; } }, ) } diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 0ee68a9578..06b2f4a629 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -146,7 +146,7 @@ const SpaceInfo = ({ space }) => { return
    { visibilitySection } { joinRule === "public" && - {(count) => count > 0 ? ( + { (count) => count > 0 ? ( { @@ -159,7 +159,7 @@ const SpaceInfo = ({ space }) => { > { _t("%(count)s members", { count }) } - ) : null} + ) : null } }
    ; }; @@ -292,7 +292,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) => - {(topic, ref) => + { (topic, ref) =>
    { topic }
    @@ -419,12 +419,12 @@ const SpaceLanding = ({ space }) => {
    - {(name) => { + { (name) => { const tags = { name: () =>

    { name }

    }; return _t("Welcome to ", {}, tags) as JSX.Element; - }} + } }
    @@ -434,11 +434,11 @@ const SpaceLanding = ({ space }) => { { settingsButton }
    - {(topic, ref) => ( + { (topic, ref) => (
    { topic }
    - )} + ) }

    @@ -458,7 +458,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => { const numFields = 3; const placeholders = [_t("General"), _t("Random"), _t("Support")]; const [roomNames, setRoomName] = useStateArray(numFields, [_t("General"), _t("Random"), ""]); - const fields = new Array(numFields).fill(0).map((_, i) => { + const fields = new Array(numFields).fill(0).map((x, i) => { const name = "roomName" + i; return { const numFields = 3; const fieldRefs: RefObject[] = [useRef(), useRef(), useRef()]; const [emailAddresses, setEmailAddress] = useStateArray(numFields, ""); - const fields = new Array(numFields).fill(0).map((_, i) => { + const fields = new Array(numFields).fill(0).map((x, i) => { const name = "emailAddress" + i; return { tabLocation: TabLocation.LEFT, }; - private _getActiveTabIndex() { + private getActiveTabIndex() { if (!this.state || !this.state.activeTabIndex) return 0; return this.state.activeTabIndex; } @@ -84,7 +84,7 @@ export default class TabbedView extends React.Component { * @param {Tab} tab the tab to show * @private */ - private _setActiveTab(tab: Tab) { + private setActiveTab(tab: Tab) { const idx = this.props.tabs.indexOf(tab); if (idx !== -1) { if (this.props.onChange) this.props.onChange(tab.id); @@ -94,23 +94,23 @@ export default class TabbedView extends React.Component { } } - private _renderTabLabel(tab: Tab) { + private renderTabLabel(tab: Tab) { let classes = "mx_TabbedView_tabLabel "; const idx = this.props.tabs.indexOf(tab); - if (idx === this._getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active"; + if (idx === this.getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active"; let tabIcon = null; if (tab.icon) { tabIcon = ; } - const onClickHandler = () => this._setActiveTab(tab); + const onClickHandler = () => this.setActiveTab(tab); const label = _t(tab.label); return ( - {tabIcon} + { tabIcon } { label } @@ -118,19 +118,19 @@ export default class TabbedView extends React.Component { ); } - private _renderTabPanel(tab: Tab): React.ReactNode { + private renderTabPanel(tab: Tab): React.ReactNode { return (
    - {tab.body} + { tab.body }
    ); } public render(): React.ReactNode { - const labels = this.props.tabs.map(tab => this._renderTabLabel(tab)); - const panel = this._renderTabPanel(this.props.tabs[this._getActiveTabIndex()]); + const labels = this.props.tabs.map(tab => this.renderTabLabel(tab)); + const panel = this.renderTabPanel(this.props.tabs[this.getActiveTabIndex()]); const tabbedViewClasses = classNames({ 'mx_TabbedView': true, @@ -141,9 +141,9 @@ export default class TabbedView extends React.Component { return (
    - {labels} + { labels }
    - {panel} + { panel }
    ); } diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 59930bf41d..c4210c68a8 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -277,7 +277,7 @@ class TimelinePanel extends React.Component { } // TODO: [REACT-WARNING] Move into constructor - // eslint-disable-next-line camelcase + // eslint-disable-next-line UNSAFE_componentWillMount() { if (this.props.manageReadReceipts) { this.updateReadReceiptOnUserActivity(); @@ -290,7 +290,7 @@ class TimelinePanel extends React.Component { } // TODO: [REACT-WARNING] Replace with appropriate lifecycle event - // eslint-disable-next-line camelcase + // eslint-disable-next-line UNSAFE_componentWillReceiveProps(newProps) { if (newProps.timelineSet !== this.props.timelineSet) { // throw new Error("changing timelineSet on a TimelinePanel is not supported"); @@ -1448,7 +1448,7 @@ class TimelinePanel extends React.Component { if (this.state.events.length == 0 && !this.state.canBackPaginate && this.props.empty) { return (
    -
    {this.props.empty}
    +
    { this.props.empty }
    ); } diff --git a/src/components/structures/ToastContainer.tsx b/src/components/structures/ToastContainer.tsx index 79a73735f4..b7b0b7c652 100644 --- a/src/components/structures/ToastContainer.tsx +++ b/src/components/structures/ToastContainer.tsx @@ -37,14 +37,14 @@ export default class ToastContainer extends React.Component<{}, IState> { // toasts may dismiss themselves in their didMount if they find // they're already irrelevant by the time they're mounted, and // our own componentDidMount is too late. - ToastStore.sharedInstance().on('update', this._onToastStoreUpdate); + ToastStore.sharedInstance().on('update', this.onToastStoreUpdate); } componentWillUnmount() { - ToastStore.sharedInstance().removeListener('update', this._onToastStoreUpdate); + ToastStore.sharedInstance().removeListener('update', this.onToastStoreUpdate); } - _onToastStoreUpdate = () => { + private onToastStoreUpdate = () => { this.setState({ toasts: ToastStore.sharedInstance().getToasts(), countSeen: ToastStore.sharedInstance().getCountSeen(), @@ -75,10 +75,10 @@ export default class ToastContainer extends React.Component<{}, IState> { }); toast = (
    -

    {title}

    - {countIndicator} +

    { title }

    + { countIndicator }
    -
    {React.createElement(component, toastProps)}
    +
    { React.createElement(component, toastProps) }
    ); containerClasses = classNames("mx_ToastContainer", { @@ -88,7 +88,7 @@ export default class ToastContainer extends React.Component<{}, IState> { return toast ? (
    - {toast} + { toast }
    ) : null; diff --git a/src/components/structures/UploadBar.tsx b/src/components/structures/UploadBar.tsx index c8e90a1c0a..6ee53da5d1 100644 --- a/src/components/structures/UploadBar.tsx +++ b/src/components/structures/UploadBar.tsx @@ -104,7 +104,7 @@ export default class UploadBar extends React.Component { const uploadSize = filesize(this.state.currentUpload.total); return (
    -
    {uploadText} ({uploadSize})
    +
    { uploadText } ({ uploadSize })
    diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index 34575ba582..0a30367e4b 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -342,20 +342,20 @@ export default class UserMenu extends React.Component { if (MatrixClientPeg.get().isGuest()) { topSection = (
    - {_t("Got an account? Sign in", {}, { + { _t("Got an account? Sign in", {}, { a: sub => ( - {sub} + { sub } ), - })} - {_t("New here? Create an account", {}, { + }) } + { _t("New here? Create an account", {}, { a: sub => ( - {sub} + { sub } ), - })} + }) }
    ); } else if (hostSignupConfig) { @@ -394,17 +394,17 @@ export default class UserMenu extends React.Component { let primaryHeader = (
    - {OwnProfileStore.instance.displayName} + { OwnProfileStore.instance.displayName } - {MatrixClientPeg.get().getUserId()} + { MatrixClientPeg.get().getUserId() }
    ); let primaryOptionList = ( - {homeButton} + { homeButton } { label={_t("All settings")} onClick={(e) => this.onSettingsOpen(e, null)} /> - {/* */} + /> */ } { feedbackButton } @@ -443,7 +443,7 @@ export default class UserMenu extends React.Component { primaryHeader = (
    - {prototypeCommunityName} + { prototypeCommunityName }
    ); @@ -470,13 +470,13 @@ export default class UserMenu extends React.Component { } primaryOptionList = ( - {settingsOption} + { settingsOption } - {inviteOption} + { inviteOption } ); secondarySection = ( @@ -485,10 +485,10 @@ export default class UserMenu extends React.Component {
    - {OwnProfileStore.instance.displayName} + { OwnProfileStore.instance.displayName } - {MatrixClientPeg.get().getUserId()} + { MatrixClientPeg.get().getUserId() }
    @@ -540,7 +540,7 @@ export default class UserMenu extends React.Component { className={classes} >
    - {primaryHeader} + { primaryHeader } { />
    - {topSection} - {primaryOptionList} - {secondarySection} + { topSection } + { primaryOptionList } + { secondarySection } ; }; @@ -570,27 +570,27 @@ export default class UserMenu extends React.Component { let isPrototype = false; let menuName = _t("User menu"); - let name = {displayName}; + let name = { displayName }; let buttons = ( - {/* masked image in CSS */} + { /* masked image in CSS */ } ); let dnd; if (this.state.selectedSpace) { name = (
    - {displayName} + { displayName } - {(roomName) => {roomName}} + { (roomName) => { roomName } }
    ); } else if (prototypeCommunityName) { name = (
    - {prototypeCommunityName} - {displayName} + { prototypeCommunityName } + { displayName }
    ); menuName = _t("Community and user menu"); @@ -598,8 +598,8 @@ export default class UserMenu extends React.Component { } else if (SettingsStore.getValue("feature_communities_v2_prototypes")) { name = (
    - {_t("Home")} - {displayName} + { _t("Home") } + { displayName }
    ); isPrototype = true; @@ -647,20 +647,20 @@ export default class UserMenu extends React.Component { className="mx_UserMenu_userAvatar" />
    - {name} - {this.state.pendingRoomJoin.size > 0 && ( + { name } + { this.state.pendingRoomJoin.size > 0 && ( - )} - {dnd} - {buttons} + ) } + { dnd } + { buttons }
    - {this.renderContextMenu()} + { this.renderContextMenu() } ); } diff --git a/src/components/structures/ViewSource.js b/src/components/structures/ViewSource.js index b69a92dd61..2bfa20e892 100644 --- a/src/components/structures/ViewSource.js +++ b/src/components/structures/ViewSource.js @@ -63,23 +63,23 @@ export default class ViewSource extends React.Component { <>
    - {_t("Decrypted event source")} + { _t("Decrypted event source") } - {JSON.stringify(decryptedEventSource, null, 2)} + { JSON.stringify(decryptedEventSource, null, 2) }
    - {_t("Original event source")} + { _t("Original event source") } - {JSON.stringify(originalEventSource, null, 2)} + { JSON.stringify(originalEventSource, null, 2) }
    ); } else { return ( <> -
    {_t("Original event source")}
    - {JSON.stringify(originalEventSource, null, 2)} +
    { _t("Original event source") }
    + { JSON.stringify(originalEventSource, null, 2) } ); } @@ -110,7 +110,7 @@ export default class ViewSource extends React.Component { if (isStateEvent) { return ( - {(cli) => ( + { (cli) => ( - )} + ) } ); } else { @@ -142,7 +142,7 @@ export default class ViewSource extends React.Component { }; return ( - {(cli) => ( + { (cli) => ( - )} + ) } ); } @@ -176,16 +176,16 @@ export default class ViewSource extends React.Component { return (
    -
    Room ID: {roomId}
    -
    Event ID: {eventId}
    +
    Room ID: { roomId }
    +
    Event ID: { eventId }
    - {isEditing ? this.editSourceContent() : this.viewSourceContent()} + { isEditing ? this.editSourceContent() : this.viewSourceContent() }
    - {!isEditing && canEdit && ( + { !isEditing && canEdit && (
    - +
    - )} + ) } ); } diff --git a/src/components/structures/auth/CompleteSecurity.tsx b/src/components/structures/auth/CompleteSecurity.tsx index 2f37e60450..8c3d5e80a0 100644 --- a/src/components/structures/auth/CompleteSecurity.tsx +++ b/src/components/structures/auth/CompleteSecurity.tsx @@ -79,8 +79,8 @@ export default class CompleteSecurity extends React.Component {

    - {icon} - {title} + { icon } + { title }

    diff --git a/src/components/structures/auth/ForgotPassword.tsx b/src/components/structures/auth/ForgotPassword.tsx index 6382e143f9..3755505f3d 100644 --- a/src/components/structures/auth/ForgotPassword.tsx +++ b/src/components/structures/auth/ForgotPassword.tsx @@ -101,7 +101,7 @@ export default class ForgotPassword extends React.Component { } // TODO: [REACT-WARNING] Replace with appropriate lifecycle event - // eslint-disable-next-line camelcase + // eslint-disable-next-line public UNSAFE_componentWillReceiveProps(newProps: IProps): void { if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl && newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return; @@ -239,14 +239,14 @@ export default class ForgotPassword extends React.Component { }); serverDeadSection = (
    - {this.state.serverDeadError} + { this.state.serverDeadError }
    ); } return
    - {errorText} - {serverDeadSection} + { errorText } + { serverDeadSection } { autoComplete="new-password" />
    - {_t( + { _t( 'A verification email will be sent to your inbox to confirm ' + 'setting your new password.', - )} + ) } { /> - {_t('Sign in instead')} + { _t('Sign in instead') }
    ; } @@ -312,8 +312,8 @@ export default class ForgotPassword extends React.Component { renderEmailSent() { return
    - {_t("An email has been sent to %(emailAddress)s. Once you've followed the " + - "link it contains, click below.", { emailAddress: this.state.email })} + { _t("An email has been sent to %(emailAddress)s. Once you've followed the " + + "link it contains, click below.", { emailAddress: this.state.email }) }
    @@ -322,12 +322,12 @@ export default class ForgotPassword extends React.Component { renderDone() { return
    -

    {_t("Your password has been reset.")}

    -

    {_t( +

    { _t("Your password has been reset.") }

    +

    { _t( "You have been logged out of all sessions and will no longer receive " + "push notifications. To re-enable notifications, sign in again on each " + "device.", - )}

    + ) }

    ; @@ -358,7 +358,7 @@ export default class ForgotPassword extends React.Component {

    { _t('Set a new password') }

    - {resetPasswordJsx} + { resetPasswordJsx }
    ); diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx index 9f12521a34..6a3d339681 100644 --- a/src/components/structures/auth/Login.tsx +++ b/src/components/structures/auth/Login.tsx @@ -144,7 +144,7 @@ export default class LoginComponent extends React.PureComponent } // TODO: [REACT-WARNING] Replace with appropriate lifecycle event - // eslint-disable-next-line camelcase + // eslint-disable-next-line UNSAFE_componentWillMount() { this.initLoginLogic(this.props.serverConfig); } @@ -154,7 +154,7 @@ export default class LoginComponent extends React.PureComponent } // TODO: [REACT-WARNING] Replace with appropriate lifecycle event - // eslint-disable-next-line camelcase + // eslint-disable-next-line UNSAFE_componentWillReceiveProps(newProps) { if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl && newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return; @@ -239,8 +239,8 @@ export default class LoginComponent extends React.PureComponent ); errorText = (
    -
    {errorTop}
    -
    {errorDetail}
    +
    { errorTop }
    +
    { errorDetail }
    ); } else if (error.httpStatus === 401 || error.httpStatus === 403) { @@ -251,10 +251,10 @@ export default class LoginComponent extends React.PureComponent
    { _t('Incorrect username and/or password.') }
    - {_t( + { _t( 'Please note you are logging into the %(hs)s server, not matrix.org.', { hs: this.props.serverConfig.hsName }, - )} + ) }
    ); @@ -565,7 +565,7 @@ export default class LoginComponent extends React.PureComponent }); serverDeadSection = (
    - {this.state.serverDeadError} + { this.state.serverDeadError }
    ); } @@ -578,15 +578,15 @@ export default class LoginComponent extends React.PureComponent { this.props.isSyncing ? _t("Syncing...") : _t("Signing In...") }
    { this.props.isSyncing &&
    - {_t("If you've joined lots of rooms, this might take a while")} + { _t("If you've joined lots of rooms, this might take a while") }
    }
    ; } else if (SettingsStore.getValue(UIFeature.Registration)) { footer = ( - {_t("New? Create account", {}, { + { _t("New? Create account", {}, { a: sub => { sub }, - })} + }) } ); } @@ -596,8 +596,8 @@ export default class LoginComponent extends React.PureComponent

    - {_t('Sign in')} - {loader} + { _t('Sign in') } + { loader }

    { errorTextSection } { serverDeadSection } diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx index 8d32981e57..549e47260f 100644 --- a/src/components/structures/auth/Registration.tsx +++ b/src/components/structures/auth/Registration.tsx @@ -141,7 +141,7 @@ export default class Registration extends React.Component { } // TODO: [REACT-WARNING] Replace with appropriate lifecycle event - // eslint-disable-next-line camelcase + // eslint-disable-next-line UNSAFE_componentWillReceiveProps(newProps) { if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl && newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return; @@ -290,8 +290,8 @@ export default class Registration extends React.Component { }, ); msg =
    -

    {errorTop}

    -

    {errorDetail}

    +

    { errorTop }

    +

    { errorDetail }

    ; } else if (response.required_stages && response.required_stages.indexOf('m.login.msisdn') > -1) { let msisdnAvailable = false; @@ -482,13 +482,13 @@ export default class Registration extends React.Component { fragmentAfterLogin={this.props.fragmentAfterLogin} />

    - {_t( + { _t( "%(ssoButtons)s Or %(usernamePassword)s", { ssoButtons: "", usernamePassword: "", }, - ).trim()} + ).trim() }

    ; } @@ -526,15 +526,15 @@ export default class Registration extends React.Component { }); serverDeadSection = (
    - {this.state.serverDeadError} + { this.state.serverDeadError }
    ); } const signIn = - {_t("Already have an account? Sign in here", {}, { + { _t("Already have an account? Sign in here", {}, { a: sub => { sub }, - })} + }) } ; // Only show the 'go back' button if you're not looking at the form @@ -550,43 +550,43 @@ export default class Registration extends React.Component { let regDoneText; if (this.state.differentLoggedInUserId) { regDoneText =
    -

    {_t( +

    { _t( "Your new account (%(newAccountId)s) is registered, but you're already " + "logged into a different account (%(loggedInUserId)s).", { newAccountId: this.state.registeredUsername, loggedInUserId: this.state.differentLoggedInUserId, }, - )}

    + ) }

    { const sessionLoaded = await this.onLoginClickWithCheck(event); if (sessionLoaded) { dis.dispatch({ action: "view_welcome_page" }); } }}> - {_t("Continue with previous account")} + { _t("Continue with previous account") }

    ; } else if (this.state.formVals.password) { // We're the client that started the registration - regDoneText =

    {_t( + regDoneText =

    { _t( "Log in to your new account.", {}, { - a: (sub) => {sub}, + a: (sub) => { sub }, }, - )}

    ; + ) }; } else { // We're not the original client: the user probably got to us by clicking the // email validation link. We can't offer a 'go straight to your account' link // as we don't have the original creds. - regDoneText =

    {_t( + regDoneText =

    { _t( "You can now close this window or log in to your new account.", {}, { - a: (sub) => {sub}, + a: (sub) => { sub }, }, - )}

    ; + ) }; } body =
    -

    {_t("Registration Successful")}

    +

    { _t("Registration Successful") }

    { regDoneText }
    ; } else { diff --git a/src/components/structures/auth/SetupEncryptionBody.tsx b/src/components/structures/auth/SetupEncryptionBody.tsx index c7ce74077b..6731156807 100644 --- a/src/components/structures/auth/SetupEncryptionBody.tsx +++ b/src/components/structures/auth/SetupEncryptionBody.tsx @@ -152,7 +152,7 @@ export default class SetupEncryptionBody extends React.Component let useRecoveryKeyButton; if (recoveryKeyPrompt) { useRecoveryKeyButton = - {recoveryKeyPrompt} + { recoveryKeyPrompt } ; } @@ -165,15 +165,15 @@ export default class SetupEncryptionBody extends React.Component return (
    -

    {_t( +

    { _t( "Verify your identity to access encrypted messages and prove your identity to others.", - )}

    + ) }

    - {verifyButton} - {useRecoveryKeyButton} + { verifyButton } + { useRecoveryKeyButton } - {_t("Skip")} + { _t("Skip") }
    @@ -181,25 +181,25 @@ export default class SetupEncryptionBody extends React.Component } else if (phase === Phase.Done) { let message; if (this.state.backupInfo) { - message =

    {_t( + message =

    { _t( "Your new session is now verified. It has access to your " + "encrypted messages, and other users will see it as trusted.", - )}

    ; + ) }

    ; } else { - message =

    {_t( + message =

    { _t( "Your new session is now verified. Other users will see it as trusted.", - )}

    ; + ) }

    ; } return (
    - {message} + { message }
    - {_t("Done")} + { _t("Done") }
    @@ -207,23 +207,23 @@ export default class SetupEncryptionBody extends React.Component } else if (phase === Phase.ConfirmSkip) { return (
    -

    {_t( +

    { _t( "Without verifying, you won’t have access to all your messages " + "and may appear as untrusted to others.", - )}

    + ) }

    - {_t("Skip")} + { _t("Skip") } - {_t("Go Back")} + { _t("Go Back") }
    diff --git a/src/components/structures/auth/SoftLogout.tsx b/src/components/structures/auth/SoftLogout.tsx index d232f55dd1..fffec949fe 100644 --- a/src/components/structures/auth/SoftLogout.tsx +++ b/src/components/structures/auth/SoftLogout.tsx @@ -219,7 +219,7 @@ export default class SoftLogout extends React.Component { if (this.state.loginView === LOGIN_VIEW.PASSWORD) { let error = null; if (this.state.errorText) { - error = {this.state.errorText}; + error = { this.state.errorText }; } if (!introText) { @@ -228,8 +228,8 @@ export default class SoftLogout extends React.Component { return (
    -

    {introText}

    - {error} +

    { introText }

    + { error } { type="submit" disabled={this.state.busy} > - {_t("Sign In")} + { _t("Sign In") } - {_t("Forgotten your password?")} + { _t("Forgotten your password?") } ); @@ -262,7 +262,7 @@ export default class SoftLogout extends React.Component { return (
    -

    {introText}

    +

    { introText }

    { // Default: assume unsupported/error return (

    - {_t( + { _t( "You cannot sign in to your account. Please contact your " + "homeserver admin for more information.", - )} + ) }

    ); } @@ -291,25 +291,25 @@ export default class SoftLogout extends React.Component {

    - {_t("You're signed out")} + { _t("You're signed out") }

    -

    {_t("Sign in")}

    +

    { _t("Sign in") }

    - {this.renderSignInSection()} + { this.renderSignInSection() }
    -

    {_t("Clear personal data")}

    +

    { _t("Clear personal data") }

    - {_t( + { _t( "Warning: Your personal data (including encryption keys) is still stored " + "in this session. Clear it if you're finished using this session, or want to sign " + "in to another account.", - )} + ) }

    - {_t("Clear all data")} + { _t("Clear all data") }
    diff --git a/src/components/views/audio_messages/AudioPlayer.tsx b/src/components/views/audio_messages/AudioPlayer.tsx index 66efa64658..748b1c9ffc 100644 --- a/src/components/views/audio_messages/AudioPlayer.tsx +++ b/src/components/views/audio_messages/AudioPlayer.tsx @@ -101,11 +101,11 @@ export default class AudioPlayer extends React.PureComponent { />
    - {this.props.mediaName || _t("Unnamed audio")} + { this.props.mediaName || _t("Unnamed audio") }
    -   {/* easiest way to introduce a gap between the components */} +   { /* easiest way to introduce a gap between the components */ } { this.renderFileSize() }
    diff --git a/src/components/views/audio_messages/Clock.tsx b/src/components/views/audio_messages/Clock.tsx index 7f387715f8..cb1a179f2e 100644 --- a/src/components/views/audio_messages/Clock.tsx +++ b/src/components/views/audio_messages/Clock.tsx @@ -43,6 +43,6 @@ export default class Clock extends React.Component { public render() { const minutes = Math.floor(this.props.seconds / 60).toFixed(0).padStart(2, '0'); const seconds = Math.floor(this.props.seconds % 60).toFixed(0).padStart(2, '0'); // hide millis - return {minutes}:{seconds}; + return { minutes }:{ seconds }; } } diff --git a/src/components/views/audio_messages/Waveform.tsx b/src/components/views/audio_messages/Waveform.tsx index 3b7a881754..8a4427fd01 100644 --- a/src/components/views/audio_messages/Waveform.tsx +++ b/src/components/views/audio_messages/Waveform.tsx @@ -47,7 +47,7 @@ export default class Waveform extends React.PureComponent { public render() { return
    - {this.props.relHeights.map((h, i) => { + { this.props.relHeights.map((h, i) => { const progress = this.props.progress; const isCompleteBar = (i / this.props.relHeights.length) <= progress && progress > 0; const classes = classNames({ @@ -57,7 +57,7 @@ export default class Waveform extends React.PureComponent { return ; - })} + }) }
    ; } } diff --git a/src/components/views/auth/AuthPage.js b/src/components/views/auth/AuthPage.js index 6ba47e5288..6a73b06c16 100644 --- a/src/components/views/auth/AuthPage.js +++ b/src/components/views/auth/AuthPage.js @@ -28,7 +28,7 @@ export default class AuthPage extends React.PureComponent { return (
    - {this.props.children} + { this.props.children }
    diff --git a/src/components/views/auth/CaptchaForm.js b/src/components/views/auth/CaptchaForm.js index bea4f89f53..e4a2fa247b 100644 --- a/src/components/views/auth/CaptchaForm.js +++ b/src/components/views/auth/CaptchaForm.js @@ -129,9 +129,9 @@ export default class CaptchaForm extends React.Component { return (
    -

    {_t( +

    { _t( "This homeserver would like to make sure you are not a robot.", - )}

    + ) }

    { error }
    diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.tsx b/src/components/views/auth/InteractiveAuthEntryComponents.tsx index d9af2c2b77..763ce10cd9 100644 --- a/src/components/views/auth/InteractiveAuthEntryComponents.tsx +++ b/src/components/views/auth/InteractiveAuthEntryComponents.tsx @@ -417,12 +417,12 @@ export class TermsAuthEntry extends React.Component{_t("Accept")}; + onClick={this.trySubmit} disabled={!allChecked}>{ _t("Accept") }; } return (
    -

    {_t("Please review and accept the policies of this homeserver:")}

    +

    { _t("Please review and accept the policies of this homeserver:") }

    { checkboxes } { errorSection } { submitButton } @@ -613,7 +613,7 @@ export class MsisdnAuthEntry extends React.Component
    - {errorSection} + { errorSection }
    ); @@ -717,21 +717,21 @@ export class SSOAuthEntry extends React.Component{_t("Cancel")} + >{ _t("Cancel") } ); if (this.state.phase === SSOAuthEntry.PHASE_PREAUTH) { continueButton = ( {this.props.continueText || _t("Single Sign On")} + >{ this.props.continueText || _t("Single Sign On") } ); } else { continueButton = ( {this.props.continueText || _t("Confirm")} + >{ this.props.continueText || _t("Confirm") } ); } @@ -753,8 +753,8 @@ export class SSOAuthEntry extends React.Component { errorSection }
    - {cancelButton} - {continueButton} + { cancelButton } + { continueButton }
    ; } @@ -825,7 +825,7 @@ export class FallbackAuthEntry extends React.Component { { _t("Start authentication") } - {errorSection} + { errorSection }
    ); } diff --git a/src/components/views/auth/PasswordLogin.tsx b/src/components/views/auth/PasswordLogin.tsx index a77dd0b683..587d7f2453 100644 --- a/src/components/views/auth/PasswordLogin.tsx +++ b/src/components/views/auth/PasswordLogin.tsx @@ -416,7 +416,7 @@ export default class PasswordLogin extends React.PureComponent { kind="link" onClick={this.onForgotPasswordClick} > - {_t("Forgot password?")} + { _t("Forgot password?") } ; } @@ -441,16 +441,16 @@ export default class PasswordLogin extends React.PureComponent { disabled={this.props.disableSubmit} >
    @@ -460,8 +460,8 @@ export default class PasswordLogin extends React.PureComponent { return (
    - {loginType} - {loginField} + { loginType } + { loginField } { onValidate={this.onPasswordValidate} ref={field => this[LoginField.Password] = field} /> - {forgotPasswordJsx} + { forgotPasswordJsx } { !this.props.busy &&
    - {this.renderUsername()} + { this.renderUsername() }
    - {this.renderPassword()} - {this.renderPasswordConfirm()} + { this.renderPassword() } + { this.renderPasswordConfirm() }
    - {this.renderEmail()} - {this.renderPhoneNumber()} + { this.renderEmail() } + { this.renderPhoneNumber() }
    { emailHelperText } { registerButton } diff --git a/src/components/views/avatars/DecoratedRoomAvatar.tsx b/src/components/views/avatars/DecoratedRoomAvatar.tsx index 5e6bf45f07..99f2b70efc 100644 --- a/src/components/views/avatars/DecoratedRoomAvatar.tsx +++ b/src/components/views/avatars/DecoratedRoomAvatar.tsx @@ -205,8 +205,8 @@ export default class DecoratedRoomAvatar extends React.PureComponent - {icon} - {badge} + { icon } + { badge }
    ; } } diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js index b8b23dc33e..82b7b8e400 100644 --- a/src/components/views/avatars/MemberStatusMessageAvatar.js +++ b/src/components/views/avatars/MemberStatusMessageAvatar.js @@ -145,7 +145,7 @@ export default class MemberStatusMessageAvatar extends React.Component { isExpanded={this.state.menuDisplayed} label={_t("User Status")} > - {avatar} + { avatar } { contextMenu } diff --git a/src/components/views/context_menus/CallContextMenu.tsx b/src/components/views/context_menus/CallContextMenu.tsx index 76e1670669..a61cdeedd3 100644 --- a/src/components/views/context_menus/CallContextMenu.tsx +++ b/src/components/views/context_menus/CallContextMenu.tsx @@ -65,15 +65,15 @@ export default class CallContextMenu extends React.Component { let transferItem; if (this.props.call.opponentCanBeTransferred()) { transferItem = - {_t("Transfer")} + { _t("Transfer") } ; } return - {holdUnholdCaption} + { holdUnholdCaption } - {transferItem} + { transferItem } ; } } diff --git a/src/components/views/context_menus/IconizedContextMenu.tsx b/src/components/views/context_menus/IconizedContextMenu.tsx index a9c75bf3ba..1d822fd246 100644 --- a/src/components/views/context_menus/IconizedContextMenu.tsx +++ b/src/components/views/context_menus/IconizedContextMenu.tsx @@ -64,8 +64,8 @@ export const IconizedContextMenuRadio: React.FC = ({ label={label} > - {label} - {active && } + { label } + { active && } ; }; @@ -85,15 +85,15 @@ export const IconizedContextMenuCheckbox: React.FC = ({ label={label} > - {label} - {active && } + { label } + { active && } ; }; export const IconizedContextMenuOption: React.FC = ({ label, iconClassName, ...props }) => { return { iconClassName && } - {label} + { label } ; }; @@ -104,7 +104,7 @@ export const IconizedContextMenuOptionList: React.FC = ({ firs }); return
    - {children} + { children }
    ; }; diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index 999e98f4ad..bf171353e8 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -268,7 +268,7 @@ export default class MessageContextMenu extends React.Component resendReactionsButton = ( ); @@ -298,7 +298,7 @@ export default class MessageContextMenu extends React.Component pinButton = ( ); @@ -333,7 +333,7 @@ export default class MessageContextMenu extends React.Component - {_t("Clear status")} + { _t("Clear status") } ; } else { actionButton = - {_t("Update status")} + { _t("Update status") } ; } } else { actionButton = - {_t("Set status")} + { _t("Set status") } ; } @@ -130,8 +130,8 @@ export default class StatusMessageContextMenu extends React.Component { onChange={this._onStatusChange} />
    - {actionButton} - {spinner} + { actionButton } + { spinner }
    ; diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx index 5024b98def..0f78b971eb 100644 --- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx +++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx @@ -221,7 +221,7 @@ export const AddExistingToSpace: React.FC = ({ return
    - +
    ; } @@ -690,7 +690,7 @@ export default class AddressPickerDialog extends React.Component { && this.props.validAddressTypes.includes('email')) { const defaultIdentityServerUrl = getDefaultIdentityServerUrl(); if (defaultIdentityServerUrl) { - identityServer =
    {_t( + identityServer =
    { _t( "Use an identity server to invite by email. " + "Use the default (%(defaultIdentityServerName)s) " + "or manage in Settings.", @@ -698,25 +698,25 @@ export default class AddressPickerDialog extends React.Component { defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl), }, { - default: sub => {sub}, - settings: sub => {sub}, + default: sub => { sub }, + settings: sub => { sub }, }, - )}
    ; + ) }
    ; } else { - identityServer =
    {_t( + identityServer =
    { _t( "Use an identity server to invite by email. " + "Manage in Settings.", {}, { - settings: sub => {sub}, + settings: sub => { sub }, }, - )}
    ; + ) }
    ; } } return ( - {inputLabel} + { inputLabel }
    { query }
    { error } diff --git a/src/components/views/dialogs/AskInviteAnywayDialog.tsx b/src/components/views/dialogs/AskInviteAnywayDialog.tsx index 26fad0c724..7445296378 100644 --- a/src/components/views/dialogs/AskInviteAnywayDialog.tsx +++ b/src/components/views/dialogs/AskInviteAnywayDialog.tsx @@ -51,7 +51,7 @@ export default class AskInviteAnywayDialog extends React.Component { public render() { const errorList = this.props.unknownProfileUsers - .map(address =>
  • {address.userId}: {address.errorText}
  • ); + .map(address =>
  • { address.userId }: { address.errorText }
  • ); return ( { contentId='mx_Dialog_content' >
    - {/* eslint-disable-next-line */} + { /* eslint-disable-next-line */ }

    {_t("Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?")}

      { errorList } diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index e92bd6315e..8ccc485d7c 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -149,7 +149,7 @@ export default class BaseDialog extends React.Component { 'mx_Dialog_headerWithCancel': !!cancelButton, })}>
      - {headerImage} + { headerImage } { this.props.title }
      { this.props.headerButton } diff --git a/src/components/views/dialogs/BetaFeedbackDialog.tsx b/src/components/views/dialogs/BetaFeedbackDialog.tsx index 5a2f16f169..917004dbc7 100644 --- a/src/components/views/dialogs/BetaFeedbackDialog.tsx +++ b/src/components/views/dialogs/BetaFeedbackDialog.tsx @@ -69,7 +69,7 @@ const BetaFeedbackDialog: React.FC = ({ featureId, onFinished }) => {
      { _t(info.feedbackSubheading) }   - { _t("Your platform and username will be noted to help us use your feedback as much as we can.")} + { _t("Your platform and username will be noted to help us use your feedback as much as we can.") } { onFinished(false); diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx index 6baf24f797..64e984fe20 100644 --- a/src/components/views/dialogs/BugReportDialog.tsx +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -166,7 +166,7 @@ export default class BugReportDialog extends React.Component { let error = null; if (this.state.err) { error =
      - {this.state.err} + { this.state.err }
      ; } @@ -175,7 +175,7 @@ export default class BugReportDialog extends React.Component { progress = (
      - {this.state.progress} ... + { this.state.progress } ...
      ); } @@ -221,7 +221,7 @@ export default class BugReportDialog extends React.Component { { _t("Download logs") } - {this.state.downloadProgress && {this.state.downloadProgress} ...} + { this.state.downloadProgress && { this.state.downloadProgress } ... }
      { "please include those things here.", )} /> - {progress} - {error} + { progress } + { error }
    { return (
  • - {commit.commit.message.split('\n')[0]} + { commit.commit.message.split('\n')[0] }
  • ); @@ -79,15 +79,15 @@ export default class ChangelogDialog extends React.Component { } return (
    -

    {repo}

    -
      {content}
    +

    { repo }

    +
      { content }
    ); }); const content = (
    - {this.props.version == null || this.props.newVersion == null ?

    {_t("Unavailable")}

    : logs} + { this.props.version == null || this.props.newVersion == null ?

    { _t("Unavailable") }

    : logs }
    ); diff --git a/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx b/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx index 7627489deb..73fd4def25 100644 --- a/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx +++ b/src/components/views/dialogs/CommunityPrototypeInviteDialog.tsx @@ -156,8 +156,8 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent< height={avatarSize} />
    - {person.user.name} - {person.userId} + { person.user.name } + { person.userId }
    this.setPersonToggle(person, e.target.checked)} />
    @@ -187,7 +187,7 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent< emailAddresses.push(( this.onAddressChange(e, emailAddresses.length)} label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")} placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")} @@ -207,16 +207,16 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent< onClick={this.onShowMorePeople} kind="link" key="more" className="mx_CommunityPrototypeInviteDialog_morePeople" - >{_t("Show more")} + >{ _t("Show more") } )); } } if (this.state.people.length > 0) { peopleIntro = (
    - {_t("People you know on %(brand)s", { brand: SdkConfig.get().brand })} + { _t("People you know on %(brand)s", { brand: SdkConfig.get().brand }) } - {this.state.showPeople ? _t("Hide") : _t("Show")} + { this.state.showPeople ? _t("Hide") : _t("Show") }
    ); @@ -236,14 +236,14 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent< >
    - {emailAddresses} - {peopleIntro} - {people} + { emailAddresses } + { peopleIntro } + { people } {buttonText} + >{ buttonText }
    diff --git a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx index 544d0df1c9..2577d5456d 100644 --- a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx +++ b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx @@ -44,10 +44,10 @@ export default class ConfirmWipeDeviceDialog extends React.Component { >

    - {_t( + { _t( "Clearing all data from this session is permanent. Encrypted messages will be lost " + "unless their keys have been backed up.", - )} + ) }

    - {_t("Community ID: +:%(domain)s", { + { _t("Community ID: +:%(domain)s", { domain: MatrixClientPeg.getHomeserverName(), }, { - localpart: () => {this.state.localpart}, - })} + localpart: () => { this.state.localpart }, + }) } - {_t("You can change this later if needed.")} + { _t("You can change this later if needed.") }
    ); if (this.state.error) { const classes = "mx_CreateCommunityPrototypeDialog_subtext mx_CreateCommunityPrototypeDialog_subtext_error"; helpText = ( - {this.state.error} + { this.state.error } ); } @@ -193,13 +193,13 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent< placeholder={_t("Enter name")} label={_t("Enter name")} /> - {helpText} + { helpText } - {/*nbsp is to reserve the height of this element when there's nothing*/} -  {communityId} + { /*nbsp is to reserve the height of this element when there's nothing*/ } +  { communityId } - {_t("Create")} + { _t("Create") }
    @@ -212,12 +212,12 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent< onClick={this.onChangeAvatar} className="mx_CreateCommunityPrototypeDialog_avatarContainer" > - {preview} + { preview }
    - {_t("Add image (optional)")} + { _t("Add image (optional)") } - {_t("An image will help people identify your community.")} + { _t("An image will help people identify your community.") }
    diff --git a/src/components/views/dialogs/CreateGroupDialog.tsx b/src/components/views/dialogs/CreateGroupDialog.tsx index d6bb582079..88ae801441 100644 --- a/src/components/views/dialogs/CreateGroupDialog.tsx +++ b/src/components/views/dialogs/CreateGroupDialog.tsx @@ -102,7 +102,7 @@ export default class CreateGroupDialog extends React.Component { }); }; - _onCancel = () => { + private onCancel = () => { this.props.onFinished(false); }; @@ -167,7 +167,7 @@ export default class CreateGroupDialog extends React.Component {
    -
    diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index b5c0096771..6d75b94c70 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -224,15 +224,15 @@ export default class CreateRoomDialog extends React.Component { ); } - let publicPrivateLabel =

    {_t( + let publicPrivateLabel =

    { _t( "Private rooms can be found and joined by invitation only. Public rooms can be " + "found and joined by anyone.", - )}

    ; + ) }

    ; if (CommunityPrototypeStore.instance.getSelectedCommunityId()) { - publicPrivateLabel =

    {_t( + publicPrivateLabel =

    { _t( "Private rooms can be found and joined by invitation only. Public rooms can be " + "found and joined by anyone in this community.", - )}

    ; + ) }

    ; } let e2eeSection; @@ -250,7 +250,7 @@ export default class CreateRoomDialog extends React.Component { } e2eeSection = { onChange={this.onNoFederateChange} value={this.state.noFederate} /> -

    {federateLabel}

    +

    { federateLabel }

    diff --git a/src/components/views/dialogs/DeactivateAccountDialog.tsx b/src/components/views/dialogs/DeactivateAccountDialog.tsx index b2ac849314..7221df222f 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.tsx +++ b/src/components/views/dialogs/DeactivateAccountDialog.tsx @@ -172,11 +172,11 @@ export default class DeactivateAccountDialog extends React.Component; } - let auth =
    {_t("Loading...")}
    ; + let auth =
    { _t("Loading...") }
    ; if (this.state.authData && this.state.authEnabled) { auth = (
    - {this.state.bodyText} + { this.state.bodyText } - {_t( + { _t( "Please forget all messages I have sent when my account is deactivated " + "(Warning: this will cause future users to see an incomplete view " + "of conversations)", {}, { b: (sub) => { sub } }, - )} + ) }

    - {error} - {auth} + { error } + { auth }
    diff --git a/src/components/views/dialogs/DevtoolsDialog.tsx b/src/components/views/dialogs/DevtoolsDialog.tsx index 86b8f93d7b..61cda796ee 100644 --- a/src/components/views/dialogs/DevtoolsDialog.tsx +++ b/src/components/views/dialogs/DevtoolsDialog.tsx @@ -337,7 +337,7 @@ class FilteredList extends React.PureComponent - {eventType} + { eventType } ; }) } @@ -726,17 +726,17 @@ const VerificationRequestExplorer: React.FC<{ return (
    Transaction
    -
    {txnId}
    +
    { txnId }
    Phase
    -
    {PHASE_MAP[request.phase] || request.phase}
    +
    { PHASE_MAP[request.phase] || request.phase }
    Timeout
    -
    {Math.floor(timeout / 1000)}
    +
    { Math.floor(timeout / 1000) }
    Methods
    -
    {request.methods && request.methods.join(", ")}
    +
    { request.methods && request.methods.join(", ") }
    requestingUserId
    -
    {request.requestingUserId}
    +
    { request.requestingUserId }
    observeOnly
    -
    {JSON.stringify(request.observeOnly)}
    +
    { JSON.stringify(request.observeOnly) }
    ); }; @@ -771,12 +771,12 @@ class VerificationExplorer extends React.PureComponent { return (
    - {Array.from(inRoomRequests.entries()).reverse().map(([txnId, request]) => + { Array.from(inRoomRequests.entries()).reverse().map(([txnId, request]) => , - )} + ) }
    - +
    ); } @@ -844,9 +844,9 @@ class WidgetExplorer extends React.Component ev.getId() === editWidget.eventId); if (!stateEv) { // "should never happen" return
    - {_t("There was an error finding this widget.")} + { _t("There was an error finding this widget.") }
    - +
    ; } @@ -865,17 +865,17 @@ class WidgetExplorer extends React.Component
    - {widgets.map(w => { + { widgets.map(w => { return ; - })} + >{ w.url }; + }) }
    - +
    ); } @@ -1007,7 +1007,7 @@ class SettingsExplorer extends React.PureComponent{canEdit.toString()}; + return
    ; } render() { @@ -1028,17 +1028,17 @@ class SettingsExplorer extends React.PureComponent - - - + + + - {allSettings.map(i => ( + { allSettings.map(i => ( - ))} + )) }
    {_t( + { _t( customVariables[row[0]].expl, customVariables[row[0]].getTextVariables ? customVariables[row[0]].getTextVariables() : null, - )}{ row[1] }
    { canEdit.toString() }
    {_t("Setting ID")}{_t("Value")}{_t("Value in this room")}{ _t("Setting ID") }{ _t("Value") }{ _t("Value in this room") }
    this.onViewClick(e, i)}> - {i} + { i } this.onEditClick(e, i)} className='mx_DevTools_SettingsExplorer_edit' @@ -1047,20 +1047,20 @@ class SettingsExplorer extends React.PureComponent - {this.renderSettingValue(SettingsStore.getValue(i))} + { this.renderSettingValue(SettingsStore.getValue(i)) } - {this.renderSettingValue(SettingsStore.getValue(i, room.roomId))} + { this.renderSettingValue(SettingsStore.getValue(i, room.roomId)) }
    - +
    ); @@ -1068,36 +1068,36 @@ class SettingsExplorer extends React.PureComponent
    -

    {_t("Setting:")} {this.state.editSetting}

    +

    { _t("Setting:") } { this.state.editSetting }

    - {_t("Caution:")} {_t( + { _t("Caution:") } { _t( "This UI does NOT check the types of the values. Use at your own risk.", - )} + ) }
    - {_t("Setting definition:")} -
    {JSON.stringify(SETTINGS[this.state.editSetting], null, 4)}
    + { _t("Setting definition:") } +
    { JSON.stringify(SETTINGS[this.state.editSetting], null, 4) }
    - - - + + + - {LEVEL_ORDER.map(lvl => ( + { LEVEL_ORDER.map(lvl => ( - - {this.renderCanEditLevel(null, lvl)} - {this.renderCanEditLevel(room.roomId, lvl)} + + { this.renderCanEditLevel(null, lvl) } + { this.renderCanEditLevel(room.roomId, lvl) } - ))} + )) }
    {_t("Level")}{_t("Settable at global")}{_t("Settable at room")}{ _t("Level") }{ _t("Settable at global") }{ _t("Settable at room") }
    {lvl}{ lvl }
    @@ -1122,8 +1122,8 @@ class SettingsExplorer extends React.PureComponent
    - - + +
    ); @@ -1131,39 +1131,39 @@ class SettingsExplorer extends React.PureComponent
    -

    {_t("Setting:")} {this.state.viewSetting}

    +

    { _t("Setting:") } { this.state.viewSetting }

    - {_t("Setting definition:")} -
    {JSON.stringify(SETTINGS[this.state.viewSetting], null, 4)}
    + { _t("Setting definition:") } +
    { JSON.stringify(SETTINGS[this.state.viewSetting], null, 4) }
    - {_t("Value:")}  - {this.renderSettingValue( + { _t("Value:") }  + { this.renderSettingValue( SettingsStore.getValue(this.state.viewSetting), - )} + ) }
    - {_t("Value in this room:")}  - {this.renderSettingValue( + { _t("Value in this room:") }  + { this.renderSettingValue( SettingsStore.getValue(this.state.viewSetting, room.roomId), - )} + ) }
    - {_t("Values at explicit levels:")} -
    {this.renderExplicitSettingValues(
    +                            { _t("Values at explicit levels:") }
    +                            
    { this.renderExplicitSettingValues(
                                     this.state.viewSetting, null,
    -                            )}
    + ) }
    - {_t("Values at explicit levels in this room:")} -
    {this.renderExplicitSettingValues(
    +                            { _t("Values at explicit levels in this room:") }
    +                            
    { this.renderExplicitSettingValues(
                                     this.state.viewSetting, room.roomId,
    -                            )}
    + ) }
    @@ -1171,7 +1171,7 @@ class SettingsExplorer extends React.PureComponent this.onEditClick(e, this.state.viewSetting)}>{ _t("Edit Values") } - + ); @@ -1232,12 +1232,12 @@ export default class DevtoolsDialog extends React.PureComponent if (this.state.mode) { body = - {(cli) => + { (cli) =>
    { this.state.mode.getLabel() }
    Room ID: { this.props.roomId }
    - } + } ; } else { const classes = "mx_DevTools_RoomStateExplorer_button"; diff --git a/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx index 217e4f2d37..1eabb68081 100644 --- a/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx +++ b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx @@ -151,16 +151,16 @@ export default class EditCommunityPrototypeDialog extends React.PureComponent{preview} + >{ preview }
    - {_t("Add image (optional)")} + { _t("Add image (optional)") } - {_t("An image will help people identify your community.")} + { _t("An image will help people identify your community.") }
    - {_t("Save")} + { _t("Save") } diff --git a/src/components/views/dialogs/FeedbackDialog.js b/src/components/views/dialogs/FeedbackDialog.js index 88a57cf8cb..85171c9bf6 100644 --- a/src/components/views/dialogs/FeedbackDialog.js +++ b/src/components/views/dialogs/FeedbackDialog.js @@ -58,10 +58,10 @@ export default (props) => { countlyFeedbackSection =
    -

    {_t("Rate %(brand)s", { brand })}

    +

    { _t("Rate %(brand)s", { brand }) }

    -

    {_t("Tell us below how you feel about %(brand)s so far.", { brand })}

    -

    {_t("Please go into as much detail as you like, so we can track down the problem.")}

    +

    { _t("Tell us below how you feel about %(brand)s so far.", { brand }) }

    +

    { _t("Please go into as much detail as you like, so we can track down the problem.") }

    { let subheading; if (hasFeedback) { subheading = ( -

    {_t("There are two ways you can provide feedback and help us improve %(brand)s.", { brand })}

    +

    { _t("There are two ways you can provide feedback and help us improve %(brand)s.", { brand }) }

    ); } @@ -106,7 +106,7 @@ export default (props) => { _t("PRO TIP: If you start a bug, please submit debug logs " + "to help us track down the problem.", {}, { debugLogsLink: sub => ( - {sub} + { sub } ), }) }

    @@ -121,7 +121,7 @@ export default (props) => { { subheading }
    -

    {_t("Report a bug")}

    +

    { _t("Report a bug") }

    { _t("Please view existing bugs on Github first. " + "No match? Start a new one.", {}, { @@ -133,7 +133,7 @@ export default (props) => { }, }) }

    - {bugReports} + { bugReports }
    { countlyFeedbackSection } } diff --git a/src/components/views/dialogs/HostSignupDialog.tsx b/src/components/views/dialogs/HostSignupDialog.tsx index 64c080bf01..4b8b7f32f0 100644 --- a/src/components/views/dialogs/HostSignupDialog.tsx +++ b/src/components/views/dialogs/HostSignupDialog.tsx @@ -177,32 +177,32 @@ export default class HostSignupDialog extends React.PureComponent

    - {_t("Continuing temporarily allows the %(hostSignupBrand)s setup process to access your " + + { _t("Continuing temporarily allows the %(hostSignupBrand)s setup process to access your " + "account to fetch verified email addresses. This data is not stored.", { hostSignupBrand: this.config.brand, - })} + }) }

    - {_t("Learn more in our , and .", + { _t("Learn more in our , and .", {}, { cookiePolicyLink: () => ( - {_t("Cookie Policy")} + { _t("Cookie Policy") } ), privacyPolicyLink: () => ( - {_t("Privacy Policy")} + { _t("Privacy Policy") } ), termsOfServiceLink: () => ( - {_t("Terms of Service")} + { _t("Terms of Service") } ), }, - )} + ) }

    ); @@ -241,12 +241,12 @@ export default class HostSignupDialog extends React.PureComponent - {this.state.minimized && + { this.state.minimized &&
    - {_t("%(hostSignupBrand)s Setup", { + { _t("%(hostSignupBrand)s Setup", { hostSignupBrand: this.config.brand, - })} + }) }
    } - {!this.state.minimized && + { !this.state.minimized &&
    } - {this.state.error && + { this.state.error &&
    - {this.state.error} + { this.state.error }
    } - {!this.state.error && + { !this.state.error &&