diff --git a/.eslintignore b/.eslintignore
index c4f7298047..e453170087 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,4 +1,4 @@
src/component-index.js
test/end-to-end-tests/node_modules/
-test/end-to-end-tests/riot/
+test/end-to-end-tests/element/
test/end-to-end-tests/synapse/
diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles
index 1faffbbdf7..d9177bebb5 100644
--- a/.eslintignore.errorfiles
+++ b/.eslintignore.errorfiles
@@ -1,57 +1,16 @@
# autogenerated file: run scripts/generate-eslint-error-ignore-file to update.
-src/components/structures/RoomDirectory.js
-src/components/structures/RoomStatusBar.js
-src/components/structures/RoomView.js
-src/components/structures/ScrollPanel.js
-src/components/structures/SearchBox.js
-src/components/structures/UploadBar.js
-src/components/views/avatars/MemberAvatar.js
-src/components/views/create_room/RoomAlias.js
-src/components/views/dialogs/SetPasswordDialog.js
-src/components/views/elements/AddressSelector.js
-src/components/views/elements/DirectorySearchBox.js
-src/components/views/elements/MemberEventListSummary.js
-src/components/views/elements/UserSelector.js
-src/components/views/globals/NewVersionBar.js
-src/components/views/messages/MFileBody.js
-src/components/views/messages/TextualBody.js
-src/components/views/room_settings/ColorSettings.js
-src/components/views/rooms/Autocomplete.js
-src/components/views/rooms/AuxPanel.js
-src/components/views/rooms/LinkPreviewWidget.js
-src/components/views/rooms/MemberInfo.js
-src/components/views/rooms/MemberList.js
-src/components/views/rooms/RoomList.js
-src/components/views/rooms/RoomPreviewBar.js
-src/components/views/rooms/SearchResultTile.js
-src/components/views/settings/ChangeAvatar.js
-src/components/views/settings/ChangePassword.js
-src/components/views/settings/DevicesPanel.js
-src/components/views/settings/Notifications.js
-src/HtmlUtils.js
-src/ImageUtils.js
src/Markdown.js
-src/notifications/ContentRules.js
-src/notifications/PushRuleVectorState.js
-src/PlatformPeg.js
-src/rageshake/rageshake.js
+src/NodeAnimator.js
+src/components/structures/RoomDirectory.js
+src/components/views/rooms/MemberList.js
src/ratelimitedfunc.js
-src/Rooms.js
-src/Unread.js
-src/utils/DecryptFile.js
-src/utils/DirectoryUtils.js
src/utils/DMRoomMap.js
-src/utils/FormattingUtils.js
src/utils/MultiInviter.js
-src/utils/Receipt.js
-src/Velociraptor.js
test/components/structures/MessagePanel-test.js
test/components/views/dialogs/InteractiveAuthDialog-test.js
test/mock-clock.js
-test/notifications/ContentRules-test.js
-test/notifications/PushRuleVectorState-test.js
src/component-index.js
test/end-to-end-tests/node_modules/
-test/end-to-end-tests/riot/
+test/end-to-end-tests/element/
test/end-to-end-tests/synapse/
diff --git a/.eslintrc.js b/.eslintrc.js
index fc82e75ce2..4959b133a0 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -15,13 +15,14 @@ module.exports = {
"prefer-promise-reject-errors": "off",
"no-async-promise-executor": "off",
"quotes": "off",
- "indent": "off",
},
overrides: [{
- "files": ["src/**/*.{ts, tsx}"],
+ "files": ["src/**/*.{ts,tsx}"],
"extends": ["matrix-org/ts"],
"rules": {
+ // We're okay being explicit at the moment
+ "@typescript-eslint/no-empty-interface": "off",
// We disable this while we're transitioning
"@typescript-eslint/no-explicit-any": "off",
// We'd rather not do this but we do
diff --git a/.gitignore b/.gitignore
index 33e8bfc7ac..50aa10fbfd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
/*.log
package-lock.json
+/coverage
/node_modules
/lib
@@ -13,3 +14,4 @@ package-lock.json
/src/component-index.js
.DS_Store
+*.tmp
diff --git a/.stylelintrc.js b/.stylelintrc.js
index 313102ea83..0e6de7000f 100644
--- a/.stylelintrc.js
+++ b/.stylelintrc.js
@@ -4,6 +4,7 @@ module.exports = {
"stylelint-scss",
],
"rules": {
+ "color-hex-case": null,
"indentation": 4,
"comment-empty-line-before": null,
"declaration-empty-line-before": null,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 468d7d211a..2582668ef9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,1917 @@
+Changes in [3.21.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.21.0) (2021-05-17)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.21.0-rc.1...v3.21.0)
+
+## Security notice
+
+matrix-react-sdk 3.21.0 fixes a low severity issue (GHSA-8796-gc9j-63rv)
+related to file upload. When uploading a file, the local file preview can lead
+to execution of scripts embedded in the uploaded file, but only after several
+user interactions to open the preview in a separate tab. This only impacts the
+local user while in the process of uploading. It cannot be exploited remotely
+or by other users. Thanks to [Muhammad Zaid Ghifari](https://github.com/MR-ZHEEV)
+for responsibly disclosing this via Matrix's Security Disclosure Policy.
+
+## All changes
+
+ * Upgrade to JS SDK 11.0.0
+ * [Release] Add missing space on beta feedback dialog
+ [\#6019](https://github.com/matrix-org/matrix-react-sdk/pull/6019)
+ * [Release] Add feedback mechanism for beta features, namely Spaces
+ [\#6013](https://github.com/matrix-org/matrix-react-sdk/pull/6013)
+ * Add feedback mechanism for beta features, namely Spaces
+ [\#6012](https://github.com/matrix-org/matrix-react-sdk/pull/6012)
+
+Changes in [3.21.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.21.0-rc.1) (2021-05-11)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.20.0...v3.21.0-rc.1)
+
+ * Upgrade to JS SDK 11.0.0-rc.1
+ * Add disclaimer about subspaces being experimental in add existing dialog
+ [\#5978](https://github.com/matrix-org/matrix-react-sdk/pull/5978)
+ * Spaces Beta release
+ [\#5933](https://github.com/matrix-org/matrix-react-sdk/pull/5933)
+ * Improve permissions error when adding new server to room directory
+ [\#6009](https://github.com/matrix-org/matrix-react-sdk/pull/6009)
+ * Allow user to progress through space creation & setup using Enter
+ [\#6006](https://github.com/matrix-org/matrix-react-sdk/pull/6006)
+ * Upgrade sanitize types
+ [\#6008](https://github.com/matrix-org/matrix-react-sdk/pull/6008)
+ * Upgrade `cheerio` and resolve type errors
+ [\#6007](https://github.com/matrix-org/matrix-react-sdk/pull/6007)
+ * Add slash commands support to edit message composer
+ [\#5865](https://github.com/matrix-org/matrix-react-sdk/pull/5865)
+ * Fix the two todays problem
+ [\#5940](https://github.com/matrix-org/matrix-react-sdk/pull/5940)
+ * Switch the Home Space out for an All rooms space
+ [\#5969](https://github.com/matrix-org/matrix-react-sdk/pull/5969)
+ * Show device ID in UserInfo when there is no device name
+ [\#5985](https://github.com/matrix-org/matrix-react-sdk/pull/5985)
+ * Switch back to release version of `sanitize-html`
+ [\#6005](https://github.com/matrix-org/matrix-react-sdk/pull/6005)
+ * Bump hosted-git-info from 2.8.8 to 2.8.9
+ [\#5998](https://github.com/matrix-org/matrix-react-sdk/pull/5998)
+ * Don't use the event's metadata to calc the scale of an image
+ [\#5982](https://github.com/matrix-org/matrix-react-sdk/pull/5982)
+ * Adjust MIME type of upload confirmation if needed
+ [\#5981](https://github.com/matrix-org/matrix-react-sdk/pull/5981)
+ * Forbid redaction of encryption events
+ [\#5991](https://github.com/matrix-org/matrix-react-sdk/pull/5991)
+ * Fix voice message playback being squished up against send button
+ [\#5988](https://github.com/matrix-org/matrix-react-sdk/pull/5988)
+ * Improve style of notification badges on the space panel
+ [\#5983](https://github.com/matrix-org/matrix-react-sdk/pull/5983)
+ * Add dev dependency for parse5 typings
+ [\#5990](https://github.com/matrix-org/matrix-react-sdk/pull/5990)
+ * Iterate Spaces admin UX around room management
+ [\#5977](https://github.com/matrix-org/matrix-react-sdk/pull/5977)
+ * Guard all isSpaceRoom calls behind the labs flag
+ [\#5979](https://github.com/matrix-org/matrix-react-sdk/pull/5979)
+ * Bump lodash from 4.17.20 to 4.17.21
+ [\#5986](https://github.com/matrix-org/matrix-react-sdk/pull/5986)
+ * Bump lodash from 4.17.19 to 4.17.21 in /test/end-to-end-tests
+ [\#5987](https://github.com/matrix-org/matrix-react-sdk/pull/5987)
+ * Bump ua-parser-js from 0.7.23 to 0.7.28
+ [\#5984](https://github.com/matrix-org/matrix-react-sdk/pull/5984)
+ * Update visual style of plain files in the timeline
+ [\#5971](https://github.com/matrix-org/matrix-react-sdk/pull/5971)
+ * Support for multiple streams (not MSC3077)
+ [\#5833](https://github.com/matrix-org/matrix-react-sdk/pull/5833)
+ * Update space ordering behaviour to match updates in MSC
+ [\#5963](https://github.com/matrix-org/matrix-react-sdk/pull/5963)
+ * Improve performance of search all spaces and space switching
+ [\#5976](https://github.com/matrix-org/matrix-react-sdk/pull/5976)
+ * Update colours and sizing for voice messages
+ [\#5970](https://github.com/matrix-org/matrix-react-sdk/pull/5970)
+ * Update link to Android SDK
+ [\#5973](https://github.com/matrix-org/matrix-react-sdk/pull/5973)
+ * Add cleanup functions for image view
+ [\#5962](https://github.com/matrix-org/matrix-react-sdk/pull/5962)
+ * Add a note about sharing your IP in P2P calls
+ [\#5961](https://github.com/matrix-org/matrix-react-sdk/pull/5961)
+ * Only aggregate DM notifications on the Space Panel in the Home Space
+ [\#5968](https://github.com/matrix-org/matrix-react-sdk/pull/5968)
+ * Add retry mechanism and progress bar to add existing to space dialog
+ [\#5975](https://github.com/matrix-org/matrix-react-sdk/pull/5975)
+ * Warn on access token reveal
+ [\#5755](https://github.com/matrix-org/matrix-react-sdk/pull/5755)
+ * Fix newly joined room appearing under the wrong space
+ [\#5945](https://github.com/matrix-org/matrix-react-sdk/pull/5945)
+ * Early rendering for voice messages in the timeline
+ [\#5955](https://github.com/matrix-org/matrix-react-sdk/pull/5955)
+ * Calculate the real waveform in the Playback class for voice messages
+ [\#5956](https://github.com/matrix-org/matrix-react-sdk/pull/5956)
+ * Don't recurse on arrayFastResample
+ [\#5957](https://github.com/matrix-org/matrix-react-sdk/pull/5957)
+ * Support a dark theme for voice messages
+ [\#5958](https://github.com/matrix-org/matrix-react-sdk/pull/5958)
+ * Handle no/blocked microphones in voice messages
+ [\#5959](https://github.com/matrix-org/matrix-react-sdk/pull/5959)
+
+Changes in [3.20.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.20.0) (2021-05-10)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.20.0-rc.1...v3.20.0)
+
+ * Upgrade to JS SDK 10.1.0
+ * [Release] Don't use the event's metadata to calc the scale of an image
+ [\#6004](https://github.com/matrix-org/matrix-react-sdk/pull/6004)
+
+Changes in [3.20.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.20.0-rc.1) (2021-05-04)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.19.0...v3.20.0-rc.1)
+
+ * Upgrade to JS SDK 10.1.0-rc.1
+ * Translations update from Weblate
+ [\#5966](https://github.com/matrix-org/matrix-react-sdk/pull/5966)
+ * Fix more space panel layout and hover behaviour issues
+ [\#5965](https://github.com/matrix-org/matrix-react-sdk/pull/5965)
+ * Fix edge case with space panel alignment with subspaces on ff
+ [\#5964](https://github.com/matrix-org/matrix-react-sdk/pull/5964)
+ * Fix saving room pill part to history
+ [\#5951](https://github.com/matrix-org/matrix-react-sdk/pull/5951)
+ * Generate room preview even when minimized
+ [\#5948](https://github.com/matrix-org/matrix-react-sdk/pull/5948)
+ * Another change from recovery passphrase to Security Phrase
+ [\#5934](https://github.com/matrix-org/matrix-react-sdk/pull/5934)
+ * Sort rooms in the add existing to space dialog based on recency
+ [\#5943](https://github.com/matrix-org/matrix-react-sdk/pull/5943)
+ * Inhibit sending RR when context switching to a room
+ [\#5944](https://github.com/matrix-org/matrix-react-sdk/pull/5944)
+ * Prevent room list keyboard handling from landing focus on hidden nodes
+ [\#5950](https://github.com/matrix-org/matrix-react-sdk/pull/5950)
+ * Make the text filter search all spaces instead of just the selected one
+ [\#5942](https://github.com/matrix-org/matrix-react-sdk/pull/5942)
+ * Enable indent rule and fix indent
+ [\#5931](https://github.com/matrix-org/matrix-react-sdk/pull/5931)
+ * Prevent peeking members from reacting
+ [\#5946](https://github.com/matrix-org/matrix-react-sdk/pull/5946)
+ * Disallow inline display maths
+ [\#5939](https://github.com/matrix-org/matrix-react-sdk/pull/5939)
+ * Space creation prompt user to add existing rooms for "Just Me" spaces
+ [\#5923](https://github.com/matrix-org/matrix-react-sdk/pull/5923)
+ * Add test coverage collection script
+ [\#5937](https://github.com/matrix-org/matrix-react-sdk/pull/5937)
+ * Fix joining room using via servers regression
+ [\#5936](https://github.com/matrix-org/matrix-react-sdk/pull/5936)
+ * Revert "Fixes the two Todays problem in Redaction"
+ [\#5938](https://github.com/matrix-org/matrix-react-sdk/pull/5938)
+ * Handle encoded matrix URLs
+ [\#5903](https://github.com/matrix-org/matrix-react-sdk/pull/5903)
+ * Render ignored users setting regardless of if there are any
+ [\#5860](https://github.com/matrix-org/matrix-react-sdk/pull/5860)
+ * Fix inserting trailing colon after mention/pill
+ [\#5830](https://github.com/matrix-org/matrix-react-sdk/pull/5830)
+ * Fixes the two Todays problem in Redaction
+ [\#5917](https://github.com/matrix-org/matrix-react-sdk/pull/5917)
+ * Fix page up/down scrolling only half a page
+ [\#5920](https://github.com/matrix-org/matrix-react-sdk/pull/5920)
+ * Voice messages: Composer controls
+ [\#5935](https://github.com/matrix-org/matrix-react-sdk/pull/5935)
+ * Support MSC3086 asserted identity
+ [\#5886](https://github.com/matrix-org/matrix-react-sdk/pull/5886)
+ * Handle possible edge case with getting stuck in "unsent messages" bar
+ [\#5930](https://github.com/matrix-org/matrix-react-sdk/pull/5930)
+ * Fix suggested rooms not showing up regression from room list optimisation
+ [\#5932](https://github.com/matrix-org/matrix-react-sdk/pull/5932)
+ * Broadcast language change to ElectronPlatform
+ [\#5913](https://github.com/matrix-org/matrix-react-sdk/pull/5913)
+ * Fix VoIP PIP frame color
+ [\#5701](https://github.com/matrix-org/matrix-react-sdk/pull/5701)
+ * Convert some Flow-typed files to TypeScript
+ [\#5912](https://github.com/matrix-org/matrix-react-sdk/pull/5912)
+ * Initial SpaceStore tests work
+ [\#5906](https://github.com/matrix-org/matrix-react-sdk/pull/5906)
+ * Fix issues with space hierarchy in layout and with incompatible servers
+ [\#5926](https://github.com/matrix-org/matrix-react-sdk/pull/5926)
+ * Scale all mxc thumbs using device pixel ratio for hidpi
+ [\#5928](https://github.com/matrix-org/matrix-react-sdk/pull/5928)
+ * Fix add existing to space dialog no longer showing rooms for public spaces
+ [\#5918](https://github.com/matrix-org/matrix-react-sdk/pull/5918)
+ * Disable spaces context switching for when exploring a space
+ [\#5924](https://github.com/matrix-org/matrix-react-sdk/pull/5924)
+ * Autofocus search box in the add existing to space dialog
+ [\#5921](https://github.com/matrix-org/matrix-react-sdk/pull/5921)
+ * Use label element in add existing to space dialog for easier hit target
+ [\#5922](https://github.com/matrix-org/matrix-react-sdk/pull/5922)
+ * Dynamic max and min zoom in the new ImageView
+ [\#5916](https://github.com/matrix-org/matrix-react-sdk/pull/5916)
+ * Improve message error states
+ [\#5897](https://github.com/matrix-org/matrix-react-sdk/pull/5897)
+ * Check for null room in `VisibilityProvider`
+ [\#5914](https://github.com/matrix-org/matrix-react-sdk/pull/5914)
+ * Add unit tests for various collection-based utility functions
+ [\#5910](https://github.com/matrix-org/matrix-react-sdk/pull/5910)
+ * Spaces visual fixes
+ [\#5909](https://github.com/matrix-org/matrix-react-sdk/pull/5909)
+ * Remove reliance on DOM API to generated message preview
+ [\#5908](https://github.com/matrix-org/matrix-react-sdk/pull/5908)
+ * Expand upon voice message event & include overall waveform
+ [\#5888](https://github.com/matrix-org/matrix-react-sdk/pull/5888)
+ * Use floats for image background opacity
+ [\#5905](https://github.com/matrix-org/matrix-react-sdk/pull/5905)
+ * Show invites to spaces at the top of the space panel
+ [\#5902](https://github.com/matrix-org/matrix-react-sdk/pull/5902)
+ * Improve edge cases with spaces context switching
+ [\#5899](https://github.com/matrix-org/matrix-react-sdk/pull/5899)
+ * Fix spaces notification dots wrongly including upgraded (hidden) rooms
+ [\#5900](https://github.com/matrix-org/matrix-react-sdk/pull/5900)
+ * Iterate the spaces face pile design
+ [\#5898](https://github.com/matrix-org/matrix-react-sdk/pull/5898)
+ * Fix alignment issue with nested spaces being cut off wrong
+ [\#5890](https://github.com/matrix-org/matrix-react-sdk/pull/5890)
+
+Changes in [3.19.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.19.0) (2021-04-26)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.19.0-rc.1...v3.19.0)
+
+ * Upgrade to JS SDK 10.0.0
+ * [Release] Dynamic max and min zoom in the new ImageView
+ [\#5927](https://github.com/matrix-org/matrix-react-sdk/pull/5927)
+ * [Release] Add a WheelEvent normalization function
+ [\#5911](https://github.com/matrix-org/matrix-react-sdk/pull/5911)
+ * Add a WheelEvent normalization function
+ [\#5904](https://github.com/matrix-org/matrix-react-sdk/pull/5904)
+ * [Release] Use floats for image background opacity
+ [\#5907](https://github.com/matrix-org/matrix-react-sdk/pull/5907)
+
+Changes in [3.19.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.19.0-rc.1) (2021-04-21)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.18.0...v3.19.0-rc.1)
+
+ * Upgrade to JS SDK 10.0.0-rc.1
+ * Translations update from Weblate
+ [\#5896](https://github.com/matrix-org/matrix-react-sdk/pull/5896)
+ * Fix sticky tags header in room list
+ [\#5895](https://github.com/matrix-org/matrix-react-sdk/pull/5895)
+ * Fix spaces filtering sometimes lagging behind or behaving oddly
+ [\#5893](https://github.com/matrix-org/matrix-react-sdk/pull/5893)
+ * Fix issue with spaces context switching looping and breaking
+ [\#5894](https://github.com/matrix-org/matrix-react-sdk/pull/5894)
+ * Improve RoomList render time when filtering
+ [\#5874](https://github.com/matrix-org/matrix-react-sdk/pull/5874)
+ * Avoid being stuck in a space
+ [\#5891](https://github.com/matrix-org/matrix-react-sdk/pull/5891)
+ * [Spaces] Context switching
+ [\#5795](https://github.com/matrix-org/matrix-react-sdk/pull/5795)
+ * Warn when you attempt to leave room that you are the only member of
+ [\#5415](https://github.com/matrix-org/matrix-react-sdk/pull/5415)
+ * Ensure PersistedElement are unmounted on application logout
+ [\#5884](https://github.com/matrix-org/matrix-react-sdk/pull/5884)
+ * Add missing space in seshat dialog and the corresponding string
+ [\#5866](https://github.com/matrix-org/matrix-react-sdk/pull/5866)
+ * A tiny change to make the Add existing rooms dialog a little nicer
+ [\#5885](https://github.com/matrix-org/matrix-react-sdk/pull/5885)
+ * Remove weird margin from the file panel
+ [\#5889](https://github.com/matrix-org/matrix-react-sdk/pull/5889)
+ * Trigger lazy loading when filtering using spaces
+ [\#5882](https://github.com/matrix-org/matrix-react-sdk/pull/5882)
+ * Fix typo in method call in add existing to space dialog
+ [\#5883](https://github.com/matrix-org/matrix-react-sdk/pull/5883)
+ * New Image View fixes/improvements
+ [\#5872](https://github.com/matrix-org/matrix-react-sdk/pull/5872)
+ * Limit voice recording length
+ [\#5871](https://github.com/matrix-org/matrix-react-sdk/pull/5871)
+ * Clean up add existing to space dialog and include DMs in it too
+ [\#5881](https://github.com/matrix-org/matrix-react-sdk/pull/5881)
+ * Fix unknown slash command error exploding
+ [\#5853](https://github.com/matrix-org/matrix-react-sdk/pull/5853)
+ * Switch to a spec conforming email validation Regexp
+ [\#5852](https://github.com/matrix-org/matrix-react-sdk/pull/5852)
+ * Cleanup unused state in MessageComposer
+ [\#5877](https://github.com/matrix-org/matrix-react-sdk/pull/5877)
+ * Pulse animation for voice messages recording state
+ [\#5869](https://github.com/matrix-org/matrix-react-sdk/pull/5869)
+ * Don't include invisible rooms in notify summary
+ [\#5875](https://github.com/matrix-org/matrix-react-sdk/pull/5875)
+ * Properly disable composer access when recording a voice message
+ [\#5870](https://github.com/matrix-org/matrix-react-sdk/pull/5870)
+ * Stabilise starting a DM with multiple people flow
+ [\#5862](https://github.com/matrix-org/matrix-react-sdk/pull/5862)
+ * Render msgOption only if showReadReceipts is enabled
+ [\#5864](https://github.com/matrix-org/matrix-react-sdk/pull/5864)
+ * Labs: Add quick/cheap "do not disturb" flag
+ [\#5873](https://github.com/matrix-org/matrix-react-sdk/pull/5873)
+ * Fix ReadReceipts animations
+ [\#5836](https://github.com/matrix-org/matrix-react-sdk/pull/5836)
+ * Add tooltips to message previews
+ [\#5859](https://github.com/matrix-org/matrix-react-sdk/pull/5859)
+ * IRC Layout fix layout spacing in replies
+ [\#5855](https://github.com/matrix-org/matrix-react-sdk/pull/5855)
+ * Move user to welcome_page if continuing with previous session
+ [\#5849](https://github.com/matrix-org/matrix-react-sdk/pull/5849)
+ * Improve image view
+ [\#5521](https://github.com/matrix-org/matrix-react-sdk/pull/5521)
+ * Add a button to reset personal encryption state during login
+ [\#5819](https://github.com/matrix-org/matrix-react-sdk/pull/5819)
+ * Fix js-sdk import in SlashCommands
+ [\#5850](https://github.com/matrix-org/matrix-react-sdk/pull/5850)
+ * Fix useRoomPowerLevels hook
+ [\#5854](https://github.com/matrix-org/matrix-react-sdk/pull/5854)
+ * Prevent state events being rendered with invalid state keys
+ [\#5851](https://github.com/matrix-org/matrix-react-sdk/pull/5851)
+ * Give server ACLs a name in 'roles & permissions' tab
+ [\#5838](https://github.com/matrix-org/matrix-react-sdk/pull/5838)
+ * Don't hide notification badge on the home space button as it has no menu
+ [\#5845](https://github.com/matrix-org/matrix-react-sdk/pull/5845)
+ * User Info hide disambiguation as we always show MXID anyway
+ [\#5843](https://github.com/matrix-org/matrix-react-sdk/pull/5843)
+ * Improve kick state to not show if the target was not joined to begin with
+ [\#5846](https://github.com/matrix-org/matrix-react-sdk/pull/5846)
+ * Fix space store wrongly switching to a non-space filter
+ [\#5844](https://github.com/matrix-org/matrix-react-sdk/pull/5844)
+ * Tweak appearance of invite reason
+ [\#5847](https://github.com/matrix-org/matrix-react-sdk/pull/5847)
+ * Update Inter font to v3.18
+ [\#5840](https://github.com/matrix-org/matrix-react-sdk/pull/5840)
+ * Enable sharing historical keys on invite
+ [\#5839](https://github.com/matrix-org/matrix-react-sdk/pull/5839)
+ * Add ability to hide post-login encryption setup with customisation point
+ [\#5834](https://github.com/matrix-org/matrix-react-sdk/pull/5834)
+ * Use LaTeX and TeX delimiters by default
+ [\#5515](https://github.com/matrix-org/matrix-react-sdk/pull/5515)
+ * Clone author's deps fork for Netlify previews
+ [\#5837](https://github.com/matrix-org/matrix-react-sdk/pull/5837)
+ * Show drop file UI only if dragging a file
+ [\#5827](https://github.com/matrix-org/matrix-react-sdk/pull/5827)
+ * Ignore punctuation when filtering rooms
+ [\#5824](https://github.com/matrix-org/matrix-react-sdk/pull/5824)
+ * Resizable CallView
+ [\#5710](https://github.com/matrix-org/matrix-react-sdk/pull/5710)
+
+Changes in [3.18.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.18.0) (2021-04-12)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.18.0-rc.1...v3.18.0)
+
+ * Upgrade to JS SDK 9.11.0
+ * [Release] Tweak appearance of invite reason
+ [\#5848](https://github.com/matrix-org/matrix-react-sdk/pull/5848)
+
+Changes in [3.18.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.18.0-rc.1) (2021-04-07)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.17.0...v3.18.0-rc.1)
+
+ * Upgrade to JS SDK 9.11.0-rc.1
+ * Translations update from Weblate
+ [\#5832](https://github.com/matrix-org/matrix-react-sdk/pull/5832)
+ * Add fake fallback thumbnail URL for encrypted videos
+ [\#5826](https://github.com/matrix-org/matrix-react-sdk/pull/5826)
+ * Fix broken "Go to Home View" shortcut on macOS
+ [\#5818](https://github.com/matrix-org/matrix-react-sdk/pull/5818)
+ * Remove status area UI defects when in-call
+ [\#5828](https://github.com/matrix-org/matrix-react-sdk/pull/5828)
+ * Fix viewing invitations when the inviter has no avatar set
+ [\#5829](https://github.com/matrix-org/matrix-react-sdk/pull/5829)
+ * Restabilize room list ordering with prefiltering on spaces/communities
+ [\#5825](https://github.com/matrix-org/matrix-react-sdk/pull/5825)
+ * Show invite reasons
+ [\#5694](https://github.com/matrix-org/matrix-react-sdk/pull/5694)
+ * Require strong password in forgot password form
+ [\#5744](https://github.com/matrix-org/matrix-react-sdk/pull/5744)
+ * Attended transfer
+ [\#5798](https://github.com/matrix-org/matrix-react-sdk/pull/5798)
+ * Make user autocomplete query search beyond prefix
+ [\#5822](https://github.com/matrix-org/matrix-react-sdk/pull/5822)
+ * Add reset option for corrupted event index store
+ [\#5806](https://github.com/matrix-org/matrix-react-sdk/pull/5806)
+ * Prevent Re-request encryption keys from appearing under redacted messages
+ [\#5816](https://github.com/matrix-org/matrix-react-sdk/pull/5816)
+ * Keybindings follow up
+ [\#5815](https://github.com/matrix-org/matrix-react-sdk/pull/5815)
+ * Increase default visible tiles for room sublists
+ [\#5821](https://github.com/matrix-org/matrix-react-sdk/pull/5821)
+ * Change copy to point to native node modules docs in element desktop
+ [\#5817](https://github.com/matrix-org/matrix-react-sdk/pull/5817)
+ * Show waveform and timer in voice messages
+ [\#5801](https://github.com/matrix-org/matrix-react-sdk/pull/5801)
+ * Label unlabeled avatar button in event panel
+ [\#5585](https://github.com/matrix-org/matrix-react-sdk/pull/5585)
+ * Fix the theme engine breaking with some web theming extensions
+ [\#5810](https://github.com/matrix-org/matrix-react-sdk/pull/5810)
+ * Add /spoiler command
+ [\#5696](https://github.com/matrix-org/matrix-react-sdk/pull/5696)
+ * Don't specify sample rates for voice messages
+ [\#5802](https://github.com/matrix-org/matrix-react-sdk/pull/5802)
+ * Tweak security key error handling
+ [\#5812](https://github.com/matrix-org/matrix-react-sdk/pull/5812)
+ * Add user settings for warn before exit
+ [\#5793](https://github.com/matrix-org/matrix-react-sdk/pull/5793)
+ * Decouple key bindings from event handling
+ [\#5720](https://github.com/matrix-org/matrix-react-sdk/pull/5720)
+ * Fixing spaces papercuts
+ [\#5792](https://github.com/matrix-org/matrix-react-sdk/pull/5792)
+ * Share keys for historical messages when inviting users to encrypted rooms
+ [\#5763](https://github.com/matrix-org/matrix-react-sdk/pull/5763)
+ * Fix upload bar not populating when starting uploads
+ [\#5804](https://github.com/matrix-org/matrix-react-sdk/pull/5804)
+ * Fix crash on login when using social login
+ [\#5803](https://github.com/matrix-org/matrix-react-sdk/pull/5803)
+ * Convert AccessSecretStorageDialog to TypeScript
+ [\#5805](https://github.com/matrix-org/matrix-react-sdk/pull/5805)
+ * Tweak cross-signing copy
+ [\#5807](https://github.com/matrix-org/matrix-react-sdk/pull/5807)
+ * Fix password change popup message
+ [\#5791](https://github.com/matrix-org/matrix-react-sdk/pull/5791)
+ * View Source: make Event ID go below Event ID
+ [\#5790](https://github.com/matrix-org/matrix-react-sdk/pull/5790)
+ * Fix line numbers when missing trailing newline
+ [\#5800](https://github.com/matrix-org/matrix-react-sdk/pull/5800)
+ * Remember reply when switching rooms
+ [\#5796](https://github.com/matrix-org/matrix-react-sdk/pull/5796)
+ * Fix edge case with redaction grouper messing up continuations
+ [\#5797](https://github.com/matrix-org/matrix-react-sdk/pull/5797)
+ * Only show the ask anyway modal for explicit user lookup failures
+ [\#5785](https://github.com/matrix-org/matrix-react-sdk/pull/5785)
+ * Improve error reporting when EventIndex fails on a supported environment
+ [\#5787](https://github.com/matrix-org/matrix-react-sdk/pull/5787)
+ * Tweak and fix some space features
+ [\#5789](https://github.com/matrix-org/matrix-react-sdk/pull/5789)
+ * Support replying with a message command
+ [\#5686](https://github.com/matrix-org/matrix-react-sdk/pull/5686)
+ * Labs feature: Early implementation of voice messages
+ [\#5769](https://github.com/matrix-org/matrix-react-sdk/pull/5769)
+
+Changes in [3.17.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.17.0) (2021-03-29)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.17.0-rc.1...v3.17.0)
+
+ * Upgrade to JS SDK 9.10.0
+ * [Release] Tweak cross-signing copy
+ [\#5808](https://github.com/matrix-org/matrix-react-sdk/pull/5808)
+ * [Release] Fix crash on login when using social login
+ [\#5809](https://github.com/matrix-org/matrix-react-sdk/pull/5809)
+ * [Release] Fix edge case with redaction grouper messing up continuations
+ [\#5799](https://github.com/matrix-org/matrix-react-sdk/pull/5799)
+
+Changes in [3.17.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.17.0-rc.1) (2021-03-25)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.16.0...v3.17.0-rc.1)
+
+ * Upgrade to JS SDK 9.10.0-rc.1
+ * Translations update from Weblate
+ [\#5788](https://github.com/matrix-org/matrix-react-sdk/pull/5788)
+ * Track next event [tile] over group boundaries
+ [\#5784](https://github.com/matrix-org/matrix-react-sdk/pull/5784)
+ * Fixing the minor UI issues in the email discovery
+ [\#5780](https://github.com/matrix-org/matrix-react-sdk/pull/5780)
+ * Don't overwrite callback with undefined if no customization provided
+ [\#5783](https://github.com/matrix-org/matrix-react-sdk/pull/5783)
+ * Fix redaction event list summaries breaking sender profiles
+ [\#5781](https://github.com/matrix-org/matrix-react-sdk/pull/5781)
+ * Fix CIDER formatting buttons on Safari
+ [\#5782](https://github.com/matrix-org/matrix-react-sdk/pull/5782)
+ * Improve discovery of rooms in a space
+ [\#5776](https://github.com/matrix-org/matrix-react-sdk/pull/5776)
+ * Spaces improve creation journeys
+ [\#5777](https://github.com/matrix-org/matrix-react-sdk/pull/5777)
+ * Make buttons in verify dialog respect the system font
+ [\#5778](https://github.com/matrix-org/matrix-react-sdk/pull/5778)
+ * Collapse redactions into an event list summary
+ [\#5728](https://github.com/matrix-org/matrix-react-sdk/pull/5728)
+ * Added invite option to room's context menu
+ [\#5648](https://github.com/matrix-org/matrix-react-sdk/pull/5648)
+ * Add an optional config option to make the welcome page the login page
+ [\#5658](https://github.com/matrix-org/matrix-react-sdk/pull/5658)
+ * Fix username showing instead of display name in Jitsi widgets
+ [\#5770](https://github.com/matrix-org/matrix-react-sdk/pull/5770)
+ * Convert a bunch more js-sdk imports to absolute paths
+ [\#5774](https://github.com/matrix-org/matrix-react-sdk/pull/5774)
+ * Remove forgotten rooms from the room list once forgotten
+ [\#5775](https://github.com/matrix-org/matrix-react-sdk/pull/5775)
+ * Log error when failing to list usermedia devices
+ [\#5771](https://github.com/matrix-org/matrix-react-sdk/pull/5771)
+ * Fix weird timeline jumps
+ [\#5772](https://github.com/matrix-org/matrix-react-sdk/pull/5772)
+ * Replace type declaration in Registration.tsx
+ [\#5773](https://github.com/matrix-org/matrix-react-sdk/pull/5773)
+ * Add possibility to delay rageshake persistence in app startup
+ [\#5767](https://github.com/matrix-org/matrix-react-sdk/pull/5767)
+ * Fix left panel resizing and lower min-width improving flexibility
+ [\#5764](https://github.com/matrix-org/matrix-react-sdk/pull/5764)
+ * Work around more cases where a rageshake server might not be present
+ [\#5766](https://github.com/matrix-org/matrix-react-sdk/pull/5766)
+ * Iterate space panel visually and functionally
+ [\#5761](https://github.com/matrix-org/matrix-react-sdk/pull/5761)
+ * Make some dispatches async
+ [\#5765](https://github.com/matrix-org/matrix-react-sdk/pull/5765)
+ * fix: make room directory correct when using a homeserver with explicit port
+ [\#5762](https://github.com/matrix-org/matrix-react-sdk/pull/5762)
+ * Hangup all calls on logout
+ [\#5756](https://github.com/matrix-org/matrix-react-sdk/pull/5756)
+ * Remove now-unused assets and CSS from CompleteSecurity step
+ [\#5757](https://github.com/matrix-org/matrix-react-sdk/pull/5757)
+ * Add details and summary to allowed HTML tags
+ [\#5760](https://github.com/matrix-org/matrix-react-sdk/pull/5760)
+ * Support a media handling customisation endpoint
+ [\#5714](https://github.com/matrix-org/matrix-react-sdk/pull/5714)
+ * Edit button on View Source dialog that takes you to devtools ->
+ SendCustomEvent
+ [\#5718](https://github.com/matrix-org/matrix-react-sdk/pull/5718)
+ * Show room alias in plain/formatted body
+ [\#5748](https://github.com/matrix-org/matrix-react-sdk/pull/5748)
+ * Allow pills on the beginning of a part string
+ [\#5754](https://github.com/matrix-org/matrix-react-sdk/pull/5754)
+ * [SK-3] Decorate easy components with replaceableComponent
+ [\#5734](https://github.com/matrix-org/matrix-react-sdk/pull/5734)
+ * Use fsync in reskindex to ensure file is written to disk
+ [\#5753](https://github.com/matrix-org/matrix-react-sdk/pull/5753)
+ * Remove unused common CSS classes
+ [\#5752](https://github.com/matrix-org/matrix-react-sdk/pull/5752)
+ * Rebuild space previews with new designs
+ [\#5751](https://github.com/matrix-org/matrix-react-sdk/pull/5751)
+ * Rework cross-signing login flow
+ [\#5727](https://github.com/matrix-org/matrix-react-sdk/pull/5727)
+ * Change read receipt drift to be non-fractional
+ [\#5745](https://github.com/matrix-org/matrix-react-sdk/pull/5745)
+
+Changes in [3.16.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.16.0) (2021-03-15)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.16.0-rc.2...v3.16.0)
+
+ * Upgrade to JS SDK 9.9.0
+ * [Release] Change read receipt drift to be non-fractional
+ [\#5746](https://github.com/matrix-org/matrix-react-sdk/pull/5746)
+ * [Release] Properly gate SpaceRoomView behind labs
+ [\#5750](https://github.com/matrix-org/matrix-react-sdk/pull/5750)
+
+Changes in [3.16.0-rc.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.16.0-rc.2) (2021-03-10)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.16.0-rc.1...v3.16.0-rc.2)
+
+ * Fixed incorrect build output in rc.1
+
+Changes in [3.16.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.16.0-rc.1) (2021-03-10)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.15.0...v3.16.0-rc.1)
+
+ * Upgrade to JS SDK 9.9.0-rc.1
+ * Translations update from Weblate
+ [\#5743](https://github.com/matrix-org/matrix-react-sdk/pull/5743)
+ * Document behaviour of showReadReceipts=false for sent receipts
+ [\#5739](https://github.com/matrix-org/matrix-react-sdk/pull/5739)
+ * Tweak sent marker code style
+ [\#5741](https://github.com/matrix-org/matrix-react-sdk/pull/5741)
+ * Fix sent markers disappearing for edits/reactions
+ [\#5737](https://github.com/matrix-org/matrix-react-sdk/pull/5737)
+ * Ignore to-device decryption in the room list store
+ [\#5740](https://github.com/matrix-org/matrix-react-sdk/pull/5740)
+ * Spaces suggested rooms support
+ [\#5736](https://github.com/matrix-org/matrix-react-sdk/pull/5736)
+ * Add tooltips to sent/sending receipts
+ [\#5738](https://github.com/matrix-org/matrix-react-sdk/pull/5738)
+ * Remove a bunch of useless 'use strict' definitions
+ [\#5735](https://github.com/matrix-org/matrix-react-sdk/pull/5735)
+ * [SK-1] Fix types for replaceableComponent
+ [\#5732](https://github.com/matrix-org/matrix-react-sdk/pull/5732)
+ * [SK-2] Make debugging skinning problems easier
+ [\#5733](https://github.com/matrix-org/matrix-react-sdk/pull/5733)
+ * Support sending invite reasons with /invite command
+ [\#5695](https://github.com/matrix-org/matrix-react-sdk/pull/5695)
+ * Fix clicking on the avatar for opening member info requires pixel-perfect
+ accuracy
+ [\#5717](https://github.com/matrix-org/matrix-react-sdk/pull/5717)
+ * Display decrypted and encrypted event source on the same dialog
+ [\#5713](https://github.com/matrix-org/matrix-react-sdk/pull/5713)
+ * Fix units of TURN server expiry time
+ [\#5730](https://github.com/matrix-org/matrix-react-sdk/pull/5730)
+ * Display room name in pills instead of address
+ [\#5624](https://github.com/matrix-org/matrix-react-sdk/pull/5624)
+ * Refresh UI for file uploads
+ [\#5723](https://github.com/matrix-org/matrix-react-sdk/pull/5723)
+ * UI refresh for uploaded files
+ [\#5719](https://github.com/matrix-org/matrix-react-sdk/pull/5719)
+ * Improve message sending states to match new designs
+ [\#5699](https://github.com/matrix-org/matrix-react-sdk/pull/5699)
+ * Add clipboard write permission for widgets
+ [\#5725](https://github.com/matrix-org/matrix-react-sdk/pull/5725)
+ * Fix widget resizing
+ [\#5722](https://github.com/matrix-org/matrix-react-sdk/pull/5722)
+ * Option for audio streaming
+ [\#5707](https://github.com/matrix-org/matrix-react-sdk/pull/5707)
+ * Show a specific error for hs_disabled
+ [\#5576](https://github.com/matrix-org/matrix-react-sdk/pull/5576)
+ * Add Edge to the targets list
+ [\#5721](https://github.com/matrix-org/matrix-react-sdk/pull/5721)
+ * File drop UI fixes and improvements
+ [\#5505](https://github.com/matrix-org/matrix-react-sdk/pull/5505)
+ * Fix Bottom border of state counters is white on the dark theme
+ [\#5715](https://github.com/matrix-org/matrix-react-sdk/pull/5715)
+ * Trim spurious whitespace of nicknames
+ [\#5332](https://github.com/matrix-org/matrix-react-sdk/pull/5332)
+ * Ensure HostSignupDialog border colour matches light theme
+ [\#5716](https://github.com/matrix-org/matrix-react-sdk/pull/5716)
+ * Don't place another call if there's already one ongoing
+ [\#5712](https://github.com/matrix-org/matrix-react-sdk/pull/5712)
+ * Space room hierarchies
+ [\#5706](https://github.com/matrix-org/matrix-react-sdk/pull/5706)
+ * Iterate Space view and right panel
+ [\#5705](https://github.com/matrix-org/matrix-react-sdk/pull/5705)
+ * Add a scroll to bottom on message sent setting
+ [\#5692](https://github.com/matrix-org/matrix-react-sdk/pull/5692)
+ * Add .tmp files to gitignore
+ [\#5708](https://github.com/matrix-org/matrix-react-sdk/pull/5708)
+ * Initial Space Room View and Creation UX
+ [\#5704](https://github.com/matrix-org/matrix-react-sdk/pull/5704)
+ * Add multi language spell check
+ [\#5452](https://github.com/matrix-org/matrix-react-sdk/pull/5452)
+ * Fix tetris effect (holes) in read receipts
+ [\#5697](https://github.com/matrix-org/matrix-react-sdk/pull/5697)
+ * Fixed edit for markdown images
+ [\#5703](https://github.com/matrix-org/matrix-react-sdk/pull/5703)
+ * Iterate Space Panel
+ [\#5702](https://github.com/matrix-org/matrix-react-sdk/pull/5702)
+ * Fix read receipts for compact layout
+ [\#5700](https://github.com/matrix-org/matrix-react-sdk/pull/5700)
+ * Space Store and Space Panel for Room List filtering
+ [\#5689](https://github.com/matrix-org/matrix-react-sdk/pull/5689)
+ * Log when turn creds expire
+ [\#5691](https://github.com/matrix-org/matrix-react-sdk/pull/5691)
+ * Null check for maxHeight in call view
+ [\#5690](https://github.com/matrix-org/matrix-react-sdk/pull/5690)
+ * Autocomplete invited users
+ [\#5687](https://github.com/matrix-org/matrix-react-sdk/pull/5687)
+ * Add send message button
+ [\#5535](https://github.com/matrix-org/matrix-react-sdk/pull/5535)
+ * Move call buttons to the room header
+ [\#5693](https://github.com/matrix-org/matrix-react-sdk/pull/5693)
+ * Use the default SSSS key if the default is set
+ [\#5638](https://github.com/matrix-org/matrix-react-sdk/pull/5638)
+ * Initial Spaces feature flag
+ [\#5668](https://github.com/matrix-org/matrix-react-sdk/pull/5668)
+ * Clean up code edge cases and add helpers
+ [\#5667](https://github.com/matrix-org/matrix-react-sdk/pull/5667)
+ * Clean up widgets when leaving the room
+ [\#5684](https://github.com/matrix-org/matrix-react-sdk/pull/5684)
+ * Fix read receipts?
+ [\#5567](https://github.com/matrix-org/matrix-react-sdk/pull/5567)
+ * Fix MAU usage alerts
+ [\#5678](https://github.com/matrix-org/matrix-react-sdk/pull/5678)
+
+Changes in [3.15.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.15.0) (2021-03-01)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.15.0-rc.1...v3.15.0)
+
+## Security notice
+
+matrix-react-sdk 3.15.0 fixes a moderate severity issue (CVE-2021-21320) where
+the user content sandbox can be abused to trick users into opening unexpected
+documents after several user interactions. The content can be opened with a
+`blob` origin from the Matrix client, so it is possible for a malicious document
+to access user messages and secrets. Thanks to @keerok for responsibly
+disclosing this via Matrix's Security Disclosure Policy.
+
+## All changes
+
+ * Upgrade to JS SDK 9.8.0
+
+Changes in [3.15.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.15.0-rc.1) (2021-02-24)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.14.0...v3.15.0-rc.1)
+
+ * Upgrade to JS SDK 9.8.0-rc.1
+ * Translations update from Weblate
+ [\#5683](https://github.com/matrix-org/matrix-react-sdk/pull/5683)
+ * Fix object diffing when objects have different keys
+ [\#5681](https://github.com/matrix-org/matrix-react-sdk/pull/5681)
+ * Add if it's missing
+ [\#5673](https://github.com/matrix-org/matrix-react-sdk/pull/5673)
+ * Add email only if the verification is complete
+ [\#5629](https://github.com/matrix-org/matrix-react-sdk/pull/5629)
+ * Fix portrait videocalls
+ [\#5676](https://github.com/matrix-org/matrix-react-sdk/pull/5676)
+ * Tweak code block icon positions
+ [\#5643](https://github.com/matrix-org/matrix-react-sdk/pull/5643)
+ * Revert "Improve URL preview formatting and image upload thumbnail size"
+ [\#5677](https://github.com/matrix-org/matrix-react-sdk/pull/5677)
+ * Fix context menu leaving visible area
+ [\#5644](https://github.com/matrix-org/matrix-react-sdk/pull/5644)
+ * Jitsi conferences names, take 3
+ [\#5675](https://github.com/matrix-org/matrix-react-sdk/pull/5675)
+ * Update isUserOnDarkTheme to take use_system_theme in account
+ [\#5670](https://github.com/matrix-org/matrix-react-sdk/pull/5670)
+ * Discard some dead code
+ [\#5665](https://github.com/matrix-org/matrix-react-sdk/pull/5665)
+ * Add developer tool to explore and edit settings
+ [\#5664](https://github.com/matrix-org/matrix-react-sdk/pull/5664)
+ * Use and create new room helpers
+ [\#5663](https://github.com/matrix-org/matrix-react-sdk/pull/5663)
+ * Clear message previews when the maximum limit is reached for history
+ [\#5661](https://github.com/matrix-org/matrix-react-sdk/pull/5661)
+ * VoIP virtual rooms, mk II
+ [\#5639](https://github.com/matrix-org/matrix-react-sdk/pull/5639)
+ * Disable chat effects when reduced motion preferred
+ [\#5660](https://github.com/matrix-org/matrix-react-sdk/pull/5660)
+ * Improve URL preview formatting and image upload thumbnail size
+ [\#5637](https://github.com/matrix-org/matrix-react-sdk/pull/5637)
+ * Fix border radius when the panel is collapsed
+ [\#5641](https://github.com/matrix-org/matrix-react-sdk/pull/5641)
+ * Use a more generic layout setting - useIRCLayout → layout
+ [\#5571](https://github.com/matrix-org/matrix-react-sdk/pull/5571)
+ * Remove redundant lockOrigin parameter from usercontent
+ [\#5657](https://github.com/matrix-org/matrix-react-sdk/pull/5657)
+ * Set ICE candidate pool size option
+ [\#5655](https://github.com/matrix-org/matrix-react-sdk/pull/5655)
+ * Prepare to encrypt when a call arrives
+ [\#5654](https://github.com/matrix-org/matrix-react-sdk/pull/5654)
+ * Use config for host signup branding
+ [\#5650](https://github.com/matrix-org/matrix-react-sdk/pull/5650)
+ * Use randomly generated conference names for Jitsi
+ [\#5649](https://github.com/matrix-org/matrix-react-sdk/pull/5649)
+ * Modified regex to account for an immediate new line after slash commands
+ [\#5647](https://github.com/matrix-org/matrix-react-sdk/pull/5647)
+ * Fix codeblock scrollbar color for non-Firefox
+ [\#5642](https://github.com/matrix-org/matrix-react-sdk/pull/5642)
+ * Fix codeblock scrollbar colors
+ [\#5630](https://github.com/matrix-org/matrix-react-sdk/pull/5630)
+ * Added loading and disabled the button while searching for server
+ [\#5634](https://github.com/matrix-org/matrix-react-sdk/pull/5634)
+
+Changes in [3.14.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.14.0) (2021-02-16)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.14.0-rc.1...v3.14.0)
+
+ * Upgrade to JS SDK 9.7.0
+ * [Release] Use config for host signup branding
+ [\#5651](https://github.com/matrix-org/matrix-react-sdk/pull/5651)
+
+Changes in [3.14.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.14.0-rc.1) (2021-02-10)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.13.1...v3.14.0-rc.1)
+
+ * Upgrade to JS SDK 9.7.0-rc.1
+ * Translations update from Weblate
+ [\#5636](https://github.com/matrix-org/matrix-react-sdk/pull/5636)
+ * Add host signup modal with iframe
+ [\#5450](https://github.com/matrix-org/matrix-react-sdk/pull/5450)
+ * Fix duplication of codeblock elements
+ [\#5633](https://github.com/matrix-org/matrix-react-sdk/pull/5633)
+ * Handle undefined call stats
+ [\#5632](https://github.com/matrix-org/matrix-react-sdk/pull/5632)
+ * Avoid delayed displaying of sources in source picker
+ [\#5631](https://github.com/matrix-org/matrix-react-sdk/pull/5631)
+ * Give breadcrumbs toolbar an accessibility label.
+ [\#5628](https://github.com/matrix-org/matrix-react-sdk/pull/5628)
+ * Fix the %s in logs
+ [\#5627](https://github.com/matrix-org/matrix-react-sdk/pull/5627)
+ * Fix jumpy notifications settings UI
+ [\#5625](https://github.com/matrix-org/matrix-react-sdk/pull/5625)
+ * Improve displaying of code blocks
+ [\#5559](https://github.com/matrix-org/matrix-react-sdk/pull/5559)
+ * Fix desktop Matrix screen sharing and add a screen/window picker
+ [\#5525](https://github.com/matrix-org/matrix-react-sdk/pull/5525)
+ * Call "MatrixClientPeg.get()" only once in method "findOverrideMuteRule"
+ [\#5498](https://github.com/matrix-org/matrix-react-sdk/pull/5498)
+ * Close current modal when session is logged out
+ [\#5616](https://github.com/matrix-org/matrix-react-sdk/pull/5616)
+ * Switch room explorer list to CSS grid
+ [\#5551](https://github.com/matrix-org/matrix-react-sdk/pull/5551)
+ * Improve SSO login start screen and 3pid invite handling somewhat
+ [\#5622](https://github.com/matrix-org/matrix-react-sdk/pull/5622)
+ * Don't jump to bottom on reaction
+ [\#5621](https://github.com/matrix-org/matrix-react-sdk/pull/5621)
+ * Fix several profile settings oddities
+ [\#5620](https://github.com/matrix-org/matrix-react-sdk/pull/5620)
+ * Add option to hide the stickers button in the composer
+ [\#5530](https://github.com/matrix-org/matrix-react-sdk/pull/5530)
+ * Fix confusing right panel button behaviour
+ [\#5598](https://github.com/matrix-org/matrix-react-sdk/pull/5598)
+ * Fix jumping timestamp if hovering a message with e2e indicator bar
+ [\#5601](https://github.com/matrix-org/matrix-react-sdk/pull/5601)
+ * Fix avatar and trash alignment
+ [\#5614](https://github.com/matrix-org/matrix-react-sdk/pull/5614)
+ * Fix z-index of stickerpicker
+ [\#5617](https://github.com/matrix-org/matrix-react-sdk/pull/5617)
+ * Fix permalink via parsing for rooms
+ [\#5615](https://github.com/matrix-org/matrix-react-sdk/pull/5615)
+ * Fix "Terms and Conditions" checkbox alignment
+ [\#5613](https://github.com/matrix-org/matrix-react-sdk/pull/5613)
+ * Fix flair height after accent changes
+ [\#5611](https://github.com/matrix-org/matrix-react-sdk/pull/5611)
+ * Iterate Social Logins work around edge cases and branding
+ [\#5609](https://github.com/matrix-org/matrix-react-sdk/pull/5609)
+ * Lock widget room ID when added
+ [\#5607](https://github.com/matrix-org/matrix-react-sdk/pull/5607)
+ * Better errors for SSO failures
+ [\#5605](https://github.com/matrix-org/matrix-react-sdk/pull/5605)
+ * Increase language search bar width
+ [\#5549](https://github.com/matrix-org/matrix-react-sdk/pull/5549)
+ * Scroll to bottom on message_sent
+ [\#5565](https://github.com/matrix-org/matrix-react-sdk/pull/5565)
+ * Fix new rooms being titled 'Empty Room'
+ [\#5587](https://github.com/matrix-org/matrix-react-sdk/pull/5587)
+ * Fix saving the collapsed state of the left panel
+ [\#5593](https://github.com/matrix-org/matrix-react-sdk/pull/5593)
+ * Fix app-url hint in the e2e-test run script output
+ [\#5600](https://github.com/matrix-org/matrix-react-sdk/pull/5600)
+ * Fix RoomView re-mounting breaking peeking
+ [\#5602](https://github.com/matrix-org/matrix-react-sdk/pull/5602)
+ * Tweak a few room ID checks
+ [\#5592](https://github.com/matrix-org/matrix-react-sdk/pull/5592)
+ * Remove pills from event permalinks with text
+ [\#5575](https://github.com/matrix-org/matrix-react-sdk/pull/5575)
+
+Changes in [3.13.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.13.1) (2021-02-04)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.13.0...v3.13.1)
+
+ * [Release] Fix z-index of stickerpicker
+ [\#5618](https://github.com/matrix-org/matrix-react-sdk/pull/5618)
+
+Changes in [3.13.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.13.0) (2021-02-03)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.13.0-rc.1...v3.13.0)
+
+ * Upgrade to JS SDK 9.6.0
+ * [Release] Fix flair height after accent changes
+ [\#5612](https://github.com/matrix-org/matrix-react-sdk/pull/5612)
+ * [Release] Iterate Social Logins work around edge cases and branding
+ [\#5610](https://github.com/matrix-org/matrix-react-sdk/pull/5610)
+ * [Release] Lock widget room ID when added
+ [\#5608](https://github.com/matrix-org/matrix-react-sdk/pull/5608)
+ * [Release] Better errors for SSO failures
+ [\#5606](https://github.com/matrix-org/matrix-react-sdk/pull/5606)
+ * [Release] Fix RoomView re-mounting breaking peeking
+ [\#5603](https://github.com/matrix-org/matrix-react-sdk/pull/5603)
+
+Changes in [3.13.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.13.0-rc.1) (2021-01-29)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.12.1...v3.13.0-rc.1)
+
+ * Upgrade to JS SDK 9.6.0-rc.1
+ * Translations update from Weblate
+ [\#5597](https://github.com/matrix-org/matrix-react-sdk/pull/5597)
+ * Support managed hybrid widgets from config
+ [\#5596](https://github.com/matrix-org/matrix-react-sdk/pull/5596)
+ * Add managed hybrid call widgets when supported
+ [\#5594](https://github.com/matrix-org/matrix-react-sdk/pull/5594)
+ * Tweak mobile guide toast copy
+ [\#5595](https://github.com/matrix-org/matrix-react-sdk/pull/5595)
+ * Improve SSO auth flow
+ [\#5578](https://github.com/matrix-org/matrix-react-sdk/pull/5578)
+ * Add optional mobile guide toast
+ [\#5586](https://github.com/matrix-org/matrix-react-sdk/pull/5586)
+ * Fix invisible text after logging out in the dark theme
+ [\#5588](https://github.com/matrix-org/matrix-react-sdk/pull/5588)
+ * Fix escape for cancelling replies
+ [\#5591](https://github.com/matrix-org/matrix-react-sdk/pull/5591)
+ * Update widget-api to beta.12
+ [\#5589](https://github.com/matrix-org/matrix-react-sdk/pull/5589)
+ * Add commands for DM conversion
+ [\#5540](https://github.com/matrix-org/matrix-react-sdk/pull/5540)
+ * Run a UI refresh over the OIDC Exchange confirmation dialog
+ [\#5580](https://github.com/matrix-org/matrix-react-sdk/pull/5580)
+ * Allow stickerpickers the legacy "visibility" capability
+ [\#5581](https://github.com/matrix-org/matrix-react-sdk/pull/5581)
+ * Hide local video if it is muted
+ [\#5529](https://github.com/matrix-org/matrix-react-sdk/pull/5529)
+ * Don't use name width in reply thread for IRC layout
+ [\#5518](https://github.com/matrix-org/matrix-react-sdk/pull/5518)
+ * Update code_style.md
+ [\#5554](https://github.com/matrix-org/matrix-react-sdk/pull/5554)
+ * Fix Czech capital letters like ŠČŘ...
+ [\#5569](https://github.com/matrix-org/matrix-react-sdk/pull/5569)
+ * Add optional search shortcut
+ [\#5548](https://github.com/matrix-org/matrix-react-sdk/pull/5548)
+ * Fix Sudden 'find a room' UI shows up when the only room moves to favourites
+ [\#5584](https://github.com/matrix-org/matrix-react-sdk/pull/5584)
+ * Increase PersistedElement's z-index
+ [\#5568](https://github.com/matrix-org/matrix-react-sdk/pull/5568)
+ * Remove check that prevents Jitsi widgets from being unpinned
+ [\#5582](https://github.com/matrix-org/matrix-react-sdk/pull/5582)
+ * Fix Jitsi widgets causing localized tile crashes
+ [\#5583](https://github.com/matrix-org/matrix-react-sdk/pull/5583)
+ * Log candidates for calls
+ [\#5573](https://github.com/matrix-org/matrix-react-sdk/pull/5573)
+ * Upgrade deps 2021-01
+ [\#5579](https://github.com/matrix-org/matrix-react-sdk/pull/5579)
+ * Fix "Continuing without email" dialog bug
+ [\#5566](https://github.com/matrix-org/matrix-react-sdk/pull/5566)
+ * Require registration for verification actions
+ [\#5574](https://github.com/matrix-org/matrix-react-sdk/pull/5574)
+ * Don't play the hangup sound when the call is answered from elsewhere
+ [\#5572](https://github.com/matrix-org/matrix-react-sdk/pull/5572)
+ * Move to newer base image for end-to-end tests
+ [\#5570](https://github.com/matrix-org/matrix-react-sdk/pull/5570)
+ * Update widgets in the room upon join
+ [\#5564](https://github.com/matrix-org/matrix-react-sdk/pull/5564)
+ * Update AuxPanel and related buttons when widgets change or on reload
+ [\#5563](https://github.com/matrix-org/matrix-react-sdk/pull/5563)
+ * Add VoIP user mapper
+ [\#5560](https://github.com/matrix-org/matrix-react-sdk/pull/5560)
+ * Improve styling of SSO Buttons for multiple IdPs
+ [\#5558](https://github.com/matrix-org/matrix-react-sdk/pull/5558)
+ * Fixes for the general tab in the room dialog
+ [\#5522](https://github.com/matrix-org/matrix-react-sdk/pull/5522)
+ * fix issue 16226 to allow switching back to default HS.
+ [\#5561](https://github.com/matrix-org/matrix-react-sdk/pull/5561)
+ * Support room-defined widget layouts
+ [\#5553](https://github.com/matrix-org/matrix-react-sdk/pull/5553)
+ * Change a bunch of strings from Recovery Key/Phrase to Security Key/Phrase
+ [\#5533](https://github.com/matrix-org/matrix-react-sdk/pull/5533)
+ * Give a bigger target area to AppsDrawer vertical resizer
+ [\#5557](https://github.com/matrix-org/matrix-react-sdk/pull/5557)
+ * Fix minimized left panel avatar alignment
+ [\#5493](https://github.com/matrix-org/matrix-react-sdk/pull/5493)
+ * Ensure component index has been written before renaming
+ [\#5556](https://github.com/matrix-org/matrix-react-sdk/pull/5556)
+ * Fixed continue button while selecting home-server
+ [\#5552](https://github.com/matrix-org/matrix-react-sdk/pull/5552)
+ * Wire up MSC2931 widget navigation
+ [\#5527](https://github.com/matrix-org/matrix-react-sdk/pull/5527)
+ * Various fixes for Bridge Info page (MSC2346)
+ [\#5454](https://github.com/matrix-org/matrix-react-sdk/pull/5454)
+ * Use room-specific listeners for message preview and community prototype
+ [\#5547](https://github.com/matrix-org/matrix-react-sdk/pull/5547)
+ * Fix some misc. React warnings when viewing timeline
+ [\#5546](https://github.com/matrix-org/matrix-react-sdk/pull/5546)
+ * Use device storage for allowed widgets if account data not supported
+ [\#5544](https://github.com/matrix-org/matrix-react-sdk/pull/5544)
+ * Fix incoming call box on dark theme
+ [\#5542](https://github.com/matrix-org/matrix-react-sdk/pull/5542)
+ * Convert DMRoomMap to typescript
+ [\#5541](https://github.com/matrix-org/matrix-react-sdk/pull/5541)
+ * Add in-call dialpad for DTMF sending
+ [\#5532](https://github.com/matrix-org/matrix-react-sdk/pull/5532)
+
+Changes in [3.12.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.12.1) (2021-01-26)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.12.0...v3.12.1)
+
+ * Upgrade to JS SDK 9.5.1
+
+Changes in [3.12.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.12.0) (2021-01-18)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.12.0-rc.1...v3.12.0)
+
+ * Upgrade to JS SDK 9.5.0
+ * Fix incoming call box on dark theme
+ [\#5543](https://github.com/matrix-org/matrix-react-sdk/pull/5543)
+
+Changes in [3.12.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.12.0-rc.1) (2021-01-13)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.11.1...v3.12.0-rc.1)
+
+ * Upgrade to JS SDK 9.5.0-rc.1
+ * Fix soft crash on soft logout page
+ [\#5539](https://github.com/matrix-org/matrix-react-sdk/pull/5539)
+ * Translations update from Weblate
+ [\#5538](https://github.com/matrix-org/matrix-react-sdk/pull/5538)
+ * Run TypeScript tests
+ [\#5537](https://github.com/matrix-org/matrix-react-sdk/pull/5537)
+ * Add a basic widget explorer to devtools (per-room)
+ [\#5528](https://github.com/matrix-org/matrix-react-sdk/pull/5528)
+ * Add to security key field
+ [\#5534](https://github.com/matrix-org/matrix-react-sdk/pull/5534)
+ * Fix avatar upload prompt/tooltip floating wrong and permissions
+ [\#5526](https://github.com/matrix-org/matrix-react-sdk/pull/5526)
+ * Add a dialpad UI for PSTN lookup
+ [\#5523](https://github.com/matrix-org/matrix-react-sdk/pull/5523)
+ * Basic call transfer initiation support
+ [\#5494](https://github.com/matrix-org/matrix-react-sdk/pull/5494)
+ * Fix #15988
+ [\#5524](https://github.com/matrix-org/matrix-react-sdk/pull/5524)
+ * Bump node-notifier from 8.0.0 to 8.0.1
+ [\#5520](https://github.com/matrix-org/matrix-react-sdk/pull/5520)
+ * Use TypeScript source for development, swap to build during release
+ [\#5503](https://github.com/matrix-org/matrix-react-sdk/pull/5503)
+ * Look for emoji in the body that will be displayed
+ [\#5517](https://github.com/matrix-org/matrix-react-sdk/pull/5517)
+ * Bump ini from 1.3.5 to 1.3.7
+ [\#5486](https://github.com/matrix-org/matrix-react-sdk/pull/5486)
+ * Recognise `*.element.io` links as Element permalinks
+ [\#5514](https://github.com/matrix-org/matrix-react-sdk/pull/5514)
+ * Fixes for call UI
+ [\#5509](https://github.com/matrix-org/matrix-react-sdk/pull/5509)
+ * Add a snowfall chat effect (with /snowfall command)
+ [\#5511](https://github.com/matrix-org/matrix-react-sdk/pull/5511)
+ * fireworks effect
+ [\#5507](https://github.com/matrix-org/matrix-react-sdk/pull/5507)
+ * Don't play call end sound for calls that never started
+ [\#5506](https://github.com/matrix-org/matrix-react-sdk/pull/5506)
+ * Add /tableflip slash command
+ [\#5485](https://github.com/matrix-org/matrix-react-sdk/pull/5485)
+ * Import from src in IncomingCallBox.tsx
+ [\#5504](https://github.com/matrix-org/matrix-react-sdk/pull/5504)
+ * Social Login support both https and mxc icons
+ [\#5499](https://github.com/matrix-org/matrix-react-sdk/pull/5499)
+ * Fix padding in confirmation email registration prompt
+ [\#5501](https://github.com/matrix-org/matrix-react-sdk/pull/5501)
+ * Fix room list help prompt alignment
+ [\#5500](https://github.com/matrix-org/matrix-react-sdk/pull/5500)
+
+Changes in [3.11.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.11.1) (2020-12-21)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.11.0...v3.11.1)
+
+ * Upgrade JS SDK to 9.4.1
+
+Changes in [3.11.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.11.0) (2020-12-21)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.11.0-rc.2...v3.11.0)
+
+ * Upgrade JS SDK to 9.4.0
+ * [Release] Look for emoji in the body that will be displayed
+ [\#5519](https://github.com/matrix-org/matrix-react-sdk/pull/5519)
+ * [Release] Recognise `*.element.io` links as Element permalinks
+ [\#5516](https://github.com/matrix-org/matrix-react-sdk/pull/5516)
+ * [Release] Fixes for call UI
+ [\#5513](https://github.com/matrix-org/matrix-react-sdk/pull/5513)
+ * [RELEASE] Add a snowfall chat effect (with /snowfall command)
+ [\#5512](https://github.com/matrix-org/matrix-react-sdk/pull/5512)
+ * [Release] Fix padding in confirmation email registration prompt
+ [\#5502](https://github.com/matrix-org/matrix-react-sdk/pull/5502)
+
+Changes in [3.11.0-rc.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.11.0-rc.2) (2020-12-16)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.11.0-rc.1...v3.11.0-rc.2)
+
+ * Upgrade JS SDK to 9.4.0-rc.2
+
+Changes in [3.11.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.11.0-rc.1) (2020-12-16)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.10.0...v3.11.0-rc.1)
+
+ * Upgrade JS SDK to 9.4.0-rc.1
+ * Translations update from Weblate
+ [\#5497](https://github.com/matrix-org/matrix-react-sdk/pull/5497)
+ * Unregister from the dispatcher in CallHandler
+ [\#5495](https://github.com/matrix-org/matrix-react-sdk/pull/5495)
+ * Better adhere to MSC process
+ [\#5496](https://github.com/matrix-org/matrix-react-sdk/pull/5496)
+ * Use random pickle key on all platforms
+ [\#5483](https://github.com/matrix-org/matrix-react-sdk/pull/5483)
+ * Fix mx_MemberList icons
+ [\#5492](https://github.com/matrix-org/matrix-react-sdk/pull/5492)
+ * Convert InviteDialog to TypeScript
+ [\#5491](https://github.com/matrix-org/matrix-react-sdk/pull/5491)
+ * Add keyboard shortcut for emoji reactions
+ [\#5425](https://github.com/matrix-org/matrix-react-sdk/pull/5425)
+ * Run chat effects on events sent by widgets too
+ [\#5488](https://github.com/matrix-org/matrix-react-sdk/pull/5488)
+ * Fix being unable to pin widgets
+ [\#5487](https://github.com/matrix-org/matrix-react-sdk/pull/5487)
+ * Line 1 / 2 Support
+ [\#5468](https://github.com/matrix-org/matrix-react-sdk/pull/5468)
+ * Remove impossible labs feature: sending hidden read receipts
+ [\#5484](https://github.com/matrix-org/matrix-react-sdk/pull/5484)
+ * Fix height of Remote Video in call
+ [\#5456](https://github.com/matrix-org/matrix-react-sdk/pull/5456)
+ * Add UI for hold functionality
+ [\#5446](https://github.com/matrix-org/matrix-react-sdk/pull/5446)
+ * Allow SearchBox to expand to fill width
+ [\#5411](https://github.com/matrix-org/matrix-react-sdk/pull/5411)
+ * Use room alias in generated permalink for rooms
+ [\#5451](https://github.com/matrix-org/matrix-react-sdk/pull/5451)
+ * Only show confetti if the current room is receiving an appropriate event
+ [\#5482](https://github.com/matrix-org/matrix-react-sdk/pull/5482)
+ * Throttle RoomState.members handler to improve performance
+ [\#5481](https://github.com/matrix-org/matrix-react-sdk/pull/5481)
+ * Handle manual hs urls better for the server picker
+ [\#5477](https://github.com/matrix-org/matrix-react-sdk/pull/5477)
+ * Add Olm as a dev dependency for types
+ [\#5479](https://github.com/matrix-org/matrix-react-sdk/pull/5479)
+ * Hide Invite to this room CTA if no permission
+ [\#5476](https://github.com/matrix-org/matrix-react-sdk/pull/5476)
+ * Fix width of underline in server picker dialog
+ [\#5478](https://github.com/matrix-org/matrix-react-sdk/pull/5478)
+ * Fix confetti room unread state check
+ [\#5475](https://github.com/matrix-org/matrix-react-sdk/pull/5475)
+ * Show confetti in a chat room on command or emoji
+ [\#5140](https://github.com/matrix-org/matrix-react-sdk/pull/5140)
+ * Fix inverted settings default value
+ [\#5391](https://github.com/matrix-org/matrix-react-sdk/pull/5391)
+ * Improve usability of the Server Picker Dialog
+ [\#5474](https://github.com/matrix-org/matrix-react-sdk/pull/5474)
+ * Fix typos in some strings
+ [\#5473](https://github.com/matrix-org/matrix-react-sdk/pull/5473)
+ * Bump highlight.js from 10.1.2 to 10.4.1
+ [\#5472](https://github.com/matrix-org/matrix-react-sdk/pull/5472)
+ * Remove old app test script path
+ [\#5471](https://github.com/matrix-org/matrix-react-sdk/pull/5471)
+ * add support for giving reason when redacting
+ [\#5260](https://github.com/matrix-org/matrix-react-sdk/pull/5260)
+ * Add support for Netlify to fetchdep script
+ [\#5469](https://github.com/matrix-org/matrix-react-sdk/pull/5469)
+ * Nest other layers inside on automation
+ [\#5467](https://github.com/matrix-org/matrix-react-sdk/pull/5467)
+ * Rebrand various CI scripts and modules
+ [\#5466](https://github.com/matrix-org/matrix-react-sdk/pull/5466)
+ * Add more widget sanity checking
+ [\#5462](https://github.com/matrix-org/matrix-react-sdk/pull/5462)
+ * Fix React complaining about unknown DOM props
+ [\#5465](https://github.com/matrix-org/matrix-react-sdk/pull/5465)
+ * Jump to home page when leaving a room
+ [\#5464](https://github.com/matrix-org/matrix-react-sdk/pull/5464)
+ * Fix SSO buttons for Social Logins
+ [\#5463](https://github.com/matrix-org/matrix-react-sdk/pull/5463)
+ * Social Login and login delight tweaks
+ [\#5426](https://github.com/matrix-org/matrix-react-sdk/pull/5426)
+
+Changes in [3.10.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.10.0) (2020-12-07)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.10.0-rc.1...v3.10.0)
+
+ * Upgrade to JS SDK 9.3.0
+
+Changes in [3.10.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.10.0-rc.1) (2020-12-02)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.9.0...v3.10.0-rc.1)
+
+ * Upgrade to JS SDK 9.3.0-rc.1
+ * Translations update from Weblate
+ [\#5461](https://github.com/matrix-org/matrix-react-sdk/pull/5461)
+ * Fix VoIP call plinth on dark theme
+ [\#5460](https://github.com/matrix-org/matrix-react-sdk/pull/5460)
+ * Add sanity checking around widget pinning
+ [\#5459](https://github.com/matrix-org/matrix-react-sdk/pull/5459)
+ * Update i18n for Appearance User Settings
+ [\#5457](https://github.com/matrix-org/matrix-react-sdk/pull/5457)
+ * Only show 'answered elsewhere' if we tried to answer too
+ [\#5455](https://github.com/matrix-org/matrix-react-sdk/pull/5455)
+ * Fixed Avatar for 3PID invites
+ [\#5442](https://github.com/matrix-org/matrix-react-sdk/pull/5442)
+ * Slightly better error if we can't capture user media
+ [\#5449](https://github.com/matrix-org/matrix-react-sdk/pull/5449)
+ * Make it possible in-code to hide rooms from the room list
+ [\#5445](https://github.com/matrix-org/matrix-react-sdk/pull/5445)
+ * Fix the stickerpicker
+ [\#5447](https://github.com/matrix-org/matrix-react-sdk/pull/5447)
+ * Add live password validation to change password dialog
+ [\#5436](https://github.com/matrix-org/matrix-react-sdk/pull/5436)
+ * LaTeX rendering in element-web using KaTeX
+ [\#5244](https://github.com/matrix-org/matrix-react-sdk/pull/5244)
+ * Add lifecycle customisation point after logout
+ [\#5448](https://github.com/matrix-org/matrix-react-sdk/pull/5448)
+ * Simplify UserMenu for Guests as they can't use most of the options
+ [\#5421](https://github.com/matrix-org/matrix-react-sdk/pull/5421)
+ * Fix known issues with modal widgets
+ [\#5444](https://github.com/matrix-org/matrix-react-sdk/pull/5444)
+ * Fix existing widgets not having approved capabilities for their function
+ [\#5443](https://github.com/matrix-org/matrix-react-sdk/pull/5443)
+ * Use the WidgetDriver to run OIDC requests
+ [\#5440](https://github.com/matrix-org/matrix-react-sdk/pull/5440)
+ * Add a customisation point for widget permissions and fix amnesia issues
+ [\#5439](https://github.com/matrix-org/matrix-react-sdk/pull/5439)
+ * Fix Widget event notification text including spurious space
+ [\#5441](https://github.com/matrix-org/matrix-react-sdk/pull/5441)
+ * Move call listener out of MatrixChat
+ [\#5438](https://github.com/matrix-org/matrix-react-sdk/pull/5438)
+ * New Look in-Call View
+ [\#5432](https://github.com/matrix-org/matrix-react-sdk/pull/5432)
+ * Support arbitrary widgets sticking to the screen + sending stickers
+ [\#5435](https://github.com/matrix-org/matrix-react-sdk/pull/5435)
+ * Auth typescripting and validation tweaks
+ [\#5433](https://github.com/matrix-org/matrix-react-sdk/pull/5433)
+ * Add new widget API actions for changing rooms and sending/receiving events
+ [\#5385](https://github.com/matrix-org/matrix-react-sdk/pull/5385)
+ * Revert room header click behaviour to opening room settings
+ [\#5434](https://github.com/matrix-org/matrix-react-sdk/pull/5434)
+ * Add option to send/edit a message with Ctrl + Enter / Command + Enter
+ [\#5160](https://github.com/matrix-org/matrix-react-sdk/pull/5160)
+ * Add Analytics instrumentation to the Homepage
+ [\#5409](https://github.com/matrix-org/matrix-react-sdk/pull/5409)
+ * Fix encrypted video playback in Chrome-based browsers
+ [\#5430](https://github.com/matrix-org/matrix-react-sdk/pull/5430)
+ * Add border-radius for video
+ [\#5333](https://github.com/matrix-org/matrix-react-sdk/pull/5333)
+ * Push name to the end, near text, in IRC layout
+ [\#5166](https://github.com/matrix-org/matrix-react-sdk/pull/5166)
+ * Disable notifications for the room you have recently been active in
+ [\#5325](https://github.com/matrix-org/matrix-react-sdk/pull/5325)
+ * Search through the list of unfiltered rooms rather than the rooms in the
+ state which are already filtered by the search text
+ [\#5331](https://github.com/matrix-org/matrix-react-sdk/pull/5331)
+ * Lighten blockquote colour in dark mode
+ [\#5353](https://github.com/matrix-org/matrix-react-sdk/pull/5353)
+ * Specify community description img must be mxc urls
+ [\#5364](https://github.com/matrix-org/matrix-react-sdk/pull/5364)
+ * Add keyboard shortcut to close the current conversation
+ [\#5253](https://github.com/matrix-org/matrix-react-sdk/pull/5253)
+ * Redirect user home from auth screens if they are already logged in
+ [\#5423](https://github.com/matrix-org/matrix-react-sdk/pull/5423)
+
+Changes in [3.9.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.9.0) (2020-11-23)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.9.0-rc.1...v3.9.0)
+
+ * Upgrade JS SDK to 9.2.0
+ * [Release] Fix encrypted video playback in Chrome-based browsers
+ [\#5431](https://github.com/matrix-org/matrix-react-sdk/pull/5431)
+
+Changes in [3.9.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.9.0-rc.1) (2020-11-18)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.8.0...v3.9.0-rc.1)
+
+ * Upgrade JS SDK to 9.2.0-rc.1
+ * Translations update from Weblate
+ [\#5429](https://github.com/matrix-org/matrix-react-sdk/pull/5429)
+ * Fix message search summary text
+ [\#5428](https://github.com/matrix-org/matrix-react-sdk/pull/5428)
+ * Shrink new room intro top margin to half for encryption bubble tile
+ [\#5427](https://github.com/matrix-org/matrix-react-sdk/pull/5427)
+ * Small delight tweaks to improve rough corners in the app
+ [\#5418](https://github.com/matrix-org/matrix-react-sdk/pull/5418)
+ * Fix DM logic to always pick a more reliable DM room
+ [\#5424](https://github.com/matrix-org/matrix-react-sdk/pull/5424)
+ * Update styling of the Analytics toast
+ [\#5408](https://github.com/matrix-org/matrix-react-sdk/pull/5408)
+ * Fix vertical centering of the Homepage and button layout
+ [\#5420](https://github.com/matrix-org/matrix-react-sdk/pull/5420)
+ * Fix BaseAvatar sometimes messing up and duplicating the url
+ [\#5422](https://github.com/matrix-org/matrix-react-sdk/pull/5422)
+ * Disable buttons when required by MSC2790
+ [\#5412](https://github.com/matrix-org/matrix-react-sdk/pull/5412)
+ * Fix drag drop file to upload for Safari
+ [\#5414](https://github.com/matrix-org/matrix-react-sdk/pull/5414)
+ * Fix poorly i18n'd string
+ [\#5416](https://github.com/matrix-org/matrix-react-sdk/pull/5416)
+ * Fix the feedback not closing without feedback/countly
+ [\#5417](https://github.com/matrix-org/matrix-react-sdk/pull/5417)
+ * Fix New Room Intro invite to this room button
+ [\#5419](https://github.com/matrix-org/matrix-react-sdk/pull/5419)
+ * Change how we expose Role in User Info and hide in DMs
+ [\#5413](https://github.com/matrix-org/matrix-react-sdk/pull/5413)
+ * Disallow sending of empty messages
+ [\#5390](https://github.com/matrix-org/matrix-react-sdk/pull/5390)
+ * hide some validation tooltips if fields are valid.
+ [\#5403](https://github.com/matrix-org/matrix-react-sdk/pull/5403)
+ * Improvements around new room empty space interactions
+ [\#5398](https://github.com/matrix-org/matrix-react-sdk/pull/5398)
+ * Implement call hold
+ [\#5366](https://github.com/matrix-org/matrix-react-sdk/pull/5366)
+ * Fix Skeleton UI showing up when not intended.
+ [\#5407](https://github.com/matrix-org/matrix-react-sdk/pull/5407)
+ * Close context menu when user clicks the Home button
+ [\#5406](https://github.com/matrix-org/matrix-react-sdk/pull/5406)
+ * Skip e2ee warn logout prompt if user has no megolm sessions to lose
+ [\#5410](https://github.com/matrix-org/matrix-react-sdk/pull/5410)
+ * Allow country names to be translated
+ [\#5405](https://github.com/matrix-org/matrix-react-sdk/pull/5405)
+ * Support thirdparty lookup for phone numbers
+ [\#5396](https://github.com/matrix-org/matrix-react-sdk/pull/5396)
+ * Change "Password" to "New Password"
+ [\#5371](https://github.com/matrix-org/matrix-react-sdk/pull/5371)
+ * Add customisation point for dehydration key
+ [\#5397](https://github.com/matrix-org/matrix-react-sdk/pull/5397)
+ * Rebrand Riot -> Element in the permalink classes
+ [\#5386](https://github.com/matrix-org/matrix-react-sdk/pull/5386)
+ * Invite / Create DM UX tweaks
+ [\#5387](https://github.com/matrix-org/matrix-react-sdk/pull/5387)
+ * Tweaks to toasts and post-registration landing
+ [\#5383](https://github.com/matrix-org/matrix-react-sdk/pull/5383)
+
+Changes in [3.8.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.8.0) (2020-11-09)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.8.0-rc.1...v3.8.0)
+
+ * Upgrade JS SDK to 9.1.0
+
+Changes in [3.8.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.8.0-rc.1) (2020-11-04)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.7.1...v3.8.0-rc.1)
+
+ * Upgrade JS SDK to 9.1.0-rc.1
+ * Log when saving profile
+ [\#5394](https://github.com/matrix-org/matrix-react-sdk/pull/5394)
+ * Translations update from Weblate
+ [\#5395](https://github.com/matrix-org/matrix-react-sdk/pull/5395)
+ * Hide prompt to add email for notifications if 3pid ui feature is off
+ [\#5392](https://github.com/matrix-org/matrix-react-sdk/pull/5392)
+ * Fix room list message preview copy for hangup events
+ [\#5388](https://github.com/matrix-org/matrix-react-sdk/pull/5388)
+ * Track UISIs as Countly Events
+ [\#5382](https://github.com/matrix-org/matrix-react-sdk/pull/5382)
+ * Don't let users accidentally redact ACL events
+ [\#5384](https://github.com/matrix-org/matrix-react-sdk/pull/5384)
+ * Two more easy files to remove from eslintignore
+ [\#5378](https://github.com/matrix-org/matrix-react-sdk/pull/5378)
+ * Fix Widget OpenID Permissions for realsies
+ [\#5381](https://github.com/matrix-org/matrix-react-sdk/pull/5381)
+ * Fix regression with OpenID permissions on widgets
+ [\#5380](https://github.com/matrix-org/matrix-react-sdk/pull/5380)
+ * Fix room directory events happening in the wrong order for Funnels
+ [\#5379](https://github.com/matrix-org/matrix-react-sdk/pull/5379)
+ * Remove a couple more files from eslintignore
+ [\#5377](https://github.com/matrix-org/matrix-react-sdk/pull/5377)
+ * Fix countly method bindings and errors
+ [\#5376](https://github.com/matrix-org/matrix-react-sdk/pull/5376)
+ * Fix a bunch of silly lint errors
+ [\#5375](https://github.com/matrix-org/matrix-react-sdk/pull/5375)
+ * Typescript: ImageUtils
+ [\#5374](https://github.com/matrix-org/matrix-react-sdk/pull/5374)
+ * Convert AuxPanel to TypeScript
+ [\#5373](https://github.com/matrix-org/matrix-react-sdk/pull/5373)
+ * Only pass metrics if they exist otherwise Countly will be unhappy!
+ [\#5372](https://github.com/matrix-org/matrix-react-sdk/pull/5372)
+ * Fix CountlyAnalytics NPE on MatrixClientPeg
+ [\#5370](https://github.com/matrix-org/matrix-react-sdk/pull/5370)
+ * fix CountlyAnalytics canEnable on wrong target
+ [\#5369](https://github.com/matrix-org/matrix-react-sdk/pull/5369)
+ * Initial Countly work
+ [\#5365](https://github.com/matrix-org/matrix-react-sdk/pull/5365)
+ * Fix videos not playing in non-encrypted rooms
+ [\#5368](https://github.com/matrix-org/matrix-react-sdk/pull/5368)
+ * Fix custom tag layout which regressed in #5309
+ [\#5367](https://github.com/matrix-org/matrix-react-sdk/pull/5367)
+ * Watch replyToEvent at RoomView to prevent races
+ [\#5360](https://github.com/matrix-org/matrix-react-sdk/pull/5360)
+ * Add a UI Feature flag for room history settings
+ [\#5362](https://github.com/matrix-org/matrix-react-sdk/pull/5362)
+ * Hide inline images when preference disabled
+ [\#5361](https://github.com/matrix-org/matrix-react-sdk/pull/5361)
+ * Fix React warning by moving handler to each button
+ [\#5359](https://github.com/matrix-org/matrix-react-sdk/pull/5359)
+ * Do not preload encrypted videos|images unless autoplay or thumbnailing is on
+ [\#5352](https://github.com/matrix-org/matrix-react-sdk/pull/5352)
+ * Fix theme variable passed to Jitsi
+ [\#5357](https://github.com/matrix-org/matrix-react-sdk/pull/5357)
+ * docs: added comment explanation
+ [\#5349](https://github.com/matrix-org/matrix-react-sdk/pull/5349)
+ * Modal Widgets - MSC2790
+ [\#5252](https://github.com/matrix-org/matrix-react-sdk/pull/5252)
+ * Widgets fixes
+ [\#5350](https://github.com/matrix-org/matrix-react-sdk/pull/5350)
+ * Fix User Menu avatar colouring being based on wrong string
+ [\#5348](https://github.com/matrix-org/matrix-react-sdk/pull/5348)
+ * Support 'answered elsewhere'
+ [\#5345](https://github.com/matrix-org/matrix-react-sdk/pull/5345)
+
+Changes in [3.7.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.7.1) (2020-10-28)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.7.0...v3.7.1)
+
+ * Upgrade JS SDK to 9.0.1
+ * [Release] Fix theme variable passed to Jitsi
+ [\#5358](https://github.com/matrix-org/matrix-react-sdk/pull/5358)
+ * [Release] Widget fixes
+ [\#5351](https://github.com/matrix-org/matrix-react-sdk/pull/5351)
+
+Changes in [3.7.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.7.0) (2020-10-26)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.7.0-rc.2...v3.7.0)
+
+ * Upgrade JS SDK to 9.0.0
+
+Changes in [3.7.0-rc.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.7.0-rc.2) (2020-10-21)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.7.0-rc.1...v3.7.0-rc.2)
+
+ * Fix JS SDK dependency to use 9.0.0-rc.1 as intended
+
+Changes in [3.7.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.7.0-rc.1) (2020-10-21)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.6.1...v3.7.0-rc.1)
+
+ * Upgrade JS SDK to 9.0.0-rc.1
+ * Update Weblate URL
+ [\#5346](https://github.com/matrix-org/matrix-react-sdk/pull/5346)
+ * Translations update from Weblate
+ [\#5347](https://github.com/matrix-org/matrix-react-sdk/pull/5347)
+ * Left Panel Widget support
+ [\#5247](https://github.com/matrix-org/matrix-react-sdk/pull/5247)
+ * Pinned widgets work
+ [\#5266](https://github.com/matrix-org/matrix-react-sdk/pull/5266)
+ * Convert resizer to Typescript
+ [\#5343](https://github.com/matrix-org/matrix-react-sdk/pull/5343)
+ * Hide filtering microcopy when left panel is minimized
+ [\#5338](https://github.com/matrix-org/matrix-react-sdk/pull/5338)
+ * Skip editor confirmation of upgrades
+ [\#5344](https://github.com/matrix-org/matrix-react-sdk/pull/5344)
+ * Spec compliance, /search doesn't have to return results
+ [\#5337](https://github.com/matrix-org/matrix-react-sdk/pull/5337)
+ * Fix excessive hosting link padding
+ [\#5336](https://github.com/matrix-org/matrix-react-sdk/pull/5336)
+ * Adjust for new widget messaging APIs
+ [\#5341](https://github.com/matrix-org/matrix-react-sdk/pull/5341)
+ * Fix case where sublist context menu missed an update
+ [\#5339](https://github.com/matrix-org/matrix-react-sdk/pull/5339)
+ * Add analytics to VoIP
+ [\#5340](https://github.com/matrix-org/matrix-react-sdk/pull/5340)
+ * Fix Jitsi OpenIDC auth
+ [\#5334](https://github.com/matrix-org/matrix-react-sdk/pull/5334)
+ * Support rejecting calls
+ [\#5324](https://github.com/matrix-org/matrix-react-sdk/pull/5324)
+ * Don't show admin tooling if we're not in the room
+ [\#5330](https://github.com/matrix-org/matrix-react-sdk/pull/5330)
+ * Show Integrations error if iframe failed to load too
+ [\#5328](https://github.com/matrix-org/matrix-react-sdk/pull/5328)
+ * Add security customisation points
+ [\#5327](https://github.com/matrix-org/matrix-react-sdk/pull/5327)
+ * Discard all mx_fadable legacy cruft which is totally useless
+ [\#5326](https://github.com/matrix-org/matrix-react-sdk/pull/5326)
+ * Fix background-image: url(null) for backdrop filter
+ [\#5319](https://github.com/matrix-org/matrix-react-sdk/pull/5319)
+ * Make the ACL update message less noisy
+ [\#5316](https://github.com/matrix-org/matrix-react-sdk/pull/5316)
+ * Fix aspect ratio of avatar before clicking Save
+ [\#5318](https://github.com/matrix-org/matrix-react-sdk/pull/5318)
+ * Don't supply popout widgets with widget parameters
+ [\#5323](https://github.com/matrix-org/matrix-react-sdk/pull/5323)
+ * Changed rainbow algorithm
+ [\#5301](https://github.com/matrix-org/matrix-react-sdk/pull/5301)
+ * Renamed TagPanel and TagOrderStore
+ [\#5309](https://github.com/matrix-org/matrix-react-sdk/pull/5309)
+ * Fix/clarify boolean logic for reaction previews
+ [\#5321](https://github.com/matrix-org/matrix-react-sdk/pull/5321)
+ * Support glare for VoIP calls
+ [\#5311](https://github.com/matrix-org/matrix-react-sdk/pull/5311)
+ * Round of Typescript conversions
+ [\#5314](https://github.com/matrix-org/matrix-react-sdk/pull/5314)
+ * Fix broken rendering of Room Create when showHiddenEvents enabled
+ [\#5317](https://github.com/matrix-org/matrix-react-sdk/pull/5317)
+ * Improve LHS resize performance and tidy stale props&classes
+ [\#5313](https://github.com/matrix-org/matrix-react-sdk/pull/5313)
+ * event-index: Pass the user/device id pair when initializing the event index.
+ [\#5312](https://github.com/matrix-org/matrix-react-sdk/pull/5312)
+ * Fix various aspects of (jitsi) widgets
+ [\#5315](https://github.com/matrix-org/matrix-react-sdk/pull/5315)
+ * Fix rogue (partial) call bar
+ [\#5310](https://github.com/matrix-org/matrix-react-sdk/pull/5310)
+ * Rewrite call state machine
+ [\#5308](https://github.com/matrix-org/matrix-react-sdk/pull/5308)
+ * Convert `src/SecurityManager.js` to TypeScript
+ [\#5307](https://github.com/matrix-org/matrix-react-sdk/pull/5307)
+ * Fix templating for v1 jitsi widgets
+ [\#5305](https://github.com/matrix-org/matrix-react-sdk/pull/5305)
+ * Use new preparing event for widget communications
+ [\#5303](https://github.com/matrix-org/matrix-react-sdk/pull/5303)
+ * Fix parsing issue in event tile preview for appearance tab
+ [\#5302](https://github.com/matrix-org/matrix-react-sdk/pull/5302)
+ * Track replyToEvent along with Cider state & history
+ [\#5284](https://github.com/matrix-org/matrix-react-sdk/pull/5284)
+ * Roving Tab Index should not interfere with inputs
+ [\#5299](https://github.com/matrix-org/matrix-react-sdk/pull/5299)
+ * Visual tweaks from 2020-10-06 polishing
+ [\#5298](https://github.com/matrix-org/matrix-react-sdk/pull/5298)
+ * Convert auth lifecycle to TS, remove dead ILAG code
+ [\#5296](https://github.com/matrix-org/matrix-react-sdk/pull/5296)
+
+Changes in [3.6.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.6.1) (2020-10-20)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.6.0...v3.6.1)
+
+ * [Release] Adjust for new widget messaging APIs
+ [\#5342](https://github.com/matrix-org/matrix-react-sdk/pull/5342)
+ * [Release] Fix Jitsi OpenIDC auth
+ [\#5335](https://github.com/matrix-org/matrix-react-sdk/pull/5335)
+
+Changes in [3.6.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.6.0) (2020-10-12)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.6.0-rc.1...v3.6.0)
+
+ * Upgrade JS SDK to 8.5.0
+ * [Release] Fix templating for v1 jitsi widgets
+ [\#5306](https://github.com/matrix-org/matrix-react-sdk/pull/5306)
+ * [Release] Use new preparing event for widget communications
+ [\#5304](https://github.com/matrix-org/matrix-react-sdk/pull/5304)
+
+Changes in [3.6.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.6.0-rc.1) (2020-10-07)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.5.0...v3.6.0-rc.1)
+
+ * Upgrade JS SDK to 8.5.0-rc.1
+ * Update from Weblate
+ [\#5297](https://github.com/matrix-org/matrix-react-sdk/pull/5297)
+ * Fix edited replies being wrongly treated as big emoji
+ [\#5295](https://github.com/matrix-org/matrix-react-sdk/pull/5295)
+ * Fix StopGapWidget infinitely recursing
+ [\#5294](https://github.com/matrix-org/matrix-react-sdk/pull/5294)
+ * Fix editing and redactions not updating the Reply Thread
+ [\#5281](https://github.com/matrix-org/matrix-react-sdk/pull/5281)
+ * Hide Jump to Read Receipt button for users who have not yet sent an RR
+ [\#5282](https://github.com/matrix-org/matrix-react-sdk/pull/5282)
+ * fix img tags not always being rendered correctly
+ [\#5279](https://github.com/matrix-org/matrix-react-sdk/pull/5279)
+ * Hopefully fix righhtpanel crash
+ [\#5293](https://github.com/matrix-org/matrix-react-sdk/pull/5293)
+ * Fix naive pinning limit and app tile widgetMessaging NPE
+ [\#5283](https://github.com/matrix-org/matrix-react-sdk/pull/5283)
+ * Show server errors from saving profile settings
+ [\#5272](https://github.com/matrix-org/matrix-react-sdk/pull/5272)
+ * Update copy for `redact` permission
+ [\#5273](https://github.com/matrix-org/matrix-react-sdk/pull/5273)
+ * Remove width limit on widgets
+ [\#5265](https://github.com/matrix-org/matrix-react-sdk/pull/5265)
+ * Fix call container avatar initial centering
+ [\#5280](https://github.com/matrix-org/matrix-react-sdk/pull/5280)
+ * Fix right panel for peeking rooms
+ [\#5268](https://github.com/matrix-org/matrix-react-sdk/pull/5268)
+ * Add support for dehydrated devices
+ [\#5239](https://github.com/matrix-org/matrix-react-sdk/pull/5239)
+ * Use Own Profile Store for the Profile Settings
+ [\#5277](https://github.com/matrix-org/matrix-react-sdk/pull/5277)
+ * null-guard defaultAvatarUrlForString
+ [\#5270](https://github.com/matrix-org/matrix-react-sdk/pull/5270)
+ * Choose first result on enter in the emoji picker
+ [\#5257](https://github.com/matrix-org/matrix-react-sdk/pull/5257)
+ * Fix room directory clipping links in the room's topic
+ [\#5276](https://github.com/matrix-org/matrix-react-sdk/pull/5276)
+ * Decorate failed e2ee downgrade attempts better
+ [\#5278](https://github.com/matrix-org/matrix-react-sdk/pull/5278)
+ * MELS use latest avatar rather than the first avatar
+ [\#5262](https://github.com/matrix-org/matrix-react-sdk/pull/5262)
+ * Fix Encryption Panel close button clashing with Base Card
+ [\#5261](https://github.com/matrix-org/matrix-react-sdk/pull/5261)
+ * Wrap canEncryptToAllUsers in a try/catch to handle server errors
+ [\#5275](https://github.com/matrix-org/matrix-react-sdk/pull/5275)
+ * Fix conditional on communities prototype room creation dialog
+ [\#5274](https://github.com/matrix-org/matrix-react-sdk/pull/5274)
+ * Fix ensureDmExists for encryption detection
+ [\#5271](https://github.com/matrix-org/matrix-react-sdk/pull/5271)
+ * Switch to using the Widget API SDK for widget messaging
+ [\#5171](https://github.com/matrix-org/matrix-react-sdk/pull/5171)
+ * Ensure package links exist when releasing
+ [\#5269](https://github.com/matrix-org/matrix-react-sdk/pull/5269)
+ * Fix the call preview when not in same room as the call
+ [\#5267](https://github.com/matrix-org/matrix-react-sdk/pull/5267)
+ * Make the hangup button do things for conference calls
+ [\#5223](https://github.com/matrix-org/matrix-react-sdk/pull/5223)
+ * Render Jitsi widget state events in a more obvious way
+ [\#5222](https://github.com/matrix-org/matrix-react-sdk/pull/5222)
+ * Make the PIP Jitsi look and feel like the 1:1 PIP
+ [\#5226](https://github.com/matrix-org/matrix-react-sdk/pull/5226)
+ * Trim range when formatting so that it excludes leading/trailing spaces
+ [\#5263](https://github.com/matrix-org/matrix-react-sdk/pull/5263)
+ * Fix button label on the Set Password Dialog
+ [\#5264](https://github.com/matrix-org/matrix-react-sdk/pull/5264)
+ * fix link to classic yarn's `yarn link`
+ [\#5259](https://github.com/matrix-org/matrix-react-sdk/pull/5259)
+ * Fix index mismatch between username colors styles and custom theming
+ [\#5256](https://github.com/matrix-org/matrix-react-sdk/pull/5256)
+ * Disable autocompletion on security key input during login
+ [\#5258](https://github.com/matrix-org/matrix-react-sdk/pull/5258)
+ * fix uninitialised state and eventlistener leak in RoomUpgradeWarningBar
+ [\#5255](https://github.com/matrix-org/matrix-react-sdk/pull/5255)
+ * Only set title when it changes
+ [\#5254](https://github.com/matrix-org/matrix-react-sdk/pull/5254)
+ * Convert CallHandler to typescript
+ [\#5248](https://github.com/matrix-org/matrix-react-sdk/pull/5248)
+ * Retry loading i18n language if it fails
+ [\#5209](https://github.com/matrix-org/matrix-react-sdk/pull/5209)
+ * Rework profile area for user and room settings to be more clear
+ [\#5243](https://github.com/matrix-org/matrix-react-sdk/pull/5243)
+ * Validation improve pattern for derived data
+ [\#5241](https://github.com/matrix-org/matrix-react-sdk/pull/5241)
+
+Changes in [3.5.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.5.0) (2020-09-28)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.5.0-rc.1...v3.5.0)
+
+ * Upgrade JS SDK to 8.4.1
+
+Changes in [3.5.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.5.0-rc.1) (2020-09-23)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.4.1...v3.5.0-rc.1)
+
+ * Upgrade JS SDK to 8.4.0-rc.1
+ * Update from Weblate
+ [\#5246](https://github.com/matrix-org/matrix-react-sdk/pull/5246)
+ * Upgrade sanitize-html, set nesting limit
+ [\#5245](https://github.com/matrix-org/matrix-react-sdk/pull/5245)
+ * Add a note to use the desktop builds when seshat isn't available
+ [\#5225](https://github.com/matrix-org/matrix-react-sdk/pull/5225)
+ * Add some permission checks to the communities v2 prototype
+ [\#5240](https://github.com/matrix-org/matrix-react-sdk/pull/5240)
+ * Support HS-preferred Secure Backup setup methods
+ [\#5242](https://github.com/matrix-org/matrix-react-sdk/pull/5242)
+ * Only show User Info verify button if the other user has e2ee devices
+ [\#5234](https://github.com/matrix-org/matrix-react-sdk/pull/5234)
+ * Fix New Room List arrow key management
+ [\#5237](https://github.com/matrix-org/matrix-react-sdk/pull/5237)
+ * Fix Room Directory View & Preview actions for federated joins
+ [\#5235](https://github.com/matrix-org/matrix-react-sdk/pull/5235)
+ * Add a UI feature to disable advanced encryption options
+ [\#5238](https://github.com/matrix-org/matrix-react-sdk/pull/5238)
+ * UI Feature Flag: Communities
+ [\#5216](https://github.com/matrix-org/matrix-react-sdk/pull/5216)
+ * Rename apps back to widgets
+ [\#5236](https://github.com/matrix-org/matrix-react-sdk/pull/5236)
+ * Adjust layout and formatting of notifications / files cards
+ [\#5229](https://github.com/matrix-org/matrix-react-sdk/pull/5229)
+ * Fix Search Results Tile undefined variable access regression
+ [\#5232](https://github.com/matrix-org/matrix-react-sdk/pull/5232)
+ * Fix Cmd/Ctrl+Shift+U for File Upload
+ [\#5233](https://github.com/matrix-org/matrix-react-sdk/pull/5233)
+ * Disable the e2ee toggle when creating a room on a server with forced e2e
+ [\#5231](https://github.com/matrix-org/matrix-react-sdk/pull/5231)
+ * UI Feature Flag: Disable advanced options and tidy up some copy
+ [\#5215](https://github.com/matrix-org/matrix-react-sdk/pull/5215)
+ * UI Feature Flag: 3PIDs
+ [\#5228](https://github.com/matrix-org/matrix-react-sdk/pull/5228)
+ * Defer encryption setup until first E2EE room
+ [\#5219](https://github.com/matrix-org/matrix-react-sdk/pull/5219)
+ * Tidy devDeps, all the webpack stuff lives in the layer above
+ [\#5179](https://github.com/matrix-org/matrix-react-sdk/pull/5179)
+ * UI Feature Flag: Hide flair
+ [\#5214](https://github.com/matrix-org/matrix-react-sdk/pull/5214)
+ * UI Feature Flag: Identity server
+ [\#5218](https://github.com/matrix-org/matrix-react-sdk/pull/5218)
+ * UI Feature Flag: Share dialog QR code and social icons
+ [\#5221](https://github.com/matrix-org/matrix-react-sdk/pull/5221)
+ * UI Feature Flag: Registration, Password Reset, Deactivate
+ [\#5227](https://github.com/matrix-org/matrix-react-sdk/pull/5227)
+ * Retry joinRoom up to 5 times in the case of a 504 GATEWAY TIMEOUT
+ [\#5204](https://github.com/matrix-org/matrix-react-sdk/pull/5204)
+ * UI Feature Flag: Disable VoIP
+ [\#5217](https://github.com/matrix-org/matrix-react-sdk/pull/5217)
+ * Fix setState() usage in the constructor of RoomDirectory
+ [\#5224](https://github.com/matrix-org/matrix-react-sdk/pull/5224)
+ * Hide Analytics sections if piwik config is not provided
+ [\#5211](https://github.com/matrix-org/matrix-react-sdk/pull/5211)
+ * UI Feature Flag: Disable feedback button
+ [\#5213](https://github.com/matrix-org/matrix-react-sdk/pull/5213)
+ * Clean up UserInfo to not show a blank Power Selector for users not in room
+ [\#5220](https://github.com/matrix-org/matrix-react-sdk/pull/5220)
+ * Also hide bug reporting prompts from the Error Boundaries
+ [\#5212](https://github.com/matrix-org/matrix-react-sdk/pull/5212)
+ * Tactical improvements to 3PID invites
+ [\#5201](https://github.com/matrix-org/matrix-react-sdk/pull/5201)
+ * If no bug_report_endpoint_url, hide rageshaking from the App
+ [\#5210](https://github.com/matrix-org/matrix-react-sdk/pull/5210)
+ * Introduce a concept of UI features, using it for URL previews at first
+ [\#5208](https://github.com/matrix-org/matrix-react-sdk/pull/5208)
+ * Remove defunct "always show encryption icons" setting
+ [\#5207](https://github.com/matrix-org/matrix-react-sdk/pull/5207)
+ * Don't show Notifications Prompt Toast if user has master rule enabled
+ [\#5203](https://github.com/matrix-org/matrix-react-sdk/pull/5203)
+ * Fix Bridges tab crashing when the room does not have bridges
+ [\#5206](https://github.com/matrix-org/matrix-react-sdk/pull/5206)
+ * Don't count widgets which no longer exist towards pinned count
+ [\#5202](https://github.com/matrix-org/matrix-react-sdk/pull/5202)
+ * Fix crashes with cannot read isResizing of undefined
+ [\#5205](https://github.com/matrix-org/matrix-react-sdk/pull/5205)
+ * Prompt to remove the jitsi widget when pressing the call button
+ [\#5193](https://github.com/matrix-org/matrix-react-sdk/pull/5193)
+ * Show verification status in the room summary card
+ [\#5195](https://github.com/matrix-org/matrix-react-sdk/pull/5195)
+ * Fix user info scrolling in new card view
+ [\#5198](https://github.com/matrix-org/matrix-react-sdk/pull/5198)
+ * Fix sticker picker height
+ [\#5197](https://github.com/matrix-org/matrix-react-sdk/pull/5197)
+ * Call jitsi widgets 'group calls'
+ [\#5191](https://github.com/matrix-org/matrix-react-sdk/pull/5191)
+ * Don't show 'unpin' for persistent widgets
+ [\#5194](https://github.com/matrix-org/matrix-react-sdk/pull/5194)
+ * Split up cross-signing and secure backup settings
+ [\#5182](https://github.com/matrix-org/matrix-react-sdk/pull/5182)
+ * Fix onNewScreen to use replace when going from roomId->roomAlias
+ [\#5185](https://github.com/matrix-org/matrix-react-sdk/pull/5185)
+ * bring back 1.2M style badge counts rather than 99+
+ [\#5192](https://github.com/matrix-org/matrix-react-sdk/pull/5192)
+ * Run the rageshake command through the bug report dialog
+ [\#5189](https://github.com/matrix-org/matrix-react-sdk/pull/5189)
+ * Account for via in pill matching regex
+ [\#5188](https://github.com/matrix-org/matrix-react-sdk/pull/5188)
+ * Remove now-unused create-react-class from lockfile
+ [\#5187](https://github.com/matrix-org/matrix-react-sdk/pull/5187)
+ * Fixed 1px jump upwards
+ [\#5163](https://github.com/matrix-org/matrix-react-sdk/pull/5163)
+ * Always allow widgets when using the local version
+ [\#5184](https://github.com/matrix-org/matrix-react-sdk/pull/5184)
+ * Migrate RoomView and RoomContext to Typescript
+ [\#5175](https://github.com/matrix-org/matrix-react-sdk/pull/5175)
+
+Changes in [3.4.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.4.1) (2020-09-14)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.4.0...v3.4.1)
+
+ * Don't count widgets which no longer exist towards pinned count
+ [\#5202](https://github.com/matrix-org/matrix-react-sdk/pull/5202)
+ * Fix crashes with cannot read isResizing of undefined
+ [\#5205](https://github.com/matrix-org/matrix-react-sdk/pull/5205)
+
+Changes in [3.4.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.4.0) (2020-09-14)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.4.0-rc.1...v3.4.0)
+
+ * Upgrade to JS SDK 8.3.0
+ * [Release] Show verification status in the room summary card
+ [\#5196](https://github.com/matrix-org/matrix-react-sdk/pull/5196)
+ * Fix user info scrolling in new card view
+ [\#5200](https://github.com/matrix-org/matrix-react-sdk/pull/5200)
+ * Fix sticker picker height
+ [\#5199](https://github.com/matrix-org/matrix-react-sdk/pull/5199)
+ * [Release] Account for via in pill matching regex
+ [\#5190](https://github.com/matrix-org/matrix-react-sdk/pull/5190)
+
+Changes in [3.4.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.4.0-rc.1) (2020-09-09)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.3.0...v3.4.0-rc.1)
+
+ * Upgrade to JS SDK 8.3.0-rc.1
+ * Update from Weblate
+ [\#5183](https://github.com/matrix-org/matrix-react-sdk/pull/5183)
+ * Right Panel Room Summary and Widgets
+ [\#5167](https://github.com/matrix-org/matrix-react-sdk/pull/5167)
+ * null-guard roomId in RightPanel and pass Room to UserView
+ [\#5180](https://github.com/matrix-org/matrix-react-sdk/pull/5180)
+ * Fix create-react-class regression.
+ [\#5178](https://github.com/matrix-org/matrix-react-sdk/pull/5178)
+ * Fix WatchManager for global room watchers and tidy widget code a little
+ [\#5176](https://github.com/matrix-org/matrix-react-sdk/pull/5176)
+ * Fix permalink local linkification to not strip via servers
+ [\#5174](https://github.com/matrix-org/matrix-react-sdk/pull/5174)
+ * Support creation of Jitsi widgets with "openidtoken-jwt" auth
+ [\#5173](https://github.com/matrix-org/matrix-react-sdk/pull/5173)
+ * Fix create-react-class regression.
+ [\#5177](https://github.com/matrix-org/matrix-react-sdk/pull/5177)
+ * Update openid_credentials Widget API action for MSC1960 updates
+ [\#5172](https://github.com/matrix-org/matrix-react-sdk/pull/5172)
+ * Allow persistent resizing of the widget app drawer
+ [\#5138](https://github.com/matrix-org/matrix-react-sdk/pull/5138)
+ * add lenny face command
+ [\#5158](https://github.com/matrix-org/matrix-react-sdk/pull/5158)
+ * Prep work for Settings changes with cross-signing deferral
+ [\#5169](https://github.com/matrix-org/matrix-react-sdk/pull/5169)
+ * Small code clean ups and tweaks
+ [\#5168](https://github.com/matrix-org/matrix-react-sdk/pull/5168)
+ * Fix soft crash from TruncatedList in the createReactClass conversion
+ [\#5170](https://github.com/matrix-org/matrix-react-sdk/pull/5170)
+ * Remove create-react-class
+ [\#5157](https://github.com/matrix-org/matrix-react-sdk/pull/5157)
+ * Consolidate Lodash files in bundle
+ [\#5162](https://github.com/matrix-org/matrix-react-sdk/pull/5162)
+ * Communities v2 prototype: "In community" view
+ [\#5161](https://github.com/matrix-org/matrix-react-sdk/pull/5161)
+ * Respect user preference for whether pills should have an avatar or not
+ [\#5165](https://github.com/matrix-org/matrix-react-sdk/pull/5165)
+ * Communities v2 prototype: DM copy updates
+ [\#5153](https://github.com/matrix-org/matrix-react-sdk/pull/5153)
+ * Only wait for public keys during verification
+ [\#5164](https://github.com/matrix-org/matrix-react-sdk/pull/5164)
+ * Fix eslint ts override tsx matching and delint
+ [\#5155](https://github.com/matrix-org/matrix-react-sdk/pull/5155)
+ * Fix react error about functional components can't take refs
+ [\#5159](https://github.com/matrix-org/matrix-react-sdk/pull/5159)
+ * Remove redundant components and devDependencies
+ [\#5156](https://github.com/matrix-org/matrix-react-sdk/pull/5156)
+ * Add display-capture to iframe allow for widgets
+ [\#5154](https://github.com/matrix-org/matrix-react-sdk/pull/5154)
+ * Update create room dialog copy & community prototype home icon
+ [\#5151](https://github.com/matrix-org/matrix-react-sdk/pull/5151)
+ * Migrate to new, separate APIs for cross-signing and secret storage
+ [\#5149](https://github.com/matrix-org/matrix-react-sdk/pull/5149)
+ * Fix clicking the background of the tag panel not clearing the filter
+ [\#5152](https://github.com/matrix-org/matrix-react-sdk/pull/5152)
+ * Communities v2 prototype: Associate created rooms with the selected
+ community
+ [\#5147](https://github.com/matrix-org/matrix-react-sdk/pull/5147)
+ * Communities v2 prototype: Tag panel selection changes
+ [\#5145](https://github.com/matrix-org/matrix-react-sdk/pull/5145)
+ * Communities v2 prototype: Create community flow
+ [\#5144](https://github.com/matrix-org/matrix-react-sdk/pull/5144)
+ * Communities v2 prototype: Override invite aesthetics for community-as-room
+ invites
+ [\#5143](https://github.com/matrix-org/matrix-react-sdk/pull/5143)
+
+Changes in [3.3.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.3.0) (2020-09-01)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.3.0-rc.1...v3.3.0)
+
+ * Upgrade to JS SDK 8.2.0
+
+Changes in [3.3.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.3.0-rc.1) (2020-08-26)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.2.0...v3.3.0-rc.1)
+
+ * Upgrade to JS SDK 8.2.0-rc.1
+ * Update from Weblate
+ [\#5146](https://github.com/matrix-org/matrix-react-sdk/pull/5146)
+ * BaseAvatar avoid initial render with default avatar
+ [\#5142](https://github.com/matrix-org/matrix-react-sdk/pull/5142)
+ * Enforce Secure Backup completion when requested by HS
+ [\#5130](https://github.com/matrix-org/matrix-react-sdk/pull/5130)
+ * Communities v2 prototype: Explore rooms, global state, and default room
+ [\#5139](https://github.com/matrix-org/matrix-react-sdk/pull/5139)
+ * Add communities v2 prototyping feature flag + initial tag panel prototypes
+ [\#5133](https://github.com/matrix-org/matrix-react-sdk/pull/5133)
+ * Remove some unused components
+ [\#5134](https://github.com/matrix-org/matrix-react-sdk/pull/5134)
+ * Allow avatar image view for 1:1 rooms
+ [\#5137](https://github.com/matrix-org/matrix-react-sdk/pull/5137)
+ * Send mx_local_settings in rageshake
+ [\#5136](https://github.com/matrix-org/matrix-react-sdk/pull/5136)
+ * Run all room leaving behaviour through a single function
+ [\#5132](https://github.com/matrix-org/matrix-react-sdk/pull/5132)
+ * Add clarifying comment in media device selection
+ [\#5131](https://github.com/matrix-org/matrix-react-sdk/pull/5131)
+ * Settings v3: Feature flag changes
+ [\#5124](https://github.com/matrix-org/matrix-react-sdk/pull/5124)
+ * Clear url previews if they all get edited out of the event
+ [\#5129](https://github.com/matrix-org/matrix-react-sdk/pull/5129)
+ * Consider tab completions as modifications for editing purposes to unlock
+ sending
+ [\#5128](https://github.com/matrix-org/matrix-react-sdk/pull/5128)
+ * Use matrix-doc for SAS emoji translations
+ [\#5125](https://github.com/matrix-org/matrix-react-sdk/pull/5125)
+ * Add a rageshake function to download the logs locally
+ [\#3849](https://github.com/matrix-org/matrix-react-sdk/pull/3849)
+ * Room List filtering visual tweaks
+ [\#5123](https://github.com/matrix-org/matrix-react-sdk/pull/5123)
+ * Make reply preview not an overlay so you can see new messages
+ [\#5072](https://github.com/matrix-org/matrix-react-sdk/pull/5072)
+ * Allow room tile context menu when minimized using right click
+ [\#5113](https://github.com/matrix-org/matrix-react-sdk/pull/5113)
+ * Add null guard to group inviter for corrupted groups
+ [\#5121](https://github.com/matrix-org/matrix-react-sdk/pull/5121)
+ * Room List styling tweaks
+ [\#5118](https://github.com/matrix-org/matrix-react-sdk/pull/5118)
+ * Fix corner rounding on images not always affecting right side
+ [\#5120](https://github.com/matrix-org/matrix-react-sdk/pull/5120)
+ * Change add room action for rooms to context menu
+ [\#5108](https://github.com/matrix-org/matrix-react-sdk/pull/5108)
+ * Switch out the globe icon and colour it depending on theme
+ [\#5106](https://github.com/matrix-org/matrix-react-sdk/pull/5106)
+ * Message Action Bar watch for event send changes
+ [\#5115](https://github.com/matrix-org/matrix-react-sdk/pull/5115)
+ * Put message previews for Emoji behind Labs
+ [\#5110](https://github.com/matrix-org/matrix-react-sdk/pull/5110)
+ * Fix styling for selected community marker
+ [\#5107](https://github.com/matrix-org/matrix-react-sdk/pull/5107)
+ * Fix action bar safe area regression
+ [\#5111](https://github.com/matrix-org/matrix-react-sdk/pull/5111)
+ * Fix /op slash command
+ [\#5109](https://github.com/matrix-org/matrix-react-sdk/pull/5109)
+
+Changes in [3.2.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.2.0) (2020-08-17)
+===================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.2.0-rc.1...v3.2.0)
+
+ * Upgrade to JS SDK 8.1.0
+ * [Release] Fix corner rounding on images not always affecting right side
+ [\#5122](https://github.com/matrix-org/matrix-react-sdk/pull/5122)
+ * [Release] Message Action Bar watch for event send changes
+ [\#5116](https://github.com/matrix-org/matrix-react-sdk/pull/5116)
+ * Fix /op slash command to release
+ [\#5114](https://github.com/matrix-org/matrix-react-sdk/pull/5114)
+ * Fix action bar safe area regression
+ [\#5112](https://github.com/matrix-org/matrix-react-sdk/pull/5112)
+
+Changes in [3.2.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.2.0-rc.1) (2020-08-13)
+=============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.1.0...v3.2.0-rc.1)
+
+ * Upgrade to JS SDK 8.1.0-rc.1
+ * Update from Weblate
+ [\#5105](https://github.com/matrix-org/matrix-react-sdk/pull/5105)
+ * padding the timeline so that its scrollbar has its own space from the
+ resizer
+ [\#5103](https://github.com/matrix-org/matrix-react-sdk/pull/5103)
+ * Try to close notification on all platforms which support it, not just
+ electron
+ [\#5102](https://github.com/matrix-org/matrix-react-sdk/pull/5102)
+ * Fix exception when stripping replies from an event with a non-string body
+ [\#5101](https://github.com/matrix-org/matrix-react-sdk/pull/5101)
+ * Quick win session 24/07/2020
+ [\#5056](https://github.com/matrix-org/matrix-react-sdk/pull/5056)
+ * Remove rebranding toast
+ [\#5100](https://github.com/matrix-org/matrix-react-sdk/pull/5100)
+ * Generate previews for rooms when the option changes
+ [\#5098](https://github.com/matrix-org/matrix-react-sdk/pull/5098)
+ * Fix Bridge Settings tab
+ [\#5095](https://github.com/matrix-org/matrix-react-sdk/pull/5095)
+ * get screen type from app prop
+ [\#5081](https://github.com/matrix-org/matrix-react-sdk/pull/5081)
+ * Update rageshake app name
+ [\#5093](https://github.com/matrix-org/matrix-react-sdk/pull/5093)
+ * Factor out Iconized Context menu for reusability
+ [\#5085](https://github.com/matrix-org/matrix-react-sdk/pull/5085)
+ * Decouple Audible notifications from Desktop notifications
+ [\#5088](https://github.com/matrix-org/matrix-react-sdk/pull/5088)
+ * Make the room sublist show more/less buttons treeitems
+ [\#5087](https://github.com/matrix-org/matrix-react-sdk/pull/5087)
+ * Share and debug master cross-signing key
+ [\#5092](https://github.com/matrix-org/matrix-react-sdk/pull/5092)
+ * Create Map comparison utilities and convert Hooks to Typescript
+ [\#5086](https://github.com/matrix-org/matrix-react-sdk/pull/5086)
+ * Fix room list scrolling in Safari
+ [\#5090](https://github.com/matrix-org/matrix-react-sdk/pull/5090)
+ * Replace Riot with Element in docs and comments
+ [\#5083](https://github.com/matrix-org/matrix-react-sdk/pull/5083)
+ * When the room view isn't active don't highlight it in room list
+ [\#5027](https://github.com/matrix-org/matrix-react-sdk/pull/5027)
+ * remove emoji icons in autocomplete/reply by designer request
+ [\#5073](https://github.com/matrix-org/matrix-react-sdk/pull/5073)
+ * Add title and icon to empty state of file and notification panel
+ [\#5079](https://github.com/matrix-org/matrix-react-sdk/pull/5079)
+ * Mass redact ignore room creation events
+ [\#5045](https://github.com/matrix-org/matrix-react-sdk/pull/5045)
+ * Replace all chevrons with a single icon
+ [\#5067](https://github.com/matrix-org/matrix-react-sdk/pull/5067)
+ * Replace i18n generation script with something matching our project
+ [\#5077](https://github.com/matrix-org/matrix-react-sdk/pull/5077)
+ * Handle tag changes in sticky room updates
+ [\#5078](https://github.com/matrix-org/matrix-react-sdk/pull/5078)
+ * Remove leftover bits of TSLint
+ [\#5075](https://github.com/matrix-org/matrix-react-sdk/pull/5075)
+ * Clean up documentation of Whenable + fix other code concerns
+ [\#5076](https://github.com/matrix-org/matrix-react-sdk/pull/5076)
+ * Center the jump down/up icon, looks misaligned
+ [\#5074](https://github.com/matrix-org/matrix-react-sdk/pull/5074)
+ * [WIP] Support a new settings structure
+ [\#5058](https://github.com/matrix-org/matrix-react-sdk/pull/5058)
+ * Convert SettingsStore to TypeScript
+ [\#5062](https://github.com/matrix-org/matrix-react-sdk/pull/5062)
+
Changes in [3.1.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.1.0) (2020-08-05)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.1.0-rc.1...v3.1.0)
diff --git a/README.md b/README.md
index e468d272d0..b3e96ef001 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ are currently filed against vector-im/element-web rather than this project).
Translation Status
==================
-[](https://translate.riot.im/engage/element-web/?utm_source=widget)
+[](https://translate.element.io/engage/element-web/?utm_source=widget)
Developer Guide
===============
@@ -28,7 +28,7 @@ Platform Targets:
* WebRTC features (VoIP and Video calling) are only available in Chrome & Firefox.
* Mobile Web is not currently a target platform - instead please use the native
iOS (https://github.com/matrix-org/matrix-ios-kit) and Android
- (https://github.com/matrix-org/matrix-android-sdk) SDKs.
+ (https://github.com/matrix-org/matrix-android-sdk2) SDKs.
All code lands on the `develop` branch - `master` is only used for stable releases.
**Please file PRs against `develop`!!**
@@ -160,8 +160,8 @@ yarn link matrix-js-sdk
yarn install
```
-See the [help for `yarn link`](https://yarnpkg.com/docs/cli/link) for more
-details about this.
+See the [help for `yarn link`](https://classic.yarnpkg.com/docs/cli/link) for
+more details about this.
Running tests
=============
diff --git a/__mocks__/browser-request.js b/__mocks__/browser-request.js
index 7d231fb9db..4c59e8a43a 100644
--- a/__mocks__/browser-request.js
+++ b/__mocks__/browser-request.js
@@ -1,5 +1,10 @@
const en = require("../src/i18n/strings/en_EN");
+const de = require("../src/i18n/strings/de_DE");
+// Mock the browser-request for the languageHandler tests to return
+// Fake languages.json containing references to en_EN and de_DE
+// en_EN.json
+// de_DE.json
module.exports = jest.fn((opts, cb) => {
const url = opts.url || opts.uri;
if (url && url.endsWith("languages.json")) {
@@ -8,9 +13,15 @@ module.exports = jest.fn((opts, cb) => {
"fileName": "en_EN.json",
"label": "English",
},
+ "de": {
+ "fileName": "de_DE.json",
+ "label": "German",
+ },
}));
} else if (url && url.endsWith("en_EN.json")) {
cb(undefined, {status: 200}, JSON.stringify(en));
+ } else if (url && url.endsWith("de_DE.json")) {
+ cb(undefined, {status: 200}, JSON.stringify(de));
} else {
cb(true, {status: 404}, "");
}
diff --git a/__mocks__/empty.js b/__mocks__/empty.js
new file mode 100644
index 0000000000..51fb4fe937
--- /dev/null
+++ b/__mocks__/empty.js
@@ -0,0 +1,2 @@
+// Yes, this is empty.
+module.exports = {};
diff --git a/__test-utils__/environment.js b/__test-utils__/environment.js
new file mode 100644
index 0000000000..9870c133a2
--- /dev/null
+++ b/__test-utils__/environment.js
@@ -0,0 +1,17 @@
+const BaseEnvironment = require("jest-environment-jsdom-sixteen");
+
+class Environment extends BaseEnvironment {
+ constructor(config, options) {
+ super(Object.assign({}, config, {
+ globals: Object.assign({}, config.globals, {
+ // Explicitly specify the correct globals to workaround Jest bug
+ // https://github.com/facebook/jest/issues/7780
+ Uint32Array: Uint32Array,
+ Uint8Array: Uint8Array,
+ ArrayBuffer: ArrayBuffer,
+ }),
+ }), options);
+ }
+}
+
+module.exports = Environment;
diff --git a/babel.config.js b/babel.config.js
index d5a97d56ce..0a3a34a391 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -3,12 +3,15 @@ module.exports = {
"presets": [
["@babel/preset-env", {
"targets": [
- "last 2 Chrome versions", "last 2 Firefox versions", "last 2 Safari versions"
+ "last 2 Chrome versions",
+ "last 2 Firefox versions",
+ "last 2 Safari versions",
+ "last 2 Edge versions",
],
}],
"@babel/preset-typescript",
"@babel/preset-flow",
- "@babel/preset-react"
+ "@babel/preset-react",
],
"plugins": [
["@babel/plugin-proposal-decorators", {legacy: true}],
@@ -18,6 +21,6 @@ module.exports = {
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-transform-flow-comments",
"@babel/plugin-syntax-dynamic-import",
- "@babel/plugin-transform-runtime"
- ]
+ "@babel/plugin-transform-runtime",
+ ],
};
diff --git a/code_style.md b/code_style.md
index fe04d2cc3d..5747540a76 100644
--- a/code_style.md
+++ b/code_style.md
@@ -35,12 +35,6 @@ General Style
- lowerCamelCase for functions and variables.
- Single line ternary operators are fine.
- UPPER_SNAKE_CASE for constants
-- Single quotes for strings by default, for consistency with most JavaScript styles:
-
- ```javascript
- "bad" // Bad
- 'good' // Good
- ```
- Use parentheses or `` ` `` instead of `\` for line continuation where ever possible
- Open braces on the same line (consistent with Node):
@@ -162,7 +156,14 @@ ECMAScript
- Be careful mixing arrow functions and regular functions, eg. if one function in a promise chain is an
arrow function, they probably all should be.
- Apart from that, newer ES features should be used whenever the author deems them to be appropriate.
-- Flow annotations are welcome and encouraged.
+
+TypeScript
+----------
+- TypeScript is preferred over the use of JavaScript
+- It's desirable to convert existing JavaScript files to TypeScript. TypeScript conversions should be done in small
+ chunks without functional changes to ease the review process.
+- Use full type definitions for function parameters and return values.
+- Avoid `any` types and `any` casts
React
-----
@@ -201,6 +202,8 @@ React
this.state = { counter: 0 };
}
```
+- Prefer class components over function components and hooks (not a strict rule though)
+
- Think about whether your component really needs state: are you duplicating
information in component state that could be derived from the model?
diff --git a/docs/ciderEditor.md b/docs/ciderEditor.md
index f522dc2fc4..379b6f5b51 100644
--- a/docs/ciderEditor.md
+++ b/docs/ciderEditor.md
@@ -21,14 +21,14 @@ caret nodes (more on that later).
For these reasons it doesn't use `innerText`, `textContent` or anything similar.
The model addresses any content in the editor within as an offset within this string.
The caret position is thus also converted from a position in the DOM tree
-to an offset in the content string. This happens in `getCaretOffsetAndText` in `dom.js`.
+to an offset in the content string. This happens in `getCaretOffsetAndText` in `dom.ts`.
Once the content string and caret offset is calculated, it is passed to the `update()`
method of the model. The model first calculates the same content string of its current parts,
basically just concatenating their text. It then looks for differences between
the current and the new content string. The diffing algorithm is very basic,
and assumes there is only one change around the caret offset,
-so this should be very inexpensive. See `diff.js` for details.
+so this should be very inexpensive. See `diff.ts` for details.
The result of the diffing is the strings that were added and/or removed from
the current content. These differences are then applied to the parts,
@@ -51,7 +51,7 @@ which relate poorly to text input or changes, and don't need the `beforeinput` e
which isn't broadly supported yet.
Once the parts of the model are updated, the DOM of the editor is then reconciled
-with the new model state, see `renderModel` in `render.js` for this.
+with the new model state, see `renderModel` in `render.ts` for this.
If the model didn't reject the input and didn't make any additional changes,
this won't make any changes to the DOM at all, and should thus be fairly efficient.
diff --git a/docs/media-handling.md b/docs/media-handling.md
new file mode 100644
index 0000000000..a4307fb7d4
--- /dev/null
+++ b/docs/media-handling.md
@@ -0,0 +1,19 @@
+# Media handling
+
+Surely media should be as easy as just putting a URL into an `img` and calling it good, right?
+Not quite. Matrix uses something called a Matrix Content URI (better known as MXC URI) to identify
+content, which is then converted to a regular HTTPS URL on the homeserver. However, sometimes that
+URL can change depending on deployment considerations.
+
+The react-sdk features a [customisation endpoint](https://github.com/vector-im/element-web/blob/develop/docs/customisations.md)
+for media handling where all conversions from MXC URI to HTTPS URL happen. This is to ensure that
+those obscure deployments can route all their media to the right place.
+
+For development, there are currently two functions available: `mediaFromMxc` and `mediaFromContent`.
+The `mediaFromMxc` function should be self-explanatory. `mediaFromContent` takes an event content as
+a parameter and will automatically parse out the source media and thumbnail. Both functions return
+a `Media` object with a number of options on it, such as getting various common HTTPS URLs for the
+media.
+
+**It is extremely important that all media calls are put through this customisation endpoint.** So
+much so it's a lint rule to avoid accidental use of the wrong functions.
diff --git a/docs/room-list-store.md b/docs/room-list-store.md
index fa849e2505..6fc5f71124 100644
--- a/docs/room-list-store.md
+++ b/docs/room-list-store.md
@@ -6,7 +6,7 @@ It's so complicated it needs its own README.
Legend:
* Orange = External event.
-* Purple = Deterministic flow.
+* Purple = Deterministic flow.
* Green = Algorithm definition.
* Red = Exit condition/point.
* Blue = Process definition.
@@ -24,8 +24,8 @@ algorithm to call, instead of having all the logic in the room list store itself
Tag sorting is effectively the comparator supplied to the list algorithm. This gives the list algorithm
-the power to decide when and how to apply the tag sorting, if at all. For example, the importance algorithm,
-later described in this document, heavily uses the list ordering behaviour to break the tag into categories.
+the power to decide when and how to apply the tag sorting, if at all. For example, the importance algorithm,
+later described in this document, heavily uses the list ordering behaviour to break the tag into categories.
Each category then gets sorted by the appropriate tag sorting algorithm.
### Tag sorting algorithm: Alphabetical
@@ -36,7 +36,7 @@ useful.
### Tag sorting algorithm: Manual
-Manual sorting makes use of the `order` property present on all tags for a room, per the
+Manual sorting makes use of the `order` property present on all tags for a room, per the
[Matrix specification](https://matrix.org/docs/spec/client_server/r0.6.0#room-tagging). Smaller values
of `order` cause rooms to appear closer to the top of the list.
@@ -74,7 +74,7 @@ relative (perceived) importance to the user:
set to 'All Messages'.
* **Bold**: The room has unread messages waiting for the user. Essentially this is a grey room without
a badge/notification count (or 'Mentions Only'/'Muted').
-* **Idle**: No useful (see definition of useful above) activity has occurred in the room since the user
+* **Idle**: No useful (see definition of useful above) activity has occurred in the room since the user
last read it.
Conveniently, each tag gets ordered by those categories as presented: red rooms appear above grey, grey
@@ -82,7 +82,7 @@ above bold, etc.
Once the algorithm has determined which rooms belong in which categories, the tag sorting algorithm
gets applied to each category in a sub-list fashion. This should result in the red rooms (for example)
-being sorted alphabetically amongst each other as well as the grey rooms sorted amongst each other, but
+being sorted alphabetically amongst each other as well as the grey rooms sorted amongst each other, but
collectively the tag will be sorted into categories with red being at the top.
## Sticky rooms
@@ -103,48 +103,62 @@ receive another notification which causes the room to move into the topmost posi
above the sticky room will move underneath to allow for the new room to take the top slot, maintaining
the sticky room's position.
-Though only applicable to the importance algorithm, the sticky room is not aware of category boundaries
-and thus the user can see a shift in what kinds of rooms move around their selection. An example would
-be the user having 4 red rooms, the user selecting the third room (leaving 2 above it), and then having
-the rooms above it read on another device. This would result in 1 red room and 1 other kind of room
+Though only applicable to the importance algorithm, the sticky room is not aware of category boundaries
+and thus the user can see a shift in what kinds of rooms move around their selection. An example would
+be the user having 4 red rooms, the user selecting the third room (leaving 2 above it), and then having
+the rooms above it read on another device. This would result in 1 red room and 1 other kind of room
above the sticky room as it will try to maintain 2 rooms above the sticky room.
An exception for the sticky room placement is when there's suddenly not enough rooms to maintain the placement
exactly. This typically happens if the user selects a room and leaves enough rooms where it cannot maintain
the N required rooms above the sticky room. In this case, the sticky room will simply decrease N as needed.
-The N value will never increase while selection remains unchanged: adding a bunch of rooms after having
+The N value will never increase while selection remains unchanged: adding a bunch of rooms after having
put the sticky room in a position where it's had to decrease N will not increase N.
## Responsibilities of the store
-The store is responsible for the ordering, upkeep, and tracking of all rooms. The room list component simply gets
-an object containing the tags it needs to worry about and the rooms within. The room list component will
-decide which tags need rendering (as it commonly filters out empty tags in most cases), and will deal with
+The store is responsible for the ordering, upkeep, and tracking of all rooms. The room list component simply gets
+an object containing the tags it needs to worry about and the rooms within. The room list component will
+decide which tags need rendering (as it commonly filters out empty tags in most cases), and will deal with
all kinds of filtering.
## Filtering
-Filters are provided to the store as condition classes, which are then passed along to the algorithm
-implementations. The implementations then get to decide how to actually filter the rooms, however in
-practice the base `Algorithm` class deals with the filtering in a more optimized/generic way.
+Filters are provided to the store as condition classes and have two major kinds: Prefilters and Runtime.
-The results of filters get cached to avoid needlessly iterating over potentially thousands of rooms,
-as the old room list store does. When a filter condition changes, it emits an update which (in this
-case) the `Algorithm` class will pick up and act accordingly. Typically, this also means filtering a
+Prefilters flush out rooms which shouldn't appear to the algorithm implementations. Typically this is
+due to some higher order room list filtering (such as spaces or tags) deliberately exposing a subset of
+rooms to the user. The algorithm implementations will not see a room being prefiltered out.
+
+Runtime filters are used for more dynamic filtering, such as the user filtering by room name. These
+filters are passed along to the algorithm implementations where those implementations decide how and
+when to apply the filter. In practice, the base `Algorithm` class ends up doing the heavy lifting for
+optimization reasons.
+
+The results of runtime filters get cached to avoid needlessly iterating over potentially thousands of
+rooms, as the old room list store does. When a filter condition changes, it emits an update which (in this
+case) the `Algorithm` class will pick up and act accordingly. Typically, this also means filtering a
minor subset where possible to avoid over-iterating rooms.
All filter conditions are considered "stable" by the consumers, meaning that the consumer does not
expect a change in the condition unless the condition says it has changed. This is intentional to
maintain the caching behaviour described above.
+One might ask why we don't just use prefilter conditions for everything, and the answer is one of slight
+subtlety: in the cases of prefilters we are knowingly exposing the user to a workspace-style UX where
+room notifications are self-contained within that workspace. Runtime filters tend to not want to affect
+visible notification counts (as it doesn't want the room header to suddenly be confusing to the user as
+they type), and occasionally UX like "found 2/12 rooms" is desirable. If prefiltering were used instead,
+the notification counts would vary while the user was typing and "found 2/12" UX would not be possible.
+
## Class breakdowns
-The `RoomListStore` is the major coordinator of various algorithm implementations, which take care
-of the various `ListAlgorithm` and `SortingAlgorithm` options. The `Algorithm` class is responsible
-for figuring out which tags get which rooms, as Matrix specifies them as a reverse map: tags get
-defined on rooms and are not defined as a collection of rooms (unlike how they are presented to the
-user). Various list-specific utilities are also included, though they are expected to move somewhere
-more general when needed. For example, the `membership` utilities could easily be moved elsewhere
+The `RoomListStore` is the major coordinator of various algorithm implementations, which take care
+of the various `ListAlgorithm` and `SortingAlgorithm` options. The `Algorithm` class is responsible
+for figuring out which tags get which rooms, as Matrix specifies them as a reverse map: tags get
+defined on rooms and are not defined as a collection of rooms (unlike how they are presented to the
+user). Various list-specific utilities are also included, though they are expected to move somewhere
+more general when needed. For example, the `membership` utilities could easily be moved elsewhere
as needed.
The various bits throughout the room list store should also have jsdoc of some kind to help describe
diff --git a/docs/settings.md b/docs/settings.md
index 46e4a68fdb..891877a57a 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -9,7 +9,7 @@ of dealing with the different levels and exposes easy to use getters and setters
## Levels
Granular Settings rely on a series of known levels in order to use the correct value for the scenario. These levels, in
-order of prioirty, are:
+order of priority, are:
* `device` - The current user's device
* `room-device` - The current user's device, but only when in a specific room
* `room-account` - The current user's account, but only when in a specific room
@@ -25,33 +25,10 @@ that room administrators cannot force account-only settings upon participants.
## Settings
Settings are the different options a user may set or experience in the application. These are pre-defined in
-`src/settings/Settings.js` under the `SETTINGS` constant and have the following minimum requirements:
-```
-// The ID is used to reference the setting throughout the application. This must be unique.
-"theSettingId": {
- // The levels this setting supports is required. In `src/settings/Settings.js` there are various pre-set arrays
- // for this option - they should be used where possible to avoid copy/pasting arrays across settings.
- supportedLevels: [...],
+`src/settings/Settings.ts` under the `SETTINGS` constant, and match the `ISetting` interface as defined there.
- // The default for this setting serves two purposes: It provides a value if the setting is not defined at other
- // levels, and it serves to demonstrate the expected type to other developers. The value isn't enforced, but it
- // should be respected throughout the code. The default may be any data type.
- default: false,
-
- // The display name has two notations: string and object. The object notation allows for different translatable
- // strings to be used for different levels, while the string notation represents the string for all levels.
-
- displayName: _td("Change something"), // effectively `displayName: { "default": _td("Change something") }`
- displayName: {
- "room": _td("Change something for participants of this room"),
-
- // Note: the default will be used if the level requested (such as `device`) does not have a string defined here.
- "default": _td("Change something"),
- }
-}
-```
-
-Settings that support the config level can be set in the config file under the `settingDefaults` key (note that some settings, like the "theme" setting, are special cased in the config file):
+Settings that support the config level can be set in the config file under the `settingDefaults` key (note that some
+settings, like the "theme" setting, are special cased in the config file):
```json
{
...
@@ -119,39 +96,42 @@ for you. If a display name cannot be found, it will return `null`.
## Features
-Occasionally some parts of the application may be undergoing testing and are not quite production ready. These are
-commonly known to be behind a "labs flag". Features behind lab flags must go through the granular settings system, and
-look and act very much normal settings. The exception is that they must supply `isFeature: true` as part of the setting
-definition and should go through the helper functions on `SettingsStore`.
+Feature flags are just like regular settings with some underlying semantics for how they are meant to be used. Usually
+a feature flag is used when a portion of the application is under development or not ready for full release yet, such
+as new functionality or experimental ideas. In these cases, the feature name *should* be named with the `feature_*`
+convention and must be tagged with `isFeature: true` in the setting definition. By doing so, the feature will automatically
+appear in the "labs" section of the user's settings.
-Although features have levels and a default value, the calculation of those options is blocked by the feature's state.
-A feature's state is determined from the `SdkConfig` and is a little complex. If `enableLabs` (a legacy flag) is `true`
-then the feature's state is `labs`, if it is `false`, the state is `disable`. If `enableLabs` is not set then the state
-is determined from the `features` config, such as in the following:
+Features can be controlled at the config level using the following structure:
```json
"features": {
- "feature_lazyloading": "labs"
+ "feature_lazyloading": true
}
```
-In this example, `feature_lazyloading` is in the `labs` state. It may also be in the `enable` or `disable` state with a
-similar approach. If the state is invalid, the feature is in the `disable` state. A feature's levels are only calculated
-if it is in the `labs` state, therefore the default only applies in that scenario. If the state is `enable`, the feature
-is always-on.
-Once a feature flag has served its purpose, it is generally recommended to remove it and the associated feature flag
-checks. This would enable the feature implicitly as it is part of the application now.
+When `true`, the user will see the feature as enabled. Similarly, when `false` the user will see the feature as disabled.
+The user will only be able to change/see these states if `showLabsSettings: true` is in the config.
### Determining if a feature is enabled
-A simple call to `SettingsStore.isFeatureEnabled` will tell you if the feature is enabled. This will perform all the
-required calculations to determine if the feature is enabled based upon the configuration and user selection.
+Call `SettingsStore.getValue()` as you would for any other setting.
### Enabling a feature
-Features can only be enabled if the feature is in the `labs` state, otherwise this is a no-op. To find the current set
-of features in the `labs` state, call `SettingsStore.getLabsFeatures`. To set the value, call
-`SettingsStore.setFeatureEnabled`.
+Call `SettingsStore.setValue("feature_name", null, SettingLevel.DEVICE, true)`.
+### A note on UI features
+
+UI features are a different concept to plain features. Instead of being representative of unstable or
+unpredicatable behaviour, they are logical chunks of UI which can be disabled by deployments for ease
+of understanding with users. They are simply represented as boring settings with a convention of being
+named as `UIFeature.$location` where `$location` is a rough descriptor of what is toggled, such as
+`URLPreviews` or `Communities`.
+
+UI features also tend to have their own setting controller (see below) to manipulate settings which might
+be affected by the UI feature being disabled. For example, if URL previews are disabled as a UI feature
+then the URL preview options will use the `UIFeatureController` to ensure they remain disabled while the
+UI feature is disabled.
## Setting controllers
@@ -162,7 +142,7 @@ kept up to date with the setting where it is otherwise not possible. An example
they can only be considered enabled if the platform supports notifications, and enabling notifications requires
additional steps to actually enable notifications.
-For more information, see `src/settings/controllers/SettingController.js`.
+For more information, see `src/settings/controllers/SettingController.ts`.
## Local echo
@@ -222,7 +202,7 @@ The `SettingsStore` uses the hardcoded `LEVEL_ORDER` constant to ensure that it
The array is checked from left to right, simulating the behaviour of overriding values from the higher levels. Each
level should be defined in this array, including `default`.
-Handlers (`src/settings/handlers/SettingsHandler.js`) represent a single level and are responsible for getting and
+Handlers (`src/settings/handlers/SettingsHandler.ts`) represent a single level and are responsible for getting and
setting values at that level. Handlers also provide additional information to the `SettingsStore` such as if the level
is supported or if the current user may set values at the level. The `SettingsStore` will use the handler to enforce
checks and manipulate settings. Handlers are also responsible for dealing with migration patterns or legacy settings for
@@ -230,7 +210,7 @@ their level (for example, a setting being renamed or using a different key from
Handlers are provided to the `SettingsStore` via the `LEVEL_HANDLERS` constant. `SettingsStore` will optimize lookups by
only considering handlers that are supported on the platform.
-Local echo is achieved through `src/settings/handlers/LocalEchoWrapper.js` which acts as a wrapper around a given
+Local echo is achieved through `src/settings/handlers/LocalEchoWrapper.ts` which acts as a wrapper around a given
handler. This is automatically applied to all defined `LEVEL_HANDLERS` and proxies the calls to the wrapped handler
where possible. The echo is achieved by a simple object cache stored within the class itself. The cache is invalidated
immediately upon the proxied save call succeeding or failing.
@@ -240,20 +220,7 @@ Controllers are notified of changes by the `SettingsStore`, and are given the op
### Features
-Features automatically get considered as `disabled` if they are not listed in the `SdkConfig` or `enableLabs` is
-false/not set. Features are always checked against the configuration before going through the level order as they have
-the option of being forced-on or forced-off for the application. This is done by the `features` section and looks
-something like this:
-
-```
-"features": {
- "feature_groups": "enable",
- "feature_pinning": "disable", // the default
- "feature_presence": "labs"
-}
-```
-
-If `enableLabs` is true in the configuration, the default for features becomes `"labs"`.
+See above for feature reference.
### Watchers
@@ -271,4 +238,3 @@ In practice, handlers which rely on remote changes (account data, room events, e
generalized `WatchManager` - a class specifically designed to deduplicate the logic of managing watchers. The handlers
which are localized to the local client (device) generally just trigger the `WatchManager` when they manipulate the
setting themselves as there's nothing to really 'watch'.
-
diff --git a/docs/widget-layouts.md b/docs/widget-layouts.md
new file mode 100644
index 0000000000..e7f72e2001
--- /dev/null
+++ b/docs/widget-layouts.md
@@ -0,0 +1,60 @@
+# Widget layout support
+
+Rooms can have a default widget layout to auto-pin certain widgets, make the container different
+sizes, etc. These are defined through the `io.element.widgets.layout` state event (empty state key).
+
+Full example content:
+```json5
+{
+ "widgets": {
+ "first-widget-id": {
+ "container": "top",
+ "index": 0,
+ "width": 60,
+ "height": 40
+ },
+ "second-widget-id": {
+ "container": "right"
+ }
+ }
+}
+```
+
+As shown, there are two containers possible for widgets. These containers have different behaviour
+and interpret the other options differently.
+
+## `top` container
+
+This is the "App Drawer" or any pinned widgets in a room. This is by far the most versatile container
+though does introduce potential usability issues upon members of the room (widgets take up space and
+therefore fewer messages can be shown).
+
+The `index` for a widget determines which order the widgets show up in from left to right. Widgets
+without an `index` will show up as the rightmost widgets. Tiebreaks (same `index` or multiple defined
+without an `index`) are resolved by comparing widget IDs. A maximum of 3 widgets can be in the top
+container - any which exceed this will be ignored (placed into the `right` container). Smaller numbers
+represent leftmost widgets.
+
+The `width` is relative width within the container in percentage points. This will be clamped to a
+range of 0-100 (inclusive). The widgets will attempt to scale to relative proportions when more than
+100% space is allocated. For example, if 3 widgets are defined at 40% width each then the client will
+attempt to show them at 33% width each.
+
+Note that the client may impose minimum widths on the widgets, such as a 10% minimum to avoid pinning
+hidden widgets. In general, widgets defined in the 30-70% range each will be free of these restrictions.
+
+The `height` is not in fact applied per-widget but is recorded per-widget for potential future
+capabilities in future containers. The top container will take the tallest `height` and use that for
+the height of the whole container, and thus all widgets in that container. The `height` is relative
+to the container, like with `width`, meaning that 100% will consume as much space as the client is
+willing to sacrifice to the widget container. Like with `width`, the client may impose minimums to avoid
+the container being uselessly small. Heights in the 30-100% range are generally acceptable. The height
+is also clamped to be within 0-100, inclusive.
+
+## `right` container
+
+This is the default container and has no special configuration. Widgets which overflow from the top
+container will be put in this container instead. Putting a widget in the right container does not
+automatically show it - it only mentions that widgets should not be in another container.
+
+The behaviour of this container may change in the future.
diff --git a/package.json b/package.json
index 989672d414..33999e3735 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
- "version": "3.1.0",
+ "version": "3.21.0",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {
@@ -23,18 +23,17 @@
"package.json"
],
"bin": {
- "reskindex": "scripts/reskindex.js",
- "matrix-gen-i18n": "scripts/gen-i18n.js",
- "matrix-prune-i18n": "scripts/prune-i18n.js"
+ "reskindex": "scripts/reskindex.js"
},
- "main": "./lib/index.js",
- "typings": "./lib/index.d.ts",
+ "main": "./src/index.js",
"matrix_src_main": "./src/index.js",
+ "matrix_lib_main": "./lib/index.js",
+ "matrix_lib_typings": "./lib/index.d.ts",
"scripts": {
- "prepare": "yarn build",
+ "prepublishOnly": "yarn build",
"i18n": "matrix-gen-i18n",
"prunei18n": "matrix-prune-i18n",
- "diff-i18n": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && ./scripts/gen-i18n.js && node scripts/compare-file.js src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
+ "diff-i18n": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && matrix-gen-i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
"reskindex": "node scripts/reskindex.js -h header",
"reskindex:watch": "node scripts/reskindex.js -h header -w",
"rethemendex": "res/css/rethemendex.sh",
@@ -50,125 +49,135 @@
"lint:types": "tsc --noEmit --jsx react",
"lint:style": "stylelint 'res/css/**/*.scss'",
"test": "jest",
- "test:e2e": "./test/end-to-end-tests/run.sh --riot-url http://localhost:8080"
+ "test:e2e": "./test/end-to-end-tests/run.sh --app-url http://localhost:8080",
+ "coverage": "yarn test --coverage"
},
"dependencies": {
- "@babel/runtime": "^7.10.5",
- "await-lock": "^2.0.1",
- "blueimp-canvas-to-blob": "^3.27.0",
+ "@babel/runtime": "^7.12.5",
+ "await-lock": "^2.1.0",
+ "blueimp-canvas-to-blob": "^3.28.0",
"blurhash": "^1.1.3",
"browser-encrypt-attachment": "^0.3.0",
"browser-request": "^0.3.3",
+ "cheerio": "^1.0.0-rc.9",
"classnames": "^2.2.6",
- "commonmark": "^0.29.1",
+ "commonmark": "^0.29.3",
"counterpart": "^0.18.6",
- "create-react-class": "^15.6.3",
- "diff-dom": "^4.1.6",
+ "diff-dom": "^4.2.2",
"diff-match-patch": "^1.0.5",
- "emojibase-data": "^5.0.1",
- "emojibase-regex": "^4.0.1",
+ "emojibase-data": "^5.1.1",
+ "emojibase-regex": "^4.1.1",
"escape-html": "^1.0.3",
- "file-saver": "^1.3.8",
- "filesize": "3.6.1",
+ "file-saver": "^2.0.5",
+ "filesize": "6.1.0",
"flux": "2.1.1",
- "focus-visible": "^5.1.0",
- "fuse.js": "^2.7.4",
+ "focus-visible": "^5.2.0",
"gfm.css": "^1.1.2",
"glob-to-regexp": "^0.4.1",
- "highlight.js": "^10.1.2",
- "html-entities": "^1.3.1",
- "is-ip": "^2.0.0",
+ "highlight.js": "^10.5.0",
+ "html-entities": "^1.4.0",
+ "is-ip": "^3.1.0",
+ "katex": "^0.12.0",
"linkifyjs": "^2.1.9",
- "lodash": "^4.17.19",
+ "lodash": "^4.17.20",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
+ "matrix-widget-api": "^0.1.0-beta.14",
"minimist": "^1.2.5",
- "pako": "^1.0.11",
- "parse5": "^5.1.1",
+ "opus-recorder": "^8.0.3",
+ "pako": "^2.0.3",
+ "parse5": "^6.0.1",
"png-chunks-extract": "^1.0.0",
- "project-name-generator": "^2.1.7",
"prop-types": "^15.7.2",
"qrcode": "^1.4.4",
- "qs": "^6.9.4",
- "re-resizable": "^6.5.4",
- "react": "^16.13.1",
+ "qs": "^6.9.6",
+ "re-resizable": "^6.9.0",
+ "react": "^16.14.0",
"react-beautiful-dnd": "^4.0.1",
- "react-dom": "^16.13.1",
- "react-focus-lock": "^2.4.1",
+ "react-dom": "^16.14.0",
+ "react-focus-lock": "^2.5.0",
"react-transition-group": "^4.4.1",
"resize-observer-polyfill": "^1.5.1",
- "sanitize-html": "^1.27.1",
+ "rfc4648": "^1.4.0",
+ "sanitize-html": "^2.3.2",
+ "tar-js": "^0.3.0",
"text-encoding-utf-8": "^1.0.2",
"url": "^0.11.0",
- "velocity-animate": "^1.5.2",
"what-input": "^5.2.10",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
- "@babel/cli": "^7.10.5",
- "@babel/core": "^7.10.5",
- "@babel/parser": "^7.11.0",
- "@babel/plugin-proposal-class-properties": "^7.10.4",
- "@babel/plugin-proposal-decorators": "^7.10.5",
- "@babel/plugin-proposal-export-default-from": "^7.10.4",
- "@babel/plugin-proposal-numeric-separator": "^7.10.4",
- "@babel/plugin-proposal-object-rest-spread": "^7.10.4",
- "@babel/plugin-transform-flow-comments": "^7.10.4",
- "@babel/plugin-transform-runtime": "^7.10.5",
- "@babel/preset-env": "^7.10.4",
- "@babel/preset-flow": "^7.10.4",
- "@babel/preset-react": "^7.10.4",
- "@babel/preset-typescript": "^7.10.4",
- "@babel/register": "^7.10.5",
- "@babel/traverse": "^7.11.0",
- "@peculiar/webcrypto": "^1.1.2",
- "@types/classnames": "^2.2.10",
+ "@babel/cli": "^7.12.10",
+ "@babel/core": "^7.12.10",
+ "@babel/parser": "^7.12.11",
+ "@babel/plugin-proposal-class-properties": "^7.12.1",
+ "@babel/plugin-proposal-decorators": "^7.12.12",
+ "@babel/plugin-proposal-export-default-from": "^7.12.1",
+ "@babel/plugin-proposal-numeric-separator": "^7.12.7",
+ "@babel/plugin-proposal-object-rest-spread": "^7.12.1",
+ "@babel/plugin-transform-flow-comments": "^7.12.1",
+ "@babel/plugin-transform-runtime": "^7.12.10",
+ "@babel/preset-env": "^7.12.11",
+ "@babel/preset-flow": "^7.12.1",
+ "@babel/preset-react": "^7.12.10",
+ "@babel/preset-typescript": "^7.12.7",
+ "@babel/register": "^7.12.10",
+ "@babel/traverse": "^7.12.12",
+ "@peculiar/webcrypto": "^1.1.4",
+ "@sinonjs/fake-timers": "^7.0.2",
+ "@types/classnames": "^2.2.11",
"@types/counterpart": "^0.18.1",
"@types/flux": "^3.1.9",
+ "@types/jest": "^26.0.20",
"@types/linkifyjs": "^2.1.3",
- "@types/lodash": "^4.14.158",
+ "@types/lodash": "^4.14.168",
"@types/modernizr": "^3.5.3",
- "@types/node": "^12.12.51",
- "@types/qrcode": "^1.3.4",
+ "@types/node": "^14.14.22",
+ "@types/pako": "^1.0.1",
+ "@types/parse5": "^6.0.0",
+ "@types/qrcode": "^1.3.5",
"@types/react": "^16.9",
- "@types/react-dom": "^16.9.8",
+ "@types/react-dom": "^16.9.10",
"@types/react-transition-group": "^4.4.0",
- "@types/sanitize-html": "^1.23.3",
+ "@types/sanitize-html": "^2.3.1",
"@types/zxcvbn": "^4.4.0",
- "@typescript-eslint/eslint-plugin": "^3.7.0",
- "@typescript-eslint/parser": "^3.7.0",
+ "@typescript-eslint/eslint-plugin": "^4.14.0",
+ "@typescript-eslint/parser": "^4.14.0",
"babel-eslint": "^10.1.0",
- "babel-jest": "^24.9.0",
- "chokidar": "^3.4.1",
- "concurrently": "^4.1.2",
+ "babel-jest": "^26.6.3",
+ "chokidar": "^3.5.1",
+ "concurrently": "^5.3.0",
"enzyme": "^3.11.0",
- "enzyme-adapter-react-16": "^1.15.2",
- "eslint": "7.5.0",
- "eslint-config-matrix-org": "^0.1.2",
+ "enzyme-adapter-react-16": "^1.15.6",
+ "eslint": "7.18.0",
+ "eslint-config-matrix-org": "^0.2.0",
"eslint-plugin-babel": "^5.3.1",
- "eslint-plugin-flowtype": "^2.50.3",
- "eslint-plugin-react": "^7.20.3",
- "eslint-plugin-react-hooks": "^2.5.1",
- "file-loader": "^3.0.1",
- "glob": "^5.0.15",
- "jest": "^24.9.0",
- "jest-canvas-mock": "^2.2.0",
- "lolex": "^5.1.2",
+ "eslint-plugin-flowtype": "^5.2.0",
+ "eslint-plugin-react": "^7.22.0",
+ "eslint-plugin-react-hooks": "^4.2.0",
+ "glob": "^7.1.6",
+ "jest": "^26.6.3",
+ "jest-canvas-mock": "^2.3.0",
+ "jest-environment-jsdom-sixteen": "^1.0.3",
+ "jest-fetch-mock": "^3.0.3",
"matrix-mock-request": "^1.2.3",
"matrix-react-test-utils": "^0.2.2",
- "react-test-renderer": "^16.13.1",
- "rimraf": "^2.7.1",
- "source-map-loader": "^0.2.4",
- "stylelint": "^9.10.1",
- "stylelint-config-standard": "^18.3.0",
+ "matrix-web-i18n": "github:matrix-org/matrix-web-i18n",
+ "olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz",
+ "react-test-renderer": "^16.14.0",
+ "rimraf": "^3.0.2",
+ "stylelint": "^13.9.0",
+ "stylelint-config-standard": "^20.0.0",
"stylelint-scss": "^3.18.0",
- "typescript": "^3.9.7",
- "walk": "^2.3.14",
- "webpack": "^4.43.0",
- "webpack-cli": "^3.3.12"
+ "typescript": "^4.1.3",
+ "walk": "^2.3.14"
+ },
+ "resolutions": {
+ "**/@types/react": "^16.14"
},
"jest": {
+ "testEnvironment": "./__test-utils__/environment.js",
"testMatch": [
- "/test/**/*-test.js"
+ "/test/**/*-test.[jt]s"
],
"setupFiles": [
"jest-canvas-mock"
@@ -178,10 +187,19 @@
],
"moduleNameMapper": {
"\\.(gif|png|svg|ttf|woff2)$": "/__mocks__/imageMock.js",
- "\\$webapp/i18n/languages.json": "/__mocks__/languages.json"
+ "\\$webapp/i18n/languages.json": "/__mocks__/languages.json",
+ "decoderWorker\\.min\\.js": "/__mocks__/empty.js",
+ "decoderWorker\\.min\\.wasm": "/__mocks__/empty.js",
+ "waveWorker\\.min\\.js": "/__mocks__/empty.js"
},
"transformIgnorePatterns": [
"/node_modules/(?!matrix-js-sdk).+$"
+ ],
+ "collectCoverageFrom": [
+ "/src/**/*.{js,ts,tsx}"
+ ],
+ "coverageReporters": [
+ "text"
]
}
}
diff --git a/release.sh b/release.sh
index 23b8822041..4742f00dea 100755
--- a/release.sh
+++ b/release.sh
@@ -9,6 +9,9 @@ set -e
cd `dirname $0`
+# This link seems to get eaten by the release process, so ensure it exists.
+yarn link matrix-js-sdk
+
for i in matrix-js-sdk
do
echo "Checking version of $i..."
@@ -29,9 +32,7 @@ do
echo "Upgrading $i to $latestver..."
yarn add -E $i@$latestver
git add -u
- # The `-e` flag opens the editor and gives you a chance to check
- # the upgrade for correctness.
- git commit -m "Upgrade $i to $latestver" -e
+ git commit -m "Upgrade $i to $latestver"
fi
fi
done
diff --git a/res/css/_common.scss b/res/css/_common.scss
index 47aa295540..d6f85edb86 100644
--- a/res/css/_common.scss
+++ b/res/css/_common.scss
@@ -17,9 +17,27 @@ limitations under the License.
*/
@import "./_font-sizes.scss";
+@import "./_font-weights.scss";
+
+$hover-transition: 0.08s cubic-bezier(.46, .03, .52, .96); // quadratic
+
+$EventTile_e2e_state_indicator_width: 4px;
+
+$MessageTimestamp_width: 46px; /* 8 + 30 (avatar) + 8 */
+$MessageTimestamp_width_hover: calc($MessageTimestamp_width - 2 * $EventTile_e2e_state_indicator_width);
:root {
font-size: 10px;
+
+ --transition-short: .1s;
+ --transition-standard: .3s;
+}
+
+@media (prefers-reduced-motion) {
+ :root {
+ --transition-short: 0;
+ --transition-standard: 0;
+ }
}
html {
@@ -57,6 +75,10 @@ pre, code {
color: $accent-color;
}
+.text-muted {
+ color: $muted-fg-color;
+}
+
b {
// On Firefox, the default weight for `` is `bolder` which results in no bold
// effect since we only have specific weights of our fonts available.
@@ -163,7 +185,6 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
border: 1px solid rgba($primary-fg-color, .1);
// these things should probably not be defined globally
margin: 9px;
- flex: 0 0 auto;
}
.mx_textinput {
@@ -206,12 +227,6 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
border: 0;
}
-/* applied to side-panels and messagepanel when in RoomSettings */
-.mx_fadable {
- opacity: 1;
- transition: opacity 0.2s ease-in-out;
-}
-
// These are magic constants which are excluded from tinting, to let themes
// (which only have CSS, unlike skins) tell the app what their non-tinted
// colourscheme is by inspecting the stylesheet DOM.
@@ -260,7 +275,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
font-weight: 300;
font-size: $font-15px;
position: relative;
- padding: 25px 30px 30px 30px;
+ padding: 24px;
max-height: 80%;
box-shadow: 2px 15px 30px 0 $dialog-shadow-color;
border-radius: 8px;
@@ -298,7 +313,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
}
.mx_Dialog_lightbox .mx_Dialog_background {
- opacity: 0.85;
+ opacity: $lightbox-background-bg-opacity;
background-color: $lightbox-background-bg-color;
}
@@ -310,6 +325,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
max-width: 100%;
max-height: 100%;
pointer-events: none;
+ padding: 0;
}
.mx_Dialog_header {
@@ -327,6 +343,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
.mx_Dialog_title {
font-size: $font-22px;
+ font-weight: $font-semi-bold;
line-height: $font-36px;
color: $dialog-title-fg-color;
}
@@ -352,8 +369,8 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
background-color: $dialog-close-fg-color;
cursor: pointer;
position: absolute;
- top: 4px;
- right: 0px;
+ top: 10px;
+ right: 0;
}
.mx_Dialog_content {
@@ -366,6 +383,11 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
.mx_Dialog_buttons {
margin-top: 20px;
text-align: right;
+
+ .mx_Dialog_buttons_additive {
+ // The consumer is responsible for positioning their elements.
+ float: left;
+ }
}
/* XXX: Our button style are a mess: buttons that happen to appear in dialogs get special styles applied
@@ -384,6 +406,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
border: 1px solid $accent-color;
color: $accent-color;
background-color: $button-secondary-bg-color;
+ font-family: inherit;
}
.mx_Dialog button:last-child {
@@ -478,54 +501,6 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
margin-top: 69px;
}
-.mx_Beta {
- color: red;
- margin-right: 10px;
- position: relative;
- top: -3px;
- background-color: white;
- padding: 0 4px;
- border-radius: 3px;
- border: 1px solid darkred;
- cursor: help;
- transition-duration: 200ms;
- font-size: smaller;
- filter: opacity(0.5);
-}
-
-.mx_Beta:hover {
- color: white;
- border: 1px solid gray;
- background-color: darkred;
-}
-
-.mx_TintableSvgButton {
- position: relative;
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-content: center;
-}
-
-.mx_TintableSvgButton object {
- margin: 0;
- padding: 0;
- width: 100%;
- height: 100%;
- max-width: 100%;
- max-height: 100%;
-}
-
-.mx_TintableSvgButton span {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- opacity: 0;
- cursor: pointer;
-}
-
// username colors
// used by SenderProfile & RoomPreviewBar
.mx_Username_color1 {
@@ -595,6 +570,13 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
}
}
+@define-mixin ProgressBarBgColour $colour {
+ background-color: $colour;
+ &::-webkit-progress-bar {
+ background-color: $colour;
+ }
+}
+
@define-mixin ProgressBarBorderRadius $radius {
border-radius: $radius;
&::-moz-progress-bar {
@@ -605,3 +587,15 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
border-radius: $radius;
}
}
+
+@define-mixin unreal-focus {
+ outline-width: 2px;
+ outline-style: solid;
+ outline-color: Highlight;
+
+ /* WebKit gets its native focus styles. */
+ @media (-webkit-min-device-pixel-ratio: 0) {
+ outline-color: -webkit-focus-ring-color;
+ outline-style: auto;
+ }
+}
diff --git a/res/css/_components.scss b/res/css/_components.scss
index 0dc267e130..c8985cbb51 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -1,6 +1,7 @@
// autogenerated by rethemendex.sh
@import "./_common.scss";
@import "./_font-sizes.scss";
+@import "./_font-weights.scss";
@import "./structures/_AutoHideScrollbar.scss";
@import "./structures/_CompatibilityPage.scss";
@import "./structures/_ContextualMenu.scss";
@@ -8,10 +9,12 @@
@import "./structures/_CustomRoomTagPanel.scss";
@import "./structures/_FilePanel.scss";
@import "./structures/_GenericErrorPage.scss";
+@import "./structures/_GroupFilterPanel.scss";
@import "./structures/_GroupView.scss";
@import "./structures/_HeaderButtons.scss";
@import "./structures/_HomePage.scss";
@import "./structures/_LeftPanel.scss";
+@import "./structures/_LeftPanelWidget.scss";
@import "./structures/_MainSplit.scss";
@import "./structures/_MatrixChat.scss";
@import "./structures/_MyGroups.scss";
@@ -24,8 +27,10 @@
@import "./structures/_RoomView.scss";
@import "./structures/_ScrollPanel.scss";
@import "./structures/_SearchBox.scss";
+@import "./structures/_SpacePanel.scss";
+@import "./structures/_SpaceRoomDirectory.scss";
+@import "./structures/_SpaceRoomView.scss";
@import "./structures/_TabbedView.scss";
-@import "./structures/_TagPanel.scss";
@import "./structures/_ToastContainer.scss";
@import "./structures/_UploadBar.scss";
@import "./structures/_UserMenu.scss";
@@ -43,72 +48,87 @@
@import "./views/auth/_InteractiveAuthEntryComponents.scss";
@import "./views/auth/_LanguageSelector.scss";
@import "./views/auth/_PassphraseField.scss";
-@import "./views/auth/_ServerConfig.scss";
-@import "./views/auth/_ServerTypeSelector.scss";
@import "./views/auth/_Welcome.scss";
@import "./views/avatars/_BaseAvatar.scss";
@import "./views/avatars/_DecoratedRoomAvatar.scss";
@import "./views/avatars/_MemberStatusMessageAvatar.scss";
@import "./views/avatars/_PulsedAvatar.scss";
+@import "./views/avatars/_WidgetAvatar.scss";
+@import "./views/beta/_BetaCard.scss";
+@import "./views/context_menus/_CallContextMenu.scss";
@import "./views/context_menus/_IconizedContextMenu.scss";
@import "./views/context_menus/_MessageContextMenu.scss";
-@import "./views/context_menus/_RoomTileContextMenu.scss";
@import "./views/context_menus/_StatusMessageContextMenu.scss";
@import "./views/context_menus/_TagTileContextMenu.scss";
-@import "./views/context_menus/_TopLeftMenu.scss";
-@import "./views/context_menus/_WidgetContextMenu.scss";
+@import "./views/dialogs/_AddExistingToSpaceDialog.scss";
@import "./views/dialogs/_AddressPickerDialog.scss";
@import "./views/dialogs/_Analytics.scss";
+@import "./views/dialogs/_BetaFeedbackDialog.scss";
+@import "./views/dialogs/_BugReportDialog.scss";
@import "./views/dialogs/_ChangelogDialog.scss";
@import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss";
+@import "./views/dialogs/_CommunityPrototypeInviteDialog.scss";
@import "./views/dialogs/_ConfirmUserActionDialog.scss";
+@import "./views/dialogs/_CreateCommunityPrototypeDialog.scss";
@import "./views/dialogs/_CreateGroupDialog.scss";
@import "./views/dialogs/_CreateRoomDialog.scss";
@import "./views/dialogs/_DeactivateAccountDialog.scss";
@import "./views/dialogs/_DevtoolsDialog.scss";
+@import "./views/dialogs/_EditCommunityPrototypeDialog.scss";
+@import "./views/dialogs/_FeedbackDialog.scss";
@import "./views/dialogs/_GroupAddressPicker.scss";
+@import "./views/dialogs/_HostSignupDialog.scss";
@import "./views/dialogs/_IncomingSasDialog.scss";
@import "./views/dialogs/_InviteDialog.scss";
@import "./views/dialogs/_KeyboardShortcutsDialog.scss";
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
+@import "./views/dialogs/_ModalWidgetDialog.scss";
@import "./views/dialogs/_NewSessionReviewDialog.scss";
-@import "./views/dialogs/_RebrandDialog.scss";
+@import "./views/dialogs/_RegistrationEmailPromptDialog.scss";
@import "./views/dialogs/_RoomSettingsDialog.scss";
@import "./views/dialogs/_RoomSettingsDialogBridges.scss";
@import "./views/dialogs/_RoomUpgradeDialog.scss";
@import "./views/dialogs/_RoomUpgradeWarningDialog.scss";
@import "./views/dialogs/_ServerOfflineDialog.scss";
+@import "./views/dialogs/_ServerPickerDialog.scss";
@import "./views/dialogs/_SetEmailDialog.scss";
-@import "./views/dialogs/_SetMxIdDialog.scss";
-@import "./views/dialogs/_SetPasswordDialog.scss";
@import "./views/dialogs/_SettingsDialog.scss";
@import "./views/dialogs/_ShareDialog.scss";
@import "./views/dialogs/_SlashCommandHelpDialog.scss";
+@import "./views/dialogs/_SpaceSettingsDialog.scss";
@import "./views/dialogs/_TabbedIntegrationManagerDialog.scss";
@import "./views/dialogs/_TermsDialog.scss";
+@import "./views/dialogs/_UntrustedDeviceDialog.scss";
@import "./views/dialogs/_UploadConfirmDialog.scss";
@import "./views/dialogs/_UserSettingsDialog.scss";
+@import "./views/dialogs/_WidgetCapabilitiesPromptDialog.scss";
@import "./views/dialogs/_WidgetOpenIDPermissionsDialog.scss";
-@import "./views/dialogs/keybackup/_CreateKeyBackupDialog.scss";
-@import "./views/dialogs/keybackup/_KeyBackupFailedDialog.scss";
-@import "./views/dialogs/keybackup/_RestoreKeyBackupDialog.scss";
-@import "./views/dialogs/secretstorage/_AccessSecretStorageDialog.scss";
-@import "./views/dialogs/secretstorage/_CreateSecretStorageDialog.scss";
+@import "./views/dialogs/security/_AccessSecretStorageDialog.scss";
+@import "./views/dialogs/security/_CreateCrossSigningDialog.scss";
+@import "./views/dialogs/security/_CreateKeyBackupDialog.scss";
+@import "./views/dialogs/security/_CreateSecretStorageDialog.scss";
+@import "./views/dialogs/security/_KeyBackupFailedDialog.scss";
+@import "./views/dialogs/security/_RestoreKeyBackupDialog.scss";
@import "./views/directory/_NetworkDropdown.scss";
@import "./views/elements/_AccessibleButton.scss";
@import "./views/elements/_AddressSelector.scss";
@import "./views/elements/_AddressTile.scss";
+@import "./views/elements/_DesktopBuildsNotice.scss";
+@import "./views/elements/_DesktopCapturerSourcePicker.scss";
@import "./views/elements/_DirectorySearchBox.scss";
@import "./views/elements/_Dropdown.scss";
@import "./views/elements/_EditableItemList.scss";
@import "./views/elements/_ErrorBoundary.scss";
@import "./views/elements/_EventListSummary.scss";
+@import "./views/elements/_FacePile.scss";
@import "./views/elements/_Field.scss";
@import "./views/elements/_FormButton.scss";
-@import "./views/elements/_IconButton.scss";
@import "./views/elements/_ImageView.scss";
+@import "./views/elements/_InfoTooltip.scss";
@import "./views/elements/_InlineSpinner.scss";
+@import "./views/elements/_InviteReason.scss";
@import "./views/elements/_ManageIntegsButton.scss";
+@import "./views/elements/_MiniAvatarUploader.scss";
@import "./views/elements/_PowerSelector.scss";
@import "./views/elements/_ProgressBar.scss";
@import "./views/elements/_QRCode.scss";
@@ -117,6 +137,8 @@
@import "./views/elements/_RichText.scss";
@import "./views/elements/_RoleButton.scss";
@import "./views/elements/_RoomAliasField.scss";
+@import "./views/elements/_SSOButtons.scss";
+@import "./views/elements/_ServerPicker.scss";
@import "./views/elements/_Slider.scss";
@import "./views/elements/_Spinner.scss";
@import "./views/elements/_StyledCheckbox.scss";
@@ -133,13 +155,16 @@
@import "./views/groups/_GroupUserSettings.scss";
@import "./views/messages/_CreateEvent.scss";
@import "./views/messages/_DateSeparator.scss";
+@import "./views/messages/_EventTileBubble.scss";
@import "./views/messages/_MEmoteBody.scss";
@import "./views/messages/_MFileBody.scss";
@import "./views/messages/_MImageBody.scss";
+@import "./views/messages/_MJitsiWidgetEvent.scss";
@import "./views/messages/_MNoticeBody.scss";
@import "./views/messages/_MStickerBody.scss";
@import "./views/messages/_MTextBody.scss";
@import "./views/messages/_MVideoBody.scss";
+@import "./views/messages/_MVoiceMessageBody.scss";
@import "./views/messages/_MessageActionBar.scss";
@import "./views/messages/_MessageTimestamp.scss";
@import "./views/messages/_MjolnirBody.scss";
@@ -152,11 +177,13 @@
@import "./views/messages/_UnknownBody.scss";
@import "./views/messages/_ViewSourceEvent.scss";
@import "./views/messages/_common_CryptoEvent.scss";
+@import "./views/right_panel/_BaseCard.scss";
@import "./views/right_panel/_EncryptionInfo.scss";
+@import "./views/right_panel/_RoomSummaryCard.scss";
@import "./views/right_panel/_UserInfo.scss";
@import "./views/right_panel/_VerificationPanel.scss";
+@import "./views/right_panel/_WidgetCard.scss";
@import "./views/room_settings/_AliasSettings.scss";
-@import "./views/room_settings/_ColorSettings.scss";
@import "./views/rooms/_AppsDrawer.scss";
@import "./views/rooms/_Autocomplete.scss";
@import "./views/rooms/_AuxPanel.scss";
@@ -173,6 +200,7 @@
@import "./views/rooms/_MemberList.scss";
@import "./views/rooms/_MessageComposer.scss";
@import "./views/rooms/_MessageComposerFormatBar.scss";
+@import "./views/rooms/_NewRoomIntro.scss";
@import "./views/rooms/_NotificationBadge.scss";
@import "./views/rooms/_PinnedEventTile.scss";
@import "./views/rooms/_PinnedEventsPanel.scss";
@@ -182,15 +210,14 @@
@import "./views/rooms/_RoomHeader.scss";
@import "./views/rooms/_RoomList.scss";
@import "./views/rooms/_RoomPreviewBar.scss";
-@import "./views/rooms/_RoomRecoveryReminder.scss";
@import "./views/rooms/_RoomSublist.scss";
@import "./views/rooms/_RoomTile.scss";
-@import "./views/rooms/_RoomTileIcon.scss";
@import "./views/rooms/_RoomUpgradeWarningBar.scss";
@import "./views/rooms/_SearchBar.scss";
@import "./views/rooms/_SendMessageComposer.scss";
@import "./views/rooms/_Stickers.scss";
@import "./views/rooms/_TopUnreadMessagesBar.scss";
+@import "./views/rooms/_VoiceRecordComposerTile.scss";
@import "./views/rooms/_WhoIsTypingTile.scss";
@import "./views/settings/_AvatarSetting.scss";
@import "./views/settings/_CrossSigningPanel.scss";
@@ -198,12 +225,13 @@
@import "./views/settings/_E2eAdvancedPanel.scss";
@import "./views/settings/_EmailAddresses.scss";
@import "./views/settings/_IntegrationManager.scss";
-@import "./views/settings/_KeyBackupPanel.scss";
@import "./views/settings/_Notifications.scss";
@import "./views/settings/_PhoneNumbers.scss";
@import "./views/settings/_ProfileSettings.scss";
+@import "./views/settings/_SecureBackupPanel.scss";
@import "./views/settings/_SetIdServer.scss";
@import "./views/settings/_SetIntegrationManager.scss";
+@import "./views/settings/_SpellCheckLanguages.scss";
@import "./views/settings/_UpdateCheckButton.scss";
@import "./views/settings/tabs/_SettingsTab.scss";
@import "./views/settings/tabs/room/_GeneralRoomSettingsTab.scss";
@@ -212,14 +240,26 @@
@import "./views/settings/tabs/user/_AppearanceUserSettingsTab.scss";
@import "./views/settings/tabs/user/_GeneralUserSettingsTab.scss";
@import "./views/settings/tabs/user/_HelpUserSettingsTab.scss";
+@import "./views/settings/tabs/user/_LabsUserSettingsTab.scss";
@import "./views/settings/tabs/user/_MjolnirUserSettingsTab.scss";
@import "./views/settings/tabs/user/_NotificationUserSettingsTab.scss";
@import "./views/settings/tabs/user/_PreferencesUserSettingsTab.scss";
@import "./views/settings/tabs/user/_SecurityUserSettingsTab.scss";
@import "./views/settings/tabs/user/_VoiceUserSettingsTab.scss";
+@import "./views/spaces/_SpaceBasicSettings.scss";
+@import "./views/spaces/_SpaceCreateMenu.scss";
+@import "./views/spaces/_SpacePublicShare.scss";
@import "./views/terms/_InlineTermsAgreement.scss";
+@import "./views/toasts/_AnalyticsToast.scss";
@import "./views/toasts/_NonUrgentEchoFailureToast.scss";
@import "./views/verification/_VerificationShowSas.scss";
+@import "./views/voice_messages/_PlayPauseButton.scss";
+@import "./views/voice_messages/_PlaybackContainer.scss";
+@import "./views/voice_messages/_Waveform.scss";
@import "./views/voip/_CallContainer.scss";
@import "./views/voip/_CallView.scss";
-@import "./views/voip/_VideoView.scss";
+@import "./views/voip/_CallViewForRoom.scss";
+@import "./views/voip/_DialPad.scss";
+@import "./views/voip/_DialPadContextMenu.scss";
+@import "./views/voip/_DialPadModal.scss";
+@import "./views/voip/_VideoFeed.scss";
diff --git a/src/resizer/index.js b/res/css/_font-weights.scss
similarity index 70%
rename from src/resizer/index.js
rename to res/css/_font-weights.scss
index 1fd8f4da46..3e2b19d516 100644
--- a/src/resizer/index.js
+++ b/res/css/_font-weights.scss
@@ -1,6 +1,5 @@
/*
-Copyright 2018 New Vector Ltd
-Copyright 2019 The Matrix.org Foundation C.I.C.
+Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,6 +14,4 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-export FixedDistributor from "./distributors/fixed";
-export CollapseDistributor from "./distributors/collapse";
-export Resizer from "./resizer";
+$font-semi-bold: 600;
diff --git a/res/css/structures/_CustomRoomTagPanel.scss b/res/css/structures/_CustomRoomTagPanel.scss
index 3feb2565be..be1138cf5b 100644
--- a/res/css/structures/_CustomRoomTagPanel.scss
+++ b/res/css/structures/_CustomRoomTagPanel.scss
@@ -16,13 +16,8 @@ limitations under the License.
// TODO: Update design for custom tags to match new designs
-.mx_LeftPanel_tagPanelContainer {
- display: flex;
- flex-direction: column;
-}
-
.mx_CustomRoomTagPanel {
- background-color: $tagpanel-bg-color;
+ background-color: $groupFilterPanel-bg-color;
max-height: 40vh;
}
diff --git a/res/css/structures/_FilePanel.scss b/res/css/structures/_FilePanel.scss
index 50b01b4a14..7b975110e1 100644
--- a/res/css/structures/_FilePanel.scss
+++ b/res/css/structures/_FilePanel.scss
@@ -22,7 +22,13 @@ limitations under the License.
}
.mx_FilePanel .mx_RoomView_messageListWrapper {
- margin-right: 20px;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+}
+
+.mx_FilePanel .mx_RoomView_MessageList {
+ width: 100%;
}
.mx_FilePanel .mx_RoomView_MessageList h2 {
@@ -41,13 +47,19 @@ limitations under the License.
.mx_FilePanel .mx_EventTile {
word-break: break-word;
+ margin-top: 32px;
}
.mx_FilePanel .mx_EventTile .mx_MImageBody {
margin-right: 0px;
}
+.mx_FilePanel .mx_EventTile .mx_MFileBody {
+ line-height: 2.4rem;
+}
+
.mx_FilePanel .mx_EventTile .mx_MFileBody_download {
+ padding-top: 8px;
display: flex;
font-size: $font-14px;
color: $event-timestamp-color;
@@ -60,7 +72,7 @@ limitations under the License.
.mx_FilePanel .mx_EventTile .mx_MImageBody_size {
flex: 1 0 0;
- font-size: $font-11px;
+ font-size: $font-14px;
text-align: right;
white-space: nowrap;
}
@@ -80,7 +92,7 @@ limitations under the License.
flex: 1 1 auto;
line-height: initial;
padding: 0px;
- font-size: $font-11px;
+ font-size: $font-14px;
opacity: 1.0;
color: $event-timestamp-color;
}
@@ -90,7 +102,7 @@ limitations under the License.
text-align: right;
visibility: visible;
position: initial;
- font-size: $font-11px;
+ font-size: $font-14px;
opacity: 1.0;
color: $event-timestamp-color;
}
diff --git a/res/css/structures/_TagPanel.scss b/res/css/structures/_GroupFilterPanel.scss
similarity index 56%
rename from res/css/structures/_TagPanel.scss
rename to res/css/structures/_GroupFilterPanel.scss
index 78e8326772..444435dd57 100644
--- a/res/css/structures/_TagPanel.scss
+++ b/res/css/structures/_GroupFilterPanel.scss
@@ -14,9 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_TagPanel {
+.mx_GroupFilterPanel {
flex: 1;
- background-color: $tagpanel-bg-color;
+ background-color: $groupFilterPanel-bg-color;
cursor: pointer;
display: flex;
@@ -26,63 +26,95 @@ limitations under the License.
min-height: 0;
}
-.mx_TagPanel_items_selected {
+.mx_GroupFilterPanel_items_selected {
cursor: pointer;
}
-.mx_TagPanel .mx_TagPanel_clearButton_container {
- /* Constant height within flex mx_TagPanel */
- height: 70px;
- width: 56px;
-
- flex: none;
-
- justify-content: center;
- align-items: flex-start;
-
- display: none;
-}
-
-.mx_TagPanel .mx_TagPanel_clearButton object {
- /* Same as .mx_SearchBox padding-top */
- margin-top: 24px;
- pointer-events: none;
-}
-
-.mx_TagPanel .mx_TagPanel_divider {
+.mx_GroupFilterPanel .mx_GroupFilterPanel_divider {
height: 0px;
- width: 34px;
- border-bottom: 1px solid $panel-divider-color;
- display: none;
+ width: 90%;
+ border: none;
+ border-bottom: 1px solid $groupFilterPanel-divider-color;
}
-.mx_TagPanel .mx_TagPanel_scroller {
+.mx_GroupFilterPanel .mx_GroupFilterPanel_scroller {
flex-grow: 1;
width: 100%;
}
-.mx_TagPanel .mx_TagPanel_tagTileContainer {
+.mx_GroupFilterPanel .mx_GroupFilterPanel_tagTileContainer {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 6px;
}
-.mx_TagPanel .mx_TagPanel_tagTileContainer > div {
+.mx_GroupFilterPanel .mx_GroupFilterPanel_tagTileContainer > div {
margin: 6px 0;
}
-.mx_TagPanel .mx_TagTile {
+.mx_GroupFilterPanel .mx_TagTile {
// opacity: 0.5;
position: relative;
+
+ .mx_BetaDot {
+ position: absolute;
+ right: -13px;
+ top: -11px;
+ }
}
-.mx_TagPanel .mx_TagTile:focus,
-.mx_TagPanel .mx_TagTile:hover,
-.mx_TagPanel .mx_TagTile.mx_TagTile_selected {
+
+.mx_GroupFilterPanel .mx_TagTile.mx_TagTile_prototype {
+ padding: 3px;
+}
+
+.mx_GroupFilterPanel .mx_TagTile:focus,
+.mx_GroupFilterPanel .mx_TagTile:hover,
+.mx_GroupFilterPanel .mx_TagTile.mx_TagTile_selected {
// opacity: 1;
}
-.mx_TagPanel .mx_TagTile_plus {
+.mx_GroupFilterPanel .mx_TagTile.mx_TagTile_selected_prototype {
+ background-color: $primary-bg-color;
+ border-radius: 6px;
+}
+
+.mx_TagTile_selected_prototype {
+ .mx_TagTile_homeIcon::before {
+ background-color: $primary-fg-color; // dark-on-light
+ }
+}
+
+.mx_TagTile:not(.mx_TagTile_selected_prototype) .mx_TagTile_homeIcon {
+ background-color: $roomheader-addroom-bg-color;
+ border-radius: 48px;
+
+ &::before {
+ background-color: $roomheader-addroom-fg-color;
+ }
+}
+
+.mx_TagTile_homeIcon {
+ width: 32px;
+ height: 32px;
+ position: relative;
+
+ &::before {
+ mask-image: url('$(res)/img/element-icons/home.svg');
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: 21px;
+ content: '';
+ display: inline-block;
+ width: 32px;
+ height: 32px;
+ position: absolute;
+ top: calc(50% - 16px);
+ left: calc(50% - 16px);
+ }
+}
+
+.mx_GroupFilterPanel .mx_TagTile_plus {
margin-bottom: 12px;
height: 32px;
width: 32px;
@@ -106,18 +138,17 @@ limitations under the License.
}
}
-.mx_TagPanel .mx_TagTile.mx_TagTile_selected::before {
+.mx_GroupFilterPanel .mx_TagTile.mx_TagTile_selected::before {
content: '';
- height: calc(100% + 16px);
+ height: 100%;
background-color: $accent-color;
- width: 5px;
+ width: 4px;
position: absolute;
- left: -15px;
+ left: -12px;
border-radius: 0 3px 3px 0;
- top: -8px; // (16px from height / 2)
}
-.mx_TagPanel .mx_TagTile.mx_AccessibleButton:focus {
+.mx_GroupFilterPanel .mx_TagTile.mx_AccessibleButton:focus {
filter: none;
}
diff --git a/res/css/structures/_HeaderButtons.scss b/res/css/structures/_HeaderButtons.scss
index 9ef40e9d6a..72b663ef0e 100644
--- a/res/css/structures/_HeaderButtons.scss
+++ b/res/css/structures/_HeaderButtons.scss
@@ -18,6 +18,14 @@ limitations under the License.
display: flex;
}
+.mx_RoomHeader_buttons + .mx_HeaderButtons {
+ // remove the | separator line for when next to RoomHeaderButtons
+ // TODO: remove this once when we redo communities and make the right panel similar to the new rooms one
+ &::before {
+ content: unset;
+ }
+}
+
.mx_HeaderButtons::before {
content: "";
background-color: $header-divider-color;
diff --git a/res/css/structures/_HomePage.scss b/res/css/structures/_HomePage.scss
index 04527bff48..9f72213d1a 100644
--- a/res/css/structures/_HomePage.scss
+++ b/res/css/structures/_HomePage.scss
@@ -26,9 +26,10 @@ limitations under the License.
.mx_HomePage_default {
text-align: center;
+ display: flex;
.mx_HomePage_default_wrapper {
- padding: 25vh 0 12px;
+ margin: auto;
}
img {
@@ -50,56 +51,54 @@ limitations under the License.
color: $muted-fg-color;
}
+ .mx_MiniAvatarUploader {
+ margin: 0 auto;
+ }
+
.mx_HomePage_default_buttons {
- margin: 80px auto 0;
+ margin: 60px auto 0;
width: fit-content;
.mx_AccessibleButton {
padding: 73px 8px 15px; // top: 20px top padding + 40px icon + 13px margin
- width: 104px; // 120px - 2* 8px
- margin: 0 39px; // 55px - 2* 8px
+ width: 160px;
+ height: 132px;
+ margin: 20px;
position: relative;
display: inline-block;
border-radius: 8px;
vertical-align: top;
word-break: break-word;
+ box-sizing: border-box;
font-weight: 600;
font-size: $font-15px;
line-height: $font-20px;
- color: $muted-fg-color;
-
- &:hover {
- color: $accent-color;
- background: rgba($accent-color, 0.06);
-
- &::before {
- background-color: $accent-color;
- }
- }
+ color: #fff; // on all themes
+ background-color: $accent-color;
&::before {
top: 20px;
- left: 40px; // (120px-40px)/2
+ left: 60px; // (160px-40px)/2
width: 40px;
height: 40px;
content: '';
position: absolute;
- background-color: $muted-fg-color;
+ background-color: #fff; // on all themes
mask-repeat: no-repeat;
mask-size: contain;
}
&.mx_HomePage_button_sendDm::before {
- mask-image: url('$(res)/img/feather-customised/message-circle.svg');
+ mask-image: url('$(res)/img/element-icons/feedback.svg');
}
&.mx_HomePage_button_explore::before {
- mask-image: url('$(res)/img/feather-customised/explore.svg');
+ mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
}
&.mx_HomePage_button_createGroup::before {
- mask-image: url('$(res)/img/feather-customised/group.svg');
+ mask-image: url('$(res)/img/element-icons/community-members.svg');
}
}
}
diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss
index 354dc87b8f..7c3cd1c513 100644
--- a/res/css/structures/_LeftPanel.scss
+++ b/res/css/structures/_LeftPanel.scss
@@ -14,40 +14,37 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-$tagPanelWidth: 56px; // only applies in this file, used for calculations
+$groupFilterPanelWidth: 56px; // only applies in this file, used for calculations
+$roomListCollapsedWidth: 68px;
.mx_LeftPanel {
background-color: $roomlist-bg-color;
- min-width: 260px;
+ // TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel
+ min-width: 206px;
max-width: 50%;
- // Create a row-based flexbox for the TagPanel and the room list
+ // Create a row-based flexbox for the GroupFilterPanel and the room list
display: flex;
- .mx_LeftPanel_tagPanelContainer {
+ .mx_LeftPanel_GroupFilterPanelContainer {
flex-grow: 0;
flex-shrink: 0;
- flex-basis: $tagPanelWidth;
+ flex-basis: $groupFilterPanelWidth;
height: 100%;
- // Create another flexbox so the TagPanel fills the container
+ // Create another flexbox so the GroupFilterPanel fills the container
display: flex;
+ flex-direction: column;
- // TagPanel handles its own CSS
- }
-
- &:not(.mx_LeftPanel_hasTagPanel) {
- .mx_LeftPanel_roomListContainer {
- width: 100%;
- }
+ // GroupFilterPanel handles its own CSS
}
// Note: The 'room list' in this context is actually everything that isn't the tag
// panel, such as the menu options, breadcrumbs, filtering, etc
.mx_LeftPanel_roomListContainer {
- width: calc(100% - $tagPanelWidth);
background-color: $roomlist-bg-color;
-
+ flex: 1 0 0;
+ min-width: 0;
// Create another flexbox (this time a column) for the room list components
display: flex;
flex-direction: column;
@@ -97,23 +94,25 @@ $tagPanelWidth: 56px; // only applies in this file, used for calculations
display: flex;
align-items: center;
- .mx_RoomSearch_expanded + .mx_LeftPanel_exploreButton {
- // Cheaty way to return the occupied space to the filter input
- flex-basis: 0;
- margin: 0;
- width: 0;
+ .mx_RoomSearch_focused, .mx_RoomSearch_hasQuery {
+ & + .mx_LeftPanel_exploreButton {
+ // Cheaty way to return the occupied space to the filter input
+ flex-basis: 0;
+ margin: 0;
+ width: 0;
- // Don't forget to hide the masked ::before icon,
- // using display:none or visibility:hidden would break accessibility
- &::before {
- content: none;
+ // Don't forget to hide the masked ::before icon,
+ // using display:none or visibility:hidden would break accessibility
+ &::before {
+ content: none;
+ }
}
}
.mx_LeftPanel_exploreButton {
- width: 28px;
- height: 28px;
- border-radius: 20px;
+ width: 32px;
+ height: 32px;
+ border-radius: 8px;
background-color: $roomlist-button-bg-color;
position: relative;
margin-left: 8px;
@@ -121,19 +120,31 @@ $tagPanelWidth: 56px; // only applies in this file, used for calculations
&::before {
content: '';
position: absolute;
- top: 6px;
- left: 6px;
+ top: 8px;
+ left: 8px;
width: 16px;
height: 16px;
- mask-image: url('$(res)/img/feather-customised/compass.svg');
+ mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
- background: $primary-fg-color;
+ background: $secondary-fg-color;
+ }
+
+ &.mx_LeftPanel_exploreButton_space::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/browse.svg');
}
}
}
+ .mx_LeftPanel_roomListFilterCount {
+ font-size: $font-13px;
+ font-weight: $font-semi-bold;
+ margin-left: 12px;
+ margin-top: 14px;
+ margin-bottom: -4px; // to counteract the normal roomListWrapper margin-top
+ }
+
.mx_LeftPanel_roomListWrapper {
overflow: hidden;
margin-top: 10px; // so we're not up against the search/filter
@@ -157,17 +168,15 @@ $tagPanelWidth: 56px; // only applies in this file, used for calculations
// These styles override the defaults for the minimized (66px) layout
&.mx_LeftPanel_minimized {
min-width: unset;
-
- // We have to forcefully set the width to override the resizer's style attribute.
- &.mx_LeftPanel_hasTagPanel {
- width: calc(68px + $tagPanelWidth) !important;
- }
- &:not(.mx_LeftPanel_hasTagPanel) {
- width: 68px !important;
- }
+ width: unset !important;
.mx_LeftPanel_roomListContainer {
- width: 68px;
+ width: $roomListCollapsedWidth;
+
+ .mx_LeftPanel_userHeader {
+ flex-direction: row;
+ justify-content: center;
+ }
.mx_LeftPanel_filterContainer {
// Organize the flexbox into a centered column layout
diff --git a/res/css/structures/_LeftPanelWidget.scss b/res/css/structures/_LeftPanelWidget.scss
new file mode 100644
index 0000000000..6e2d99bb37
--- /dev/null
+++ b/res/css/structures/_LeftPanelWidget.scss
@@ -0,0 +1,145 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_LeftPanelWidget {
+ // largely based on RoomSublist
+ margin-left: 8px;
+ margin-bottom: 4px;
+
+ .mx_LeftPanelWidget_headerContainer {
+ display: flex;
+ align-items: center;
+
+ height: 24px;
+ color: $roomlist-header-color;
+ margin-top: 4px;
+
+ .mx_LeftPanelWidget_stickable {
+ flex: 1;
+ max-width: 100%;
+
+ display: flex;
+ align-items: center;
+ }
+
+ .mx_LeftPanelWidget_headerText {
+ flex: 1;
+ max-width: calc(100% - 16px);
+ line-height: $font-16px;
+ font-size: $font-13px;
+ font-weight: 600;
+
+ // Ellipsize any text overflow
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+
+ .mx_LeftPanelWidget_collapseBtn {
+ display: inline-block;
+ position: relative;
+ width: 14px;
+ height: 14px;
+ margin-right: 6px;
+
+ &::before {
+ content: '';
+ width: 18px;
+ height: 18px;
+ position: absolute;
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ background-color: $roomlist-header-color;
+ mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
+ }
+
+ &.mx_LeftPanelWidget_collapseBtn_collapsed::before {
+ transform: rotate(-90deg);
+ }
+ }
+ }
+ }
+
+ .mx_LeftPanelWidget_resizeBox {
+ position: relative;
+
+ display: flex;
+ flex-direction: column;
+ overflow: visible; // let the resize handle out
+ }
+
+ .mx_AppTileFullWidth {
+ flex: 1 0 0;
+ overflow: hidden;
+ // need this to be flex otherwise the overflow hidden from above
+ // sometimes vertically centers the clipped list ... no idea why it would do this
+ // as the box model should be top aligned. Happens in both FF and Chromium
+ display: flex;
+ flex-direction: column;
+ box-sizing: border-box;
+
+ mask-image: linear-gradient(0deg, transparent, black 4px);
+ }
+
+ .mx_LeftPanelWidget_resizerHandle {
+ cursor: ns-resize;
+ border-radius: 3px;
+
+ // Override styles from library
+ width: unset !important;
+ height: 4px !important;
+
+ position: absolute;
+ top: -24px !important; // override from library - puts it in the margin-top of the headerContainer
+
+ // Together, these make the bar 64px wide
+ // These are also overridden from the library
+ left: calc(50% - 32px) !important;
+ right: calc(50% - 32px) !important;
+ }
+
+ &:hover .mx_LeftPanelWidget_resizerHandle {
+ opacity: 0.8;
+ background-color: $primary-fg-color;
+ }
+
+ .mx_LeftPanelWidget_maximizeButton {
+ margin-left: 8px;
+ margin-right: 7px;
+ position: relative;
+ width: 24px;
+ height: 24px;
+ border-radius: 32px;
+
+ &::before {
+ content: '';
+ width: 16px;
+ height: 16px;
+ position: absolute;
+ top: 4px;
+ left: 4px;
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ mask-image: url('$(res)/img/feather-customised/maximise.svg');
+ background: $muted-fg-color;
+ }
+ }
+}
+
+.mx_LeftPanelWidget_maximizeButtonTooltip {
+ margin-top: -3px;
+}
diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss
index aee7b5a154..8199121420 100644
--- a/res/css/structures/_MainSplit.scss
+++ b/res/css/structures/_MainSplit.scss
@@ -18,11 +18,15 @@ limitations under the License.
display: flex;
flex-direction: row;
min-width: 0;
+ min-height: 0;
height: 100%;
}
.mx_MainSplit > .mx_RightPanel_ResizeWrapper {
padding: 5px;
+ // margin left to not allow the handle to not encroach on the space for the scrollbar
+ margin-left: 8px;
+ height: calc(100vh - 51px); // height of .mx_RoomHeader.light-panel
&:hover .mx_RightPanel_ResizeHandle {
// Need to use important to override element style attributes
diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss
index f4e46a8e94..a220c5d505 100644
--- a/res/css/structures/_MatrixChat.scss
+++ b/res/css/structures/_MatrixChat.scss
@@ -66,7 +66,7 @@ limitations under the License.
}
/* not the left panel, and not the resize handle, so the roomview/groupview/... */
-.mx_MatrixChat > :not(.mx_LeftPanel):not(.mx_ResizeHandle) {
+.mx_MatrixChat > :not(.mx_LeftPanel):not(.mx_SpacePanel):not(.mx_ResizeHandle) {
background-color: $primary-bg-color;
flex: 1 1 0;
@@ -79,7 +79,6 @@ limitations under the License.
height: 100%;
}
-.mx_MatrixChat > .mx_LeftPanel2:hover + .mx_ResizeHandle_horizontal,
.mx_MatrixChat > .mx_ResizeHandle_horizontal:hover {
position: relative;
diff --git a/res/css/structures/_MyGroups.scss b/res/css/structures/_MyGroups.scss
index 73f1332cd0..9c0062b72d 100644
--- a/res/css/structures/_MyGroups.scss
+++ b/res/css/structures/_MyGroups.scss
@@ -17,6 +17,11 @@ limitations under the License.
.mx_MyGroups {
display: flex;
flex-direction: column;
+
+ .mx_BetaCard {
+ margin: 0 72px;
+ max-width: 760px;
+ }
}
.mx_MyGroups .mx_RoomHeader_simpleHeader {
@@ -30,7 +35,7 @@ limitations under the License.
flex-wrap: wrap;
}
-.mx_MyGroups > :not(.mx_RoomHeader) {
+.mx_MyGroups > :not(.mx_RoomHeader):not(.mx_BetaCard) {
max-width: 960px;
margin: 40px;
}
diff --git a/res/css/structures/_NotificationPanel.scss b/res/css/structures/_NotificationPanel.scss
index 715a94fe2c..1258ace069 100644
--- a/res/css/structures/_NotificationPanel.scss
+++ b/res/css/structures/_NotificationPanel.scss
@@ -22,7 +22,13 @@ limitations under the License.
}
.mx_NotificationPanel .mx_RoomView_messageListWrapper {
- margin-right: 20px;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+}
+
+.mx_NotificationPanel .mx_RoomView_MessageList {
+ width: 100%;
}
.mx_NotificationPanel .mx_RoomView_MessageList h2 {
@@ -35,11 +41,32 @@ limitations under the License.
.mx_NotificationPanel .mx_EventTile {
word-break: break-word;
+ position: relative;
+ padding-bottom: 18px;
+
+ &:not(.mx_EventTile_last):not(.mx_EventTile_lastInSection)::after {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: $tertiary-fg-color;
+ height: 1px;
+ opacity: 0.4;
+ content: '';
+ }
}
.mx_NotificationPanel .mx_EventTile_roomName {
font-weight: bold;
font-size: $font-14px;
+
+ > * {
+ vertical-align: middle;
+ }
+
+ > .mx_BaseAvatar {
+ margin-right: 8px;
+ }
}
.mx_NotificationPanel .mx_EventTile_roomName a {
@@ -47,8 +74,7 @@ limitations under the License.
}
.mx_NotificationPanel .mx_EventTile_avatar {
- top: 8px;
- left: 0px;
+ display: none; // we don't need this in this view
}
.mx_NotificationPanel .mx_EventTile .mx_SenderProfile,
@@ -60,8 +86,7 @@ limitations under the License.
}
.mx_NotificationPanel .mx_EventTile_senderDetails {
- padding-left: 32px;
- padding-top: 8px;
+ padding-left: 36px; // align with the room name
position: relative;
a {
@@ -82,7 +107,7 @@ limitations under the License.
.mx_NotificationPanel .mx_EventTile_line {
margin-right: 0px;
- padding-left: 32px;
+ padding-left: 36px; // align with the room name
padding-top: 0px;
padding-bottom: 0px;
padding-right: 0px;
diff --git a/res/css/structures/_RightPanel.scss b/res/css/structures/_RightPanel.scss
index 120f44db90..5515fe4060 100644
--- a/res/css/structures/_RightPanel.scss
+++ b/res/css/structures/_RightPanel.scss
@@ -64,20 +64,18 @@ limitations under the License.
left: 4px; // center with parent of 32px
height: 24px;
width: 24px;
- background-color: $rightpanel-button-color;
+ background-color: $icon-button-color;
mask-repeat: no-repeat;
mask-size: contain;
}
-}
-.mx_RightPanel_membersButton::before {
- mask-image: url('$(res)/img/element-icons/room/members.svg');
- mask-position: center;
-}
+ &:hover {
+ background: rgba($accent-color, 0.1);
-.mx_RightPanel_filesButton::before {
- mask-image: url('$(res)/img/element-icons/room/files.svg');
- mask-position: center;
+ &::before {
+ background-color: $accent-color;
+ }
+ }
}
.mx_RightPanel_notifsButton::before {
@@ -85,6 +83,11 @@ limitations under the License.
mask-position: center;
}
+.mx_RightPanel_roomSummaryButton::before {
+ mask-image: url('$(res)/img/element-icons/room/room-summary.svg');
+ mask-position: center;
+}
+
.mx_RightPanel_groupMembersButton::before {
mask-image: url('$(res)/img/element-icons/community-members.svg');
mask-position: center;
@@ -96,20 +99,8 @@ limitations under the License.
}
.mx_RightPanel_headerButton_highlight {
- background: rgba($accent-color, 0.25);
- // make the icon the accent color too
&::before {
- background-color: $accent-color;
- }
-}
-
-.mx_RightPanel_headerButton:not(.mx_RightPanel_headerButton_highlight) {
- &:hover {
- background: rgba($accent-color, 0.1);
-
- &::before {
- background-color: $accent-color;
- }
+ background-color: $accent-color !important;
}
}
@@ -146,7 +137,7 @@ limitations under the License.
}
.mx_RightPanel_empty {
- margin-right: -42px;
+ margin-right: -28px;
h2 {
font-weight: 700;
@@ -169,3 +160,20 @@ limitations under the License.
mask-position: center;
}
}
+
+.mx_RightPanel_scopeHeader {
+ margin: 24px;
+ text-align: center;
+ font-weight: $font-semi-bold;
+ font-size: $font-18px;
+ line-height: $font-22px;
+
+ .mx_BaseAvatar {
+ margin-right: 8px;
+ vertical-align: middle;
+ }
+
+ .mx_BaseAvatar_image {
+ border-radius: 8px;
+ }
+}
diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss
index e0814182f5..89cb21b7a6 100644
--- a/res/css/structures/_RoomDirectory.scss
+++ b/res/css/structures/_RoomDirectory.scss
@@ -64,28 +64,23 @@ limitations under the License.
}
.mx_RoomDirectory_table {
- font-size: $font-12px;
color: $primary-fg-color;
- width: 100%;
+ display: grid;
+ font-size: $font-12px;
+ grid-template-columns: max-content auto max-content max-content max-content;
+ row-gap: 24px;
text-align: left;
- table-layout: fixed;
+ width: 100%;
}
.mx_RoomDirectory_roomAvatar {
- width: 32px;
- padding-right: 14px;
- vertical-align: top;
-}
-
-.mx_RoomDirectory_roomDescription {
- padding-bottom: 16px;
+ padding: 2px 14px 0 0;
}
.mx_RoomDirectory_roomMemberCount {
+ align-self: center;
color: $light-fg-color;
- width: 60px;
- padding: 0 10px;
- text-align: center;
+ padding: 3px 10px 0;
&::before {
background-color: $light-fg-color;
@@ -105,8 +100,7 @@ limitations under the License.
}
.mx_RoomDirectory_join, .mx_RoomDirectory_preview {
- width: 80px;
- text-align: center;
+ align-self: center;
white-space: nowrap;
}
@@ -133,6 +127,10 @@ limitations under the License.
.mx_RoomDirectory_topic {
cursor: initial;
color: $light-fg-color;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 3;
+ overflow: hidden;
}
.mx_RoomDirectory_alias {
diff --git a/res/css/structures/_RoomSearch.scss b/res/css/structures/_RoomSearch.scss
index 39a3dee30b..7fdafab5a6 100644
--- a/res/css/structures/_RoomSearch.scss
+++ b/res/css/structures/_RoomSearch.scss
@@ -17,10 +17,12 @@ limitations under the License.
// Note: this component expects to be contained within a flexbox
.mx_RoomSearch {
flex: 1;
- border-radius: 20px;
+ border-radius: 8px;
background-color: $roomlist-button-bg-color;
+ // keep border thickness consistent to prevent movement
+ border: 1px solid transparent;
height: 28px;
- padding: 2px;
+ padding: 1px;
// Create a flexbox for the icons (easier to manage)
display: flex;
@@ -29,9 +31,9 @@ limitations under the License.
.mx_RoomSearch_icon {
width: 16px;
height: 16px;
- mask: url('$(res)/img/feather-customised/search-input.svg');
+ mask: url('$(res)/img/element-icons/roomlist/search.svg');
mask-repeat: no-repeat;
- background: $primary-fg-color;
+ background-color: $secondary-fg-color;
margin-left: 7px;
}
@@ -46,19 +48,30 @@ limitations under the License.
line-height: $font-16px;
&:not(.mx_RoomSearch_inputExpanded)::placeholder {
- color: $primary-fg-color !important; // !important to override default app-wide styles
+ color: $tertiary-fg-color !important; // !important to override default app-wide styles
}
}
- &.mx_RoomSearch_expanded {
+ &.mx_RoomSearch_hasQuery {
+ border-color: $secondary-fg-color;
+ }
+
+ &.mx_RoomSearch_focused {
+ box-shadow: 0 0 4px 4px rgba(0, 132, 255, 0.5);
+ border-color: transparent;
+ }
+
+ &.mx_RoomSearch_focused, &.mx_RoomSearch_hasQuery {
+ background-color: $roomlist-filter-active-bg-color;
+
.mx_RoomSearch_clearButton {
width: 16px;
height: 16px;
- mask-image: url('$(res)/img/feather-customised/x.svg');
+ mask-image: url('$(res)/img/element-icons/roomlist/search-clear.svg');
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
- background: $primary-fg-color;
+ background-color: $secondary-fg-color;
margin-right: 8px;
}
}
diff --git a/res/css/structures/_RoomStatusBar.scss b/res/css/structures/_RoomStatusBar.scss
index cd4390ee5c..8cc00aba0f 100644
--- a/res/css/structures/_RoomStatusBar.scss
+++ b/res/css/structures/_RoomStatusBar.scss
@@ -14,62 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_RoomStatusBar {
+.mx_RoomStatusBar:not(.mx_RoomStatusBar_unsentMessages) {
margin-left: 65px;
min-height: 50px;
}
-/* position the indicator in the same place horizontally as .mx_EventTile_avatar. */
-.mx_RoomStatusBar_indicator {
- padding-left: 17px;
- padding-right: 12px;
- margin-left: -73px;
- margin-top: 15px;
- float: left;
- width: 24px;
- text-align: center;
-}
-
-.mx_RoomStatusBar_callBar {
- height: 50px;
- line-height: $font-50px;
-}
-
-.mx_RoomStatusBar_placeholderIndicator span {
- color: $primary-fg-color;
- opacity: 0.5;
- position: relative;
- top: -4px;
- /*
- animation-duration: 1s;
- animation-name: bounce;
- animation-direction: alternate;
- animation-iteration-count: infinite;
- */
-}
-
-.mx_RoomStatusBar_placeholderIndicator span:nth-child(1) {
- animation-delay: 0.3s;
-}
-.mx_RoomStatusBar_placeholderIndicator span:nth-child(2) {
- animation-delay: 0.6s;
-}
-.mx_RoomStatusBar_placeholderIndicator span:nth-child(3) {
- animation-delay: 0.9s;
-}
-
-@keyframes bounce {
- from {
- opacity: 0.5;
- top: 0;
- }
-
- to {
- opacity: 0.2;
- top: -3px;
- }
-}
-
.mx_RoomStatusBar_typingIndicatorAvatars {
width: 52px;
margin-top: -1px;
@@ -119,6 +68,99 @@ limitations under the License.
min-height: 58px;
}
+.mx_RoomStatusBar_unsentMessages {
+ > div[role="alert"] {
+ // cheat some basic alignment
+ display: flex;
+ align-items: center;
+ min-height: 70px;
+ margin: 12px;
+ padding-left: 16px;
+ background-color: $header-panel-bg-color;
+ border-radius: 4px;
+ }
+
+ .mx_RoomStatusBar_unsentBadge {
+ margin-right: 12px;
+
+ .mx_NotificationBadge {
+ // Override sizing from the default badge
+ width: 24px !important;
+ height: 24px !important;
+ border-radius: 24px !important;
+
+ .mx_NotificationBadge_count {
+ font-size: $font-16px !important; // override default
+ }
+ }
+ }
+
+ .mx_RoomStatusBar_unsentTitle {
+ color: $warning-color;
+ font-size: $font-15px;
+ }
+
+ .mx_RoomStatusBar_unsentDescription {
+ font-size: $font-12px;
+ }
+
+ .mx_RoomStatusBar_unsentButtonBar {
+ flex-grow: 1;
+ text-align: right;
+ margin-right: 22px;
+ color: $muted-fg-color;
+
+ .mx_AccessibleButton {
+ padding: 5px 10px;
+ padding-left: 28px; // 16px for the icon, 2px margin to text, 10px regular padding
+ display: inline-block;
+ position: relative;
+
+ &:nth-child(2) {
+ border-left: 1px solid $resend-button-divider-color;
+ }
+
+ &::before {
+ content: '';
+ position: absolute;
+ left: 10px; // inset for regular button padding
+ background-color: $muted-fg-color;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: contain;
+ }
+
+ &.mx_RoomStatusBar_unsentCancelAllBtn::before {
+ mask-image: url('$(res)/img/element-icons/trashcan.svg');
+ width: 12px;
+ height: 16px;
+ top: calc(50% - 8px); // text sizes are dynamic
+ }
+
+ &.mx_RoomStatusBar_unsentResendAllBtn {
+ padding-left: 34px; // 28px from above, but +6px to account for the wider icon
+
+ &::before {
+ mask-image: url('$(res)/img/element-icons/retry.svg');
+ width: 18px;
+ height: 18px;
+ top: calc(50% - 9px); // text sizes are dynamic
+ }
+ }
+ }
+
+ .mx_InlineSpinner {
+ vertical-align: middle;
+ margin-right: 5px;
+ top: 1px; // just to help the vertical alignment be slightly better
+
+ & + span {
+ margin-right: 10px; // same margin/padding as the rightmost button
+ }
+ }
+ }
+}
+
.mx_RoomStatusBar_connectionLostBar img {
padding-left: 10px;
padding-right: 10px;
@@ -153,18 +195,8 @@ limitations under the License.
display: block;
}
-.mx_RoomStatusBar_isAlone {
- height: 50px;
- line-height: $font-50px;
-
- color: $primary-fg-color;
- opacity: 0.5;
- overflow-y: hidden;
- display: block;
-}
-
.mx_MatrixChat_useCompactLayout {
- .mx_RoomStatusBar {
+ .mx_RoomStatusBar:not(.mx_RoomStatusBar_unsentMessages) {
min-height: 40px;
}
@@ -172,11 +204,6 @@ limitations under the License.
margin-top: 10px;
}
- .mx_RoomStatusBar_callBar {
- height: 40px;
- line-height: $font-40px;
- }
-
.mx_RoomStatusBar_typingBar {
height: 40px;
line-height: $font-40px;
diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss
index 3b60c4e62b..cdbe47178d 100644
--- a/res/css/structures/_RoomView.scss
+++ b/res/css/structures/_RoomView.scss
@@ -20,35 +20,54 @@ limitations under the License.
flex-direction: column;
}
+
+@keyframes mx_RoomView_fileDropTarget_animation {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 0.95;
+ }
+}
+
.mx_RoomView_fileDropTarget {
min-width: 0px;
width: 100%;
+ height: 100%;
+
font-size: $font-18px;
text-align: center;
pointer-events: none;
- padding-left: 12px;
- padding-right: 12px;
- margin-left: -12px;
+ background-color: $primary-bg-color;
+ opacity: 0.95;
- border-top-left-radius: 10px;
- border-top-right-radius: 10px;
-
- background-color: $droptarget-bg-color;
- border: 2px #e1dddd solid;
- border-bottom: none;
position: absolute;
- top: 52px;
- bottom: 0px;
z-index: 3000;
+
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ animation: mx_RoomView_fileDropTarget_animation;
+ animation-duration: 0.5s;
}
-.mx_RoomView_fileDropTargetLabel {
- top: 50%;
- width: 100%;
- margin-top: -50px;
- position: absolute;
+@keyframes mx_RoomView_fileDropTarget_image_animation {
+ from {
+ width: 0px;
+ }
+ to {
+ width: 32px;
+ }
+}
+
+.mx_RoomView_fileDropTarget_image {
+ animation: mx_RoomView_fileDropTarget_image_animation;
+ animation-duration: 0.5s;
+ margin-bottom: 16px;
}
.mx_RoomView_auxPanel {
@@ -117,7 +136,6 @@ limitations under the License.
}
.mx_RoomView_body {
- position: relative; //for .mx_RoomView_auxPanel_fullHeight
display: flex;
flex-direction: column;
flex: 1;
@@ -185,13 +203,11 @@ limitations under the License.
}
.mx_RoomView_empty {
- flex: 1 1 auto;
font-size: $font-13px;
- padding-left: 3em;
- padding-right: 3em;
- margin-right: 20px;
- margin-top: 33%;
+ padding: 0 24px;
+ margin-right: 30px;
text-align: center;
+ margin-bottom: 80px; // visually center the content (intentional offset)
}
.mx_RoomView_MessageList {
@@ -221,7 +237,7 @@ hr.mx_RoomView_myReadMarker {
position: relative;
top: -1px;
z-index: 1;
- transition: width 400ms easeInSine 1s, opacity 400ms easeInSine 1s;
+ transition: width 400ms easeinsine 1s, opacity 400ms easeinsine 1s;
width: 99%;
opacity: 1;
}
@@ -246,12 +262,6 @@ hr.mx_RoomView_myReadMarker {
padding-top: 1px;
}
-.mx_RoomView_inCall .mx_RoomView_statusAreaBox {
- background-color: $accent-color;
- color: $accent-fg-color;
- position: relative;
-}
-
.mx_RoomView_voipChevron {
position: absolute;
bottom: -11px;
diff --git a/res/css/structures/_ScrollPanel.scss b/res/css/structures/_ScrollPanel.scss
index 699224949b..a4e501b339 100644
--- a/res/css/structures/_ScrollPanel.scss
+++ b/res/css/structures/_ScrollPanel.scss
@@ -21,6 +21,5 @@ limitations under the License.
display: flex;
flex-direction: column;
justify-content: flex-end;
- overflow-y: hidden;
}
}
diff --git a/res/css/structures/_SpacePanel.scss b/res/css/structures/_SpacePanel.scss
new file mode 100644
index 0000000000..c433ccf275
--- /dev/null
+++ b/res/css/structures/_SpacePanel.scss
@@ -0,0 +1,371 @@
+/*
+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.
+*/
+
+$topLevelHeight: 32px;
+$nestedHeight: 24px;
+$gutterSize: 16px;
+$activeBorderTransparentGap: 1px;
+
+$activeBackgroundColor: $roomtile-selected-bg-color;
+$activeBorderColor: $secondary-fg-color;
+
+.mx_SpacePanel {
+ flex: 0 0 auto;
+ background-color: $groupFilterPanel-bg-color;
+ padding: 0;
+ margin: 0;
+
+ // Create another flexbox so the Panel fills the container
+ display: flex;
+ flex-direction: column;
+ overflow-y: auto;
+
+ .mx_SpacePanel_spaceTreeWrapper {
+ flex: 1;
+ padding: 8px 8px 16px 0;
+ }
+
+ .mx_SpacePanel_toggleCollapse {
+ flex: 0 0 auto;
+ width: 40px;
+ height: 40px;
+ mask-position: center;
+ mask-size: 32px;
+ mask-repeat: no-repeat;
+ margin-left: $gutterSize;
+ margin-bottom: 12px;
+ background-color: $roomlist-header-color;
+ mask-image: url('$(res)/img/element-icons/expand-space-panel.svg');
+
+ &.expanded {
+ transform: scaleX(-1);
+ }
+ }
+
+ ul {
+ margin: 0;
+ list-style: none;
+ padding: 0;
+
+ > .mx_SpaceItem {
+ padding-left: 16px;
+ }
+ }
+
+ .mx_SpaceButton_toggleCollapse {
+ cursor: pointer;
+ }
+
+ .mx_SpaceTreeLevel {
+ display: flex;
+ flex-direction: column;
+ max-width: 250px;
+ flex-grow: 1;
+ }
+
+ .mx_SpaceItem {
+ display: inline-flex;
+ flex-flow: wrap;
+
+ &.mx_SpaceItem_narrow {
+ align-self: baseline;
+ }
+ }
+
+ .mx_SpaceItem.collapsed {
+ & > .mx_SpaceButton > .mx_SpaceButton_toggleCollapse {
+ transform: rotate(-90deg);
+ }
+
+ & > .mx_SpaceTreeLevel {
+ display: none;
+ }
+ }
+
+ .mx_SpaceItem:not(.hasSubSpaces) > .mx_SpaceButton {
+ margin-left: $gutterSize;
+ min-width: 40px;
+ }
+
+ .mx_SpaceButton {
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ padding: 4px 4px 4px 0;
+ width: 100%;
+
+ &.mx_SpaceButton_active {
+ &:not(.mx_SpaceButton_narrow) .mx_SpaceButton_selectionWrapper {
+ background-color: $activeBackgroundColor;
+ }
+
+ &.mx_SpaceButton_narrow .mx_SpaceButton_selectionWrapper {
+ padding: $activeBorderTransparentGap;
+ border: 3px $activeBorderColor solid;
+ }
+ }
+
+ .mx_SpaceButton_selectionWrapper {
+ position: relative;
+ display: flex;
+ flex: 1;
+ align-items: center;
+ border-radius: 12px;
+ padding: 4px;
+ }
+
+ &:not(.mx_SpaceButton_narrow) {
+ .mx_SpaceButton_selectionWrapper {
+ width: 100%;
+ padding-right: 16px;
+ overflow: hidden;
+ }
+ }
+
+ .mx_SpaceButton_name {
+ flex: 1;
+ margin-left: 8px;
+ white-space: nowrap;
+ display: block;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ padding-right: 8px;
+ font-size: $font-14px;
+ line-height: $font-18px;
+ }
+
+ .mx_SpaceButton_toggleCollapse {
+ width: $gutterSize;
+ height: 20px;
+ mask-position: center;
+ mask-size: 20px;
+ mask-repeat: no-repeat;
+ background-color: $roomlist-header-color;
+ mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
+ }
+
+ .mx_SpaceButton_icon {
+ width: $topLevelHeight;
+ min-width: $topLevelHeight;
+ height: $topLevelHeight;
+ border-radius: 8px;
+ position: relative;
+
+ &::before {
+ position: absolute;
+ content: '';
+ width: $topLevelHeight;
+ height: $topLevelHeight;
+ top: 0;
+ left: 0;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: 18px;
+ }
+ }
+
+ &.mx_SpaceButton_home .mx_SpaceButton_icon {
+ background-color: #ffffff;
+
+ &::before {
+ background-color: #3f3d3d;
+ mask-image: url('$(res)/img/element-icons/home.svg');
+ }
+ }
+
+ &.mx_SpaceButton_new .mx_SpaceButton_icon {
+ background-color: $accent-color;
+ transition: all .1s ease-in-out; // TODO transition
+
+ &::before {
+ background-color: #ffffff;
+ mask-image: url('$(res)/img/element-icons/plus.svg');
+ transition: all .2s ease-in-out; // TODO transition
+ }
+ }
+
+ &.mx_SpaceButton_newCancel .mx_SpaceButton_icon {
+ background-color: $icon-button-color;
+
+ &::before {
+ transform: rotate(45deg);
+ }
+ }
+
+ .mx_BaseAvatar_image {
+ border-radius: 8px;
+ }
+
+ .mx_SpaceButton_menuButton {
+ width: 20px;
+ min-width: 20px; // yay flex
+ height: 20px;
+ margin-top: auto;
+ margin-bottom: auto;
+ display: none;
+ position: absolute;
+ right: 4px;
+
+ &::before {
+ top: 2px;
+ left: 2px;
+ content: '';
+ width: 16px;
+ height: 16px;
+ position: absolute;
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ mask-image: url('$(res)/img/element-icons/context-menu.svg');
+ background: $primary-fg-color;
+ }
+ }
+ }
+
+ .mx_SpacePanel_badgeContainer {
+ position: absolute;
+
+ // Create a flexbox to make aligning dot badges easier
+ display: flex;
+ align-items: center;
+
+ .mx_NotificationBadge {
+ margin: 0 2px; // centering
+ }
+
+ .mx_NotificationBadge_dot {
+ // make the smaller dot occupy the same width for centering
+ margin: 0 7px;
+ }
+ }
+
+ &.collapsed {
+ .mx_SpaceButton {
+ .mx_SpacePanel_badgeContainer {
+ right: 0;
+ top: 0;
+
+ .mx_NotificationBadge {
+ background-clip: padding-box;
+ }
+
+ .mx_NotificationBadge_dot {
+ margin: 0 -1px 0 0;
+ border: 3px solid $groupFilterPanel-bg-color;
+ }
+
+ .mx_NotificationBadge_2char,
+ .mx_NotificationBadge_3char {
+ margin: -5px -5px 0 0;
+ border: 2px solid $groupFilterPanel-bg-color;
+ }
+ }
+
+ &.mx_SpaceButton_active .mx_SpacePanel_badgeContainer {
+ // when we draw the selection border we move the relative bounds of our parent
+ // so update our position within the bounds of the parent to maintain position overall
+ right: -3px;
+ top: -3px;
+ }
+ }
+ }
+
+ &:not(.collapsed) {
+ .mx_SpacePanel_badgeContainer {
+ position: absolute;
+ right: 4px;
+ }
+
+ .mx_SpaceButton:hover,
+ .mx_SpaceButton:focus-within,
+ .mx_SpaceButton_hasMenuOpen {
+ &:not(.mx_SpaceButton_home):not(.mx_SpaceButton_invite) {
+ // Hide the badge container on hover because it'll be a menu button
+ .mx_SpacePanel_badgeContainer {
+ width: 0;
+ height: 0;
+ display: none;
+ }
+
+ .mx_SpaceButton_menuButton {
+ display: block;
+ }
+ }
+ }
+ }
+
+ /* root space buttons are bigger and not indented */
+ & > .mx_AutoHideScrollbar {
+ & > .mx_SpaceButton {
+ height: $topLevelHeight;
+
+ &.mx_SpaceButton_active::before {
+ height: $topLevelHeight;
+ }
+ }
+
+ & > ul {
+ padding-left: 0;
+ }
+ }
+}
+
+.mx_SpacePanel_contextMenu {
+ .mx_SpacePanel_contextMenu_header {
+ margin: 12px 16px 12px;
+ font-weight: $font-semi-bold;
+ font-size: $font-15px;
+ line-height: $font-18px;
+ }
+
+ .mx_IconizedContextMenu_optionList .mx_AccessibleButton.mx_SpacePanel_contextMenu_inviteButton {
+ color: $accent-color;
+
+ .mx_SpacePanel_iconInvite::before {
+ background-color: $accent-color;
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ }
+ }
+
+ .mx_SpacePanel_iconSettings::before {
+ mask-image: url('$(res)/img/element-icons/settings.svg');
+ }
+
+ .mx_SpacePanel_iconLeave::before {
+ mask-image: url('$(res)/img/element-icons/leave.svg');
+ }
+
+ .mx_SpacePanel_iconMembers::before {
+ mask-image: url('$(res)/img/element-icons/room/members.svg');
+ }
+
+ .mx_SpacePanel_iconPlus::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/plus-circle.svg');
+ }
+
+ .mx_SpacePanel_iconHash::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/hash-circle.svg');
+ }
+
+ .mx_SpacePanel_iconExplore::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/browse.svg');
+ }
+}
+
+
+.mx_SpacePanel_sharePublicSpace {
+ margin: 0;
+}
diff --git a/res/css/structures/_SpaceRoomDirectory.scss b/res/css/structures/_SpaceRoomDirectory.scss
new file mode 100644
index 0000000000..7925686bf1
--- /dev/null
+++ b/res/css/structures/_SpaceRoomDirectory.scss
@@ -0,0 +1,315 @@
+/*
+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_SpaceRoomDirectory_dialogWrapper > .mx_Dialog {
+ max-width: 960px;
+ height: 100%;
+}
+
+.mx_SpaceRoomDirectory {
+ height: 100%;
+ margin-bottom: 12px;
+ color: $primary-fg-color;
+ word-break: break-word;
+ display: flex;
+ flex-direction: column;
+}
+
+.mx_SpaceRoomDirectory,
+.mx_SpaceRoomView_landing {
+ .mx_Dialog_title {
+ display: flex;
+
+ .mx_BaseAvatar {
+ margin-right: 12px;
+ align-self: center;
+ }
+
+ .mx_BaseAvatar_image {
+ border-radius: 8px;
+ }
+
+ > div {
+ > h1 {
+ font-weight: $font-semi-bold;
+ font-size: $font-18px;
+ line-height: $font-22px;
+ margin: 0;
+ }
+
+ > div {
+ font-weight: 400;
+ color: $secondary-fg-color;
+ font-size: $font-15px;
+ line-height: $font-24px;
+ }
+ }
+ }
+
+ .mx_AccessibleButton_kind_link {
+ padding: 0;
+ }
+
+ .mx_SearchBox {
+ margin: 24px 0 16px;
+ }
+
+ .mx_SpaceRoomDirectory_noResults {
+ text-align: center;
+
+ > div {
+ font-size: $font-15px;
+ line-height: $font-24px;
+ color: $secondary-fg-color;
+ }
+ }
+
+ .mx_SpaceRoomDirectory_listHeader {
+ display: flex;
+ min-height: 32px;
+ align-items: center;
+ font-size: $font-15px;
+ line-height: $font-24px;
+ color: $primary-fg-color;
+
+ .mx_AccessibleButton {
+ padding: 4px 12px;
+ font-weight: normal;
+
+ & + .mx_AccessibleButton {
+ margin-left: 16px;
+ }
+ }
+
+ .mx_AccessibleButton_kind_danger_outline,
+ .mx_AccessibleButton_kind_primary_outline {
+ padding: 3px 12px; // to account for the 1px border
+ }
+
+ > span {
+ margin-left: auto;
+ }
+ }
+
+ .mx_SpaceRoomDirectory_error {
+ position: relative;
+ font-weight: $font-semi-bold;
+ color: $notice-primary-color;
+ font-size: $font-15px;
+ line-height: $font-18px;
+ margin: 20px auto 12px;
+ padding-left: 24px;
+ width: max-content;
+
+ &::before {
+ content: "";
+ position: absolute;
+ height: 16px;
+ width: 16px;
+ left: 0;
+ background-image: url("$(res)/img/element-icons/warning-badge.svg");
+ }
+ }
+}
+
+.mx_SpaceRoomDirectory_list {
+ margin-top: 16px;
+ padding-bottom: 40px;
+
+ .mx_SpaceRoomDirectory_roomCount {
+ > h3 {
+ display: inline;
+ font-weight: $font-semi-bold;
+ font-size: $font-18px;
+ line-height: $font-22px;
+ color: $primary-fg-color;
+ }
+
+ > span {
+ margin-left: 8px;
+ font-size: $font-15px;
+ line-height: $font-24px;
+ color: $secondary-fg-color;
+ }
+ }
+
+ .mx_SpaceRoomDirectory_subspace {
+ .mx_BaseAvatar_image {
+ border-radius: 8px;
+ }
+ }
+
+ .mx_SpaceRoomDirectory_subspace_toggle {
+ position: absolute;
+ left: -1px;
+ top: 10px;
+ height: 16px;
+ width: 16px;
+ border-radius: 4px;
+ background-color: $primary-bg-color;
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 16px;
+ width: 16px;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ background-color: $tertiary-fg-color;
+ mask-size: 16px;
+ transform: rotate(270deg);
+ mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
+ }
+
+ &.mx_SpaceRoomDirectory_subspace_toggle_shown::before {
+ transform: rotate(0deg);
+ }
+ }
+
+ .mx_SpaceRoomDirectory_subspace_children {
+ position: relative;
+ padding-left: 12px;
+ }
+
+ .mx_SpaceRoomDirectory_roomTile {
+ position: relative;
+ padding: 8px 16px;
+ border-radius: 8px;
+ min-height: 56px;
+ box-sizing: border-box;
+
+ display: grid;
+ grid-template-columns: 20px auto max-content;
+ grid-column-gap: 8px;
+ grid-row-gap: 6px;
+ align-items: center;
+
+ .mx_BaseAvatar {
+ grid-row: 1;
+ grid-column: 1;
+ }
+
+ .mx_SpaceRoomDirectory_roomTile_name {
+ font-weight: $font-semi-bold;
+ font-size: $font-15px;
+ line-height: $font-18px;
+ grid-row: 1;
+ grid-column: 2;
+
+ .mx_InfoTooltip {
+ display: inline;
+ margin-left: 12px;
+ color: $tertiary-fg-color;
+ font-size: $font-12px;
+ line-height: $font-15px;
+
+ .mx_InfoTooltip_icon {
+ margin-right: 4px;
+ position: relative;
+ vertical-align: text-top;
+
+ &::before {
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+ }
+ }
+ }
+
+ .mx_SpaceRoomDirectory_roomTile_info {
+ font-size: $font-14px;
+ line-height: $font-18px;
+ color: $secondary-fg-color;
+ grid-row: 2;
+ grid-column: 1/3;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ overflow: hidden;
+ }
+
+ .mx_SpaceRoomDirectory_actions {
+ text-align: right;
+ margin-left: 20px;
+ grid-column: 3;
+ grid-row: 1/3;
+
+ .mx_AccessibleButton {
+ line-height: $font-24px;
+ padding: 4px 16px;
+ display: inline-block;
+ visibility: hidden;
+ }
+
+ .mx_AccessibleButton_kind_danger_outline,
+ .mx_AccessibleButton_kind_primary_outline {
+ padding: 3px 16px; // to account for the 1px border
+ }
+
+ .mx_Checkbox {
+ display: inline-flex;
+ vertical-align: middle;
+ margin-left: 12px;
+ }
+ }
+
+ &:hover {
+ background-color: $groupFilterPanel-bg-color;
+
+ .mx_AccessibleButton {
+ visibility: visible;
+ }
+ }
+ }
+
+ .mx_SpaceRoomDirectory_roomTile,
+ .mx_SpaceRoomDirectory_subspace_children {
+ &::before {
+ content: "";
+ position: absolute;
+ background-color: $groupFilterPanel-bg-color;
+ width: 1px;
+ height: 100%;
+ left: 6px;
+ top: 0;
+ }
+ }
+
+ .mx_SpaceRoomDirectory_actions {
+ .mx_SpaceRoomDirectory_actionsText {
+ font-weight: normal;
+ font-size: $font-12px;
+ line-height: $font-15px;
+ color: $secondary-fg-color;
+ }
+ }
+
+ > hr {
+ border: none;
+ height: 1px;
+ background-color: rgba(141, 151, 165, 0.2);
+ margin: 20px 0;
+ }
+
+ .mx_SpaceRoomDirectory_createRoom {
+ display: block;
+ margin: 16px auto 0;
+ width: max-content;
+ }
+}
diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss
new file mode 100644
index 0000000000..503fe72414
--- /dev/null
+++ b/res/css/structures/_SpaceRoomView.scss
@@ -0,0 +1,528 @@
+/*
+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.
+*/
+
+$SpaceRoomViewInnerWidth: 428px;
+
+@define-mixin SpacePillButton {
+ position: relative;
+ padding: 16px 32px 16px 72px;
+ width: 432px;
+ box-sizing: border-box;
+ border-radius: 8px;
+ border: 1px solid $input-border-color;
+ font-size: $font-15px;
+ margin: 20px 0;
+
+ > h3 {
+ font-weight: $font-semi-bold;
+ margin: 0 0 4px;
+ }
+
+ > span {
+ color: $secondary-fg-color;
+ }
+
+ &::before {
+ position: absolute;
+ content: '';
+ width: 32px;
+ height: 32px;
+ top: 24px;
+ left: 20px;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: 24px;
+ background-color: $tertiary-fg-color;
+ }
+
+ &:hover {
+ border-color: $accent-color;
+
+ &::before {
+ background-color: $accent-color;
+ }
+
+ > span {
+ color: $primary-fg-color;
+ }
+ }
+}
+
+.mx_SpaceRoomView {
+ .mx_MainSplit > div:first-child {
+ padding: 80px 60px;
+ flex-grow: 1;
+ max-height: 100%;
+ overflow-y: auto;
+
+ h1 {
+ margin: 0;
+ font-size: $font-24px;
+ font-weight: $font-semi-bold;
+ color: $primary-fg-color;
+ width: max-content;
+ }
+
+ .mx_SpaceRoomView_description {
+ font-size: $font-15px;
+ color: $secondary-fg-color;
+ margin-top: 12px;
+ margin-bottom: 24px;
+ max-width: $SpaceRoomViewInnerWidth;
+ }
+
+ .mx_AddExistingToSpace {
+ max-width: $SpaceRoomViewInnerWidth;
+
+ .mx_AddExistingToSpace_content {
+ height: calc(100vh - 360px);
+ max-height: 400px;
+ }
+ }
+
+ &:not(.mx_SpaceRoomView_landing) .mx_SpaceFeedbackPrompt {
+ width: $SpaceRoomViewInnerWidth;
+ }
+
+ .mx_SpaceRoomView_buttons {
+ display: block;
+ margin-top: 44px;
+ width: $SpaceRoomViewInnerWidth;
+ text-align: right; // button alignment right
+
+ .mx_AccessibleButton_hasKind {
+ padding: 8px 22px;
+ margin-left: 16px;
+ }
+
+ input.mx_AccessibleButton {
+ border: none; // override default styles
+ }
+ }
+
+ .mx_Field {
+ max-width: $SpaceRoomViewInnerWidth;
+
+ & + .mx_Field {
+ margin-top: 28px;
+ }
+ }
+
+ .mx_SpaceRoomView_errorText {
+ font-weight: $font-semi-bold;
+ font-size: $font-12px;
+ line-height: $font-15px;
+ color: $notice-primary-color;
+ margin-bottom: 28px;
+ }
+
+ .mx_AccessibleButton_disabled {
+ cursor: not-allowed;
+ }
+ }
+
+ .mx_SpaceRoomView_preview {
+ padding: 32px 24px !important; // override default padding from above
+ margin: auto;
+ max-width: 480px;
+ box-sizing: border-box;
+ box-shadow: 2px 15px 30px $dialog-shadow-color;
+ border-radius: 8px;
+ position: relative;
+
+ // XXX remove this when spaces leaves Beta
+ .mx_BetaCard_betaPill {
+ position: absolute;
+ right: 24px;
+ top: 32px;
+ }
+ // XXX remove this when spaces leaves Beta
+ .mx_SpaceRoomView_preview_spaceBetaPrompt {
+ font-weight: $font-semi-bold;
+ font-size: $font-14px;
+ line-height: $font-24px;
+ color: $primary-fg-color;
+ margin-top: 24px;
+ position: relative;
+ padding-left: 24px;
+
+ .mx_AccessibleButton_kind_link {
+ display: inline;
+ padding: 0;
+ font-size: inherit;
+ line-height: inherit;
+ }
+
+ &::before {
+ content: "";
+ position: absolute;
+ height: $font-24px;
+ width: 20px;
+ left: 0;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: contain;
+ mask-image: url('$(res)/img/element-icons/room/room-summary.svg');
+ background-color: $secondary-fg-color;
+ }
+ }
+
+ .mx_SpaceRoomView_preview_inviter {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ font-size: $font-15px;
+
+ > div {
+ margin-left: 8px;
+
+ .mx_SpaceRoomView_preview_inviter_name {
+ line-height: $font-18px;
+ }
+
+ .mx_SpaceRoomView_preview_inviter_mxid {
+ line-height: $font-24px;
+ color: $secondary-fg-color;
+ }
+ }
+ }
+
+ > .mx_BaseAvatar_image,
+ > .mx_BaseAvatar > .mx_BaseAvatar_image {
+ border-radius: 12px;
+ }
+
+ h1.mx_SpaceRoomView_preview_name {
+ margin: 20px 0 !important; // override default margin from above
+ }
+
+ .mx_SpaceRoomView_preview_topic {
+ font-size: $font-14px;
+ line-height: $font-22px;
+ color: $secondary-fg-color;
+ margin: 20px 0;
+ max-height: 160px;
+ overflow-y: auto;
+ }
+
+ .mx_SpaceRoomView_preview_joinButtons {
+ margin-top: 20px;
+
+ .mx_AccessibleButton {
+ width: 200px;
+ box-sizing: border-box;
+ padding: 14px 0;
+
+ & + .mx_AccessibleButton {
+ margin-left: 20px;
+ }
+ }
+ }
+ }
+
+ .mx_SpaceRoomView_landing {
+ > .mx_BaseAvatar_image,
+ > .mx_BaseAvatar > .mx_BaseAvatar_image {
+ border-radius: 12px;
+ }
+
+ .mx_SpaceRoomView_landing_name {
+ margin: 24px 0 16px;
+ font-size: $font-15px;
+ color: $secondary-fg-color;
+
+ > span {
+ display: inline-block;
+ }
+
+ .mx_SpaceRoomView_landing_nameRow {
+ margin-top: 12px;
+
+ > h1 {
+ display: inline-block;
+ }
+ }
+
+ .mx_SpaceRoomView_landing_inviter {
+ .mx_BaseAvatar {
+ margin-right: 4px;
+ vertical-align: middle;
+ }
+ }
+ }
+
+ .mx_SpaceRoomView_landing_info {
+ display: flex;
+ align-items: center;
+
+ .mx_SpaceRoomView_info {
+ display: inline-block;
+ margin: 0 auto 0 0;
+ }
+
+ .mx_FacePile {
+ display: inline-block;
+ margin-right: 12px;
+
+ .mx_FacePile_faces {
+ cursor: pointer;
+ }
+ }
+
+ .mx_SpaceRoomView_landing_inviteButton {
+ position: relative;
+ padding: 4px 18px 4px 40px;
+ line-height: $font-24px;
+ height: min-content;
+
+ &::before {
+ position: absolute;
+ content: "";
+ left: 8px;
+ height: 16px;
+ width: 16px;
+ background: #ffffff; // white icon fill
+ mask-position: center;
+ mask-size: 16px;
+ mask-repeat: no-repeat;
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ }
+ }
+
+ .mx_SpaceRoomView_landing_settingsButton {
+ position: relative;
+ margin-left: 16px;
+ width: 24px;
+ height: 24px;
+
+ &::before {
+ position: absolute;
+ content: "";
+ left: 0;
+ top: 0;
+ height: 24px;
+ width: 24px;
+ background: $tertiary-fg-color;
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ mask-image: url('$(res)/img/element-icons/settings.svg');
+ }
+ }
+ }
+
+ .mx_SpaceRoomView_landing_topic {
+ font-size: $font-15px;
+ margin-top: 12px;
+ margin-bottom: 16px;
+ }
+
+ > hr {
+ border: none;
+ height: 1px;
+ background-color: $groupFilterPanel-bg-color;
+ }
+
+ .mx_SearchBox {
+ margin: 0 0 20px;
+ }
+
+ .mx_SpaceFeedbackPrompt {
+ margin-bottom: 16px;
+
+ // hide the HR as we have our own
+ & + hr {
+ display: none;
+ }
+ }
+ }
+
+ .mx_SpaceRoomView_privateScope {
+ > .mx_AccessibleButton {
+ @mixin SpacePillButton;
+ }
+
+ .mx_SpaceRoomView_privateScope_justMeButton::before {
+ mask-image: url('$(res)/img/element-icons/room/members.svg');
+ }
+
+ .mx_SpaceRoomView_privateScope_meAndMyTeammatesButton::before {
+ mask-image: url('$(res)/img/element-icons/community-members.svg');
+ }
+ }
+
+ .mx_SpaceRoomView_inviteTeammates {
+ // XXX remove this when spaces leaves Beta
+ .mx_SpaceRoomView_inviteTeammates_betaDisclaimer {
+ padding: 58px 16px 16px;
+ position: relative;
+ border-radius: 8px;
+ background-color: $header-panel-bg-color;
+ max-width: $SpaceRoomViewInnerWidth;
+ margin: 20px 0 30px;
+ box-sizing: border-box;
+
+ .mx_BetaCard_betaPill {
+ position: absolute;
+ left: 16px;
+ top: 16px;
+ }
+ }
+
+ .mx_SpaceRoomView_inviteTeammates_buttons {
+ color: $secondary-fg-color;
+ margin-top: 28px;
+
+ .mx_AccessibleButton {
+ position: relative;
+ display: inline-block;
+ padding-left: 32px;
+ line-height: 24px; // to center icons
+
+ &::before {
+ content: "";
+ position: absolute;
+ height: 24px;
+ width: 24px;
+ top: 0;
+ left: 0;
+ background-color: $secondary-fg-color;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: contain;
+ }
+
+ & + .mx_AccessibleButton {
+ margin-left: 32px;
+ }
+ }
+
+ .mx_SpaceRoomView_inviteTeammates_inviteDialogButton::before {
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ }
+ }
+ }
+}
+
+.mx_SpaceRoomView_info {
+ color: $secondary-fg-color;
+ font-size: $font-15px;
+ line-height: $font-24px;
+ margin: 20px 0;
+
+ .mx_SpaceRoomView_info_public,
+ .mx_SpaceRoomView_info_private {
+ padding-left: 20px;
+ position: relative;
+
+ &::before {
+ position: absolute;
+ content: "";
+ width: 20px;
+ height: 20px;
+ top: 0;
+ left: -2px;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ background-color: $tertiary-fg-color;
+ }
+ }
+
+ .mx_SpaceRoomView_info_public::before {
+ mask-size: 12px;
+ mask-image: url("$(res)/img/globe.svg");
+ }
+
+ .mx_SpaceRoomView_info_private::before {
+ mask-size: 14px;
+ mask-image: url("$(res)/img/element-icons/lock.svg");
+ }
+
+ .mx_AccessibleButton_kind_link {
+ color: inherit;
+ position: relative;
+ padding-left: 16px;
+
+ &::before {
+ content: "·"; // visual separator
+ position: absolute;
+ left: 6px;
+ }
+ }
+}
+
+.mx_SpaceFeedbackPrompt {
+ margin-top: 18px;
+ margin-bottom: 12px;
+
+ > hr {
+ border: none;
+ border-top: 1px solid $input-border-color;
+ margin-bottom: 12px;
+ }
+
+ > div {
+ display: flex;
+ flex-direction: row;
+ font-size: $font-15px;
+ line-height: $font-24px;
+
+ > span {
+ color: $secondary-fg-color;
+ position: relative;
+ padding-left: 32px;
+ font-size: inherit;
+ line-height: inherit;
+ margin-right: auto;
+
+ &::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 2px;
+ height: 20px;
+ width: 20px;
+ background-color: $secondary-fg-color;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ mask-image: url('$(res)/img/element-icons/room/room-summary.svg');
+ mask-position: center;
+ }
+ }
+
+ .mx_AccessibleButton_kind_link {
+ color: $accent-color;
+ position: relative;
+ padding: 0 0 0 24px;
+ margin-left: 8px;
+ font-size: inherit;
+ line-height: inherit;
+
+ &::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ height: 16px;
+ width: 16px;
+ background-color: $accent-color;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ mask-image: url('$(res)/img/element-icons/chat-bubbles.svg');
+ mask-position: center;
+ }
+ }
+ }
+}
diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss
index 4a4bb125a3..39a8ebed32 100644
--- a/res/css/structures/_TabbedView.scss
+++ b/res/css/structures/_TabbedView.scss
@@ -17,7 +17,7 @@ limitations under the License.
.mx_TabbedView {
margin: 0;
- padding: 0 0 0 58px;
+ padding: 0 0 0 16px;
display: flex;
flex-direction: column;
position: absolute;
@@ -25,6 +25,7 @@ limitations under the License.
bottom: 0;
left: 0;
right: 0;
+ margin-top: 8px;
}
.mx_TabbedView_tabLabels {
@@ -35,13 +36,13 @@ limitations under the License.
}
.mx_TabbedView_tabLabel {
+ display: flex;
+ align-items: center;
vertical-align: text-top;
cursor: pointer;
- display: block;
- border-radius: 3px;
- font-size: $font-14px;
- min-height: 24px; // use min-height instead of height to allow the label to overflow a bit
- margin-bottom: 6px;
+ padding: 8px 0;
+ border-radius: 8px;
+ font-size: $font-13px;
position: relative;
}
@@ -51,9 +52,8 @@ limitations under the License.
}
.mx_TabbedView_maskedIcon {
- margin-left: 6px;
- margin-right: 9px;
- margin-top: 1px;
+ margin-left: 8px;
+ margin-right: 16px;
width: 16px;
height: 16px;
display: inline-block;
@@ -65,10 +65,9 @@ limitations under the License.
mask-repeat: no-repeat;
mask-size: 16px;
width: 16px;
- height: 22px;
+ height: 16px;
mask-position: center;
content: '';
- vertical-align: middle;
}
.mx_TabbedView_tabLabel_active .mx_TabbedView_maskedIcon::before {
diff --git a/res/css/structures/_ToastContainer.scss b/res/css/structures/_ToastContainer.scss
index e798e4ac52..09f834a6e3 100644
--- a/res/css/structures/_ToastContainer.scss
+++ b/res/css/structures/_ToastContainer.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2019 The Matrix.org Foundation C.I.C.
+Copyright 2019-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.
@@ -80,8 +80,9 @@ limitations under the License.
}
}
- &.mx_Toast_icon_element_logo::after {
- background-image: url("$(res)/img/element-logo.svg");
+ &.mx_Toast_icon_secure_backup::after {
+ mask-image: url('$(res)/img/feather-customised/secure-backup.svg');
+ background-color: $primary-fg-color;
}
.mx_Toast_title, .mx_Toast_body {
@@ -157,6 +158,10 @@ limitations under the License.
}
}
+ .mx_Toast_detail {
+ color: $secondary-fg-color;
+ }
+
.mx_Toast_deviceID {
font-size: $font-10px;
}
diff --git a/res/css/structures/_UploadBar.scss b/res/css/structures/_UploadBar.scss
index d76c81668c..7c62516b47 100644
--- a/res/css/structures/_UploadBar.scss
+++ b/res/css/structures/_UploadBar.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2015, 2016 OpenMarket Ltd
+Copyright 2015, 2016, 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.
@@ -15,47 +15,45 @@ limitations under the License.
*/
.mx_UploadBar {
+ padding-left: 65px; // line up with the shield area in the composer
position: relative;
+
+ .mx_ProgressBar {
+ width: calc(100% - 40px); // cheating at a right margin
+ }
}
-.mx_UploadBar_uploadProgressOuter {
- height: 5px;
- margin-left: 63px;
- margin-top: -1px;
- padding-bottom: 5px;
-}
-
-.mx_UploadBar_uploadProgressInner {
- background-color: $accent-color;
- height: 5px;
-}
-
-.mx_UploadBar_uploadFilename {
+.mx_UploadBar_filename {
margin-top: 5px;
- margin-left: 65px;
- opacity: 0.5;
- color: $primary-fg-color;
-}
-
-.mx_UploadBar_uploadIcon {
- float: left;
- margin-top: 5px;
- margin-left: 14px;
-}
-
-.mx_UploadBar_uploadCancel {
- float: right;
- margin-top: 5px;
- margin-right: 10px;
+ color: $muted-fg-color;
position: relative;
- opacity: 0.6;
- cursor: pointer;
- z-index: 1;
+ padding-left: 22px; // 18px for icon, 4px for padding
+ font-size: $font-15px;
+ vertical-align: middle;
+
+ &::before {
+ content: "";
+ height: 18px;
+ width: 18px;
+ position: absolute;
+ top: 0;
+ left: 0;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ background-color: $muted-fg-color;
+ mask-image: url('$(res)/img/element-icons/upload.svg');
+ }
}
-.mx_UploadBar_uploadBytes {
- float: right;
- margin-top: 5px;
- margin-right: 30px;
- color: $accent-color;
+.mx_UploadBar_cancel {
+ position: absolute;
+ top: 0;
+ right: 0;
+ height: 16px;
+ width: 16px;
+ margin-right: 16px; // align over rightmost button in composer
+ mask-repeat: no-repeat;
+ mask-position: center;
+ background-color: $muted-fg-color;
+ mask-image: url('$(res)/img/icons-close.svg');
}
diff --git a/res/css/structures/_UserMenu.scss b/res/css/structures/_UserMenu.scss
index 78795c85a2..17e6ad75df 100644
--- a/res/css/structures/_UserMenu.scss
+++ b/res/css/structures/_UserMenu.scss
@@ -15,10 +15,33 @@ limitations under the License.
*/
.mx_UserMenu {
-
- // to make the ... button sort of aligned with the explore button below
+ // to make the menu button sort of aligned with the explore button below
padding-right: 6px;
+ &.mx_UserMenu_prototype {
+ // The margin & padding combination between here and the ::after is to
+ // align the border line with the tag panel.
+ margin-bottom: 6px;
+
+ padding-right: 0; // make the right edge line up with the explore button
+
+ .mx_UserMenu_headerButtons {
+ // considering we've eliminated right padding on the menu itself, we need to
+ // push the chevron in slightly (roughly lining up with the center of the
+ // plus buttons)
+ margin-right: 2px;
+ }
+
+ // we cheat opacity on the theme colour with an after selector here
+ &::after {
+ content: '';
+ border-bottom: 1px solid $primary-fg-color; // XXX: Variable abuse
+ opacity: 0.2;
+ display: block;
+ padding-top: 8px;
+ }
+ }
+
.mx_UserMenu_headerButtons {
width: 16px;
height: 16px;
@@ -35,8 +58,8 @@ limitations under the License.
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
- background: $primary-fg-color;
- mask-image: url('$(res)/img/element-icons/context-menu.svg');
+ background: $tertiary-fg-color;
+ mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
}
}
@@ -49,6 +72,7 @@ limitations under the License.
position: relative; // to make default avatars work
margin-right: 8px;
height: 32px; // to remove the unknown 4px gap the browser puts below it
+ padding: 3px 0; // to align with and without using doubleName
.mx_UserMenu_userAvatar {
border-radius: 32px; // should match avatar size
@@ -56,6 +80,28 @@ limitations under the License.
}
}
+ .mx_UserMenu_doubleName {
+ flex: 1;
+ min-width: 0; // make flexbox aware that it can crush this to a tiny width
+
+ .mx_UserMenu_userName,
+ .mx_UserMenu_subUserName {
+ display: block;
+ }
+
+ .mx_UserMenu_subUserName {
+ color: $muted-fg-color;
+ font-size: $font-13px;
+ line-height: $font-18px;
+ flex: 1;
+
+ // Ellipsize any text overflow
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+ }
+
.mx_UserMenu_userName {
font-weight: 600;
font-size: $font-15px;
@@ -71,23 +117,83 @@ limitations under the License.
.mx_UserMenu_headerButtons {
// No special styles: the rest of the layout happens to make it work.
}
+
+ .mx_UserMenu_dnd {
+ width: 24px;
+ height: 24px;
+ margin-right: 8px;
+ position: relative;
+
+ &::before {
+ content: '';
+ position: absolute;
+ width: 24px;
+ height: 24px;
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ background: $muted-fg-color;
+ }
+
+ &.mx_UserMenu_dnd_noisy::before {
+ mask-image: url('$(res)/img/element-icons/notifications.svg');
+ }
+
+ &.mx_UserMenu_dnd_muted::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/notifications-off.svg');
+ }
+ }
}
&.mx_UserMenu_minimized {
- .mx_UserMenu_userHeader {
- .mx_UserMenu_row {
- justify-content: center;
- }
+ padding-right: 0px;
- .mx_UserMenu_userAvatarContainer {
- margin-right: 0;
- }
+ .mx_UserMenu_userAvatarContainer {
+ margin-right: 0px;
}
}
}
.mx_UserMenu_contextMenu {
- width: 247px;
+ width: 258px;
+
+ // These override the styles already present on the user menu rather than try to
+ // define a new menu. They are specifically for the stacked menu when a community
+ // is being represented as a prototype.
+ &.mx_UserMenu_contextMenu_prototype {
+ padding-bottom: 16px;
+
+ .mx_UserMenu_contextMenu_header {
+ padding-bottom: 0;
+ padding-top: 16px;
+
+ &:nth-child(n + 2) {
+ padding-top: 8px;
+ }
+ }
+
+ hr {
+ width: 85%;
+ opacity: 0.2;
+ border: none;
+ border-bottom: 1px solid $primary-fg-color; // XXX: Variable abuse
+ }
+
+ &.mx_IconizedContextMenu {
+ > .mx_IconizedContextMenu_optionList {
+ margin-top: 4px;
+
+ &::before {
+ border: none;
+ }
+
+ > .mx_AccessibleButton {
+ padding-top: 2px;
+ padding-bottom: 2px;
+ }
+ }
+ }
+ }
&.mx_IconizedContextMenu .mx_IconizedContextMenu_optionList_red {
.mx_AccessibleButton {
@@ -147,6 +253,30 @@ limitations under the License.
align-items: center;
justify-content: center;
}
+
+ &.mx_UserMenu_contextMenu_guestPrompts,
+ &.mx_UserMenu_contextMenu_hostingLink {
+ padding-top: 0;
+ }
+
+ &.mx_UserMenu_contextMenu_guestPrompts {
+ display: inline-block;
+
+ > span {
+ font-weight: 600;
+ display: block;
+
+ & + span {
+ margin-top: 8px;
+ }
+ }
+
+ .mx_AccessibleButton_kind_link {
+ font-weight: normal;
+ font-size: inherit;
+ padding: 0;
+ }
+ }
}
.mx_IconizedContextMenu_icon {
@@ -169,6 +299,9 @@ limitations under the License.
.mx_UserMenu_iconHome::before {
mask-image: url('$(res)/img/element-icons/roomlist/home.svg');
}
+ .mx_UserMenu_iconHosting::before {
+ mask-image: url('$(res)/img/element-icons/brands/element.svg');
+ }
.mx_UserMenu_iconBell::before {
mask-image: url('$(res)/img/element-icons/notifications.svg');
@@ -193,4 +326,12 @@ limitations under the License.
.mx_UserMenu_iconSignOut::before {
mask-image: url('$(res)/img/element-icons/leave.svg');
}
+
+ .mx_UserMenu_iconMembers::before {
+ mask-image: url('$(res)/img/element-icons/room/members.svg');
+ }
+
+ .mx_UserMenu_iconInvite::before {
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ }
}
diff --git a/res/css/structures/_ViewSource.scss b/res/css/structures/_ViewSource.scss
index 421d1f03cd..248eab5d88 100644
--- a/res/css/structures/_ViewSource.scss
+++ b/res/css/structures/_ViewSource.scss
@@ -14,17 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_ViewSource_label_left {
- float: left;
-}
-
-.mx_ViewSource_label_right {
- float: right;
-}
-
-.mx_ViewSource_label_bottom {
+.mx_ViewSource_separator {
clear: both;
border-bottom: 1px solid #e5e5e5;
+ padding-top: 0.7em;
+ padding-bottom: 0.7em;
+}
+
+.mx_ViewSource_heading {
+ font-size: $font-17px;
+ font-weight: 400;
+ color: $primary-fg-color;
+ margin-top: 0.7em;
}
.mx_ViewSource pre {
@@ -34,3 +35,7 @@ limitations under the License.
word-wrap: break-word;
white-space: pre-wrap;
}
+
+.mx_ViewSource_details {
+ margin-top: 0.8em;
+}
diff --git a/res/css/structures/auth/_CompleteSecurity.scss b/res/css/structures/auth/_CompleteSecurity.scss
index f742be70e4..80e7aaada0 100644
--- a/res/css/structures/auth/_CompleteSecurity.scss
+++ b/res/css/structures/auth/_CompleteSecurity.scss
@@ -26,50 +26,6 @@ limitations under the License.
position: relative;
}
-.mx_CompleteSecurity_clients {
- width: max-content;
- margin: 36px auto 0;
-
- .mx_CompleteSecurity_clients_desktop, .mx_CompleteSecurity_clients_mobile {
- position: relative;
- width: 160px;
- text-align: center;
- padding-top: 64px;
- display: inline-block;
-
- &::before {
- content: '';
- position: absolute;
- height: 48px;
- width: 48px;
- left: 56px;
- top: 0;
- background-color: $muted-fg-color;
- mask-repeat: no-repeat;
- mask-size: contain;
- }
- }
-
- .mx_CompleteSecurity_clients_desktop {
- margin-right: 56px;
- }
-
- .mx_CompleteSecurity_clients_desktop::before {
- mask-image: url('$(res)/img/feather-customised/monitor.svg');
- }
-
- .mx_CompleteSecurity_clients_mobile::before {
- mask-image: url('$(res)/img/feather-customised/smartphone.svg');
- }
-
- p {
- margin-top: 16px;
- font-size: $font-12px;
- color: $muted-fg-color;
- text-align: center;
- }
-}
-
.mx_CompleteSecurity_heroIcon {
width: 128px;
height: 128px;
diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss
index 02436833a2..9c98ca3a1c 100644
--- a/res/css/structures/auth/_Login.scss
+++ b/res/css/structures/auth/_Login.scss
@@ -18,7 +18,7 @@ limitations under the License.
.mx_Login_submit {
@mixin mx_DialogButton;
width: 100%;
- margin-top: 35px;
+ margin-top: 24px;
margin-bottom: 24px;
box-sizing: border-box;
text-align: center;
@@ -33,12 +33,6 @@ limitations under the License.
cursor: default;
}
-.mx_AuthBody a.mx_Login_sso_link:link,
-.mx_AuthBody a.mx_Login_sso_link:hover,
-.mx_AuthBody a.mx_Login_sso_link:visited {
- color: $button-primary-fg-color;
-}
-
.mx_Login_loader {
display: inline;
position: relative;
@@ -87,10 +81,13 @@ limitations under the License.
}
.mx_Login_underlinedServerName {
+ width: max-content;
border-bottom: 1px dashed $accent-color;
}
div.mx_AccessibleButton_kind_link.mx_Login_forgot {
+ display: block;
+ margin: 0 auto;
// style it as a link
font-size: inherit;
padding: 0;
diff --git a/res/css/views/auth/_AuthBody.scss b/res/css/views/auth/_AuthBody.scss
index 0ba0d10e06..90dca32e48 100644
--- a/res/css/views/auth/_AuthBody.scss
+++ b/res/css/views/auth/_AuthBody.scss
@@ -34,7 +34,11 @@ limitations under the License.
h3 {
font-size: $font-14px;
font-weight: 600;
- color: $authpage-primary-color;
+ color: $authpage-secondary-color;
+ }
+
+ h3.mx_AuthBody_centered {
+ text-align: center;
}
a:link,
@@ -96,12 +100,6 @@ limitations under the License.
}
}
-.mx_AuthBody_editServerDetails {
- padding-left: 1em;
- font-size: $font-12px;
- font-weight: normal;
-}
-
.mx_AuthBody_fieldRow {
display: flex;
margin-bottom: 10px;
@@ -146,6 +144,14 @@ limitations under the License.
display: block;
text-align: center;
width: 100%;
+
+ > a {
+ font-weight: $font-semi-bold;
+ }
+}
+
+.mx_SSOButtons + .mx_AuthBody_changeFlow {
+ margin-top: 24px;
}
.mx_AuthBody_spinner {
diff --git a/res/css/views/auth/_AuthHeader.scss b/res/css/views/auth/_AuthHeader.scss
index b1372affee..13d5195160 100644
--- a/res/css/views/auth/_AuthHeader.scss
+++ b/res/css/views/auth/_AuthHeader.scss
@@ -18,7 +18,7 @@ limitations under the License.
display: flex;
flex-direction: column;
width: 206px;
- padding: 25px 40px;
+ padding: 25px 25px;
box-sizing: border-box;
}
diff --git a/res/css/views/auth/_AuthHeaderLogo.scss b/res/css/views/auth/_AuthHeaderLogo.scss
index 917dcabf67..86f0313b68 100644
--- a/res/css/views/auth/_AuthHeaderLogo.scss
+++ b/res/css/views/auth/_AuthHeaderLogo.scss
@@ -17,7 +17,7 @@ limitations under the License.
.mx_AuthHeaderLogo {
margin-top: 15px;
flex: 1;
- padding: 0 10px;
+ padding: 0 25px;
}
.mx_AuthHeaderLogo img {
diff --git a/res/css/views/auth/_InteractiveAuthEntryComponents.scss b/res/css/views/auth/_InteractiveAuthEntryComponents.scss
index 05cddf2c48..ffaad3cd7a 100644
--- a/res/css/views/auth/_InteractiveAuthEntryComponents.scss
+++ b/res/css/views/auth/_InteractiveAuthEntryComponents.scss
@@ -14,6 +14,35 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+.mx_InteractiveAuthEntryComponents_emailWrapper {
+ padding-right: 100px;
+ position: relative;
+ margin-top: 32px;
+ margin-bottom: 32px;
+
+ &::before, &::after {
+ position: absolute;
+ width: 116px;
+ height: 116px;
+ content: "";
+ right: -10px;
+ }
+
+ &::before {
+ background-color: rgba(244, 246, 250, 0.91);
+ border-radius: 50%;
+ top: -20px;
+ }
+
+ &::after {
+ background-image: url('$(res)/img/element-icons/email-prompt.svg');
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: contain;
+ top: -25px;
+ }
+}
+
.mx_InteractiveAuthEntryComponents_msisdnWrapper {
text-align: center;
}
@@ -54,7 +83,10 @@ limitations under the License.
}
.mx_InteractiveAuthEntryComponents_termsPolicy {
- display: block;
+ display: flex;
+ flex-direction: row;
+ justify-content: start;
+ align-items: center;
}
.mx_InteractiveAuthEntryComponents_passwordSection {
diff --git a/res/css/views/auth/_LanguageSelector.scss b/res/css/views/auth/_LanguageSelector.scss
index 781561f876..885ee7f30d 100644
--- a/res/css/views/auth/_LanguageSelector.scss
+++ b/res/css/views/auth/_LanguageSelector.scss
@@ -23,6 +23,7 @@ limitations under the License.
font-size: $font-14px;
font-weight: 600;
color: $authpage-lang-color;
+ width: auto;
}
.mx_AuthBody_language .mx_Dropdown_arrow {
diff --git a/res/css/views/auth/_ServerTypeSelector.scss b/res/css/views/auth/_ServerTypeSelector.scss
deleted file mode 100644
index fbd3d2655d..0000000000
--- a/res/css/views/auth/_ServerTypeSelector.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-Copyright 2019 New Vector Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-.mx_ServerTypeSelector {
- display: flex;
- margin-bottom: 28px;
-}
-
-.mx_ServerTypeSelector_type {
- margin: 0 5px;
-}
-
-.mx_ServerTypeSelector_type:first-child {
- margin-left: 0;
-}
-
-.mx_ServerTypeSelector_type:last-child {
- margin-right: 0;
-}
-
-.mx_ServerTypeSelector_label {
- text-align: center;
- font-weight: 600;
- color: $authpage-primary-color;
- margin: 8px 0;
-}
-
-.mx_ServerTypeSelector_type .mx_AccessibleButton {
- padding: 10px;
- border: 1px solid $input-border-color;
- border-radius: 4px;
-}
-
-.mx_ServerTypeSelector_type.mx_ServerTypeSelector_type_selected .mx_AccessibleButton {
- border-color: $input-valid-border-color;
-}
-
-.mx_ServerTypeSelector_logo {
- display: flex;
- justify-content: center;
- height: 18px;
- margin-bottom: 12px;
- font-weight: 600;
- color: $authpage-primary-color;
-}
-
-.mx_ServerTypeSelector_logo > div {
- display: flex;
- width: 70%;
- align-items: center;
- justify-content: space-evenly;
-}
-
-.mx_ServerTypeSelector_description {
- font-size: $font-10px;
-}
diff --git a/res/css/views/auth/_Welcome.scss b/res/css/views/auth/_Welcome.scss
index 9043289184..894174d6e2 100644
--- a/res/css/views/auth/_Welcome.scss
+++ b/res/css/views/auth/_Welcome.scss
@@ -18,9 +18,14 @@ limitations under the License.
display: flex;
flex-direction: column;
align-items: center;
+ &.mx_WelcomePage_registrationDisabled {
+ .mx_ButtonCreateAccount {
+ display: none;
+ }
+ }
}
.mx_Welcome .mx_AuthBody_language {
- width: 120px;
+ width: 160px;
margin-bottom: 10px;
}
diff --git a/res/css/views/avatars/_BaseAvatar.scss b/res/css/views/avatars/_BaseAvatar.scss
index 1a1e14e7ac..cbddd97e18 100644
--- a/res/css/views/avatars/_BaseAvatar.scss
+++ b/res/css/views/avatars/_BaseAvatar.scss
@@ -41,7 +41,7 @@ limitations under the License.
.mx_BaseAvatar_image {
object-fit: cover;
- border-radius: 40px;
+ border-radius: 125px;
vertical-align: top;
background-color: $avatar-bg-color;
}
diff --git a/res/css/views/avatars/_DecoratedRoomAvatar.scss b/res/css/views/avatars/_DecoratedRoomAvatar.scss
index 48d72131b5..2631cbfb40 100644
--- a/res/css/views/avatars/_DecoratedRoomAvatar.scss
+++ b/res/css/views/avatars/_DecoratedRoomAvatar.scss
@@ -14,14 +14,52 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-// XXX: We shouldn't be using TemporaryTile anywhere - delete it.
-.mx_DecoratedRoomAvatar, .mx_TemporaryTile {
+.mx_DecoratedRoomAvatar, .mx_ExtraTile {
position: relative;
- .mx_RoomTileIcon {
+ &.mx_DecoratedRoomAvatar_cutout .mx_BaseAvatar {
+ mask-image: url('$(res)/img/element-icons/roomlist/decorated-avatar-mask.svg');
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ }
+
+ .mx_DecoratedRoomAvatar_icon {
position: absolute;
- bottom: 0;
- right: 0;
+ bottom: -2px;
+ right: -2px;
+ margin: 4px;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ }
+
+ .mx_DecoratedRoomAvatar_icon::before {
+ content: '';
+ width: 8px;
+ height: 8px;
+ position: absolute;
+ border-radius: 8px;
+ }
+
+ .mx_DecoratedRoomAvatar_icon_globe::before {
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ background: $secondary-fg-color;
+ mask-image: url('$(res)/img/globe.svg');
+ }
+
+ .mx_DecoratedRoomAvatar_icon_offline::before {
+ background-color: $presence-offline;
+ }
+
+ .mx_DecoratedRoomAvatar_icon_online::before {
+ background-color: $presence-online;
+ }
+
+ .mx_DecoratedRoomAvatar_icon_away::before {
+ background-color: $presence-away;
}
.mx_NotificationBadge, .mx_RoomTile_badgeContainer {
diff --git a/src/email.js b/res/css/views/avatars/_WidgetAvatar.scss
similarity index 74%
rename from src/email.js
rename to res/css/views/avatars/_WidgetAvatar.scss
index 6e2ed69bb7..8e5cfb54d8 100644
--- a/src/email.js
+++ b/res/css/views/avatars/_WidgetAvatar.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2016 OpenMarket Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-const EMAIL_ADDRESS_REGEX = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;
-
-export function looksValid(email) {
- return EMAIL_ADDRESS_REGEX.test(email);
+.mx_WidgetAvatar {
+ border-radius: 4px;
}
diff --git a/res/css/views/beta/_BetaCard.scss b/res/css/views/beta/_BetaCard.scss
new file mode 100644
index 0000000000..3463a653fc
--- /dev/null
+++ b/res/css/views/beta/_BetaCard.scss
@@ -0,0 +1,114 @@
+/*
+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_BetaCard {
+ margin-bottom: 20px;
+ padding: 24px;
+ background-color: $settings-profile-placeholder-bg-color;
+ border-radius: 8px;
+ display: flex;
+ box-sizing: border-box;
+
+ > div {
+ .mx_BetaCard_title {
+ font-weight: $font-semi-bold;
+ font-size: $font-18px;
+ line-height: $font-22px;
+ color: $primary-fg-color;
+ margin: 4px 0 14px;
+
+ .mx_BetaCard_betaPill {
+ margin-left: 12px;
+ }
+ }
+
+ .mx_BetaCard_caption {
+ font-size: $font-15px;
+ line-height: $font-20px;
+ color: $secondary-fg-color;
+ margin-bottom: 20px;
+ }
+
+ .mx_AccessibleButton {
+ display: block;
+ margin: 12px 0;
+ padding: 7px 40px;
+ width: auto;
+ }
+
+ .mx_BetaCard_disclaimer {
+ font-size: $font-12px;
+ line-height: $font-15px;
+ color: $secondary-fg-color;
+ margin-top: 20px;
+ }
+ }
+
+ > img {
+ margin: auto 0 auto 20px;
+ width: 300px;
+ object-fit: contain;
+ height: 100%;
+ }
+}
+
+.mx_BetaCard_betaPill {
+ background-color: $accent-color-alt;
+ padding: 4px 10px;
+ border-radius: 8px;
+ text-transform: uppercase;
+ font-size: 12px;
+ line-height: 15px;
+ color: #FFFFFF;
+ display: inline-block;
+ vertical-align: text-bottom;
+
+ &.mx_BetaCard_betaPill_clickable {
+ cursor: pointer;
+ }
+}
+
+$pulse-color: $accent-color-alt;
+$dot-size: 12px;
+
+.mx_BetaDot {
+ border-radius: 50%;
+ margin: 10px;
+ height: $dot-size;
+ width: $dot-size;
+ transform: scale(1);
+ background: rgba($pulse-color, 1);
+ box-shadow: 0 0 0 0 rgba($pulse-color, 1);
+ animation: mx_Beta_bluePulse 2s infinite;
+ animation-iteration-count: 20;
+}
+
+@keyframes mx_Beta_bluePulse {
+ 0% {
+ transform: scale(0.95);
+ box-shadow: 0 0 0 0 rgba($pulse-color, 0.7);
+ }
+
+ 70% {
+ transform: scale(1);
+ box-shadow: 0 0 0 10px rgba($pulse-color, 0);
+ }
+
+ 100% {
+ transform: scale(0.95);
+ box-shadow: 0 0 0 0 rgba($pulse-color, 0);
+ }
+}
diff --git a/res/css/views/context_menus/_CallContextMenu.scss b/res/css/views/context_menus/_CallContextMenu.scss
new file mode 100644
index 0000000000..55b73b0344
--- /dev/null
+++ b/res/css/views/context_menus/_CallContextMenu.scss
@@ -0,0 +1,23 @@
+/*
+Copyright 2020 New Vector Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_CallContextMenu_item {
+ width: 205px;
+ height: 40px;
+ padding-left: 16px;
+ line-height: 40px;
+ vertical-align: center;
+}
diff --git a/res/css/views/context_menus/_IconizedContextMenu.scss b/res/css/views/context_menus/_IconizedContextMenu.scss
index 7913058995..204435995f 100644
--- a/res/css/views/context_menus/_IconizedContextMenu.scss
+++ b/res/css/views/context_menus/_IconizedContextMenu.scss
@@ -75,6 +75,11 @@ limitations under the License.
background-color: $menu-selected-color;
}
+ &.mx_AccessibleButton_disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+
img, .mx_IconizedContextMenu_icon { // icons
width: 16px;
min-width: 16px;
@@ -82,7 +87,6 @@ limitations under the License.
}
span.mx_IconizedContextMenu_label { // labels
- padding-left: 14px;
width: 100%;
flex: 1;
@@ -91,6 +95,10 @@ limitations under the License.
overflow: hidden;
white-space: nowrap;
}
+
+ .mx_IconizedContextMenu_icon + .mx_IconizedContextMenu_label {
+ padding-left: 14px;
+ }
}
}
diff --git a/res/css/views/context_menus/_RoomTileContextMenu.scss b/res/css/views/context_menus/_RoomTileContextMenu.scss
deleted file mode 100644
index 9697ac9bef..0000000000
--- a/res/css/views/context_menus/_RoomTileContextMenu.scss
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-Copyright 2015, 2016 OpenMarket Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-.mx_RoomTileContextMenu {
- padding: 6px;
-}
-
-.mx_RoomTileContextMenu_tag_icon {
- padding-right: 8px;
- padding-left: 4px;
- display: inline-block;
-}
-
-.mx_RoomTileContextMenu_tag_icon_set {
- padding-right: 8px;
- padding-left: 4px;
- display: none;
-}
-
-.mx_RoomTileContextMenu_tag_field, .mx_RoomTileContextMenu_leave {
- padding-top: 8px;
- padding-right: 20px;
- padding-bottom: 8px;
- cursor: pointer;
- white-space: nowrap;
- display: flex;
- align-items: center;
- line-height: $font-16px;
-}
-
-.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldSet {
- font-weight: bold;
-}
-
-.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldSet .mx_RoomTileContextMenu_tag_icon {
- display: none;
-}
-
-.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldSet .mx_RoomTileContextMenu_tag_icon_set {
- display: inline-block;
-}
-
-.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldDisabled {
- color: rgba(0, 0, 0, 0.2);
-}
-
-.mx_RoomTileContextMenu_separator {
- margin-top: 0;
- margin-bottom: 0;
- border-bottom-style: none;
- border-left-style: none;
- border-right-style: none;
- border-top-style: solid;
- border-top-width: 1px;
- border-color: $menu-border-color;
-}
-
-.mx_RoomTileContextMenu_leave {
- color: $warning-color;
-}
-
-.mx_RoomTileContextMenu_notif_picker {
- position: absolute;
- top: 16px;
- left: 5px;
-}
-
-.mx_RoomTileContextMenu_notif_field {
- padding-top: 4px;
- padding-right: 6px;
- padding-bottom: 10px;
- padding-left: 8px; /* 20px */
- cursor: pointer;
- white-space: nowrap;
- display: flex;
- align-items: center;
-}
-
-.mx_RoomTileContextMenu_notif_field.mx_RoomTileContextMenu_notif_fieldSet {
- font-weight: bold;
-}
-
-.mx_RoomTileContextMenu_notif_field.mx_RoomTileContextMenu_notif_fieldDisabled {
- color: rgba(0, 0, 0, 0.2);
-}
-
-.mx_RoomTileContextMenu_notif_icon {
- padding-right: 4px;
- padding-left: 4px;
-}
-
-.mx_RoomTileContextMenu_notif_activeIcon {
- display: inline-block;
- opacity: 0;
- position: relative;
- left: -5px;
-}
-
-.mx_RoomTileContextMenu_notif_fieldSet .mx_RoomTileContextMenu_notif_activeIcon {
- opacity: 1;
-}
diff --git a/res/css/views/context_menus/_TopLeftMenu.scss b/res/css/views/context_menus/_TopLeftMenu.scss
deleted file mode 100644
index e0f5dd47bd..0000000000
--- a/res/css/views/context_menus/_TopLeftMenu.scss
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
-Copyright 2018 New Vector Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-.mx_TopLeftMenu {
- min-width: 210px;
- border-radius: 4px;
-
- .mx_TopLeftMenu_greyedText {
- font-size: $font-12px;
- opacity: 0.5;
- }
-
- .mx_TopLeftMenu_upgradeLink {
- font-size: $font-12px;
-
- img {
- margin-left: 5px;
- }
- }
-
- .mx_TopLeftMenu_section:not(:last-child) {
- border-bottom: 1px solid $menu-border-color;
- }
-
- .mx_TopLeftMenu_section_noIcon {
- margin: 5px 0;
- padding: 5px 20px 5px 15px;
-
- div:not(:first-child) {
- margin-top: 5px;
- }
- }
-
- .mx_TopLeftMenu_section_withIcon {
- margin: 5px 0;
- padding: 0;
- list-style: none;
-
- .mx_TopLeftMenu_icon_home::after {
- mask-image: url('$(res)/img/feather-customised/home.svg');
- }
-
- .mx_TopLeftMenu_icon_help::after {
- mask-image: url('$(res)/img/feather-customised/life-buoy.svg');
- }
-
- .mx_TopLeftMenu_icon_settings::after {
- mask-image: url('$(res)/img/feather-customised/settings.svg');
- }
-
- .mx_TopLeftMenu_icon_signin::after {
- mask-image: url('$(res)/img/feather-customised/sign-in.svg');
- }
-
- .mx_TopLeftMenu_icon_signout::after {
- mask-image: url('$(res)/img/feather-customised/sign-out.svg');
- }
-
- .mx_AccessibleButton::after {
- mask-repeat: no-repeat;
- mask-position: 0 center;
- mask-size: $font-16px;
- position: absolute;
- width: $font-16px;
- height: $font-16px;
- content: "";
- top: 5px;
- left: 14px;
- background-color: $primary-fg-color;
- }
-
- .mx_AccessibleButton {
- position: relative;
- cursor: pointer;
- white-space: nowrap;
- padding: 5px 20px 5px 43px;
- }
-
- .mx_AccessibleButton:hover {
- background-color: $menu-selected-color;
- }
- }
-}
diff --git a/res/css/views/context_menus/_WidgetContextMenu.scss b/res/css/views/context_menus/_WidgetContextMenu.scss
deleted file mode 100644
index 60b7b93f99..0000000000
--- a/res/css/views/context_menus/_WidgetContextMenu.scss
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-Copyright 2019 The Matrix.org Foundaction 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_WidgetContextMenu {
- padding: 6px;
-
- .mx_WidgetContextMenu_option {
- padding: 3px 6px 3px 6px;
- cursor: pointer;
- white-space: nowrap;
- }
-
- .mx_WidgetContextMenu_separator {
- margin-top: 0;
- margin-bottom: 0;
- border-bottom-style: none;
- border-left-style: none;
- border-right-style: none;
- border-top-style: solid;
- border-top-width: 1px;
- border-color: $menu-border-color;
- }
-}
diff --git a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss
new file mode 100644
index 0000000000..2776c477fc
--- /dev/null
+++ b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss
@@ -0,0 +1,281 @@
+/*
+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_AddExistingToSpaceDialog_wrapper {
+ .mx_Dialog {
+ display: flex;
+ flex-direction: column;
+ }
+}
+
+.mx_AddExistingToSpace {
+ .mx_SearchBox {
+ // To match the space around the title
+ margin: 0 0 15px 0;
+ flex-grow: 0;
+ }
+
+ .mx_AddExistingToSpace_content {
+ flex-grow: 1;
+ }
+
+ .mx_AddExistingToSpace_noResults {
+ display: block;
+ margin-top: 24px;
+ }
+
+ .mx_AddExistingToSpace_section {
+ &:not(:first-child) {
+ margin-top: 24px;
+ }
+
+ > h3 {
+ margin: 0;
+ color: $secondary-fg-color;
+ font-size: $font-12px;
+ font-weight: $font-semi-bold;
+ line-height: $font-15px;
+ }
+
+ .mx_AddExistingToSpace_entry {
+ display: flex;
+ margin-top: 12px;
+
+ // we can't target .mx_BaseAvatar here as it'll break the decorated avatar styling
+ .mx_DecoratedRoomAvatar {
+ margin-right: 12px;
+ }
+
+ .mx_AddExistingToSpace_entry_name {
+ font-size: $font-15px;
+ line-height: 30px;
+ flex-grow: 1;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ margin-right: 12px;
+ }
+
+ .mx_Checkbox {
+ align-items: center;
+ }
+ }
+ }
+
+ .mx_AddExistingToSpace_section_spaces {
+ .mx_BaseAvatar {
+ margin-right: 12px;
+ }
+
+ .mx_BaseAvatar_image {
+ border-radius: 8px;
+ }
+ }
+
+ .mx_AddExistingToSpace_section_experimental {
+ position: relative;
+ border-radius: 8px;
+ margin: 12px 0;
+ padding: 8px 8px 8px 42px;
+ background-color: $header-panel-bg-color;
+
+ font-size: $font-12px;
+ line-height: $font-15px;
+ color: $secondary-fg-color;
+
+ &::before {
+ content: '';
+ position: absolute;
+ left: 10px;
+ top: calc(50% - 8px); // vertical centering
+ height: 16px;
+ width: 16px;
+ background-color: $secondary-fg-color;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ mask-image: url('$(res)/img/element-icons/room/room-summary.svg');
+ mask-position: center;
+ }
+ }
+
+ .mx_AddExistingToSpace_footer {
+ display: flex;
+ margin-top: 20px;
+
+ > span {
+ flex-grow: 1;
+ font-size: $font-12px;
+ line-height: $font-15px;
+ color: $secondary-fg-color;
+
+ .mx_ProgressBar {
+ height: 8px;
+ width: 100%;
+
+ @mixin ProgressBarBorderRadius 8px;
+ }
+
+ .mx_AddExistingToSpace_progressText {
+ margin-top: 8px;
+ font-size: $font-15px;
+ line-height: $font-24px;
+ color: $primary-fg-color;
+ }
+
+ > * {
+ vertical-align: middle;
+ }
+ }
+
+ .mx_AddExistingToSpace_error {
+ padding-left: 12px;
+
+ > img {
+ align-self: center;
+ }
+
+ .mx_AddExistingToSpace_errorHeading {
+ font-weight: $font-semi-bold;
+ font-size: $font-15px;
+ line-height: $font-18px;
+ color: $notice-primary-color;
+ }
+
+ .mx_AddExistingToSpace_errorCaption {
+ margin-top: 4px;
+ font-size: $font-12px;
+ line-height: $font-15px;
+ color: $primary-fg-color;
+ }
+ }
+
+ .mx_AccessibleButton {
+ display: inline-block;
+ align-self: center;
+ }
+
+ .mx_AccessibleButton_kind_primary {
+ padding: 8px 36px;
+ }
+
+ .mx_AddExistingToSpace_retryButton {
+ margin-left: 12px;
+ padding-left: 24px;
+ position: relative;
+
+ &::before {
+ content: '';
+ position: absolute;
+ background-color: $primary-fg-color;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: contain;
+ mask-image: url('$(res)/img/element-icons/retry.svg');
+ width: 18px;
+ height: 18px;
+ left: 0;
+ }
+ }
+
+ .mx_AccessibleButton_kind_link {
+ padding: 0;
+ }
+ }
+}
+
+.mx_AddExistingToSpaceDialog {
+ width: 480px;
+ color: $primary-fg-color;
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ min-height: 0;
+ height: 80vh;
+
+ .mx_Dialog_title {
+ display: flex;
+
+ .mx_BaseAvatar_image {
+ border-radius: 8px;
+ margin: 0;
+ vertical-align: unset;
+ }
+
+ .mx_BaseAvatar {
+ display: inline-flex;
+ margin: auto 16px auto 5px;
+ vertical-align: middle;
+ }
+
+ > div {
+ > h1 {
+ font-weight: $font-semi-bold;
+ font-size: $font-18px;
+ line-height: $font-22px;
+ margin: 0;
+ }
+
+ .mx_AddExistingToSpaceDialog_onlySpace {
+ color: $secondary-fg-color;
+ font-size: $font-15px;
+ line-height: $font-24px;
+ }
+ }
+
+ .mx_Dropdown_input {
+ border: none;
+
+ > .mx_Dropdown_option {
+ padding-left: 0;
+ flex: unset;
+ height: unset;
+ color: $secondary-fg-color;
+ font-size: $font-15px;
+ line-height: $font-24px;
+
+ .mx_BaseAvatar {
+ display: none;
+ }
+ }
+
+ .mx_Dropdown_menu {
+ .mx_AddExistingToSpaceDialog_dropdownOptionActive {
+ color: $accent-color;
+ padding-right: 32px;
+ position: relative;
+
+ &::before {
+ content: '';
+ width: 20px;
+ height: 20px;
+ top: 8px;
+ right: 0;
+ position: absolute;
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ background-color: $accent-color;
+ mask-image: url('$(res)/img/element-icons/roomlist/checkmark.svg');
+ }
+ }
+ }
+ }
+ }
+
+ .mx_AddExistingToSpace {
+ display: contents;
+ }
+}
diff --git a/res/css/views/dialogs/_BetaFeedbackDialog.scss b/res/css/views/dialogs/_BetaFeedbackDialog.scss
new file mode 100644
index 0000000000..9f5f6b512e
--- /dev/null
+++ b/res/css/views/dialogs/_BetaFeedbackDialog.scss
@@ -0,0 +1,30 @@
+/*
+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_BetaFeedbackDialog {
+ .mx_BetaFeedbackDialog_subheading {
+ color: $primary-fg-color;
+ font-size: $font-14px;
+ line-height: $font-20px;
+ margin-bottom: 24px;
+ }
+
+ .mx_AccessibleButton_kind_link {
+ padding: 0;
+ font-size: inherit;
+ line-height: inherit;
+ }
+}
diff --git a/src/extend.js b/res/css/views/dialogs/_BugReportDialog.scss
similarity index 73%
rename from src/extend.js
rename to res/css/views/dialogs/_BugReportDialog.scss
index 263d802ab6..1920ac33ea 100644
--- a/src/extend.js
+++ b/res/css/views/dialogs/_BugReportDialog.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2015, 2016 OpenMarket Ltd
+Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,13 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-'use strict';
-
-export default function(dest, src) {
- for (const i in src) {
- if (src.hasOwnProperty(i)) {
- dest[i] = src[i];
+.mx_BugReportDialog {
+ .mx_BugReportDialog_download {
+ .mx_AccessibleButton_kind_link {
+ padding-left: 0;
}
}
- return dest;
}
diff --git a/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss b/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss
new file mode 100644
index 0000000000..beae03f00f
--- /dev/null
+++ b/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss
@@ -0,0 +1,88 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_CommunityPrototypeInviteDialog {
+ &.mx_Dialog_fixedWidth {
+ width: 360px;
+ }
+
+ .mx_Dialog_content {
+ margin-bottom: 0;
+
+ .mx_CommunityPrototypeInviteDialog_people {
+ position: relative;
+ margin-bottom: 4px;
+
+ .mx_AccessibleButton {
+ display: inline-block;
+ background-color: $focus-bg-color; // XXX: Abuse of variables
+ border-radius: 4px;
+ padding: 3px 5px;
+ font-size: $font-12px;
+ float: right;
+ }
+ }
+
+ .mx_CommunityPrototypeInviteDialog_morePeople {
+ margin-top: 8px;
+ }
+
+ .mx_CommunityPrototypeInviteDialog_person {
+ position: relative;
+ margin-top: 4px;
+
+ & > * {
+ vertical-align: middle;
+ }
+
+ .mx_Checkbox {
+ position: absolute;
+ right: 0;
+ top: calc(50% - 8px); // checkbox is 16px high
+ width: 16px; // to force a square
+ }
+
+ .mx_CommunityPrototypeInviteDialog_personIdentifiers {
+ display: inline-block;
+
+ & > * {
+ display: block;
+ }
+
+ .mx_CommunityPrototypeInviteDialog_personName {
+ font-weight: 600;
+ font-size: $font-14px;
+ color: $primary-fg-color;
+ margin-left: 7px;
+ }
+
+ .mx_CommunityPrototypeInviteDialog_personId {
+ font-size: $font-12px;
+ color: $muted-fg-color;
+ margin-left: 7px;
+ }
+ }
+ }
+
+ .mx_CommunityPrototypeInviteDialog_primaryButton {
+ display: block;
+ font-size: $font-13px;
+ line-height: 20px;
+ height: 20px;
+ margin-top: 24px;
+ }
+ }
+}
diff --git a/res/css/views/dialogs/_CreateCommunityPrototypeDialog.scss b/res/css/views/dialogs/_CreateCommunityPrototypeDialog.scss
new file mode 100644
index 0000000000..81babc4c38
--- /dev/null
+++ b/res/css/views/dialogs/_CreateCommunityPrototypeDialog.scss
@@ -0,0 +1,102 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_CreateCommunityPrototypeDialog {
+ .mx_Dialog_content {
+ display: flex;
+ flex-direction: row;
+ margin-bottom: 12px;
+
+ .mx_CreateCommunityPrototypeDialog_colName {
+ flex-basis: 66.66%;
+ padding-right: 100px;
+
+ .mx_Field input {
+ font-size: $font-16px;
+ line-height: $font-20px;
+ }
+
+ .mx_CreateCommunityPrototypeDialog_subtext {
+ display: block;
+ color: $muted-fg-color;
+ margin-bottom: 16px;
+
+ &:last-child {
+ margin-top: 16px;
+ }
+
+ &.mx_CreateCommunityPrototypeDialog_subtext_error {
+ color: $warning-color;
+ }
+ }
+
+ .mx_CreateCommunityPrototypeDialog_communityId {
+ position: relative;
+
+ .mx_InfoTooltip {
+ float: right;
+ }
+ }
+
+ .mx_AccessibleButton {
+ display: block;
+ height: 32px;
+ font-size: $font-16px;
+ line-height: 32px;
+ }
+ }
+
+ .mx_CreateCommunityPrototypeDialog_colAvatar {
+ flex-basis: 33.33%;
+
+ .mx_CreateCommunityPrototypeDialog_avatarContainer {
+ margin-top: 12px;
+ margin-bottom: 20px;
+
+ .mx_CreateCommunityPrototypeDialog_avatar,
+ .mx_CreateCommunityPrototypeDialog_placeholderAvatar {
+ width: 96px;
+ height: 96px;
+ border-radius: 96px;
+ }
+
+ .mx_CreateCommunityPrototypeDialog_placeholderAvatar {
+ background-color: #368bd6; // hardcoded for both themes
+
+ &::before {
+ display: inline-block;
+ background-color: #fff; // hardcoded because the background is
+ mask-repeat: no-repeat;
+ mask-size: 96px;
+ width: 96px;
+ height: 96px;
+ mask-position: center;
+ content: '';
+ vertical-align: middle;
+ mask-image: url('$(res)/img/element-icons/add-photo.svg');
+ }
+ }
+ }
+
+ .mx_CreateCommunityPrototypeDialog_tip {
+ & > b, & > span {
+ display: block;
+ color: $muted-fg-color;
+ }
+ }
+ }
+ }
+}
diff --git a/res/css/views/dialogs/_DevtoolsDialog.scss b/res/css/views/dialogs/_DevtoolsDialog.scss
index 35cb6bc7ab..8fee740016 100644
--- a/res/css/views/dialogs/_DevtoolsDialog.scss
+++ b/res/css/views/dialogs/_DevtoolsDialog.scss
@@ -223,3 +223,54 @@ limitations under the License.
content: ":";
}
}
+
+.mx_DevTools_SettingsExplorer {
+ table {
+ width: 100%;
+ table-layout: fixed;
+ border-collapse: collapse;
+
+ th {
+ // Colour choice: first one autocomplete gave me.
+ border-bottom: 1px solid $accent-color;
+ text-align: left;
+ }
+
+ td, th {
+ width: 360px; // "feels right" number
+
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ td + td, th + th {
+ width: auto;
+ }
+
+ tr:hover {
+ // Colour choice: first one autocomplete gave me.
+ background-color: $accent-color-50pct;
+ }
+ }
+
+ .mx_DevTools_SettingsExplorer_mutable {
+ background-color: $accent-color;
+ }
+
+ .mx_DevTools_SettingsExplorer_immutable {
+ background-color: $warning-color;
+ }
+
+ .mx_DevTools_SettingsExplorer_edit {
+ float: right;
+ margin-right: 16px;
+ }
+
+ .mx_DevTools_SettingsExplorer_warning {
+ border: 2px solid $warning-color;
+ border-radius: 4px;
+ padding: 4px;
+ margin-bottom: 8px;
+ }
+}
diff --git a/res/css/views/dialogs/_EditCommunityPrototypeDialog.scss b/res/css/views/dialogs/_EditCommunityPrototypeDialog.scss
new file mode 100644
index 0000000000..75a56bf6b3
--- /dev/null
+++ b/res/css/views/dialogs/_EditCommunityPrototypeDialog.scss
@@ -0,0 +1,77 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// XXX: many of these styles are shared with the create dialog
+.mx_EditCommunityPrototypeDialog {
+ &.mx_Dialog_fixedWidth {
+ width: 360px;
+ }
+
+ .mx_Dialog_content {
+ margin-bottom: 12px;
+
+ .mx_AccessibleButton.mx_AccessibleButton_kind_primary {
+ display: block;
+ height: 32px;
+ font-size: $font-16px;
+ line-height: 32px;
+ }
+
+ .mx_EditCommunityPrototypeDialog_rowAvatar {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ }
+
+ .mx_EditCommunityPrototypeDialog_avatarContainer {
+ margin-top: 20px;
+ margin-bottom: 20px;
+
+ .mx_EditCommunityPrototypeDialog_avatar,
+ .mx_EditCommunityPrototypeDialog_placeholderAvatar {
+ width: 96px;
+ height: 96px;
+ border-radius: 96px;
+ }
+
+ .mx_EditCommunityPrototypeDialog_placeholderAvatar {
+ background-color: #368bd6; // hardcoded for both themes
+
+ &::before {
+ display: inline-block;
+ background-color: #fff; // hardcoded because the background is
+ mask-repeat: no-repeat;
+ mask-size: 96px;
+ width: 96px;
+ height: 96px;
+ mask-position: center;
+ content: '';
+ vertical-align: middle;
+ mask-image: url('$(res)/img/element-icons/add-photo.svg');
+ }
+ }
+ }
+
+ .mx_EditCommunityPrototypeDialog_tip {
+ margin-left: 20px;
+
+ & > b, & > span {
+ display: block;
+ color: $muted-fg-color;
+ }
+ }
+ }
+}
diff --git a/res/css/views/dialogs/_FeedbackDialog.scss b/res/css/views/dialogs/_FeedbackDialog.scss
new file mode 100644
index 0000000000..fd225dd882
--- /dev/null
+++ b/res/css/views/dialogs/_FeedbackDialog.scss
@@ -0,0 +1,121 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_FeedbackDialog {
+ hr {
+ margin: 24px 0;
+ border-color: $input-border-color;
+ }
+
+ .mx_Dialog_content {
+ margin-bottom: 24px;
+
+ > h2 {
+ margin-bottom: 32px;
+ }
+ }
+
+ .mx_FeedbackDialog_section {
+ position: relative;
+ padding-left: 52px;
+
+ > p {
+ color: $tertiary-fg-color;
+ }
+
+ .mx_AccessibleButton_kind_link {
+ padding: 0;
+ font-size: inherit;
+ }
+
+ a, .mx_AccessibleButton_kind_link {
+ color: $accent-color;
+ text-decoration: underline;
+ }
+
+ &::before, &::after {
+ content: "";
+ position: absolute;
+ width: 40px;
+ height: 40px;
+ left: 0;
+ top: 0;
+ }
+
+ &::before {
+ background-color: $icon-button-color;
+ border-radius: 20px;
+ }
+
+ &::after {
+ background: $avatar-initial-color; // TODO
+ mask-position: center;
+ mask-size: 24px;
+ mask-repeat: no-repeat;
+ }
+ }
+
+ .mx_FeedbackDialog_reportBug {
+ &::after {
+ mask-image: url('$(res)/img/feather-customised/bug.svg');
+ }
+ }
+
+ .mx_FeedbackDialog_rateApp {
+ .mx_RadioButton {
+ display: inline-flex;
+ font-size: 20px;
+ transition: font-size 1s, border .5s;
+ border-radius: 50%;
+ border: 2px solid transparent;
+ margin-top: 12px;
+ margin-bottom: 24px;
+ vertical-align: top;
+ cursor: pointer;
+
+ input[type="radio"] + div {
+ display: none;
+ }
+
+ .mx_RadioButton_content {
+ background: $icon-button-color;
+ width: 40px;
+ height: 40px;
+ text-align: center;
+ line-height: 40px;
+ border-radius: 20px;
+ margin: 5px;
+ }
+
+ .mx_RadioButton_spacer {
+ display: none;
+ }
+
+ & + .mx_RadioButton {
+ margin-left: 16px;
+ }
+ }
+
+ .mx_RadioButton_checked {
+ font-size: 24px;
+ border-color: $accent-color;
+ }
+
+ &::after {
+ mask-image: url('$(res)/img/element-icons/feedback.svg');
+ }
+ }
+}
diff --git a/res/css/views/dialogs/_HostSignupDialog.scss b/res/css/views/dialogs/_HostSignupDialog.scss
new file mode 100644
index 0000000000..ac4bc41951
--- /dev/null
+++ b/res/css/views/dialogs/_HostSignupDialog.scss
@@ -0,0 +1,143 @@
+/*
+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_HostSignupDialog {
+ width: 90vw;
+ max-width: 580px;
+ height: 80vh;
+ max-height: 600px;
+ // Ensure dialog borders are always white as the HostSignupDialog
+ // does not yet support dark mode or theming in general.
+ // In the future we might want to pass the theme to the called
+ // iframe, should some hosting provider have that need.
+ background-color: #ffffff;
+
+ .mx_HostSignupDialog_info {
+ text-align: center;
+
+ .mx_HostSignupDialog_content_top {
+ margin-bottom: 24px;
+ }
+
+ .mx_HostSignupDialog_paragraphs {
+ text-align: left;
+ padding-left: 25%;
+ padding-right: 25%;
+ }
+
+ .mx_HostSignupDialog_buttons {
+ margin-bottom: 24px;
+ display: flex;
+ justify-content: center;
+
+ button {
+ padding: 12px;
+ margin: 0 16px;
+ }
+ }
+
+ .mx_HostSignupDialog_footer {
+ display: flex;
+ justify-content: center;
+ align-items: baseline;
+
+ img {
+ padding-right: 5px;
+ }
+ }
+ }
+
+ iframe {
+ width: 100%;
+ height: 100%;
+ border: none;
+ background-color: #fff;
+ min-height: 540px;
+ }
+}
+
+.mx_HostSignupDialog_text_dark {
+ color: $primary-fg-color;
+}
+
+.mx_HostSignupDialog_text_light {
+ color: $secondary-fg-color;
+}
+
+.mx_HostSignup_maximize_button {
+ mask: url('$(res)/img/feather-customised/maximise.svg');
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: cover;
+ width: 14px;
+ height: 14px;
+ background-color: $dialog-close-fg-color;
+ cursor: pointer;
+ position: absolute;
+ top: 10px;
+ right: 10px;
+}
+
+.mx_HostSignup_minimize_button {
+ mask: url('$(res)/img/feather-customised/minimise.svg');
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: cover;
+ width: 14px;
+ height: 14px;
+ background-color: $dialog-close-fg-color;
+ cursor: pointer;
+ position: absolute;
+ top: 10px;
+ right: 25px;
+}
+
+.mx_HostSignup_persisted {
+ width: 90vw;
+ max-width: 580px;
+ height: 80vh;
+ max-height: 600px;
+ top: 0;
+ left: 0;
+ position: fixed;
+ display: none;
+}
+
+.mx_HostSignupDialog_minimized {
+ position: fixed;
+ bottom: 80px;
+ right: 26px;
+ width: 314px;
+ height: 217px;
+ overflow: hidden;
+
+ &.mx_Dialog {
+ padding: 12px;
+ }
+
+ .mx_Dialog_title {
+ text-align: left !important;
+ padding-left: 20px;
+ font-size: $font-15px;
+ }
+
+ iframe {
+ width: 100%;
+ height: 100%;
+ border: none;
+ background-color: #fff;
+ }
+}
diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss
index a77d0bfbba..d8ff56663a 100644
--- a/res/css/views/dialogs/_InviteDialog.scss
+++ b/res/css/views/dialogs/_InviteDialog.scss
@@ -27,37 +27,29 @@ limitations under the License.
padding-left: 8px;
overflow-x: hidden;
overflow-y: auto;
+ display: flex;
+ flex-wrap: wrap;
.mx_InviteDialog_userTile {
+ margin: 6px 6px 0 0;
display: inline-block;
- float: left;
- position: relative;
- top: 7px;
+ min-width: max-content; // prevent manipulation by flexbox
}
- // Using a textarea for this element, to circumvent autofill
- // Mostly copied from AddressPickerDialog
- textarea,
- textarea:focus {
- height: 34px;
- line-height: $font-34px;
+ // Mostly copied from AddressPickerDialog; overrides bunch of our default text input styles
+ > input[type="text"] {
+ margin: 6px 0 !important;
+ height: 24px;
+ line-height: $font-24px;
font-size: $font-14px;
padding-left: 12px;
- margin: 0 !important;
border: 0 !important;
outline: 0 !important;
resize: none;
- overflow: hidden;
box-sizing: border-box;
- word-wrap: nowrap;
-
- // Roughly fill about 2/5ths of the available space. This is to try and 'fill' the
- // remaining space after a bunch of pills, but is a bit hacky. Ideally we'd have
- // support for "fill remaining width", but traditional tricks don't work with what
- // we're pushing into this "field". Flexbox just makes things worse. The theory is
- // that users won't need more than about 2/5ths of the input to find the person
- // they're looking for.
- width: 40%;
+ min-width: 40%;
+ flex: 1 !important;
+ color: $primary-fg-color !important;
}
}
@@ -89,6 +81,13 @@ limitations under the License.
font-weight: bold;
text-transform: uppercase;
}
+
+ .mx_InviteDialog_subname {
+ margin-bottom: 10px;
+ margin-top: -10px; // HACK: Positioning with margins is bad
+ font-size: $font-12px;
+ color: $muted-fg-color;
+ }
}
.mx_InviteDialog_roomTile {
@@ -141,6 +140,10 @@ limitations under the License.
}
}
+ .mx_InviteDialog_roomTile_nameStack {
+ display: inline-block;
+ }
+
.mx_InviteDialog_roomTile_name {
font-weight: 600;
font-size: $font-14px;
@@ -226,3 +229,7 @@ limitations under the License.
.mx_InviteDialog_addressBar {
margin-right: 45px;
}
+
+.mx_InviteDialog_helpText .mx_AccessibleButton_kind_link {
+ padding: 0;
+}
diff --git a/src/utils/NamingUtils.ts b/res/css/views/dialogs/_ModalWidgetDialog.scss
similarity index 53%
rename from src/utils/NamingUtils.ts
rename to res/css/views/dialogs/_ModalWidgetDialog.scss
index 44ccb9b030..aa2dd0d395 100644
--- a/src/utils/NamingUtils.ts
+++ b/res/css/views/dialogs/_ModalWidgetDialog.scss
@@ -14,16 +14,29 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import * as projectNameGenerator from "project-name-generator";
+.mx_ModalWidgetDialog {
+ .mx_ModalWidgetDialog_warning {
+ margin-bottom: 24px;
-/**
- * Generates a human readable identifier. This should not be used for anything
- * which needs secure/cryptographic random: just a level uniquness that is offered
- * by something like Date.now().
- * @returns {string} The randomly generated ID
- */
-export function generateHumanReadableId(): string {
- return projectNameGenerator({words: 3}).raw.map(w => {
- return w[0].toUpperCase() + w.substring(1).toLowerCase();
- }).join('');
+ > img {
+ vertical-align: middle;
+ margin-right: 8px;
+ }
+ }
+
+ .mx_ModalWidgetDialog_buttons {
+ float: right;
+ margin-top: 24px;
+
+ .mx_AccessibleButton + .mx_AccessibleButton {
+ margin-left: 8px;
+ }
+ }
+
+ iframe {
+ width: 100%;
+ height: 450px;
+ border: 0;
+ border-radius: 8px;
+ }
}
diff --git a/res/css/views/dialogs/_RebrandDialog.scss b/res/css/views/dialogs/_RebrandDialog.scss
deleted file mode 100644
index 534584ae2a..0000000000
--- a/res/css/views/dialogs/_RebrandDialog.scss
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-Copyright 2020 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-.mx_RebrandDialog {
- text-align: center;
-
- a:link,
- a:hover,
- a:visited {
- @mixin mx_Dialog_link;
- }
-
- .mx_Dialog_buttons {
- margin-top: 43px;
- text-align: center;
- }
-}
-
-.mx_RebrandDialog_body {
- width: 550px;
- margin-left: auto;
- margin-right: auto;
-}
-
-.mx_RebrandDialog_logoContainer {
- margin-top: 35px;
- margin-bottom: 20px;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.mx_RebrandDialog_logo {
- margin-left: 28px;
- margin-right: 28px;
- width: 64px;
- height: 64px;
-}
-
-.mx_RebrandDialog_chevron::after {
- content: '';
- display: inline-block;
- width: 30px;
- height: 30px;
- mask-position: center;
- mask-size: contain;
- mask-repeat: no-repeat;
- background-color: $muted-fg-color;
- mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
- transform: rotate(-90deg);
-}
diff --git a/src/components/views/avatars/PulsedAvatar.tsx b/res/css/views/dialogs/_RegistrationEmailPromptDialog.scss
similarity index 73%
rename from src/components/views/avatars/PulsedAvatar.tsx
rename to res/css/views/dialogs/_RegistrationEmailPromptDialog.scss
index 94a6c87687..31fc6d7a04 100644
--- a/src/components/views/avatars/PulsedAvatar.tsx
+++ b/res/css/views/dialogs/_RegistrationEmailPromptDialog.scss
@@ -14,15 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import React from 'react';
+.mx_RegistrationEmailPromptDialog {
+ width: 417px;
-interface IProps {
+ .mx_Dialog_content {
+ margin-bottom: 24px;
+ color: $tertiary-fg-color;
+ }
+
+ .mx_Dialog_primary {
+ width: 100%;
+ }
}
-
-const PulsedAvatar: React.FC = (props) => {
- return
- {props.children}
-
;
-};
-
-export default PulsedAvatar;
\ No newline at end of file
diff --git a/res/css/views/dialogs/_RoomSettingsDialog.scss b/res/css/views/dialogs/_RoomSettingsDialog.scss
index d4199a1e66..9bcde6e1e0 100644
--- a/res/css/views/dialogs/_RoomSettingsDialog.scss
+++ b/res/css/views/dialogs/_RoomSettingsDialog.scss
@@ -48,7 +48,6 @@ limitations under the License.
white-space: nowrap;
overflow: hidden;
margin: 0 auto;
- padding-left: 40px;
padding-right: 80px;
}
diff --git a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
index a1793cc75e..c97a3b69b7 100644
--- a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
+++ b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss
@@ -89,24 +89,18 @@ limitations under the License.
}
}
- .mx_showMore {
- display: block;
- text-align: left;
- margin-top: 10px;
- }
-
.metadata {
color: $muted-fg-color;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
margin-bottom: 0;
- }
-
- .metadata.visible {
overflow-y: visible;
text-overflow: ellipsis;
white-space: normal;
+ padding: 0;
+
+ > li {
+ padding: 0;
+ border: 0;
+ }
}
}
}
diff --git a/res/css/views/dialogs/_ServerPickerDialog.scss b/res/css/views/dialogs/_ServerPickerDialog.scss
new file mode 100644
index 0000000000..b01b49d7af
--- /dev/null
+++ b/res/css/views/dialogs/_ServerPickerDialog.scss
@@ -0,0 +1,78 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_ServerPickerDialog {
+ width: 468px;
+ box-sizing: border-box;
+
+ .mx_Dialog_content {
+ margin-bottom: 0;
+
+ > p {
+ color: $secondary-fg-color;
+ font-size: $font-14px;
+ margin: 16px 0;
+
+ &:first-of-type {
+ margin-bottom: 40px;
+ }
+
+ &:last-of-type {
+ margin: 0 24px 24px;
+ }
+ }
+
+ > h4 {
+ font-size: $font-15px;
+ font-weight: $font-semi-bold;
+ color: $secondary-fg-color;
+ margin-left: 8px;
+ }
+
+ > a {
+ color: $accent-color;
+ margin-left: 8px;
+ }
+ }
+
+ .mx_ServerPickerDialog_otherHomeserverRadio {
+ input[type="radio"] + div {
+ margin-top: auto;
+ margin-bottom: auto;
+ }
+ }
+
+ .mx_ServerPickerDialog_otherHomeserver {
+ border-top: none;
+ border-left: none;
+ border-right: none;
+ border-radius: unset;
+
+ > input {
+ padding-left: 0;
+ }
+
+ > label {
+ margin-left: 0;
+ }
+ }
+
+ .mx_AccessibleButton_kind_primary {
+ width: calc(100% - 64px);
+ margin: 0 8px;
+ padding: 15px 18px;
+ }
+}
diff --git a/res/css/views/dialogs/_SetMxIdDialog.scss b/res/css/views/dialogs/_SetMxIdDialog.scss
deleted file mode 100644
index 1df34f3408..0000000000
--- a/res/css/views/dialogs/_SetMxIdDialog.scss
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-Copyright 2015, 2016 OpenMarket Ltd
-Copyright 2017 Vector Creations Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-.mx_SetMxIdDialog .mx_Dialog_title {
- padding-right: 40px;
-}
-
-.mx_SetMxIdDialog_input_group {
- display: flex;
-}
-
-.mx_SetMxIdDialog_input {
- border-radius: 3px;
- border: 1px solid $input-border-color;
- padding: 9px;
- color: $primary-fg-color;
- background-color: $primary-bg-color;
- font-size: $font-15px;
- width: 100%;
- max-width: 280px;
-}
-
-.mx_SetMxIdDialog_input.error,
-.mx_SetMxIdDialog_input.error:focus {
- border: 1px solid $warning-color;
-}
-
-.mx_SetMxIdDialog_input_group .mx_Spinner {
- height: 37px;
- padding-left: 10px;
- justify-content: flex-start;
-}
-
-.mx_SetMxIdDialog .success {
- color: $accent-color;
-}
diff --git a/res/css/views/dialogs/_SettingsDialog.scss b/res/css/views/dialogs/_SettingsDialog.scss
index ec813a1a07..6c4ed35c5a 100644
--- a/res/css/views/dialogs/_SettingsDialog.scss
+++ b/res/css/views/dialogs/_SettingsDialog.scss
@@ -36,7 +36,6 @@ limitations under the License.
}
.mx_Dialog_title {
- text-align: center;
margin-bottom: 24px;
}
}
diff --git a/res/css/views/dialogs/_ShareDialog.scss b/res/css/views/dialogs/_ShareDialog.scss
index d2fe98e8f9..ce3fdd021f 100644
--- a/res/css/views/dialogs/_ShareDialog.scss
+++ b/res/css/views/dialogs/_ShareDialog.scss
@@ -51,7 +51,8 @@ limitations under the License.
display: inherit;
}
.mx_ShareDialog_matrixto_copy > div {
- background-image: url($copy-button-url);
+ mask-image: url($copy-button-url);
+ background-color: $message-action-bar-fg-color;
margin-left: 5px;
width: 20px;
height: 20px;
@@ -70,9 +71,12 @@ limitations under the License.
margin-right: 64px;
}
+.mx_ShareDialog_qrcode_container + .mx_ShareDialog_social_container {
+ width: 299px;
+}
+
.mx_ShareDialog_social_container {
display: inline-block;
- width: 299px;
}
.mx_ShareDialog_social_icon {
diff --git a/res/css/views/dialogs/_SpaceSettingsDialog.scss b/res/css/views/dialogs/_SpaceSettingsDialog.scss
new file mode 100644
index 0000000000..6e5fd9c8c8
--- /dev/null
+++ b/res/css/views/dialogs/_SpaceSettingsDialog.scss
@@ -0,0 +1,55 @@
+/*
+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_SpaceSettingsDialog {
+ width: 480px;
+ color: $primary-fg-color;
+
+ .mx_SpaceSettings_errorText {
+ font-weight: $font-semi-bold;
+ font-size: $font-12px;
+ line-height: $font-15px;
+ color: $notice-primary-color;
+ margin-bottom: 28px;
+ }
+
+ .mx_ToggleSwitch {
+ display: inline-block;
+ vertical-align: middle;
+ margin-left: 16px;
+ }
+
+ .mx_AccessibleButton_kind_danger {
+ margin-top: 28px;
+ }
+
+ .mx_SpaceSettingsDialog_buttons {
+ display: flex;
+ margin-top: 64px;
+
+ .mx_AccessibleButton {
+ display: inline-block;
+ }
+
+ .mx_AccessibleButton_kind_link {
+ margin-left: auto;
+ }
+ }
+
+ .mx_AccessibleButton_hasKind {
+ padding: 8px 22px;
+ }
+}
diff --git a/res/css/views/dialogs/_UntrustedDeviceDialog.scss b/res/css/views/dialogs/_UntrustedDeviceDialog.scss
new file mode 100644
index 0000000000..0ecd9d4f71
--- /dev/null
+++ b/res/css/views/dialogs/_UntrustedDeviceDialog.scss
@@ -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.
+*/
+
+.mx_UntrustedDeviceDialog {
+ .mx_Dialog_title {
+ display: flex;
+ align-items: center;
+
+ .mx_E2EIcon {
+ margin-left: 0;
+ }
+ }
+}
diff --git a/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss b/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss
new file mode 100644
index 0000000000..176919b84c
--- /dev/null
+++ b/res/css/views/dialogs/_WidgetCapabilitiesPromptDialog.scss
@@ -0,0 +1,75 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+
+.mx_WidgetCapabilitiesPromptDialog {
+ .text-muted {
+ font-size: $font-12px;
+ }
+
+ .mx_Dialog_content {
+ margin-bottom: 16px;
+ }
+
+ .mx_WidgetCapabilitiesPromptDialog_cap {
+ margin-top: 20px;
+ font-size: $font-15px;
+ line-height: $font-15px;
+
+ .mx_WidgetCapabilitiesPromptDialog_byline {
+ color: $muted-fg-color;
+ margin-left: 26px;
+ font-size: $font-12px;
+ line-height: $font-12px;
+ }
+ }
+
+ .mx_Dialog_buttons {
+ margin-top: 40px; // double normal
+ }
+
+ .mx_SettingsFlag {
+ line-height: calc($font-14px + 7px + 7px); // 7px top & bottom padding
+ color: $muted-fg-color;
+ font-size: $font-12px;
+
+ .mx_ToggleSwitch {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 8px;
+
+ // downsize the switch + ball
+ width: $font-32px;
+ height: $font-15px;
+
+
+ &.mx_ToggleSwitch_on > .mx_ToggleSwitch_ball {
+ left: calc(100% - $font-15px);
+ }
+
+ .mx_ToggleSwitch_ball {
+ width: $font-15px;
+ height: $font-15px;
+ border-radius: $font-15px;
+ }
+ }
+
+ .mx_SettingsFlag_label {
+ display: inline-block;
+ vertical-align: middle;
+ }
+ }
+}
diff --git a/res/css/views/dialogs/secretstorage/_AccessSecretStorageDialog.scss b/res/css/views/dialogs/security/_AccessSecretStorageDialog.scss
similarity index 73%
rename from res/css/views/dialogs/secretstorage/_AccessSecretStorageDialog.scss
rename to res/css/views/dialogs/security/_AccessSecretStorageDialog.scss
index 63d0ca555d..30b79c1a9a 100644
--- a/res/css/views/dialogs/secretstorage/_AccessSecretStorageDialog.scss
+++ b/res/css/views/dialogs/security/_AccessSecretStorageDialog.scss
@@ -1,6 +1,5 @@
/*
-Copyright 2018 New Vector Ltd
-Copyright 2019 The Matrix.org Foundation C.I.C.
+Copyright 2018, 2019, 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.
@@ -15,6 +14,27 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+.mx_AccessSecretStorageDialog_reset {
+ position: relative;
+ padding-left: 24px; // 16px icon + 8px padding
+ margin-top: 7px; // vertical alignment to buttons
+
+ &::before {
+ content: "";
+ display: inline-block;
+ position: absolute;
+ height: 16px;
+ width: 16px;
+ left: 0;
+ top: 2px; // alignment
+ background-image: url("$(res)/img/element-icons/warning-badge.svg");
+ }
+
+ .mx_AccessSecretStorageDialog_reset_link {
+ color: $warning-color;
+ }
+}
+
.mx_AccessSecretStorageDialog_titleWithIcon::before {
content: '';
display: inline-block;
@@ -26,6 +46,13 @@ limitations under the License.
background-color: $primary-fg-color;
}
+.mx_AccessSecretStorageDialog_resetBadge::before {
+ // The image isn't capable of masking, so we use a background instead.
+ background-image: url("$(res)/img/element-icons/warning-badge.svg");
+ background-size: 24px;
+ background-color: transparent;
+}
+
.mx_AccessSecretStorageDialog_secureBackupTitle::before {
mask-image: url('$(res)/img/feather-customised/secure-backup.svg');
}
diff --git a/res/css/views/dialogs/security/_CreateCrossSigningDialog.scss b/res/css/views/dialogs/security/_CreateCrossSigningDialog.scss
new file mode 100644
index 0000000000..8303e02b9e
--- /dev/null
+++ b/res/css/views/dialogs/security/_CreateCrossSigningDialog.scss
@@ -0,0 +1,33 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_CreateCrossSigningDialog {
+ // Why you ask? Because CompleteSecurityBody is 600px so this is the width
+ // we end up when in there, but when in our own dialog we set our own width
+ // so need to fix it to something sensible as otherwise we'd end up either
+ // really wide or really narrow depending on the phase. I bet you wish you
+ // never asked.
+ width: 560px;
+
+ details .mx_AccessibleButton {
+ margin: 1em 0; // emulate paragraph spacing because we can't put this button in a paragraph due to HTML rules
+ }
+}
+
+.mx_CreateCrossSigningDialog .mx_Dialog_title {
+ /* TODO: Consider setting this for all dialog titles. */
+ margin-bottom: 1em;
+}
diff --git a/res/css/views/dialogs/keybackup/_CreateKeyBackupDialog.scss b/res/css/views/dialogs/security/_CreateKeyBackupDialog.scss
similarity index 100%
rename from res/css/views/dialogs/keybackup/_CreateKeyBackupDialog.scss
rename to res/css/views/dialogs/security/_CreateKeyBackupDialog.scss
diff --git a/res/css/views/dialogs/secretstorage/_CreateSecretStorageDialog.scss b/res/css/views/dialogs/security/_CreateSecretStorageDialog.scss
similarity index 100%
rename from res/css/views/dialogs/secretstorage/_CreateSecretStorageDialog.scss
rename to res/css/views/dialogs/security/_CreateSecretStorageDialog.scss
diff --git a/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss b/res/css/views/dialogs/security/_KeyBackupFailedDialog.scss
similarity index 100%
rename from res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss
rename to res/css/views/dialogs/security/_KeyBackupFailedDialog.scss
diff --git a/res/css/views/dialogs/keybackup/_RestoreKeyBackupDialog.scss b/res/css/views/dialogs/security/_RestoreKeyBackupDialog.scss
similarity index 100%
rename from res/css/views/dialogs/keybackup/_RestoreKeyBackupDialog.scss
rename to res/css/views/dialogs/security/_RestoreKeyBackupDialog.scss
diff --git a/res/css/views/elements/_AccessibleButton.scss b/res/css/views/elements/_AccessibleButton.scss
index 96269cea43..2997c83cfd 100644
--- a/res/css/views/elements/_AccessibleButton.scss
+++ b/res/css/views/elements/_AccessibleButton.scss
@@ -25,8 +25,10 @@ limitations under the License.
.mx_AccessibleButton_hasKind {
padding: 7px 18px;
text-align: center;
- border-radius: 4px;
- display: inline-block;
+ border-radius: 8px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
font-size: $font-14px;
}
@@ -74,12 +76,16 @@ limitations under the License.
border: 1px solid $button-danger-bg-color;
}
-.mx_AccessibleButton_kind_danger.mx_AccessibleButton_disabled,
-.mx_AccessibleButton_kind_danger_outline.mx_AccessibleButton_disabled {
+.mx_AccessibleButton_kind_danger.mx_AccessibleButton_disabled {
color: $button-danger-disabled-fg-color;
background-color: $button-danger-disabled-bg-color;
}
+.mx_AccessibleButton_kind_danger_outline.mx_AccessibleButton_disabled {
+ color: $button-danger-disabled-bg-color;
+ border-color: $button-danger-disabled-bg-color;
+}
+
.mx_AccessibleButton_hasKind.mx_AccessibleButton_kind_danger_sm {
padding: 5px 12px;
color: $button-danger-fg-color;
diff --git a/res/css/views/elements/_DesktopBuildsNotice.scss b/res/css/views/elements/_DesktopBuildsNotice.scss
new file mode 100644
index 0000000000..3672595bf1
--- /dev/null
+++ b/res/css/views/elements/_DesktopBuildsNotice.scss
@@ -0,0 +1,28 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_DesktopBuildsNotice {
+ text-align: center;
+ padding: 0 16px;
+
+ > * {
+ vertical-align: middle;
+ }
+
+ > img {
+ margin-right: 8px;
+ }
+}
diff --git a/res/css/views/elements/_DesktopCapturerSourcePicker.scss b/res/css/views/elements/_DesktopCapturerSourcePicker.scss
new file mode 100644
index 0000000000..69dde5925e
--- /dev/null
+++ b/res/css/views/elements/_DesktopCapturerSourcePicker.scss
@@ -0,0 +1,72 @@
+/*
+Copyright 2021 Šimon Brandner
+
+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_desktopCapturerSourcePicker {
+ overflow: hidden;
+}
+
+.mx_desktopCapturerSourcePicker_tabLabels {
+ display: flex;
+ padding: 0 0 8px 0;
+}
+
+.mx_desktopCapturerSourcePicker_tabLabel,
+.mx_desktopCapturerSourcePicker_tabLabel_selected {
+ width: 100%;
+ text-align: center;
+ border-radius: 8px;
+ padding: 8px 0;
+ font-size: $font-13px;
+}
+
+.mx_desktopCapturerSourcePicker_tabLabel_selected {
+ background-color: $tab-label-active-bg-color;
+ color: $tab-label-active-fg-color;
+}
+
+.mx_desktopCapturerSourcePicker_panel {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ align-items: flex-start;
+ height: 500px;
+ overflow: overlay;
+}
+
+.mx_desktopCapturerSourcePicker_stream_button {
+ display: flex;
+ flex-direction: column;
+ margin: 8px;
+ border-radius: 4px;
+}
+
+.mx_desktopCapturerSourcePicker_stream_button:hover,
+.mx_desktopCapturerSourcePicker_stream_button:focus {
+ background: $roomtile-selected-bg-color;
+}
+
+.mx_desktopCapturerSourcePicker_stream_thumbnail {
+ margin: 4px;
+ width: 312px;
+}
+
+.mx_desktopCapturerSourcePicker_stream_name {
+ margin: 0 4px;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ width: 312px;
+}
diff --git a/res/css/views/elements/_FacePile.scss b/res/css/views/elements/_FacePile.scss
new file mode 100644
index 0000000000..c691baffb5
--- /dev/null
+++ b/res/css/views/elements/_FacePile.scss
@@ -0,0 +1,65 @@
+/*
+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_FacePile {
+ .mx_FacePile_faces {
+ display: inline-flex;
+ flex-direction: row-reverse;
+ vertical-align: middle;
+
+ > .mx_FacePile_face + .mx_FacePile_face {
+ margin-right: -8px;
+ }
+
+ .mx_BaseAvatar_image {
+ border: 1px solid $primary-bg-color;
+ }
+
+ .mx_BaseAvatar_initial {
+ margin: 1px; // to offset the border on the image
+ }
+
+ .mx_FacePile_more {
+ position: relative;
+ border-radius: 100%;
+ width: 30px;
+ height: 30px;
+ background-color: $groupFilterPanel-bg-color;
+
+ &::before {
+ content: "";
+ z-index: 1;
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: inherit;
+ width: inherit;
+ background: $tertiary-fg-color;
+ mask-position: center;
+ mask-size: 20px;
+ mask-repeat: no-repeat;
+ mask-image: url('$(res)/img/element-icons/room/ellipsis.svg');
+ }
+ }
+ }
+
+ .mx_FacePile_summary {
+ margin-left: 12px;
+ font-size: $font-14px;
+ line-height: $font-24px;
+ color: $tertiary-fg-color;
+ }
+}
diff --git a/res/css/views/elements/_FormButton.scss b/res/css/views/elements/_FormButton.scss
index 7ec01f17e6..eda201ff03 100644
--- a/res/css/views/elements/_FormButton.scss
+++ b/res/css/views/elements/_FormButton.scss
@@ -33,4 +33,10 @@ limitations under the License.
color: $notice-primary-color;
background-color: $notice-primary-bg-color;
}
+
+ &.mx_AccessibleButton_kind_secondary {
+ color: $secondary-fg-color;
+ border: 1px solid $secondary-fg-color;
+ background-color: unset;
+ }
}
diff --git a/res/css/views/elements/_IconButton.scss b/res/css/views/elements/_IconButton.scss
deleted file mode 100644
index d8ebbeb65e..0000000000
--- a/res/css/views/elements/_IconButton.scss
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-Copyright 2019 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-.mx_IconButton {
- width: 32px;
- height: 32px;
- border-radius: 100%;
- background-color: $accent-bg-color;
- // don't shrink or grow if in a flex container
- flex: 0 0 auto;
-
- &.mx_AccessibleButton_disabled {
- background-color: none;
-
- &::before {
- background-color: lightgrey;
- }
- }
-
- &:hover {
- opacity: 90%;
- }
-
- &::before {
- content: "";
- display: block;
- width: 100%;
- height: 100%;
- mask-repeat: no-repeat;
- mask-position: center;
- mask-size: 55%;
- background-color: $accent-color;
- }
-
- &.mx_IconButton_icon_check::before {
- mask-image: url('$(res)/img/feather-customised/check.svg');
- }
-
- &.mx_IconButton_icon_edit::before {
- mask-image: url('$(res)/img/feather-customised/edit.svg');
- }
-}
diff --git a/res/css/views/elements/_ImageView.scss b/res/css/views/elements/_ImageView.scss
index 0a4ed2a194..71035dadc3 100644
--- a/res/css/views/elements/_ImageView.scss
+++ b/res/css/views/elements/_ImageView.scss
@@ -14,139 +14,107 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-/* This has got to be the most fragile piece of CSS ever written.
- But empirically it works on Chrome/FF/Safari
- */
-
.mx_ImageView {
display: flex;
width: 100%;
height: 100%;
- align-items: center;
-}
-
-.mx_ImageView_lhs {
- order: 1;
- flex: 1 1 10%;
- min-width: 60px;
- // background-color: #080;
- // height: 20px;
-}
-
-.mx_ImageView_content {
- order: 2;
- /* min-width hack needed for FF */
- min-width: 0px;
- height: 90%;
- flex: 15 15 0;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.mx_ImageView_content img {
- max-width: 100%;
- /* XXX: max-height interacts badly with flex on Chrome and doesn't relayout properly until you refresh */
- max-height: 100%;
- /* object-fit hack needed for Chrome due to Chrome not re-laying-out until you refresh */
- object-fit: contain;
- /* background-image: url('$(res)/img/trans.png'); */
- pointer-events: all;
-}
-
-.mx_ImageView_labelWrapper {
- position: absolute;
- top: 0px;
- right: 0px;
- height: 100%;
- overflow: auto;
- pointer-events: all;
-}
-
-.mx_ImageView_label {
- text-align: left;
- display: flex;
- justify-content: center;
flex-direction: column;
- padding-left: 30px;
- padding-right: 30px;
- min-height: 100%;
- max-width: 240px;
+}
+
+.mx_ImageView_image_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ overflow: hidden;
+}
+
+.mx_ImageView_image {
+ pointer-events: all;
+ flex-shrink: 0;
+}
+
+.mx_ImageView_panel {
+ width: 100%;
+ height: 68px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.mx_ImageView_info_wrapper {
+ pointer-events: all;
+ padding-left: 32px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
color: $lightbox-fg-color;
}
-.mx_ImageView_cancel {
- position: absolute;
- // hack for mx_Dialog having a top padding of 40px
- top: 40px;
- right: 0px;
- padding-top: 35px;
- padding-right: 35px;
- cursor: pointer;
+.mx_ImageView_info {
+ padding-left: 12px;
+ display: flex;
+ flex-direction: column;
}
-.mx_ImageView_rotateClockwise {
- position: absolute;
- top: 40px;
- right: 70px;
- padding-top: 35px;
- cursor: pointer;
+.mx_ImageView_info_sender {
+ font-weight: bold;
}
-.mx_ImageView_rotateCounterClockwise {
- position: absolute;
- top: 40px;
- right: 105px;
- padding-top: 35px;
- cursor: pointer;
-}
-
-.mx_ImageView_name {
- font-size: $font-18px;
- margin-bottom: 6px;
- word-wrap: break-word;
-}
-
-.mx_ImageView_metadata {
- font-size: $font-15px;
- opacity: 0.5;
-}
-
-.mx_ImageView_download {
- display: table;
- margin-top: 24px;
- margin-bottom: 6px;
- border-radius: 5px;
- background-color: $lightbox-bg-color;
- font-size: $font-14px;
- padding: 9px;
- border: 1px solid $lightbox-border-color;
-}
-
-.mx_ImageView_size {
- font-size: $font-11px;
-}
-
-.mx_ImageView_link {
- color: $lightbox-fg-color !important;
- text-decoration: none !important;
+.mx_ImageView_toolbar {
+ padding-right: 16px;
+ pointer-events: all;
+ display: flex;
+ align-items: center;
}
.mx_ImageView_button {
- font-size: $font-15px;
- opacity: 0.5;
- margin-top: 18px;
- cursor: pointer;
+ margin-left: 24px;
+ display: block;
+
+ &::before {
+ content: '';
+ height: 22px;
+ width: 22px;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ mask-position: center;
+ display: block;
+ background-color: $icon-button-color;
+ }
}
-.mx_ImageView_shim {
- height: 30px;
+.mx_ImageView_button_rotateCW::before {
+ mask-image: url('$(res)/img/image-view/rotate-cw.svg');
}
-.mx_ImageView_rhs {
- order: 3;
- flex: 1 1 10%;
- min-width: 300px;
- // background-color: #800;
- // height: 20px;
+.mx_ImageView_button_rotateCCW::before {
+ mask-image: url('$(res)/img/image-view/rotate-ccw.svg');
+}
+
+.mx_ImageView_button_zoomOut::before {
+ mask-image: url('$(res)/img/image-view/zoom-out.svg');
+}
+
+.mx_ImageView_button_zoomIn::before {
+ mask-image: url('$(res)/img/image-view/zoom-in.svg');
+}
+
+.mx_ImageView_button_download::before {
+ mask-image: url('$(res)/img/image-view/download.svg');
+}
+
+.mx_ImageView_button_more::before {
+ mask-image: url('$(res)/img/image-view/more.svg');
+}
+
+.mx_ImageView_button_close {
+ border-radius: 100%;
+ background: #21262c; // same on all themes
+ &::before {
+ width: 32px;
+ height: 32px;
+ mask-image: url('$(res)/img/image-view/close.svg');
+ mask-size: 40%;
+ }
}
diff --git a/res/css/views/room_settings/_ColorSettings.scss b/res/css/views/elements/_InfoTooltip.scss
similarity index 56%
rename from res/css/views/room_settings/_ColorSettings.scss
rename to res/css/views/elements/_InfoTooltip.scss
index fc6a4443ad..5858a60629 100644
--- a/res/css/views/room_settings/_ColorSettings.scss
+++ b/res/css/views/elements/_InfoTooltip.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2019 New Vector Ltd.
+Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,26 +14,21 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_ColorSettings_roomColor {
+.mx_InfoTooltip_icon {
+ width: 16px;
+ height: 16px;
display: inline-block;
- position: relative;
- width: 37px;
- height: 37px;
- border: 1px solid #979797;
- margin-right: 13px;
- cursor: pointer;
}
-.mx_ColorSettings_roomColor_selected {
- position: absolute;
- left: 10px;
- top: 4px;
- cursor: default !important;
-}
-
-.mx_ColorSettings_roomColorPrimary {
- height: 10px;
- position: absolute;
- bottom: 0px;
- width: 100%;
+.mx_InfoTooltip_icon::before {
+ display: inline-block;
+ background-color: $muted-fg-color;
+ mask-repeat: no-repeat;
+ mask-size: 16px;
+ width: 16px;
+ height: 16px;
+ mask-position: center;
+ content: '';
+ vertical-align: middle;
+ mask-image: url('$(res)/img/element-icons/info.svg');
}
diff --git a/res/css/views/elements/_InviteReason.scss b/res/css/views/elements/_InviteReason.scss
new file mode 100644
index 0000000000..2c2e5687e6
--- /dev/null
+++ b/res/css/views/elements/_InviteReason.scss
@@ -0,0 +1,57 @@
+/*
+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_InviteReason {
+ position: relative;
+ margin-bottom: 1em;
+
+ .mx_InviteReason_reason {
+ visibility: visible;
+ }
+
+ .mx_InviteReason_view {
+ display: none;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ color: $secondary-fg-color;
+
+ &::before {
+ content: "";
+ margin-right: 8px;
+ background-color: $secondary-fg-color;
+ mask-image: url('$(res)/img/feather-customised/eye.svg');
+ display: inline-block;
+ width: 18px;
+ height: 14px;
+ }
+ }
+}
+
+.mx_InviteReason_hidden {
+ .mx_InviteReason_reason {
+ visibility: hidden;
+ }
+
+ .mx_InviteReason_view {
+ display: flex;
+ }
+}
diff --git a/res/css/views/elements/_MiniAvatarUploader.scss b/res/css/views/elements/_MiniAvatarUploader.scss
new file mode 100644
index 0000000000..698184a095
--- /dev/null
+++ b/res/css/views/elements/_MiniAvatarUploader.scss
@@ -0,0 +1,66 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_MiniAvatarUploader {
+ position: relative;
+ width: min-content;
+
+ // this isn't a floating tooltip so override some things to not need to bother with z-index and floating
+ .mx_Tooltip {
+ display: inline-block;
+ position: absolute;
+ z-index: unset;
+ width: max-content;
+ left: 72px;
+ top: 0;
+ }
+
+ &::before, &::after {
+ content: '';
+ position: absolute;
+
+ height: 26px;
+ width: 26px;
+
+ right: -6px;
+ bottom: -6px;
+ }
+
+ &::before {
+ background-color: $primary-bg-color;
+ border-radius: 50%;
+ z-index: 1;
+ }
+
+ &::after {
+ background-color: $secondary-fg-color;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-image: url('$(res)/img/element-icons/camera.svg');
+ mask-size: 16px;
+ z-index: 2;
+ }
+
+ &.mx_MiniAvatarUploader_busy::after {
+ background: url("$(res)/img/spinner.gif") no-repeat center;
+ background-size: 80%;
+ mask: unset;
+ }
+}
+
+.mx_MiniAvatarUploader_input {
+ display: none;
+}
diff --git a/res/css/views/elements/_ProgressBar.scss b/res/css/views/elements/_ProgressBar.scss
index e49d85af04..c075ac74ff 100644
--- a/res/css/views/elements/_ProgressBar.scss
+++ b/res/css/views/elements/_ProgressBar.scss
@@ -1,5 +1,5 @@
/*
-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.
@@ -15,15 +15,15 @@ limitations under the License.
*/
progress.mx_ProgressBar {
- height: 4px;
+ height: 6px;
width: 60px;
- border-radius: 10px;
overflow: hidden;
appearance: none;
- border: 0;
+ border: none;
- @mixin ProgressBarBorderRadius "10px";
- @mixin ProgressBarColour $accent-color;
+ @mixin ProgressBarBorderRadius 6px;
+ @mixin ProgressBarColour $progressbar-fg-color;
+ @mixin ProgressBarBgColour $progressbar-bg-color;
::-webkit-progress-value {
transition: width 1s;
}
diff --git a/res/css/views/elements/_SSOButtons.scss b/res/css/views/elements/_SSOButtons.scss
new file mode 100644
index 0000000000..e02816780f
--- /dev/null
+++ b/res/css/views/elements/_SSOButtons.scss
@@ -0,0 +1,74 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_SSOButtons {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+
+ .mx_SSOButtons_row {
+ & + .mx_SSOButtons_row {
+ margin-top: 16px;
+ }
+ }
+
+ .mx_SSOButton {
+ position: relative;
+ width: 100%;
+ padding: 7px 32px;
+ text-align: center;
+ border-radius: 8px;
+ display: inline-block;
+ font-size: $font-14px;
+ font-weight: $font-semi-bold;
+ border: 1px solid $input-border-color;
+ color: $primary-fg-color;
+
+ > img {
+ object-fit: contain;
+ position: absolute;
+ left: 8px;
+ top: 4px;
+ }
+ }
+
+ .mx_SSOButton_default {
+ color: $button-primary-bg-color;
+ background-color: $button-secondary-bg-color;
+ border-color: $button-primary-bg-color;
+ }
+ .mx_SSOButton_default.mx_SSOButton_primary {
+ color: $button-primary-fg-color;
+ background-color: $button-primary-bg-color;
+ }
+
+ .mx_SSOButton_mini {
+ box-sizing: border-box;
+ width: 50px; // 48px + 1px border on all sides
+ height: 50px; // 48px + 1px border on all sides
+ min-width: 50px; // prevent crushing by the flexbox
+ padding: 12px;
+
+ > img {
+ left: 12px;
+ top: 12px;
+ }
+
+ & + .mx_SSOButton_mini {
+ margin-left: 16px;
+ }
+ }
+}
diff --git a/res/css/views/elements/_ServerPicker.scss b/res/css/views/elements/_ServerPicker.scss
new file mode 100644
index 0000000000..188eb5d655
--- /dev/null
+++ b/res/css/views/elements/_ServerPicker.scss
@@ -0,0 +1,88 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_ServerPicker {
+ margin-bottom: 14px;
+ border-bottom: 1px solid rgba(141, 151, 165, 0.2);
+ display: grid;
+ grid-template-columns: auto min-content;
+ grid-template-rows: auto auto auto;
+ font-size: $font-14px;
+ line-height: $font-20px;
+
+ > h3 {
+ font-weight: $font-semi-bold;
+ margin: 0 0 20px;
+ grid-column: 1;
+ grid-row: 1;
+ }
+
+ .mx_ServerPicker_help {
+ width: 20px;
+ height: 20px;
+ background-color: $icon-button-color;
+ border-radius: 10px;
+ grid-column: 2;
+ grid-row: 1;
+ margin-left: auto;
+ text-align: center;
+ color: #ffffff;
+ font-size: 16px;
+ position: relative;
+
+ &::before {
+ content: '';
+ width: 24px;
+ height: 24px;
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ mask-image: url('$(res)/img/element-icons/i.svg');
+ background: #ffffff;
+ }
+ }
+
+ .mx_ServerPicker_server {
+ color: $authpage-primary-color;
+ grid-column: 1;
+ grid-row: 2;
+ margin-bottom: 16px;
+ }
+
+ .mx_ServerPicker_change {
+ padding: 0;
+ font-size: inherit;
+ grid-column: 2;
+ grid-row: 2;
+ }
+
+ .mx_ServerPicker_desc {
+ margin-top: -12px;
+ color: $tertiary-fg-color;
+ grid-column: 1 / 2;
+ grid-row: 3;
+ margin-bottom: 16px;
+ }
+}
+
+.mx_ServerPicker_helpDialog {
+ .mx_Dialog_content {
+ width: 456px;
+ }
+}
diff --git a/res/css/views/elements/_StyledCheckbox.scss b/res/css/views/elements/_StyledCheckbox.scss
index 60f1bf0277..e2d61c033b 100644
--- a/res/css/views/elements/_StyledCheckbox.scss
+++ b/res/css/views/elements/_StyledCheckbox.scss
@@ -80,5 +80,11 @@ limitations under the License.
background-color: $accent-color;
border-color: $accent-color;
}
+
+ &.focus-visible {
+ & + label .mx_Checkbox_background {
+ @mixin unreal-focus;
+ }
+ }
}
}
diff --git a/res/css/views/elements/_StyledRadioButton.scss b/res/css/views/elements/_StyledRadioButton.scss
index ffa1337ebb..62fb5c5512 100644
--- a/res/css/views/elements/_StyledRadioButton.scss
+++ b/res/css/views/elements/_StyledRadioButton.scss
@@ -63,6 +63,7 @@ limitations under the License.
box-sizing: border-box;
height: $font-16px;
width: $font-16px;
+ margin-left: 2px; // For the highlight on focus
border: $font-1-5px solid $radio-circle-color;
border-radius: $font-16px;
@@ -77,6 +78,12 @@ limitations under the License.
}
}
+ &.focus-visible {
+ & + div {
+ @mixin unreal-focus;
+ }
+ }
+
&:checked {
& + div {
border-color: $active-radio-circle-color;
diff --git a/res/css/views/messages/_CreateEvent.scss b/res/css/views/messages/_CreateEvent.scss
index d45645863f..cb2bf841dd 100644
--- a/res/css/views/messages/_CreateEvent.scss
+++ b/res/css/views/messages/_CreateEvent.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2018 New Vector Ltd
+Copyright 2018, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,25 +15,8 @@ limitations under the License.
*/
.mx_CreateEvent {
- background-color: $info-plinth-bg-color;
- padding-left: 20px;
- padding-right: 20px;
- padding-top: 10px;
- padding-bottom: 10px;
-}
-
-.mx_CreateEvent_image {
- float: left;
- margin-right: 20px;
- width: 72px;
- height: 34px;
-
- background-color: $primary-fg-color;
- mask: url('$(res)/img/room-continuation.svg');
- mask-repeat: no-repeat;
- mask-position: center;
-}
-
-.mx_CreateEvent_header {
- font-weight: bold;
+ &::before {
+ background-color: $composer-e2e-icon-color;
+ mask-image: url('$(res)/img/element-icons/chat-bubbles.svg');
+ }
}
diff --git a/res/css/views/messages/_EventTileBubble.scss b/res/css/views/messages/_EventTileBubble.scss
new file mode 100644
index 0000000000..e0f5d521cb
--- /dev/null
+++ b/res/css/views/messages/_EventTileBubble.scss
@@ -0,0 +1,60 @@
+/*
+Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_EventTileBubble {
+ background-color: $dark-panel-bg-color;
+ padding: 10px;
+ border-radius: 8px;
+ margin: 10px auto;
+ max-width: 75%;
+ box-sizing: border-box;
+ display: grid;
+ grid-template-columns: 24px minmax(0, 1fr) min-content;
+
+ &::before, &::after {
+ position: relative;
+ grid-column: 1;
+ grid-row: 1 / 3;
+ width: 16px;
+ height: 16px;
+ content: "";
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: contain;
+ margin-top: 4px;
+ }
+
+ .mx_EventTileBubble_title, .mx_EventTileBubble_subtitle {
+ overflow-wrap: break-word;
+ }
+
+ .mx_EventTileBubble_title {
+ font-weight: 600;
+ font-size: $font-15px;
+ grid-column: 2;
+ grid-row: 1;
+ }
+
+ .mx_EventTileBubble_subtitle {
+ font-size: $font-12px;
+ grid-column: 2;
+ grid-row: 2;
+ }
+}
diff --git a/res/css/views/messages/_MFileBody.scss b/res/css/views/messages/_MFileBody.scss
index 6cbce68745..c215d69ec2 100644
--- a/res/css/views/messages/_MFileBody.scss
+++ b/res/css/views/messages/_MFileBody.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2015, 2016 OpenMarket Ltd
+Copyright 2015, 2016, 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.
@@ -16,6 +16,19 @@ limitations under the License.
.mx_MFileBody_download {
color: $accent-color;
+
+ .mx_MFileBody_download_icon {
+ // 12px instead of 14px to better match surrounding font size
+ width: 12px;
+ height: 12px;
+ mask-size: 12px;
+
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-image: url("$(res)/img/download.svg");
+ background-color: $accent-color;
+ display: inline-block;
+ }
}
.mx_MFileBody_download a {
@@ -45,3 +58,46 @@ limitations under the License.
* big the content of the iframe is. */
height: 1.5em;
}
+
+.mx_MFileBody_info {
+ background-color: $message-body-panel-bg-color;
+ border-radius: 12px;
+ width: 243px; // same width as a playable voice message, accounting for padding
+ padding: 6px 12px;
+ color: $message-body-panel-fg-color;
+
+ .mx_MFileBody_info_icon {
+ background-color: $message-body-panel-icon-bg-color;
+ border-radius: 20px;
+ display: inline-block;
+ width: 32px;
+ height: 32px;
+ position: relative;
+ vertical-align: middle;
+ margin-right: 12px;
+
+ &::before {
+ content: '';
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: cover;
+ mask-image: url('$(res)/img/element-icons/room/composer/attach.svg');
+ background-color: $message-body-panel-icon-fg-color;
+ width: 13px;
+ height: 15px;
+
+ position: absolute;
+ top: 8px;
+ left: 9px;
+ }
+ }
+
+ .mx_MFileBody_info_filename {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ display: inline-block;
+ width: calc(100% - 32px - 12px); // 32px icon, 12px margin on the icon
+ vertical-align: middle;
+ }
+}
diff --git a/res/css/views/messages/_MImageBody.scss b/res/css/views/messages/_MImageBody.scss
index 547b16e9ad..1c773c2f06 100644
--- a/res/css/views/messages/_MImageBody.scss
+++ b/res/css/views/messages/_MImageBody.scss
@@ -25,6 +25,7 @@ limitations under the License.
height: 100%;
left: 0;
top: 0;
+ border-radius: 4px;
}
.mx_MImageBody_thumbnail_container {
diff --git a/res/css/views/messages/_MJitsiWidgetEvent.scss b/res/css/views/messages/_MJitsiWidgetEvent.scss
new file mode 100644
index 0000000000..bea8651543
--- /dev/null
+++ b/res/css/views/messages/_MJitsiWidgetEvent.scss
@@ -0,0 +1,22 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_MJitsiWidgetEvent {
+ &::before {
+ background-color: $composer-e2e-icon-color; // XXX: Variable abuse
+ mask-image: url('$(res)/img/element-icons/call/video-call.svg');
+ }
+}
diff --git a/res/css/views/messages/_MVideoBody.scss b/res/css/views/messages/_MVideoBody.scss
index 3b05c53f34..ac3491bc8f 100644
--- a/res/css/views/messages/_MVideoBody.scss
+++ b/res/css/views/messages/_MVideoBody.scss
@@ -18,5 +18,6 @@ span.mx_MVideoBody {
video.mx_MVideoBody {
max-width: 100%;
height: auto;
+ border-radius: 4px;
}
}
diff --git a/res/css/views/messages/_MVoiceMessageBody.scss b/res/css/views/messages/_MVoiceMessageBody.scss
new file mode 100644
index 0000000000..3dfb98f778
--- /dev/null
+++ b/res/css/views/messages/_MVoiceMessageBody.scss
@@ -0,0 +1,19 @@
+/*
+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_MVoiceMessageBody {
+ display: inline-block; // makes the playback controls magically line up
+}
diff --git a/res/css/views/messages/_MessageActionBar.scss b/res/css/views/messages/_MessageActionBar.scss
index e3ccd99611..d41ac3a4ba 100644
--- a/res/css/views/messages/_MessageActionBar.scss
+++ b/res/css/views/messages/_MessageActionBar.scss
@@ -24,7 +24,7 @@ limitations under the License.
line-height: $font-24px;
border-radius: 4px;
background: $message-action-bar-bg-color;
- top: -18px;
+ top: -26px;
right: 8px;
user-select: none;
// Ensure the action bar appears above over things, like the read marker.
@@ -41,7 +41,7 @@ limitations under the License.
width: calc(10px + 48px + 100% + 8px);
// safe area + action bar
height: calc(20px + 100%);
- top: -20px;
+ top: -12px;
left: -58px;
z-index: -1;
cursor: initial;
@@ -85,6 +85,7 @@ limitations under the License.
left: 0;
height: 100%;
width: 100%;
+ mask-size: 18px;
mask-repeat: no-repeat;
mask-position: center;
background-color: $message-action-bar-fg-color;
@@ -105,3 +106,11 @@ limitations under the License.
.mx_MessageActionBar_optionsButton::after {
mask-image: url('$(res)/img/element-icons/context-menu.svg');
}
+
+.mx_MessageActionBar_resendButton::after {
+ mask-image: url('$(res)/img/element-icons/retry.svg');
+}
+
+.mx_MessageActionBar_cancelButton::after {
+ mask-image: url('$(res)/img/element-icons/trashcan.svg');
+}
diff --git a/res/css/views/messages/_ReactionsRow.scss b/res/css/views/messages/_ReactionsRow.scss
index 2f5695e1fb..e05065eb02 100644
--- a/res/css/views/messages/_ReactionsRow.scss
+++ b/res/css/views/messages/_ReactionsRow.scss
@@ -17,18 +17,56 @@ limitations under the License.
.mx_ReactionsRow {
margin: 6px 0;
color: $primary-fg-color;
+
+ .mx_ReactionsRow_addReactionButton {
+ position: relative;
+ display: inline-block;
+ visibility: hidden; // show on hover of the .mx_EventTile
+ width: 24px;
+ height: 24px;
+ vertical-align: middle;
+ margin-left: 4px;
+
+ &::before {
+ content: '';
+ position: absolute;
+ height: 100%;
+ width: 100%;
+ mask-size: 16px;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ background-color: $tertiary-fg-color;
+ mask-image: url('$(res)/img/element-icons/room/message-bar/emoji.svg');
+ }
+
+ &.mx_ReactionsRow_addReactionButton_active {
+ visibility: visible; // keep showing whilst the context menu is shown
+ }
+
+ &:hover, &.mx_ReactionsRow_addReactionButton_active {
+ &::before {
+ background-color: $primary-fg-color;
+ }
+ }
+ }
+}
+
+.mx_EventTile:hover .mx_ReactionsRow_addReactionButton {
+ visibility: visible;
}
.mx_ReactionsRow_showAll {
text-decoration: none;
- font-size: $font-10px;
- font-weight: 600;
- margin-left: 6px;
- vertical-align: top;
+ font-size: $font-12px;
+ line-height: $font-20px;
+ margin-left: 4px;
+ vertical-align: middle;
- &:hover,
- &:link,
- &:visited {
- color: $accent-color;
+ &:link, &:visited {
+ color: $tertiary-fg-color;
+ }
+
+ &:hover {
+ color: $primary-fg-color;
}
}
diff --git a/res/css/views/messages/_ReactionsRowButton.scss b/res/css/views/messages/_ReactionsRowButton.scss
index 7158ffc027..766fea2f8f 100644
--- a/res/css/views/messages/_ReactionsRowButton.scss
+++ b/res/css/views/messages/_ReactionsRowButton.scss
@@ -16,14 +16,15 @@ limitations under the License.
.mx_ReactionsRowButton {
display: inline-flex;
- line-height: $font-21px;
+ line-height: $font-20px;
margin-right: 6px;
- padding: 0 6px;
+ padding: 1px 6px;
border: 1px solid $reaction-row-button-border-color;
border-radius: 10px;
background-color: $reaction-row-button-bg-color;
cursor: pointer;
user-select: none;
+ vertical-align: middle;
&:hover {
border-color: $reaction-row-button-hover-border-color;
@@ -34,6 +35,10 @@ limitations under the License.
border-color: $reaction-row-button-selected-border-color;
}
+ &.mx_AccessibleButton_disabled {
+ cursor: not-allowed;
+ }
+
.mx_ReactionsRowButton_content {
max-width: 100px;
overflow: hidden;
diff --git a/res/css/views/messages/_RedactedBody.scss b/res/css/views/messages/_RedactedBody.scss
index e4ab0c0835..600ac0c6b7 100644
--- a/res/css/views/messages/_RedactedBody.scss
+++ b/res/css/views/messages/_RedactedBody.scss
@@ -30,7 +30,7 @@ limitations under the License.
mask-size: contain;
content: '';
position: absolute;
- top: 2px;
+ top: 1px;
left: 0;
}
}
diff --git a/res/css/views/messages/_ViewSourceEvent.scss b/res/css/views/messages/_ViewSourceEvent.scss
index 076932ee97..66825030e0 100644
--- a/res/css/views/messages/_ViewSourceEvent.scss
+++ b/res/css/views/messages/_ViewSourceEvent.scss
@@ -35,13 +35,13 @@ limitations under the License.
mask-size: auto 12px;
visibility: hidden;
background-color: $accent-color;
- mask-image: url('$(res)/img/feather-customised/widget/maximise.svg');
+ mask-image: url('$(res)/img/feather-customised/maximise.svg');
}
&.mx_ViewSourceEvent_expanded .mx_ViewSourceEvent_toggle {
mask-position: 0 bottom;
margin-bottom: 7px;
- mask-image: url('$(res)/img/feather-customised/widget/minimise.svg');
+ mask-image: url('$(res)/img/feather-customised/minimise.svg');
}
&:hover .mx_ViewSourceEvent_toggle {
diff --git a/res/css/views/messages/_common_CryptoEvent.scss b/res/css/views/messages/_common_CryptoEvent.scss
index 09c78ae5b4..4faa4b594f 100644
--- a/res/css/views/messages/_common_CryptoEvent.scss
+++ b/res/css/views/messages/_common_CryptoEvent.scss
@@ -15,28 +15,6 @@ limitations under the License.
*/
.mx_cryptoEvent {
- display: grid;
- grid-template-columns: 24px minmax(0, 1fr) min-content;
-
- &.mx_cryptoEvent_icon::before,
- &.mx_cryptoEvent_icon::after {
- grid-column: 1;
- grid-row: 1 / 3;
- width: 16px;
- height: 16px;
- content: "";
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- mask-repeat: no-repeat;
- mask-position: center;
- mask-size: contain;
- mask-image: url('$(res)/img/e2e/normal.svg');
- background-color: $composer-e2e-icon-color;
- margin-top: 4px;
- }
-
// white infill for the transparency
&.mx_cryptoEvent_icon::before {
background-color: #ffffff;
@@ -46,6 +24,11 @@ limitations under the License.
mask-size: 90%;
}
+ &.mx_cryptoEvent_icon::after {
+ mask-image: url('$(res)/img/e2e/normal.svg');
+ background-color: $composer-e2e-icon-color;
+ }
+
&.mx_cryptoEvent_icon_verified::after {
mask-image: url("$(res)/img/e2e/verified.svg");
background-color: $accent-color;
@@ -56,25 +39,6 @@ limitations under the License.
background-color: $notice-primary-color;
}
- .mx_cryptoEvent_title, .mx_cryptoEvent_subtitle, .mx_cryptoEvent_state {
- overflow-wrap: break-word;
- }
-
- .mx_cryptoEvent_title {
- font-weight: 600;
- font-size: $font-15px;
- grid-column: 2;
- grid-row: 1;
- }
-
- .mx_cryptoEvent_subtitle {
- grid-column: 2;
- grid-row: 2;
- }
-
- .mx_cryptoEvent_state, .mx_cryptoEvent_subtitle {
- font-size: $font-12px;
- }
.mx_cryptoEvent_state, .mx_cryptoEvent_buttons {
grid-column: 3;
@@ -92,5 +56,7 @@ limitations under the License.
margin: auto 0;
text-align: center;
color: $notice-secondary-color;
+ overflow-wrap: break-word;
+ font-size: $font-12px;
}
}
diff --git a/res/css/views/right_panel/_BaseCard.scss b/res/css/views/right_panel/_BaseCard.scss
new file mode 100644
index 0000000000..9a5a59bda8
--- /dev/null
+++ b/res/css/views/right_panel/_BaseCard.scss
@@ -0,0 +1,172 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_BaseCard {
+ padding: 0 8px;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+
+ .mx_BaseCard_header {
+ margin: 8px 0;
+
+ > h2 {
+ margin: 0 44px;
+ font-size: $font-18px;
+ font-weight: $font-semi-bold;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .mx_BaseCard_back, .mx_BaseCard_close {
+ position: absolute;
+ background-color: rgba(141, 151, 165, 0.2);
+ height: 20px;
+ width: 20px;
+ margin: 12px;
+ top: 0;
+ border-radius: 10px;
+
+ &::before {
+ content: "";
+ position: absolute;
+ height: 20px;
+ width: 20px;
+ top: 0;
+ left: 0;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ background-color: $rightpanel-button-color;
+ }
+ }
+
+ .mx_BaseCard_back {
+ left: 0;
+
+ &::before {
+ transform: rotate(90deg);
+ mask-size: 22px;
+ mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
+ }
+ }
+
+ .mx_BaseCard_close {
+ right: 0;
+
+ &::before {
+ mask-image: url('$(res)/img/icons-close.svg');
+ mask-size: 8px;
+ }
+ }
+ }
+
+ .mx_AutoHideScrollbar {
+ // collapse the margin into a padding to move the scrollbar into the right gutter
+ margin-right: -8px;
+ padding-right: 8px;
+ min-height: 0;
+ width: 100%;
+ height: 100%;
+ }
+
+ .mx_BaseCard_Group {
+ margin: 20px 0 16px;
+
+ & > * {
+ margin-left: 12px;
+ margin-right: 12px;
+ }
+
+ > h1 {
+ color: $tertiary-fg-color;
+ font-size: $font-12px;
+ font-weight: 500;
+ }
+
+ .mx_BaseCard_Button {
+ padding: 10px 38px 10px 12px;
+ margin: 0;
+ position: relative;
+ font-size: $font-13px;
+ height: 20px;
+ line-height: 20px;
+ border-radius: 8px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+
+ &:hover {
+ background-color: rgba(141, 151, 165, 0.1);
+ }
+
+ &::after {
+ content: '';
+ position: absolute;
+ top: 10px;
+ right: 6px;
+ height: 20px;
+ width: 20px;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ background-color: $icon-button-color;
+ transform: rotate(270deg);
+ mask-size: 20px;
+ mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
+ }
+
+ &.mx_AccessibleButton_disabled {
+ padding-right: 12px;
+ &::after {
+ content: unset;
+ }
+ }
+ }
+ }
+
+ .mx_BaseCard_footer {
+ padding-top: 4px;
+ text-align: center;
+ display: flex;
+ justify-content: space-around;
+
+ .mx_AccessibleButton_kind_secondary {
+ color: $secondary-fg-color;
+ background-color: rgba(141, 151, 165, 0.2);
+ font-weight: $font-semi-bold;
+ font-size: $font-14px;
+ }
+
+ .mx_AccessibleButton_disabled {
+ cursor: not-allowed;
+ }
+ }
+}
+
+.mx_FilePanel,
+.mx_UserInfo,
+.mx_NotificationPanel,
+.mx_MemberList {
+ &.mx_BaseCard {
+ padding: 32px 0 0;
+
+ .mx_AutoHideScrollbar {
+ margin-right: unset;
+ padding-right: unset;
+ }
+ }
+}
diff --git a/res/css/views/right_panel/_EncryptionInfo.scss b/res/css/views/right_panel/_EncryptionInfo.scss
index e13b1b6802..b3d4275f60 100644
--- a/res/css/views/right_panel/_EncryptionInfo.scss
+++ b/res/css/views/right_panel/_EncryptionInfo.scss
@@ -14,13 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_UserInfo {
- .mx_EncryptionInfo_spinner {
- .mx_Spinner {
- margin-top: 25px;
- margin-bottom: 15px;
- }
-
- text-align: center;
+.mx_EncryptionInfo_spinner {
+ .mx_Spinner {
+ margin-top: 25px;
+ margin-bottom: 15px;
}
+
+ text-align: center;
}
diff --git a/res/css/views/right_panel/_RoomSummaryCard.scss b/res/css/views/right_panel/_RoomSummaryCard.scss
new file mode 100644
index 0000000000..36882f4e8b
--- /dev/null
+++ b/res/css/views/right_panel/_RoomSummaryCard.scss
@@ -0,0 +1,240 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_RoomSummaryCard {
+ .mx_BaseCard_header {
+ text-align: center;
+ margin-top: 20px;
+
+ h2 {
+ font-weight: $font-semi-bold;
+ font-size: $font-18px;
+ margin: 12px 0 4px;
+ }
+
+ .mx_RoomSummaryCard_alias {
+ font-size: $font-13px;
+ color: $secondary-fg-color;
+ }
+
+ h2, .mx_RoomSummaryCard_alias {
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .mx_RoomSummaryCard_avatar {
+ display: inline-flex;
+
+ .mx_RoomSummaryCard_e2ee {
+ display: inline-block;
+ position: relative;
+ width: 54px;
+ height: 54px;
+ border-radius: 50%;
+ background-color: #737d8c;
+ margin-top: -3px; // alignment
+ margin-left: -10px; // overlap
+ border: 3px solid $dark-panel-bg-color;
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: 13px;
+ left: 13px;
+ height: 28px;
+ width: 28px;
+ mask-size: cover;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-image: url('$(res)/img/e2e/disabled.svg');
+ background-color: #ffffff;
+ }
+ }
+
+ .mx_RoomSummaryCard_e2ee_normal {
+ background-color: #424446;
+ &::before {
+ mask-image: url('$(res)/img/e2e/normal.svg');
+ }
+ }
+
+ .mx_RoomSummaryCard_e2ee_verified {
+ background-color: #0dbd8b;
+ &::before {
+ mask-image: url('$(res)/img/e2e/verified.svg');
+ }
+ }
+
+ .mx_RoomSummaryCard_e2ee_warning {
+ background-color: #ff4b55;
+ &::before {
+ mask-image: url('$(res)/img/e2e/warning.svg');
+ }
+ }
+ }
+ }
+
+ .mx_RoomSummaryCard_aboutGroup {
+ .mx_RoomSummaryCard_Button {
+ padding-left: 44px;
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: 8px;
+ left: 10px;
+ height: 24px;
+ width: 24px;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ background-color: $icon-button-color;
+ }
+ }
+ }
+
+ .mx_RoomSummaryCard_appsGroup {
+ .mx_RoomSummaryCard_Button {
+ // this button is special so we have to override some of the original styling
+ // as we will be applying it in its children
+ padding: 0;
+ height: auto;
+ color: $tertiary-fg-color;
+
+ .mx_RoomSummaryCard_icon_app {
+ padding: 10px 48px 10px 12px; // based on typical mx_RoomSummaryCard_Button padding
+ text-overflow: ellipsis;
+ overflow: hidden;
+
+ .mx_BaseAvatar_image {
+ vertical-align: top;
+ margin-right: 12px;
+ }
+
+ span {
+ color: $primary-fg-color;
+ }
+ }
+
+ .mx_RoomSummaryCard_app_pinToggle,
+ .mx_RoomSummaryCard_app_options {
+ position: absolute;
+ top: 0;
+ height: 100%; // to give bigger interactive zone
+ width: 24px;
+ padding: 12px 4px;
+ box-sizing: border-box;
+ min-width: 24px; // prevent flexbox crushing
+
+ &:hover {
+ &::after {
+ content: '';
+ position: absolute;
+ height: 24px;
+ width: 24px;
+ top: 8px; // equal to padding-top of parent
+ left: 0;
+ border-radius: 12px;
+ background-color: rgba(141, 151, 165, 0.1);
+ }
+ }
+
+ &::before {
+ content: '';
+ position: absolute;
+ height: 16px;
+ width: 16px;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: 16px;
+ background-color: $icon-button-color;
+ }
+ }
+
+ .mx_RoomSummaryCard_app_pinToggle {
+ right: 24px;
+
+ &::before {
+ mask-image: url('$(res)/img/element-icons/room/pin-upright.svg');
+ }
+ }
+
+ .mx_RoomSummaryCard_app_options {
+ right: 48px;
+ display: none;
+
+ &::before {
+ mask-image: url('$(res)/img/element-icons/room/ellipsis.svg');
+ }
+ }
+
+ &.mx_RoomSummaryCard_Button_pinned {
+ &::after {
+ opacity: 0.2;
+ }
+
+ .mx_RoomSummaryCard_app_pinToggle::before {
+ background-color: $accent-color;
+ }
+ }
+
+ &:hover {
+ .mx_RoomSummaryCard_icon_app {
+ padding-right: 72px;
+ }
+
+ .mx_RoomSummaryCard_app_options {
+ display: unset;
+ }
+ }
+
+ &::before {
+ content: unset;
+ }
+
+ &::after {
+ top: 8px; // re-align based on the height change
+ pointer-events: none; // pass through to the real button
+ }
+ }
+ }
+
+ .mx_AccessibleButton_kind_link {
+ padding: 0;
+ margin-top: 12px;
+ margin-bottom: 12px;
+ font-size: $font-13px;
+ font-weight: $font-semi-bold;
+ }
+}
+
+.mx_RoomSummaryCard_icon_people::before {
+ mask-image: url("$(res)/img/element-icons/room/members.svg");
+}
+
+.mx_RoomSummaryCard_icon_files::before {
+ mask-image: url('$(res)/img/element-icons/room/files.svg');
+}
+
+.mx_RoomSummaryCard_icon_share::before {
+ mask-image: url('$(res)/img/element-icons/room/share.svg');
+}
+
+.mx_RoomSummaryCard_icon_settings::before {
+ mask-image: url('$(res)/img/element-icons/settings.svg');
+}
diff --git a/res/css/views/right_panel/_UserInfo.scss b/res/css/views/right_panel/_UserInfo.scss
index 6f86d1ad18..87420ae4e7 100644
--- a/res/css/views/right_panel/_UserInfo.scss
+++ b/res/css/views/right_panel/_UserInfo.scss
@@ -15,7 +15,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_UserInfo {
+.mx_UserInfo.mx_BaseCard {
+ // UserInfo has a circular image at the top so it fits between the back & close buttons
+ padding-top: 0;
display: flex;
flex-direction: column;
flex: 1;
@@ -171,26 +173,12 @@ limitations under the License.
margin: 6px 0;
- .mx_IconButton, .mx_Spinner {
- margin-left: 20px;
- width: 16px;
- height: 16px;
-
- &::before {
- mask-size: 80%;
- }
- }
-
.mx_UserInfo_roleDescription {
display: flex;
justify-content: center;
align-items: center;
// try to make it the same height as the dropdown
margin: 11px 0 12px 0;
-
- .mx_IconButton {
- margin-left: 6px;
- }
}
.mx_Field {
@@ -217,9 +205,8 @@ limitations under the License.
text-overflow: clip;
}
- .mx_UserInfo_scrollContainer {
+ .mx_AutoHideScrollbar {
flex: 1 1 0;
- padding-bottom: 16px;
}
.mx_UserInfo_container:not(.mx_UserInfo_separator) {
diff --git a/res/css/views/right_panel/_WidgetCard.scss b/res/css/views/right_panel/_WidgetCard.scss
new file mode 100644
index 0000000000..a90e744a5a
--- /dev/null
+++ b/res/css/views/right_panel/_WidgetCard.scss
@@ -0,0 +1,63 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_WidgetCard {
+ height: 100%;
+ display: contents;
+
+ .mx_AppTileFullWidth {
+ max-width: unset;
+ height: 100%;
+ border: 0;
+ }
+
+ .mx_BaseCard_header {
+ display: inline-flex;
+
+ & > h2 {
+ margin-right: 0;
+ flex-grow: 1;
+ }
+
+ .mx_WidgetCard_optionsButton {
+ position: relative;
+ margin-right: 44px;
+ height: 20px;
+ width: 20px;
+ min-width: 20px; // prevent crushing by the flexbox
+ padding: 0;
+
+ &::before {
+ content: "";
+ position: absolute;
+ width: 20px;
+ height: 20px;
+ top: 0;
+ left: 4px;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: contain;
+ mask-image: url('$(res)/img/element-icons/room/ellipsis.svg');
+ background-color: $secondary-fg-color;
+ }
+ }
+ }
+}
+
+.mx_WidgetCard_maxPinnedTooltip {
+ background-color: $notice-primary-color;
+ color: #ffffff;
+}
diff --git a/res/css/views/rooms/_AppsDrawer.scss b/res/css/views/rooms/_AppsDrawer.scss
index 6be417f631..fd80836237 100644
--- a/res/css/views/rooms/_AppsDrawer.scss
+++ b/res/css/views/rooms/_AppsDrawer.scss
@@ -15,90 +15,171 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-/*
-the tile title bar is 5 (top border) + 12 (title, buttons) + 5 (bottom padding) px = 22px
-the body is assumed to be 300px (assumed by at least the sticker pickerm, perhaps elsewhere),
-so the body height would be 300px - 22px (room for title bar) = 278px
-BUT! the sticker picker also assumes it's a little less high than that because the iframe
-for the sticker picker doesn't have any padding or margin on it's bottom.
-so subtracking another 5px, which brings us at 273px.
-*/
-$AppsDrawerBodyHeight: 273px;
+$MiniAppTileHeight: 200px;
.mx_AppsDrawer {
- margin: 5px;
+ margin: 5px 5px 5px 18px;
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+
+ .mx_AppsContainer_resizerHandleContainer {
+ width: 100%;
+ height: 10px;
+ margin-top: -3px; // move it up so the interactions are slightly more comfortable
+ display: block;
+ position: relative;
+ }
+
+ .mx_AppsContainer_resizerHandle {
+ cursor: ns-resize;
+
+ // Override styles from library, making the whole area the target area
+ width: 100% !important;
+ height: 100% !important;
+
+ // This is positioned directly below frame
+ position: absolute;
+ bottom: 0 !important; // override from library
+
+ // We then render the pill handle in an ::after to keep it in the handle's
+ // area without being a massive line across the screen
+ &::after {
+ content: '';
+ position: absolute;
+ border-radius: 3px;
+
+ // The combination of these two should make the pill 4px high
+ top: 6px;
+ bottom: 0;
+
+ // Together, these make the bar 64px wide
+ // These are also overridden from the library
+ left: calc(50% - 32px);
+ right: calc(50% - 32px);
+ }
+ }
+
+ &:hover {
+ .mx_AppsContainer_resizerHandle::after {
+ opacity: 0.8;
+ background: $primary-fg-color;
+ }
+
+ .mx_ResizeHandle_horizontal::before {
+ position: absolute;
+ left: 3px;
+ top: 50%;
+ transform: translate(0, -50%);
+
+ height: 64px; // to match width of the ones on roomlist
+ width: 4px;
+ border-radius: 4px;
+
+ content: '';
+
+ background-color: $primary-fg-color;
+ opacity: 0.8;
+ }
+ }
}
-.mx_AppsDrawer_hidden {
- display: none;
+.mx_AppsContainer_resizer {
+ margin-bottom: 8px;
}
.mx_AppsContainer {
display: flex;
flex-direction: row;
- align-items: center;
+ align-items: stretch;
justify-content: center;
+ height: 100%;
+ width: 100%;
+ flex: 1;
+ min-height: 0;
+
+ .mx_AppTile:first-of-type {
+ border-left-width: 8px;
+ border-radius: 10px 0 0 10px;
+ }
+ .mx_AppTile:last-of-type {
+ border-right-width: 8px;
+ border-radius: 0 10px 10px 0;
+ }
+
+ .mx_ResizeHandle_horizontal {
+ position: relative;
+
+ > div {
+ width: 0;
+ }
+ }
}
-.mx_AddWidget_button {
- order: 2;
- cursor: pointer;
- padding: 0;
- margin: 5px auto 5px auto;
- color: $accent-color;
- font-size: $font-12px;
-}
+// TODO this should be 300px but that's too large
+$MinWidth: 240px;
-.mx_AddWidget_button_full_width {
- max-width: 960px;
-}
+.mx_AppsDrawer_2apps .mx_AppTile {
+ width: 50%;
-.mx_SetAppURLDialog_input {
- border-radius: 3px;
- border: 1px solid $input-border-color;
- padding: 9px;
- color: $primary-hairline-color;
- background-color: $primary-bg-color;
- font-size: $font-15px;
+ &:nth-child(3) {
+ flex-grow: 1;
+ width: 0 !important;
+ min-width: $MinWidth !important;
+ }
+}
+.mx_AppsDrawer_3apps .mx_AppTile {
+ width: 33%;
+
+ &:nth-child(3) {
+ flex-grow: 1;
+ width: 0 !important;
+ min-width: $MinWidth !important;
+ }
}
.mx_AppTile {
- max-width: 960px;
width: 50%;
- margin-right: 5px;
- border: 5px solid $widget-menu-bar-bg-color;
- border-radius: 4px;
-}
-
-.mx_AppTile:last-child {
- margin-right: 1px;
+ min-width: $MinWidth;
+ border: 8px solid $widget-menu-bar-bg-color;
+ border-left-width: 5px;
+ border-right-width: 5px;
+ display: flex;
+ flex-direction: column;
+ box-sizing: border-box;
+ background-color: $widget-menu-bar-bg-color;
}
.mx_AppTileFullWidth {
- max-width: 960px;
- width: 100%;
- height: 100%;
+ width: 100% !important; // to override the inline style set by the resizer
margin: 0;
padding: 0;
border: 5px solid $widget-menu-bar-bg-color;
border-radius: 8px;
+ display: flex;
+ flex-direction: column;
+ background-color: $widget-menu-bar-bg-color;
}
.mx_AppTile_mini {
- max-width: 960px;
width: 100%;
- height: 100%;
margin: 0;
padding: 0;
+ display: flex;
+ flex-direction: column;
+ height: $MiniAppTileHeight;
}
-.mx_AppTile_persistedWrapper {
- height: $AppsDrawerBodyHeight;
-}
-
+.mx_AppTile .mx_AppTile_persistedWrapper,
+.mx_AppTileFullWidth .mx_AppTile_persistedWrapper,
.mx_AppTile_mini .mx_AppTile_persistedWrapper {
- height: 114px;
- min-width: 300px;
+ flex: 1;
+}
+
+.mx_AppTile_persistedWrapper div {
+ width: 100%;
+ height: 100%;
}
.mx_AppTileMenuBar {
@@ -109,18 +190,20 @@ $AppsDrawerBodyHeight: 273px;
flex-direction: row;
align-items: center;
justify-content: space-between;
- cursor: pointer;
-}
-
-.mx_AppTileMenuBar_expanded {
- padding-bottom: 5px;
+ width: 100%;
+ padding-top: 2px;
+ padding-bottom: 8px;
}
.mx_AppTileMenuBarTitle {
- display: flex;
- flex-direction: row;
- align-items: center;
- pointer-events: none;
+ line-height: 20px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+
+ .mx_WidgetAvatar {
+ margin-right: 12px;
+ }
}
.mx_AppTileMenuBarTitle > :last-child {
@@ -144,43 +227,34 @@ $AppsDrawerBodyHeight: 273px;
margin: 0 3px;
}
-.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_minimise {
- mask-image: url('$(res)/img/feather-customised/widget/minimise.svg');
- background-color: $accent-color;
-}
-
-.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_maximise {
- mask-image: url('$(res)/img/feather-customised/widget/maximise.svg');
- background-color: $accent-color;
-}
-
.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_popout {
mask-image: url('$(res)/img/feather-customised/widget/external-link.svg');
}
.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_menu {
- mask-image: url('$(res)/img/icon_context.svg');
-}
-
-.mx_AppTileMenuBarWidgetDelete {
- filter: none;
-}
-
-.mx_AppTileMenuBarWidget:hover {
- border: 1px solid $primary-fg-color;
- border-radius: 2px;
+ mask-image: url('$(res)/img/element-icons/room/ellipsis.svg');
}
.mx_AppTileBody {
- height: $AppsDrawerBodyHeight;
+ height: 100%;
width: 100%;
overflow: hidden;
+ border-radius: 8px;
+ background-color: $widget-body-bg-color;
}
.mx_AppTileBody_mini {
- height: 112px;
+ height: $MiniAppTileHeight;
width: 100%;
overflow: hidden;
+ border-radius: 8px;
+}
+
+.mx_AppTile .mx_AppTileBody,
+.mx_AppTileFullWidth .mx_AppTileBody,
+.mx_AppTile_mini .mx_AppTileBody_mini {
+ height: inherit;
+ flex: 1;
}
.mx_AppTileBody_mini iframe {
@@ -191,7 +265,7 @@ $AppsDrawerBodyHeight: 273px;
.mx_AppTileBody iframe {
width: 100%;
- height: $AppsDrawerBodyHeight;
+ height: 100%;
overflow: hidden;
border: none;
padding: 0;
@@ -199,75 +273,8 @@ $AppsDrawerBodyHeight: 273px;
display: block;
}
-.mx_AppTileMenuBarWidgetPadding {
- margin-right: 5px;
-}
-
-.mx_AppIconTile {
- background-color: $lightbox-bg-color;
- border: 1px solid rgba(0, 0, 0, 0);
- width: 200px;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- transition: 0.3s;
- border-radius: 3px;
- margin: 5px;
- display: inline-block;
-}
-
-.mx_AppIconTile.mx_AppIconTile_active {
- color: $accent-color;
- border-color: $accent-color;
-}
-
-.mx_AppIconTile:hover {
- border: 1px solid $accent-color;
- box-shadow: 0 0 10px 5px rgba(200, 200, 200, 0.5);
-}
-
-.mx_AppIconTile_content {
- padding: 2px 16px;
- height: 60px;
- overflow: hidden;
-}
-
-.mx_AppIconTile_content h4 {
- margin-top: 5px;
- margin-bottom: 2px;
-}
-
-.mx_AppIconTile_content p {
- margin-top: 0;
- margin-bottom: 5px;
- font-size: smaller;
-}
-
-.mx_AppIconTile_image {
- padding: 10px;
- max-width: 100px;
- max-height: 100px;
- width: auto;
- height: auto;
-}
-
-.mx_AppIconTile_imageContainer {
- text-align: center;
- width: 100%;
- background-color: white;
- border-radius: 3px 3px 0 0;
- height: 155px;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-form.mx_Custom_Widget_Form div {
- margin-top: 10px;
- margin-bottom: 10px;
-}
-
.mx_AppPermissionWarning {
text-align: center;
- background-color: $widget-menu-bar-bg-color;
display: flex;
height: 100%;
flex-direction: column;
@@ -331,7 +338,11 @@ form.mx_Custom_Widget_Form div {
align-items: center;
font-weight: bold;
position: relative;
- height: $AppsDrawerBodyHeight;
+ height: 100%;
+
+ // match bg of border so that the cut corners have the right fill
+ background-color: $widget-body-bg-color !important;
+ border-radius: 8px;
}
.mx_AppLoading .mx_Spinner {
@@ -358,3 +369,7 @@ form.mx_Custom_Widget_Form div {
.mx_AppLoading iframe {
display: none;
}
+
+.mx_AppsDrawer_resizing .mx_AppTile_persistedWrapper {
+ z-index: 1;
+}
diff --git a/res/css/views/rooms/_AuxPanel.scss b/res/css/views/rooms/_AuxPanel.scss
index 34ef5e01d4..17a6294bf0 100644
--- a/res/css/views/rooms/_AuxPanel.scss
+++ b/res/css/views/rooms/_AuxPanel.scss
@@ -17,7 +17,7 @@ limitations under the License.
.m_RoomView_auxPanel_stateViews {
padding: 5px;
padding-left: 19px;
- border-bottom: 1px solid #e5e5e5;
+ border-bottom: 1px solid $primary-hairline-color;
}
.m_RoomView_auxPanel_stateViews_span a {
diff --git a/res/css/views/rooms/_BasicMessageComposer.scss b/res/css/views/rooms/_BasicMessageComposer.scss
index e126e523a6..e1ba468204 100644
--- a/res/css/views/rooms/_BasicMessageComposer.scss
+++ b/res/css/views/rooms/_BasicMessageComposer.scss
@@ -66,6 +66,11 @@ limitations under the License.
}
}
}
+
+ &.mx_BasicMessageComposer_input_disabled {
+ // Ignore all user input to avoid accidentally triggering the composer
+ pointer-events: none;
+ }
}
.mx_BasicMessageComposer_AutoCompleteWrapper {
diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss
index 2a2191b799..5d1dd04383 100644
--- a/res/css/views/rooms/_EventTile.scss
+++ b/res/css/views/rooms/_EventTile.scss
@@ -25,17 +25,8 @@ $left-gutter: 64px;
position: relative;
}
-.mx_EventTile_bubble {
- background-color: $dark-panel-bg-color;
- padding: 10px;
- border-radius: 5px;
- margin: 10px auto;
- max-width: 75%;
- box-sizing: border-box;
-}
-
.mx_EventTile.mx_EventTile_info {
- padding-top: 0px;
+ padding-top: 1px;
}
.mx_EventTile_avatar {
@@ -46,7 +37,7 @@ $left-gutter: 64px;
}
.mx_EventTile.mx_EventTile_info .mx_EventTile_avatar {
- top: $font-8px;
+ top: $font-6px;
left: $left-gutter;
}
@@ -83,7 +74,6 @@ $left-gutter: 64px;
margin-left: 5px;
display: inline-block;
vertical-align: top;
- height: 16px;
overflow: hidden;
user-select: none;
@@ -131,9 +121,10 @@ $left-gutter: 64px;
grid-template-columns: 1fr 100px;
.mx_EventTile_line {
- margin-right: 0px;
+ margin-right: 0;
grid-column: 1 / 3;
- padding: 0;
+ // override default padding of mx_EventTile_line so that we can be centered
+ padding: 0 !important;
}
.mx_EventTile_msgOption {
@@ -168,6 +159,7 @@ $left-gutter: 64px;
.mx_EventTile.focus-visible:focus-within > div > a > .mx_MessageTimestamp,
.mx_IRCLayout .mx_EventTile_last > a > .mx_MessageTimestamp,
.mx_IRCLayout .mx_EventTile:hover > a > .mx_MessageTimestamp,
+.mx_IRCLayout .mx_ReplyThread .mx_EventTile > a > .mx_MessageTimestamp,
.mx_IRCLayout .mx_EventTile.mx_EventTile_actionBarFocused > a > .mx_MessageTimestamp,
.mx_IRCLayout .mx_EventTile.focus-visible:focus-within > a > .mx_MessageTimestamp {
visibility: visible;
@@ -222,21 +214,30 @@ $left-gutter: 64px;
color: $accent-fg-color;
}
-.mx_EventTile_encrypting {
- color: $event-encrypting-color !important;
-}
+.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
-.mx_EventTile_sending {
- color: $event-sending-color;
+ &::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_sending .mx_UserPill,
-.mx_EventTile_sending .mx_RoomPill {
- opacity: 0.5;
+.mx_EventTile_receiptSent::before {
+ mask-image: url('$(res)/img/element-icons/circle-sent.svg');
}
-
-.mx_EventTile_notSent {
- color: $event-notsent-color;
+.mx_EventTile_receiptSending::before {
+ mask-image: url('$(res)/img/element-icons/circle-sending.svg');
}
.mx_EventTile_contextual {
@@ -266,22 +267,22 @@ $left-gutter: 64px;
display: inline-block;
width: 14px;
height: 14px;
- top: 29px;
+ // This aligns the avatar with the last line of the
+ // message. We want to move it one line up - 2.2rem
+ top: -2.2rem;
user-select: none;
z-index: 1;
}
-.mx_EventTile_continuation .mx_EventTile_readAvatars,
-.mx_EventTile_info .mx_EventTile_readAvatars,
-.mx_EventTile_emote .mx_EventTile_readAvatars {
- top: 7px;
-}
-
.mx_EventTile_readAvatars .mx_BaseAvatar {
position: absolute;
display: inline-block;
height: $font-14px;
width: $font-14px;
+
+ transition:
+ left var(--transition-short) ease-out,
+ top var(--transition-standard) ease-out;
}
.mx_EventTile_readAvatarRemainder {
@@ -394,16 +395,6 @@ $left-gutter: 64px;
opacity: 1;
}
-.mx_EventTile_e2eIcon_hidden {
- display: none;
-}
-
-/* always override hidden attribute for blocked and warning */
-.mx_EventTile_e2eIcon_hidden[src*="img/e2e-blocked.svg"],
-.mx_EventTile_e2eIcon_hidden[src*="img/e2e-warning.svg"] {
- display: block;
-}
-
.mx_EventTile_keyRequestInfo {
font-size: $font-12px;
}
@@ -439,15 +430,15 @@ $left-gutter: 64px;
}
.mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line {
- border-left: $e2e-verified-color 4px solid;
+ 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 4px solid;
+ 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 4px solid;
+ border-left: $e2e-unknown-color $EventTile_e2e_state_indicator_width solid;
}
.mx_EventTile:hover.mx_EventTile_verified.mx_EventTile_info .mx_EventTile_line,
@@ -465,8 +456,7 @@ $left-gutter: 64px;
.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: 3px;
- width: auto;
+ width: $MessageTimestamp_width_hover;
}
// Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies)
@@ -511,7 +501,6 @@ $left-gutter: 64px;
// https://github.com/vector-im/vector-web/issues/754
overflow-x: overlay;
overflow-y: visible;
- max-height: 30vh;
}
code {
@@ -520,6 +509,22 @@ $left-gutter: 64px;
}
}
+.mx_EventTile_lineNumbers {
+ float: left;
+ margin: 0 0.5em 0 -1.5em;
+ color: gray;
+}
+
+.mx_EventTile_lineNumber {
+ text-align: right;
+ display: block;
+ padding-left: 1em;
+}
+
+.mx_EventTile_collapsedCodeBlock {
+ max-height: 30vh;
+}
+
.mx_EventTile:hover .mx_EventTile_body pre,
.mx_EventTile.focus-visible:focus-within .mx_EventTile_body pre {
border: 1px solid #e5e5e5; // deliberate constant as we're behind an invert filter
@@ -531,20 +536,42 @@ $left-gutter: 64px;
}
// Inserted adjacent to
blocks, (See TextualBody)
-.mx_EventTile_copyButton {
+.mx_EventTile_button {
position: absolute;
display: inline-block;
visibility: hidden;
cursor: pointer;
top: 8px;
- right: 6px;
+ right: 8px;
width: 19px;
height: 19px;
- background-image: url($copy-button-url);
+ background-color: $message-action-bar-fg-color;
+}
+.mx_EventTile_buttonBottom {
+ top: 33px;
+}
+.mx_EventTile_copyButton {
+ mask-image: url($copy-button-url);
+}
+.mx_EventTile_collapseButton {
+ mask-size: 75%;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-image: url($collapse-button-url);
+}
+.mx_EventTile_expandButton {
+ mask-size: 75%;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-image: url($expand-button-url);
}
.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_copyButton,
-.mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_copyButton {
+.mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_copyButton,
+.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_collapseButton,
+.mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_collapseButton,
+.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_expandButton,
+.mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_expandButton {
visibility: visible;
}
diff --git a/res/css/views/rooms/_GroupLayout.scss b/res/css/views/rooms/_GroupLayout.scss
index 2b447be44a..818509785b 100644
--- a/res/css/views/rooms/_GroupLayout.scss
+++ b/res/css/views/rooms/_GroupLayout.scss
@@ -20,8 +20,8 @@ $left-gutter: 64px;
.mx_GroupLayout {
.mx_EventTile {
> .mx_SenderProfile {
- line-height: $font-17px;
- padding-left: $left-gutter;
+ line-height: $font-20px;
+ margin-left: $left-gutter;
}
> .mx_EventTile_line {
@@ -34,11 +34,11 @@ $left-gutter: 64px;
.mx_MessageTimestamp {
position: absolute;
- width: 46px; /* 8 + 30 (avatar) + 8 */
+ width: $MessageTimestamp_width;
}
.mx_EventTile_line, .mx_EventTile_reply {
- padding-top: 3px;
+ padding-top: 1px;
padding-bottom: 3px;
line-height: $font-22px;
}
@@ -105,16 +105,9 @@ $left-gutter: 64px;
}
.mx_EventTile_readAvatars {
- top: 27px;
- }
-
- &.mx_EventTile_continuation .mx_EventTile_readAvatars,
- &.mx_EventTile_emote .mx_EventTile_readAvatars {
- top: 5px;
- }
-
- &.mx_EventTile_info .mx_EventTile_readAvatars {
- top: 4px;
+ // This aligns the avatar with the last line of the
+ // message. We want to move it one line up - 2rem
+ top: -2rem;
}
.mx_EventTile_content .markdown-body {
diff --git a/res/css/views/rooms/_IRCLayout.scss b/res/css/views/rooms/_IRCLayout.scss
index ed60c220e7..b6b901757c 100644
--- a/res/css/views/rooms/_IRCLayout.scss
+++ b/res/css/views/rooms/_IRCLayout.scss
@@ -54,7 +54,7 @@ $irc-line-height: $font-18px;
flex-shrink: 0;
width: var(--name-width);
text-overflow: ellipsis;
- text-align: right;
+ text-align: left;
display: flex;
align-items: center;
overflow: visible;
@@ -181,11 +181,11 @@ $irc-line-height: $font-18px;
> span {
display: flex;
- > .mx_SenderProfile_name,
- > .mx_SenderProfile_aux {
+ > .mx_SenderProfile_name {
overflow: hidden;
text-overflow: ellipsis;
min-width: var(--name-width);
+ text-align: end;
}
}
}
@@ -206,6 +206,35 @@ $irc-line-height: $font-18px;
width: unset;
max-width: var(--name-width);
}
+
+ .mx_SenderProfile_hover {
+ background: transparent;
+
+ > span {
+ > .mx_SenderProfile_name {
+ min-width: inherit;
+ }
+ }
+ }
+
+ .mx_EventTile_emote {
+ > .mx_EventTile_avatar {
+ margin-left: initial;
+ }
+ }
+
+ .mx_MessageTimestamp {
+ width: initial;
+ }
+
+ /**
+ * adding the icon back in the document flow
+ * if it's not present, there's no unwanted wasted space
+ */
+ .mx_EventTile_e2eIcon {
+ position: relative;
+ order: -1;
+ }
}
.mx_ProfileResizer {
diff --git a/res/css/views/rooms/_MemberInfo.scss b/res/css/views/rooms/_MemberInfo.scss
index fb082843f1..3f7f83d334 100644
--- a/res/css/views/rooms/_MemberInfo.scss
+++ b/res/css/views/rooms/_MemberInfo.scss
@@ -19,6 +19,7 @@ limitations under the License.
flex-direction: column;
flex: 1;
overflow-y: auto;
+ margin-top: 8px;
}
.mx_MemberInfo_name {
@@ -70,7 +71,7 @@ limitations under the License.
}
.mx_MemberInfo_avatar {
- background: $tagpanel-bg-color;
+ background: $groupFilterPanel-bg-color;
margin-bottom: 16px;
}
diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss
index 90667d41b4..075e9ff585 100644
--- a/res/css/views/rooms/_MemberList.scss
+++ b/res/css/views/rooms/_MemberList.scss
@@ -44,6 +44,17 @@ limitations under the License.
.mx_AutoHideScrollbar {
flex: 1 1 0;
}
+
+ .mx_RightPanel_scopeHeader {
+ // vertically align with position on other right panel cards
+ // to prevent it bouncing as user navigates right panel
+ margin-top: -8px;
+ }
+}
+
+.mx_GroupMemberList_query,
+.mx_GroupRoomList_query {
+ flex: 0 0 auto;
}
.mx_MemberList_chevron {
@@ -59,10 +70,8 @@ limitations under the License.
flex: 1 1 0px;
}
-.mx_MemberList_query,
-.mx_GroupMemberList_query,
-.mx_GroupRoomList_query {
- flex: 1 1 0;
+.mx_MemberList_query {
+ height: 16px;
// stricter rule to override the one in _common.scss
&[type="text"] {
@@ -92,17 +101,27 @@ limitations under the License.
}
.mx_MemberList_invite span {
- background-image: url('$(res)/img/element-icons/room/invite.svg');
- background-repeat: no-repeat;
- background-position: center left;
- background-size: 20px;
- padding: 8px 0 8px 25px;
+ padding: 8px 0;
+ display: inline-flex;
+
+ &::before {
+ content: '';
+ display: inline-block;
+ background-color: $button-fg-color;
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: 20px;
+ width: 20px;
+ height: 20px;
+ margin-right: 5px;
+ }
}
-.mx_MemberList_inviteCommunity span {
- background-image: url('$(res)/img/icon-invite-people.svg');
+.mx_MemberList_inviteCommunity span::before {
+ mask-image: url('$(res)/img/icon-invite-people.svg');
}
-.mx_MemberList_addRoomToCommunity span {
- background-image: url('$(res)/img/icons-room-add.svg');
+.mx_MemberList_addRoomToCommunity span::before {
+ mask-image: url('$(res)/img/icons-room-add.svg');
}
diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss
index ec95403262..e6c0cc3f46 100644
--- a/res/css/views/rooms/_MessageComposer.scss
+++ b/res/css/views/rooms/_MessageComposer.scss
@@ -21,6 +21,7 @@ limitations under the License.
border-top: 1px solid $primary-hairline-color;
position: relative;
padding-left: 82px;
+ padding-right: 6px;
}
.mx_MessageComposer_replaced_wrapper {
@@ -178,26 +179,45 @@ limitations under the License.
color: $accent-color;
}
+.mx_MessageComposer_button_highlight {
+ background: rgba($accent-color, 0.25);
+ // make the icon the accent color too
+ &::before {
+ background-color: $accent-color !important;
+ }
+}
+
.mx_MessageComposer_button {
position: relative;
- margin-right: 12px;
+ margin-right: 6px;
cursor: pointer;
- height: 20px;
- width: 20px;
+ height: 26px;
+ width: 26px;
+ border-radius: 100%;
&::before {
content: '';
position: absolute;
+ top: 3px;
+ left: 3px;
height: 20px;
width: 20px;
- background-color: $composer-button-color;
+ background-color: $icon-button-color;
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
}
- &.mx_MessageComposer_hangup::before {
+ &:hover {
+ background: rgba($accent-color, 0.1);
+
+ &::before {
+ background-color: $accent-color;
+ }
+ }
+
+ &.mx_MessageComposer_hangup:not(.mx_AccessibleButton_disabled)::before {
background-color: $warning-color;
}
}
@@ -207,16 +227,8 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/room/composer/attach.svg');
}
-.mx_MessageComposer_hangup::before {
- mask-image: url('$(res)/img/element-icons/call/hangup.svg');
-}
-
-.mx_MessageComposer_voicecall::before {
- mask-image: url('$(res)/img/element-icons/call/voice-call.svg');
-}
-
-.mx_MessageComposer_videocall::before {
- mask-image: url('$(res)/img/element-icons/call/video-call.svg');
+.mx_MessageComposer_voiceMessage::before {
+ mask-image: url('$(res)/img/voip/mic-on-mask.svg');
}
.mx_MessageComposer_emoji::before {
@@ -227,6 +239,32 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/room/composer/sticker.svg');
}
+.mx_MessageComposer_sendMessage {
+ cursor: pointer;
+ position: relative;
+ margin-right: 6px;
+ width: 32px;
+ height: 32px;
+ border-radius: 100%;
+ background-color: $button-bg-color;
+
+ &::before {
+ position: absolute;
+ height: 16px;
+ width: 16px;
+ top: 8px;
+ left: 9px;
+
+ mask-image: url('$(res)/img/element-icons/send-message.svg');
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ mask-position: center;
+
+ background-color: $button-fg-color;
+ content: '';
+ }
+}
+
.mx_MessageComposer_formatting {
cursor: pointer;
margin: 0 11px;
@@ -288,7 +326,7 @@ limitations under the License.
mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
- background-color: $composer-button-color;
+ background-color: $icon-button-color;
&.mx_MessageComposer_markdownDisabled {
opacity: 0.2;
diff --git a/res/css/views/rooms/_MessageComposerFormatBar.scss b/res/css/views/rooms/_MessageComposerFormatBar.scss
index d97c49630a..b305e91db0 100644
--- a/res/css/views/rooms/_MessageComposerFormatBar.scss
+++ b/res/css/views/rooms/_MessageComposerFormatBar.scss
@@ -60,6 +60,8 @@ limitations under the License.
width: 27px;
height: 24px;
box-sizing: border-box;
+ background: none;
+ vertical-align: middle;
}
.mx_MessageComposerFormatBar_button::after {
diff --git a/res/css/views/rooms/_NewRoomIntro.scss b/res/css/views/rooms/_NewRoomIntro.scss
new file mode 100644
index 0000000000..9c2a428cb3
--- /dev/null
+++ b/res/css/views/rooms/_NewRoomIntro.scss
@@ -0,0 +1,72 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_NewRoomIntro {
+ margin: 40px 0 48px 64px;
+
+ .mx_MiniAvatarUploader_hasAvatar:not(.mx_MiniAvatarUploader_busy):not(:hover) {
+ &::before, &::after {
+ content: unset;
+ }
+ }
+
+ .mx_AccessibleButton_kind_link {
+ padding: 0;
+ font-size: inherit;
+ }
+
+ .mx_NewRoomIntro_buttons {
+ margin-top: 28px;
+
+ .mx_AccessibleButton {
+ line-height: $font-24px;
+ display: inline-block;
+
+ & + .mx_AccessibleButton {
+ margin-left: 12px;
+ }
+
+ &:not(.mx_AccessibleButton_kind_primary_outline)::before {
+ content: '';
+ display: inline-block;
+ background-color: $button-fg-color;
+ mask-position: center;
+ mask-repeat: no-repeat;
+ mask-size: 20px;
+ width: 20px;
+ height: 20px;
+ margin-right: 5px;
+ vertical-align: text-bottom;
+ }
+ }
+
+ .mx_NewRoomIntro_inviteButton::before {
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ }
+ }
+
+ > h2 {
+ margin-top: 24px;
+ font-size: $font-24px;
+ font-weight: 600;
+ }
+
+ > p {
+ margin: 0;
+ font-size: $font-15px;
+ color: $secondary-fg-color;
+ }
+}
diff --git a/res/css/views/rooms/_ReplyPreview.scss b/res/css/views/rooms/_ReplyPreview.scss
index 9feb337042..10f8e21e43 100644
--- a/res/css/views/rooms/_ReplyPreview.scss
+++ b/res/css/views/rooms/_ReplyPreview.scss
@@ -15,10 +15,6 @@ limitations under the License.
*/
.mx_ReplyPreview {
- position: absolute;
- bottom: 0;
- z-index: 1000;
- width: 100%;
border: 1px solid $primary-hairline-color;
background: $primary-bg-color;
border-bottom: none;
diff --git a/res/css/views/rooms/_RoomHeader.scss b/res/css/views/rooms/_RoomHeader.scss
index ba46100ea6..387d1588a3 100644
--- a/res/css/views/rooms/_RoomHeader.scss
+++ b/res/css/views/rooms/_RoomHeader.scss
@@ -222,7 +222,7 @@ limitations under the License.
left: 4px; // center with parent of 32px
height: 24px;
width: 24px;
- background-color: $roomheader-button-color;
+ background-color: $icon-button-color;
mask-repeat: no-repeat;
mask-size: contain;
}
@@ -236,25 +236,33 @@ limitations under the License.
}
}
-.mx_RoomHeader_settingsButton::before {
- mask-image: url('$(res)/img/element-icons/settings.svg');
-}
-
.mx_RoomHeader_forgetButton::before {
mask-image: url('$(res)/img/element-icons/leave.svg');
width: 26px;
}
+.mx_RoomHeader_appsButton::before {
+ mask-image: url('$(res)/img/element-icons/room/apps.svg');
+}
+.mx_RoomHeader_appsButton_highlight::before {
+ background-color: $accent-color;
+}
+
.mx_RoomHeader_searchButton::before {
mask-image: url('$(res)/img/element-icons/room/search-inset.svg');
}
-.mx_RoomHeader_shareButton::before {
- mask-image: url('$(res)/img/element-icons/room/share.svg');
+.mx_RoomHeader_voiceCallButton::before {
+ mask-image: url('$(res)/img/element-icons/call/voice-call.svg');
+
+ // The call button SVG is padded slightly differently, so match it up to the size
+ // of the other icons
+ mask-size: 20px;
+ mask-position: center;
}
-.mx_RoomHeader_manageIntegsButton::before {
- mask-image: url('$(res)/img/element-icons/room/integrations.svg');
+.mx_RoomHeader_videoCallButton::before {
+ mask-image: url('$(res)/img/element-icons/call/video-call.svg');
}
.mx_RoomHeader_showPanel {
diff --git a/res/css/views/rooms/_RoomList.scss b/res/css/views/rooms/_RoomList.scss
index 89ab85e146..8eda25d0c9 100644
--- a/res/css/views/rooms/_RoomList.scss
+++ b/res/css/views/rooms/_RoomList.scss
@@ -17,3 +17,73 @@ limitations under the License.
.mx_RoomList {
padding-right: 7px; // width of the scrollbar, to line things up
}
+
+.mx_RoomList_iconPlus::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/plus-circle.svg');
+}
+.mx_RoomList_iconHash::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/hash-circle.svg');
+}
+.mx_RoomList_iconExplore::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
+}
+.mx_RoomList_iconBrowse::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/browse.svg');
+}
+.mx_RoomList_iconDialpad::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/dialpad.svg');
+}
+
+.mx_RoomList_explorePrompt {
+ margin: 4px 12px 4px;
+ padding-top: 12px;
+ border-top: 1px solid $input-border-color;
+ font-size: $font-14px;
+
+ div:first-child {
+ font-weight: $font-semi-bold;
+ line-height: $font-18px;
+ color: $primary-fg-color;
+ }
+
+ .mx_AccessibleButton {
+ color: $primary-fg-color;
+ position: relative;
+ padding: 8px 8px 8px 32px;
+ font-size: inherit;
+ margin-top: 12px;
+ display: block;
+ text-align: start;
+ background-color: $roomlist-button-bg-color;
+ border-radius: 4px;
+
+ &::before {
+ content: '';
+ width: 16px;
+ height: 16px;
+ position: absolute;
+ top: 8px;
+ left: 8px;
+ background: $secondary-fg-color;
+ mask-position: center;
+ mask-size: contain;
+ mask-repeat: no-repeat;
+ }
+
+ &.mx_RoomList_explorePrompt_startChat::before {
+ mask-image: url('$(res)/img/element-icons/feedback.svg');
+ }
+
+ &.mx_RoomList_explorePrompt_explore::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
+ }
+
+ &.mx_RoomList_explorePrompt_spaceInvite::before {
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ }
+
+ &.mx_RoomList_explorePrompt_spaceExplore::before {
+ mask-image: url('$(res)/img/element-icons/roomlist/browse.svg');
+ }
+ }
+}
diff --git a/res/css/views/rooms/_RoomSublist.scss b/res/css/views/rooms/_RoomSublist.scss
index fe80dfca22..1aafa8da0e 100644
--- a/res/css/views/rooms/_RoomSublist.scss
+++ b/res/css/views/rooms/_RoomSublist.scss
@@ -18,6 +18,10 @@ limitations under the License.
margin-left: 8px;
margin-bottom: 4px;
+ &.mx_RoomSublist_hidden {
+ display: none;
+ }
+
.mx_RoomSublist_headerContainer {
// Create a flexbox to make alignment easy
display: flex;
@@ -37,7 +41,9 @@ limitations under the License.
// The combined height must be set in the LeftPanel component for sticky headers
// to work correctly.
padding-bottom: 8px;
- height: 24px;
+ // Allow the container to collapse on itself if its children
+ // are not in the normal document flow
+ max-height: 24px;
color: $roomlist-header-color;
.mx_RoomSublist_stickable {
@@ -59,10 +65,6 @@ limitations under the License.
width: calc(100% - 22px);
}
- &.mx_RoomSublist_headerContainer_stickyBottom {
- bottom: 0;
- }
-
// We don't have a top style because the top is dependent on the room list header's
// height, and is therefore calculated in JS.
// The class, mx_RoomSublist_headerContainer_stickyTop, is applied though.
@@ -96,7 +98,7 @@ limitations under the License.
position: relative;
width: 24px;
height: 24px;
- border-radius: 32px;
+ border-radius: 8px;
&::before {
content: '';
@@ -112,6 +114,11 @@ limitations under the License.
}
}
+ .mx_RoomSublist_auxButton:hover,
+ .mx_RoomSublist_menuButton:hover {
+ background: $roomlist-button-bg-color;
+ }
+
// Hide the menu button by default
.mx_RoomSublist_menuButton {
visibility: hidden;
@@ -120,7 +127,7 @@ limitations under the License.
}
.mx_RoomSublist_auxButton::before {
- mask-image: url('$(res)/img/feather-customised/plus.svg');
+ mask-image: url('$(res)/img/element-icons/roomlist/plus.svg');
}
.mx_RoomSublist_menuButton::before {
@@ -201,6 +208,9 @@ limitations under the License.
.mx_RoomSublist_resizerHandles {
flex: 0 0 4px;
+ display: flex;
+ justify-content: center;
+ width: 100%;
}
// Class name comes from the ResizableBox component
@@ -211,17 +221,12 @@ limitations under the License.
border-radius: 3px;
// Override styles from library
- width: unset !important;
+ max-width: 64px;
height: 4px !important; // Update RESIZE_HANDLE_HEIGHT if this changes
// This is positioned directly below the 'show more' button.
- position: absolute;
+ position: relative !important;
bottom: 0 !important; // override from library
-
- // Together, these make the bar 64px wide
- // These are also overridden from the library
- left: calc(50% - 32px) !important;
- right: calc(50% - 32px) !important;
}
&:hover, &.mx_RoomSublist_hasMenuOpen {
@@ -387,3 +392,22 @@ limitations under the License.
.mx_RoomSublist_addRoomTooltip {
margin-top: -3px;
}
+
+.mx_RoomSublist_skeletonUI {
+ position: relative;
+ margin-left: 4px;
+ height: 288px;
+
+ &::before {
+ background: $roomsublist-skeleton-ui-bg;
+
+ width: 100%;
+ height: 100%;
+
+ content: '';
+ position: absolute;
+ mask-repeat: repeat-y;
+ mask-size: auto 48px;
+ mask-image: url('$(res)/img/element-icons/roomlist/skeleton-ui.svg');
+ }
+}
diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss
index 8eca3f1efa..72d29dfd4c 100644
--- a/res/css/views/rooms/_RoomTile.scss
+++ b/res/css/views/rooms/_RoomTile.scss
@@ -189,6 +189,10 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/settings.svg');
}
+ .mx_RoomTile_iconInvite::before {
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ }
+
.mx_RoomTile_iconSignOut::before {
mask-image: url('$(res)/img/element-icons/leave.svg');
}
diff --git a/res/css/views/rooms/_RoomTileIcon.scss b/res/css/views/rooms/_RoomTileIcon.scss
deleted file mode 100644
index 2f3afdd446..0000000000
--- a/res/css/views/rooms/_RoomTileIcon.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-Copyright 2020 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-.mx_RoomTileIcon {
- width: 12px;
- height: 12px;
- border-radius: 12px;
- background-color: $roomlist-bg-color; // to match the room list itself
-}
-
-.mx_RoomTileIcon_globe::before {
- content: '';
- width: 8px;
- height: 8px;
- top: 2px;
- left: 2px;
- position: absolute;
- mask-position: center;
- mask-size: contain;
- mask-repeat: no-repeat;
- background: $primary-fg-color;
- mask-image: url('$(res)/img/globe.svg');
-}
-
-.mx_RoomTileIcon_offline::before {
- content: '';
- width: 8px;
- height: 8px;
- top: 2px;
- left: 2px;
- position: absolute;
- border-radius: 8px;
- background-color: $presence-offline;
-}
-
-.mx_RoomTileIcon_online::before {
- content: '';
- width: 8px;
- height: 8px;
- top: 2px;
- left: 2px;
- position: absolute;
- border-radius: 8px;
- background-color: $presence-online;
-}
-
-.mx_RoomTileIcon_away::before {
- content: '';
- width: 8px;
- height: 8px;
- top: 2px;
- left: 2px;
- position: absolute;
- border-radius: 8px;
- background-color: $presence-away;
-}
diff --git a/res/css/views/rooms/_SearchBar.scss b/res/css/views/rooms/_SearchBar.scss
index fecc8d78d8..d9f730a8b6 100644
--- a/res/css/views/rooms/_SearchBar.scss
+++ b/res/css/views/rooms/_SearchBar.scss
@@ -68,3 +68,4 @@ limitations under the License.
cursor: pointer;
}
}
+
diff --git a/res/css/views/rooms/_SendMessageComposer.scss b/res/css/views/rooms/_SendMessageComposer.scss
index 0b646666e7..9f6a8d52ce 100644
--- a/res/css/views/rooms/_SendMessageComposer.scss
+++ b/res/css/views/rooms/_SendMessageComposer.scss
@@ -44,10 +44,5 @@ limitations under the License.
overflow-y: auto;
}
}
-
- .mx_SendMessageComposer_overlayWrapper {
- position: relative;
- height: 0;
- }
}
diff --git a/res/css/views/rooms/_Stickers.scss b/res/css/views/rooms/_Stickers.scss
index 4bd45631cc..da86797f42 100644
--- a/res/css/views/rooms/_Stickers.scss
+++ b/res/css/views/rooms/_Stickers.scss
@@ -7,12 +7,23 @@
height: 300px;
}
-#mx_persistedElement_stickerPicker .mx_AppTileFullWidth {
- height: unset;
- box-sizing: border-box;
- border-left: none;
- border-right: none;
- border-bottom: none;
+#mx_persistedElement_stickerPicker {
+ .mx_AppTileFullWidth {
+ height: unset;
+ box-sizing: border-box;
+ border-left: none;
+ border-right: none;
+ border-bottom: none;
+ }
+
+ .mx_AppTileMenuBar {
+ padding: 0;
+ }
+
+ iframe {
+ // Sticker picker depends on the fixed height previously used for all tiles
+ height: 283px; // height of the popout minus the AppTile menu bar
+ }
}
.mx_Stickers_contentPlaceholder {
diff --git a/res/css/views/rooms/_VoiceRecordComposerTile.scss b/res/css/views/rooms/_VoiceRecordComposerTile.scss
new file mode 100644
index 0000000000..a3ee104bd8
--- /dev/null
+++ b/res/css/views/rooms/_VoiceRecordComposerTile.scss
@@ -0,0 +1,98 @@
+/*
+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_VoiceRecordComposerTile_stop {
+ // 28px plus a 2px border makes this a 32px square (as intended)
+ width: 28px;
+ height: 28px;
+ border: 2px solid $voice-record-stop-border-color;
+ border-radius: 32px;
+ margin-right: 16px; // between us and the send button
+ position: relative;
+
+ &::after {
+ content: '';
+ width: 14px;
+ height: 14px;
+ position: absolute;
+ top: 7px;
+ left: 7px;
+ border-radius: 2px;
+ background-color: $voice-record-stop-symbol-color;
+ }
+}
+
+.mx_VoiceRecordComposerTile_delete {
+ width: 14px; // w&h are size of icon
+ height: 18px;
+ vertical-align: middle;
+ margin-right: 11px; // distance from left edge of waveform container (container has some margin too)
+ background-color: $voice-record-icon-color;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ mask-image: url('$(res)/img/element-icons/trashcan.svg');
+}
+
+.mx_MessageComposer_row .mx_VoiceMessagePrimaryContainer {
+ // Note: remaining class properties are in the PlayerContainer CSS.
+
+ margin: 6px; // force the composer area to put a gutter around us
+ margin-right: 12px; // isolate from stop/send button
+
+ position: relative; // important for the live circle
+
+ &.mx_VoiceRecordComposerTile_recording {
+ // We are putting the circle in this padding, so we need +10px from the regular
+ // padding on the left side.
+ padding-left: 22px;
+
+ &::before {
+ animation: recording-pulse 2s infinite;
+
+ content: '';
+ background-color: $voice-record-live-circle-color;
+ width: 10px;
+ height: 10px;
+ position: absolute;
+ left: 12px; // 12px from the left edge for container padding
+ top: 18px; // vertically center (middle align with clock)
+ border-radius: 10px;
+ }
+ }
+}
+
+// The keyframes are slightly weird here to help make a ramping/punch effect
+// for the recording dot. We start and end at 100% opacity to help make the
+// dot feel a bit like a real lamp that is blinking: the animation ends up
+// spending a lot of its time showing a steady state without a fade effect.
+// This lamp effect extends into why the 0% opacity keyframe is not in the
+// midpoint: lamps take longer to turn off than they do to turn on, and the
+// extra frames give it a bit of a realistic punch for when the animation is
+// ramping back up to 100% opacity.
+//
+// Target animation timings: steady for 1.5s, fade out for 0.3s, fade in for 0.2s
+// (intended to be used in a loop for 2s animation speed)
+@keyframes recording-pulse {
+ 0% {
+ opacity: 1;
+ }
+ 35% {
+ opacity: 0;
+ }
+ 65% {
+ opacity: 1;
+ }
+}
diff --git a/res/css/views/settings/_AvatarSetting.scss b/res/css/views/settings/_AvatarSetting.scss
index eddcf9f55a..a350605ab1 100644
--- a/res/css/views/settings/_AvatarSetting.scss
+++ b/res/css/views/settings/_AvatarSetting.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2019 The Matrix.org Foundation C.I.C.
+Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,13 +15,56 @@ limitations under the License.
*/
.mx_AvatarSetting_avatar {
- width: $font-88px;
- height: $font-88px;
- margin-left: 13px;
+ width: 90px;
+ min-width: 90px; // so it doesn't get crushed by the flexbox in languages with longer words
+ height: 90px;
+ margin-top: 8px;
position: relative;
+ .mx_AvatarSetting_hover {
+ transition: opacity $hover-transition;
+
+ // position to place the hover bg over the entire thing
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+
+ pointer-events: none; // let the pointer fall through the underlying thing
+
+ line-height: 90px;
+ text-align: center;
+
+ > span {
+ color: #fff; // hardcoded to contrast with background
+ position: relative; // tricks the layout engine into putting this on top of the bg
+ font-weight: 500;
+ }
+
+ .mx_AvatarSetting_hoverBg {
+ // absolute position to lazily fill the entire container
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+
+ opacity: 0.5;
+ background-color: $settings-profile-overlay-placeholder-fg-color;
+ border-radius: 90px;
+ }
+ }
+
+ &.mx_AvatarSetting_avatar_hovering .mx_AvatarSetting_hover {
+ opacity: 1;
+ }
+
+ &:not(.mx_AvatarSetting_avatar_hovering) .mx_AvatarSetting_hover {
+ opacity: 0;
+ }
+
& > * {
- width: $font-88px;
box-sizing: border-box;
}
@@ -30,7 +73,7 @@ limitations under the License.
}
.mx_AccessibleButton.mx_AccessibleButton_kind_link_sm {
- color: $button-danger-bg-color;
+ width: 100%;
}
& > img {
@@ -41,8 +84,10 @@ limitations under the License.
& > img,
.mx_AvatarSetting_avatarPlaceholder {
display: block;
- height: $font-88px;
- border-radius: 4px;
+ height: 90px;
+ width: inherit;
+ border-radius: 90px;
+ cursor: pointer;
}
.mx_AvatarSetting_avatarPlaceholder::before {
@@ -58,6 +103,29 @@ limitations under the License.
left: 0;
right: 0;
}
+
+ .mx_AvatarSetting_uploadButton {
+ width: 32px;
+ height: 32px;
+ border-radius: 32px;
+ background-color: $settings-profile-button-bg-color;
+
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ }
+
+ .mx_AvatarSetting_uploadButton::before {
+ content: "";
+ display: block;
+ width: 100%;
+ height: 100%;
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: 55%;
+ background-color: $settings-profile-button-fg-color;
+ mask-image: url('$(res)/img/feather-customised/edit.svg');
+ }
}
.mx_AvatarSetting_avatar .mx_AvatarSetting_avatarPlaceholder {
diff --git a/res/css/views/settings/_CrossSigningPanel.scss b/res/css/views/settings/_CrossSigningPanel.scss
index fa9f76a963..12a0e36835 100644
--- a/res/css/views/settings/_CrossSigningPanel.scss
+++ b/res/css/views/settings/_CrossSigningPanel.scss
@@ -28,4 +28,8 @@ limitations under the License.
.mx_CrossSigningPanel_buttonRow {
margin: 1em 0;
+
+ :nth-child(n + 1) {
+ margin-inline-end: 10px;
+ }
}
diff --git a/res/css/views/settings/_Notifications.scss b/res/css/views/settings/_Notifications.scss
index e6d09b9a2a..77a7bc5b68 100644
--- a/res/css/views/settings/_Notifications.scss
+++ b/res/css/views/settings/_Notifications.scss
@@ -64,6 +64,7 @@ limitations under the License.
.mx_UserNotifSettings_notifTable {
display: table;
+ position: relative;
}
.mx_UserNotifSettings_notifTable .mx_Spinner {
diff --git a/res/css/views/settings/_ProfileSettings.scss b/res/css/views/settings/_ProfileSettings.scss
index 58624d1597..4cbcb8e708 100644
--- a/res/css/views/settings/_ProfileSettings.scss
+++ b/res/css/views/settings/_ProfileSettings.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2019 New Vector Ltd
+Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,12 +14,25 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+.mx_ProfileSettings_controls_topic {
+ & > textarea {
+ resize: vertical;
+ }
+}
+
.mx_ProfileSettings_profile {
display: flex;
}
.mx_ProfileSettings_controls {
flex-grow: 1;
+ margin-right: 54px;
+
+ // We put the header under the controls with some minor styling to cheat
+ // alignment of the field with the avatar
+ .mx_SettingsTab_subheading {
+ margin-top: 0;
+ }
}
.mx_ProfileSettings_controls .mx_Field #profileTopic {
@@ -41,3 +54,17 @@ limitations under the License.
.mx_ProfileSettings_avatarUpload {
display: none;
}
+
+.mx_ProfileSettings_profileForm {
+ @mixin mx_Settings_fullWidthField;
+ border-bottom: 1px solid $menu-border-color;
+}
+
+.mx_ProfileSettings_buttons {
+ margin-top: 10px; // 18px is already accounted for by the
above the buttons
+ margin-bottom: 28px;
+
+ > .mx_AccessibleButton_kind_link {
+ padding-left: 0; // to align with left side
+ }
+}
diff --git a/res/css/views/settings/_KeyBackupPanel.scss b/res/css/views/settings/_SecureBackupPanel.scss
similarity index 52%
rename from res/css/views/settings/_KeyBackupPanel.scss
rename to res/css/views/settings/_SecureBackupPanel.scss
index 872162caad..a9dab06b57 100644
--- a/res/css/views/settings/_KeyBackupPanel.scss
+++ b/res/css/views/settings/_SecureBackupPanel.scss
@@ -1,6 +1,6 @@
/*
Copyright 2018 New Vector Ltd
-Copyright 2019 The Matrix.org Foundation C.I.C.
+Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,23 +15,39 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_KeyBackupPanel_sigValid, .mx_KeyBackupPanel_sigInvalid,
-.mx_KeyBackupPanel_deviceVerified, .mx_KeyBackupPanel_deviceNotVerified {
+.mx_SecureBackupPanel_sigValid, .mx_SecureBackupPanel_sigInvalid,
+.mx_SecureBackupPanel_deviceVerified, .mx_SecureBackupPanel_deviceNotVerified {
font-weight: bold;
}
-.mx_KeyBackupPanel_sigValid, .mx_KeyBackupPanel_deviceVerified {
+.mx_SecureBackupPanel_sigValid, .mx_SecureBackupPanel_deviceVerified {
color: $e2e-verified-color;
}
-.mx_KeyBackupPanel_sigInvalid, .mx_KeyBackupPanel_deviceNotVerified {
+.mx_SecureBackupPanel_sigInvalid, .mx_SecureBackupPanel_deviceNotVerified {
color: $e2e-warning-color;
}
-.mx_KeyBackupPanel_deviceName {
+.mx_SecureBackupPanel_deviceName {
font-style: italic;
}
-.mx_KeyBackupPanel_buttonRow {
+.mx_SecureBackupPanel_buttonRow {
margin: 1em 0;
+
+ :nth-child(n + 1) {
+ margin-inline-end: 10px;
+ }
+}
+
+.mx_SecureBackupPanel_statusList {
+ border-spacing: 0;
+
+ td {
+ padding: 0;
+
+ &:first-of-type {
+ padding-inline-end: 1em;
+ }
+ }
}
diff --git a/res/css/views/rooms/_RoomRecoveryReminder.scss b/res/css/views/settings/_SpellCheckLanguages.scss
similarity index 59%
rename from res/css/views/rooms/_RoomRecoveryReminder.scss
rename to res/css/views/settings/_SpellCheckLanguages.scss
index 09b28ae235..bb322c983f 100644
--- a/res/css/views/rooms/_RoomRecoveryReminder.scss
+++ b/res/css/views/settings/_SpellCheckLanguages.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2018 New Vector Ltd
+Copyright 2021 Šimon Brandner
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,26 +14,22 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_RoomRecoveryReminder {
+.mx_ExistingSpellCheckLanguage {
display: flex;
- flex-direction: column;
- text-align: center;
- background-color: $room-warning-bg-color;
- padding: 20px;
- border: 1px solid $primary-hairline-color;
- border-bottom: unset;
+ align-items: center;
+ margin-bottom: 5px;
}
-.mx_RoomRecoveryReminder_header {
- font-weight: bold;
- margin-bottom: 1em;
+.mx_ExistingSpellCheckLanguage_language {
+ flex: 1;
+ margin-right: 10px;
}
-.mx_RoomRecoveryReminder_body {
- margin-bottom: 1em;
-}
-
-.mx_RoomRecoveryReminder_secondary {
- font-size: 90%;
+.mx_GeneralUserSettingsTab_spellCheckLanguageInput {
margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.mx_SpellCheckLanguages {
+ @mixin mx_Settings_fullWidthField;
}
diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss
index e3a61e6825..892f5fe744 100644
--- a/res/css/views/settings/tabs/_SettingsTab.scss
+++ b/res/css/views/settings/tabs/_SettingsTab.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2019 New Vector Ltd
+Copyright 2019, 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,6 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+.mx_SettingsTab {
+ color: $muted-fg-color;
+}
+
.mx_SettingsTab_warningText {
color: $warning-color;
}
@@ -22,6 +26,7 @@ limitations under the License.
font-size: $font-20px;
font-weight: 600;
color: $primary-fg-color;
+ margin-bottom: 10px;
}
.mx_SettingsTab_heading:nth-child(n + 2) {
diff --git a/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss
index b5a57dfefb..23dcc532b2 100644
--- a/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss
+++ b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss
@@ -14,10 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_SecurityRoomSettingsTab label {
- display: block;
-}
-
.mx_SecurityRoomSettingsTab_warning {
display: block;
diff --git a/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss b/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss
index 6c9b89cf5a..8b73e69031 100644
--- a/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss
@@ -22,6 +22,13 @@ limitations under the License.
margin-top: 0;
}
+// TODO: Make this selector less painful
+.mx_GeneralUserSettingsTab_accountSection .mx_SettingsTab_subheading:nth-child(n + 1),
+.mx_GeneralUserSettingsTab_discovery .mx_SettingsTab_subheading:nth-child(n + 2),
+.mx_SetIdServer .mx_SettingsTab_subheading {
+ margin-top: 24px;
+}
+
.mx_GeneralUserSettingsTab_accountSection .mx_Spinner,
.mx_GeneralUserSettingsTab_discovery .mx_Spinner {
// Move the spinner to the left side of the container (default center)
diff --git a/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss
index 109edfff81..0f879d209e 100644
--- a/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss
@@ -22,3 +22,34 @@ limitations under the License.
.mx_HelpUserSettingsTab span.mx_AccessibleButton {
word-break: break-word;
}
+
+.mx_HelpUserSettingsTab code {
+ word-break: break-all;
+ user-select: all;
+}
+
+.mx_HelpUserSettingsTab_accessToken {
+ display: flex;
+ justify-content: space-between;
+ border-radius: 5px;
+ border: solid 1px $light-fg-color;
+ margin-bottom: 10px;
+ margin-top: 10px;
+ padding: 10px;
+}
+
+.mx_HelpUserSettingsTab_accessToken_copy {
+ flex-shrink: 0;
+ cursor: pointer;
+ margin-left: 20px;
+ display: inherit;
+}
+
+.mx_HelpUserSettingsTab_accessToken_copy > div {
+ mask-image: url($copy-button-url);
+ background-color: $message-action-bar-fg-color;
+ margin-left: 5px;
+ width: 20px;
+ height: 20px;
+ background-repeat: no-repeat;
+}
diff --git a/res/css/views/settings/tabs/user/_LabsUserSettingsTab.scss b/res/css/views/settings/tabs/user/_LabsUserSettingsTab.scss
new file mode 100644
index 0000000000..540db48d65
--- /dev/null
+++ b/res/css/views/settings/tabs/user/_LabsUserSettingsTab.scss
@@ -0,0 +1,25 @@
+/*
+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_LabsUserSettingsTab {
+ .mx_SettingsTab_section {
+ margin-top: 32px;
+
+ .mx_SettingsFlag {
+ margin-right: 0; // remove right margin to align with beta cards
+ }
+ }
+}
diff --git a/res/css/views/spaces/_SpaceBasicSettings.scss b/res/css/views/spaces/_SpaceBasicSettings.scss
new file mode 100644
index 0000000000..204ccab2b7
--- /dev/null
+++ b/res/css/views/spaces/_SpaceBasicSettings.scss
@@ -0,0 +1,86 @@
+/*
+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_SpaceBasicSettings {
+ .mx_Field {
+ margin: 32px 0;
+ }
+
+ .mx_SpaceBasicSettings_avatarContainer {
+ display: flex;
+ margin-top: 24px;
+
+ .mx_SpaceBasicSettings_avatar {
+ position: relative;
+ height: 80px;
+ width: 80px;
+ background-color: $tertiary-fg-color;
+ border-radius: 16px;
+ }
+
+ img.mx_SpaceBasicSettings_avatar {
+ width: 80px;
+ height: 80px;
+ object-fit: cover;
+ border-radius: 16px;
+ }
+
+ // only show it when the button is a div and not an img (has avatar)
+ div.mx_SpaceBasicSettings_avatar {
+ cursor: pointer;
+
+ &::before {
+ content: "";
+ position: absolute;
+ height: 80px;
+ width: 80px;
+ top: 0;
+ left: 0;
+ background-color: #ffffff; // white icon fill
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: 20px;
+ mask-image: url('$(res)/img/element-icons/camera.svg');
+ }
+ }
+
+ > input[type="file"] {
+ display: none;
+ }
+
+ > .mx_AccessibleButton_kind_link {
+ display: inline-block;
+ padding: 0;
+ margin: auto 16px;
+ color: #368bd6;
+ }
+
+ > .mx_SpaceBasicSettings_avatar_remove {
+ color: $notice-primary-color;
+ }
+ }
+
+ .mx_FormButton {
+ padding: 8px 22px;
+ margin-left: auto;
+ display: block;
+ width: min-content;
+ }
+
+ .mx_AccessibleButton_disabled {
+ cursor: not-allowed;
+ }
+}
diff --git a/res/css/views/spaces/_SpaceCreateMenu.scss b/res/css/views/spaces/_SpaceCreateMenu.scss
new file mode 100644
index 0000000000..88b9d8f693
--- /dev/null
+++ b/res/css/views/spaces/_SpaceCreateMenu.scss
@@ -0,0 +1,101 @@
+/*
+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.
+*/
+
+$spacePanelWidth: 71px;
+
+.mx_SpaceCreateMenu_wrapper {
+ // background blur everything except SpacePanel
+ .mx_ContextualMenu_background {
+ background-color: $dialog-backdrop-color;
+ opacity: 0.6;
+ left: $spacePanelWidth;
+ }
+
+ .mx_ContextualMenu {
+ padding: 24px;
+ width: 480px;
+ box-sizing: border-box;
+ background-color: $primary-bg-color;
+ position: relative;
+
+ > div {
+ > h2 {
+ font-weight: $font-semi-bold;
+ font-size: $font-18px;
+ margin-top: 4px;
+ }
+
+ > p {
+ font-size: $font-15px;
+ color: $secondary-fg-color;
+ margin: 0;
+ }
+ }
+
+ // XXX remove this when spaces leaves Beta
+ .mx_BetaCard_betaPill {
+ position: absolute;
+ top: 24px;
+ right: 24px;
+ }
+
+ .mx_SpaceCreateMenuType {
+ @mixin SpacePillButton;
+ }
+
+ .mx_SpaceCreateMenuType_public::before {
+ mask-image: url('$(res)/img/globe.svg');
+ }
+ .mx_SpaceCreateMenuType_private::before {
+ mask-image: url('$(res)/img/element-icons/lock.svg');
+ }
+
+ .mx_SpaceCreateMenu_back {
+ width: 28px;
+ height: 28px;
+ position: relative;
+ background-color: $roomlist-button-bg-color;
+ border-radius: 14px;
+ margin-bottom: 12px;
+
+ &::before {
+ content: "";
+ position: absolute;
+ height: 28px;
+ width: 28px;
+ top: 0;
+ left: 0;
+ background-color: $tertiary-fg-color;
+ transform: rotate(90deg);
+ mask-repeat: no-repeat;
+ mask-position: 2px 3px;
+ mask-size: 24px;
+ mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
+ }
+ }
+
+ .mx_AccessibleButton_kind_primary {
+ padding: 8px 22px;
+ margin-left: auto;
+ display: block;
+ width: min-content;
+ }
+
+ .mx_AccessibleButton_disabled {
+ cursor: not-allowed;
+ }
+ }
+}
diff --git a/src/RoomListSorter.js b/res/css/views/spaces/_SpacePublicShare.scss
similarity index 57%
rename from src/RoomListSorter.js
rename to res/css/views/spaces/_SpacePublicShare.scss
index 0ff37a6af2..373fa94e00 100644
--- a/src/RoomListSorter.js
+++ b/res/css/views/spaces/_SpacePublicShare.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2015, 2016 OpenMarket Ltd
+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.
@@ -14,18 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-'use strict';
+.mx_SpacePublicShare {
+ .mx_AccessibleButton {
+ @mixin SpacePillButton;
-function tsOfNewestEvent(room) {
- if (room.timeline.length) {
- return room.timeline[room.timeline.length - 1].getTs();
- } else {
- return Number.MAX_SAFE_INTEGER;
+ &.mx_SpacePublicShare_shareButton::before {
+ mask-image: url('$(res)/img/element-icons/link.svg');
+ }
+
+ &.mx_SpacePublicShare_inviteButton::before {
+ mask-image: url('$(res)/img/element-icons/room/invite.svg');
+ }
}
}
-
-export function mostRecentActivityFirst(roomList) {
- return roomList.sort(function(a, b) {
- return tsOfNewestEvent(b) - tsOfNewestEvent(a);
- });
-}
diff --git a/res/css/views/toasts/_AnalyticsToast.scss b/res/css/views/toasts/_AnalyticsToast.scss
new file mode 100644
index 0000000000..fdbe7f1c76
--- /dev/null
+++ b/res/css/views/toasts/_AnalyticsToast.scss
@@ -0,0 +1,27 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_AnalyticsToast {
+ .mx_AccessibleButton_kind_danger {
+ background: none;
+ color: $accent-color;
+ }
+
+ .mx_AccessibleButton_kind_primary {
+ background: $accent-color;
+ color: #ffffff;
+ }
+}
diff --git a/res/css/views/voice_messages/_PlayPauseButton.scss b/res/css/views/voice_messages/_PlayPauseButton.scss
new file mode 100644
index 0000000000..6caedafa29
--- /dev/null
+++ b/res/css/views/voice_messages/_PlayPauseButton.scss
@@ -0,0 +1,51 @@
+/*
+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_PlayPauseButton {
+ position: relative;
+ width: 32px;
+ height: 32px;
+ border-radius: 32px;
+ background-color: $voice-playback-button-bg-color;
+
+ &::before {
+ content: '';
+ position: absolute; // sizing varies by icon
+ background-color: $voice-playback-button-fg-color;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ }
+
+ &.mx_PlayPauseButton_disabled::before {
+ opacity: 0.5;
+ }
+
+ &.mx_PlayPauseButton_play::before {
+ width: 13px;
+ height: 16px;
+ top: 8px; // center
+ left: 12px; // center
+ mask-image: url('$(res)/img/element-icons/play.svg');
+ }
+
+ &.mx_PlayPauseButton_pause::before {
+ width: 10px;
+ height: 12px;
+ top: 10px; // center
+ left: 11px; // center
+ mask-image: url('$(res)/img/element-icons/pause.svg');
+ }
+}
diff --git a/res/css/views/voice_messages/_PlaybackContainer.scss b/res/css/views/voice_messages/_PlaybackContainer.scss
new file mode 100644
index 0000000000..20def16d6a
--- /dev/null
+++ b/res/css/views/voice_messages/_PlaybackContainer.scss
@@ -0,0 +1,53 @@
+/*
+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.
+*/
+
+// Dev note: there's no actual component called . These classes
+// are shared amongst multiple voice message components.
+
+// Container for live recording and playback controls
+.mx_VoiceMessagePrimaryContainer {
+ // 7px top and bottom for visual design. 12px left & right, but the waveform (right)
+ // has a 1px padding on it that we want to account for.
+ padding: 7px 12px 7px 11px;
+ background-color: $voice-record-waveform-bg-color;
+ border-radius: 12px;
+
+ // Cheat at alignment a bit
+ display: flex;
+ align-items: center;
+
+ color: $voice-record-waveform-fg-color;
+ font-size: $font-14px;
+ line-height: $font-24px;
+
+ .mx_Waveform {
+ .mx_Waveform_bar {
+ background-color: $voice-record-waveform-incomplete-fg-color;
+
+ &.mx_Waveform_bar_100pct {
+ // Small animation to remove the mechanical feel of progress
+ transition: background-color 250ms ease;
+ background-color: $voice-record-waveform-fg-color;
+ }
+ }
+ }
+
+ .mx_Clock {
+ width: $font-42px; // we're not using a monospace font, so fake it
+ padding-right: 6px; // with the fixed width this ends up as a visual 8px most of the time, as intended.
+ padding-left: 8px; // isolate from recording circle / play control
+ }
+}
diff --git a/res/css/views/voice_messages/_Waveform.scss b/res/css/views/voice_messages/_Waveform.scss
new file mode 100644
index 0000000000..cf03c84601
--- /dev/null
+++ b/res/css/views/voice_messages/_Waveform.scss
@@ -0,0 +1,40 @@
+/*
+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_Waveform {
+ position: relative;
+ height: 30px; // tallest bar can only be 30px
+ top: 1px; // because of our border trick (see below), we're off by 1px of aligntment
+
+ display: flex;
+ align-items: center; // so the bars grow from the middle
+
+ overflow: hidden; // this is cheaper than a `max-height: calc(100% - 4px)` in the bar's CSS.
+
+ // A bar is meant to be a 2x2 circle when at zero height, and otherwise a 2px wide line
+ // with rounded caps.
+ .mx_Waveform_bar {
+ width: 0; // 0px width means we'll end up using the border as our width
+ border: 1px solid transparent; // transparent means we'll use the background colour
+ border-radius: 2px; // rounded end caps, based on the border
+ min-height: 0; // like the width, we'll rely on the border to give us height
+ max-height: 100%; // this makes the `height: 42%` work on the element
+ margin-left: 1px; // we want 2px between each bar, so 1px on either side for balance
+ margin-right: 1px;
+
+ // background color is handled by the parent components
+ }
+}
diff --git a/res/css/views/voip/_CallContainer.scss b/res/css/views/voip/_CallContainer.scss
index 8d1b68dd99..8262075559 100644
--- a/res/css/views/voip/_CallContainer.scss
+++ b/res/css/views/voip/_CallContainer.scss
@@ -18,34 +18,47 @@ limitations under the License.
position: absolute;
right: 20px;
bottom: 72px;
- border-radius: 8px;
- overflow: hidden;
z-index: 100;
- box-shadow: 0px 14px 24px rgba(0, 0, 0, 0.08);
- cursor: pointer;
+ // Disable pointer events for Jitsi widgets to function. Direct
+ // calls have their own cursor and behaviour, but we need to make
+ // sure the cursor hits the iframe for Jitsi which will be at a
+ // different level.
+ pointer-events: none;
.mx_CallPreview {
- .mx_VideoView {
+ pointer-events: initial; // restore pointer events so the user can leave/interact
+ cursor: pointer;
+
+ .mx_CallView_video {
width: 350px;
}
- .mx_VideoView_localVideoFeed {
+ .mx_VideoFeed_local {
border-radius: 8px;
overflow: hidden;
}
}
+ .mx_AppTile_persistedWrapper div {
+ min-width: 350px;
+ }
+
.mx_IncomingCallBox {
min-width: 250px;
- background-color: $primary-bg-color;
+ background-color: $voipcall-plinth-color;
padding: 8px;
+ box-shadow: 0px 14px 24px rgba(0, 0, 0, 0.08);
+ border-radius: 8px;
+
+ pointer-events: initial; // restore pointer events so the user can accept/decline
+ cursor: pointer;
.mx_IncomingCallBox_CallerInfo {
display: flex;
direction: row;
- img {
+ img, .mx_BaseAvatar_initial {
margin: 8px;
}
diff --git a/res/css/views/voip/_CallView.scss b/res/css/views/voip/_CallView.scss
index f6f3d40308..0be75be28c 100644
--- a/res/css/views/voip/_CallView.scss
+++ b/res/css/views/voip/_CallView.scss
@@ -15,80 +15,364 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_CallView_voice {
- background-color: $accent-color;
- color: $accent-fg-color;
- cursor: pointer;
- padding: 6px;
- font-weight: bold;
-
+.mx_CallView {
border-radius: 8px;
- min-width: 200px;
+ background-color: $dark-panel-bg-color;
+ padding-left: 8px;
+ padding-right: 8px;
+ // XXX: CallContainer sets pointer-events: none - should probably be set back in a better place
+ pointer-events: initial;
+}
+.mx_CallView_large {
+ padding-bottom: 10px;
+ margin: 5px 5px 5px 18px;
display: flex;
- align-items: center;
+ flex-direction: column;
+ flex: 1;
- img {
- margin: 4px;
- margin-right: 10px;
- }
-
- > div {
- display: flex;
- flex-direction: column;
- // Hacky vertical align
- padding-top: 3px;
- }
-
- > div > p,
- > div > h1 {
- padding: 0;
- margin: 0;
- font-size: $font-13px;
- line-height: $font-15px;
- }
-
- > div > p {
- font-weight: bold;
- }
-
- > * {
- flex-grow: 0;
- flex-shrink: 0;
+ .mx_CallView_voice {
+ flex: 1;
}
}
-.mx_CallView_hangup {
+.mx_CallView_pip {
+ width: 320px;
+ padding-bottom: 8px;
+ margin-top: 10px;
+ background-color: $voipcall-plinth-color;
+ box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.20);
+ border-radius: 8px;
+
+ .mx_CallView_voice {
+ height: 180px;
+ }
+
+ .mx_CallView_callControls {
+ bottom: 0px;
+ }
+
+ .mx_CallView_callControls_button {
+ &::before {
+ width: 36px;
+ height: 36px;
+ }
+ }
+
+ .mx_CallView_holdTransferContent {
+ padding-top: 10px;
+ padding-bottom: 25px;
+ }
+}
+
+.mx_CallView_content {
+ position: relative;
+ display: flex;
+ border-radius: 8px;
+}
+
+.mx_CallView_voice {
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ background-color: $inverted-bg-color;
+}
+
+.mx_CallView_voice_avatarsContainer {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ div {
+ margin-left: 12px;
+ margin-right: 12px;
+ }
+}
+
+.mx_CallView_voice .mx_CallView_holdTransferContent {
+ // This masks the avatar image so when it's blurred, the edge is still crisp
+ .mx_CallView_voice_avatarContainer {
+ border-radius: 2000px;
+ overflow: hidden;
+ position: relative;
+ }
+}
+
+.mx_CallView_holdTransferContent {
+ height: 20px;
+ padding-top: 20px;
+ padding-bottom: 15px;
+ color: $accent-fg-color;
+ .mx_AccessibleButton_hasKind {
+ padding: 0px;
+ font-weight: bold;
+ }
+}
+
+.mx_CallView_video {
+ width: 100%;
+ height: 100%;
+ z-index: 30;
+ overflow: hidden;
+}
+
+.mx_CallView_video_hold {
+ overflow: hidden;
+
+ // we keep these around in the DOM: it saved wiring them up again when the call
+ // is resumed and keeps the container the right size
+ .mx_VideoFeed {
+ visibility: hidden;
+ }
+}
+
+.mx_CallView_video_holdBackground {
position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ right: 0;
+ background-repeat: no-repeat;
+ background-size: cover;
+ background-position: center;
+ filter: blur(20px);
+ &::after {
+ content: '';
+ display: block;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ right: 0;
+ background-color: rgba(0, 0, 0, 0.6);
+ }
+}
- right: 8px;
- bottom: 10px;
+.mx_CallView_video .mx_CallView_holdTransferContent {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-weight: bold;
+ color: $accent-fg-color;
+ text-align: center;
- height: 35px;
- width: 35px;
+ &::before {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ content: '';
+ width: 40px;
+ height: 40px;
+ background-image: url('$(res)/img/voip/paused.svg');
+ background-position: center;
+ background-size: cover;
+ }
+ .mx_CallView_pip &::before {
+ width: 30px;
+ height: 30px;
+ }
+ .mx_AccessibleButton_hasKind {
+ padding: 0px;
+ }
+}
- border-radius: 35px;
+.mx_CallView_header {
+ height: 44px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: left;
+ flex-shrink: 0;
+}
- background-color: $notice-primary-color;
+.mx_CallView_header_callType {
+ font-size: 1.2rem;
+ font-weight: bold;
+ vertical-align: middle;
+}
- z-index: 101;
+.mx_CallView_header_secondaryCallInfo {
+ &::before {
+ content: '·';
+ margin-left: 6px;
+ margin-right: 6px;
+ }
+}
+.mx_CallView_header_controls {
+ margin-left: auto;
+}
+
+.mx_CallView_header_button {
+ display: inline-block;
+ vertical-align: middle;
cursor: pointer;
&::before {
content: '';
- position: absolute;
-
+ display: inline-block;
height: 20px;
width: 20px;
-
- top: 6.5px;
- left: 7.5px;
-
- mask: url('$(res)/img/hangup.svg');
+ vertical-align: middle;
+ background-color: $secondary-fg-color;
+ mask-repeat: no-repeat;
mask-size: contain;
- background-size: contain;
-
- background-color: $primary-fg-color;
+ mask-position: center;
}
}
+
+.mx_CallView_header_button_fullscreen {
+ &::before {
+ mask-image: url('$(res)/img/element-icons/call/fullscreen.svg');
+ }
+}
+
+.mx_CallView_header_button_expand {
+ &::before {
+ mask-image: url('$(res)/img/element-icons/call/expand.svg');
+ }
+}
+
+.mx_CallView_header_callInfo {
+ margin-left: 12px;
+ margin-right: 16px;
+}
+
+.mx_CallView_header_roomName {
+ font-weight: bold;
+ font-size: 12px;
+ line-height: initial;
+ height: 15px;
+}
+
+.mx_CallView_secondaryCall_roomName {
+ margin-left: 4px;
+}
+
+.mx_CallView_header_callTypeSmall {
+ font-size: 12px;
+ color: $secondary-fg-color;
+ line-height: initial;
+ height: 15px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ max-width: 240px;
+}
+
+.mx_CallView_header_phoneIcon {
+ display: inline-block;
+ margin-right: 6px;
+ height: 16px;
+ width: 16px;
+ vertical-align: middle;
+
+ &::before {
+ content: '';
+ display: inline-block;
+ vertical-align: top;
+
+ height: 16px;
+ width: 16px;
+ background-color: $warning-color;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ mask-position: center;
+ mask-image: url('$(res)/img/element-icons/call/voice-call.svg');
+ }
+}
+
+.mx_CallView_callControls {
+ position: absolute;
+ display: flex;
+ justify-content: center;
+ bottom: 5px;
+ width: 100%;
+ opacity: 1;
+ transition: opacity 0.5s;
+}
+
+.mx_CallView_callControls_hidden {
+ opacity: 0.001; // opacity 0 can cause a re-layout
+ pointer-events: none;
+}
+
+.mx_CallView_callControls_button {
+ cursor: pointer;
+ margin-left: 8px;
+ margin-right: 8px;
+
+
+ &::before {
+ content: '';
+ display: inline-block;
+
+ height: 48px;
+ width: 48px;
+
+ background-repeat: no-repeat;
+ background-size: contain;
+ background-position: center;
+ }
+}
+
+.mx_CallView_callControls_dialpad {
+ margin-right: auto;
+ &::before {
+ background-image: url('$(res)/img/voip/dialpad.svg');
+ }
+}
+
+.mx_CallView_callControls_button_dialpad_hidden {
+ margin-right: auto;
+ cursor: initial;
+}
+
+.mx_CallView_callControls_button_micOn {
+ &::before {
+ background-image: url('$(res)/img/voip/mic-on.svg');
+ }
+}
+
+.mx_CallView_callControls_button_micOff {
+ &::before {
+ background-image: url('$(res)/img/voip/mic-off.svg');
+ }
+}
+
+.mx_CallView_callControls_button_vidOn {
+ &::before {
+ background-image: url('$(res)/img/voip/vid-on.svg');
+ }
+}
+
+.mx_CallView_callControls_button_vidOff {
+ &::before {
+ background-image: url('$(res)/img/voip/vid-off.svg');
+ }
+}
+
+.mx_CallView_callControls_button_hangup {
+ &::before {
+ background-image: url('$(res)/img/voip/hangup.svg');
+ }
+}
+
+.mx_CallView_callControls_button_more {
+ margin-left: auto;
+ &::before {
+ background-image: url('$(res)/img/voip/more.svg');
+ }
+}
+
+.mx_CallView_callControls_button_more_hidden {
+ margin-left: auto;
+ cursor: initial;
+}
+
+.mx_CallView_callControls_button_invisible {
+ visibility: hidden;
+ pointer-events: none;
+ position: absolute;
+}
diff --git a/res/css/views/voip/_CallViewForRoom.scss b/res/css/views/voip/_CallViewForRoom.scss
new file mode 100644
index 0000000000..769e00338e
--- /dev/null
+++ b/res/css/views/voip/_CallViewForRoom.scss
@@ -0,0 +1,46 @@
+/*
+Copyright 2021 Šimon Brandner
+
+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_CallViewForRoom {
+ overflow: hidden;
+
+ .mx_CallViewForRoom_ResizeWrapper {
+ display: flex;
+ margin-bottom: 8px;
+
+ &:hover .mx_CallViewForRoom_ResizeHandle {
+ // Need to use important to override element style attributes
+ // set by re-resizable
+ width: 100% !important;
+
+ display: flex;
+ justify-content: center;
+
+ &::after {
+ content: '';
+ margin-top: 3px;
+
+ border-radius: 4px;
+
+ height: 4px;
+ width: 100%;
+ max-width: 64px;
+
+ background-color: $primary-fg-color;
+ }
+ }
+ }
+}
diff --git a/res/css/views/voip/_DialPad.scss b/res/css/views/voip/_DialPad.scss
new file mode 100644
index 0000000000..0c7bff0ce8
--- /dev/null
+++ b/res/css/views/voip/_DialPad.scss
@@ -0,0 +1,62 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_DialPad {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 16px;
+}
+
+.mx_DialPad_button {
+ width: 40px;
+ height: 40px;
+ background-color: $theme-button-bg-color;
+ border-radius: 40px;
+ font-size: 18px;
+ font-weight: 600;
+ text-align: center;
+ vertical-align: middle;
+ line-height: 40px;
+}
+
+.mx_DialPad_deleteButton, .mx_DialPad_dialButton {
+ &::before {
+ content: '';
+ display: inline-block;
+ height: 40px;
+ width: 40px;
+ vertical-align: middle;
+ mask-repeat: no-repeat;
+ mask-size: 20px;
+ mask-position: center;
+ background-color: $primary-bg-color;
+ }
+}
+
+.mx_DialPad_deleteButton {
+ background-color: $notice-primary-color;
+ &::before {
+ mask-image: url('$(res)/img/element-icons/call/delete.svg');
+ mask-position: 9px; // delete icon is right-heavy so have to be slightly to the left to look centered
+ }
+}
+
+.mx_DialPad_dialButton {
+ background-color: $accent-color;
+ &::before {
+ mask-image: url('$(res)/img/element-icons/call/voice-call.svg');
+ }
+}
diff --git a/res/css/views/voip/_DialPadContextMenu.scss b/res/css/views/voip/_DialPadContextMenu.scss
new file mode 100644
index 0000000000..520f51cf93
--- /dev/null
+++ b/res/css/views/voip/_DialPadContextMenu.scss
@@ -0,0 +1,47 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_DialPadContextMenu_header {
+ margin-top: 12px;
+ margin-left: 12px;
+ margin-right: 12px;
+}
+
+.mx_DialPadContextMenu_title {
+ color: $muted-fg-color;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.mx_DialPadContextMenu_dialled {
+ height: 1em;
+ font-size: 18px;
+ font-weight: 600;
+}
+
+.mx_DialPadContextMenu_dialPad {
+ margin: 16px;
+}
+
+.mx_DialPadContextMenu_horizSep {
+ position: relative;
+ &::before {
+ content: '';
+ position: absolute;
+ width: 100%;
+ border-bottom: 1px solid $input-darker-bg-color;
+ }
+}
diff --git a/res/css/views/voip/_DialPadModal.scss b/res/css/views/voip/_DialPadModal.scss
new file mode 100644
index 0000000000..f9d7673a38
--- /dev/null
+++ b/res/css/views/voip/_DialPadModal.scss
@@ -0,0 +1,74 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+.mx_Dialog_dialPadWrapper .mx_Dialog {
+ padding: 0px;
+}
+
+.mx_DialPadModal {
+ width: 192px;
+ height: 368px;
+}
+
+.mx_DialPadModal_header {
+ margin-top: 12px;
+ margin-left: 12px;
+ margin-right: 12px;
+}
+
+.mx_DialPadModal_title {
+ color: $muted-fg-color;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.mx_DialPadModal_cancel {
+ float: right;
+ mask: url('$(res)/img/feather-customised/cancel.svg');
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: cover;
+ width: 14px;
+ height: 14px;
+ background-color: $dialog-close-fg-color;
+ cursor: pointer;
+}
+
+.mx_DialPadModal_field {
+ border: none;
+ margin: 0px;
+}
+
+.mx_DialPadModal_field input {
+ font-size: 18px;
+ font-weight: 600;
+}
+
+.mx_DialPadModal_dialPad {
+ margin-left: 16px;
+ margin-right: 16px;
+ margin-top: 16px;
+}
+
+.mx_DialPadModal_horizSep {
+ position: relative;
+ &::before {
+ content: '';
+ position: absolute;
+ width: 100%;
+ border-bottom: 1px solid $input-darker-bg-color;
+ }
+}
diff --git a/res/css/views/voip/_VideoView.scss b/res/css/views/voip/_VideoFeed.scss
similarity index 51%
rename from res/css/views/voip/_VideoView.scss
rename to res/css/views/voip/_VideoFeed.scss
index feb60f4763..7d85ac264e 100644
--- a/res/css/views/voip/_VideoView.scss
+++ b/res/css/views/voip/_VideoFeed.scss
@@ -1,5 +1,5 @@
/*
-Copyright 2015, 2016 OpenMarket Ltd
+Copyright 2015, 2016, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,36 +14,39 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_VideoView {
+.mx_VideoFeed_voice {
+ // We don't want to collide with the call controls that have 52px of height
+ padding-bottom: 52px;
+ background-color: $inverted-bg-color;
+}
+
+
+.mx_VideoFeed_remote {
width: 100%;
- position: relative;
- z-index: 30;
-}
-
-.mx_VideoView video {
- width: 100%;
-}
-
-.mx_VideoView_remoteVideoFeed {
- width: 100%;
- background-color: #000;
- z-index: 50;
-}
-
-.mx_VideoView_localVideoFeed {
- width: 25%;
- height: 25%;
- position: absolute;
- left: 10px;
- bottom: 10px;
- z-index: 100;
-}
-
-.mx_VideoView_localVideoFeed video {
- width: auto;
height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ &.mx_VideoFeed_video {
+ background-color: #000;
+ }
}
-.mx_VideoView_localVideoFeed.mx_VideoView_localVideoFeed_flipped video {
+.mx_VideoFeed_local {
+ max-width: 25%;
+ max-height: 25%;
+ position: absolute;
+ right: 10px;
+ top: 10px;
+ z-index: 100;
+ border-radius: 4px;
+
+ &.mx_VideoFeed_video {
+ background-color: transparent;
+ }
+}
+
+.mx_VideoFeed_mirror {
transform: scale(-1, 1);
}
diff --git a/res/fonts/Inter/Inter-Bold.woff b/res/fonts/Inter/Inter-Bold.woff
index 61e1c25e64..2ec7ac3d21 100644
Binary files a/res/fonts/Inter/Inter-Bold.woff and b/res/fonts/Inter/Inter-Bold.woff differ
diff --git a/res/fonts/Inter/Inter-Bold.woff2 b/res/fonts/Inter/Inter-Bold.woff2
index 6c401bb09b..6989c99229 100644
Binary files a/res/fonts/Inter/Inter-Bold.woff2 and b/res/fonts/Inter/Inter-Bold.woff2 differ
diff --git a/res/fonts/Inter/Inter-BoldItalic.woff b/res/fonts/Inter/Inter-BoldItalic.woff
index 2de403edd1..aa35b79745 100644
Binary files a/res/fonts/Inter/Inter-BoldItalic.woff and b/res/fonts/Inter/Inter-BoldItalic.woff differ
diff --git a/res/fonts/Inter/Inter-BoldItalic.woff2 b/res/fonts/Inter/Inter-BoldItalic.woff2
index 80efd4848d..18b4c1ce5e 100644
Binary files a/res/fonts/Inter/Inter-BoldItalic.woff2 and b/res/fonts/Inter/Inter-BoldItalic.woff2 differ
diff --git a/res/fonts/Inter/Inter-Italic.woff b/res/fonts/Inter/Inter-Italic.woff
index e7da6663fe..4b765bd592 100644
Binary files a/res/fonts/Inter/Inter-Italic.woff and b/res/fonts/Inter/Inter-Italic.woff differ
diff --git a/res/fonts/Inter/Inter-Italic.woff2 b/res/fonts/Inter/Inter-Italic.woff2
index 8559dfde38..bd5f255a98 100644
Binary files a/res/fonts/Inter/Inter-Italic.woff2 and b/res/fonts/Inter/Inter-Italic.woff2 differ
diff --git a/res/fonts/Inter/Inter-Medium.woff b/res/fonts/Inter/Inter-Medium.woff
index 8c36a6345e..7d55f34cca 100644
Binary files a/res/fonts/Inter/Inter-Medium.woff and b/res/fonts/Inter/Inter-Medium.woff differ
diff --git a/res/fonts/Inter/Inter-Medium.woff2 b/res/fonts/Inter/Inter-Medium.woff2
index 3b31d3350a..a916b47fc8 100644
Binary files a/res/fonts/Inter/Inter-Medium.woff2 and b/res/fonts/Inter/Inter-Medium.woff2 differ
diff --git a/res/fonts/Inter/Inter-MediumItalic.woff b/res/fonts/Inter/Inter-MediumItalic.woff
index fb79e91ff4..422ab0576a 100644
Binary files a/res/fonts/Inter/Inter-MediumItalic.woff and b/res/fonts/Inter/Inter-MediumItalic.woff differ
diff --git a/res/fonts/Inter/Inter-MediumItalic.woff2 b/res/fonts/Inter/Inter-MediumItalic.woff2
index d32c111f9c..f623924aea 100644
Binary files a/res/fonts/Inter/Inter-MediumItalic.woff2 and b/res/fonts/Inter/Inter-MediumItalic.woff2 differ
diff --git a/res/fonts/Inter/Inter-Regular.woff b/res/fonts/Inter/Inter-Regular.woff
index 7d587c40bf..7ff51b7d8f 100644
Binary files a/res/fonts/Inter/Inter-Regular.woff and b/res/fonts/Inter/Inter-Regular.woff differ
diff --git a/res/fonts/Inter/Inter-Regular.woff2 b/res/fonts/Inter/Inter-Regular.woff2
index d5ffd2a1f1..554aed6612 100644
Binary files a/res/fonts/Inter/Inter-Regular.woff2 and b/res/fonts/Inter/Inter-Regular.woff2 differ
diff --git a/res/fonts/Inter/Inter-SemiBold.woff b/res/fonts/Inter/Inter-SemiBold.woff
index 99df06cbee..76e507a515 100644
Binary files a/res/fonts/Inter/Inter-SemiBold.woff and b/res/fonts/Inter/Inter-SemiBold.woff differ
diff --git a/res/fonts/Inter/Inter-SemiBold.woff2 b/res/fonts/Inter/Inter-SemiBold.woff2
index df746af999..9307998993 100644
Binary files a/res/fonts/Inter/Inter-SemiBold.woff2 and b/res/fonts/Inter/Inter-SemiBold.woff2 differ
diff --git a/res/fonts/Inter/Inter-SemiBoldItalic.woff b/res/fonts/Inter/Inter-SemiBoldItalic.woff
index 91e192b9f1..382181212d 100644
Binary files a/res/fonts/Inter/Inter-SemiBoldItalic.woff and b/res/fonts/Inter/Inter-SemiBoldItalic.woff differ
diff --git a/res/fonts/Inter/Inter-SemiBoldItalic.woff2 b/res/fonts/Inter/Inter-SemiBoldItalic.woff2
index ff8774ccb4..f19f5505ec 100644
Binary files a/res/fonts/Inter/Inter-SemiBoldItalic.woff2 and b/res/fonts/Inter/Inter-SemiBoldItalic.woff2 differ
diff --git a/res/img/betas/spaces.png b/res/img/betas/spaces.png
new file mode 100644
index 0000000000..f4cfa90b4e
Binary files /dev/null and b/res/img/betas/spaces.png differ
diff --git a/res/img/cancel-white.svg b/res/img/cancel-white.svg
deleted file mode 100644
index 65e14c2fbc..0000000000
--- a/res/img/cancel-white.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
\ No newline at end of file
diff --git a/res/img/e2e/disabled.svg b/res/img/e2e/disabled.svg
new file mode 100644
index 0000000000..2f6110a36a
--- /dev/null
+++ b/res/img/e2e/disabled.svg
@@ -0,0 +1,5 @@
+
diff --git a/res/img/e2e/normal.svg b/res/img/e2e/normal.svg
index 23ca78e44d..83b544a326 100644
--- a/res/img/e2e/normal.svg
+++ b/res/img/e2e/normal.svg
@@ -1,3 +1,3 @@
-
,
@@ -914,7 +978,7 @@ export const Commands = [
args: '',
runFn: function(roomId, args) {
if (!args) return reject(this.getUserId());
- return success(MatrixClientPeg.get().sendHtmlMessage(roomId, args, textToHtmlRainbow(args)));
+ return success(ContentHelpers.makeHtmlMessage(args, textToHtmlRainbow(args)));
},
category: CommandCategories.messages,
}),
@@ -924,7 +988,7 @@ export const Commands = [
args: '',
runFn: function(roomId, args) {
if (!args) return reject(this.getUserId());
- return success(MatrixClientPeg.get().sendHtmlEmote(roomId, args, textToHtmlRainbow(args)));
+ return success(ContentHelpers.makeHtmlEmote(args, textToHtmlRainbow(args)));
},
category: CommandCategories.messages,
}),
@@ -963,19 +1027,13 @@ export const Commands = [
command: "rageshake",
aliases: ["bugreport"],
description: _td("Send a bug report with logs"),
+ isEnabled: () => !!SdkConfig.get().bug_report_endpoint_url,
args: "",
runFn: function(roomId, args) {
return success(
- sendBugReport(SdkConfig.get().bug_report_endpoint_url, {
- userText: args,
- sendLogs: true,
- }).then(() => {
- const InfoDialog = sdk.getComponent('dialogs.InfoDialog');
- Modal.createTrackedDialog('Slash Commands', 'Rageshake sent', InfoDialog, {
- title: _t('Logs sent'),
- description: _t('Thank you!'),
- });
- }),
+ Modal.createTrackedDialog('Slash Commands', 'Bug Report Dialog', BugReportDialog, {
+ initialText: args,
+ }).finished,
);
},
category: CommandCategories.advanced,
@@ -985,14 +1043,27 @@ export const Commands = [
description: _td("Opens chat with the given user"),
args: "",
runFn: function(roomId, userId) {
- if (!userId || !userId.startsWith("@") || !userId.includes(":")) {
+ // easter-egg for now: look up phone numbers through the thirdparty API
+ // (very dumb phone number detection...)
+ const isPhoneNumber = userId && /^\+?[0123456789]+$/.test(userId);
+ if (!userId || (!userId.startsWith("@") || !userId.includes(":")) && !isPhoneNumber) {
return reject(this.getUsage());
}
return success((async () => {
+ if (isPhoneNumber) {
+ const results = await CallHandler.sharedInstance().pstnLookup(this.state.value);
+ if (!results || results.length === 0 || !results[0].userid) {
+ throw new Error("Unable to find Matrix ID for phone number");
+ }
+ userId = results[0].userid;
+ }
+
+ const roomId = await ensureDMExists(MatrixClientPeg.get(), userId);
+
dis.dispatch({
action: 'view_room',
- room_id: await ensureDMExists(MatrixClientPeg.get(), userId),
+ room_id: roomId,
});
})());
},
@@ -1026,6 +1097,50 @@ export const Commands = [
},
category: CommandCategories.actions,
}),
+ new Command({
+ command: "holdcall",
+ description: _td("Places the call in the current room on hold"),
+ category: CommandCategories.other,
+ runFn: function(roomId, args) {
+ const call = CallHandler.sharedInstance().getCallForRoom(roomId);
+ if (!call) {
+ return reject("No active call in this room");
+ }
+ call.setRemoteOnHold(true);
+ return success();
+ },
+ }),
+ new Command({
+ command: "unholdcall",
+ description: _td("Takes the call in the current room off hold"),
+ category: CommandCategories.other,
+ runFn: function(roomId, args) {
+ const call = CallHandler.sharedInstance().getCallForRoom(roomId);
+ if (!call) {
+ return reject("No active call in this room");
+ }
+ call.setRemoteOnHold(false);
+ return success();
+ },
+ }),
+ new Command({
+ command: "converttodm",
+ description: _td("Converts the room to a DM"),
+ category: CommandCategories.other,
+ runFn: function(roomId, args) {
+ const room = MatrixClientPeg.get().getRoom(roomId);
+ return success(guessAndSetDMRoom(room, true));
+ },
+ }),
+ new Command({
+ command: "converttoroom",
+ description: _td("Converts the DM to a room"),
+ category: CommandCategories.other,
+ runFn: function(roomId, args) {
+ const room = MatrixClientPeg.get().getRoom(roomId);
+ return success(guessAndSetDMRoom(room, false));
+ },
+ }),
// Command definitions for autocompletion ONLY:
// /me is special because its not handled by SlashCommands.js and is instead done inside the Composer classes
@@ -1036,6 +1151,30 @@ export const Commands = [
category: CommandCategories.messages,
hideCompletionAfterSpace: true,
}),
+
+ ...CHAT_EFFECTS.map((effect) => {
+ return new Command({
+ command: effect.command,
+ description: effect.description(),
+ args: '',
+ runFn: function(roomId, args) {
+ return success((async () => {
+ if (!args) {
+ args = effect.fallbackMessage();
+ MatrixClientPeg.get().sendEmoteMessage(roomId, args);
+ } else {
+ const content = {
+ msgtype: effect.msgType,
+ body: args,
+ };
+ MatrixClientPeg.get().sendMessage(roomId, content);
+ }
+ dis.dispatch({action: `effects.${effect.command}`});
+ })());
+ },
+ category: CommandCategories.effects,
+ })
+ }),
];
// build a map from names and aliases to the Command objects.
@@ -1047,13 +1186,13 @@ Commands.forEach(cmd => {
});
});
-export function parseCommandString(input) {
+export function parseCommandString(input: string) {
// trim any trailing whitespace, as it can confuse the parser for
// IRC-style commands
input = input.replace(/\s+$/, '');
if (input[0] !== '/') return {}; // not a command
- const bits = input.match(/^(\S+?)(?: +((.|\n)*))?$/);
+ const bits = input.match(/^(\S+?)(?:[ \n]+((.|\n)*))?$/);
let cmd;
let args;
if (bits) {
@@ -1074,10 +1213,14 @@ export function parseCommandString(input) {
* processing the command, or 'promise' if a request was sent out.
* Returns null if the input didn't match a command.
*/
-export function getCommand(roomId, input) {
+export function getCommand(input: string) {
const {cmd, args} = parseCommandString(input);
- if (CommandMap.has(cmd)) {
- return () => CommandMap.get(cmd).run(roomId, args, cmd);
+ if (CommandMap.has(cmd) && CommandMap.get(cmd).isEnabled()) {
+ return {
+ cmd: CommandMap.get(cmd),
+ args,
+ };
}
+ return {};
}
diff --git a/src/Terms.js b/src/Terms.ts
similarity index 87%
rename from src/Terms.js
rename to src/Terms.ts
index 6ae89f9a2c..1bdff36cbc 100644
--- a/src/Terms.js
+++ b/src/Terms.ts
@@ -1,5 +1,5 @@
/*
-Copyright 2019 The Matrix.org Foundation C.I.C.
+Copyright 2019, 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.
@@ -17,7 +17,7 @@ limitations under the License.
import classNames from 'classnames';
import {MatrixClientPeg} from './MatrixClientPeg';
-import * as sdk from './';
+import * as sdk from '.';
import Modal from './Modal';
export class TermsNotSignedError extends Error {}
@@ -32,13 +32,30 @@ export class Service {
* @param {string} baseUrl The Base URL of the service (ie. before '/_matrix')
* @param {string} accessToken The user's access token for the service
*/
- constructor(serviceType, baseUrl, accessToken) {
- this.serviceType = serviceType;
- this.baseUrl = baseUrl;
- this.accessToken = accessToken;
+ constructor(public serviceType: string, public baseUrl: string, public accessToken: string) {
}
}
+interface Policy {
+ // @ts-ignore: No great way to express indexed types together with other keys
+ version: string;
+ [lang: string]: {
+ url: string;
+ };
+}
+type Policies = {
+ [policy: string]: Policy,
+};
+
+export type TermsInteractionCallback = (
+ policiesAndServicePairs: {
+ service: Service,
+ policies: Policies,
+ }[],
+ agreedUrls: string[],
+ extraClassNames?: string,
+) => Promise;
+
/**
* Start a flow where the user is presented with terms & conditions for some services
*
@@ -51,8 +68,8 @@ export class Service {
* if they cancel.
*/
export async function startTermsFlow(
- services,
- interactionCallback = dialogTermsInteractionCallback,
+ services: Service[],
+ interactionCallback: TermsInteractionCallback = dialogTermsInteractionCallback,
) {
const termsPromises = services.map(
(s) => MatrixClientPeg.get().getTerms(s.serviceType, s.baseUrl),
@@ -77,7 +94,7 @@ export async function startTermsFlow(
* }
*/
- const terms = await Promise.all(termsPromises);
+ const terms: { policies: Policies }[] = await Promise.all(termsPromises);
const policiesAndServicePairs = terms.map((t, i) => { return { 'service': services[i], 'policies': t.policies }; });
// fetch the set of agreed policy URLs from account data
@@ -158,10 +175,13 @@ export async function startTermsFlow(
}
export function dialogTermsInteractionCallback(
- policiesAndServicePairs,
- agreedUrls,
- extraClassNames,
-) {
+ policiesAndServicePairs: {
+ service: Service,
+ policies: { [policy: string]: Policy },
+ }[],
+ agreedUrls: string[],
+ extraClassNames?: string,
+): Promise {
return new Promise((resolve, reject) => {
console.log("Terms that need agreement", policiesAndServicePairs);
const TermsDialog = sdk.getComponent("views.dialogs.TermsDialog");
diff --git a/src/TextForEvent.js b/src/TextForEvent.js
index c55380bd9b..86f9ff20f4 100644
--- a/src/TextForEvent.js
+++ b/src/TextForEvent.js
@@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {MatrixClientPeg} from './MatrixClientPeg';
-import CallHandler from './CallHandler';
import { _t } from './languageHandler';
import * as Roles from './Roles';
import {isValid3pidInvite} from "./RoomInvite";
import SettingsStore from "./settings/SettingsStore";
import {ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES} from "./mjolnir/BanList";
+import {WIDGET_LAYOUT_EVENT_TYPE} from "./stores/widgets/WidgetLayoutStore";
function textForMemberEvent(ev) {
// XXX: SYJS-16 "sender is sometimes null for join messages"
@@ -28,7 +28,6 @@ function textForMemberEvent(ev) {
const prevContent = ev.getPrevContent();
const content = ev.getContent();
- const ConferenceHandler = CallHandler.getConferenceHandler();
const reason = content.reason ? (_t('Reason') + ': ' + content.reason) : '';
switch (content.membership) {
case 'invite': {
@@ -43,11 +42,7 @@ function textForMemberEvent(ev) {
return _t('%(targetName)s accepted an invitation.', {targetName});
}
} else {
- if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
- return _t('%(senderName)s requested a VoIP conference.', {senderName});
- } else {
- return _t('%(senderName)s invited %(targetName)s.', {senderName, targetName});
- }
+ return _t('%(senderName)s invited %(targetName)s.', {senderName, targetName});
}
}
case 'ban':
@@ -84,17 +79,11 @@ function textForMemberEvent(ev) {
}
} else {
if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key);
- if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
- return _t('VoIP conference started.');
- } else {
- return _t('%(targetName)s joined the room.', {targetName});
- }
+ return _t('%(targetName)s joined the room.', {targetName});
}
case 'leave':
if (ev.getSender() === ev.getStateKey()) {
- if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
- return _t('VoIP conference finished.');
- } else if (prevContent.membership === "invite") {
+ if (prevContent.membership === "invite") {
return _t('%(targetName)s rejected the invitation.', {targetName});
} else {
return _t('%(targetName)s left the room.', {targetName});
@@ -106,9 +95,10 @@ function textForMemberEvent(ev) {
senderName,
targetName,
}) + ' ' + reason;
- } else {
- // sender is not target and made the target leave, if not from invite/ban then this is a kick
+ } else if (prevContent.membership === "join") {
return _t('%(senderName)s kicked %(targetName)s.', {senderName, targetName}) + ' ' + reason;
+ } else {
+ return "";
}
}
}
@@ -210,59 +200,30 @@ function textForRelatedGroupsEvent(ev) {
function textForServerACLEvent(ev) {
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
const prevContent = ev.getPrevContent();
- const changes = [];
const current = ev.getContent();
const prev = {
deny: Array.isArray(prevContent.deny) ? prevContent.deny : [],
allow: Array.isArray(prevContent.allow) ? prevContent.allow : [],
allow_ip_literals: !(prevContent.allow_ip_literals === false),
};
+
let text = "";
if (prev.deny.length === 0 && prev.allow.length === 0) {
- text = `${senderDisplayName} set server ACLs for this room: `;
+ text = _t("%(senderDisplayName)s set the server ACLs for this room.", {senderDisplayName});
} else {
- text = `${senderDisplayName} changed the server ACLs for this room: `;
+ text = _t("%(senderDisplayName)s changed the server ACLs for this room.", {senderDisplayName});
}
if (!Array.isArray(current.allow)) {
current.allow = [];
}
- /* If we know for sure everyone is banned, don't bother showing the diff view */
+
+ // If we know for sure everyone is banned, mark the room as obliterated
if (current.allow.length === 0) {
- return text + "🎉 All servers are banned from participating! This room can no longer be used.";
+ return text + " " + _t("🎉 All servers are banned from participating! This room can no longer be used.");
}
- if (!Array.isArray(current.deny)) {
- current.deny = [];
- }
-
- const bannedServers = current.deny.filter((srv) => typeof(srv) === 'string' && !prev.deny.includes(srv));
- const unbannedServers = prev.deny.filter((srv) => typeof(srv) === 'string' && !current.deny.includes(srv));
- const allowedServers = current.allow.filter((srv) => typeof(srv) === 'string' && !prev.allow.includes(srv));
- const unallowedServers = prev.allow.filter((srv) => typeof(srv) === 'string' && !current.allow.includes(srv));
-
- if (bannedServers.length > 0) {
- changes.push(`Servers matching ${bannedServers.join(", ")} are now banned.`);
- }
-
- if (unbannedServers.length > 0) {
- changes.push(`Servers matching ${unbannedServers.join(", ")} were removed from the ban list.`);
- }
-
- if (allowedServers.length > 0) {
- changes.push(`Servers matching ${allowedServers.join(", ")} are now allowed.`);
- }
-
- if (unallowedServers.length > 0) {
- changes.push(`Servers matching ${unallowedServers.join(", ")} were removed from the allowed list.`);
- }
-
- if (prev.allow_ip_literals !== current.allow_ip_literals) {
- const allowban = current.allow_ip_literals ? "allowed" : "banned";
- changes.push(`Participating from a server using an IP literal hostname is now ${allowban}.`);
- }
-
- return text + changes.join(" ");
+ return text;
}
function textForMessageEvent(ev) {
@@ -341,14 +302,27 @@ function textForCallHangupEvent(event) {
reason = _t('(not supported by this browser)');
} else if (eventContent.reason) {
if (eventContent.reason === "ice_failed") {
+ // We couldn't establish a connection at all
reason = _t('(could not connect media)');
+ } else if (eventContent.reason === "ice_timeout") {
+ // We established a connection but it died
+ reason = _t('(connection failed)');
+ } else if (eventContent.reason === "user_media_failed") {
+ // The other side couldn't open capture devices
+ reason = _t("(their device couldn't start the camera / microphone)");
+ } else if (eventContent.reason === "unknown_error") {
+ // An error code the other side doesn't have a way to express
+ // (as opposed to an error code they gave but we don't know about,
+ // in which case we show the error code)
+ reason = _t("(an error occurred)");
} else if (eventContent.reason === "invite_timeout") {
reason = _t('(no answer)');
- } else if (eventContent.reason === "user hangup") {
+ } else if (eventContent.reason === "user hangup" || eventContent.reason === "user_hangup") {
// workaround for https://github.com/vector-im/element-web/issues/5178
// it seems Android randomly sets a reason of "user hangup" which is
// interpreted as an error code :(
// https://github.com/vector-im/riot-android/issues/2623
+ // Also the correct hangup code as of VoIP v1 (with underscore)
reason = '';
} else {
reason = _t('(unknown failure: %(reason)s)', {reason: eventContent.reason});
@@ -357,6 +331,11 @@ function textForCallHangupEvent(event) {
return _t('%(senderName)s ended the call.', {senderName}) + ' ' + reason;
}
+function textForCallRejectEvent(event) {
+ const senderName = event.sender ? event.sender.name : _t('Someone');
+ return _t('%(senderName)s declined the call.', {senderName});
+}
+
function textForCallInviteEvent(event) {
const senderName = event.sender ? event.sender.name : _t('Someone');
// FIXME: Find a better way to determine this from the event?
@@ -478,7 +457,7 @@ function textForWidgetEvent(event) {
let widgetName = name || prevName || type || prevType || '';
// Apply sentence case to widget name
if (widgetName && widgetName.length > 0) {
- widgetName = widgetName[0].toUpperCase() + widgetName.slice(1) + ' ';
+ widgetName = widgetName[0].toUpperCase() + widgetName.slice(1);
}
// If the widget was removed, its content should be {}, but this is sufficiently
@@ -500,6 +479,11 @@ function textForWidgetEvent(event) {
}
}
+function textForWidgetLayoutEvent(event) {
+ const senderName = event.sender?.name || event.getSender();
+ return _t("%(senderName)s has updated the widget layout", {senderName});
+}
+
function textForMjolnirEvent(event) {
const senderName = event.getSender();
const {entity: prevEntity} = event.getPrevContent();
@@ -563,17 +547,23 @@ function textForMjolnirEvent(event) {
// else the entity !== prevEntity - count as a removal & add
if (USER_RULE_TYPES.includes(event.getType())) {
- return _t("%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching " +
+ return _t(
+ "%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching " +
"%(newGlob)s for %(reason)s",
- {senderName, oldGlob: prevEntity, newGlob: entity, reason});
+ {senderName, oldGlob: prevEntity, newGlob: entity, reason},
+ );
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
- return _t("%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching " +
+ return _t(
+ "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching " +
"%(newGlob)s for %(reason)s",
- {senderName, oldGlob: prevEntity, newGlob: entity, reason});
+ {senderName, oldGlob: prevEntity, newGlob: entity, reason},
+ );
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
- return _t("%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching " +
+ return _t(
+ "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching " +
"%(newGlob)s for %(reason)s",
- {senderName, oldGlob: prevEntity, newGlob: entity, reason});
+ {senderName, oldGlob: prevEntity, newGlob: entity, reason},
+ );
}
// Unknown type. We'll say something but we shouldn't end up here.
@@ -586,6 +576,7 @@ const handlers = {
'm.call.invite': textForCallInviteEvent,
'm.call.answer': textForCallAnswerEvent,
'm.call.hangup': textForCallHangupEvent,
+ 'm.call.reject': textForCallRejectEvent,
};
const stateHandlers = {
@@ -605,6 +596,7 @@ const stateHandlers = {
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
'im.vector.modular.widgets': textForWidgetEvent,
+ [WIDGET_LAYOUT_EVENT_TYPE]: textForWidgetLayoutEvent,
};
// Add all the Mjolnir stuff to the renderer
diff --git a/src/ToWidgetPostMessageApi.js b/src/ToWidgetPostMessageApi.js
deleted file mode 100644
index 00309d252c..0000000000
--- a/src/ToWidgetPostMessageApi.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-Copyright 2018 New Vector Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// const OUTBOUND_API_NAME = 'toWidget';
-
-// Initiate requests using the "toWidget" postMessage API and handle responses
-// NOTE: ToWidgetPostMessageApi only handles message events with a data payload with a
-// response field
-export default class ToWidgetPostMessageApi {
- constructor(timeoutMs) {
- this._timeoutMs = timeoutMs || 5000; // default to 5s timer
- this._counter = 0;
- this._requestMap = {
- // $ID: {resolve, reject}
- };
- this.start = this.start.bind(this);
- this.stop = this.stop.bind(this);
- this.onPostMessage = this.onPostMessage.bind(this);
- }
-
- start() {
- window.addEventListener('message', this.onPostMessage);
- }
-
- stop() {
- window.removeEventListener('message', this.onPostMessage);
- }
-
- onPostMessage(ev) {
- // THIS IS ALL UNSAFE EXECUTION.
- // We do not verify who the sender of `ev` is!
- const payload = ev.data;
- // NOTE: Workaround for running in a mobile WebView where a
- // postMessage immediately triggers this callback even though it is
- // not the response.
- if (payload.response === undefined) {
- return;
- }
- const promise = this._requestMap[payload.requestId];
- if (!promise) {
- return;
- }
- delete this._requestMap[payload.requestId];
- promise.resolve(payload);
- }
-
- // Initiate outbound requests (toWidget)
- exec(action, targetWindow, targetOrigin) {
- targetWindow = targetWindow || window.parent; // default to parent window
- targetOrigin = targetOrigin || "*";
- this._counter += 1;
- action.requestId = Date.now() + "-" + Math.random().toString(36) + "-" + this._counter;
-
- return new Promise((resolve, reject) => {
- this._requestMap[action.requestId] = {resolve, reject};
- targetWindow.postMessage(action, targetOrigin);
-
- if (this._timeoutMs > 0) {
- setTimeout(() => {
- if (!this._requestMap[action.requestId]) {
- return;
- }
- console.error("postMessage request timed out. Sent object: " + JSON.stringify(action),
- this._requestMap);
- this._requestMap[action.requestId].reject(new Error("Timed out"));
- delete this._requestMap[action.requestId];
- }, this._timeoutMs);
- }
- });
- }
-}
diff --git a/src/Unread.js b/src/Unread.js
index cf131cac00..25c425aa9a 100644
--- a/src/Unread.js
+++ b/src/Unread.js
@@ -16,12 +16,14 @@ limitations under the License.
import {MatrixClientPeg} from "./MatrixClientPeg";
import shouldHideEvent from './shouldHideEvent';
-import * as sdk from "./index";
import {haveTileForEvent} from "./components/views/rooms/EventTile";
/**
* Returns true iff this event arriving in a room should affect the room's
* count of unread messages
+ *
+ * @param {Object} ev The event
+ * @returns {boolean} True if the given event should affect the unread message count
*/
export function eventTriggersUnreadCount(ev) {
if (ev.sender && ev.sender.userId == MatrixClientPeg.get().credentials.userId) {
@@ -38,12 +40,14 @@ export function eventTriggersUnreadCount(ev) {
return false;
} else if (ev.getType() == 'm.room.server_acl') {
return false;
+ } else if (ev.isRedacted()) {
+ return false;
}
return haveTileForEvent(ev);
}
export function doesRoomHaveUnreadMessages(room) {
- const myUserId = MatrixClientPeg.get().credentials.userId;
+ const myUserId = MatrixClientPeg.get().getUserId();
// get the most recent read receipt sent by our account.
// N.B. this is NOT a read marker (RM, aka "read up to marker"),
diff --git a/src/UserActivity.js b/src/UserActivity.ts
similarity index 61%
rename from src/UserActivity.js
rename to src/UserActivity.ts
index 0174aebaf5..606075ec7c 100644
--- a/src/UserActivity.js
+++ b/src/UserActivity.ts
@@ -38,26 +38,23 @@ const RECENTLY_ACTIVE_THRESHOLD_MS = 2 * 60 * 1000;
* see doc on the userActive* functions for what these mean.
*/
export default class UserActivity {
- constructor(windowObj, documentObj) {
- this._window = windowObj;
- this._document = documentObj;
+ private readonly activeNowTimeout: Timer;
+ private readonly activeRecentlyTimeout: Timer;
+ private attachedActiveNowTimers: Timer[] = [];
+ private attachedActiveRecentlyTimers: Timer[] = [];
+ private lastScreenX = 0;
+ private lastScreenY = 0;
- this._attachedActiveNowTimers = [];
- this._attachedActiveRecentlyTimers = [];
- this._activeNowTimeout = new Timer(CURRENTLY_ACTIVE_THRESHOLD_MS);
- this._activeRecentlyTimeout = new Timer(RECENTLY_ACTIVE_THRESHOLD_MS);
- this._onUserActivity = this._onUserActivity.bind(this);
- this._onWindowBlurred = this._onWindowBlurred.bind(this);
- this._onPageVisibilityChanged = this._onPageVisibilityChanged.bind(this);
- this.lastScreenX = 0;
- this.lastScreenY = 0;
+ constructor(private readonly window: Window, private readonly document: Document) {
+ this.activeNowTimeout = new Timer(CURRENTLY_ACTIVE_THRESHOLD_MS);
+ this.activeRecentlyTimeout = new Timer(RECENTLY_ACTIVE_THRESHOLD_MS);
}
static sharedInstance() {
- if (global.mxUserActivity === undefined) {
- global.mxUserActivity = new UserActivity(window, document);
+ if (window.mxUserActivity === undefined) {
+ window.mxUserActivity = new UserActivity(window, document);
}
- return global.mxUserActivity;
+ return window.mxUserActivity;
}
/**
@@ -69,8 +66,8 @@ export default class UserActivity {
* later on when the user does become active.
* @param {Timer} timer the timer to use
*/
- timeWhileActiveNow(timer) {
- this._timeWhile(timer, this._attachedActiveNowTimers);
+ public timeWhileActiveNow(timer: Timer) {
+ this.timeWhile(timer, this.attachedActiveNowTimers);
if (this.userActiveNow()) {
timer.start();
}
@@ -85,14 +82,14 @@ export default class UserActivity {
* later on when the user does become active.
* @param {Timer} timer the timer to use
*/
- timeWhileActiveRecently(timer) {
- this._timeWhile(timer, this._attachedActiveRecentlyTimers);
+ public timeWhileActiveRecently(timer: Timer) {
+ this.timeWhile(timer, this.attachedActiveRecentlyTimers);
if (this.userActiveRecently()) {
timer.start();
}
}
- _timeWhile(timer, attachedTimers) {
+ private timeWhile(timer: Timer, attachedTimers: Timer[]) {
// important this happens first
const index = attachedTimers.indexOf(timer);
if (index === -1) {
@@ -112,36 +109,36 @@ export default class UserActivity {
/**
* Start listening to user activity
*/
- start() {
- this._document.addEventListener('mousedown', this._onUserActivity);
- this._document.addEventListener('mousemove', this._onUserActivity);
- this._document.addEventListener('keydown', this._onUserActivity);
- this._document.addEventListener("visibilitychange", this._onPageVisibilityChanged);
- this._window.addEventListener("blur", this._onWindowBlurred);
- this._window.addEventListener("focus", this._onUserActivity);
+ public start() {
+ this.document.addEventListener('mousedown', this.onUserActivity);
+ this.document.addEventListener('mousemove', this.onUserActivity);
+ this.document.addEventListener('keydown', this.onUserActivity);
+ this.document.addEventListener("visibilitychange", this.onPageVisibilityChanged);
+ this.window.addEventListener("blur", this.onWindowBlurred);
+ this.window.addEventListener("focus", this.onUserActivity);
// can't use document.scroll here because that's only the document
// itself being scrolled. Need to use addEventListener's useCapture.
// also this needs to be the wheel event, not scroll, as scroll is
// fired when the view scrolls down for a new message.
- this._window.addEventListener('wheel', this._onUserActivity, {
- passive: true, capture: true,
+ this.window.addEventListener('wheel', this.onUserActivity, {
+ passive: true,
+ capture: true,
});
}
/**
* Stop tracking user activity
*/
- stop() {
- this._document.removeEventListener('mousedown', this._onUserActivity);
- this._document.removeEventListener('mousemove', this._onUserActivity);
- this._document.removeEventListener('keydown', this._onUserActivity);
- this._window.removeEventListener('wheel', this._onUserActivity, {
- passive: true, capture: true,
+ public stop() {
+ this.document.removeEventListener('mousedown', this.onUserActivity);
+ this.document.removeEventListener('mousemove', this.onUserActivity);
+ this.document.removeEventListener('keydown', this.onUserActivity);
+ this.window.removeEventListener('wheel', this.onUserActivity, {
+ capture: true,
});
-
- this._document.removeEventListener("visibilitychange", this._onPageVisibilityChanged);
- this._window.removeEventListener("blur", this._onWindowBlurred);
- this._window.removeEventListener("focus", this._onUserActivity);
+ this.document.removeEventListener("visibilitychange", this.onPageVisibilityChanged);
+ this.window.removeEventListener("blur", this.onWindowBlurred);
+ this.window.removeEventListener("focus", this.onUserActivity);
}
/**
@@ -151,8 +148,8 @@ export default class UserActivity {
* user's attention at any given moment.
* @returns {boolean} true if user is currently 'active'
*/
- userActiveNow() {
- return this._activeNowTimeout.isRunning();
+ public userActiveNow() {
+ return this.activeNowTimeout.isRunning();
}
/**
@@ -163,27 +160,27 @@ export default class UserActivity {
* (or they may have gone to make tea and left the window focused).
* @returns {boolean} true if user has been active recently
*/
- userActiveRecently() {
- return this._activeRecentlyTimeout.isRunning();
+ public userActiveRecently() {
+ return this.activeRecentlyTimeout.isRunning();
}
- _onPageVisibilityChanged(e) {
- if (this._document.visibilityState === "hidden") {
- this._activeNowTimeout.abort();
- this._activeRecentlyTimeout.abort();
+ private onPageVisibilityChanged = e => {
+ if (this.document.visibilityState === "hidden") {
+ this.activeNowTimeout.abort();
+ this.activeRecentlyTimeout.abort();
} else {
- this._onUserActivity(e);
+ this.onUserActivity(e);
}
- }
+ };
- _onWindowBlurred() {
- this._activeNowTimeout.abort();
- this._activeRecentlyTimeout.abort();
- }
+ private onWindowBlurred = () => {
+ this.activeNowTimeout.abort();
+ this.activeRecentlyTimeout.abort();
+ };
- _onUserActivity(event) {
+ private onUserActivity = (event: MouseEvent) => {
// ignore anything if the window isn't focused
- if (!this._document.hasFocus()) return;
+ if (!this.document.hasFocus()) return;
if (event.screenX && event.type === "mousemove") {
if (event.screenX === this.lastScreenX && event.screenY === this.lastScreenY) {
@@ -195,25 +192,25 @@ export default class UserActivity {
}
dis.dispatch({action: 'user_activity'});
- if (!this._activeNowTimeout.isRunning()) {
- this._activeNowTimeout.start();
+ if (!this.activeNowTimeout.isRunning()) {
+ this.activeNowTimeout.start();
dis.dispatch({action: 'user_activity_start'});
- this._runTimersUntilTimeout(this._attachedActiveNowTimers, this._activeNowTimeout);
+ UserActivity.runTimersUntilTimeout(this.attachedActiveNowTimers, this.activeNowTimeout);
} else {
- this._activeNowTimeout.restart();
+ this.activeNowTimeout.restart();
}
- if (!this._activeRecentlyTimeout.isRunning()) {
- this._activeRecentlyTimeout.start();
+ if (!this.activeRecentlyTimeout.isRunning()) {
+ this.activeRecentlyTimeout.start();
- this._runTimersUntilTimeout(this._attachedActiveRecentlyTimers, this._activeRecentlyTimeout);
+ UserActivity.runTimersUntilTimeout(this.attachedActiveRecentlyTimers, this.activeRecentlyTimeout);
} else {
- this._activeRecentlyTimeout.restart();
+ this.activeRecentlyTimeout.restart();
}
- }
+ };
- async _runTimersUntilTimeout(attachedTimers, timeout) {
+ private static async runTimersUntilTimeout(attachedTimers: Timer[], timeout: Timer) {
attachedTimers.forEach((t) => t.start());
try {
await timeout.finished();
diff --git a/src/VectorConferenceHandler.js b/src/VectorConferenceHandler.js
deleted file mode 100644
index c10bc659ae..0000000000
--- a/src/VectorConferenceHandler.js
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-Copyright 2015, 2016 OpenMarket Ltd
-Copyright 2019 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import {createNewMatrixCall as jsCreateNewMatrixCall, Room} from "matrix-js-sdk";
-import CallHandler from './CallHandler';
-import {MatrixClientPeg} from "./MatrixClientPeg";
-
-// FIXME: this is Element specific code, but will be removed shortly when we
-// switch over to Jitsi entirely for video conferencing.
-
-// FIXME: This currently forces Element to try to hit the matrix.org AS for
-// conferencing. This is bad because it prevents people running their own ASes
-// from being used. This isn't permanent and will be customisable in the future:
-// see the proposal at docs/conferencing.md for more info.
-const USER_PREFIX = "fs_";
-const DOMAIN = "matrix.org";
-
-export function ConferenceCall(matrixClient, groupChatRoomId) {
- this.client = matrixClient;
- this.groupRoomId = groupChatRoomId;
- this.confUserId = getConferenceUserIdForRoom(this.groupRoomId);
-}
-
-ConferenceCall.prototype.setup = function() {
- const self = this;
- return this._joinConferenceUser().then(function() {
- return self._getConferenceUserRoom();
- }).then(function(room) {
- // return a call for *this* room to be placed. We also tack on
- // confUserId to speed up lookups (else we'd need to loop every room
- // looking for a 1:1 room with this conf user ID!)
- const call = jsCreateNewMatrixCall(self.client, room.roomId);
- call.confUserId = self.confUserId;
- call.groupRoomId = self.groupRoomId;
- return call;
- });
-};
-
-ConferenceCall.prototype._joinConferenceUser = function() {
- // Make sure the conference user is in the group chat room
- const groupRoom = this.client.getRoom(this.groupRoomId);
- if (!groupRoom) {
- return Promise.reject("Bad group room ID");
- }
- const member = groupRoom.getMember(this.confUserId);
- if (member && member.membership === "join") {
- return Promise.resolve();
- }
- return this.client.invite(this.groupRoomId, this.confUserId);
-};
-
-ConferenceCall.prototype._getConferenceUserRoom = function() {
- // Use an existing 1:1 with the conference user; else make one
- const rooms = this.client.getRooms();
- let confRoom = null;
- for (let i = 0; i < rooms.length; i++) {
- const confUser = rooms[i].getMember(this.confUserId);
- if (confUser && confUser.membership === "join" &&
- rooms[i].getJoinedMemberCount() === 2) {
- confRoom = rooms[i];
- break;
- }
- }
- if (confRoom) {
- return Promise.resolve(confRoom);
- }
- return this.client.createRoom({
- preset: "private_chat",
- invite: [this.confUserId],
- }).then(function(res) {
- return new Room(res.room_id, null, MatrixClientPeg.get().getUserId());
- });
-};
-
-/**
- * Check if this user ID is in fact a conference bot.
- * @param {string} userId The user ID to check.
- * @return {boolean} True if it is a conference bot.
- */
-export function isConferenceUser(userId) {
- if (userId.indexOf("@" + USER_PREFIX) !== 0) {
- return false;
- }
- const base64part = userId.split(":")[0].substring(1 + USER_PREFIX.length);
- if (base64part) {
- const decoded = new Buffer(base64part, "base64").toString();
- // ! $STUFF : $STUFF
- return /^!.+:.+/.test(decoded);
- }
- return false;
-}
-
-export function getConferenceUserIdForRoom(roomId) {
- // abuse browserify's core node Buffer support (strip padding ='s)
- const base64RoomId = new Buffer(roomId).toString("base64").replace(/=/g, "");
- return "@" + USER_PREFIX + base64RoomId + ":" + DOMAIN;
-}
-
-export function createNewMatrixCall(client, roomId) {
- const confCall = new ConferenceCall(
- client, roomId,
- );
- return confCall.setup();
-}
-
-export function getConferenceCallForRoom(roomId) {
- // search for a conference 1:1 call for this group chat room ID
- const activeCall = CallHandler.getAnyActiveCall();
- if (activeCall && activeCall.confUserId) {
- const thisRoomConfUserId = getConferenceUserIdForRoom(
- roomId,
- );
- if (thisRoomConfUserId === activeCall.confUserId) {
- return activeCall;
- }
- }
- return null;
-}
-
-// TODO: Document this.
-export const slot = 'conference';
diff --git a/src/VelocityBounce.js b/src/VelocityBounce.js
deleted file mode 100644
index ffbf7de829..0000000000
--- a/src/VelocityBounce.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import Velocity from "velocity-animate";
-
-// courtesy of https://github.com/julianshapiro/velocity/issues/283
-// We only use easeOutBounce (easeInBounce is just sort of nonsensical)
-function bounce( p ) {
- let pow2;
- let bounce = 4;
-
- while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {
- // just sets pow2
- }
- return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
-}
-
-Velocity.Easings.easeOutBounce = function(p) {
- return 1 - bounce(1 - p);
-};
diff --git a/src/VoipUserMapper.ts b/src/VoipUserMapper.ts
new file mode 100644
index 0000000000..e5bed2e812
--- /dev/null
+++ b/src/VoipUserMapper.ts
@@ -0,0 +1,116 @@
+/*
+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 { ensureVirtualRoomExists, findDMForUser } from './createRoom';
+import { MatrixClientPeg } from "./MatrixClientPeg";
+import DMRoomMap from "./utils/DMRoomMap";
+import CallHandler, { VIRTUAL_ROOM_EVENT_TYPE } from './CallHandler';
+import { Room } from 'matrix-js-sdk/src/models/room';
+
+// Functions for mapping virtual users & rooms. Currently the only lookup
+// is sip virtual: there could be others in the future.
+
+export default class VoipUserMapper {
+ private virtualRoomIdCache = new Set();
+
+ public static sharedInstance(): VoipUserMapper {
+ if (window.mxVoipUserMapper === undefined) window.mxVoipUserMapper = new VoipUserMapper();
+ return window.mxVoipUserMapper;
+ }
+
+ private async userToVirtualUser(userId: string): Promise {
+ const results = await CallHandler.sharedInstance().sipVirtualLookup(userId);
+ if (results.length === 0) return null;
+ return results[0].userid;
+ }
+
+ public async getOrCreateVirtualRoomForRoom(roomId: string): Promise {
+ const userId = DMRoomMap.shared().getUserIdForRoomId(roomId);
+ if (!userId) return null;
+
+ const virtualUser = await this.userToVirtualUser(userId);
+ if (!virtualUser) return null;
+
+ const virtualRoomId = await ensureVirtualRoomExists(MatrixClientPeg.get(), virtualUser, roomId);
+ MatrixClientPeg.get().setRoomAccountData(virtualRoomId, VIRTUAL_ROOM_EVENT_TYPE, {
+ native_room: roomId,
+ });
+
+ return virtualRoomId;
+ }
+
+ public nativeRoomForVirtualRoom(roomId: string): string {
+ const virtualRoom = MatrixClientPeg.get().getRoom(roomId);
+ if (!virtualRoom) return null;
+ const virtualRoomEvent = virtualRoom.getAccountData(VIRTUAL_ROOM_EVENT_TYPE);
+ if (!virtualRoomEvent || !virtualRoomEvent.getContent()) return null;
+ const nativeRoomID = virtualRoomEvent.getContent()['native_room'];
+ const nativeRoom = MatrixClientPeg.get().getRoom(nativeRoomID);
+ if (!nativeRoom || nativeRoom.getMyMembership() !== 'join') return null;
+
+ return nativeRoomID;
+ }
+
+ public isVirtualRoom(room: Room): boolean {
+ if (this.nativeRoomForVirtualRoom(room.roomId)) return true;
+
+ if (this.virtualRoomIdCache.has(room.roomId)) return true;
+
+ // also look in the create event for the claimed native room ID, which is the only
+ // way we can recognise a virtual room we've created when it first arrives down
+ // our stream. We don't trust this in general though, as it could be faked by an
+ // inviter: our main source of truth is the DM state.
+ const roomCreateEvent = room.currentState.getStateEvents("m.room.create", "");
+ if (!roomCreateEvent || !roomCreateEvent.getContent()) return false;
+ // we only look at this for rooms we created (so inviters can't just cause rooms
+ // to be invisible)
+ if (roomCreateEvent.getSender() !== MatrixClientPeg.get().getUserId()) return false;
+ const claimedNativeRoomId = roomCreateEvent.getContent()[VIRTUAL_ROOM_EVENT_TYPE];
+ return Boolean(claimedNativeRoomId);
+ }
+
+ public async onNewInvitedRoom(invitedRoom: Room) {
+ if (!CallHandler.sharedInstance().getSupportsVirtualRooms()) return;
+
+ const inviterId = invitedRoom.getDMInviter();
+ console.log(`Checking virtual-ness of room ID ${invitedRoom.roomId}, invited by ${inviterId}`);
+ const result = await CallHandler.sharedInstance().sipNativeLookup(inviterId);
+ if (result.length === 0) {
+ return true;
+ }
+
+ if (result[0].fields.is_virtual) {
+ const nativeUser = result[0].userid;
+ const nativeRoom = findDMForUser(MatrixClientPeg.get(), nativeUser);
+ if (nativeRoom) {
+ // It's a virtual room with a matching native room, so set the room account data. This
+ // will make sure we know where how to map calls and also allow us know not to display
+ // it in the future.
+ MatrixClientPeg.get().setRoomAccountData(invitedRoom.roomId, VIRTUAL_ROOM_EVENT_TYPE, {
+ native_room: nativeRoom.roomId,
+ });
+ // also auto-join the virtual room if we have a matching native room
+ // (possibly we should only join if we've also joined the native room, then we'd also have
+ // to make sure we joined virtual rooms on joining a native one)
+ MatrixClientPeg.get().joinRoom(invitedRoom.roomId);
+ }
+
+ // also put this room in the virtual room ID cache so isVirtualRoom return the right answer
+ // in however long it takes for the echo of setAccountData to come down the sync
+ this.virtualRoomIdCache.add(invitedRoom.roomId);
+ }
+ }
+}
diff --git a/src/WhoIsTyping.js b/src/WhoIsTyping.ts
similarity index 72%
rename from src/WhoIsTyping.js
rename to src/WhoIsTyping.ts
index d11cddf487..a8ca425ea8 100644
--- a/src/WhoIsTyping.js
+++ b/src/WhoIsTyping.ts
@@ -14,19 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+import {Room} from "matrix-js-sdk/src/models/room";
+import {RoomMember} from "matrix-js-sdk/src/models/room-member";
+
import {MatrixClientPeg} from "./MatrixClientPeg";
import { _t } from './languageHandler';
-export function usersTypingApartFromMeAndIgnored(room) {
- return usersTyping(
- room, [MatrixClientPeg.get().credentials.userId].concat(MatrixClientPeg.get().getIgnoredUsers()),
- );
+export function usersTypingApartFromMeAndIgnored(room: Room): RoomMember[] {
+ return usersTyping(room, [MatrixClientPeg.get().getUserId()].concat(MatrixClientPeg.get().getIgnoredUsers()));
}
-export function usersTypingApartFromMe(room) {
- return usersTyping(
- room, [MatrixClientPeg.get().credentials.userId],
- );
+export function usersTypingApartFromMe(room: Room): RoomMember[] {
+ return usersTyping(room, [MatrixClientPeg.get().getUserId()]);
}
/**
@@ -34,15 +33,11 @@ export function usersTypingApartFromMe(room) {
* to exclude, return a list of user objects who are typing.
* @param {Room} room: room object to get users from.
* @param {string[]} exclude: list of user mxids to exclude.
- * @returns {string[]} list of user objects who are typing.
+ * @returns {RoomMember[]} list of user objects who are typing.
*/
-export function usersTyping(room, exclude) {
+export function usersTyping(room: Room, exclude: string[] = []): RoomMember[] {
const whoIsTyping = [];
- if (exclude === undefined) {
- exclude = [];
- }
-
const memberKeys = Object.keys(room.currentState.members);
for (let i = 0; i < memberKeys.length; ++i) {
const userId = memberKeys[i];
@@ -57,20 +52,21 @@ export function usersTyping(room, exclude) {
return whoIsTyping;
}
-export function whoIsTypingString(whoIsTyping, limit) {
+export function whoIsTypingString(whoIsTyping: RoomMember[], limit: number): string {
let othersCount = 0;
if (whoIsTyping.length > limit) {
othersCount = whoIsTyping.length - limit + 1;
}
+
if (whoIsTyping.length === 0) {
return '';
} else if (whoIsTyping.length === 1) {
return _t('%(displayName)s is typing …', {displayName: whoIsTyping[0].name});
}
- const names = whoIsTyping.map(function(m) {
- return m.name;
- });
- if (othersCount>=1) {
+
+ const names = whoIsTyping.map(m => m.name);
+
+ if (othersCount >= 1) {
return _t('%(names)s and %(count)s others are typing …', {
names: names.slice(0, limit - 1).join(', '),
count: othersCount,
diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js
deleted file mode 100644
index 6aed08c39d..0000000000
--- a/src/WidgetMessaging.js
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
-Copyright 2017 New Vector Ltd
-Copyright 2019 Travis Ralston
-
-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.
-*/
-
-/*
-* See - https://docs.google.com/document/d/1uPF7XWY_dXTKVKV7jZQ2KmsI19wn9-kFRgQ1tFQP7wQ/edit?usp=sharing for
-* spec. details / documentation.
-*/
-
-import FromWidgetPostMessageApi from './FromWidgetPostMessageApi';
-import ToWidgetPostMessageApi from './ToWidgetPostMessageApi';
-import Modal from "./Modal";
-import {MatrixClientPeg} from "./MatrixClientPeg";
-import SettingsStore from "./settings/SettingsStore";
-import WidgetOpenIDPermissionsDialog from "./components/views/dialogs/WidgetOpenIDPermissionsDialog";
-import WidgetUtils from "./utils/WidgetUtils";
-import {KnownWidgetActions} from "./widgets/WidgetApi";
-
-if (!global.mxFromWidgetMessaging) {
- global.mxFromWidgetMessaging = new FromWidgetPostMessageApi();
- global.mxFromWidgetMessaging.start();
-}
-if (!global.mxToWidgetMessaging) {
- global.mxToWidgetMessaging = new ToWidgetPostMessageApi();
- global.mxToWidgetMessaging.start();
-}
-
-const OUTBOUND_API_NAME = 'toWidget';
-
-export default class WidgetMessaging {
- /**
- * @param {string} widgetId The widget's ID
- * @param {string} wurl The raw URL of the widget as in the event (the 'wURL')
- * @param {string} renderedUrl The url used in the widget's iframe (either similar to the wURL
- * or a different URL of the clients choosing if it is using its own impl).
- * @param {bool} isUserWidget If true, the widget is a user widget, otherwise it's a room widget
- * @param {object} target Where widget messages should be sent (eg. the iframe object)
- */
- constructor(widgetId, wurl, renderedUrl, isUserWidget, target) {
- this.widgetId = widgetId;
- this.wurl = wurl;
- this.renderedUrl = renderedUrl;
- this.isUserWidget = isUserWidget;
- this.target = target;
- this.fromWidget = global.mxFromWidgetMessaging;
- this.toWidget = global.mxToWidgetMessaging;
- this._onOpenIdRequest = this._onOpenIdRequest.bind(this);
- this.start();
- }
-
- messageToWidget(action) {
- action.widgetId = this.widgetId; // Required to be sent for all outbound requests
-
- return this.toWidget.exec(action, this.target).then((data) => {
- // Check for errors and reject if found
- if (data.response === undefined) { // null is valid
- throw new Error("Missing 'response' field");
- }
- if (data.response && data.response.error) {
- const err = data.response.error;
- const msg = String(err.message ? err.message : "An error was returned");
- if (err._error) {
- console.error(err._error);
- }
- // Potential XSS attack if 'msg' is not appropriately sanitized,
- // as it is untrusted input by our parent window (which we assume is Element).
- // We can't aggressively sanitize [A-z0-9] since it might be a translation.
- throw new Error(msg);
- }
- // Return the response field for the request
- return data.response;
- });
- }
-
- /**
- * Tells the widget that the client is ready to handle further widget requests.
- * @returns {Promise<*>} Resolves after the widget has acknowledged the ready message.
- */
- flagReadyToContinue() {
- return this.messageToWidget({
- api: OUTBOUND_API_NAME,
- action: KnownWidgetActions.ClientReady,
- });
- }
-
- /**
- * Tells the widget that it should terminate now.
- * @returns {Promise<*>} Resolves when widget has acknowledged the message.
- */
- terminate() {
- return this.messageToWidget({
- api: OUTBOUND_API_NAME,
- action: KnownWidgetActions.Terminate,
- });
- }
-
- /**
- * Request a screenshot from a widget
- * @return {Promise} To be resolved with screenshot data when it has been generated
- */
- getScreenshot() {
- console.log('Requesting screenshot for', this.widgetId);
- return this.messageToWidget({
- api: OUTBOUND_API_NAME,
- action: "screenshot",
- })
- .catch((error) => new Error("Failed to get screenshot: " + error.message))
- .then((response) => response.screenshot);
- }
-
- /**
- * Request capabilities required by the widget
- * @return {Promise} To be resolved with an array of requested widget capabilities
- */
- getCapabilities() {
- console.log('Requesting capabilities for', this.widgetId);
- return this.messageToWidget({
- api: OUTBOUND_API_NAME,
- action: "capabilities",
- }).then((response) => {
- console.log('Got capabilities for', this.widgetId, response.capabilities);
- return response.capabilities;
- });
- }
-
- sendVisibility(visible) {
- return this.messageToWidget({
- api: OUTBOUND_API_NAME,
- action: "visibility",
- visible,
- })
- .catch((error) => {
- console.error("Failed to send visibility: ", error);
- });
- }
-
- start() {
- this.fromWidget.addEndpoint(this.widgetId, this.renderedUrl);
- this.fromWidget.addListener("get_openid", this._onOpenIdRequest);
- }
-
- stop() {
- this.fromWidget.removeEndpoint(this.widgetId, this.renderedUrl);
- this.fromWidget.removeListener("get_openid", this._onOpenIdRequest);
- }
-
- async _onOpenIdRequest(ev, rawEv) {
- if (ev.widgetId !== this.widgetId) return; // not interesting
-
- const widgetSecurityKey = WidgetUtils.getWidgetSecurityKey(this.widgetId, this.wurl, this.isUserWidget);
-
- const settings = SettingsStore.getValue("widgetOpenIDPermissions");
- if (settings.deny && settings.deny.includes(widgetSecurityKey)) {
- this.fromWidget.sendResponse(rawEv, {state: "blocked"});
- return;
- }
- if (settings.allow && settings.allow.includes(widgetSecurityKey)) {
- const responseBody = {state: "allowed"};
- const credentials = await MatrixClientPeg.get().getOpenIdToken();
- Object.assign(responseBody, credentials);
- this.fromWidget.sendResponse(rawEv, responseBody);
- return;
- }
-
- // Confirm that we received the request
- this.fromWidget.sendResponse(rawEv, {state: "request"});
-
- // Actually ask for permission to send the user's data
- Modal.createTrackedDialog("OpenID widget permissions", '',
- WidgetOpenIDPermissionsDialog, {
- widgetUrl: this.wurl,
- widgetId: this.widgetId,
- isUserWidget: this.isUserWidget,
-
- onFinished: async (confirm) => {
- const responseBody = {success: confirm};
- if (confirm) {
- const credentials = await MatrixClientPeg.get().getOpenIdToken();
- Object.assign(responseBody, credentials);
- }
- this.messageToWidget({
- api: OUTBOUND_API_NAME,
- action: "openid_credentials",
- data: responseBody,
- }).catch((error) => {
- console.error("Failed to send OpenID credentials: ", error);
- });
- },
- },
- );
- }
-}
diff --git a/src/WidgetMessagingEndpoint.js b/src/WidgetMessagingEndpoint.js
deleted file mode 100644
index 9114e12137..0000000000
--- a/src/WidgetMessagingEndpoint.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-Copyright 2018 New Vector Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-
-/**
- * Represents mapping of widget instance to URLs for trusted postMessage communication.
- */
-export default class WidgetMessageEndpoint {
- /**
- * Mapping of widget instance to URL for trusted postMessage communication.
- * @param {string} widgetId Unique widget identifier
- * @param {string} endpointUrl Widget wurl origin.
- */
- constructor(widgetId, endpointUrl) {
- if (!widgetId) {
- throw new Error("No widgetId specified in widgetMessageEndpoint constructor");
- }
- if (!endpointUrl) {
- throw new Error("No endpoint specified in widgetMessageEndpoint constructor");
- }
- this.widgetId = widgetId;
- this.endpointUrl = endpointUrl;
- }
-}
diff --git a/src/accessibility/KeyboardShortcuts.tsx b/src/accessibility/KeyboardShortcuts.tsx
index f527ab4a14..2a3e576e31 100644
--- a/src/accessibility/KeyboardShortcuts.tsx
+++ b/src/accessibility/KeyboardShortcuts.tsx
@@ -168,7 +168,13 @@ const shortcuts: Record = {
key: Key.U,
}],
description: _td("Upload a file"),
- }
+ }, {
+ keybinds: [{
+ modifiers: [CMD_OR_CTRL],
+ key: Key.F,
+ }],
+ description: _td("Search (must be enabled)"),
+ },
],
[Categories.ROOM_LIST]: [
@@ -257,6 +263,12 @@ const shortcuts: Record = {
key: Key.SLASH,
}],
description: _td("Toggle this dialog"),
+ }, {
+ keybinds: [{
+ modifiers: [Modifiers.CONTROL, isMac ? Modifiers.SHIFT : Modifiers.ALT],
+ key: Key.H,
+ }],
+ description: _td("Go to Home View"),
},
],
diff --git a/src/accessibility/RovingTabIndex.tsx b/src/accessibility/RovingTabIndex.tsx
index 5a650d4b6e..4cb537f318 100644
--- a/src/accessibility/RovingTabIndex.tsx
+++ b/src/accessibility/RovingTabIndex.tsx
@@ -166,7 +166,8 @@ export const RovingTabIndexProvider: React.FC = ({children, handleHomeEn
const onKeyDownHandler = useCallback((ev) => {
let handled = false;
- if (handleHomeEnd) {
+ // Don't interfere with input default keydown behaviour
+ if (handleHomeEnd && ev.target.tagName !== "INPUT" && ev.target.tagName !== "TEXTAREA") {
// check if we actually have any items
switch (ev.key) {
case Key.HOME:
@@ -190,7 +191,7 @@ export const RovingTabIndexProvider: React.FC = ({children, handleHomeEn
ev.preventDefault();
ev.stopPropagation();
} else if (onKeyDown) {
- return onKeyDown(ev, state);
+ return onKeyDown(ev, context.state);
}
}, [context.state, onKeyDown, handleHomeEnd]);
@@ -204,7 +205,7 @@ export const RovingTabIndexProvider: React.FC = ({children, handleHomeEn
// onFocus should be called when the index gained focus in any manner
// isActive should be used to set tabIndex in a manner such as `tabIndex={isActive ? 0 : -1}`
// ref should be passed to a DOM node which will be used for DOM compareDocumentPosition
-export const useRovingTabIndex = (inputRef: Ref): [FocusHandler, boolean, Ref] => {
+export const useRovingTabIndex = (inputRef?: Ref): [FocusHandler, boolean, Ref] => {
const context = useContext(RovingTabIndexContext);
let ref = useRef(null);
diff --git a/src/accessibility/Toolbar.tsx b/src/accessibility/Toolbar.tsx
index 0e968461a8..e756d948e5 100644
--- a/src/accessibility/Toolbar.tsx
+++ b/src/accessibility/Toolbar.tsx
@@ -28,8 +28,12 @@ interface IProps extends Omit, "onKeyDown"> {
const Toolbar: React.FC = ({children, ...props}) => {
const onKeyDown = (ev: React.KeyboardEvent, state: IState) => {
const target = ev.target as HTMLElement;
+ // Don't interfere with input default keydown behaviour
+ if (target.tagName === "INPUT") return;
+
let handled = true;
+ // HOME and END are handled by RovingTabIndexProvider
switch (ev.key) {
case Key.ARROW_UP:
case Key.ARROW_DOWN:
@@ -47,8 +51,6 @@ const Toolbar: React.FC = ({children, ...props}) => {
}
break;
- // HOME and END are handled by RovingTabIndexProvider
-
default:
handled = false;
}
diff --git a/src/accessibility/context_menu/ContextMenuTooltipButton.tsx b/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
index abc5412100..49f57ca7b6 100644
--- a/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
+++ b/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
@@ -20,7 +20,7 @@ import React from "react";
import AccessibleTooltipButton from "../../components/views/elements/AccessibleTooltipButton";
-interface IProps extends React.ComponentProps {
+interface IProps extends React.ComponentProps {
// whether or not the context menu is currently open
isExpanded: boolean;
}
diff --git a/src/accessibility/context_menu/MenuItem.tsx b/src/accessibility/context_menu/MenuItem.tsx
index 64233e51ad..9a7c1d1f0a 100644
--- a/src/accessibility/context_menu/MenuItem.tsx
+++ b/src/accessibility/context_menu/MenuItem.tsx
@@ -19,15 +19,25 @@ limitations under the License.
import React from "react";
import AccessibleButton from "../../components/views/elements/AccessibleButton";
+import AccessibleTooltipButton from "../../components/views/elements/AccessibleTooltipButton";
interface IProps extends React.ComponentProps {
label?: string;
+ tooltip?: string;
}
// Semantic component for representing a role=menuitem
-export const MenuItem: React.FC = ({children, label, ...props}) => {
+export const MenuItem: React.FC = ({children, label, tooltip, ...props}) => {
+ const ariaLabel = props["aria-label"] || label;
+
+ if (tooltip) {
+ return
+ { children }
+ ;
+ }
+
return (
-
+
{ children }
);
diff --git a/src/accessibility/roving/RovingAccessibleTooltipButton.tsx b/src/accessibility/roving/RovingAccessibleTooltipButton.tsx
index cc824fef22..2cb974d60e 100644
--- a/src/accessibility/roving/RovingAccessibleTooltipButton.tsx
+++ b/src/accessibility/roving/RovingAccessibleTooltipButton.tsx
@@ -20,7 +20,8 @@ import AccessibleTooltipButton from "../../components/views/elements/AccessibleT
import {useRovingTabIndex} from "../RovingTabIndex";
import {Ref} from "./types";
-interface IProps extends Omit, "onFocus" | "inputRef" | "tabIndex"> {
+type ATBProps = React.ComponentProps;
+interface IProps extends Omit {
inputRef?: Ref;
}
diff --git a/src/accessibility/roving/RovingTabIndexWrapper.tsx b/src/accessibility/roving/RovingTabIndexWrapper.tsx
index c826b74497..5211f30215 100644
--- a/src/accessibility/roving/RovingTabIndexWrapper.tsx
+++ b/src/accessibility/roving/RovingTabIndexWrapper.tsx
@@ -16,7 +16,6 @@ limitations under the License.
import React from "react";
-import AccessibleButton from "../../components/views/elements/AccessibleButton";
import {useRovingTabIndex} from "../RovingTabIndex";
import {FocusHandler, Ref} from "./types";
diff --git a/src/actions/TagOrderActions.ts b/src/actions/TagOrderActions.ts
index c203172874..021cd11b55 100644
--- a/src/actions/TagOrderActions.ts
+++ b/src/actions/TagOrderActions.ts
@@ -17,14 +17,14 @@ limitations under the License.
import Analytics from '../Analytics';
import { asyncAction } from './actionCreators';
-import TagOrderStore from '../stores/TagOrderStore';
+import GroupFilterOrderStore from '../stores/GroupFilterOrderStore';
import { AsyncActionPayload } from "../dispatcher/payloads";
import { MatrixClient } from "matrix-js-sdk/src/client";
export default class TagOrderActions {
/**
* Creates an action thunk that will do an asynchronous request to
- * move a tag in TagOrderStore to destinationIx.
+ * move a tag in GroupFilterOrderStore to destinationIx.
*
* @param {MatrixClient} matrixClient the matrix client to set the
* account data on.
@@ -36,8 +36,8 @@ export default class TagOrderActions {
*/
public static moveTag(matrixClient: MatrixClient, tag: string, destinationIx: number): AsyncActionPayload {
// Only commit tags if the state is ready, i.e. not null
- let tags = TagOrderStore.getOrderedTags();
- let removedTags = TagOrderStore.getRemovedTagsAccountData() || [];
+ let tags = GroupFilterOrderStore.getOrderedTags();
+ let removedTags = GroupFilterOrderStore.getRemovedTagsAccountData() || [];
if (!tags) {
return;
}
@@ -47,7 +47,7 @@ export default class TagOrderActions {
removedTags = removedTags.filter((t) => t !== tag);
- const storeId = TagOrderStore.getStoreId();
+ const storeId = GroupFilterOrderStore.getStoreId();
return asyncAction('TagOrderActions.moveTag', () => {
Analytics.trackEvent('TagOrderActions', 'commitTagOrdering');
@@ -83,8 +83,8 @@ export default class TagOrderActions {
*/
public static removeTag(matrixClient: MatrixClient, tag: string): AsyncActionPayload {
// Don't change tags, just removedTags
- const tags = TagOrderStore.getOrderedTags();
- const removedTags = TagOrderStore.getRemovedTagsAccountData() || [];
+ const tags = GroupFilterOrderStore.getOrderedTags();
+ const removedTags = GroupFilterOrderStore.getRemovedTagsAccountData() || [];
if (removedTags.includes(tag)) {
// Return a thunk that doesn't do anything, we don't even need
@@ -94,7 +94,7 @@ export default class TagOrderActions {
removedTags.push(tag);
- const storeId = TagOrderStore.getStoreId();
+ const storeId = GroupFilterOrderStore.getStoreId();
return asyncAction('TagOrderActions.removeTag', () => {
Analytics.trackEvent('TagOrderActions', 'removeTag');
diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx
similarity index 90%
rename from src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js
rename to src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx
index be3368b87b..0710c513da 100644
--- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js
+++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx
@@ -1,5 +1,5 @@
/*
-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.
@@ -16,7 +16,6 @@ limitations under the License.
import React from 'react';
import * as sdk from '../../../../index';
-import PropTypes from 'prop-types';
import { _t } from '../../../../languageHandler';
import SdkConfig from '../../../../SdkConfig';
import SettingsStore from "../../../../settings/SettingsStore";
@@ -26,14 +25,23 @@ import {formatBytes, formatCountLong} from "../../../../utils/FormattingUtils";
import EventIndexPeg from "../../../../indexing/EventIndexPeg";
import {SettingLevel} from "../../../../settings/SettingLevel";
+interface IProps {
+ onFinished: (confirmed: boolean) => void;
+}
+
+interface IState {
+ eventIndexSize: number;
+ eventCount: number;
+ crawlingRoomsCount: number;
+ roomCount: number;
+ currentRoom: string;
+ crawlerSleepTime: number;
+}
+
/*
* Allows the user to introspect the event index state and disable it.
*/
-export default class ManageEventIndexDialog extends React.Component {
- static propTypes = {
- onFinished: PropTypes.func.isRequired,
- };
-
+export default class ManageEventIndexDialog extends React.Component {
constructor(props) {
super(props);
@@ -84,7 +92,7 @@ export default class ManageEventIndexDialog extends React.Component {
}
}
- async componentDidMount(): void {
+ async componentDidMount(): Promise {
let eventIndexSize = 0;
let crawlingRoomsCount = 0;
let roomCount = 0;
@@ -123,14 +131,14 @@ export default class ManageEventIndexDialog extends React.Component {
});
}
- _onDisable = async () => {
+ private onDisable = async () => {
Modal.createTrackedDialogAsync("Disable message search", "Disable message search",
import("./DisableEventIndexDialog"),
null, null, /* priority = */ false, /* static = */ true,
);
};
- _onCrawlerSleepTimeChange = (e) => {
+ private onCrawlerSleepTimeChange = (e) => {
this.setState({crawlerSleepTime: e.target.value});
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value);
};
@@ -144,7 +152,7 @@ export default class ManageEventIndexDialog extends React.Component {
crawlerState = _t("Not currently indexing messages for any room.");
} else {
crawlerState = (
- _t("Currently indexing: %(currentRoom)s", { currentRoom: this.state.currentRoom })
+ _t("Currently indexing: %(currentRoom)s", { currentRoom: this.state.currentRoom })
);
}
@@ -169,7 +177,7 @@ export default class ManageEventIndexDialog extends React.Component {
label={_t('Message downloading sleep time(ms)')}
type='number'
value={this.state.crawlerSleepTime}
- onChange={this._onCrawlerSleepTimeChange} />
+ onChange={this.onCrawlerSleepTimeChange} />
);
@@ -188,7 +196,7 @@ export default class ManageEventIndexDialog extends React.Component {
onPrimaryButtonClick={this.props.onFinished}
primaryButtonClass="primary"
cancelButton={_t("Disable")}
- onCancel={this._onDisable}
+ onCancel={this.onDisable}
cancelButtonClass="danger"
/>
diff --git a/src/async-components/views/dialogs/keybackup/IgnoreRecoveryReminderDialog.js b/src/async-components/views/dialogs/keybackup/IgnoreRecoveryReminderDialog.js
deleted file mode 100644
index b79911c66e..0000000000
--- a/src/async-components/views/dialogs/keybackup/IgnoreRecoveryReminderDialog.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-Copyright 2018 New Vector Ltd
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import React from "react";
-import PropTypes from "prop-types";
-import * as sdk from "../../../../index";
-import { _t } from "../../../../languageHandler";
-
-export default class IgnoreRecoveryReminderDialog extends React.PureComponent {
- static propTypes = {
- onDontAskAgain: PropTypes.func.isRequired,
- onFinished: PropTypes.func.isRequired,
- onSetup: PropTypes.func.isRequired,
- }
-
- onDontAskAgainClick = () => {
- this.props.onFinished();
- this.props.onDontAskAgain();
- }
-
- onSetupClick = () => {
- this.props.onFinished();
- this.props.onSetup();
- }
-
- render() {
- const BaseDialog = sdk.getComponent("views.dialogs.BaseDialog");
- const DialogButtons = sdk.getComponent("views.elements.DialogButtons");
-
- return (
-
-
-
{_t(
- "Without setting up Secure Message Recovery, " +
- "you'll lose your secure message history when you " +
- "log out.",
- )}
-
{_t(
- "If you don't want to set this up now, you can later " +
- "in Settings.",
- )}
-
-
-
-
-
- );
- }
-}
diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.js
similarity index 93%
rename from src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
rename to src/async-components/views/dialogs/security/CreateKeyBackupDialog.js
index c3aef9109a..549494b5cb 100644
--- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
+++ b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.js
@@ -21,7 +21,7 @@ import * as sdk from '../../../../index';
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
import PropTypes from 'prop-types';
import {_t, _td} from '../../../../languageHandler';
-import { accessSecretStorage } from '../../../../CrossSigningManager';
+import { accessSecretStorage } from '../../../../SecurityManager';
import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
import {copyNode} from "../../../../utils/strings";
import PassphraseField from "../../../../components/views/auth/PassphraseField";
@@ -95,7 +95,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
const blob = new Blob([this._keyBackupInfo.recovery_key], {
type: 'text/plain;charset=us-ascii',
});
- FileSaver.saveAs(blob, 'recovery-key.txt');
+ FileSaver.saveAs(blob, 'security-key.txt');
this.setState({
downloaded: true,
@@ -238,7 +238,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
)}
{_t(
"We'll store an encrypted copy of your keys on our server. " +
- "Secure your backup with a recovery passphrase.",
+ "Secure your backup with a Security Phrase.",
)}
{_t("For maximum security, this should be different from your account password.")}
@@ -252,10 +252,10 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
onValidate={this._onPassPhraseValidate}
fieldRef={this._passphraseField}
autoFocus={true}
- label={_td("Enter a recovery passphrase")}
- labelEnterPassword={_td("Enter a recovery passphrase")}
- labelStrongPassword={_td("Great! This recovery passphrase looks strong enough.")}
- labelAllowedButUnsafe={_td("Great! This recovery passphrase looks strong enough.")}
+ label={_td("Enter a Security Phrase")}
+ labelEnterPassword={_td("Enter a Security Phrase")}
+ labelStrongPassword={_td("Great! This Security Phrase looks strong enough.")}
+ labelAllowedButUnsafe={_td("Great! This Security Phrase looks strong enough.")}
/>
@@ -270,7 +270,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
{_t("Advanced")}
- {_t("Set up with a recovery key")}
+ {_t("Set up with a Security Key")}
;
@@ -310,7 +310,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
return