Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into add-invite-to-context-menu
1
.gitignore
vendored
|
@ -13,3 +13,4 @@ package-lock.json
|
|||
/src/component-index.js
|
||||
|
||||
.DS_Store
|
||||
*.tmp
|
||||
|
|
285
CHANGELOG.md
|
@ -1,3 +1,288 @@
|
|||
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 low severity issue (CVE-2021-21320) where the
|
||||
user content sandbox can be abused to trick users into opening unexpected
|
||||
documents. The content is opened with a `blob` origin that cannot access Matrix
|
||||
user data, so messages and secrets are not at risk. 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 <code> 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)
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
};
|
||||
|
|
19
docs/media-handling.md
Normal file
|
@ -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.
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "matrix-react-sdk",
|
||||
"version": "3.13.1",
|
||||
"version": "3.16.0",
|
||||
"description": "SDK for matrix.org using React",
|
||||
"author": "matrix.org",
|
||||
"repository": {
|
||||
|
@ -86,7 +86,6 @@
|
|||
"pako": "^2.0.3",
|
||||
"parse5": "^6.0.1",
|
||||
"png-chunks-extract": "^1.0.0",
|
||||
"project-name-generator": "^2.1.9",
|
||||
"prop-types": "^15.7.2",
|
||||
"qrcode": "^1.4.4",
|
||||
"qs": "^6.9.6",
|
||||
|
@ -102,7 +101,7 @@
|
|||
"tar-js": "^0.3.0",
|
||||
"text-encoding-utf-8": "^1.0.2",
|
||||
"url": "^0.11.0",
|
||||
"velocity-animate": "^1.5.2",
|
||||
"velocity-animate": "^2.0.6",
|
||||
"what-input": "^5.2.10",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
|
@ -158,6 +157,7 @@
|
|||
"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",
|
||||
"olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz",
|
||||
|
|
|
@ -489,54 +489,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 {
|
||||
|
@ -606,6 +558,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 {
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
@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/_ToastContainer.scss";
|
||||
@import "./structures/_UploadBar.scss";
|
||||
|
@ -56,6 +59,7 @@
|
|||
@import "./views/context_menus/_MessageContextMenu.scss";
|
||||
@import "./views/context_menus/_StatusMessageContextMenu.scss";
|
||||
@import "./views/context_menus/_TagTileContextMenu.scss";
|
||||
@import "./views/dialogs/_AddExistingToSpaceDialog.scss";
|
||||
@import "./views/dialogs/_AddressPickerDialog.scss";
|
||||
@import "./views/dialogs/_Analytics.scss";
|
||||
@import "./views/dialogs/_BugReportDialog.scss";
|
||||
|
@ -89,6 +93,7 @@
|
|||
@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/_UploadConfirmDialog.scss";
|
||||
|
@ -212,6 +217,7 @@
|
|||
@import "./views/settings/_DevicesPanel.scss";
|
||||
@import "./views/settings/_E2eAdvancedPanel.scss";
|
||||
@import "./views/settings/_EmailAddresses.scss";
|
||||
@import "./views/settings/_SpellCheckLanguages.scss";
|
||||
@import "./views/settings/_IntegrationManager.scss";
|
||||
@import "./views/settings/_Notifications.scss";
|
||||
@import "./views/settings/_PhoneNumbers.scss";
|
||||
|
@ -232,6 +238,9 @@
|
|||
@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";
|
||||
|
|
|
@ -15,10 +15,12 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
$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 GroupFilterPanel and the room list
|
||||
|
@ -37,18 +39,12 @@ $groupFilterPanelWidth: 56px; // only applies in this file, used for calculation
|
|||
// GroupFilterPanel handles its own CSS
|
||||
}
|
||||
|
||||
&:not(.mx_LeftPanel_hasGroupFilterPanel) {
|
||||
.mx_LeftPanel_roomListContainer {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// 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% - $groupFilterPanelWidth);
|
||||
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;
|
||||
|
@ -168,17 +164,10 @@ $groupFilterPanelWidth: 56px; // only applies in this file, used for calculation
|
|||
// 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_hasGroupFilterPanel {
|
||||
width: calc(68px + $groupFilterPanelWidth) !important;
|
||||
}
|
||||
&:not(.mx_LeftPanel_hasGroupFilterPanel) {
|
||||
width: 68px !important;
|
||||
}
|
||||
width: unset !important;
|
||||
|
||||
.mx_LeftPanel_roomListContainer {
|
||||
width: 68px;
|
||||
width: $roomListCollapsedWidth;
|
||||
|
||||
.mx_LeftPanel_userHeader {
|
||||
flex-direction: row;
|
||||
|
|
|
@ -18,6 +18,7 @@ limitations under the License.
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -160,3 +160,20 @@ limitations under the License.
|
|||
mask-position: center;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_RightPanel_scopeHeader {
|
||||
margin: 24px;
|
||||
text-align: center;
|
||||
font-weight: $font-semi-bold;
|
||||
font-size: $font-18px;
|
||||
line-height: $font-22px;
|
||||
|
||||
.mx_BaseAvatar {
|
||||
margin-right: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_BaseAvatar_image {
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
357
res/css/structures/_SpacePanel.scss
Normal file
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
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;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.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;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.mx_AutoHideScrollbar {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.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.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;
|
||||
margin-bottom: 2px;
|
||||
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;
|
||||
// negative margin to place it correctly even with the complex
|
||||
// 4px selection border each space button has when active
|
||||
margin-right: -4px;
|
||||
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;
|
||||
height: 16px;
|
||||
|
||||
// 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-left: 7px;
|
||||
margin-right: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
.mx_SpaceButton {
|
||||
.mx_SpacePanel_badgeContainer {
|
||||
right: -3px;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
&.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: -6px;
|
||||
top: -6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.collapsed) {
|
||||
.mx_SpacePanel_badgeContainer {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
}
|
||||
|
||||
.mx_SpaceButton:hover,
|
||||
.mx_SpaceButton:focus-within,
|
||||
.mx_SpaceButton_hasMenuOpen {
|
||||
// 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_iconHome::before {
|
||||
mask-image: url('$(res)/img/element-icons/roomlist/home.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/plus.svg');
|
||||
}
|
||||
|
||||
.mx_SpacePanel_iconExplore::before {
|
||||
mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.mx_SpacePanel_sharePublicSpace {
|
||||
margin: 0;
|
||||
}
|
229
res/css/structures/_SpaceRoomDirectory.scss
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
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_Dialog_title {
|
||||
display: flex;
|
||||
|
||||
.mx_BaseAvatar {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.mx_BaseAvatar_image {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
> div {
|
||||
> h1 {
|
||||
font-weight: $font-semi-bold;
|
||||
font-size: $font-18px;
|
||||
line-height: $font-22px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
> div {
|
||||
color: $secondary-fg-color;
|
||||
font-size: $font-15px;
|
||||
line-height: $font-24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_Dialog_content {
|
||||
// TODO fix scrollbar
|
||||
//display: flex;
|
||||
//flex-direction: column;
|
||||
//height: calc(100% - 80px);
|
||||
|
||||
.mx_AccessibleButton_kind_link {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mx_SearchBox {
|
||||
margin: 24px 0 28px;
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_listHeader {
|
||||
display: flex;
|
||||
font-size: $font-12px;
|
||||
line-height: $font-15px;
|
||||
color: $secondary-fg-color;
|
||||
|
||||
.mx_FormButton {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
> span {
|
||||
margin: auto 0 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_list {
|
||||
margin-top: 8px;
|
||||
|
||||
.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 {
|
||||
margin-top: 8px;
|
||||
|
||||
.mx_SpaceRoomDirectory_subspace_info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
color: $secondary-fg-color;
|
||||
font-weight: $font-semi-bold;
|
||||
font-size: $font-12px;
|
||||
line-height: $font-15px;
|
||||
|
||||
.mx_BaseAvatar {
|
||||
margin-right: 12px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_BaseAvatar_image {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_actions {
|
||||
text-align: right;
|
||||
height: min-content;
|
||||
margin-left: auto;
|
||||
margin-right: 16px;
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_subspace_children {
|
||||
margin-left: 12px;
|
||||
border-left: 2px solid $space-button-outline-color;
|
||||
padding-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_roomTile {
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid $space-button-outline-color;
|
||||
margin: 8px 0 16px;
|
||||
display: flex;
|
||||
min-height: 76px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.mx_AccessibleButton:hover {
|
||||
background-color: rgba(141, 151, 165, 0.1);
|
||||
}
|
||||
|
||||
.mx_BaseAvatar {
|
||||
margin-right: 16px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_roomTile_info {
|
||||
display: inline-block;
|
||||
font-size: $font-15px;
|
||||
flex-grow: 1;
|
||||
height: min-content;
|
||||
margin: auto 0;
|
||||
|
||||
.mx_SpaceRoomDirectory_roomTile_name {
|
||||
font-weight: $font-semi-bold;
|
||||
line-height: $font-18px;
|
||||
}
|
||||
.mx_SpaceRoomDirectory_roomTile_topic {
|
||||
line-height: $font-24px;
|
||||
color: $secondary-fg-color;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_roomTile_memberCount {
|
||||
position: relative;
|
||||
margin: auto 0 auto 24px;
|
||||
padding: 0 0 0 28px;
|
||||
line-height: $font-24px;
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
mask-position: center;
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
background-color: $secondary-fg-color;
|
||||
mask-image: url('$(res)/img/element-icons/community-members.svg');
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_actions {
|
||||
width: 180px;
|
||||
text-align: right;
|
||||
margin-left: 28px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
.mx_AccessibleButton {
|
||||
vertical-align: middle;
|
||||
|
||||
& + .mx_AccessibleButton {
|
||||
margin-left: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_actions {
|
||||
.mx_SpaceRoomDirectory_actionsText {
|
||||
font-weight: normal;
|
||||
font-size: $font-12px;
|
||||
line-height: $font-15px;
|
||||
color: $secondary-fg-color;
|
||||
}
|
||||
}
|
||||
}
|
437
res/css/structures/_SpaceRoomView.scss
Normal file
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
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;
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.mx_SpaceRoomView_buttons {
|
||||
display: block;
|
||||
margin-top: 44px;
|
||||
width: $SpaceRoomViewInnerWidth;
|
||||
text-align: right; // button alignment right
|
||||
|
||||
.mx_FormButton {
|
||||
padding: 8px 22px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.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: 1px solid $input-border-color;
|
||||
border-radius: 8px;
|
||||
|
||||
.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_info {
|
||||
color: $tertiary-fg-color;
|
||||
font-size: $font-15px;
|
||||
line-height: $font-24px;
|
||||
margin: 20px 0;
|
||||
|
||||
.mx_SpaceRoomView_preview_info_public,
|
||||
.mx_SpaceRoomView_preview_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_preview_info_public::before {
|
||||
mask-size: 12px;
|
||||
mask-image: url("$(res)/img/globe.svg");
|
||||
}
|
||||
|
||||
.mx_SpaceRoomView_preview_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_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_memberCount {
|
||||
position: relative;
|
||||
margin-left: 24px;
|
||||
padding: 0 0 0 28px;
|
||||
line-height: $font-24px;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
mask-position: center;
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
background-color: $accent-color;
|
||||
mask-image: url('$(res)/img/element-icons/community-members.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceRoomView_landing_topic {
|
||||
font-size: $font-15px;
|
||||
}
|
||||
|
||||
.mx_SpaceRoomView_landing_adminButtons {
|
||||
margin-top: 32px;
|
||||
|
||||
.mx_AccessibleButton {
|
||||
position: relative;
|
||||
width: 160px;
|
||||
height: 124px;
|
||||
box-sizing: border-box;
|
||||
padding: 72px 16px 0;
|
||||
border-radius: 12px;
|
||||
border: 1px solid $space-button-outline-color;
|
||||
margin-right: 28px;
|
||||
margin-bottom: 28px;
|
||||
font-size: $font-14px;
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(141, 151, 165, 0.1);
|
||||
}
|
||||
|
||||
&::before, &::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
left: 16px;
|
||||
top: 16px;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
mask-position: center;
|
||||
mask-size: 30px;
|
||||
mask-repeat: no-repeat;
|
||||
background: #ffffff; // white icon fill
|
||||
}
|
||||
|
||||
&.mx_SpaceRoomView_landing_inviteButton {
|
||||
&::before {
|
||||
background-color: $accent-color;
|
||||
}
|
||||
|
||||
&::after {
|
||||
mask-image: url('$(res)/img/element-icons/room/invite.svg');
|
||||
}
|
||||
}
|
||||
|
||||
&.mx_SpaceRoomView_landing_addButton {
|
||||
&::before {
|
||||
background-color: #ac3ba8;
|
||||
}
|
||||
|
||||
&::after {
|
||||
mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
|
||||
}
|
||||
}
|
||||
|
||||
&.mx_SpaceRoomView_landing_createButton {
|
||||
&::before {
|
||||
background-color: #368bd6;
|
||||
}
|
||||
|
||||
&::after {
|
||||
mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
|
||||
}
|
||||
}
|
||||
|
||||
&.mx_SpaceRoomView_landing_settingsButton {
|
||||
&::before {
|
||||
background-color: #5c56f5;
|
||||
}
|
||||
|
||||
&::after {
|
||||
mask-image: url('$(res)/img/element-icons/settings.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceRoomDirectory_list {
|
||||
max-width: 600px;
|
||||
|
||||
.mx_SpaceRoomDirectory_roomTile_actions {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceRoomView_privateScope {
|
||||
.mx_RadioButton {
|
||||
width: $SpaceRoomViewInnerWidth;
|
||||
border-radius: 8px;
|
||||
border: 1px solid $space-button-outline-color;
|
||||
padding: 16px 16px 16px 72px;
|
||||
margin-top: 36px;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
|
||||
> div:first-of-type {
|
||||
// hide radio dot
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_RadioButton_content {
|
||||
margin: 0;
|
||||
|
||||
> h3 {
|
||||
margin: 0 0 4px;
|
||||
font-size: $font-15px;
|
||||
font-weight: $font-semi-bold;
|
||||
line-height: $font-18px;
|
||||
}
|
||||
|
||||
> div {
|
||||
color: $secondary-fg-color;
|
||||
font-size: $font-15px;
|
||||
line-height: $font-24px;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
top: 24px;
|
||||
left: 20px;
|
||||
background-color: $secondary-fg-color;
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-size: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_RadioButton_checked {
|
||||
border-color: $accent-color;
|
||||
|
||||
.mx_RadioButton_content {
|
||||
> div {
|
||||
color: $primary-fg-color;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-color: $accent-color;
|
||||
}
|
||||
}
|
||||
|
||||
.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 {
|
||||
.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');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
}
|
||||
|
|
|
@ -72,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
|
||||
|
@ -128,7 +129,7 @@ limitations under the License.
|
|||
}
|
||||
|
||||
.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
|
||||
|
|
|
@ -22,9 +22,18 @@ limitations under the License.
|
|||
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 +43,7 @@ limitations under the License.
|
|||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.mx_ViewSource_details {
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -14,8 +14,7 @@ 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_DecoratedRoomAvatar_cutout .mx_BaseAvatar {
|
||||
|
|
|
@ -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;
|
||||
|
|
185
res/css/views/dialogs/_AddExistingToSpaceDialog.scss
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
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_AddExistingToSpaceDialog {
|
||||
width: 480px;
|
||||
color: $primary-fg-color;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
min-height: 0;
|
||||
|
||||
.mx_Dialog_title {
|
||||
display: flex;
|
||||
|
||||
.mx_BaseAvatar {
|
||||
display: inline-flex;
|
||||
margin: 5px 16px 5px 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mx_BaseAvatar_image {
|
||||
border-radius: 8px;
|
||||
margin: 0;
|
||||
vertical-align: unset;
|
||||
}
|
||||
|
||||
> 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_SearchBox {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mx_AddExistingToSpaceDialog_errorText {
|
||||
font-weight: $font-semi-bold;
|
||||
font-size: $font-12px;
|
||||
line-height: $font-15px;
|
||||
color: $notice-primary-color;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.mx_AddExistingToSpaceDialog_content {
|
||||
.mx_AddExistingToSpaceDialog_noResults {
|
||||
margin-top: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_AddExistingToSpaceDialog_section {
|
||||
margin-top: 24px;
|
||||
|
||||
> h3 {
|
||||
margin: 0;
|
||||
color: $secondary-fg-color;
|
||||
font-size: $font-12px;
|
||||
font-weight: $font-semi-bold;
|
||||
line-height: $font-15px;
|
||||
}
|
||||
|
||||
.mx_AddExistingToSpaceDialog_entry {
|
||||
display: flex;
|
||||
margin-top: 12px;
|
||||
|
||||
.mx_BaseAvatar {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.mx_AddExistingToSpaceDialog_entry_name {
|
||||
font-size: $font-15px;
|
||||
line-height: 30px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.mx_FormButton {
|
||||
min-width: 92px;
|
||||
font-weight: normal;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_AddExistingToSpaceDialog_section_spaces {
|
||||
.mx_BaseAvatar_image {
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_AddExistingToSpaceDialog_footer {
|
||||
display: flex;
|
||||
margin-top: 32px;
|
||||
|
||||
> span {
|
||||
flex-grow: 1;
|
||||
font-size: $font-12px;
|
||||
line-height: $font-15px;
|
||||
|
||||
> * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_AccessibleButton {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mx_AccessibleButton_kind_link {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_FormButton {
|
||||
padding: 8px 22px;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,11 @@ limitations under the License.
|
|||
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;
|
||||
|
|
55
res/css/views/dialogs/_SpaceSettingsDialog.scss
Normal file
|
@ -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_FormButton {
|
||||
padding: 8px 22px;
|
||||
}
|
||||
}
|
|
@ -26,7 +26,9 @@ limitations under the License.
|
|||
padding: 7px 18px;
|
||||
text-align: center;
|
||||
border-radius: 8px;
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: $font-14px;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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: 4px;
|
||||
width: 270px;
|
||||
padding: 8px;
|
||||
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-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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,13 +14,11 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_UserInfo {
|
||||
.mx_EncryptionInfo_spinner {
|
||||
.mx_EncryptionInfo_spinner {
|
||||
.mx_Spinner {
|
||||
margin-top: 25px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -370,11 +370,6 @@ $MinWidth: 240px;
|
|||
display: none;
|
||||
}
|
||||
|
||||
/* Avoid apptile iframes capturing mouse event focus when resizing */
|
||||
.mx_AppsDrawer_resizing iframe {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mx_AppsDrawer_resizing .mx_AppTile_persistedWrapper {
|
||||
z-index: 1;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -213,23 +213,36 @@ $left-gutter: 64px;
|
|||
color: $accent-fg-color;
|
||||
}
|
||||
|
||||
.mx_EventTile_encrypting {
|
||||
color: $event-encrypting-color !important;
|
||||
}
|
||||
|
||||
.mx_EventTile_sending {
|
||||
color: $event-sending-color;
|
||||
}
|
||||
|
||||
.mx_EventTile_sending .mx_UserPill,
|
||||
.mx_EventTile_sending .mx_RoomPill {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.mx_EventTile_notSent {
|
||||
color: $event-notsent-color;
|
||||
}
|
||||
|
||||
.mx_EventTile_receiptSent,
|
||||
.mx_EventTile_receiptSending {
|
||||
// We don't use `position: relative` on the element because then it won't line
|
||||
// up with the other read receipts
|
||||
|
||||
&::before {
|
||||
background-color: $tertiary-fg-color;
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-size: 14px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
.mx_EventTile_receiptSent::before {
|
||||
mask-image: url('$(res)/img/element-icons/circle-sent.svg');
|
||||
}
|
||||
.mx_EventTile_receiptSending::before {
|
||||
mask-image: url('$(res)/img/element-icons/circle-sending.svg');
|
||||
}
|
||||
|
||||
.mx_EventTile_contextual {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
@ -257,17 +270,13 @@ $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;
|
||||
|
@ -531,14 +540,14 @@ $left-gutter: 64px;
|
|||
display: inline-block;
|
||||
visibility: hidden;
|
||||
cursor: pointer;
|
||||
top: 6px;
|
||||
right: 12px;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
background-color: $message-action-bar-fg-color;
|
||||
}
|
||||
.mx_EventTile_buttonBottom {
|
||||
top: 31px;
|
||||
top: 33px;
|
||||
}
|
||||
.mx_EventTile_copyButton {
|
||||
mask-image: url($copy-button-url);
|
||||
|
|
|
@ -21,7 +21,7 @@ $left-gutter: 64px;
|
|||
.mx_EventTile {
|
||||
> .mx_SenderProfile {
|
||||
line-height: $font-20px;
|
||||
padding-left: $left-gutter;
|
||||
margin-left: $left-gutter;
|
||||
}
|
||||
|
||||
> .mx_EventTile_line {
|
||||
|
@ -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 {
|
||||
|
|
|
@ -181,8 +181,7 @@ $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);
|
||||
|
@ -212,8 +211,7 @@ $irc-line-height: $font-18px;
|
|||
background: transparent;
|
||||
|
||||
> span {
|
||||
> .mx_SenderProfile_name,
|
||||
> .mx_SenderProfile_aux {
|
||||
> .mx_SenderProfile_name {
|
||||
min-width: inherit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ limitations under the License.
|
|||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.mx_MemberInfo_name {
|
||||
|
|
|
@ -44,6 +44,12 @@ 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,
|
||||
|
|
|
@ -227,18 +227,6 @@ 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_emoji::before {
|
||||
mask-image: url('$(res)/img/element-icons/room/composer/emoji.svg');
|
||||
}
|
||||
|
@ -247,6 +235,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;
|
||||
|
|
|
@ -252,6 +252,19 @@ limitations under the License.
|
|||
mask-image: url('$(res)/img/element-icons/room/search-inset.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_videoCallButton::before {
|
||||
mask-image: url('$(res)/img/element-icons/call/video-call.svg');
|
||||
}
|
||||
|
||||
.mx_RoomHeader_showPanel {
|
||||
height: 16px;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@ limitations under the License.
|
|||
}
|
||||
|
||||
.mx_RoomList_iconPlus::before {
|
||||
mask-image: url('$(res)/img/element-icons/roomlist/plus.svg');
|
||||
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');
|
||||
|
|
|
@ -197,6 +197,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
|
||||
|
@ -207,17 +210,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 {
|
||||
|
|
35
res/css/views/settings/_SpellCheckLanguages.scss
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_ExistingSpellCheckLanguage {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.mx_ExistingSpellCheckLanguage_language {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.mx_GeneralUserSettingsTab_spellCheckLanguageInput {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.mx_SpellCheckLanguages {
|
||||
@mixin mx_Settings_fullWidthField;
|
||||
}
|
86
res/css/views/spaces/_SpaceBasicSettings.scss
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
138
res/css/views/spaces/_SpaceCreateMenu.scss
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// TODO: the space panel currently does not have a fixed width,
|
||||
// just the headers at each level have a max-width of 150px
|
||||
// so this will look slightly off for now. We should probably use css grid for the whole main layout...
|
||||
$spacePanelWidth: 200px;
|
||||
|
||||
.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;
|
||||
|
||||
> 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;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceCreateMenuType {
|
||||
position: relative;
|
||||
padding: 16px 32px 16px 72px;
|
||||
width: 432px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 8px;
|
||||
border: 1px solid $input-darker-bg-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: 32px;
|
||||
background-color: $tertiary-fg-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: $accent-color;
|
||||
|
||||
&::before {
|
||||
background-color: $accent-color;
|
||||
}
|
||||
|
||||
> span {
|
||||
color: $primary-fg-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_SpaceCreateMenuType_public::before {
|
||||
mask-image: url('$(res)/img/globe.svg');
|
||||
mask-size: 26px;
|
||||
}
|
||||
.mx_SpaceCreateMenuType_private::before {
|
||||
mask-image: url('$(res)/img/element-icons/lock.svg');
|
||||
}
|
||||
|
||||
.mx_SpaceCreateMenu_back {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
position: relative;
|
||||
background-color: $theme-button-bg-color;
|
||||
border-radius: 14px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: $muted-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_FormButton {
|
||||
padding: 8px 22px;
|
||||
margin-left: auto;
|
||||
display: block;
|
||||
width: min-content;
|
||||
}
|
||||
|
||||
.mx_AccessibleButton_disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
60
res/css/views/spaces/_SpacePublicShare.scss
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
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_SpacePublicShare {
|
||||
.mx_AccessibleButton {
|
||||
border: 1px solid $space-button-outline-color;
|
||||
box-sizing: border-box;
|
||||
border-radius: 8px;
|
||||
padding: 12px 24px 12px 52px;
|
||||
margin-top: 16px;
|
||||
width: $SpaceRoomViewInnerWidth;
|
||||
font-size: $font-15px;
|
||||
line-height: $font-24px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
> span {
|
||||
color: #368bd6;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(141, 151, 165, 0.1);
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
mask-position: center;
|
||||
background: $muted-fg-color;
|
||||
left: 12px;
|
||||
top: 9px;
|
||||
}
|
||||
|
||||
&.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');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
|||
|
||||
.mx_VideoFeed_remote {
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
background-color: #000;
|
||||
z-index: 50;
|
||||
}
|
||||
|
|
3
res/img/element-icons/circle-sending.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="8" cy="8" r="7.5" stroke="#8D99A5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 152 B |
4
res/img/element-icons/circle-sent.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z" fill="#8D99A5"/>
|
||||
<path d="M11.8697 4.95309C11.6784 4.7576 11.3597 4.74731 11.1578 4.93251L6.62066 9.04804L4.95244 7.91627C4.7293 7.77223 4.42116 7.77223 4.20865 7.95742C3.95363 8.1632 3.93238 8.5336 4.14489 8.78053L6.06813 10.9206C6.1 10.9515 6.13188 10.9926 6.17438 11.0132C6.53565 11.3013 7.07756 11.2498 7.37508 10.9L7.40695 10.8589L11.891 5.60128C12.0397 5.41608 12.0397 5.13828 11.8697 4.95309Z" fill="#8D99A5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 784 B |
4
res/img/element-icons/expand-space-panel.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.7701 16.617H22.3721L18.614 20.3751C18.3137 20.6754 18.3137 21.1683 18.614 21.4686C18.9143 21.769 19.3995 21.769 19.6998 21.4686L24.7747 16.3937C25.0751 16.0934 25.0751 15.6082 24.7747 15.3079L19.7075 10.2253C19.4072 9.92492 18.922 9.92492 18.6217 10.2253C18.3214 10.5256 18.3214 11.0107 18.6217 11.3111L22.3721 15.0768H13.7701C13.3465 15.0768 13 15.4234 13 15.8469C13 16.2705 13.3465 16.617 13.7701 16.617Z" fill="#86888A"/>
|
||||
<rect x="7" y="10" width="1.5" height="12" rx="0.75" fill="#86888A"/>
|
||||
</svg>
|
After Width: | Height: | Size: 651 B |
3
res/img/element-icons/link.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.5285 6.54089L13.0273 6.04207C14.4052 4.66426 16.6259 4.65104 17.9874 6.01253C19.349 7.37402 19.3357 9.59466 17.9579 10.9725L15.5878 13.3425C14.21 14.7203 11.9893 14.7335 10.6277 13.372M11.4717 17.4589L10.9727 17.9579C9.59481 19.3357 7.37409 19.349 6.01256 17.9875C4.65102 16.626 4.66426 14.4053 6.04211 13.0275L8.41203 10.6577C9.78988 9.27988 12.0106 9.26665 13.3721 10.6281" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 549 B |
3
res/img/element-icons/lock.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.1113 2.6665C11.1839 2.6665 8.00016 5.85026 8.00016 9.77762V13.3332L7.3335 13.3332C6.22893 13.3332 5.3335 14.2286 5.3335 15.3332V27.3332C5.3335 28.4377 6.22893 29.3332 7.3335 29.3332H24.6668C25.7714 29.3332 26.6668 28.4377 26.6668 27.3332V15.3332C26.6668 14.2286 25.7714 13.3332 24.6668 13.3332L24.0002 13.3332V9.77762C24.0002 5.85026 20.8164 2.6665 16.8891 2.6665H15.1113ZM20.4446 13.3332V9.77762C20.4446 7.81394 18.8527 6.22206 16.8891 6.22206H15.1113C13.1476 6.22206 11.5557 7.81394 11.5557 9.77762V13.3332H20.4446Z" fill="#8E99A4"/>
|
||||
</svg>
|
After Width: | Height: | Size: 692 B |
3
res/img/element-icons/plus.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.74986 3.55554C8.74986 3.14133 8.41408 2.80554 7.99986 2.80554C7.58565 2.80554 7.24986 3.14133 7.24986 3.55554V7.24999L3.55542 7.24999C3.14121 7.24999 2.80542 7.58577 2.80542 7.99999C2.80542 8.4142 3.14121 8.74999 3.55542 8.74999L7.24987 8.74999V12.4444C7.24987 12.8586 7.58565 13.1944 7.99987 13.1944C8.41408 13.1944 8.74987 12.8586 8.74987 12.4444V8.74999L12.4443 8.74999C12.8585 8.74999 13.1943 8.4142 13.1943 7.99999C13.1943 7.58577 12.8585 7.24999 12.4443 7.24999L8.74986 7.24999V3.55554Z" fill="#8E99A4"/>
|
||||
</svg>
|
After Width: | Height: | Size: 670 B |
|
@ -1,3 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg width="24" height="24" viewBox="-0.4 1 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.1001 9C18.7779 9 18.5168 8.73883 18.5168 8.41667V6.08333H16.1834C15.8613 6.08333 15.6001 5.82217 15.6001 5.5C15.6001 5.17783 15.8613 4.91667 16.1834 4.91667H18.5168V2.58333C18.5168 2.26117 18.7779 2 19.1001 2C19.4223 2 19.6834 2.26117 19.6834 2.58333V4.91667H22.0168C22.3389 4.91667 22.6001 5.17783 22.6001 5.5C22.6001 5.82217 22.3389 6.08333 22.0168 6.08333H19.6834V8.41667C19.6834 8.73883 19.4223 9 19.1001 9ZM19.6001 11C20.0669 11 20.5212 10.9467 20.9574 10.8458C21.1161 11.5383 21.2 12.2594 21.2 13C21.2 16.1409 19.6917 18.9294 17.3598 20.6808V20.6807C16.0014 21.7011 14.3635 22.3695 12.5815 22.5505C12.2588 22.5832 11.9314 22.6 11.6 22.6C6.29807 22.6 2 18.302 2 13C2 7.69809 6.29807 3.40002 11.6 3.40002C12.3407 3.40002 13.0618 3.48391 13.7543 3.64268C13.6534 4.07884 13.6001 4.53319 13.6001 5C13.6001 8.31371 16.2864 11 19.6001 11ZM11.5999 20.68C13.6754 20.68 15.5585 19.8567 16.9407 18.5189C16.0859 16.4086 14.0167 14.92 11.5998 14.92C9.18298 14.92 7.11378 16.4086 6.25901 18.5189C7.64115 19.8567 9.52436 20.68 11.5999 20.68ZM11.7426 7.41172C10.3168 7.54168 9.2 8.74043 9.2 10.2C9.2 11.7464 10.4536 13 12 13C13.0308 13 13.9315 12.443 14.4176 11.6135C13.0673 10.6058 12.0929 9.12248 11.7426 7.41172Z" fill="black"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
7
res/img/element-icons/roomlist/hash-circle.svg
Normal file
After Width: | Height: | Size: 8.4 KiB |
3
res/img/element-icons/roomlist/plus-circle.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17 9C17 13.4183 13.4183 17 9 17C4.58172 17 1 13.4183 1 9C1 4.58172 4.58172 1 9 1C13.4183 1 17 4.58172 17 9ZM5.25 9C5.25 8.58579 5.58579 8.25 6 8.25H8.25V6C8.25 5.58579 8.58579 5.25 9 5.25C9.41421 5.25 9.75 5.58579 9.75 6V8.25H12C12.4142 8.25 12.75 8.58579 12.75 9C12.75 9.41421 12.4142 9.75 12 9.75H9.75V12C9.75 12.4142 9.41421 12.75 9 12.75C8.58579 12.75 8.25 12.4142 8.25 12V9.75H6C5.58579 9.75 5.25 9.41421 5.25 9Z" fill="black"/>
|
||||
</svg>
|
After Width: | Height: | Size: 587 B |
3
res/img/element-icons/send-message.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 18.792 11.145 L 2.356 19.359 C 1.249 19.913 0.097 18.725 0.638 17.642 C 0.638 17.642 2.675 13.528 3.235 12.451 C 3.796 11.373 4.437 11.187 10.393 10.417 C 10.614 10.388 10.794 10.222 10.794 10 C 10.794 9.778 10.614 9.612 10.393 9.583 C 4.437 8.813 3.796 8.627 3.235 7.549 C 2.675 6.472 0.638 2.358 0.638 2.358 C 0.097 1.275 1.249 0.087 2.356 0.64 L 18.792 8.855 C 19.736 9.326 19.736 10.674 18.792 11.145 Z" fill="black"/>
|
||||
</svg>
|
After Width: | Height: | Size: 537 B |
4
res/img/element-icons/upload.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.99902 14L8.99902 4" stroke="black" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M12.5352 7.52441L8.99944 4.00012L5.46373 7.52441" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 336 B |
|
@ -1,5 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 5C2 3.89543 2.89543 3 4 3H20C21.1046 3 22 3.89543 22 5V15C22 16.1046 21.1046 17 20 17H4C2.89543 17 2 16.1046 2 15V5Z" stroke="#2E2F32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 21H16" stroke="#2E2F32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 17V21" stroke="#2E2F32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 510 B |
|
@ -1,4 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 4C5 2.89543 5.89543 2 7 2H17C18.1046 2 19 2.89543 19 4V20C19 21.1046 18.1046 22 17 22H7C5.89543 22 5 21.1046 5 20V4Z" stroke="#2E2F32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="12" cy="18" r="1" fill="#2E2F32"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 386 B |
|
@ -1,19 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="45px" height="59px" viewBox="-1 -1 45 59" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<!-- Generator: bin/sketchtool 1.4 (305) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>icons_upload_drop</title>
|
||||
<desc>Created with bin/sketchtool.</desc>
|
||||
<defs></defs>
|
||||
<g id="03-Input" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="03_05-File-drop" sketch:type="MSArtboardGroup" transform="translate(-570.000000, -368.000000)">
|
||||
<g id="icons_upload_drop" sketch:type="MSLayerGroup" transform="translate(570.000000, 368.000000)">
|
||||
<g id="Rectangle-5-+-Rectangle-6" sketch:type="MSShapeGroup">
|
||||
<path d="M0,4.00812931 C0,1.79450062 1.78537926,0 4.00241155,0 L24.8253683,0 C24.8253683,0 42.2466793,16.8210687 42.2466793,16.8210687 L42.2466793,53.000599 C42.2466793,55.2094072 40.4583762,57 38.2531894,57 L3.99348992,57 C1.78794634,57 0,55.1999609 0,52.9918707 L0,4.00812931 Z" id="Rectangle-5" stroke="#76CFA6"></path>
|
||||
<path d="M40.5848017,19.419576 L29.8354335,19.419576 C26.7387692,19.419576 24.2284269,16.9063989 24.2284269,13.8067771 L24.2284269,4.88501382 L40.5848017,19.419576 Z" id="Rectangle-6-Copy" fill="#FFFFFF"></path>
|
||||
<path d="M42.2466793,18.3870968 L29.539478,18.3870968 C26.4130381,18.3870968 23.8785579,15.8497544 23.8785579,12.7203286 L23.8785579,0" id="Rectangle-6" stroke="#76CFA6"></path>
|
||||
</g>
|
||||
<path d="M31.3419737,32.9284726 C31.701384,32.9284726 32.0607942,32.8000473 32.3359677,32.5414375 C32.8825707,32.0259772 32.8825707,31.1920926 32.3359677,30.6766323 L21.622922,20.6119619 C21.076319,20.0965016 20.187153,20.0982608 19.638678,20.6102026 L8.9125289,30.6607991 C8.36405391,31.1762594 8.36218198,32.0119032 8.90878504,32.5273635 C9.4553881,33.0445831 10.344554,33.0445831 10.893029,32.530882 L19.2399573,24.7092556 L19.2437012,46.487014 C19.2437012,47.2153435 19.874541,47.8064516 20.6476474,47.8064516 C21.4244976,47.8064516 22.0515936,47.2153435 22.0515936,46.487014 L22.0478497,24.7426814 L30.3498517,32.5414375 C30.6231533,32.8000473 30.9825635,32.9284726 31.3419737,32.9284726 L31.3419737,32.9284726 Z" id="Fill-75" fill="#76CFA6" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32C24.8366 32 32 24.8366 32 16C32 7.16344 24.8366 0 16 0ZM17.2511 6.97409C16.9775 6.68236 16.5885 6.50012 16.157 6.50012C15.793 6.50012 15.4593 6.62973 15.1996 6.84532C15.1545 6.88267 15.1115 6.92281 15.0707 6.96564L8.79618 13.5539C8.22485 14.1538 8.24801 15.1032 8.8479 15.6746C9.4478 16.2459 10.3973 16.2227 10.9686 15.6228L14.657 11.7501V23.0589C14.657 23.8874 15.3285 24.5589 16.157 24.5589C16.9854 24.5589 17.657 23.8874 17.657 23.0589V11.7502L21.3452 15.6228C21.9165 16.2227 22.866 16.2459 23.4659 15.6746C24.0658 15.1032 24.0889 14.1538 23.5176 13.5539L17.2511 6.97409Z" fill="#0DBD8B"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 802 B |
|
@ -123,6 +123,7 @@ $roomsublist-divider-color: $primary-fg-color;
|
|||
$roomsublist-skeleton-ui-bg: linear-gradient(180deg, #3e444c 0%, #3e444c00 100%);
|
||||
|
||||
$groupFilterPanel-divider-color: $roomlist-header-color;
|
||||
$space-button-outline-color: rgba(141, 151, 165, 0.2);
|
||||
|
||||
$roomtile-preview-color: $secondary-fg-color;
|
||||
$roomtile-default-badge-bg-color: #61708b;
|
||||
|
@ -137,9 +138,6 @@ $panel-divider-color: transparent;
|
|||
$widget-menu-bar-bg-color: $header-panel-bg-color;
|
||||
$widget-body-bg-color: rgba(141, 151, 165, 0.2);
|
||||
|
||||
// event tile lifecycle
|
||||
$event-sending-color: $text-secondary-color;
|
||||
|
||||
// event redaction
|
||||
$event-redacted-fg-color: #606060;
|
||||
$event-redacted-border-color: #000000;
|
||||
|
@ -172,6 +170,9 @@ $button-link-bg-color: transparent;
|
|||
// Toggle switch
|
||||
$togglesw-off-color: $room-highlight-color;
|
||||
|
||||
$progressbar-fg-color: $accent-color;
|
||||
$progressbar-bg-color: #21262c;
|
||||
|
||||
$visual-bell-bg-color: #800;
|
||||
|
||||
$room-warning-bg-color: $header-panel-bg-color;
|
||||
|
@ -202,6 +203,10 @@ $breadcrumb-placeholder-bg-color: #272c35;
|
|||
|
||||
$user-tile-hover-bg-color: $header-panel-bg-color;
|
||||
|
||||
$message-body-panel-bg-color: #21262c82;
|
||||
$message-body-panel-icon-bg-color: #8e99a4;
|
||||
$message-body-panel-fg-color: $primary-fg-color;
|
||||
|
||||
// Appearance tab colors
|
||||
$appearance-tab-border-color: $room-highlight-color;
|
||||
|
||||
|
@ -259,6 +264,11 @@ $composer-shadow-color: rgba(0, 0, 0, 0.28);
|
|||
.mx_EventTile_content .markdown-body pre:hover {
|
||||
border-color: #808080 !important; // inverted due to rules below
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent; // copied from light theme due to inversion below
|
||||
// the code above works only in Firefox, this is for other browsers
|
||||
// see https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.2); // copied from light theme due to inversion below
|
||||
}
|
||||
}
|
||||
.mx_EventTile_content .markdown-body {
|
||||
pre, code {
|
||||
|
|
|
@ -120,6 +120,7 @@ $roomsublist-divider-color: $primary-fg-color;
|
|||
$roomsublist-skeleton-ui-bg: linear-gradient(180deg, #3e444c 0%, #3e444c00 100%);
|
||||
|
||||
$groupFilterPanel-divider-color: $roomlist-header-color;
|
||||
$space-button-outline-color: rgba(141, 151, 165, 0.2);
|
||||
|
||||
$roomtile-preview-color: #9e9e9e;
|
||||
$roomtile-default-badge-bg-color: #61708b;
|
||||
|
@ -132,9 +133,6 @@ $panel-divider-color: $header-panel-border-color;
|
|||
$widget-menu-bar-bg-color: $header-panel-bg-color;
|
||||
$widget-body-bg-color: #1A1D23;
|
||||
|
||||
// event tile lifecycle
|
||||
$event-sending-color: $text-secondary-color;
|
||||
|
||||
// event redaction
|
||||
$event-redacted-fg-color: #606060;
|
||||
$event-redacted-border-color: #000000;
|
||||
|
@ -167,6 +165,9 @@ $button-link-bg-color: transparent;
|
|||
// Toggle switch
|
||||
$togglesw-off-color: $room-highlight-color;
|
||||
|
||||
$progressbar-fg-color: $accent-color;
|
||||
$progressbar-bg-color: #21262c;
|
||||
|
||||
$visual-bell-bg-color: #800;
|
||||
|
||||
$room-warning-bg-color: $header-panel-bg-color;
|
||||
|
@ -197,6 +198,10 @@ $breadcrumb-placeholder-bg-color: #272c35;
|
|||
|
||||
$user-tile-hover-bg-color: $header-panel-bg-color;
|
||||
|
||||
$message-body-panel-bg-color: #21262c82;
|
||||
$message-body-panel-icon-bg-color: #8e99a4;
|
||||
$message-body-panel-fg-color: $primary-fg-color;
|
||||
|
||||
// Appearance tab colors
|
||||
$appearance-tab-border-color: $room-highlight-color;
|
||||
|
||||
|
|
|
@ -187,6 +187,7 @@ $roomsublist-divider-color: $primary-fg-color;
|
|||
$roomsublist-skeleton-ui-bg: linear-gradient(180deg, #ffffff 0%, #ffffff00 100%);
|
||||
|
||||
$groupFilterPanel-divider-color: $roomlist-header-color;
|
||||
$space-button-outline-color: #E3E8F0;
|
||||
|
||||
$roomtile-preview-color: #9e9e9e;
|
||||
$roomtile-default-badge-bg-color: #61708b;
|
||||
|
@ -222,8 +223,6 @@ $widget-body-bg-color: #fff;
|
|||
$yellow-background: #fff8e3;
|
||||
|
||||
// event tile lifecycle
|
||||
$event-encrypting-color: #abddbc;
|
||||
$event-sending-color: #ddd;
|
||||
$event-notsent-color: #f44;
|
||||
|
||||
$event-highlight-fg-color: $warning-color;
|
||||
|
@ -281,7 +280,8 @@ $togglesw-ball-color: #fff;
|
|||
$slider-selection-color: $accent-color;
|
||||
$slider-background-color: #c1c9d6;
|
||||
|
||||
$progressbar-color: #000;
|
||||
$progressbar-fg-color: $accent-color;
|
||||
$progressbar-bg-color: rgba(141, 151, 165, 0.2);
|
||||
|
||||
$room-warning-bg-color: $yellow-background;
|
||||
|
||||
|
@ -321,6 +321,10 @@ $breadcrumb-placeholder-bg-color: #e8eef5;
|
|||
|
||||
$user-tile-hover-bg-color: $header-panel-bg-color;
|
||||
|
||||
$message-body-panel-bg-color: #e3e8f082;
|
||||
$message-body-panel-icon-bg-color: #ffffff;
|
||||
$message-body-panel-fg-color: $muted-fg-color;
|
||||
|
||||
// FontSlider colors
|
||||
$appearance-tab-border-color: $input-darker-bg-color;
|
||||
|
||||
|
|
|
@ -67,9 +67,6 @@ $groupFilterPanel-bg-color: rgba(232, 232, 232, 0.77);
|
|||
// used by RoomDirectory permissions
|
||||
$plinth-bg-color: $secondary-accent-color;
|
||||
|
||||
// used by RoomDropTarget
|
||||
$droptarget-bg-color: rgba(255,255,255,0.5);
|
||||
|
||||
// used by AddressSelector
|
||||
$selected-color: $secondary-accent-color;
|
||||
|
||||
|
@ -181,6 +178,7 @@ $roomsublist-divider-color: $primary-fg-color;
|
|||
$roomsublist-skeleton-ui-bg: linear-gradient(180deg, #ffffff 0%, #ffffff00 100%);
|
||||
|
||||
$groupFilterPanel-divider-color: $roomlist-header-color;
|
||||
$space-button-outline-color: #E3E8F0;
|
||||
|
||||
$roomtile-preview-color: $secondary-fg-color;
|
||||
$roomtile-default-badge-bg-color: #61708b;
|
||||
|
@ -222,8 +220,6 @@ $widget-body-bg-color: #FFF;
|
|||
$yellow-background: #fff8e3;
|
||||
|
||||
// event tile lifecycle
|
||||
$event-encrypting-color: #abddbc;
|
||||
$event-sending-color: #ddd;
|
||||
$event-notsent-color: #f44;
|
||||
|
||||
$event-highlight-fg-color: $warning-color;
|
||||
|
@ -281,7 +277,8 @@ $togglesw-ball-color: #fff;
|
|||
$slider-selection-color: $accent-color;
|
||||
$slider-background-color: #c1c9d6;
|
||||
|
||||
$progressbar-color: #000;
|
||||
$progressbar-fg-color: $accent-color;
|
||||
$progressbar-bg-color: rgba(141, 151, 165, 0.2);
|
||||
|
||||
$room-warning-bg-color: $yellow-background;
|
||||
|
||||
|
@ -322,6 +319,10 @@ $breadcrumb-placeholder-bg-color: #e8eef5;
|
|||
|
||||
$user-tile-hover-bg-color: $header-panel-bg-color;
|
||||
|
||||
$message-body-panel-bg-color: #e3e8f082;
|
||||
$message-body-panel-icon-bg-color: #ffffff;
|
||||
$message-body-panel-fg-color: $muted-fg-color;
|
||||
|
||||
// FontSlider colors
|
||||
$appearance-tab-border-color: $input-darker-bg-color;
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
backdrop-filter: blur($groupFilterPanel-background-blur-amount);
|
||||
}
|
||||
|
||||
.mx_SpacePanel {
|
||||
backdrop-filter: blur($groupFilterPanel-background-blur-amount);
|
||||
}
|
||||
|
||||
.mx_LeftPanel .mx_LeftPanel_roomListContainer {
|
||||
backdrop-filter: blur($roomlist-background-blur-amount);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env node
|
||||
const fs = require('fs');
|
||||
const { promises: fsp } = fs;
|
||||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
const util = require('util');
|
||||
|
@ -25,6 +26,8 @@ async function reskindex() {
|
|||
const header = args.h || args.header;
|
||||
|
||||
const strm = fs.createWriteStream(componentIndexTmp);
|
||||
// Wait for the open event to ensure the file descriptor is set
|
||||
await new Promise(resolve => strm.once("open", resolve));
|
||||
|
||||
if (header) {
|
||||
strm.write(fs.readFileSync(header));
|
||||
|
@ -53,14 +56,9 @@ async function reskindex() {
|
|||
|
||||
strm.write("export {components};\n");
|
||||
// Ensure the file has been fully written to disk before proceeding
|
||||
await util.promisify(fs.fsync)(strm.fd);
|
||||
await util.promisify(strm.end);
|
||||
fs.rename(componentIndexTmp, componentIndex, function(err) {
|
||||
if (err) {
|
||||
console.error("Error moving new index into place: " + err);
|
||||
} else {
|
||||
console.log('Reskindex: completed');
|
||||
}
|
||||
});
|
||||
await fsp.rename(componentIndexTmp, componentIndex);
|
||||
}
|
||||
|
||||
// Expects both arrays of file names to be sorted
|
||||
|
@ -77,9 +75,17 @@ function filesHaveChanged(files, prevFiles) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Wrapper since await at the top level is not well supported yet
|
||||
function run() {
|
||||
(async function() {
|
||||
await reskindex();
|
||||
console.log("Reskindex completed");
|
||||
})();
|
||||
}
|
||||
|
||||
// -w indicates watch mode where any FS events will trigger reskindex
|
||||
if (!args.w) {
|
||||
reskindex();
|
||||
run();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -87,5 +93,5 @@ let watchDebouncer = null;
|
|||
chokidar.watch(path.join(componentsDir, componentJsGlob)).on('all', (event, path) => {
|
||||
if (path === componentIndex) return;
|
||||
if (watchDebouncer) clearTimeout(watchDebouncer);
|
||||
watchDebouncer = setTimeout(reskindex, 1000);
|
||||
watchDebouncer = setTimeout(run, 1000);
|
||||
});
|
||||
|
|
4
src/@types/global.d.ts
vendored
|
@ -37,6 +37,8 @@ import CountlyAnalytics from "../CountlyAnalytics";
|
|||
import UserActivity from "../UserActivity";
|
||||
import {ModalWidgetStore} from "../stores/ModalWidgetStore";
|
||||
import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore";
|
||||
import VoipUserMapper from "../VoipUserMapper";
|
||||
import {SpaceStoreClass} from "../stores/SpaceStore";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
@ -66,6 +68,8 @@ declare global {
|
|||
mxCountlyAnalytics: typeof CountlyAnalytics;
|
||||
mxUserActivity: UserActivity;
|
||||
mxModalWidgetStore: ModalWidgetStore;
|
||||
mxVoipUserMapper: VoipUserMapper;
|
||||
mxSpaceStore: SpaceStoreClass;
|
||||
}
|
||||
|
||||
interface Document {
|
||||
|
|
|
@ -14,27 +14,23 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
|
||||
import {RoomMember} from "matrix-js-sdk/src/models/room-member";
|
||||
import {User} from "matrix-js-sdk/src/models/user";
|
||||
import {Room} from "matrix-js-sdk/src/models/room";
|
||||
|
||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
||||
import DMRoomMap from './utils/DMRoomMap';
|
||||
import {mediaFromMxc} from "./customisations/Media";
|
||||
|
||||
export type ResizeMethod = "crop" | "scale";
|
||||
|
||||
// Not to be used for BaseAvatar urls as that has similar default avatar fallback already
|
||||
export function avatarUrlForMember(member: RoomMember, width: number, height: number, resizeMethod: ResizeMethod) {
|
||||
let url: string;
|
||||
if (member && member.getAvatarUrl) {
|
||||
url = member.getAvatarUrl(
|
||||
MatrixClientPeg.get().getHomeserverUrl(),
|
||||
if (member?.getMxcAvatarUrl()) {
|
||||
url = mediaFromMxc(member.getMxcAvatarUrl()).getThumbnailOfSourceHttp(
|
||||
Math.floor(width * window.devicePixelRatio),
|
||||
Math.floor(height * window.devicePixelRatio),
|
||||
resizeMethod,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
}
|
||||
if (!url) {
|
||||
|
@ -47,16 +43,12 @@ export function avatarUrlForMember(member: RoomMember, width: number, height: nu
|
|||
}
|
||||
|
||||
export function avatarUrlForUser(user: User, width: number, height: number, resizeMethod?: ResizeMethod) {
|
||||
const url = getHttpUriForMxc(
|
||||
MatrixClientPeg.get().getHomeserverUrl(), user.avatarUrl,
|
||||
if (!user.avatarUrl) return null;
|
||||
return mediaFromMxc(user.avatarUrl).getThumbnailOfSourceHttp(
|
||||
Math.floor(width * window.devicePixelRatio),
|
||||
Math.floor(height * window.devicePixelRatio),
|
||||
resizeMethod,
|
||||
);
|
||||
if (!url || url.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
function isValidHexColor(color: string): boolean {
|
||||
|
@ -154,17 +146,13 @@ export function getInitialLetter(name: string): string {
|
|||
export function avatarUrlForRoom(room: Room, width: number, height: number, resizeMethod?: ResizeMethod) {
|
||||
if (!room) return null; // null-guard
|
||||
|
||||
const explicitRoomAvatar = room.getAvatarUrl(
|
||||
MatrixClientPeg.get().getHomeserverUrl(),
|
||||
width,
|
||||
height,
|
||||
resizeMethod,
|
||||
false,
|
||||
);
|
||||
if (explicitRoomAvatar) {
|
||||
return explicitRoomAvatar;
|
||||
if (room.getMxcAvatarUrl()) {
|
||||
return mediaFromMxc(room.getMxcAvatarUrl()).getThumbnailOfSourceHttp(width, height, resizeMethod);
|
||||
}
|
||||
|
||||
// space rooms cannot be DMs so skip the rest
|
||||
if (room.isSpaceRoom()) return null;
|
||||
|
||||
let otherMember = null;
|
||||
const otherUserId = DMRoomMap.shared().getUserIdForRoomId(room.roomId);
|
||||
if (otherUserId) {
|
||||
|
@ -174,14 +162,8 @@ export function avatarUrlForRoom(room: Room, width: number, height: number, resi
|
|||
// then still try to show any avatar (pref. other member)
|
||||
otherMember = room.getAvatarFallbackMember();
|
||||
}
|
||||
if (otherMember) {
|
||||
return otherMember.getAvatarUrl(
|
||||
MatrixClientPeg.get().getHomeserverUrl(),
|
||||
width,
|
||||
height,
|
||||
resizeMethod,
|
||||
false,
|
||||
);
|
||||
if (otherMember?.getMxcAvatarUrl()) {
|
||||
return mediaFromMxc(otherMember.getMxcAvatarUrl()).getThumbnailOfSourceHttp(width, height, resizeMethod);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -131,6 +131,14 @@ export default abstract class BasePlatform {
|
|||
hideUpdateToast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if platform supports multi-language
|
||||
* spell-checking, otherwise false.
|
||||
*/
|
||||
supportsMultiLanguageSpellCheck(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the platform supports displaying
|
||||
* notifications, otherwise false.
|
||||
|
@ -240,6 +248,16 @@ export default abstract class BasePlatform {
|
|||
|
||||
setLanguage(preferredLangs: string[]) {}
|
||||
|
||||
setSpellCheckLanguages(preferredLangs: string[]) {}
|
||||
|
||||
getSpellCheckLanguages(): Promise<string[]> | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
getAvailableSpellCheckLanguages(): Promise<string[]> | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected getSSOCallbackUrl(fragmentAfterLogin: string): URL {
|
||||
const url = new URL(window.location.href);
|
||||
url.hash = fragmentAfterLogin || "";
|
||||
|
|
|
@ -64,7 +64,6 @@ import dis from './dispatcher/dispatcher';
|
|||
import WidgetUtils from './utils/WidgetUtils';
|
||||
import WidgetEchoStore from './stores/WidgetEchoStore';
|
||||
import SettingsStore from './settings/SettingsStore';
|
||||
import {generateHumanReadableId} from "./utils/NamingUtils";
|
||||
import {Jitsi} from "./widgets/Jitsi";
|
||||
import {WidgetType} from "./widgets/WidgetType";
|
||||
import {SettingLevel} from "./settings/SettingLevel";
|
||||
|
@ -84,10 +83,19 @@ import { CallError } from "matrix-js-sdk/src/webrtc/call";
|
|||
import { logger } from 'matrix-js-sdk/src/logger';
|
||||
import DesktopCapturerSourcePicker from "./components/views/elements/DesktopCapturerSourcePicker"
|
||||
import { Action } from './dispatcher/actions';
|
||||
import { roomForVirtualRoom, getOrCreateVirtualRoomForRoom } from './VoipUserMapper';
|
||||
import VoipUserMapper from './VoipUserMapper';
|
||||
import { addManagedHybridWidget, isManagedHybridWidgetEnabled } from './widgets/ManagedHybrid';
|
||||
import { randomUppercaseString, randomLowercaseString } from "matrix-js-sdk/src/randomstring";
|
||||
|
||||
const CHECK_PSTN_SUPPORT_ATTEMPTS = 3;
|
||||
export const PROTOCOL_PSTN = 'm.protocol.pstn';
|
||||
export const PROTOCOL_PSTN_PREFIXED = 'im.vector.protocol.pstn';
|
||||
export const PROTOCOL_SIP_NATIVE = 'im.vector.protocol.sip_native';
|
||||
export const PROTOCOL_SIP_VIRTUAL = 'im.vector.protocol.sip_virtual';
|
||||
|
||||
const CHECK_PROTOCOLS_ATTEMPTS = 3;
|
||||
// Event type for room account data and room creation content used to mark rooms as virtual rooms
|
||||
// (and store the ID of their native room)
|
||||
export const VIRTUAL_ROOM_EVENT_TYPE = 'im.vector.is_virtual_room';
|
||||
|
||||
enum AudioID {
|
||||
Ring = 'ringAudio',
|
||||
|
@ -96,6 +104,29 @@ enum AudioID {
|
|||
Busy = 'busyAudio',
|
||||
}
|
||||
|
||||
interface ThirdpartyLookupResponseFields {
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
// im.vector.sip_native
|
||||
virtual_mxid?: string;
|
||||
is_virtual?: boolean;
|
||||
|
||||
// im.vector.sip_virtual
|
||||
native_mxid?: string;
|
||||
is_native?: boolean;
|
||||
|
||||
// common
|
||||
lookup_success?: boolean;
|
||||
|
||||
/* eslint-enable camelcase */
|
||||
}
|
||||
|
||||
interface ThirdpartyLookupResponse {
|
||||
userid: string,
|
||||
protocol: string,
|
||||
fields: ThirdpartyLookupResponseFields,
|
||||
}
|
||||
|
||||
// Unlike 'CallType' in js-sdk, this one includes screen sharing
|
||||
// (because a screen sharing call is only a screen sharing call to the caller,
|
||||
// to the callee it's just a video call, at least as far as the current impl
|
||||
|
@ -126,7 +157,12 @@ export default class CallHandler {
|
|||
private audioPromises = new Map<AudioID, Promise<void>>();
|
||||
private dispatcherRef: string = null;
|
||||
private supportsPstnProtocol = null;
|
||||
private pstnSupportPrefixed = null; // True if the server only support the prefixed pstn protocol
|
||||
private supportsSipNativeVirtual = null; // im.vector.protocol.sip_virtual and im.vector.protocol.sip_native
|
||||
private pstnSupportCheckTimer: NodeJS.Timeout; // number actually because we're in the browser
|
||||
// For rooms we've been invited to, true if they're from virtual user, false if we've checked and they aren't.
|
||||
private invitedRoomsAreVirtual = new Map<string, boolean>();
|
||||
private invitedRoomCheckInProgress = false;
|
||||
|
||||
static sharedInstance() {
|
||||
if (!window.mxCallHandler) {
|
||||
|
@ -140,9 +176,9 @@ export default class CallHandler {
|
|||
* Gets the user-facing room associated with a call (call.roomId may be the call "virtual room"
|
||||
* if a voip_mxid_translate_pattern is set in the config)
|
||||
*/
|
||||
public static roomIdForCall(call: MatrixCall) {
|
||||
public static roomIdForCall(call: MatrixCall): string {
|
||||
if (!call) return null;
|
||||
return roomForVirtualRoom(call.roomId) || call.roomId;
|
||||
return VoipUserMapper.sharedInstance().nativeRoomForVirtualRoom(call.roomId) || call.roomId;
|
||||
}
|
||||
|
||||
start() {
|
||||
|
@ -163,7 +199,7 @@ export default class CallHandler {
|
|||
MatrixClientPeg.get().on('Call.incoming', this.onCallIncoming);
|
||||
}
|
||||
|
||||
this.checkForPstnSupport(CHECK_PSTN_SUPPORT_ATTEMPTS);
|
||||
this.checkProtocols(CHECK_PROTOCOLS_ATTEMPTS);
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
@ -177,33 +213,73 @@ export default class CallHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private async checkForPstnSupport(maxTries) {
|
||||
private async checkProtocols(maxTries) {
|
||||
try {
|
||||
const protocols = await MatrixClientPeg.get().getThirdpartyProtocols();
|
||||
if (protocols['im.vector.protocol.pstn'] !== undefined) {
|
||||
this.supportsPstnProtocol = protocols['im.vector.protocol.pstn'];
|
||||
} else if (protocols['m.protocol.pstn'] !== undefined) {
|
||||
this.supportsPstnProtocol = protocols['m.protocol.pstn'];
|
||||
|
||||
if (protocols[PROTOCOL_PSTN] !== undefined) {
|
||||
this.supportsPstnProtocol = Boolean(protocols[PROTOCOL_PSTN]);
|
||||
if (this.supportsPstnProtocol) this.pstnSupportPrefixed = false;
|
||||
} else if (protocols[PROTOCOL_PSTN_PREFIXED] !== undefined) {
|
||||
this.supportsPstnProtocol = Boolean(protocols[PROTOCOL_PSTN_PREFIXED]);
|
||||
if (this.supportsPstnProtocol) this.pstnSupportPrefixed = true;
|
||||
} else {
|
||||
this.supportsPstnProtocol = null;
|
||||
}
|
||||
|
||||
dis.dispatch({action: Action.PstnSupportUpdated});
|
||||
|
||||
if (protocols[PROTOCOL_SIP_NATIVE] !== undefined && protocols[PROTOCOL_SIP_VIRTUAL] !== undefined) {
|
||||
this.supportsSipNativeVirtual = Boolean(
|
||||
protocols[PROTOCOL_SIP_NATIVE] && protocols[PROTOCOL_SIP_VIRTUAL],
|
||||
);
|
||||
}
|
||||
|
||||
dis.dispatch({action: Action.VirtualRoomSupportUpdated});
|
||||
} catch (e) {
|
||||
if (maxTries === 1) {
|
||||
console.log("Failed to check for pstn protocol support and no retries remain: assuming no support", e);
|
||||
console.log("Failed to check for protocol support and no retries remain: assuming no support", e);
|
||||
} else {
|
||||
console.log("Failed to check for pstn protocol support: will retry", e);
|
||||
console.log("Failed to check for protocol support: will retry", e);
|
||||
this.pstnSupportCheckTimer = setTimeout(() => {
|
||||
this.checkForPstnSupport(maxTries - 1);
|
||||
this.checkProtocols(maxTries - 1);
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getSupportsPstnProtocol() {
|
||||
public getSupportsPstnProtocol() {
|
||||
return this.supportsPstnProtocol;
|
||||
}
|
||||
|
||||
public getSupportsVirtualRooms() {
|
||||
return this.supportsPstnProtocol;
|
||||
}
|
||||
|
||||
public pstnLookup(phoneNumber: string): Promise<ThirdpartyLookupResponse[]> {
|
||||
return MatrixClientPeg.get().getThirdpartyUser(
|
||||
this.pstnSupportPrefixed ? PROTOCOL_PSTN_PREFIXED : PROTOCOL_PSTN, {
|
||||
'm.id.phone': phoneNumber,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public sipVirtualLookup(nativeMxid: string): Promise<ThirdpartyLookupResponse[]> {
|
||||
return MatrixClientPeg.get().getThirdpartyUser(
|
||||
PROTOCOL_SIP_VIRTUAL, {
|
||||
'native_mxid': nativeMxid,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public sipNativeLookup(virtualMxid: string): Promise<ThirdpartyLookupResponse[]> {
|
||||
return MatrixClientPeg.get().getThirdpartyUser(
|
||||
PROTOCOL_SIP_NATIVE, {
|
||||
'virtual_mxid': virtualMxid,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private onCallIncoming = (call) => {
|
||||
// we dispatch this synchronously to make sure that the event
|
||||
// handlers on the call are set up immediately (so that if
|
||||
|
@ -550,9 +626,11 @@ export default class CallHandler {
|
|||
Analytics.trackEvent('voip', 'placeCall', 'type', type);
|
||||
CountlyAnalytics.instance.trackStartCall(roomId, type === PlaceCallType.Video, false);
|
||||
|
||||
const mappedRoomId = (await getOrCreateVirtualRoomForRoom(roomId)) || roomId;
|
||||
const mappedRoomId = (await VoipUserMapper.sharedInstance().getOrCreateVirtualRoomForRoom(roomId)) || roomId;
|
||||
logger.debug("Mapped real room " + roomId + " to room ID " + mappedRoomId);
|
||||
|
||||
const timeUntilTurnCresExpire = MatrixClientPeg.get().getTurnServersExpiry() - Date.now();
|
||||
console.log("Current turn creds expire in " + timeUntilTurnCresExpire + " ms");
|
||||
const call = createNewMatrixCall(MatrixClientPeg.get(), mappedRoomId);
|
||||
|
||||
this.calls.set(roomId, call);
|
||||
|
@ -628,6 +706,14 @@ export default class CallHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.getCallForRoom(room.roomId)) {
|
||||
Modal.createTrackedDialog('Call Handler', 'Existing Call with user', ErrorDialog, {
|
||||
title: _t('Already in call'),
|
||||
description: _t("You're already in a call with this person."),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const members = room.getJoinedMembers();
|
||||
if (members.length <= 1) {
|
||||
Modal.createTrackedDialog('Call Handler', 'Cannot place call with self', ErrorDialog, {
|
||||
|
@ -681,6 +767,12 @@ export default class CallHandler {
|
|||
Analytics.trackEvent('voip', 'receiveCall', 'type', call.type);
|
||||
this.calls.set(mappedRoomId, call)
|
||||
this.setCallListeners(call);
|
||||
|
||||
// get ready to send encrypted events in the room, so if the user does answer
|
||||
// the call, we'll be ready to send. NB. This is the protocol-level room ID not
|
||||
// the mapped one: that's where we'll send the events.
|
||||
const cli = MatrixClientPeg.get();
|
||||
cli.prepareToEncrypt(cli.getRoom(call.roomId));
|
||||
}
|
||||
break;
|
||||
case 'hangup':
|
||||
|
@ -696,6 +788,11 @@ export default class CallHandler {
|
|||
// don't remove the call yet: let the hangup event handler do it (otherwise it will throw
|
||||
// the hangup event away)
|
||||
break;
|
||||
case 'hangup_all':
|
||||
for (const call of this.calls.values()) {
|
||||
call.hangup(CallErrorCode.UserHangup, false);
|
||||
}
|
||||
break;
|
||||
case 'answer': {
|
||||
if (!this.calls.has(payload.room_id)) {
|
||||
return; // no call to answer
|
||||
|
@ -779,8 +876,9 @@ export default class CallHandler {
|
|||
// https://github.com/matrix-org/prosody-mod-auth-matrix-user-verification
|
||||
confId = base32.stringify(Buffer.from(roomId), { pad: false });
|
||||
} else {
|
||||
// Create a random human readable conference ID
|
||||
confId = `JitsiConference${generateHumanReadableId()}`;
|
||||
// Create a random conference ID
|
||||
const random = randomUppercaseString(1) + randomLowercaseString(23);
|
||||
confId = 'Jitsi' + random;
|
||||
}
|
||||
|
||||
let widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl({auth: jitsiAuth});
|
||||
|
@ -796,6 +894,7 @@ export default class CallHandler {
|
|||
isAudioOnly: type === 'voice',
|
||||
domain: jitsiDomain,
|
||||
auth: jitsiAuth,
|
||||
roomName: room.name,
|
||||
};
|
||||
|
||||
const widgetId = (
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Matrix from 'matrix-js-sdk';
|
||||
import SettingsStore from "./settings/SettingsStore";
|
||||
import {SettingLevel} from "./settings/SettingLevel";
|
||||
import {setMatrixCallAudioInput, setMatrixCallAudioOutput, setMatrixCallVideoInput} from "matrix-js-sdk/src/matrix";
|
||||
|
||||
export default {
|
||||
hasAnyLabeledDevices: async function() {
|
||||
|
@ -54,24 +54,24 @@ export default {
|
|||
const audioDeviceId = SettingsStore.getValue("webrtc_audioinput");
|
||||
const videoDeviceId = SettingsStore.getValue("webrtc_videoinput");
|
||||
|
||||
Matrix.setMatrixCallAudioOutput(audioOutDeviceId);
|
||||
Matrix.setMatrixCallAudioInput(audioDeviceId);
|
||||
Matrix.setMatrixCallVideoInput(videoDeviceId);
|
||||
setMatrixCallAudioOutput(audioOutDeviceId);
|
||||
setMatrixCallAudioInput(audioDeviceId);
|
||||
setMatrixCallVideoInput(videoDeviceId);
|
||||
},
|
||||
|
||||
setAudioOutput: function(deviceId) {
|
||||
SettingsStore.setValue("webrtc_audiooutput", null, SettingLevel.DEVICE, deviceId);
|
||||
Matrix.setMatrixCallAudioOutput(deviceId);
|
||||
setMatrixCallAudioOutput(deviceId);
|
||||
},
|
||||
|
||||
setAudioInput: function(deviceId) {
|
||||
SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId);
|
||||
Matrix.setMatrixCallAudioInput(deviceId);
|
||||
setMatrixCallAudioInput(deviceId);
|
||||
},
|
||||
|
||||
setVideoInput: function(deviceId) {
|
||||
SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId);
|
||||
Matrix.setMatrixCallVideoInput(deviceId);
|
||||
setMatrixCallVideoInput(deviceId);
|
||||
},
|
||||
|
||||
getAudioOutput: function() {
|
||||
|
|
|
@ -32,6 +32,14 @@ import Spinner from "./components/views/elements/Spinner";
|
|||
import "blueimp-canvas-to-blob";
|
||||
import { Action } from "./dispatcher/actions";
|
||||
import CountlyAnalytics from "./CountlyAnalytics";
|
||||
import {
|
||||
UploadCanceledPayload,
|
||||
UploadErrorPayload,
|
||||
UploadFinishedPayload,
|
||||
UploadProgressPayload,
|
||||
UploadStartedPayload,
|
||||
} from "./dispatcher/payloads/UploadPayload";
|
||||
import {IUpload} from "./models/IUpload";
|
||||
|
||||
const MAX_WIDTH = 800;
|
||||
const MAX_HEIGHT = 600;
|
||||
|
@ -44,15 +52,6 @@ export class UploadCanceledError extends Error {}
|
|||
|
||||
type ThumbnailableElement = HTMLImageElement | HTMLVideoElement;
|
||||
|
||||
interface IUpload {
|
||||
fileName: string;
|
||||
roomId: string;
|
||||
total: number;
|
||||
loaded: number;
|
||||
promise: Promise<any>;
|
||||
canceled?: boolean;
|
||||
}
|
||||
|
||||
interface IMediaConfig {
|
||||
"m.upload.size"?: number;
|
||||
}
|
||||
|
@ -478,7 +477,7 @@ export default class ContentMessages {
|
|||
if (upload) {
|
||||
upload.canceled = true;
|
||||
MatrixClientPeg.get().cancelUpload(upload.promise);
|
||||
dis.dispatch({action: 'upload_canceled', upload});
|
||||
dis.dispatch<UploadCanceledPayload>({action: Action.UploadCanceled, upload});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -539,7 +538,7 @@ export default class ContentMessages {
|
|||
promise: prom,
|
||||
};
|
||||
this.inprogress.push(upload);
|
||||
dis.dispatch({action: 'upload_started'});
|
||||
dis.dispatch<UploadStartedPayload>({action: Action.UploadStarted, upload});
|
||||
|
||||
// Focus the composer view
|
||||
dis.fire(Action.FocusComposer);
|
||||
|
@ -547,7 +546,7 @@ export default class ContentMessages {
|
|||
function onProgress(ev) {
|
||||
upload.total = ev.total;
|
||||
upload.loaded = ev.loaded;
|
||||
dis.dispatch({action: 'upload_progress', upload: upload});
|
||||
dis.dispatch<UploadProgressPayload>({action: Action.UploadProgress, upload});
|
||||
}
|
||||
|
||||
let error;
|
||||
|
@ -601,9 +600,9 @@ export default class ContentMessages {
|
|||
if (error && error.http_status === 413) {
|
||||
this.mediaConfig = null;
|
||||
}
|
||||
dis.dispatch({action: 'upload_failed', upload, error});
|
||||
dis.dispatch<UploadErrorPayload>({action: Action.UploadFailed, upload, error});
|
||||
} else {
|
||||
dis.dispatch({action: 'upload_finished', upload});
|
||||
dis.dispatch<UploadFinishedPayload>({action: Action.UploadFinished, upload});
|
||||
dis.dispatch({action: 'message_sent'});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -32,10 +32,10 @@ import { AllHtmlEntities } from 'html-entities';
|
|||
import SettingsStore from './settings/SettingsStore';
|
||||
import cheerio from 'cheerio';
|
||||
|
||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
||||
import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/Permalinks";
|
||||
import {SHORTCODE_TO_EMOJI, getEmojiFromUnicode} from "./emoji";
|
||||
import ReplyThread from "./components/views/elements/ReplyThread";
|
||||
import {mediaFromMxc} from "./customisations/Media";
|
||||
|
||||
linkifyMatrix(linkify);
|
||||
|
||||
|
@ -181,11 +181,9 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = { // custom to
|
|||
if (!attribs.src || !attribs.src.startsWith('mxc://') || !SettingsStore.getValue("showImages")) {
|
||||
return { tagName, attribs: {}};
|
||||
}
|
||||
attribs.src = MatrixClientPeg.get().mxcUrlToHttp(
|
||||
attribs.src,
|
||||
attribs.width || 800,
|
||||
attribs.height || 600,
|
||||
);
|
||||
const width = Number(attribs.width) || 800;
|
||||
const height = Number(attribs.height) || 600;
|
||||
attribs.src = mediaFromMxc(attribs.src).getThumbnailOfSourceHttp(width, height);
|
||||
return { tagName, attribs };
|
||||
},
|
||||
'code': function(tagName: string, attribs: sanitizeHtml.Attributes) {
|
||||
|
@ -239,6 +237,7 @@ const sanitizeHtmlParams: IExtendedSanitizeOptions = {
|
|||
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'sup', 'sub',
|
||||
'nl', 'li', 'b', 'i', 'u', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div',
|
||||
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'span', 'img',
|
||||
'details', 'summary',
|
||||
],
|
||||
allowedAttributes: {
|
||||
// custom ones first:
|
||||
|
|
|
@ -14,7 +14,8 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { createClient, SERVICE_TYPES } from 'matrix-js-sdk';
|
||||
import { SERVICE_TYPES } from 'matrix-js-sdk/src/service-types';
|
||||
import { createClient } from 'matrix-js-sdk/src/matrix';
|
||||
|
||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
||||
import Modal from './Modal';
|
||||
|
|
|
@ -17,8 +17,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// @ts-ignore - XXX: tsc doesn't like this: our js-sdk imports are complex so this isn't surprising
|
||||
import Matrix from 'matrix-js-sdk';
|
||||
import { createClient } from 'matrix-js-sdk/src/matrix';
|
||||
import { InvalidStoreError } from "matrix-js-sdk/src/errors";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import {decryptAES, encryptAES} from "matrix-js-sdk/src/crypto/aes";
|
||||
|
@ -219,7 +218,7 @@ export function attemptTokenLogin(
|
|||
button: _t("Try again"),
|
||||
onFinished: tryAgain => {
|
||||
if (tryAgain) {
|
||||
const cli = Matrix.createClient({
|
||||
const cli = createClient({
|
||||
baseUrl: homeserver,
|
||||
idBaseUrl: identityServer,
|
||||
});
|
||||
|
@ -276,7 +275,7 @@ function registerAsGuest(
|
|||
console.log(`Doing guest login on ${hsUrl}`);
|
||||
|
||||
// create a temporary MatrixClient to do the login
|
||||
const client = Matrix.createClient({
|
||||
const client = createClient({
|
||||
baseUrl: hsUrl,
|
||||
});
|
||||
|
||||
|
|
55
src/Livestream.ts
Normal file
|
@ -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.
|
||||
*/
|
||||
|
||||
import { ClientWidgetApi } from "matrix-widget-api";
|
||||
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||
import SdkConfig from "./SdkConfig";
|
||||
import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
|
||||
|
||||
export function getConfigLivestreamUrl() {
|
||||
return SdkConfig.get()["audioStreamUrl"];
|
||||
}
|
||||
|
||||
// Dummy rtmp URL used to signal that we want a special audio-only stream
|
||||
const AUDIOSTREAM_DUMMY_URL = 'rtmp://audiostream.dummy/';
|
||||
|
||||
async function createLiveStream(roomId: string) {
|
||||
const openIdToken = await MatrixClientPeg.get().getOpenIdToken();
|
||||
|
||||
const url = getConfigLivestreamUrl() + "/createStream";
|
||||
|
||||
const response = await window.fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
room_id: roomId,
|
||||
openid_token: openIdToken,
|
||||
}),
|
||||
});
|
||||
|
||||
const respBody = await response.json();
|
||||
return respBody['stream_id'];
|
||||
}
|
||||
|
||||
export async function startJitsiAudioLivestream(widgetMessaging: ClientWidgetApi, roomId: string) {
|
||||
const streamId = await createLiveStream(roomId);
|
||||
|
||||
await widgetMessaging.transport.send(ElementWidgetActions.StartLiveStream, {
|
||||
rtmpStreamKey: AUDIOSTREAM_DUMMY_URL + streamId,
|
||||
});
|
||||
}
|
|
@ -19,7 +19,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
// @ts-ignore - XXX: tsc doesn't like this: our js-sdk imports are complex so this isn't surprising
|
||||
import Matrix from "matrix-js-sdk";
|
||||
import {createClient} from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { IMatrixClientCreds } from "./MatrixClientPeg";
|
||||
import SecurityCustomisations from "./customisations/Security";
|
||||
|
@ -115,7 +115,7 @@ export default class Login {
|
|||
*/
|
||||
public createTemporaryClient(): MatrixClient {
|
||||
if (this.tempClient) return this.tempClient; // use memoization
|
||||
return this.tempClient = Matrix.createClient({
|
||||
return this.tempClient = createClient({
|
||||
baseUrl: this.hsUrl,
|
||||
idBaseUrl: this.isUrl,
|
||||
});
|
||||
|
@ -210,7 +210,7 @@ export async function sendLoginRequest(
|
|||
loginType: string,
|
||||
loginParams: ILoginParams,
|
||||
): Promise<IMatrixClientCreds> {
|
||||
const client = Matrix.createClient({
|
||||
const client = createClient({
|
||||
baseUrl: hsUrl,
|
||||
idBaseUrl: isUrl,
|
||||
});
|
||||
|
|
|
@ -261,7 +261,7 @@ class _MatrixClientPeg implements IMatrixClientPeg {
|
|||
}
|
||||
|
||||
public getHomeserverName(): string {
|
||||
const matches = /^@.+:(.+)$/.exec(this.matrixClient.credentials.userId);
|
||||
const matches = /^@[^:]+:(.+)$/.exec(this.matrixClient.credentials.userId);
|
||||
if (matches === null || matches.length < 1) {
|
||||
throw new Error("Failed to derive homeserver name from user ID!");
|
||||
}
|
||||
|
@ -279,6 +279,10 @@ class _MatrixClientPeg implements IMatrixClientPeg {
|
|||
timelineSupport: true,
|
||||
forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer'),
|
||||
fallbackICEServerAllowed: !!SettingsStore.getValue('fallbackICEServerAllowed'),
|
||||
// Gather up to 20 ICE candidates when a call arrives: this should be more than we'd
|
||||
// ever normally need, so effectively this should make all the gathering happen when
|
||||
// the call arrives.
|
||||
iceCandidatePoolSize: 20,
|
||||
verificationMethods: [
|
||||
verificationMethods.SAS,
|
||||
SHOW_QR_CODE_METHOD,
|
||||
|
|
|
@ -36,6 +36,7 @@ import {SettingLevel} from "./settings/SettingLevel";
|
|||
import {isPushNotifyDisabled} from "./settings/controllers/NotificationControllers";
|
||||
import RoomViewStore from "./stores/RoomViewStore";
|
||||
import UserActivity from "./UserActivity";
|
||||
import {mediaFromMxc} from "./customisations/Media";
|
||||
|
||||
/*
|
||||
* Dispatches:
|
||||
|
@ -150,7 +151,7 @@ export const Notifier = {
|
|||
// Ideally in here we could use MSC1310 to detect the type of file, and reject it.
|
||||
|
||||
return {
|
||||
url: MatrixClientPeg.get().mxcUrlToHttp(content.url),
|
||||
url: mediaFromMxc(content.url).srcHttp,
|
||||
name: content.name,
|
||||
type: content.type,
|
||||
size: content.size,
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* For two objects of the form { key: [val1, val2, val3] }, work out the added/removed
|
||||
* values. Entirely new keys will result in the entire value array being added.
|
||||
* @param {Object} before
|
||||
* @param {Object} after
|
||||
* @return {Object[]} An array of objects with the form:
|
||||
* { key: $KEY, val: $VALUE, place: "add|del" }
|
||||
*/
|
||||
export function getKeyValueArrayDiffs(before, after) {
|
||||
const results = [];
|
||||
const delta = {};
|
||||
Object.keys(before).forEach(function(beforeKey) {
|
||||
delta[beforeKey] = delta[beforeKey] || 0; // init to 0 initially
|
||||
delta[beforeKey]--; // keys present in the past have -ve values
|
||||
});
|
||||
Object.keys(after).forEach(function(afterKey) {
|
||||
delta[afterKey] = delta[afterKey] || 0; // init to 0 initially
|
||||
delta[afterKey]++; // keys present in the future have +ve values
|
||||
});
|
||||
|
||||
Object.keys(delta).forEach(function(muxedKey) {
|
||||
switch (delta[muxedKey]) {
|
||||
case 1: // A new key in after
|
||||
after[muxedKey].forEach(function(afterVal) {
|
||||
results.push({ place: "add", key: muxedKey, val: afterVal });
|
||||
});
|
||||
break;
|
||||
case -1: // A before key was removed
|
||||
before[muxedKey].forEach(function(beforeVal) {
|
||||
results.push({ place: "del", key: muxedKey, val: beforeVal });
|
||||
});
|
||||
break;
|
||||
case 0: {// A mix of added/removed keys
|
||||
// compare old & new vals
|
||||
const itemDelta = {};
|
||||
before[muxedKey].forEach(function(beforeVal) {
|
||||
itemDelta[beforeVal] = itemDelta[beforeVal] || 0;
|
||||
itemDelta[beforeVal]--;
|
||||
});
|
||||
after[muxedKey].forEach(function(afterVal) {
|
||||
itemDelta[afterVal] = itemDelta[afterVal] || 0;
|
||||
itemDelta[afterVal]++;
|
||||
});
|
||||
|
||||
Object.keys(itemDelta).forEach(function(item) {
|
||||
if (itemDelta[item] === 1) {
|
||||
results.push({ place: "add", key: muxedKey, val: item });
|
||||
} else if (itemDelta[item] === -1) {
|
||||
results.push({ place: "del", key: muxedKey, val: item });
|
||||
} else {
|
||||
// itemDelta of 0 means it was unchanged between before/after
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.error("Calculated key delta of " + delta[muxedKey] + " - this should never happen!");
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shallow-compare two objects for equality: each key and value must be identical
|
||||
* @param {Object} objA First object to compare against the second
|
||||
* @param {Object} objB Second object to compare against the first
|
||||
* @return {boolean} whether the two objects have same key=values
|
||||
*/
|
||||
export function shallowEqual(objA, objB) {
|
||||
if (objA === objB) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof objA !== 'object' || objA === null ||
|
||||
typeof objB !== 'object' || objB === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const keysA = Object.keys(objA);
|
||||
const keysB = Object.keys(objB);
|
||||
|
||||
if (keysA.length !== keysB.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < keysA.length; i++) {
|
||||
const key = keysA[i];
|
||||
if (!objB.hasOwnProperty(key) || objA[key] !== objB[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Matrix from 'matrix-js-sdk';
|
||||
import { createClient } from 'matrix-js-sdk/src/matrix';
|
||||
import { _t } from './languageHandler';
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,7 @@ export default class PasswordReset {
|
|||
* @param {string} identityUrl The URL to the IS which has linked the email -> mxid mapping.
|
||||
*/
|
||||
constructor(homeserverUrl, identityUrl) {
|
||||
this.client = Matrix.createClient({
|
||||
this.client = createClient({
|
||||
baseUrl: homeserverUrl,
|
||||
idBaseUrl: identityUrl,
|
||||
});
|
||||
|
|
|
@ -1,51 +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 SdkConfig from './SdkConfig';
|
||||
import {hashCode} from './utils/FormattingUtils';
|
||||
|
||||
export function phasedRollOutExpiredForUser(username, feature, now, rollOutConfig = SdkConfig.get().phasedRollOut) {
|
||||
if (!rollOutConfig) {
|
||||
console.log(`no phased rollout configuration, so enabling ${feature}`);
|
||||
return true;
|
||||
}
|
||||
const featureConfig = rollOutConfig[feature];
|
||||
if (!featureConfig) {
|
||||
console.log(`${feature} doesn't have phased rollout configured, so enabling`);
|
||||
return true;
|
||||
}
|
||||
if (!Number.isFinite(featureConfig.offset) || !Number.isFinite(featureConfig.period)) {
|
||||
console.error(`phased rollout of ${feature} is misconfigured, ` +
|
||||
`offset and/or period are not numbers, so disabling`, featureConfig);
|
||||
return false;
|
||||
}
|
||||
|
||||
const hash = hashCode(username);
|
||||
//ms -> min, enable users at minute granularity
|
||||
const bucketRatio = 1000 * 60;
|
||||
const bucketCount = featureConfig.period / bucketRatio;
|
||||
const userBucket = hash % bucketCount;
|
||||
const userMs = userBucket * bucketRatio;
|
||||
const enableAt = featureConfig.offset + userMs;
|
||||
const result = now >= enableAt;
|
||||
const bucketStr = `(bucket ${userBucket}/${bucketCount})`;
|
||||
if (result) {
|
||||
console.log(`${feature} enabled for ${username} ${bucketStr}`);
|
||||
} else {
|
||||
console.log(`${feature} will be enabled for ${username} in ${Math.ceil((enableAt - now)/1000)}s ${bucketStr}`);
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -99,9 +99,9 @@ class Presence {
|
|||
|
||||
try {
|
||||
await MatrixClientPeg.get().setPresence(this.state);
|
||||
console.info("Presence: %s", newState);
|
||||
console.info("Presence:", newState);
|
||||
} catch (err) {
|
||||
console.error("Failed to set presence: %s", err);
|
||||
console.error("Failed to set presence:", err);
|
||||
this.state = oldState;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
|
||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
||||
import dis from './dispatcher/dispatcher';
|
||||
import { EventStatus } from 'matrix-js-sdk';
|
||||
import { EventStatus } from 'matrix-js-sdk/src/models/event';
|
||||
|
||||
export default class Resend {
|
||||
static resendUnsentEvents(room) {
|
||||
|
|
|
@ -22,7 +22,7 @@ import MultiInviter from './utils/MultiInviter';
|
|||
import Modal from './Modal';
|
||||
import * as sdk from './';
|
||||
import { _t } from './languageHandler';
|
||||
import {KIND_DM, KIND_INVITE} from "./components/views/dialogs/InviteDialog";
|
||||
import InviteDialog, {KIND_DM, KIND_INVITE} from "./components/views/dialogs/InviteDialog";
|
||||
import CommunityPrototypeInviteDialog from "./components/views/dialogs/CommunityPrototypeInviteDialog";
|
||||
import {CommunityPrototypeStore} from "./stores/CommunityPrototypeStore";
|
||||
|
||||
|
@ -51,9 +51,11 @@ export function showStartChatInviteDialog(initialText) {
|
|||
|
||||
export function showRoomInviteDialog(roomId) {
|
||||
// This dialog handles the room creation internally - we don't need to worry about it.
|
||||
const InviteDialog = sdk.getComponent("dialogs.InviteDialog");
|
||||
Modal.createTrackedDialog(
|
||||
'Invite Users', '', InviteDialog, {kind: KIND_INVITE, roomId},
|
||||
"Invite Users", "", InviteDialog, {
|
||||
kind: KIND_INVITE,
|
||||
roomId,
|
||||
},
|
||||
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ import { Service, startTermsFlow, TermsNotSignedError } from './Terms';
|
|||
import {MatrixClientPeg} from "./MatrixClientPeg";
|
||||
import request from "browser-request";
|
||||
|
||||
import * as Matrix from 'matrix-js-sdk';
|
||||
import SdkConfig from "./SdkConfig";
|
||||
import {WidgetType} from "./widgets/WidgetType";
|
||||
import {SERVICE_TYPES} from "matrix-js-sdk/src/service-types";
|
||||
|
||||
// The version of the integration manager API we're intending to work with
|
||||
const imApiVersion = "1.1";
|
||||
|
@ -153,7 +153,7 @@ export default class ScalarAuthClient {
|
|||
parsedImRestUrl.path = '';
|
||||
parsedImRestUrl.pathname = '';
|
||||
return startTermsFlow([new Service(
|
||||
Matrix.SERVICE_TYPES.IM,
|
||||
SERVICE_TYPES.IM,
|
||||
parsedImRestUrl.format(),
|
||||
token,
|
||||
)], this.termsInteractionCallback).then(() => {
|
||||
|
|
|
@ -237,7 +237,7 @@ Example:
|
|||
*/
|
||||
|
||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
||||
import { MatrixEvent } from 'matrix-js-sdk';
|
||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
import dis from './dispatcher/dispatcher';
|
||||
import WidgetUtils from './utils/WidgetUtils';
|
||||
import RoomViewStore from './stores/RoomViewStore';
|
||||
|
|
|
@ -98,11 +98,27 @@ async function getSecretStorageKey(
|
|||
{ keys: keyInfos }: { keys: Record<string, ISecretStorageKeyInfo> },
|
||||
ssssItemName,
|
||||
): Promise<[string, Uint8Array]> {
|
||||
const cli = MatrixClientPeg.get();
|
||||
let keyId = await cli.getDefaultSecretStorageKeyId();
|
||||
let keyInfo;
|
||||
if (keyId) {
|
||||
// use the default SSSS key if set
|
||||
keyInfo = keyInfos[keyId];
|
||||
if (!keyInfo) {
|
||||
// if the default key is not available, pretend the default key
|
||||
// isn't set
|
||||
keyId = undefined;
|
||||
}
|
||||
}
|
||||
if (!keyId) {
|
||||
// if no default SSSS key is set, fall back to a heuristic of using the
|
||||
// only available key, if only one key is set
|
||||
const keyInfoEntries = Object.entries(keyInfos);
|
||||
if (keyInfoEntries.length > 1) {
|
||||
throw new Error("Multiple storage key requests not implemented");
|
||||
}
|
||||
const [keyId, keyInfo] = keyInfoEntries[0];
|
||||
[keyId, keyInfo] = keyInfoEntries[0];
|
||||
}
|
||||
|
||||
// Check the in-memory cache
|
||||
if (isCachingAllowed() && secretStorageKeys[keyId]) {
|
||||
|
|
|
@ -23,7 +23,7 @@ class Skinner {
|
|||
if (!name) throw new Error(`Invalid component name: ${name}`);
|
||||
if (this.components === null) {
|
||||
throw new Error(
|
||||
"Attempted to get a component before a skin has been loaded."+
|
||||
`Attempted to get a component (${name}) before a skin has been loaded.`+
|
||||
" This is probably because either:"+
|
||||
" a) Your app has not called sdk.loadSkin(), or"+
|
||||
" b) A component has called getComponent at the root level",
|
||||
|
|
|
@ -441,15 +441,14 @@ export const Commands = [
|
|||
}),
|
||||
new Command({
|
||||
command: 'invite',
|
||||
args: '<user-id>',
|
||||
args: '<user-id> [<reason>]',
|
||||
description: _td('Invites user with given id to current room'),
|
||||
runFn: function(roomId, args) {
|
||||
if (args) {
|
||||
const matches = args.match(/^(\S+)$/);
|
||||
if (matches) {
|
||||
const [address, reason] = args.split(/\s+(.+)/);
|
||||
if (address) {
|
||||
// We use a MultiInviter to re-use the invite logic, even though
|
||||
// we're only inviting one user.
|
||||
const address = matches[1];
|
||||
// If we need an identity server but don't have one, things
|
||||
// get a bit more complex here, but we try to show something
|
||||
// meaningful.
|
||||
|
@ -490,7 +489,7 @@ export const Commands = [
|
|||
}
|
||||
const inviter = new MultiInviter(roomId);
|
||||
return success(prom.then(() => {
|
||||
return inviter.invite([address]);
|
||||
return inviter.invite([address], reason);
|
||||
}).then(() => {
|
||||
if (inviter.getCompletionState(address) !== "invited") {
|
||||
throw new Error(inviter.getErrorText(address));
|
||||
|
@ -1040,9 +1039,7 @@ export const Commands = [
|
|||
|
||||
return success((async () => {
|
||||
if (isPhoneNumber) {
|
||||
const results = await MatrixClientPeg.get().getThirdpartyUser('im.vector.protocol.pstn', {
|
||||
'm.id.phone': userId,
|
||||
});
|
||||
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");
|
||||
}
|
||||
|
@ -1182,7 +1179,7 @@ export function parseCommandString(input: string) {
|
|||
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) {
|
||||
|
|
|
@ -118,25 +118,10 @@ export default class Velociraptor extends React.Component {
|
|||
domNode.style.visibility = restingStyle.visibility;
|
||||
});
|
||||
|
||||
/*
|
||||
console.log("enter:",
|
||||
JSON.stringify(transitionOpts[i-1]),
|
||||
"->",
|
||||
JSON.stringify(restingStyle));
|
||||
*/
|
||||
} else if (node === null) {
|
||||
// Velocity stores data on elements using the jQuery .data()
|
||||
// method, and assumes you'll be using jQuery's .remove() to
|
||||
// remove the element, but we don't use jQuery, so we need to
|
||||
// blow away the element's data explicitly otherwise it will leak.
|
||||
// This uses Velocity's internal jQuery compatible wrapper.
|
||||
// See the bug at
|
||||
// https://github.com/julianshapiro/velocity/issues/300
|
||||
// and the FAQ entry, "Preventing memory leaks when
|
||||
// creating/destroying large numbers of elements"
|
||||
// (https://github.com/julianshapiro/velocity/issues/47)
|
||||
const domNode = ReactDom.findDOMNode(this.nodes[k]);
|
||||
if (domNode) Velocity.Utilities.removeData(domNode);
|
||||
// console.log("enter:",
|
||||
// JSON.stringify(transitionOpts[i-1]),
|
||||
// "->",
|
||||
// JSON.stringify(restingStyle));
|
||||
}
|
||||
this.nodes[k] = node;
|
||||
}
|
||||
|
|
|
@ -14,66 +14,99 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { ensureDMExists, findDMForUser } from './createRoom';
|
||||
import { ensureVirtualRoomExists, findDMForUser } from './createRoom';
|
||||
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||
import DMRoomMap from "./utils/DMRoomMap";
|
||||
import SdkConfig from "./SdkConfig";
|
||||
import CallHandler, { VIRTUAL_ROOM_EVENT_TYPE } from './CallHandler';
|
||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
|
||||
// Functions for mapping users & rooms for the voip_mxid_translate_pattern
|
||||
// config option
|
||||
// Functions for mapping virtual users & rooms. Currently the only lookup
|
||||
// is sip virtual: there could be others in the future.
|
||||
|
||||
export function voipUserMapperEnabled(): boolean {
|
||||
return SdkConfig.get()['voip_mxid_translate_pattern'] !== undefined;
|
||||
}
|
||||
export default class VoipUserMapper {
|
||||
private virtualRoomIdCache = new Set<string>();
|
||||
|
||||
// only exported for tests
|
||||
export function userToVirtualUser(userId: string, templateString?: string): string {
|
||||
if (templateString === undefined) templateString = SdkConfig.get()['voip_mxid_translate_pattern'];
|
||||
if (!templateString) return null;
|
||||
return templateString.replace('${mxid}', encodeURIComponent(userId).replace(/%/g, '=').toLowerCase());
|
||||
}
|
||||
public static sharedInstance(): VoipUserMapper {
|
||||
if (window.mxVoipUserMapper === undefined) window.mxVoipUserMapper = new VoipUserMapper();
|
||||
return window.mxVoipUserMapper;
|
||||
}
|
||||
|
||||
// only exported for tests
|
||||
export function virtualUserToUser(userId: string, templateString?: string): string {
|
||||
if (templateString === undefined) templateString = SdkConfig.get()['voip_mxid_translate_pattern'];
|
||||
if (!templateString) return null;
|
||||
private async userToVirtualUser(userId: string): Promise<string> {
|
||||
const results = await CallHandler.sharedInstance().sipVirtualLookup(userId);
|
||||
if (results.length === 0) return null;
|
||||
return results[0].userid;
|
||||
}
|
||||
|
||||
const regexString = templateString.replace('${mxid}', '(.+)');
|
||||
public async getOrCreateVirtualRoomForRoom(roomId: string): Promise<string> {
|
||||
const userId = DMRoomMap.shared().getUserIdForRoomId(roomId);
|
||||
if (!userId) return null;
|
||||
|
||||
const match = userId.match('^' + regexString + '$');
|
||||
if (!match) return null;
|
||||
|
||||
return decodeURIComponent(match[1].replace(/=/g, '%'));
|
||||
}
|
||||
|
||||
async function getOrCreateVirtualRoomForUser(userId: string):Promise<string> {
|
||||
const virtualUser = userToVirtualUser(userId);
|
||||
const virtualUser = await this.userToVirtualUser(userId);
|
||||
if (!virtualUser) return null;
|
||||
|
||||
return await ensureDMExists(MatrixClientPeg.get(), virtualUser);
|
||||
}
|
||||
const virtualRoomId = await ensureVirtualRoomExists(MatrixClientPeg.get(), virtualUser, roomId);
|
||||
MatrixClientPeg.get().setRoomAccountData(virtualRoomId, VIRTUAL_ROOM_EVENT_TYPE, {
|
||||
native_room: roomId,
|
||||
});
|
||||
|
||||
export async function getOrCreateVirtualRoomForRoom(roomId: string):Promise<string> {
|
||||
const user = DMRoomMap.shared().getUserIdForRoomId(roomId);
|
||||
if (!user) return null;
|
||||
return getOrCreateVirtualRoomForUser(user);
|
||||
}
|
||||
return virtualRoomId;
|
||||
}
|
||||
|
||||
export function roomForVirtualRoom(roomId: string):string {
|
||||
const virtualUser = DMRoomMap.shared().getUserIdForRoomId(roomId);
|
||||
if (!virtualUser) return null;
|
||||
const realUser = virtualUserToUser(virtualUser);
|
||||
const room = findDMForUser(MatrixClientPeg.get(), realUser);
|
||||
if (room) {
|
||||
return room.roomId;
|
||||
} else {
|
||||
return null;
|
||||
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;
|
||||
return virtualRoomEvent.getContent()['native_room'] || null;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isVirtualRoom(roomId: string):boolean {
|
||||
const virtualUser = DMRoomMap.shared().getUserIdForRoomId(roomId);
|
||||
if (!virtualUser) return null;
|
||||
const realUser = virtualUserToUser(virtualUser);
|
||||
return Boolean(realUser);
|
||||
}
|
||||
|
|
|
@ -19,14 +19,23 @@ 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<typeof AccessibleButton> {
|
||||
label?: string;
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
// Semantic component for representing a role=menuitem
|
||||
export const MenuItem: React.FC<IProps> = ({children, label, ...props}) => {
|
||||
export const MenuItem: React.FC<IProps> = ({children, label, tooltip, ...props}) => {
|
||||
const ariaLabel = props["aria-label"] || label;
|
||||
|
||||
if (tooltip) {
|
||||
return <AccessibleTooltipButton {...props} role="menuitem" tabIndex={-1} aria-label={ariaLabel} title={tooltip}>
|
||||
{ children }
|
||||
</AccessibleTooltipButton>;
|
||||
}
|
||||
|
||||
return (
|
||||
<AccessibleButton {...props} role="menuitem" tabIndex={-1} aria-label={ariaLabel}>
|
||||
{ children }
|
||||
|
|
|
@ -19,7 +19,7 @@ import React, {createRef} from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { _t } from '../../../../languageHandler';
|
||||
|
||||
import { MatrixClient } from 'matrix-js-sdk';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import * as MegolmExportEncryption from '../../../../utils/MegolmExportEncryption';
|
||||
import * as sdk from '../../../../index';
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
import React, {createRef} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { MatrixClient } from 'matrix-js-sdk';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import * as MegolmExportEncryption from '../../../../utils/MegolmExportEncryption';
|
||||
import * as sdk from '../../../../index';
|
||||
import { _t } from '../../../../languageHandler';
|
||||
|
|
|
@ -27,6 +27,7 @@ import {sortBy} from "lodash";
|
|||
import {makeGroupPermalink} from "../utils/permalinks/Permalinks";
|
||||
import {ICompletion, ISelectionRange} from "./Autocompleter";
|
||||
import FlairStore from "../stores/FlairStore";
|
||||
import {mediaFromMxc} from "../customisations/Media";
|
||||
|
||||
const COMMUNITY_REGEX = /\B\+\S*/g;
|
||||
|
||||
|
@ -95,7 +96,7 @@ export default class CommunityProvider extends AutocompleteProvider {
|
|||
name={name || groupId}
|
||||
width={24}
|
||||
height={24}
|
||||
url={avatarUrl ? cli.mxcUrlToHttp(avatarUrl, 24, 24) : null} />
|
||||
url={avatarUrl ? mediaFromMxc(avatarUrl).getSquareThumbnailHttp(24) : null} />
|
||||
</PillCompletion>
|
||||
),
|
||||
range,
|
||||
|
|
|
@ -155,6 +155,7 @@ export default class UserProvider extends AutocompleteProvider {
|
|||
|
||||
const currentUserId = MatrixClientPeg.get().credentials.userId;
|
||||
this.users = this.room.getJoinedMembers().filter(({userId}) => userId !== currentUserId);
|
||||
this.users = this.users.concat(this.room.getMembersWithMembership("invite"));
|
||||
|
||||
this.users = sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import classNames from "classnames";
|
|||
|
||||
import {Key} from "../../Keyboard";
|
||||
import {Writeable} from "../../@types/common";
|
||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
||||
|
||||
// Shamelessly ripped off Modal.js. There's probably a better way
|
||||
// of doing reusable widgets like dialog boxes & menus where we go and
|
||||
|
@ -76,6 +77,7 @@ export interface IProps extends IPosition {
|
|||
hasBackground?: boolean;
|
||||
// whether this context menu should be focus managed. If false it must handle itself
|
||||
managed?: boolean;
|
||||
wrapperClassName?: string;
|
||||
|
||||
// Function to be called on menu close
|
||||
onFinished();
|
||||
|
@ -90,6 +92,7 @@ interface IState {
|
|||
// Generic ContextMenu Portal wrapper
|
||||
// all options inside the menu should be of role=menuitem/menuitemcheckbox/menuitemradiobutton and have tabIndex={-1}
|
||||
// this will allow the ContextMenu to manage its own focus using arrow keys as per the ARIA guidelines.
|
||||
@replaceableComponent("structures.ContextMenu")
|
||||
export class ContextMenu extends React.PureComponent<IProps, IState> {
|
||||
private initialFocus: HTMLElement;
|
||||
|
||||
|
@ -299,7 +302,7 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
|
|||
// such that it does not leave the (padded) window.
|
||||
if (contextMenuRect) {
|
||||
const padding = 10;
|
||||
adjusted = Math.min(position.top, document.body.clientHeight - contextMenuRect.height + padding);
|
||||
adjusted = Math.min(position.top, document.body.clientHeight - contextMenuRect.height - padding);
|
||||
}
|
||||
|
||||
position.top = adjusted;
|
||||
|
@ -365,7 +368,7 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="mx_ContextualMenu_wrapper"
|
||||
className={classNames("mx_ContextualMenu_wrapper", this.props.wrapperClassName)}
|
||||
style={{...position, ...wrapperStyle}}
|
||||
onKeyDown={this.onKeyDown}
|
||||
onContextMenu={this.onContextMenuPreventBubbling}
|
||||
|
@ -390,7 +393,7 @@ export class ContextMenu extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
|
||||
// Placement method for <ContextMenu /> to position context menu to right of elementRect with chevronOffset
|
||||
export const toRightOf = (elementRect: DOMRect, chevronOffset = 12) => {
|
||||
export const toRightOf = (elementRect: Pick<DOMRect, "right" | "top" | "height">, chevronOffset = 12) => {
|
||||
const left = elementRect.right + window.pageXOffset + 3;
|
||||
let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
|
||||
top -= chevronOffset + 8; // where 8 is half the height of the chevron
|
||||
|
@ -466,6 +469,7 @@ export const useContextMenu = <T extends any = HTMLElement>(): ContextMenuTuple<
|
|||
return [isOpen, button, open, close, setIsOpen];
|
||||
};
|
||||
|
||||
@replaceableComponent("structures.LegacyContextMenu")
|
||||
export default class LegacyContextMenu extends ContextMenu {
|
||||
render() {
|
||||
return this.renderMenu(false);
|
||||
|
|
|
@ -21,7 +21,9 @@ import * as sdk from '../../index';
|
|||
import dis from '../../dispatcher/dispatcher';
|
||||
import classNames from 'classnames';
|
||||
import * as FormattingUtils from '../../utils/FormattingUtils';
|
||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
||||
|
||||
@replaceableComponent("structures.CustomRoomTagPanel")
|
||||
class CustomRoomTagPanel extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
|
@ -16,8 +16,6 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import request from 'browser-request';
|
||||
|
|