Merge remote-tracking branch 'upstream/develop' into compact-reply-rendering

pull/21833/head
Tulir Asokan 2020-09-04 12:41:38 +03:00
commit 75a0178dad
400 changed files with 12445 additions and 9279 deletions

View File

@ -19,7 +19,7 @@ module.exports = {
},
overrides: [{
"files": ["src/**/*.{ts, tsx}"],
"files": ["src/**/*.{ts,tsx}"],
"extends": ["matrix-org/ts"],
"rules": {
// We disable this while we're transitioning

View File

@ -17,7 +17,7 @@ module.exports = {
"at-rule-no-unknown": null,
"no-descending-specificity": null,
"scss/at-rule-no-unknown": [true, {
// https://github.com/vector-im/riot-web/issues/10544
// https://github.com/vector-im/element-web/issues/10544
"ignoreAtRules": ["define-mixin"],
}],
}

View File

@ -1,3 +1,206 @@
Changes in [3.3.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.3.0) (2020-09-01)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.3.0-rc.1...v3.3.0)
* Upgrade to JS SDK 8.2.0
Changes in [3.3.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.3.0-rc.1) (2020-08-26)
=============================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.2.0...v3.3.0-rc.1)
* Upgrade to JS SDK 8.2.0-rc.1
* Update from Weblate
[\#5146](https://github.com/matrix-org/matrix-react-sdk/pull/5146)
* BaseAvatar avoid initial render with default avatar
[\#5142](https://github.com/matrix-org/matrix-react-sdk/pull/5142)
* Enforce Secure Backup completion when requested by HS
[\#5130](https://github.com/matrix-org/matrix-react-sdk/pull/5130)
* Communities v2 prototype: Explore rooms, global state, and default room
[\#5139](https://github.com/matrix-org/matrix-react-sdk/pull/5139)
* Add communities v2 prototyping feature flag + initial tag panel prototypes
[\#5133](https://github.com/matrix-org/matrix-react-sdk/pull/5133)
* Remove some unused components
[\#5134](https://github.com/matrix-org/matrix-react-sdk/pull/5134)
* Allow avatar image view for 1:1 rooms
[\#5137](https://github.com/matrix-org/matrix-react-sdk/pull/5137)
* Send mx_local_settings in rageshake
[\#5136](https://github.com/matrix-org/matrix-react-sdk/pull/5136)
* Run all room leaving behaviour through a single function
[\#5132](https://github.com/matrix-org/matrix-react-sdk/pull/5132)
* Add clarifying comment in media device selection
[\#5131](https://github.com/matrix-org/matrix-react-sdk/pull/5131)
* Settings v3: Feature flag changes
[\#5124](https://github.com/matrix-org/matrix-react-sdk/pull/5124)
* Clear url previews if they all get edited out of the event
[\#5129](https://github.com/matrix-org/matrix-react-sdk/pull/5129)
* Consider tab completions as modifications for editing purposes to unlock
sending
[\#5128](https://github.com/matrix-org/matrix-react-sdk/pull/5128)
* Use matrix-doc for SAS emoji translations
[\#5125](https://github.com/matrix-org/matrix-react-sdk/pull/5125)
* Add a rageshake function to download the logs locally
[\#3849](https://github.com/matrix-org/matrix-react-sdk/pull/3849)
* Room List filtering visual tweaks
[\#5123](https://github.com/matrix-org/matrix-react-sdk/pull/5123)
* Make reply preview not an overlay so you can see new messages
[\#5072](https://github.com/matrix-org/matrix-react-sdk/pull/5072)
* Allow room tile context menu when minimized using right click
[\#5113](https://github.com/matrix-org/matrix-react-sdk/pull/5113)
* Add null guard to group inviter for corrupted groups
[\#5121](https://github.com/matrix-org/matrix-react-sdk/pull/5121)
* Room List styling tweaks
[\#5118](https://github.com/matrix-org/matrix-react-sdk/pull/5118)
* Fix corner rounding on images not always affecting right side
[\#5120](https://github.com/matrix-org/matrix-react-sdk/pull/5120)
* Change add room action for rooms to context menu
[\#5108](https://github.com/matrix-org/matrix-react-sdk/pull/5108)
* Switch out the globe icon and colour it depending on theme
[\#5106](https://github.com/matrix-org/matrix-react-sdk/pull/5106)
* Message Action Bar watch for event send changes
[\#5115](https://github.com/matrix-org/matrix-react-sdk/pull/5115)
* Put message previews for Emoji behind Labs
[\#5110](https://github.com/matrix-org/matrix-react-sdk/pull/5110)
* Fix styling for selected community marker
[\#5107](https://github.com/matrix-org/matrix-react-sdk/pull/5107)
* Fix action bar safe area regression
[\#5111](https://github.com/matrix-org/matrix-react-sdk/pull/5111)
* Fix /op slash command
[\#5109](https://github.com/matrix-org/matrix-react-sdk/pull/5109)
Changes in [3.2.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.2.0) (2020-08-17)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.2.0-rc.1...v3.2.0)
* Upgrade to JS SDK 8.1.0
* [Release] Fix corner rounding on images not always affecting right side
[\#5122](https://github.com/matrix-org/matrix-react-sdk/pull/5122)
* [Release] Message Action Bar watch for event send changes
[\#5116](https://github.com/matrix-org/matrix-react-sdk/pull/5116)
* Fix /op slash command to release
[\#5114](https://github.com/matrix-org/matrix-react-sdk/pull/5114)
* Fix action bar safe area regression
[\#5112](https://github.com/matrix-org/matrix-react-sdk/pull/5112)
Changes in [3.2.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.2.0-rc.1) (2020-08-13)
=============================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.1.0...v3.2.0-rc.1)
* Upgrade to JS SDK 8.1.0-rc.1
* Update from Weblate
[\#5105](https://github.com/matrix-org/matrix-react-sdk/pull/5105)
* padding the timeline so that its scrollbar has its own space from the
resizer
[\#5103](https://github.com/matrix-org/matrix-react-sdk/pull/5103)
* Try to close notification on all platforms which support it, not just
electron
[\#5102](https://github.com/matrix-org/matrix-react-sdk/pull/5102)
* Fix exception when stripping replies from an event with a non-string body
[\#5101](https://github.com/matrix-org/matrix-react-sdk/pull/5101)
* Quick win session 24/07/2020
[\#5056](https://github.com/matrix-org/matrix-react-sdk/pull/5056)
* Remove rebranding toast
[\#5100](https://github.com/matrix-org/matrix-react-sdk/pull/5100)
* Generate previews for rooms when the option changes
[\#5098](https://github.com/matrix-org/matrix-react-sdk/pull/5098)
* Fix Bridge Settings tab
[\#5095](https://github.com/matrix-org/matrix-react-sdk/pull/5095)
* get screen type from app prop
[\#5081](https://github.com/matrix-org/matrix-react-sdk/pull/5081)
* Update rageshake app name
[\#5093](https://github.com/matrix-org/matrix-react-sdk/pull/5093)
* Factor out Iconized Context menu for reusability
[\#5085](https://github.com/matrix-org/matrix-react-sdk/pull/5085)
* Decouple Audible notifications from Desktop notifications
[\#5088](https://github.com/matrix-org/matrix-react-sdk/pull/5088)
* Make the room sublist show more/less buttons treeitems
[\#5087](https://github.com/matrix-org/matrix-react-sdk/pull/5087)
* Share and debug master cross-signing key
[\#5092](https://github.com/matrix-org/matrix-react-sdk/pull/5092)
* Create Map comparison utilities and convert Hooks to Typescript
[\#5086](https://github.com/matrix-org/matrix-react-sdk/pull/5086)
* Fix room list scrolling in Safari
[\#5090](https://github.com/matrix-org/matrix-react-sdk/pull/5090)
* Replace Riot with Element in docs and comments
[\#5083](https://github.com/matrix-org/matrix-react-sdk/pull/5083)
* When the room view isn't active don't highlight it in room list
[\#5027](https://github.com/matrix-org/matrix-react-sdk/pull/5027)
* remove emoji icons in autocomplete/reply by designer request
[\#5073](https://github.com/matrix-org/matrix-react-sdk/pull/5073)
* Add title and icon to empty state of file and notification panel
[\#5079](https://github.com/matrix-org/matrix-react-sdk/pull/5079)
* Mass redact ignore room creation events
[\#5045](https://github.com/matrix-org/matrix-react-sdk/pull/5045)
* Replace all chevrons with a single icon
[\#5067](https://github.com/matrix-org/matrix-react-sdk/pull/5067)
* Replace i18n generation script with something matching our project
[\#5077](https://github.com/matrix-org/matrix-react-sdk/pull/5077)
* Handle tag changes in sticky room updates
[\#5078](https://github.com/matrix-org/matrix-react-sdk/pull/5078)
* Remove leftover bits of TSLint
[\#5075](https://github.com/matrix-org/matrix-react-sdk/pull/5075)
* Clean up documentation of Whenable + fix other code concerns
[\#5076](https://github.com/matrix-org/matrix-react-sdk/pull/5076)
* Center the jump down/up icon, looks misaligned
[\#5074](https://github.com/matrix-org/matrix-react-sdk/pull/5074)
* [WIP] Support a new settings structure
[\#5058](https://github.com/matrix-org/matrix-react-sdk/pull/5058)
* Convert SettingsStore to TypeScript
[\#5062](https://github.com/matrix-org/matrix-react-sdk/pull/5062)
Changes in [3.1.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.1.0) (2020-08-05)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.1.0-rc.1...v3.1.0)
* Upgrade JS SDK to 8.0.1
* Fix room list scrolling in Safari
[\#5091](https://github.com/matrix-org/matrix-react-sdk/pull/5091)
* Add null guard in InviteDialog
[\#5084](https://github.com/matrix-org/matrix-react-sdk/pull/5084)
* Add null guard in InviteDialog
[\#5082](https://github.com/matrix-org/matrix-react-sdk/pull/5082)
* Handle tag changes in sticky room updates
[\#5080](https://github.com/matrix-org/matrix-react-sdk/pull/5080)
Changes in [3.1.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.1.0-rc.1) (2020-07-31)
=============================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.0.0...v3.1.0-rc.1)
* Upgrade JS SDK to 8.0.1-rc.1
* Update from Weblate
[\#5071](https://github.com/matrix-org/matrix-react-sdk/pull/5071)
* Add local echo for notifications in the new room list
[\#5065](https://github.com/matrix-org/matrix-react-sdk/pull/5065)
* Fix various small regressions in the room list's behaviour
[\#5070](https://github.com/matrix-org/matrix-react-sdk/pull/5070)
* Remove redundant lint dependencies
[\#5059](https://github.com/matrix-org/matrix-react-sdk/pull/5059)
* Fix key backup warning on soft logout page
[\#5069](https://github.com/matrix-org/matrix-react-sdk/pull/5069)
* Bump elliptic from 6.5.2 to 6.5.3
[\#5066](https://github.com/matrix-org/matrix-react-sdk/pull/5066)
* Fix crash on logging in again after soft logout
[\#5068](https://github.com/matrix-org/matrix-react-sdk/pull/5068)
* Convert right_panel to TS
[\#5036](https://github.com/matrix-org/matrix-react-sdk/pull/5036)
* Remove all unreferenced images
[\#5063](https://github.com/matrix-org/matrix-react-sdk/pull/5063)
* Provide nicer error for no known servers error when accepting an invite
[\#5061](https://github.com/matrix-org/matrix-react-sdk/pull/5061)
* add logging for keytar/pickle key
[\#5057](https://github.com/matrix-org/matrix-react-sdk/pull/5057)
* Don't speak the outgoing message if it is in the Sending state.
[\#4075](https://github.com/matrix-org/matrix-react-sdk/pull/4075)
* Remove poorly contrasted "dark style" heading in Room Preview Bar
[\#5052](https://github.com/matrix-org/matrix-react-sdk/pull/5052)
* Fix Query Matcher regression with certain unhomoglyph'd characters
[\#5050](https://github.com/matrix-org/matrix-react-sdk/pull/5050)
* Fix handlebar interaction
[\#4989](https://github.com/matrix-org/matrix-react-sdk/pull/4989)
* Minor improvements to filtering performance
[\#5054](https://github.com/matrix-org/matrix-react-sdk/pull/5054)
* Fix TextWithTooltip "leaking" tooltip wrappers
[\#5055](https://github.com/matrix-org/matrix-react-sdk/pull/5055)
Changes in [3.0.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.0.0) (2020-07-27)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.10.1...v3.0.0)

View File

@ -11,14 +11,14 @@ a 'skin'. A skin provides:
* The containing application
* Zero or more 'modules' containing non-UI functionality
As of Aug 2018, the only skin that exists is `vector-im/riot-web`; it and
As of Aug 2018, the only skin that exists is `vector-im/element-web`; it and
`matrix-org/matrix-react-sdk` should effectively
be considered as a single project (for instance, matrix-react-sdk bugs
are currently filed against vector-im/riot-web rather than this project).
are currently filed against vector-im/element-web rather than this project).
Translation Status
==================
[![Translation status](https://translate.riot.im/widgets/riot-web/-/multi-auto.svg)](https://translate.riot.im/engage/riot-web/?utm_source=widget)
[![Translation status](https://translate.riot.im/widgets/element-web/-/multi-auto.svg)](https://translate.riot.im/engage/element-web/?utm_source=widget)
Developer Guide
===============
@ -41,10 +41,10 @@ https://github.com/matrix-org/matrix-react-sdk/blob/master/code_style.md
Code should be committed as follows:
* All new components: https://github.com/matrix-org/matrix-react-sdk/tree/master/src/components
* Riot-specific components: https://github.com/vector-im/riot-web/tree/master/src/components
* Element-specific components: https://github.com/vector-im/element-web/tree/master/src/components
* In practice, `matrix-react-sdk` is still evolving so fast that the maintenance
burden of customising and overriding these components for Riot can seriously
impede development. So right now, there should be very few (if any) customisations for Riot.
burden of customising and overriding these components for Element can seriously
impede development. So right now, there should be very few (if any) customisations for Element.
* CSS: https://github.com/matrix-org/matrix-react-sdk/tree/master/res/css
* Theme specific CSS & resources: https://github.com/matrix-org/matrix-react-sdk/tree/master/res/themes
@ -71,7 +71,7 @@ practices that anyone working with the SDK needs to be be aware of and uphold:
* The view's CSS file MUST have the same name (e.g. view/rooms/MessageTile.css).
CSS for matrix-react-sdk currently resides in
https://github.com/vector-im/riot-web/tree/master/src/skins/vector/css/matrix-react-sdk.
https://github.com/vector-im/element-web/tree/master/src/skins/vector/css/matrix-react-sdk.
* Per-view CSS is optional - it could choose to inherit all its styling from
the context of the rest of the app, although this is unusual for any but
@ -125,7 +125,7 @@ from it.
Github Issues
=============
All issues should be filed under https://github.com/vector-im/riot-web/issues
All issues should be filed under https://github.com/vector-im/element-web/issues
for now.
Development
@ -174,5 +174,5 @@ yarn test
## End-to-End tests
Make sure you've got your Riot development server running (by doing `yarn start` in riot-web), and then in this project, run `yarn run e2etests`.
Make sure you've got your Element development server running (by doing `yarn start` in element-web), and then in this project, run `yarn run e2etests`.
See `test/end-to-end-tests/README.md` for more information.

View File

@ -1,6 +1,6 @@
# The CIDER (Contenteditable-Input-Diff-Error-Reconcile) editor
The CIDER editor is a custom editor written for Riot.
The CIDER editor is a custom editor written for Element.
Most of the code can be found in the `/editor/` directory of the `matrix-react-sdk` project.
It is used to power the composer main composer (both to send and edit messages), and might be used for other usecases where autocomplete is desired (invite box, ...).

View File

@ -25,7 +25,7 @@ which takes several parameters:
be null.
The react-sdk will assume that `jitsi.html` is at the path of wherever it is currently
being served. For example, `https://riot.im/develop/jitsi.html` or `vector://webapp/jitsi.html`.
being served. For example, `https://develop.element.io/jitsi.html` or `vector://webapp/jitsi.html`.
The `jitsi.html` wrapper can use the react-sdk's `WidgetApi` to communicate, making
it easier to actually implement the feature.

View File

@ -55,7 +55,7 @@ timestamp contained within the event (generated server-side by the sender's serv
This is the easiest of the algorithms to understand because it does essentially nothing. It imposes no
behavioural changes over the tag sorting algorithm and is by far the simplest way to order a room list.
Historically, it's been the only option in Riot and extremely common in most chat applications due to
Historically, it's been the only option in Element and extremely common in most chat applications due to
its relative deterministic behaviour.
### List ordering algorithm: Importance

View File

@ -13,7 +13,7 @@ ScrollPanel supports a mode to prevent it shrinking. This is used to prevent a j
BACAT scrolling implements a different way of restoring the scroll position in the timeline while tiles out of view are changing height or tiles are being added or removed. It was added in https://github.com/matrix-org/matrix-react-sdk/pull/2842.
The motivation for the changes is having noticed that setting scrollTop while scrolling tends to not work well, with it interrupting ongoing scrolling and also querying scrollTop reporting outdated values and consecutive scroll adjustments cancelling each out previous ones. This seems to be worse on macOS than other platforms, presumably because of a higher resolution in scroll events there. Also see https://github.com/vector-im/riot-web/issues/528. The BACAT approach allows to only have to change the scroll offset when adding or removing tiles.
The motivation for the changes is having noticed that setting scrollTop while scrolling tends to not work well, with it interrupting ongoing scrolling and also querying scrollTop reporting outdated values and consecutive scroll adjustments cancelling each out previous ones. This seems to be worse on macOS than other platforms, presumably because of a higher resolution in scroll events there. Also see https://github.com/vector-im/element-web/issues/528. The BACAT approach allows to only have to change the scroll offset when adding or removing tiles.
The approach taken instead is to vertically align the timeline tiles to the bottom of the scroll container (using flexbox) and give the timeline inside the scroll container an explicit height, initially set to a multiple of the PAGE_SIZE (400px at time of writing) as needed by the content. When scrolled up, we can compensate for anything that grew below the viewport by changing the height of the timeline to maintain what's currently visible in the viewport without adjusting the scrollTop and hence without jumping.

View File

@ -9,7 +9,7 @@ of dealing with the different levels and exposes easy to use getters and setters
## Levels
Granular Settings rely on a series of known levels in order to use the correct value for the scenario. These levels, in
order of prioirty, are:
order of priority, are:
* `device` - The current user's device
* `room-device` - The current user's device, but only when in a specific room
* `room-account` - The current user's account, but only when in a specific room
@ -25,33 +25,10 @@ that room administrators cannot force account-only settings upon participants.
## Settings
Settings are the different options a user may set or experience in the application. These are pre-defined in
`src/settings/Settings.js` under the `SETTINGS` constant and have the following minimum requirements:
```
// The ID is used to reference the setting throughout the application. This must be unique.
"theSettingId": {
// The levels this setting supports is required. In `src/settings/Settings.js` there are various pre-set arrays
// for this option - they should be used where possible to avoid copy/pasting arrays across settings.
supportedLevels: [...],
`src/settings/Settings.ts` under the `SETTINGS` constant, and match the `ISetting` interface as defined there.
// The default for this setting serves two purposes: It provides a value if the setting is not defined at other
// levels, and it serves to demonstrate the expected type to other developers. The value isn't enforced, but it
// should be respected throughout the code. The default may be any data type.
default: false,
// The display name has two notations: string and object. The object notation allows for different translatable
// strings to be used for different levels, while the string notation represents the string for all levels.
displayName: _td("Change something"), // effectively `displayName: { "default": _td("Change something") }`
displayName: {
"room": _td("Change something for participants of this room"),
// Note: the default will be used if the level requested (such as `device`) does not have a string defined here.
"default": _td("Change something"),
}
}
```
Settings that support the config level can be set in the config file under the `settingDefaults` key (note that some settings, like the "theme" setting, are special cased in the config file):
Settings that support the config level can be set in the config file under the `settingDefaults` key (note that some
settings, like the "theme" setting, are special cased in the config file):
```json
{
...
@ -119,38 +96,29 @@ for you. If a display name cannot be found, it will return `null`.
## Features
Occasionally some parts of the application may be undergoing testing and are not quite production ready. These are
commonly known to be behind a "labs flag". Features behind lab flags must go through the granular settings system, and
look and act very much normal settings. The exception is that they must supply `isFeature: true` as part of the setting
definition and should go through the helper functions on `SettingsStore`.
Feature flags are just like regular settings with some underlying semantics for how they are meant to be used. Usually
a feature flag is used when a portion of the application is under development or not ready for full release yet, such
as new functionality or experimental ideas. In these cases, the feature name *should* be named with the `feature_*`
convention and must be tagged with `isFeature: true` in the setting definition. By doing so, the feature will automatically
appear in the "labs" section of the user's settings.
Although features have levels and a default value, the calculation of those options is blocked by the feature's state.
A feature's state is determined from the `SdkConfig` and is a little complex. If `enableLabs` (a legacy flag) is `true`
then the feature's state is `labs`, if it is `false`, the state is `disable`. If `enableLabs` is not set then the state
is determined from the `features` config, such as in the following:
Features can be controlled at the config level using the following structure:
```json
"features": {
"feature_lazyloading": "labs"
"feature_lazyloading": true
}
```
In this example, `feature_lazyloading` is in the `labs` state. It may also be in the `enable` or `disable` state with a
similar approach. If the state is invalid, the feature is in the `disable` state. A feature's levels are only calculated
if it is in the `labs` state, therefore the default only applies in that scenario. If the state is `enable`, the feature
is always-on.
Once a feature flag has served its purpose, it is generally recommended to remove it and the associated feature flag
checks. This would enable the feature implicitly as it is part of the application now.
When `true`, the user will see the feature as enabled. Similarly, when `false` the user will see the feature as disabled.
The user will only be able to change/see these states if `showLabsSettings: true` is in the config.
### Determining if a feature is enabled
A simple call to `SettingsStore.isFeatureEnabled` will tell you if the feature is enabled. This will perform all the
required calculations to determine if the feature is enabled based upon the configuration and user selection.
Call `SettingsStore.getValue()` as you would for any other setting.
### Enabling a feature
Features can only be enabled if the feature is in the `labs` state, otherwise this is a no-op. To find the current set
of features in the `labs` state, call `SettingsStore.getLabsFeatures`. To set the value, call
`SettingsStore.setFeatureEnabled`.
Call `SettingsStore.setValue("feature_name", null, SettingLevel.DEVICE, true)`.
## Setting controllers
@ -162,7 +130,7 @@ kept up to date with the setting where it is otherwise not possible. An example
they can only be considered enabled if the platform supports notifications, and enabling notifications requires
additional steps to actually enable notifications.
For more information, see `src/settings/controllers/SettingController.js`.
For more information, see `src/settings/controllers/SettingController.ts`.
## Local echo
@ -222,7 +190,7 @@ The `SettingsStore` uses the hardcoded `LEVEL_ORDER` constant to ensure that it
The array is checked from left to right, simulating the behaviour of overriding values from the higher levels. Each
level should be defined in this array, including `default`.
Handlers (`src/settings/handlers/SettingsHandler.js`) represent a single level and are responsible for getting and
Handlers (`src/settings/handlers/SettingsHandler.ts`) represent a single level and are responsible for getting and
setting values at that level. Handlers also provide additional information to the `SettingsStore` such as if the level
is supported or if the current user may set values at the level. The `SettingsStore` will use the handler to enforce
checks and manipulate settings. Handlers are also responsible for dealing with migration patterns or legacy settings for
@ -230,7 +198,7 @@ their level (for example, a setting being renamed or using a different key from
Handlers are provided to the `SettingsStore` via the `LEVEL_HANDLERS` constant. `SettingsStore` will optimize lookups by
only considering handlers that are supported on the platform.
Local echo is achieved through `src/settings/handlers/LocalEchoWrapper.js` which acts as a wrapper around a given
Local echo is achieved through `src/settings/handlers/LocalEchoWrapper.ts` which acts as a wrapper around a given
handler. This is automatically applied to all defined `LEVEL_HANDLERS` and proxies the calls to the wrapped handler
where possible. The echo is achieved by a simple object cache stored within the class itself. The cache is invalidated
immediately upon the proxied save call succeeding or failing.
@ -240,20 +208,7 @@ Controllers are notified of changes by the `SettingsStore`, and are given the op
### Features
Features automatically get considered as `disabled` if they are not listed in the `SdkConfig` or `enableLabs` is
false/not set. Features are always checked against the configuration before going through the level order as they have
the option of being forced-on or forced-off for the application. This is done by the `features` section and looks
something like this:
```
"features": {
"feature_groups": "enable",
"feature_pinning": "disable", // the default
"feature_presence": "labs"
}
```
If `enableLabs` is true in the configuration, the default for features becomes `"labs"`.
See above for feature reference.
### Watchers

View File

@ -5,9 +5,9 @@ letting the browser and user interact with the resulting data may be dangerous,
previously `usercontent.riot.im` was used to act as a sandbox on a different origin to close the attack surface,
it is now possible to do by using a combination of a sandboxed iframe and some code written into the app which consumes this SDK.
Usercontent is an iframe sandbox target for allowing a user to safely download a decrypted attachment from a sandboxed origin where it cannot be used to XSS your riot session out from under you.
Usercontent is an iframe sandbox target for allowing a user to safely download a decrypted attachment from a sandboxed origin where it cannot be used to XSS your Element session out from under you.
Its function is to create an Object URL for the user/browser to use but bound to an origin different to that of the riot instance to protect against XSS.
Its function is to create an Object URL for the user/browser to use but bound to an origin different to that of the Element instance to protect against XSS.
It exposes a function over a postMessage API, when sent an object with the matching fields to render a download link with the Object URL:
@ -24,4 +24,4 @@ It exposes a function over a postMessage API, when sent an object with the match
If only imgSrc, imgStyle and style are passed then just update the existing link without overwriting other things about it.
It is expected that this target be available at `usercontent/` relative to the root of the app, this can be seen in riot-web's webpack config.
It is expected that this target be available at `usercontent/` relative to the root of the app, this can be seen in element-web's webpack config.

View File

@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
"version": "3.0.0",
"version": "3.3.0",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {
@ -61,7 +61,6 @@
"classnames": "^2.2.6",
"commonmark": "^0.29.1",
"counterpart": "^0.18.6",
"create-react-class": "^15.6.3",
"diff-dom": "^4.1.6",
"diff-match-patch": "^1.0.5",
"emojibase-data": "^5.0.1",
@ -96,6 +95,7 @@
"react-transition-group": "^4.4.1",
"resize-observer-polyfill": "^1.5.1",
"sanitize-html": "^1.27.1",
"tar-js": "^0.3.0",
"text-encoding-utf-8": "^1.0.2",
"url": "^0.11.0",
"velocity-animate": "^1.5.2",
@ -127,6 +127,7 @@
"@types/lodash": "^4.14.158",
"@types/modernizr": "^3.5.3",
"@types/node": "^12.12.51",
"@types/pako": "^1.0.1",
"@types/qrcode": "^1.3.4",
"@types/react": "^16.9",
"@types/react-dom": "^16.9.8",
@ -161,9 +162,7 @@
"stylelint-config-standard": "^18.3.0",
"stylelint-scss": "^3.18.0",
"typescript": "^3.9.7",
"walk": "^2.3.14",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
"walk": "^2.3.14"
},
"jest": {
"testMatch": [

View File

@ -38,7 +38,7 @@ body {
margin: 0px;
// needed to match the designs correctly on macOS
// see https://github.com/vector-im/riot-web/issues/11425
// see https://github.com/vector-im/element-web/issues/11425
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@ -436,7 +436,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
// TODO: Review mx_GeneralButton usage to see if it can use a different class
// These classes were brought in from the old UserSettings and are included here to avoid
// breaking the app.
// Ref: https://github.com/vector-im/riot-web/issues/8420
// Ref: https://github.com/vector-im/element-web/issues/8420
.mx_GeneralButton {
@mixin mx_DialogButton;
display: inline;
@ -585,93 +585,6 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
max-width: 120px;
}
// A context menu that largely fits the | [icon] [label] | format.
.mx_IconizedContextMenu {
min-width: 146px;
.mx_IconizedContextMenu_optionList {
& > * {
padding-left: 20px;
padding-right: 20px;
}
// the notFirst class is for cases where the optionList might be under a header of sorts.
&:nth-child(n + 2), .mx_IconizedContextMenu_optionList_notFirst {
// This is a bit of a hack when we could just use a simple border-top property,
// however we have a (kinda) good reason for doing it this way: we need opacity.
// To get the right color, we need an opacity modifier which means we have to work
// around the problem. PostCSS doesn't support the opacity() function, and if we
// use something like postcss-functions we quickly run into an issue where the
// function we would define gets passed a CSS variable for custom themes, which
// can't be converted easily even when considering https://stackoverflow.com/a/41265350/7037379
//
// Therefore, we just hack in a line and border the thing ourselves
&::before {
border-top: 1px solid $primary-fg-color;
opacity: 0.1;
content: '';
// Counteract the padding problems (width: 100% ignores the 40px padding,
// unless we position it absolutely then it does the right thing).
width: 100%;
position: absolute;
left: 0;
}
}
// round the top corners of the top button for the hover effect to be bounded
&:first-child .mx_AccessibleButton:first-child {
border-radius: 8px 8px 0 0; // radius matches .mx_ContextualMenu
}
// round the bottom corners of the bottom button for the hover effect to be bounded
&:last-child .mx_AccessibleButton:last-child {
border-radius: 0 0 8px 8px; // radius matches .mx_ContextualMenu
}
.mx_AccessibleButton {
// pad the inside of the button so that the hover background is padded too
padding-top: 12px;
padding-bottom: 12px;
text-decoration: none;
color: $primary-fg-color;
font-size: $font-15px;
line-height: $font-24px;
// Create a flexbox to more easily define the list items
display: flex;
align-items: center;
&:hover {
background-color: $menu-selected-color;
}
img, .mx_IconizedContextMenu_icon { // icons
width: 16px;
min-width: 16px;
max-width: 16px;
}
span.mx_IconizedContextMenu_label { // labels
padding-left: 14px;
width: 100%;
flex: 1;
// Ellipsize any text overflow
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
}
&.mx_IconizedContextMenu_compact {
.mx_IconizedContextMenu_optionList > * {
padding: 8px 16px 8px 11px;
}
}
}
@define-mixin ProgressBarColour $colour {
color: $colour;
&::-moz-progress-bar {
@ -692,3 +605,15 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
border-radius: $radius;
}
}
@define-mixin unreal-focus {
outline-width: 2px;
outline-style: solid;
outline-color: Highlight;
/* WebKit gets its native focus styles. */
@media (-webkit-min-device-pixel-ratio: 0) {
outline-color: -webkit-focus-ring-color;
outline-style: auto;
}
}

View File

@ -1,6 +1,7 @@
// autogenerated by rethemendex.sh
@import "./_common.scss";
@import "./_font-sizes.scss";
@import "./_font-weights.scss";
@import "./structures/_AutoHideScrollbar.scss";
@import "./structures/_CompatibilityPage.scss";
@import "./structures/_ContextualMenu.scss";
@ -50,28 +51,30 @@
@import "./views/avatars/_DecoratedRoomAvatar.scss";
@import "./views/avatars/_MemberStatusMessageAvatar.scss";
@import "./views/avatars/_PulsedAvatar.scss";
@import "./views/context_menus/_IconizedContextMenu.scss";
@import "./views/context_menus/_MessageContextMenu.scss";
@import "./views/context_menus/_RoomTileContextMenu.scss";
@import "./views/context_menus/_StatusMessageContextMenu.scss";
@import "./views/context_menus/_TagTileContextMenu.scss";
@import "./views/context_menus/_TopLeftMenu.scss";
@import "./views/context_menus/_WidgetContextMenu.scss";
@import "./views/dialogs/_AddressPickerDialog.scss";
@import "./views/dialogs/_Analytics.scss";
@import "./views/dialogs/_BugReportDialog.scss";
@import "./views/dialogs/_ChangelogDialog.scss";
@import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss";
@import "./views/dialogs/_CommunityPrototypeInviteDialog.scss";
@import "./views/dialogs/_ConfirmUserActionDialog.scss";
@import "./views/dialogs/_CreateCommunityPrototypeDialog.scss";
@import "./views/dialogs/_CreateGroupDialog.scss";
@import "./views/dialogs/_CreateRoomDialog.scss";
@import "./views/dialogs/_DeactivateAccountDialog.scss";
@import "./views/dialogs/_DevtoolsDialog.scss";
@import "./views/dialogs/_EditCommunityPrototypeDialog.scss";
@import "./views/dialogs/_GroupAddressPicker.scss";
@import "./views/dialogs/_IncomingSasDialog.scss";
@import "./views/dialogs/_InviteDialog.scss";
@import "./views/dialogs/_KeyboardShortcutsDialog.scss";
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
@import "./views/dialogs/_NewSessionReviewDialog.scss";
@import "./views/dialogs/_RebrandDialog.scss";
@import "./views/dialogs/_RoomSettingsDialog.scss";
@import "./views/dialogs/_RoomSettingsDialogBridges.scss";
@import "./views/dialogs/_RoomUpgradeDialog.scss";
@ -106,6 +109,7 @@
@import "./views/elements/_FormButton.scss";
@import "./views/elements/_IconButton.scss";
@import "./views/elements/_ImageView.scss";
@import "./views/elements/_InfoTooltip.scss";
@import "./views/elements/_InlineSpinner.scss";
@import "./views/elements/_ManageIntegsButton.scss";
@import "./views/elements/_PowerSelector.scss";
@ -156,7 +160,6 @@
@import "./views/right_panel/_UserInfo.scss";
@import "./views/right_panel/_VerificationPanel.scss";
@import "./views/room_settings/_AliasSettings.scss";
@import "./views/room_settings/_ColorSettings.scss";
@import "./views/rooms/_AppsDrawer.scss";
@import "./views/rooms/_Autocomplete.scss";
@import "./views/rooms/_AuxPanel.scss";
@ -186,7 +189,6 @@
@import "./views/rooms/_RoomRecoveryReminder.scss";
@import "./views/rooms/_RoomSublist.scss";
@import "./views/rooms/_RoomTile.scss";
@import "./views/rooms/_RoomTileIcon.scss";
@import "./views/rooms/_RoomUpgradeWarningBar.scss";
@import "./views/rooms/_SearchBar.scss";
@import "./views/rooms/_SendMessageComposer.scss";

View File

@ -0,0 +1,17 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
$font-semi-bold: 600;

View File

@ -41,13 +41,19 @@ limitations under the License.
.mx_FilePanel .mx_EventTile {
word-break: break-word;
margin-top: 32px;
}
.mx_FilePanel .mx_EventTile .mx_MImageBody {
margin-right: 0px;
}
.mx_FilePanel .mx_EventTile .mx_MFileBody {
line-height: 2.4rem;
}
.mx_FilePanel .mx_EventTile .mx_MFileBody_download {
padding-top: 8px;
display: flex;
font-size: $font-14px;
color: $event-timestamp-color;
@ -60,7 +66,7 @@ limitations under the License.
.mx_FilePanel .mx_EventTile .mx_MImageBody_size {
flex: 1 0 0;
font-size: $font-11px;
font-size: $font-14px;
text-align: right;
white-space: nowrap;
}
@ -80,7 +86,7 @@ limitations under the License.
flex: 1 1 auto;
line-height: initial;
padding: 0px;
font-size: $font-11px;
font-size: $font-14px;
opacity: 1.0;
color: $event-timestamp-color;
}
@ -90,7 +96,7 @@ limitations under the License.
text-align: right;
visibility: visible;
position: initial;
font-size: $font-11px;
font-size: $font-14px;
opacity: 1.0;
color: $event-timestamp-color;
}

View File

@ -97,23 +97,25 @@ $tagPanelWidth: 56px; // only applies in this file, used for calculations
display: flex;
align-items: center;
.mx_RoomSearch_expanded + .mx_LeftPanel_exploreButton {
// Cheaty way to return the occupied space to the filter input
flex-basis: 0;
margin: 0;
width: 0;
.mx_RoomSearch_focused, .mx_RoomSearch_hasQuery {
& + .mx_LeftPanel_exploreButton {
// Cheaty way to return the occupied space to the filter input
flex-basis: 0;
margin: 0;
width: 0;
// Don't forget to hide the masked ::before icon,
// using display:none or visibility:hidden would break accessibility
&::before {
content: none;
// Don't forget to hide the masked ::before icon,
// using display:none or visibility:hidden would break accessibility
&::before {
content: none;
}
}
}
.mx_LeftPanel_exploreButton {
width: 28px;
height: 28px;
border-radius: 20px;
width: 32px;
height: 32px;
border-radius: 8px;
background-color: $roomlist-button-bg-color;
position: relative;
margin-left: 8px;
@ -121,22 +123,31 @@ $tagPanelWidth: 56px; // only applies in this file, used for calculations
&::before {
content: '';
position: absolute;
top: 6px;
left: 6px;
top: 8px;
left: 8px;
width: 16px;
height: 16px;
mask-image: url('$(res)/img/feather-customised/compass.svg');
mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background: $primary-fg-color;
background: $secondary-fg-color;
}
}
}
.mx_LeftPanel_roomListFilterCount {
font-size: $font-13px;
font-weight: $font-semi-bold;
margin-left: 12px;
margin-top: 14px;
margin-bottom: -4px; // to counteract the normal roomListWrapper margin-top
}
.mx_LeftPanel_roomListWrapper {
overflow: hidden;
margin-top: 10px; // so we're not up against the search/filter
flex: 1 0 0; // needed in Safari to properly set flex-basis
&.mx_LeftPanel_roomListWrapper_stickyBottom {
padding-bottom: 32px;

View File

@ -23,6 +23,8 @@ limitations under the License.
.mx_MainSplit > .mx_RightPanel_ResizeWrapper {
padding: 5px;
// margin left to not allow the handle to not encroach on the space for the scrollbar
margin-left: 8px;
&:hover .mx_RightPanel_ResizeHandle {
// Need to use important to override element style attributes

View File

@ -72,7 +72,7 @@ limitations under the License.
flex: 1 1 0;
min-width: 0;
/* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari
/* To fix https://github.com/vector-im/element-web/issues/3298 where Safari
needed height 100% all the way down to the HomePage. Height does not
have to be auto, empirically.
*/

View File

@ -64,7 +64,7 @@ limitations under the License.
left: 4px; // center with parent of 32px
height: 24px;
width: 24px;
background-color: $rightpanel-button-color;
background-color: $icon-button-color;
mask-repeat: no-repeat;
mask-size: contain;
}
@ -99,7 +99,7 @@ limitations under the License.
background: rgba($accent-color, 0.25);
// make the icon the accent color too
&::before {
background-color: $accent-color;
background-color: $accent-color !important;
}
}

View File

@ -17,8 +17,10 @@ limitations under the License.
// Note: this component expects to be contained within a flexbox
.mx_RoomSearch {
flex: 1;
border-radius: 20px;
border-radius: 8px;
background-color: $roomlist-button-bg-color;
// keep border thickness consistent to prevent movement
border: 1px solid transparent;
height: 28px;
padding: 2px;
@ -29,9 +31,9 @@ limitations under the License.
.mx_RoomSearch_icon {
width: 16px;
height: 16px;
mask: url('$(res)/img/feather-customised/search-input.svg');
mask: url('$(res)/img/element-icons/roomlist/search.svg');
mask-repeat: no-repeat;
background: $primary-fg-color;
background-color: $secondary-fg-color;
margin-left: 7px;
}
@ -46,19 +48,30 @@ limitations under the License.
line-height: $font-16px;
&:not(.mx_RoomSearch_inputExpanded)::placeholder {
color: $primary-fg-color !important; // !important to override default app-wide styles
color: $tertiary-fg-color !important; // !important to override default app-wide styles
}
}
&.mx_RoomSearch_expanded {
&.mx_RoomSearch_hasQuery {
border-color: $secondary-fg-color;
}
&.mx_RoomSearch_focused {
box-shadow: 0 0 4px 4px rgba(0, 132, 255, 0.5);
border-color: transparent;
}
&.mx_RoomSearch_focused, &.mx_RoomSearch_hasQuery {
background-color: $roomlist-filter-active-bg-color;
.mx_RoomSearch_clearButton {
width: 16px;
height: 16px;
mask-image: url('$(res)/img/feather-customised/x.svg');
mask-image: url('$(res)/img/element-icons/roomlist/search-clear.svg');
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background: $primary-fg-color;
background-color: $secondary-fg-color;
margin-right: 8px;
}
}

View File

@ -30,30 +30,11 @@ limitations under the License.
cursor: pointer;
}
.mx_TagPanel .mx_TagPanel_clearButton_container {
/* Constant height within flex mx_TagPanel */
height: 70px;
width: 56px;
flex: none;
justify-content: center;
align-items: flex-start;
display: none;
}
.mx_TagPanel .mx_TagPanel_clearButton object {
/* Same as .mx_SearchBox padding-top */
margin-top: 24px;
pointer-events: none;
}
.mx_TagPanel .mx_TagPanel_divider {
height: 0px;
width: 34px;
border-bottom: 1px solid $panel-divider-color;
display: none;
width: 90%;
border: none;
border-bottom: 1px solid $tagpanel-divider-color;
}
.mx_TagPanel .mx_TagPanel_scroller {
@ -76,12 +57,57 @@ limitations under the License.
// opacity: 0.5;
position: relative;
}
.mx_TagPanel .mx_TagTile.mx_TagTile_prototype {
padding: 3px;
}
.mx_TagPanel .mx_TagTile:focus,
.mx_TagPanel .mx_TagTile:hover,
.mx_TagPanel .mx_TagTile.mx_TagTile_selected {
// opacity: 1;
}
.mx_TagPanel .mx_TagTile.mx_TagTile_selected_prototype {
background-color: $primary-bg-color;
border-radius: 6px;
}
.mx_TagTile_selected_prototype {
.mx_TagTile_homeIcon::before {
background-color: $primary-fg-color; // dark-on-light
}
}
.mx_TagTile:not(.mx_TagTile_selected_prototype) .mx_TagTile_homeIcon {
background-color: $roomheader-addroom-bg-color;
border-radius: 48px;
&::before {
background-color: $roomheader-addroom-fg-color;
}
}
.mx_TagTile_homeIcon {
width: 32px;
height: 32px;
position: relative;
&::before {
mask-image: url('$(res)/img/element-icons/home.svg');
mask-position: center;
mask-repeat: no-repeat;
mask-size: 21px;
content: '';
display: inline-block;
width: 32px;
height: 32px;
position: absolute;
top: calc(50% - 16px);
left: calc(50% - 16px);
}
}
.mx_TagPanel .mx_TagTile_plus {
margin-bottom: 12px;
height: 32px;
@ -108,13 +134,12 @@ limitations under the License.
.mx_TagPanel .mx_TagTile.mx_TagTile_selected::before {
content: '';
height: calc(100% + 16px);
height: 100%;
background-color: $accent-color;
width: 5px;
width: 4px;
position: absolute;
left: -15px;
left: -12px;
border-radius: 0 3px 3px 0;
top: -8px; // (16px from height / 2)
}
.mx_TagPanel .mx_TagTile.mx_AccessibleButton:focus {

View File

@ -80,10 +80,6 @@ limitations under the License.
}
}
&.mx_Toast_icon_element_logo::after {
background-image: url("$(res)/img/element-logo.svg");
}
.mx_Toast_title, .mx_Toast_body {
grid-column: 2;
}

View File

@ -16,9 +16,33 @@ limitations under the License.
.mx_UserMenu {
// to make the ... button sort of aligned with the explore button below
// to make the menu button sort of aligned with the explore button below
padding-right: 6px;
&.mx_UserMenu_prototype {
// The margin & padding combination between here and the ::after is to
// align the border line with the tag panel.
margin-bottom: 6px;
padding-right: 0; // make the right edge line up with the explore button
.mx_UserMenu_headerButtons {
// considering we've eliminated right padding on the menu itself, we need to
// push the chevron in slightly (roughly lining up with the center of the
// plus buttons)
margin-right: 2px;
}
// we cheat opacity on the theme colour with an after selector here
&::after {
content: '';
border-bottom: 1px solid $primary-fg-color; // XXX: Variable abuse
opacity: 0.2;
display: block;
padding-top: 8px;
}
}
.mx_UserMenu_headerButtons {
width: 16px;
height: 16px;
@ -36,7 +60,7 @@ limitations under the License.
mask-size: contain;
mask-repeat: no-repeat;
background: $primary-fg-color;
mask-image: url('$(res)/img/element-icons/context-menu.svg');
mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
}
}
@ -56,6 +80,28 @@ limitations under the License.
}
}
.mx_UserMenu_doubleName {
flex: 1;
min-width: 0; // make flexbox aware that it can crush this to a tiny width
.mx_UserMenu_userName,
.mx_UserMenu_subUserName {
display: block;
}
.mx_UserMenu_subUserName {
color: $muted-fg-color;
font-size: $font-13px;
line-height: $font-18px;
flex: 1;
// Ellipsize any text overflow
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
.mx_UserMenu_userName {
font-weight: 600;
font-size: $font-15px;
@ -89,15 +135,48 @@ limitations under the License.
.mx_UserMenu_contextMenu {
width: 247px;
.mx_UserMenu_contextMenu_redRow {
// These override the styles already present on the user menu rather than try to
// define a new menu. They are specifically for the stacked menu when a community
// is being represented as a prototype.
&.mx_UserMenu_contextMenu_prototype {
padding-bottom: 16px;
.mx_UserMenu_contextMenu_header {
padding-bottom: 0;
padding-top: 16px;
&:nth-child(n + 2) {
padding-top: 8px;
}
}
hr {
width: 85%;
opacity: 0.2;
border: none;
border-bottom: 1px solid $primary-fg-color; // XXX: Variable abuse
}
&.mx_IconizedContextMenu {
> .mx_IconizedContextMenu_optionList {
margin-top: 4px;
&::before {
border: none;
}
> .mx_AccessibleButton {
padding-top: 2px;
padding-bottom: 2px;
}
}
}
}
&.mx_IconizedContextMenu .mx_IconizedContextMenu_optionList_red {
.mx_AccessibleButton {
padding-top: 16px;
padding-bottom: 16px;
color: $warning-color !important; // !important to override styles from context menu
}
.mx_IconizedContextMenu_icon::before {
background-color: $warning-color;
}
}
@ -198,4 +277,12 @@ limitations under the License.
.mx_UserMenu_iconSignOut::before {
mask-image: url('$(res)/img/element-icons/leave.svg');
}
.mx_UserMenu_iconMembers::before {
mask-image: url('$(res)/img/element-icons/room/members.svg');
}
.mx_UserMenu_iconInvite::before {
mask-image: url('$(res)/img/element-icons/room/invite.svg');
}
}

View File

@ -22,7 +22,7 @@ limitations under the License.
// different results during full reflow of the page vs. incremental reflow
// of small portions. While that's surely a browser bug, we can avoid it by
// using `inline-block` instead of the default `inline`.
// https://github.com/vector-im/riot-web/issues/5594
// https://github.com/vector-im/element-web/issues/5594
// https://bugzilla.mozilla.org/show_bug.cgi?id=1535053
// https://bugzilla.mozilla.org/show_bug.cgi?id=255139
display: inline-block;

View File

@ -18,10 +18,49 @@ limitations under the License.
.mx_DecoratedRoomAvatar, .mx_TemporaryTile {
position: relative;
.mx_RoomTileIcon {
&.mx_DecoratedRoomAvatar_cutout .mx_BaseAvatar {
mask-image: url('$(res)/img/element-icons/roomlist/decorated-avatar-mask.svg');
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
}
.mx_DecoratedRoomAvatar_icon {
position: absolute;
bottom: 0;
right: 0;
bottom: -2px;
right: -2px;
margin: 4px;
width: 8px;
height: 8px;
border-radius: 50%;
}
.mx_DecoratedRoomAvatar_icon::before {
content: '';
width: 8px;
height: 8px;
position: absolute;
border-radius: 8px;
}
.mx_DecoratedRoomAvatar_icon_globe::before {
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background: $secondary-fg-color;
mask-image: url('$(res)/img/globe.svg');
}
.mx_DecoratedRoomAvatar_icon_offline::before {
background-color: $presence-offline;
}
.mx_DecoratedRoomAvatar_icon_online::before {
background-color: $presence-online;
}
.mx_DecoratedRoomAvatar_icon_away::before {
background-color: $presence-away;
}
.mx_NotificationBadge, .mx_RoomTile_badgeContainer {

View File

@ -0,0 +1,148 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// A context menu that largely fits the | [icon] [label] | format.
.mx_IconizedContextMenu {
min-width: 146px;
.mx_IconizedContextMenu_optionList {
& > * {
padding-left: 20px;
padding-right: 20px;
}
// the notFirst class is for cases where the optionList might be under a header of sorts.
&:nth-child(n + 2), .mx_IconizedContextMenu_optionList_notFirst {
// This is a bit of a hack when we could just use a simple border-top property,
// however we have a (kinda) good reason for doing it this way: we need opacity.
// To get the right color, we need an opacity modifier which means we have to work
// around the problem. PostCSS doesn't support the opacity() function, and if we
// use something like postcss-functions we quickly run into an issue where the
// function we would define gets passed a CSS variable for custom themes, which
// can't be converted easily even when considering https://stackoverflow.com/a/41265350/7037379
//
// Therefore, we just hack in a line and border the thing ourselves
&::before {
border-top: 1px solid $primary-fg-color;
opacity: 0.1;
content: '';
// Counteract the padding problems (width: 100% ignores the 40px padding,
// unless we position it absolutely then it does the right thing).
width: 100%;
position: absolute;
left: 0;
}
}
// round the top corners of the top button for the hover effect to be bounded
&:first-child .mx_AccessibleButton:first-child {
border-radius: 8px 8px 0 0; // radius matches .mx_ContextualMenu
}
// round the bottom corners of the bottom button for the hover effect to be bounded
&:last-child .mx_AccessibleButton:last-child {
border-radius: 0 0 8px 8px; // radius matches .mx_ContextualMenu
}
.mx_AccessibleButton {
// pad the inside of the button so that the hover background is padded too
padding-top: 12px;
padding-bottom: 12px;
text-decoration: none;
color: $primary-fg-color;
font-size: $font-15px;
line-height: $font-24px;
// Create a flexbox to more easily define the list items
display: flex;
align-items: center;
&:hover {
background-color: $menu-selected-color;
}
img, .mx_IconizedContextMenu_icon { // icons
width: 16px;
min-width: 16px;
max-width: 16px;
}
span.mx_IconizedContextMenu_label { // labels
padding-left: 14px;
width: 100%;
flex: 1;
// Ellipsize any text overflow
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
}
.mx_IconizedContextMenu_icon {
position: relative;
width: 16px;
height: 16px;
&::before {
content: '';
width: 16px;
height: 16px;
position: absolute;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background: $primary-fg-color;
}
}
.mx_IconizedContextMenu_optionList_red {
.mx_AccessibleButton {
color: $warning-color !important;
}
.mx_IconizedContextMenu_icon::before {
background-color: $warning-color;
}
}
.mx_IconizedContextMenu_active {
&.mx_AccessibleButton, .mx_AccessibleButton {
color: $accent-color !important;
}
.mx_IconizedContextMenu_icon::before {
background-color: $accent-color;
}
}
&.mx_IconizedContextMenu_compact {
.mx_IconizedContextMenu_optionList > * {
padding: 8px 16px 8px 11px;
}
}
.mx_IconizedContextMenu_checked {
margin-left: 16px;
margin-right: -5px;
&::before {
mask-image: url('$(res)/img/element-icons/roomlist/checkmark.svg');
}
}
}

View File

@ -1,114 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_RoomTileContextMenu {
padding: 6px;
}
.mx_RoomTileContextMenu_tag_icon {
padding-right: 8px;
padding-left: 4px;
display: inline-block;
}
.mx_RoomTileContextMenu_tag_icon_set {
padding-right: 8px;
padding-left: 4px;
display: none;
}
.mx_RoomTileContextMenu_tag_field, .mx_RoomTileContextMenu_leave {
padding-top: 8px;
padding-right: 20px;
padding-bottom: 8px;
cursor: pointer;
white-space: nowrap;
display: flex;
align-items: center;
line-height: $font-16px;
}
.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldSet {
font-weight: bold;
}
.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldSet .mx_RoomTileContextMenu_tag_icon {
display: none;
}
.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldSet .mx_RoomTileContextMenu_tag_icon_set {
display: inline-block;
}
.mx_RoomTileContextMenu_tag_field.mx_RoomTileContextMenu_tag_fieldDisabled {
color: rgba(0, 0, 0, 0.2);
}
.mx_RoomTileContextMenu_separator {
margin-top: 0;
margin-bottom: 0;
border-bottom-style: none;
border-left-style: none;
border-right-style: none;
border-top-style: solid;
border-top-width: 1px;
border-color: $menu-border-color;
}
.mx_RoomTileContextMenu_leave {
color: $warning-color;
}
.mx_RoomTileContextMenu_notif_picker {
position: absolute;
top: 16px;
left: 5px;
}
.mx_RoomTileContextMenu_notif_field {
padding-top: 4px;
padding-right: 6px;
padding-bottom: 10px;
padding-left: 8px; /* 20px */
cursor: pointer;
white-space: nowrap;
display: flex;
align-items: center;
}
.mx_RoomTileContextMenu_notif_field.mx_RoomTileContextMenu_notif_fieldSet {
font-weight: bold;
}
.mx_RoomTileContextMenu_notif_field.mx_RoomTileContextMenu_notif_fieldDisabled {
color: rgba(0, 0, 0, 0.2);
}
.mx_RoomTileContextMenu_notif_icon {
padding-right: 4px;
padding-left: 4px;
}
.mx_RoomTileContextMenu_notif_activeIcon {
display: inline-block;
opacity: 0;
position: relative;
left: -5px;
}
.mx_RoomTileContextMenu_notif_fieldSet .mx_RoomTileContextMenu_notif_activeIcon {
opacity: 1;
}

View File

@ -1,96 +0,0 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_TopLeftMenu {
min-width: 210px;
border-radius: 4px;
.mx_TopLeftMenu_greyedText {
font-size: $font-12px;
opacity: 0.5;
}
.mx_TopLeftMenu_upgradeLink {
font-size: $font-12px;
img {
margin-left: 5px;
}
}
.mx_TopLeftMenu_section:not(:last-child) {
border-bottom: 1px solid $menu-border-color;
}
.mx_TopLeftMenu_section_noIcon {
margin: 5px 0;
padding: 5px 20px 5px 15px;
div:not(:first-child) {
margin-top: 5px;
}
}
.mx_TopLeftMenu_section_withIcon {
margin: 5px 0;
padding: 0;
list-style: none;
.mx_TopLeftMenu_icon_home::after {
mask-image: url('$(res)/img/feather-customised/home.svg');
}
.mx_TopLeftMenu_icon_help::after {
mask-image: url('$(res)/img/feather-customised/life-buoy.svg');
}
.mx_TopLeftMenu_icon_settings::after {
mask-image: url('$(res)/img/feather-customised/settings.svg');
}
.mx_TopLeftMenu_icon_signin::after {
mask-image: url('$(res)/img/feather-customised/sign-in.svg');
}
.mx_TopLeftMenu_icon_signout::after {
mask-image: url('$(res)/img/feather-customised/sign-out.svg');
}
.mx_AccessibleButton::after {
mask-repeat: no-repeat;
mask-position: 0 center;
mask-size: $font-16px;
position: absolute;
width: $font-16px;
height: $font-16px;
content: "";
top: 5px;
left: 14px;
background-color: $primary-fg-color;
}
.mx_AccessibleButton {
position: relative;
cursor: pointer;
white-space: nowrap;
padding: 5px 20px 5px 43px;
}
.mx_AccessibleButton:hover {
background-color: $menu-selected-color;
}
}
}

View File

@ -0,0 +1,23 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_BugReportDialog {
.mx_BugReportDialog_download {
.mx_AccessibleButton_kind_link {
padding-left: 0;
}
}
}

View File

@ -0,0 +1,88 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_CommunityPrototypeInviteDialog {
&.mx_Dialog_fixedWidth {
width: 360px;
}
.mx_Dialog_content {
margin-bottom: 0;
.mx_CommunityPrototypeInviteDialog_people {
position: relative;
margin-bottom: 4px;
.mx_AccessibleButton {
display: inline-block;
background-color: $focus-bg-color; // XXX: Abuse of variables
border-radius: 4px;
padding: 3px 5px;
font-size: $font-12px;
float: right;
}
}
.mx_CommunityPrototypeInviteDialog_morePeople {
margin-top: 8px;
}
.mx_CommunityPrototypeInviteDialog_person {
position: relative;
margin-top: 4px;
& > * {
vertical-align: middle;
}
.mx_Checkbox {
position: absolute;
right: 0;
top: calc(50% - 8px); // checkbox is 16px high
width: 16px; // to force a square
}
.mx_CommunityPrototypeInviteDialog_personIdentifiers {
display: inline-block;
& > * {
display: block;
}
.mx_CommunityPrototypeInviteDialog_personName {
font-weight: 600;
font-size: $font-14px;
color: $primary-fg-color;
margin-left: 7px;
}
.mx_CommunityPrototypeInviteDialog_personId {
font-size: $font-12px;
color: $muted-fg-color;
margin-left: 7px;
}
}
}
.mx_CommunityPrototypeInviteDialog_primaryButton {
display: block;
font-size: $font-13px;
line-height: 20px;
height: 20px;
margin-top: 24px;
}
}
}

View File

@ -0,0 +1,102 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_CreateCommunityPrototypeDialog {
.mx_Dialog_content {
display: flex;
flex-direction: row;
margin-bottom: 12px;
.mx_CreateCommunityPrototypeDialog_colName {
flex-basis: 66.66%;
padding-right: 100px;
.mx_Field input {
font-size: $font-16px;
line-height: $font-20px;
}
.mx_CreateCommunityPrototypeDialog_subtext {
display: block;
color: $muted-fg-color;
margin-bottom: 16px;
&:last-child {
margin-top: 16px;
}
&.mx_CreateCommunityPrototypeDialog_subtext_error {
color: $warning-color;
}
}
.mx_CreateCommunityPrototypeDialog_communityId {
position: relative;
.mx_InfoTooltip {
float: right;
}
}
.mx_AccessibleButton {
display: block;
height: 32px;
font-size: $font-16px;
line-height: 32px;
}
}
.mx_CreateCommunityPrototypeDialog_colAvatar {
flex-basis: 33.33%;
.mx_CreateCommunityPrototypeDialog_avatarContainer {
margin-top: 12px;
margin-bottom: 20px;
.mx_CreateCommunityPrototypeDialog_avatar,
.mx_CreateCommunityPrototypeDialog_placeholderAvatar {
width: 96px;
height: 96px;
border-radius: 96px;
}
.mx_CreateCommunityPrototypeDialog_placeholderAvatar {
background-color: #368bd6; // hardcoded for both themes
&::before {
display: inline-block;
background-color: #fff; // hardcoded because the background is
mask-repeat: no-repeat;
mask-size: 96px;
width: 96px;
height: 96px;
mask-position: center;
content: '';
vertical-align: middle;
mask-image: url('$(res)/img/element-icons/add-photo.svg');
}
}
}
.mx_CreateCommunityPrototypeDialog_tip {
& > b, & > span {
display: block;
color: $muted-fg-color;
}
}
}
}
}

View File

@ -0,0 +1,77 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// XXX: many of these styles are shared with the create dialog
.mx_EditCommunityPrototypeDialog {
&.mx_Dialog_fixedWidth {
width: 360px;
}
.mx_Dialog_content {
margin-bottom: 12px;
.mx_AccessibleButton.mx_AccessibleButton_kind_primary {
display: block;
height: 32px;
font-size: $font-16px;
line-height: 32px;
}
.mx_EditCommunityPrototypeDialog_rowAvatar {
display: flex;
flex-direction: row;
align-items: center;
}
.mx_EditCommunityPrototypeDialog_avatarContainer {
margin-top: 20px;
margin-bottom: 20px;
.mx_EditCommunityPrototypeDialog_avatar,
.mx_EditCommunityPrototypeDialog_placeholderAvatar {
width: 96px;
height: 96px;
border-radius: 96px;
}
.mx_EditCommunityPrototypeDialog_placeholderAvatar {
background-color: #368bd6; // hardcoded for both themes
&::before {
display: inline-block;
background-color: #fff; // hardcoded because the background is
mask-repeat: no-repeat;
mask-size: 96px;
width: 96px;
height: 96px;
mask-position: center;
content: '';
vertical-align: middle;
mask-image: url('$(res)/img/element-icons/add-photo.svg');
}
}
}
.mx_EditCommunityPrototypeDialog_tip {
margin-left: 20px;
& > b, & > span {
display: block;
color: $muted-fg-color;
}
}
}
}

View File

@ -89,6 +89,13 @@ limitations under the License.
font-weight: bold;
text-transform: uppercase;
}
.mx_InviteDialog_subname {
margin-bottom: 10px;
margin-top: -10px; // HACK: Positioning with margins is bad
font-size: $font-12px;
color: $muted-fg-color;
}
}
.mx_InviteDialog_roomTile {
@ -226,3 +233,7 @@ limitations under the License.
.mx_InviteDialog_addressBar {
margin-right: 45px;
}
.mx_InviteDialog_helpText .mx_AccessibleButton_kind_link {
padding: 0;
}

View File

@ -1,64 +0,0 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_RebrandDialog {
text-align: center;
a:link,
a:hover,
a:visited {
@mixin mx_Dialog_link;
}
.mx_Dialog_buttons {
margin-top: 43px;
text-align: center;
}
}
.mx_RebrandDialog_body {
width: 550px;
margin-left: auto;
margin-right: auto;
}
.mx_RebrandDialog_logoContainer {
margin-top: 35px;
margin-bottom: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.mx_RebrandDialog_logo {
margin-left: 28px;
margin-right: 28px;
width: 64px;
height: 64px;
}
.mx_RebrandDialog_chevron::after {
content: '';
display: inline-block;
width: 30px;
height: 30px;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background-color: $muted-fg-color;
mask-image: url('$(res)/img/feather-customised/chevron-down.svg');
transform: rotate(-90deg);
}

View File

@ -51,7 +51,8 @@ limitations under the License.
display: inherit;
}
.mx_ShareDialog_matrixto_copy > div {
background-image: url($copy-button-url);
mask-image: url($copy-button-url);
background-color: $message-action-bar-fg-color;
margin-left: 5px;
width: 20px;
height: 20px;

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -14,26 +14,21 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_ColorSettings_roomColor {
.mx_InfoTooltip_icon {
width: 16px;
height: 16px;
display: inline-block;
position: relative;
width: 37px;
height: 37px;
border: 1px solid #979797;
margin-right: 13px;
cursor: pointer;
}
.mx_ColorSettings_roomColor_selected {
position: absolute;
left: 10px;
top: 4px;
cursor: default !important;
}
.mx_ColorSettings_roomColorPrimary {
height: 10px;
position: absolute;
bottom: 0px;
width: 100%;
.mx_InfoTooltip_icon::before {
display: inline-block;
background-color: $muted-fg-color;
mask-repeat: no-repeat;
mask-size: 16px;
width: 16px;
height: 16px;
mask-position: center;
content: '';
vertical-align: middle;
mask-image: url('$(res)/img/element-icons/info.svg');
}

View File

@ -80,5 +80,11 @@ limitations under the License.
background-color: $accent-color;
border-color: $accent-color;
}
&.focus-visible {
& + label .mx_Checkbox_background {
@mixin unreal-focus;
}
}
}
}

View File

@ -63,6 +63,7 @@ limitations under the License.
box-sizing: border-box;
height: $font-16px;
width: $font-16px;
margin-left: 2px; // For the highlight on focus
border: $font-1-5px solid $radio-circle-color;
border-radius: $font-16px;
@ -77,6 +78,12 @@ limitations under the License.
}
}
&.focus-visible {
& + div {
@mixin unreal-focus;
}
}
&:checked {
& + div {
border-color: $active-radio-circle-color;

View File

@ -25,6 +25,7 @@ limitations under the License.
height: 100%;
left: 0;
top: 0;
border-radius: 4px;
}
.mx_MImageBody_thumbnail_container {

View File

@ -24,7 +24,7 @@ limitations under the License.
line-height: $font-24px;
border-radius: 4px;
background: $message-action-bar-bg-color;
top: -18px;
top: -26px;
right: 8px;
user-select: none;
// Ensure the action bar appears above over things, like the read marker.
@ -41,7 +41,7 @@ limitations under the License.
width: calc(10px + 48px + 100% + 8px);
// safe area + action bar
height: calc(20px + 100%);
top: -20px;
top: -12px;
left: -58px;
z-index: -1;
cursor: initial;

View File

@ -536,11 +536,12 @@ $left-gutter: 64px;
display: inline-block;
visibility: hidden;
cursor: pointer;
top: 8px;
top: 6px;
right: 6px;
width: 19px;
height: 19px;
background-image: url($copy-button-url);
mask-image: url($copy-button-url);
background-color: $message-action-bar-fg-color;
}
.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_copyButton,

View File

@ -54,7 +54,7 @@ $irc-line-height: $font-18px;
flex-shrink: 0;
width: var(--name-width);
text-overflow: ellipsis;
text-align: right;
text-align: left;
display: flex;
align-items: center;
overflow: visible;

View File

@ -21,6 +21,7 @@ limitations under the License.
border-top: 1px solid $primary-hairline-color;
position: relative;
padding-left: 82px;
padding-right: 6px;
}
.mx_MessageComposer_replaced_wrapper {
@ -178,25 +179,44 @@ limitations under the License.
color: $accent-color;
}
.mx_MessageComposer_button_highlight {
background: rgba($accent-color, 0.25);
// make the icon the accent color too
&::before {
background-color: $accent-color !important;
}
}
.mx_MessageComposer_button {
position: relative;
margin-right: 12px;
margin-right: 6px;
cursor: pointer;
height: 20px;
width: 20px;
height: 26px;
width: 26px;
border-radius: 100%;
&::before {
content: '';
position: absolute;
top: 3px;
left: 3px;
height: 20px;
width: 20px;
background-color: $composer-button-color;
background-color: $icon-button-color;
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
}
&:hover {
background: rgba($accent-color, 0.1);
&::before {
background-color: $accent-color;
}
}
&.mx_MessageComposer_hangup::before {
background-color: $warning-color;
}
@ -288,7 +308,7 @@ limitations under the License.
mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
background-color: $composer-button-color;
background-color: $icon-button-color;
&.mx_MessageComposer_markdownDisabled {
opacity: 0.2;

View File

@ -15,10 +15,6 @@ limitations under the License.
*/
.mx_ReplyPreview {
position: absolute;
bottom: 0;
z-index: 1000;
width: 100%;
border: 1px solid $primary-hairline-color;
background: $primary-bg-color;
border-bottom: none;

View File

@ -222,7 +222,7 @@ limitations under the License.
left: 4px; // center with parent of 32px
height: 24px;
width: 24px;
background-color: $roomheader-button-color;
background-color: $icon-button-color;
mask-repeat: no-repeat;
mask-size: contain;
}

View File

@ -17,3 +17,43 @@ limitations under the License.
.mx_RoomList {
padding-right: 7px; // width of the scrollbar, to line things up
}
.mx_RoomList_iconPlus::before {
mask-image: url('$(res)/img/element-icons/roomlist/plus.svg');
}
.mx_RoomList_iconExplore::before {
mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
}
.mx_RoomList_explorePrompt {
margin: 4px 12px 4px;
padding-top: 12px;
border-top: 1px solid $tertiary-fg-color;
font-size: $font-13px;
div:first-child {
font-weight: $font-semi-bold;
margin-bottom: 8px;
}
.mx_AccessibleButton {
color: $secondary-fg-color;
position: relative;
padding: 0 0 0 24px;
font-size: inherit;
&::before {
content: '';
width: 16px;
height: 16px;
position: absolute;
top: 0;
left: 0;
background: $secondary-fg-color;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
}
}
}

View File

@ -120,7 +120,7 @@ limitations under the License.
}
.mx_RoomSublist_auxButton::before {
mask-image: url('$(res)/img/feather-customised/plus.svg');
mask-image: url('$(res)/img/element-icons/roomlist/plus.svg');
}
.mx_RoomSublist_menuButton::before {
@ -169,7 +169,7 @@ limitations under the License.
// that the sublists below them do not jump. However, that leaves a gap
// when scrolled to the top above the first sublist (whose header can only
// ever stick to top), so we force height to 0 for only that first header.
// See also https://github.com/vector-im/riot-web/issues/14429.
// See also https://github.com/vector-im/element-web/issues/14429.
&:first-child .mx_RoomSublist_headerContainer {
height: 0;
padding-bottom: 4px;

View File

@ -175,48 +175,8 @@ limitations under the License.
.mx_RoomTile_iconBellMentions::before {
mask-image: url('$(res)/img/element-icons/roomlist/notifications-dm.svg');
}
.mx_RoomTile_iconCheck::before {
mask-image: url('$(res)/img/element-icons/roomlist/checkmark.svg');
}
.mx_RoomTile_contextMenu {
.mx_RoomTile_contextMenu_redRow {
.mx_AccessibleButton {
color: $warning-color !important; // !important to override styles from context menu
}
.mx_IconizedContextMenu_icon::before {
background-color: $warning-color;
}
}
.mx_RoomTile_contextMenu_activeRow {
&.mx_AccessibleButton, .mx_AccessibleButton {
color: $accent-color !important; // !important to override styles from context menu
}
.mx_IconizedContextMenu_icon::before {
background-color: $accent-color;
}
}
.mx_IconizedContextMenu_icon {
position: relative;
width: 16px;
height: 16px;
&::before {
content: '';
width: 16px;
height: 16px;
position: absolute;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background: $primary-fg-color;
}
}
.mx_RoomTile_iconStar::before {
mask-image: url('$(res)/img/element-icons/roomlist/favorite.svg');
}

View File

@ -1,69 +0,0 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_RoomTileIcon {
width: 12px;
height: 12px;
border-radius: 12px;
background-color: $roomlist-bg-color; // to match the room list itself
}
.mx_RoomTileIcon_globe::before {
content: '';
width: 8px;
height: 8px;
top: 2px;
left: 2px;
position: absolute;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background: $primary-fg-color;
mask-image: url('$(res)/img/globe.svg');
}
.mx_RoomTileIcon_offline::before {
content: '';
width: 8px;
height: 8px;
top: 2px;
left: 2px;
position: absolute;
border-radius: 8px;
background-color: $presence-offline;
}
.mx_RoomTileIcon_online::before {
content: '';
width: 8px;
height: 8px;
top: 2px;
left: 2px;
position: absolute;
border-radius: 8px;
background-color: $presence-online;
}
.mx_RoomTileIcon_away::before {
content: '';
width: 8px;
height: 8px;
top: 2px;
left: 2px;
position: absolute;
border-radius: 8px;
background-color: $presence-away;
}

View File

@ -44,10 +44,5 @@ limitations under the License.
overflow-y: auto;
}
}
.mx_SendMessageComposer_overlayWrapper {
position: relative;
height: 0;
}
}

View File

@ -14,10 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_SecurityRoomSettingsTab label {
display: block;
}
.mx_SecurityRoomSettingsTab_warning {
display: block;

View File

@ -0,0 +1,5 @@
<svg width="84" height="84" viewBox="0 0 84 84" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M36.7988 34.9062C37.077 33.5217 38.2978 32.5 39.7396 32.5H44.2604C45.7022 32.5 46.923 33.5217 47.2012 34.9062C47.2429 35.1137 47.3232 35.3141 47.4627 35.4731L48.0649 36.1595C48.2548 36.3759 48.5287 36.5 48.8166 36.5H52C53.1046 36.5 54 37.3954 54 38.5V49.5C54 50.6046 53.1046 51.5 52 51.5H32C30.8954 51.5 30 50.6046 30 49.5V38.5C30 37.3954 30.8954 36.5 32 36.5H35.1834C35.4713 36.5 35.7452 36.3759 35.9351 36.1595L36.5373 35.4731C36.6768 35.3141 36.7571 35.1137 36.7988 34.9062ZM42 47.5C44.2091 47.5 46 45.7091 46 43.5C46 41.2909 44.2091 39.5 42 39.5C39.7909 39.5 38 41.2909 38 43.5C38 45.7091 39.7909 47.5 42 47.5Z" fill="white"/>
<rect x="32" y="35" width="3" height="1" rx="0.5" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M59.75 27C59.75 26.5858 59.4142 26.25 59 26.25C58.5858 26.25 58.25 26.5858 58.25 27V31.25L54 31.25C53.5858 31.25 53.25 31.5858 53.25 32C53.25 32.4142 53.5858 32.75 54 32.75L58.25 32.75V37C58.25 37.4142 58.5858 37.75 59 37.75C59.4142 37.75 59.75 37.4142 59.75 37V32.75L64 32.75C64.4142 32.75 64.75 32.4142 64.75 32C64.75 31.5858 64.4142 31.25 64 31.25L59.75 31.25V27Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View 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="M2.33301 7.28322V14.9493C2.33301 16.0735 3.25744 16.9776 4.38152 16.9659C4.90089 16.9605 5.44431 16.9567 6 16.9543V11.5C6 10.6716 6.67157 10 7.5 10H10.5C11.3284 10 12 10.6716 12 11.5V16.9662C12.6022 16.9703 13.1579 16.9748 13.6449 16.9791C14.7592 16.989 15.6663 16.0899 15.6663 14.9756V7.28178C15.6663 6.89062 15.4946 6.52064 15.1965 6.2673L9.97115 1.82572C9.411 1.3496 8.58834 1.3496 8.0282 1.82572L2.80281 6.2673C2.50477 6.52064 2.33301 6.89206 2.33301 7.28322Z" fill="#737D8C"/>
</svg>

After

Width:  |  Height:  |  Size: 634 B

View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="10" cy="10" r="9.5" stroke="#787878"/>
<path d="M9.79248 14H11.2065V8H9.79248V14ZM10.5034 7.14844C10.9526 7.14844 11.3198 6.80469 11.3198 6.38281C11.3198 5.95703 10.9526 5.61328 10.5034 5.61328C10.0503 5.61328 9.68311 5.95703 9.68311 6.38281C9.68311 6.80469 10.0503 7.14844 10.5034 7.14844Z" fill="#787878"/>
</svg>

After

Width:  |  Height:  |  Size: 424 B

View 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="M30.7161 22.2903C31.5425 20.3595 32 18.2332 32 16C32 7.16344 24.8366 0 16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32C18.2332 32 20.3595 31.5425 22.2903 30.7161C20.8956 29.6174 20 27.9133 20 26C20 22.6863 22.6863 20 26 20C27.9133 20 29.6174 20.8956 30.7161 22.2903Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 444 B

View 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 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 9ZM13.375 5.3266C13.5583 4.92826 13.0716 4.44152 12.6733 4.62491L7.66968 6.9285C7.33893 7.08077 7.08014 7.33956 6.92787 7.67031L4.62428 12.6739C4.44089 13.0722 4.92763 13.559 5.32597 13.3756L10.3295 11.072C10.6603 10.9197 10.9191 10.6609 11.0714 10.3302L13.375 5.3266Z" fill="black"/>
<path d="M9.8835 9.88413C9.39534 10.3723 8.60389 10.3723 8.11573 9.88413C7.62757 9.39597 7.62757 8.60452 8.11573 8.11636C8.60389 7.62821 9.39534 7.62821 9.8835 8.11636C10.3717 8.60452 10.3717 9.39597 9.8835 9.88413Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 775 B

View 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="M9.75 4C9.75 3.58579 9.41421 3.25 9 3.25C8.58579 3.25 8.25 3.58579 8.25 4V8.25L4 8.25C3.58579 8.25 3.25 8.58579 3.25 9C3.25 9.41421 3.58579 9.75 4 9.75L8.25 9.75V14C8.25 14.4142 8.58579 14.75 9 14.75C9.41421 14.75 9.75 14.4142 9.75 14V9.75L14 9.75C14.4142 9.75 14.75 9.41421 14.75 9C14.75 8.58579 14.4142 8.25 14 8.25L9.75 8.25V4Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 499 B

View 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="M9 16C12.866 16 16 12.866 16 9C16 5.13401 12.866 2 9 2C5.13401 2 2 5.13401 2 9C2 12.866 5.13401 16 9 16ZM5.96967 5.96967C6.26256 5.67678 6.73744 5.67678 7.03033 5.96967L9 7.93934L10.9697 5.96967C11.2626 5.67678 11.7374 5.67678 12.0303 5.96967C12.3232 6.26256 12.3232 6.73744 12.0303 7.03033L10.0607 9L12.0303 10.9697C12.3232 11.2626 12.3232 11.7374 12.0303 12.0303C11.7374 12.3232 11.2626 12.3232 10.9697 12.0303L9 10.0607L7.03033 12.0303C6.73744 12.3232 6.26256 12.3232 5.96967 12.0303C5.67678 11.7374 5.67678 11.2626 5.96967 10.9697L7.93934 9L5.96967 7.03033C5.67678 6.73744 5.67678 6.26256 5.96967 5.96967Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 778 B

View 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="M12.1333 8.06667C12.1333 10.3126 10.3126 12.1333 8.06667 12.1333C5.82071 12.1333 4 10.3126 4 8.06667C4 5.82071 5.82071 4 8.06667 4C10.3126 4 12.1333 5.82071 12.1333 8.06667ZM12.9992 11.5994C13.7131 10.6044 14.1333 9.38463 14.1333 8.06667C14.1333 4.71614 11.4172 2 8.06667 2C4.71614 2 2 4.71614 2 8.06667C2 11.4172 4.71614 14.1333 8.06667 14.1333C9.38457 14.1333 10.6043 13.7131 11.5992 12.9993C11.6274 13.0369 11.6586 13.0729 11.6928 13.1071L14.2928 15.7071C14.6833 16.0977 15.3165 16.0977 15.707 15.7071C16.0975 15.3166 16.0975 14.6834 15.707 14.2929L13.107 11.6929C13.0728 11.6587 13.0368 11.6276 12.9992 11.5994Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 784 B

View File

@ -1,6 +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="M8.64001 1.44C8.64001 0.64471 9.28472 0 10.08 0C15.3819 0 19.68 4.29807 19.68 9.6C19.68 10.3953 19.0353 11.04 18.24 11.04C17.4447 11.04 16.8 10.3953 16.8 9.6C16.8 5.88865 13.7914 2.88 10.08 2.88C9.28472 2.88 8.64001 2.23529 8.64001 1.44Z" fill="#0DBD8B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.36 22.56C15.36 23.3553 14.7153 24 13.92 24C8.61805 24 4.31999 19.7019 4.31999 14.4C4.31999 13.6047 4.9647 12.96 5.75999 12.96C6.55528 12.96 7.19999 13.6047 7.19999 14.4C7.19999 18.1114 10.2086 21.12 13.92 21.12C14.7153 21.12 15.36 21.7647 15.36 22.56Z" fill="#0DBD8B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.44 15.36C0.64471 15.36 -1.40906e-08 14.7153 -3.14722e-08 13.92C-1.4735e-07 8.61805 4.29807 4.31999 9.6 4.31998C10.3953 4.31998 11.04 4.96469 11.04 5.75998C11.04 6.55527 10.3953 7.19998 9.6 7.19998C5.88865 7.19998 2.88 10.2086 2.88 13.92C2.88 14.7153 2.23529 15.36 1.44 15.36Z" fill="#0DBD8B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.56 8.64001C23.3553 8.64001 24 9.28472 24 10.08C24 15.3819 19.7019 19.68 14.4 19.68C13.6047 19.68 12.96 19.0353 12.96 18.24C12.96 17.4447 13.6047 16.8 14.4 16.8C18.1114 16.8 21.12 13.7914 21.12 10.08C21.12 9.28472 21.7647 8.64001 22.56 8.64001Z" fill="#0DBD8B"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View 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="M10.75 3.75H3.75V10.75" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="7" y="7" width="7" height="7" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 341 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-compass"><circle cx="12" cy="12" r="10"></circle><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"></polygon></svg>

Before

Width:  |  Height:  |  Size: 342 B

View File

@ -1,6 +1,3 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="icon">
<path id="sea" fill-rule="evenodd" clip-rule="evenodd" d="M4 8C6.20914 8 8 6.20914 8 4C8 1.79086 6.20914 0 4 0C1.79086 0 0 1.79086 0 4C0 6.20914 1.79086 8 4 8ZM4.6693 2.43613C4.8306 2.64728 4.94732 2.80007 4.45289 2.80007C4.14732 2.80007 3.84175 2.74171 3.58076 2.69186C3.15847 2.61121 2.85289 2.55285 2.85289 2.80007C2.85289 3.00007 3.65289 3.40007 4.45289 3.80007C5.25289 4.20007 6.05289 4.60007 6.05289 4.80007C6.05289 5.20007 6.05289 7.60007 5.25289 7.20007C4.45289 6.80007 2.45289 5.20007 2.45289 4.80007C2.45289 4.65277 2.18168 4.39698 1.85897 4.09263C1.30535 3.57051 0.600192 2.90547 0.852893 2.40007C1.25289 1.60007 2.85289 6.51479e-05 5.25289 0.800065C4.98623 1.06673 4.45289 1.68007 4.45289 2.00007C4.45289 2.15285 4.56961 2.30564 4.6693 2.43613Z" fill="#2E2F32"/>
<path id="earth" d="M4.45294 2.80007C5.25294 2.80007 4.45294 2.40007 4.45294 2.00007C4.45294 1.68007 4.98627 1.06673 5.25294 0.800065C2.85294 6.51479e-05 1.25294 1.60007 0.852941 2.40007C0.452941 3.20007 2.45294 4.40007 2.45294 4.80007C2.45294 5.20007 4.45294 6.80007 5.25294 7.20007C6.05294 7.60007 6.05294 5.20007 6.05294 4.80007C6.05294 4.40007 2.85294 3.20007 2.85294 2.80007C2.85294 2.40007 3.65294 2.80007 4.45294 2.80007Z" />
</g>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 8C6.20914 8 8 6.20914 8 4C8 1.79086 6.20914 0 4 0C1.79086 0 0 1.79086 0 4C0 6.20914 1.79086 8 4 8ZM6.53332 5.3468L6.24528 6.23562C6.23346 6.27208 6.21342 6.30534 6.1867 6.33282L5.90913 6.61831L5.59095 6.94559L5.52111 7.01743C5.4003 7.14169 5.19279 7.10832 5.11702 6.95246L4.97216 6.65447C4.96052 6.63052 4.94513 6.60859 4.92657 6.58949L4.63641 6.29104L4.39185 6.0395C4.34478 5.99108 4.28013 5.96377 4.2126 5.96377H3.83831C3.74261 5.96377 3.6553 5.90914 3.61347 5.82307L3.38884 5.36098C3.37228 5.32692 3.36368 5.28955 3.36368 5.25168V4.47996C3.36368 4.38629 3.31132 4.30048 3.22802 4.25764L2.78114 4.02781C2.74577 4.00962 2.70657 4.00013 2.6668 4.00013H2.19658C2.12905 4.00013 2.0644 3.97282 2.01733 3.9244L1.53085 3.42402C1.48223 3.37402 1.45672 3.30599 1.46046 3.23635L1.49316 2.62739C1.4977 2.54285 1.51357 2.45929 1.54034 2.37897L1.65227 2.0432C1.87098 1.38707 2.38792 0.873558 3.0455 0.659224L3.05974 0.654815C3.66901 0.466234 4.32388 0.487134 4.91987 0.714181C4.94274 0.722892 4.96343 0.736497 4.98049 0.754043L5.42152 1.20768C5.51586 1.30471 5.51586 1.45919 5.42152 1.55622L4.70716 2.291C4.66179 2.33766 4.63641 2.40018 4.63641 2.46527V2.71165C4.63641 2.86997 4.49111 2.98843 4.33603 2.95652L3.34587 2.75283C3.1908 2.72093 3.0455 2.83938 3.0455 2.99771V3.09559C3.0455 3.23366 3.15743 3.34559 3.2955 3.34559H3.75004C3.88812 3.34559 4.00004 3.45752 4.00004 3.59559V3.75013C4.00004 3.8882 4.11197 4.00013 4.25004 4.00013H5.16715C5.23467 4.00013 5.29933 4.02745 5.3464 4.07586L5.56243 4.29807C5.58132 4.3175 5.60324 4.33373 5.62734 4.34612L6.19093 4.63596C6.21503 4.64836 6.23695 4.66459 6.25584 4.68402L6.47475 4.90918C6.52012 4.95584 6.5455 5.01836 6.5455 5.08345V5.26973C6.5455 5.2959 6.54139 5.3219 6.53332 5.3468Z" fill="#A9B2BC"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,86 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="19px"
height="19px"
viewBox="0 0 19 19"
version="1.1"
id="svg3734"
sodipodi:docname="icon_copy_message.svg"
inkscape:version="0.92.1 r">
<metadata
id="metadata3738">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>ED5D3E59-2561-4AC1-9B43-82FBC51767FC</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1596"
inkscape:window-height="846"
id="namedview3736"
showgrid="false"
inkscape:zoom="12.421053"
inkscape:cx="3.4935767"
inkscape:cy="2.469644"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="Symbols" />
<!-- Generator: sketchtool 39.1 (31720) - http://www.bohemiancoding.com/sketch -->
<title
id="title3722">ED5D3E59-2561-4AC1-9B43-82FBC51767FC</title>
<desc
id="desc3724">Created with sketchtool.</desc>
<defs
id="defs3726" />
<g
id="Symbols"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd">
<path
d="M 9.5,19 C 14.746705,19 19,14.746705 19,9.5 19,4.2532949 14.746705,0 9.5,0 4.2532949,0 0,4.2532949 0,9.5 0,14.746705 4.2532949,19 9.5,19 Z"
id="Oval-69"
inkscape:connector-curvature="0"
style="fill:#ececec" />
<g
id="g4632"
transform="translate(-2.3841858e-7,-1)">
<rect
style="stroke:#9b9b9b;stroke-width:0.91585475;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
y="4.3017478"
x="4.6289611"
height="10.396504"
width="7.7420783"
id="rect3745-3" />
<rect
style="fill:#ececec;fill-opacity:1;stroke:#9b9b9b;stroke-width:0.91585475;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
y="6.3017478"
x="6.6289611"
height="10.396504"
width="7.7420783"
id="rect3745" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -1,6 +0,0 @@
<svg width="42" height="50" viewBox="0 0 42 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.04021 42.174C1.04021 45.944 4.27657 49 8.26822 49C12.2603 49 15.4962 45.944 15.4962 42.174V35.2587L22.8119 35.2518C23.2234 35.2518 23.6386 35.2385 24.0415 35.2122C33.5209 34.6096 40.9465 27.1046 40.9465 18.1261C40.9465 8.68273 32.8114 1 22.8119 1H8.26822C4.27657 1 1.04021 4.05637 1.04021 7.82645V27.7141C1.01327 27.9548 0.999582 28.1987 1.00001 28.4459C1.00001 28.6887 1.01412 28.9286 1.04021 29.1645V42.174ZM15.4963 21.6066V14.6525H22.812C24.8405 14.6525 26.4901 16.2103 26.4901 18.1261C26.4901 19.9469 24.9881 21.4692 23.0665 21.5916C22.9822 21.5969 22.8975 21.5993 22.8047 21.5993L15.4963 21.6066Z" fill="#A2DDEF"/>
<path d="M15.4963 14.6525V14.0405H14.8844V14.6525H15.4963ZM15.4963 21.6066H14.8844V22.2191L15.4969 22.2185L15.4963 21.6066ZM22.8047 21.5993V20.9874H22.8041L22.8047 21.5993ZM23.0665 21.5916L23.1045 22.2024L23.1053 22.2023L23.0665 21.5916ZM1.04021 29.1645H1.65214V29.1308L1.64843 29.0972L1.04021 29.1645ZM1.00001 28.4459H1.61194L1.61193 28.4449L1.00001 28.4459ZM1.04021 27.7141L1.64834 27.7821L1.65214 27.7482V27.7141H1.04021ZM24.0415 35.2122L24.0027 34.6015L24.0017 34.6016L24.0415 35.2122ZM22.8119 35.2518V34.6399H22.8113L22.8119 35.2518ZM15.4962 35.2587L15.4957 34.6467L14.8843 34.6473V35.2587H15.4962ZM14.8844 14.6525V21.6066H16.1082V14.6525H14.8844ZM15.4969 22.2185L22.8053 22.2112L22.8041 20.9874L15.4957 20.9946L15.4969 22.2185ZM22.8047 22.2112C22.9085 22.2112 23.006 22.2085 23.1045 22.2024L23.0284 20.9809C22.9584 20.9852 22.8865 20.9874 22.8047 20.9874V22.2112ZM23.1053 22.2023C25.3203 22.0612 27.1021 20.2979 27.1021 18.1261H25.8782C25.8782 19.5959 24.6559 20.8772 23.0276 20.9809L23.1053 22.2023ZM27.1021 18.1261C27.1021 15.8399 25.145 14.0405 22.812 14.0405V15.2644C24.536 15.2644 25.8782 16.5808 25.8782 18.1261H27.1021ZM22.812 14.0405H15.4963V15.2644H22.812V14.0405ZM8.26822 48.3881C4.58104 48.3881 1.65214 45.5735 1.65214 42.174H0.428288C0.428288 46.3145 3.97209 49.6119 8.26822 49.6119V48.3881ZM1.65214 42.174V29.1645H0.428288V42.174H1.65214ZM1.64843 29.0972C1.62467 28.8824 1.61193 28.665 1.61193 28.4459H0.388085C0.388085 28.7124 0.403576 28.9748 0.431997 29.2318L1.64843 29.0972ZM1.61193 28.4449C1.61155 28.221 1.62394 28.0001 1.64834 27.7821L0.432085 27.646C0.402599 27.9094 0.387617 28.1765 0.388085 28.447L1.61193 28.4449ZM1.65214 27.7141V7.82645H0.428288V27.7141H1.65214ZM1.65214 7.82645C1.65214 4.42682 4.58109 1.61193 8.26822 1.61193V0.388075C3.97204 0.388075 0.428288 3.68592 0.428288 7.82645H1.65214ZM8.26822 1.61193H22.8119V0.388075H8.26822V1.61193ZM22.8119 1.61193C32.5069 1.61193 40.3346 9.05321 40.3346 18.1261H41.5584C41.5584 8.31226 33.1159 0.388075 22.8119 0.388075V1.61193ZM40.3346 18.1261C40.3346 26.7525 33.1898 34.0175 24.0027 34.6015L24.0804 35.8229C33.8521 35.2017 41.5584 27.4566 41.5584 18.1261H40.3346ZM24.0017 34.6016C23.6124 34.6269 23.2104 34.6399 22.8119 34.6399V35.8637C23.2363 35.8637 23.6649 35.85 24.0813 35.8228L24.0017 34.6016ZM22.8113 34.6399L15.4957 34.6467L15.4968 35.8706L22.8125 35.8637L22.8113 34.6399ZM14.8843 35.2587V42.174H16.1082V35.2587H14.8843ZM14.8843 42.174C14.8843 45.5736 11.9558 48.3881 8.26822 48.3881V49.6119C12.5648 49.6119 16.1082 46.3145 16.1082 42.174H14.8843Z" fill="#368BD6"/>
<path d="M8.26823 42.174V7.82642H22.8119C28.8351 7.82642 33.7181 12.4378 33.7181 18.1261C33.7181 23.5784 29.232 28.0412 23.5561 28.4019C23.3098 28.4176 23.0621 28.4257 22.8119 28.4257L8.22803 28.4395" stroke="#368BD6" stroke-width="1.22385" stroke-linecap="round"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.4227 9.0113C15.758 7.21673 15.3325 5.4048 14.2243 3.91155C11.9366 0.828522 7.41753 0.0768486 4.15037 2.23574C2.56747 3.28105 1.51106 4.84579 1.17575 6.64116C0.84001 8.43653 1.26557 10.2481 2.37372 11.7413C4.66146 14.8243 9.18092 15.576 12.4481 13.4171C14.0306 12.3714 15.087 10.8071 15.4227 9.0113ZM27.852 46.0868C29.2587 47.9824 31.4998 48.9962 33.7777 48.9962C35.21 48.9962 36.6569 48.5951 37.9195 47.7594C41.1883 45.5965 41.9817 41.3397 39.6905 38.2522L29.4751 24.4846C27.1843 21.3972 22.6769 20.6475 19.408 22.8121C16.1392 24.975 15.3458 29.2318 17.6365 32.3192L27.852 46.0868Z" fill="#368BD6"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -46,7 +46,7 @@ $inverted-bg-color: $base-color;
$selected-color: $room-highlight-color;
// selected for hoverover & selected event tiles
$event-selected-color: $header-panel-bg-color;
$event-selected-color: #21262c;
// used for the hairline dividers in RoomView
$primary-hairline-color: transparent;
@ -100,10 +100,9 @@ $roomheader-bg-color: $bg-color;
$roomheader-addroom-bg-color: rgba(92, 100, 112, 0.3);
$roomheader-addroom-fg-color: $text-primary-color;
$tagpanel-button-color: $header-panel-text-primary-color;
$roomheader-button-color: $header-panel-text-primary-color;
$groupheader-button-color: $header-panel-text-primary-color;
$rightpanel-button-color: $header-panel-text-primary-color;
$composer-button-color: $header-panel-text-primary-color;
$icon-button-color: #8E99A4;
$roomtopic-color: $text-secondary-color;
$eventtile-meta-color: $roomtopic-color;
@ -115,10 +114,13 @@ $composer-e2e-icon-color: $header-panel-text-primary-color;
$theme-button-bg-color: #e3e8f0;
$roomlist-button-bg-color: rgba(141, 151, 165, 0.2); // Buttons include the filter box, explore button, and sublist buttons
$roomlist-filter-active-bg-color: $bg-color;
$roomlist-bg-color: rgba(33, 38, 44, 0.90);
$roomlist-header-color: $tertiary-fg-color;
$roomsublist-divider-color: $primary-fg-color;
$tagpanel-divider-color: $roomlist-header-color;
$roomtile-preview-color: $secondary-fg-color;
$roomtile-default-badge-bg-color: #61708b;
$roomtile-selected-bg-color: rgba(141, 151, 165, 0.2);

View File

@ -15,6 +15,8 @@ $room-highlight-color: #343a46;
// typical text (dark-on-white in light skin)
$primary-fg-color: $text-primary-color;
$secondary-fg-color: $primary-fg-color;
$tertiary-fg-color: $primary-fg-color;
$primary-bg-color: $bg-color;
$muted-fg-color: $header-panel-text-primary-color;
@ -95,10 +97,9 @@ $roomheader-color: $text-primary-color;
$roomheader-addroom-bg-color: #3c4556; // $search-placeholder-color at 0.5 opacity
$roomheader-addroom-fg-color: $text-primary-color;
$tagpanel-button-color: $header-panel-text-primary-color;
$roomheader-button-color: $header-panel-text-primary-color;
$groupheader-button-color: $header-panel-text-primary-color;
$rightpanel-button-color: $header-panel-text-primary-color;
$composer-button-color: $header-panel-text-primary-color;
$icon-button-color: $header-panel-text-primary-color;
$roomtopic-color: $text-secondary-color;
$eventtile-meta-color: $roomtopic-color;
@ -110,10 +111,13 @@ $composer-e2e-icon-color: $header-panel-text-primary-color;
$theme-button-bg-color: #e3e8f0;
$roomlist-button-bg-color: #1A1D23; // Buttons include the filter box, explore button, and sublist buttons
$roomlist-filter-active-bg-color: $roomlist-button-bg-color;
$roomlist-bg-color: $header-panel-bg-color;
$roomsublist-divider-color: $primary-fg-color;
$tagpanel-divider-color: $roomlist-header-color;
$roomtile-preview-color: #9e9e9e;
$roomtile-default-badge-bg-color: #61708b;
$roomtile-selected-bg-color: #1A1D23;

View File

@ -23,6 +23,8 @@ $header-panel-bg-color: #f3f8fd;
// typical text (dark-on-white in light skin)
$primary-fg-color: #2e2f32;
$secondary-fg-color: $primary-fg-color;
$tertiary-fg-color: $primary-fg-color;
$primary-bg-color: #ffffff;
$muted-fg-color: #61708b; // Commonly used in headings and relevant alt text
@ -162,10 +164,9 @@ $roomheader-bg-color: $primary-bg-color;
$roomheader-addroom-bg-color: #91a1c0;
$roomheader-addroom-fg-color: $accent-fg-color;
$tagpanel-button-color: #91a1c0;
$roomheader-button-color: #91a1c0;
$groupheader-button-color: #91a1c0;
$rightpanel-button-color: #91a1c0;
$composer-button-color: #91a1c0;
$icon-button-color: #91a1c0;
$roomtopic-color: #9e9e9e;
$eventtile-meta-color: $roomtopic-color;
@ -177,10 +178,13 @@ $header-divider-color: #91a1c0;
$theme-button-bg-color: #e3e8f0;
$roomlist-button-bg-color: #fff; // Buttons include the filter box, explore button, and sublist buttons
$roomlist-filter-active-bg-color: $roomlist-button-bg-color;
$roomlist-bg-color: $header-panel-bg-color;
$roomlist-header-color: $primary-fg-color;
$roomsublist-divider-color: $primary-fg-color;
$tagpanel-divider-color: $roomlist-header-color;
$roomtile-preview-color: #9e9e9e;
$roomtile-default-badge-bg-color: #61708b;
$roomtile-selected-bg-color: #fff;
@ -228,7 +232,8 @@ $event-redacted-border-color: #cccccc;
// event timestamp
$event-timestamp-color: #acacac;
$copy-button-url: "$(res)/img/icon_copy_message.svg";
$copy-button-url: "$(res)/img/feather-customised/clipboard.svg";
// e2e
$e2e-verified-color: #76cfa5; // N.B. *NOT* the same as $accent-color

View File

@ -1,3 +1,3 @@
// Path from root SCSS file (such as `light.scss`) to `res` dir in the source tree
// This value is overridden by external themes in `riot-web`.
// This value is overridden by external themes in `element-web`.
$res: ../../..;

View File

@ -74,7 +74,7 @@ $droptarget-bg-color: rgba(255,255,255,0.5);
$selected-color: $secondary-accent-color;
// selected for hoverover & selected event tiles
$event-selected-color: $header-panel-bg-color;
$event-selected-color: #f6f7f8;
// used for the hairline dividers in RoomView
$primary-hairline-color: transparent;
@ -158,10 +158,9 @@ $roomheader-bg-color: $primary-bg-color;
$roomheader-addroom-bg-color: rgba(92, 100, 112, 0.2);
$roomheader-addroom-fg-color: #5c6470;
$tagpanel-button-color: #91A1C0;
$roomheader-button-color: #91A1C0;
$groupheader-button-color: #91A1C0;
$rightpanel-button-color: #91A1C0;
$composer-button-color: #91A1C0;
$icon-button-color: #C1C6CD;
$roomtopic-color: #9e9e9e;
$eventtile-meta-color: $roomtopic-color;
@ -172,11 +171,14 @@ $header-divider-color: #91A1C0;
$theme-button-bg-color: #e3e8f0;
$roomlist-button-bg-color: #fff; // Buttons include the filter box, explore button, and sublist buttons
$roomlist-button-bg-color: rgba(141, 151, 165, 0.2); // Buttons include the filter box, explore button, and sublist buttons
$roomlist-filter-active-bg-color: #ffffff;
$roomlist-bg-color: rgba(245, 245, 245, 0.90);
$roomlist-header-color: $tertiary-fg-color;
$roomsublist-divider-color: $primary-fg-color;
$tagpanel-divider-color: $roomlist-header-color;
$roomtile-preview-color: $secondary-fg-color;
$roomtile-default-badge-bg-color: #61708b;
$roomtile-selected-bg-color: #FFF;
@ -230,7 +232,7 @@ $event-redacted-border-color: #cccccc;
// event timestamp
$event-timestamp-color: #acacac;
$copy-button-url: "$(res)/img/icon_copy_message.svg";
$copy-button-url: "$(res)/img/feather-customised/clipboard.svg";
// e2e
$e2e-verified-color: #76cfa5; // N.B. *NOT* the same as $accent-color

View File

@ -1,3 +1,3 @@
// Path from root SCSS file (such as `light.scss`) to `res` dir in the source tree
// This value is overridden by external themes in `riot-web`.
// This value is overridden by external themes in `element-web`.
$res: ../../..;

View File

@ -13,7 +13,7 @@ handle_error() {
trap 'handle_error' ERR
echo "--- Building Riot"
echo "--- Building Element"
scripts/ci/layered-riot-web.sh
cd ../riot-web
riot_web_dir=`pwd`

View File

@ -217,7 +217,7 @@ function getTranslationsOther(file) {
const trs = new Set();
// Taken from riot-web src/components/structures/HomePage.js
// Taken from element-web src/components/structures/HomePage.js
const translationsRegex = /_t\(['"]([\s\S]*?)['"]\)/mg;
let matches;
while (matches = translationsRegex.exec(contents)) {

View File

@ -19,17 +19,20 @@ import ContentMessages from "../ContentMessages";
import { IMatrixClientPeg } from "../MatrixClientPeg";
import ToastStore from "../stores/ToastStore";
import DeviceListener from "../DeviceListener";
import RebrandListener from "../RebrandListener";
import { RoomListStoreClass } from "../stores/room-list/RoomListStore";
import { PlatformPeg } from "../PlatformPeg";
import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore";
import {IntegrationManagers} from "../integrations/IntegrationManagers";
import {ModalManager} from "../Modal";
import SettingsStore from "../settings/SettingsStore";
import {ActiveRoomObserver} from "../ActiveRoomObserver";
import {Notifier} from "../Notifier";
import type {Renderer} from "react-dom";
declare global {
interface Window {
Modernizr: ModernizrStatic;
matrixChat: ReturnType<Renderer>;
mxMatrixClientPeg: IMatrixClientPeg;
Olm: {
init: () => Promise<void>;
@ -38,18 +41,14 @@ declare global {
mxContentMessages: ContentMessages;
mxToastStore: ToastStore;
mxDeviceListener: DeviceListener;
mxRebrandListener: RebrandListener;
mxRoomListStore: RoomListStoreClass;
mxRoomListLayoutStore: RoomListLayoutStore;
mxActiveRoomObserver: ActiveRoomObserver;
mxPlatformPeg: PlatformPeg;
mxIntegrationManagers: typeof IntegrationManagers;
singletonModalManager: ModalManager;
mxSettingsStore: SettingsStore;
}
// workaround for https://github.com/microsoft/TypeScript/issues/30933
interface ObjectConstructor {
fromEntries?(xs: [string|number|symbol, any][]): object;
mxNotifier: typeof Notifier;
}
interface Document {
@ -77,4 +76,8 @@ declare global {
interface PromiseConstructor {
allSettled<T>(promises: Promise<T>[]): Promise<Array<ISettledFulfilled<T> | ISettledRejected>>;
}
interface HTMLAudioElement {
type?: string;
}
}

View File

@ -16,6 +16,8 @@ limitations under the License.
import RoomViewStore from './stores/RoomViewStore';
type Listener = (isActive: boolean) => void;
/**
* Consumes changes from the RoomViewStore and notifies specific things
* about when the active room changes. Unlike listening for RoomViewStore
@ -25,57 +27,57 @@ import RoomViewStore from './stores/RoomViewStore';
* TODO: If we introduce an observer for something else, factor out
* the adding / removing of listeners & emitting into a common class.
*/
class ActiveRoomObserver {
constructor() {
this._listeners = {}; // key=roomId, value=function(isActive:boolean)
export class ActiveRoomObserver {
private listeners: {[key: string]: Listener[]} = {};
private _activeRoomId = RoomViewStore.getRoomId();
private readonly roomStoreToken: string;
this._activeRoomId = RoomViewStore.getRoomId();
// TODO: We could self-destruct when the last listener goes away, or at least
// stop listening.
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this));
constructor() {
// TODO: We could self-destruct when the last listener goes away, or at least stop listening.
this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
}
get activeRoomId(): string {
public get activeRoomId(): string {
return this._activeRoomId;
}
addListener(roomId, listener) {
if (!this._listeners[roomId]) this._listeners[roomId] = [];
this._listeners[roomId].push(listener);
public addListener(roomId, listener) {
if (!this.listeners[roomId]) this.listeners[roomId] = [];
this.listeners[roomId].push(listener);
}
removeListener(roomId, listener) {
if (this._listeners[roomId]) {
const i = this._listeners[roomId].indexOf(listener);
public removeListener(roomId, listener) {
if (this.listeners[roomId]) {
const i = this.listeners[roomId].indexOf(listener);
if (i > -1) {
this._listeners[roomId].splice(i, 1);
this.listeners[roomId].splice(i, 1);
}
} else {
console.warn("Unregistering unrecognised listener (roomId=" + roomId + ")");
}
}
_emit(roomId, isActive: boolean) {
if (!this._listeners[roomId]) return;
private emit(roomId, isActive: boolean) {
if (!this.listeners[roomId]) return;
for (const l of this._listeners[roomId]) {
for (const l of this.listeners[roomId]) {
l.call(null, isActive);
}
}
_onRoomViewStoreUpdate() {
private onRoomViewStoreUpdate = () => {
// emit for the old room ID
if (this._activeRoomId) this._emit(this._activeRoomId, false);
if (this._activeRoomId) this.emit(this._activeRoomId, false);
// update our cache
this._activeRoomId = RoomViewStore.getRoomId();
// and emit for the new one
if (this._activeRoomId) this._emit(this._activeRoomId, true);
}
if (this._activeRoomId) this.emit(this._activeRoomId, true);
};
}
if (global.mx_ActiveRoomObserver === undefined) {
global.mx_ActiveRoomObserver = new ActiveRoomObserver();
if (window.mxActiveRoomObserver === undefined) {
window.mxActiveRoomObserver = new ActiveRoomObserver();
}
export default global.mx_ActiveRoomObserver;
export default window.mxActiveRoomObserver;

View File

@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import createReactClass from 'create-react-class';
import React from "react";
import * as sdk from './index';
import PropTypes from 'prop-types';
import { _t } from './languageHandler';
@ -24,24 +24,22 @@ import { _t } from './languageHandler';
* Wrap an asynchronous loader function with a react component which shows a
* spinner until the real component loads.
*/
export default createReactClass({
propTypes: {
export default class AsyncWrapper extends React.Component {
static propTypes = {
/** A promise which resolves with the real component
*/
prom: PropTypes.object.isRequired,
},
};
getInitialState: function() {
return {
component: null,
error: null,
};
},
state = {
component: null,
error: null,
};
componentDidMount: function() {
componentDidMount() {
this._unmounted = false;
// XXX: temporary logging to try to diagnose
// https://github.com/vector-im/riot-web/issues/3148
// https://github.com/vector-im/element-web/issues/3148
console.log('Starting load of AsyncWrapper for modal');
this.props.prom.then((result) => {
if (this._unmounted) {
@ -56,17 +54,17 @@ export default createReactClass({
console.warn('AsyncWrapper promise failed', e);
this.setState({error: e});
});
},
}
componentWillUnmount: function() {
componentWillUnmount() {
this._unmounted = true;
},
}
_onWrapperCancelClick: function() {
_onWrapperCancelClick = () => {
this.props.onFinished(false);
},
};
render: function() {
render() {
if (this.state.component) {
const Component = this.state.component;
return <Component {...this.props} />;
@ -87,6 +85,6 @@ export default createReactClass({
const Spinner = sdk.getComponent("elements.Spinner");
return <Spinner />;
}
},
});
}
}

View File

@ -156,6 +156,14 @@ export default abstract class BasePlatform {
loudNotification(ev: Event, room: Object) {
}
clearNotification(notif: Notification) {
// Some browsers don't support this, e.g Safari on iOS
// https://developer.mozilla.org/en-US/docs/Web/API/Notification/close
if (notif.close) {
notif.close();
}
}
/**
* Returns a promise that resolves to a string representing the current version of the application.
*/

View File

@ -90,7 +90,7 @@ function play(audioId) {
// This is usually because the user hasn't interacted with the document,
// or chrome doesn't think so and is denying the request. Not sure what
// we can really do here...
// https://github.com/vector-im/riot-web/issues/7657
// https://github.com/vector-im/element-web/issues/7657
console.log("Unable to play audio clip", e);
}
};
@ -474,15 +474,15 @@ const callHandler = {
/**
* The conference handler is a module that deals with implementation-specific
* multi-party calling implementations. Riot passes in its own which creates
* multi-party calling implementations. Element passes in its own which creates
* a one-to-one call with a freeswitch conference bridge. As of July 2018,
* the de-facto way of conference calling is a Jitsi widget, so this is
* deprecated. It reamins here for two reasons:
* 1. So Riot still supports joining existing freeswitch conference calls
* 1. So Element still supports joining existing freeswitch conference calls
* (but doesn't support creating them). After a transition period, we can
* remove support for joining them too.
* 2. To hide the one-to-one rooms that old-style conferencing creates. This
* is much harder to remove: probably either we make Riot leave & forget these
* is much harder to remove: probably either we make Element leave & forget these
* rooms after we remove support for joining freeswitch conferences, or we
* accept that random rooms with cryptic users will suddently appear for
* anyone who's ever used conference calling, or we are stuck with this

View File

@ -70,6 +70,7 @@ interface IContent {
interface IThumbnail {
info: {
// eslint-disable-next-line camelcase
thumbnail_info: {
w: number;
h: number;
@ -104,7 +105,12 @@ interface IAbortablePromise<T> extends Promise<T> {
* @return {Promise} A promise that resolves with an object with an info key
* and a thumbnail key.
*/
function createThumbnail(element: ThumbnailableElement, inputWidth: number, inputHeight: number, mimeType: string): Promise<IThumbnail> {
function createThumbnail(
element: ThumbnailableElement,
inputWidth: number,
inputHeight: number,
mimeType: string,
): Promise<IThumbnail> {
return new Promise((resolve) => {
let targetWidth = inputWidth;
let targetHeight = inputHeight;
@ -437,11 +443,13 @@ export default class ContentMessages {
for (let i = 0; i < okFiles.length; ++i) {
const file = okFiles[i];
if (!uploadAll) {
const {finished} = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation', '', UploadConfirmDialog, {
file,
currentIndex: i,
totalFiles: okFiles.length,
});
const {finished} = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation',
'', UploadConfirmDialog, {
file,
currentIndex: i,
totalFiles: okFiles.length,
},
);
const [shouldContinue, shouldUploadAll] = await finished;
if (!shouldContinue) break;
if (shouldUploadAll) {

View File

@ -21,6 +21,7 @@ import { deriveKey } from 'matrix-js-sdk/src/crypto/key_passphrase';
import { decodeRecoveryKey } from 'matrix-js-sdk/src/crypto/recoverykey';
import { _t } from './languageHandler';
import {encodeBase64} from "matrix-js-sdk/src/crypto/olmlib";
import { isSecureBackupRequired } from './utils/WellKnownUtils';
// This stores the secret storage private keys in memory for the JS SDK. This is
// only meant to act as a cache to avoid prompting the user multiple times
@ -34,6 +35,17 @@ function isCachingAllowed() {
return secretStorageBeingAccessed;
}
/**
* This can be used by other components to check if secret storage access is in
* progress, so that we can e.g. avoid intermittently showing toasts during
* secret storage setup.
*
* @returns {bool}
*/
export function isSecretStorageBeingAccessed() {
return secretStorageBeingAccessed;
}
export class AccessCancelledError extends Error {
constructor() {
super("Secret storage access canceled");
@ -57,19 +69,19 @@ async function getSecretStorageKey({ keys: keyInfos }, ssssItemName) {
if (keyInfoEntries.length > 1) {
throw new Error("Multiple storage key requests not implemented");
}
const [name, info] = keyInfoEntries[0];
const [keyId, keyInfo] = keyInfoEntries[0];
// Check the in-memory cache
if (isCachingAllowed() && secretStorageKeys[name]) {
return [name, secretStorageKeys[name]];
if (isCachingAllowed() && secretStorageKeys[keyId]) {
return [keyId, secretStorageKeys[keyId]];
}
const inputToKey = async ({ passphrase, recoveryKey }) => {
if (passphrase) {
return deriveKey(
passphrase,
info.passphrase.salt,
info.passphrase.iterations,
keyInfo.passphrase.salt,
keyInfo.passphrase.iterations,
);
} else {
return decodeRecoveryKey(recoveryKey);
@ -81,10 +93,10 @@ async function getSecretStorageKey({ keys: keyInfos }, ssssItemName) {
AccessSecretStorageDialog,
/* props= */
{
keyInfo: info,
keyInfo,
checkPrivateKey: async (input) => {
const key = await inputToKey(input);
return await MatrixClientPeg.get().checkSecretStorageKey(key, info);
return await MatrixClientPeg.get().checkSecretStorageKey(key, keyInfo);
},
},
/* className= */ null,
@ -106,11 +118,15 @@ async function getSecretStorageKey({ keys: keyInfos }, ssssItemName) {
const key = await inputToKey(input);
// Save to cache to avoid future prompts in the current session
if (isCachingAllowed()) {
secretStorageKeys[name] = key;
}
cacheSecretStorageKey(keyId, key);
return [name, key];
return [keyId, key];
}
function cacheSecretStorageKey(keyId, key) {
if (isCachingAllowed()) {
secretStorageKeys[keyId] = key;
}
}
const onSecretRequested = async function({
@ -129,27 +145,21 @@ const onSecretRequested = async function({
console.log(`CrossSigningManager: Ignoring request from untrusted device ${deviceId}`);
return;
}
if (name.startsWith("m.cross_signing")) {
if (
name === "m.cross_signing.master" ||
name === "m.cross_signing.self_signing" ||
name === "m.cross_signing.user_signing"
) {
const callbacks = client.getCrossSigningCacheCallbacks();
if (!callbacks.getCrossSigningKeyCache) return;
/* Explicit enumeration here is deliberate never share the master key! */
if (name === "m.cross_signing.self_signing") {
const key = await callbacks.getCrossSigningKeyCache("self_signing");
if (!key) {
console.log(
`self_signing requested by ${deviceId}, but not found in cache`,
);
}
return key && encodeBase64(key);
} else if (name === "m.cross_signing.user_signing") {
const key = await callbacks.getCrossSigningKeyCache("user_signing");
if (!key) {
console.log(
`user_signing requested by ${deviceId}, but not found in cache`,
);
}
return key && encodeBase64(key);
const keyId = name.replace("m.cross_signing.", "");
const key = await callbacks.getCrossSigningKeyCache(keyId);
if (!key) {
console.log(
`${keyId} requested by ${deviceId}, but not found in cache`,
);
}
return key && encodeBase64(key);
} else if (name === "m.megolm_backup.v1") {
const key = await client._crypto.getSessionBackupPrivateKey();
if (!key) {
@ -164,6 +174,7 @@ const onSecretRequested = async function({
export const crossSigningCallbacks = {
getSecretStorageKey,
cacheSecretStorageKey,
onSecretRequested,
};
@ -212,9 +223,20 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
const { finished } = Modal.createTrackedDialogAsync('Create Secret Storage dialog', '',
import("./async-components/views/dialogs/secretstorage/CreateSecretStorageDialog"),
{
force: forceReset,
forceReset,
},
null,
/* priority = */ false,
/* static = */ true,
/* options = */ {
onBeforeClose(reason) {
// If Secure Backup is required, you cannot leave the modal.
if (reason === "backgroundClick") {
return !isSecureBackupRequired();
}
return true;
},
},
null, /* priority = */ false, /* static = */ true,
);
const [confirmed] = await finished;
if (!confirmed) {
@ -222,7 +244,7 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
}
} else {
const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog");
await cli.bootstrapSecretStorage({
await cli.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (makeRequest) => {
const { finished } = Modal.createTrackedDialog(
'Cross-signing keys dialog', '', InteractiveAuthDialog,
@ -237,7 +259,9 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
throw new Error("Cross-signing key upload auth canceled");
}
},
getBackupPassphrase: promptForBackupPassphrase,
});
await cli.bootstrapSecretStorage({
getKeyBackupPassphrase: promptForBackupPassphrase,
});
}

View File

@ -15,6 +15,7 @@ limitations under the License.
*/
import {MatrixClientPeg} from './MatrixClientPeg';
import dis from "./dispatcher/dispatcher";
import {
hideToast as hideBulkUnverifiedSessionsToast,
showToast as showBulkUnverifiedSessionsToast,
@ -28,11 +29,16 @@ import {
hideToast as hideUnverifiedSessionsToast,
showToast as showUnverifiedSessionsToast,
} from "./toasts/UnverifiedSessionToast";
import {privateShouldBeEncrypted} from "./createRoom";
import { privateShouldBeEncrypted } from "./createRoom";
import { isSecretStorageBeingAccessed, accessSecretStorage } from "./CrossSigningManager";
import { isSecureBackupRequired } from './utils/WellKnownUtils';
import { isLoggedIn } from './components/structures/MatrixChat';
const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000;
export default class DeviceListener {
private dispatcherRef: string;
// device IDs for which the user has dismissed the verify toast ('Later')
private dismissed = new Set<string>();
// has the user dismissed any of the various nag toasts to setup encryption on this device?
@ -60,6 +66,7 @@ export default class DeviceListener {
MatrixClientPeg.get().on('crossSigning.keysChanged', this._onCrossSingingKeysChanged);
MatrixClientPeg.get().on('accountData', this._onAccountData);
MatrixClientPeg.get().on('sync', this._onSync);
this.dispatcherRef = dis.register(this._onAction);
this._recheck();
}
@ -73,6 +80,10 @@ export default class DeviceListener {
MatrixClientPeg.get().removeListener('accountData', this._onAccountData);
MatrixClientPeg.get().removeListener('sync', this._onSync);
}
if (this.dispatcherRef) {
dis.unregister(this.dispatcherRef);
this.dispatcherRef = null;
}
this.dismissed.clear();
this.dismissedThisDeviceToast = false;
this.keyBackupInfo = null;
@ -158,6 +169,11 @@ export default class DeviceListener {
if (state === 'PREPARED' && prevState === null) this._recheck();
};
_onAction = ({ action }) => {
if (action !== "on_logged_in") return;
this._recheck();
};
// The server doesn't tell us when key backup is set up, so we poll
// & cache the result
async _getKeyBackupInfo() {
@ -170,6 +186,9 @@ export default class DeviceListener {
}
private shouldShowSetupEncryptionToast() {
// If we're in the middle of a secret storage operation, we're likely
// modifying the state involved here, so don't add new toasts to setup.
if (isSecretStorageBeingAccessed()) return false;
// In a default configuration, show the toasts. If the well-known config causes e2ee default to be false
// then do not show the toasts until user is in at least one encrypted room.
if (privateShouldBeEncrypted()) return true;
@ -188,16 +207,23 @@ export default class DeviceListener {
// (we add a listener on sync to do once check after the initial sync is done)
if (!cli.isInitialSyncComplete()) return;
// JRS: This will change again in the next PR which moves secret storage
// later in the process.
const crossSigningReady = await cli.isCrossSigningReady();
const secretStorageReady = await cli.isSecretStorageReady();
const allSystemsReady = crossSigningReady && secretStorageReady;
if (this.dismissedThisDeviceToast || crossSigningReady) {
if (this.dismissedThisDeviceToast || allSystemsReady) {
hideSetupEncryptionToast();
} else if (this.shouldShowSetupEncryptionToast()) {
// make sure our keys are finished downloading
await cli.downloadKeys([cli.getUserId()]);
// cross signing isn't enabled - nag to enable it
// There are 3 different toasts for:
if (cli.getStoredCrossSigningForUser(cli.getUserId())) {
if (
!cli.getCrossSigningId() &&
cli.getStoredCrossSigningForUser(cli.getUserId())
) {
// Cross-signing on account but this device doesn't trust the master key (verify this session)
showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION);
} else {
@ -207,7 +233,15 @@ export default class DeviceListener {
showSetupEncryptionToast(SetupKind.UPGRADE_ENCRYPTION);
} else {
// No cross-signing or key backup on account (set up encryption)
showSetupEncryptionToast(SetupKind.SET_UP_ENCRYPTION);
await cli.waitForClientWellKnown();
if (isSecureBackupRequired() && isLoggedIn()) {
// If we're meant to set up, and Secure Backup is required,
// trigger the flow directly without a toast once logged in.
hideSetupEncryptionToast();
accessSecretStorage();
} else {
showSetupEncryptionToast(SetupKind.SET_UP_ENCRYPTION);
}
}
}
}

View File

@ -197,7 +197,7 @@ export default class FromWidgetPostMessageApi {
const integId = (data && data.integId) ? data.integId : null;
// TODO: Open the right integration manager for the widget
if (SettingsStore.isFeatureEnabled("feature_many_integration_managers")) {
if (SettingsStore.getValue("feature_many_integration_managers")) {
IntegrationManagers.sharedInstance().openAll(
MatrixClientPeg.get().getRoom(RoomViewStore.getRoomId()),
`type_${integType}`,

View File

@ -339,33 +339,9 @@ class HtmlHighlighter extends BaseHighlighter<string> {
}
}
class TextHighlighter extends BaseHighlighter<React.ReactNode> {
private key = 0;
/* create a <span> node to hold the given content
*
* snippet: content of the span
* highlight: true to highlight as a search match
*
* returns a React node
*/
protected processSnippet(snippet: string, highlight: boolean): React.ReactNode {
const key = this.key++;
let node = <span key={key} className={highlight ? this.highlightClass : null}>
{ snippet }
</span>;
if (highlight && this.highlightLink) {
node = <a key={key} href={this.highlightLink}>{ node }</a>;
}
return node;
}
}
interface IContent {
format?: string;
// eslint-disable-next-line camelcase
formatted_body?: string;
body: string;
}
@ -421,7 +397,7 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts
}
let formattedBody = typeof content.formatted_body === 'string' ? content.formatted_body : null;
const plainBody = typeof content.body === 'string' ? content.body : null;
const plainBody = typeof content.body === 'string' ? content.body : "";
if (opts.stripReplyFallback && formattedBody) formattedBody = ReplyThread.stripHTMLReply(formattedBody);
strippedBody = opts.stripReplyFallback ? ReplyThread.stripPlainReply(plainBody) : plainBody;
@ -474,8 +450,13 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts
});
return isDisplayedWithHtml ?
<span key="body" ref={opts.ref} className={className} dangerouslySetInnerHTML={{ __html: safeBody }} dir="auto" /> :
<span key="body" ref={opts.ref} className={className} dir="auto">{ strippedBody }</span>;
<span
key="body"
ref={opts.ref}
className={className}
dangerouslySetInnerHTML={{ __html: safeBody }}
dir="auto"
/> : <span key="body" ref={opts.ref} className={className} dir="auto">{ strippedBody }</span>;
}
/**

View File

@ -177,7 +177,7 @@ export default class IdentityAuthClient {
// appropriately. We already clear storage on sign out, but we'll need
// additional clearing when changing ISes in settings as part of future
// privacy work.
// See also https://github.com/vector-im/riot-web/issues/10455.
// See also https://github.com/vector-im/element-web/issues/10455.
}
async registerForToken(check=true) {

View File

@ -40,7 +40,6 @@ import ToastStore from "./stores/ToastStore";
import {IntegrationManagers} from "./integrations/IntegrationManagers";
import {Mjolnir} from "./mjolnir/Mjolnir";
import DeviceListener from "./DeviceListener";
import RebrandListener from "./RebrandListener";
import {Jitsi} from "./widgets/Jitsi";
import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "./BasePlatform";
@ -647,8 +646,6 @@ async function startMatrixClient(startSyncing=true) {
// Now that we have a MatrixClientPeg, update the Jitsi info
await Jitsi.getInstance().start();
RebrandListener.sharedInstance().start();
// dispatch that we finished starting up to wire up any other bits
// of the matrix client that cannot be set prior to starting up.
dis.dispatch({action: 'client_started'});
@ -710,7 +707,6 @@ export function stopMatrixClient(unsetClient=true) {
IntegrationManagers.sharedInstance().stopWatching();
Mjolnir.sharedInstance().stop();
DeviceListener.sharedInstance().stop();
RebrandListener.sharedInstance().stop();
if (DMRoomMap.shared()) DMRoomMap.shared().stop();
EventIndexPeg.stop();
const cli = MatrixClientPeg.get();

View File

@ -15,7 +15,7 @@ limitations under the License.
*/
import commonmark from 'commonmark';
import escape from 'lodash/escape';
import {escape} from "lodash";
const ALLOWED_HTML_TAGS = ['sub', 'sup', 'del', 'u'];
@ -99,7 +99,7 @@ export default class Markdown {
// puts softbreaks in for multiple lines in a blockquote,
// so if these are just newline characters then the
// block quote ends up all on one line
// (https://github.com/vector-im/riot-web/issues/3154)
// (https://github.com/vector-im/element-web/issues/3154)
softbreak: '<br />',
});
@ -166,7 +166,7 @@ export default class Markdown {
* Render the markdown message to plain text. That is, essentially
* just remove any backslashes escaping what would otherwise be
* markdown syntax
* (to fix https://github.com/vector-im/riot-web/issues/2870).
* (to fix https://github.com/vector-im/element-web/issues/2870).
*
* N.B. this does **NOT** render arbitrary MD to plain text - only MD
* which has no formatting. Otherwise it emits HTML(!).

View File

@ -151,7 +151,7 @@ export class ModalManager {
prom: Promise<React.ComponentType>,
props?: IProps<T>,
className?: string,
options?: IOptions<T>
options?: IOptions<T>,
) {
const modal: IModal<T> = {
onFinished: props ? props.onFinished : null,
@ -182,7 +182,7 @@ export class ModalManager {
private getCloseFn<T extends any[]>(
modal: IModal<T>,
props: IProps<T>
props: IProps<T>,
): [IHandle<T>["close"], IHandle<T>["finished"]] {
const deferred = defer<T>();
return [async (...args: T) => {
@ -264,7 +264,7 @@ export class ModalManager {
className?: string,
isPriorityModal = false,
isStaticModal = false,
options: IOptions<T> = {}
options: IOptions<T> = {},
): IHandle<T> {
const {modal, closeDialog, onFinishedProm} = this.buildModal<T>(prom, props, className, options);
if (isPriorityModal) {
@ -287,7 +287,7 @@ export class ModalManager {
private appendDialogAsync<T extends any[]>(
prom: Promise<React.ComponentType>,
props?: IProps<T>,
className?: string
className?: string,
): IHandle<T> {
const {modal, closeDialog, onFinishedProm} = this.buildModal<T>(prom, props, className, {});
@ -319,7 +319,7 @@ export class ModalManager {
private reRender() {
if (this.modals.length === 0 && !this.priorityModal && !this.staticModal) {
// If there is no modal to render, make all of Riot available
// If there is no modal to render, make all of Element available
// to screen reader users again
dis.dispatch({
action: 'aria_unhide_main_app',

View File

@ -17,6 +17,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClientPeg } from './MatrixClientPeg';
import SdkConfig from './SdkConfig';
import PlatformPeg from './PlatformPeg';
@ -28,9 +31,7 @@ import * as sdk from './index';
import { _t } from './languageHandler';
import Modal from './Modal';
import SettingsStore from "./settings/SettingsStore";
import {
hideToast as hideNotificationsToast,
} from "./toasts/DesktopNotificationsToast";
import { hideToast as hideNotificationsToast } from "./toasts/DesktopNotificationsToast";
import {SettingLevel} from "./settings/SettingLevel";
/*
@ -55,7 +56,7 @@ const typehandlers = {
},
};
const Notifier = {
export const Notifier = {
notifsByRoom: {},
// A list of event IDs that we've received but need to wait until
@ -63,14 +64,14 @@ const Notifier = {
// or not
pendingEncryptedEventIds: [],
notificationMessageForEvent: function(ev) {
notificationMessageForEvent: function(ev: MatrixEvent) {
if (typehandlers.hasOwnProperty(ev.getContent().msgtype)) {
return typehandlers[ev.getContent().msgtype](ev);
}
return TextForEvent.textForEvent(ev);
},
_displayPopupNotification: function(ev, room) {
_displayPopupNotification: function(ev: MatrixEvent, room: Room) {
const plaf = PlatformPeg.get();
if (!plaf) {
return;
@ -125,7 +126,7 @@ const Notifier = {
}
},
getSoundForRoom: function(roomId) {
getSoundForRoom: function(roomId: string) {
// We do no caching here because the SDK caches setting
// and the browser will cache the sound.
const content = SettingsStore.getValue("notificationSound", roomId);
@ -153,12 +154,13 @@ const Notifier = {
};
},
_playAudioNotification: async function(ev, room) {
_playAudioNotification: async function(ev: MatrixEvent, room: Room) {
const sound = this.getSoundForRoom(room.roomId);
console.log(`Got sound ${sound && sound.name || "default"} for ${room.roomId}`);
try {
const selector = document.querySelector(sound ? `audio[src='${sound.url}']` : "#messageAudio");
const selector =
document.querySelector<HTMLAudioElement>(sound ? `audio[src='${sound.url}']` : "#messageAudio");
let audioElement = selector;
if (!selector) {
if (!sound) {
@ -207,7 +209,7 @@ const Notifier = {
return plaf && plaf.supportsNotifications();
},
setEnabled: function(enable, callback) {
setEnabled: function(enable: boolean, callback?: () => void) {
const plaf = PlatformPeg.get();
if (!plaf) return;
@ -277,10 +279,11 @@ const Notifier = {
},
isAudioEnabled: function() {
return this.isEnabled() && SettingsStore.getValue("audioNotificationsEnabled");
// We don't route Audio via the HTML Notifications API so it is possible regardless of other things
return SettingsStore.getValue("audioNotificationsEnabled");
},
setToolbarHidden: function(hidden, persistent = true) {
setToolbarHidden: function(hidden: boolean, persistent = true) {
this.toolbarHidden = hidden;
Analytics.trackEvent('Notifier', 'Set Toolbar Hidden', hidden);
@ -289,7 +292,7 @@ const Notifier = {
// update the info to localStorage for persistent settings
if (persistent && global.localStorage) {
global.localStorage.setItem("notifications_hidden", hidden);
global.localStorage.setItem("notifications_hidden", String(hidden));
}
},
@ -312,7 +315,7 @@ const Notifier = {
return this.toolbarHidden;
},
onSyncStateChange: function(state) {
onSyncStateChange: function(state: string) {
if (state === "SYNCING") {
this.isSyncing = true;
} else if (state === "STOPPED" || state === "ERROR") {
@ -320,7 +323,7 @@ const Notifier = {
}
},
onEvent: function(ev) {
onEvent: function(ev: MatrixEvent) {
if (!this.isSyncing) return; // don't alert for any messages initially
if (ev.sender && ev.sender.userId === MatrixClientPeg.get().credentials.userId) return;
@ -338,7 +341,7 @@ const Notifier = {
this._evaluateEvent(ev);
},
onEventDecrypted: function(ev) {
onEventDecrypted: function(ev: MatrixEvent) {
// 'decrypted' means the decryption process has finished: it may have failed,
// in which case it might decrypt soon if the keys arrive
if (ev.isDecryptionFailure()) return;
@ -350,7 +353,7 @@ const Notifier = {
this._evaluateEvent(ev);
},
onRoomReceipt: function(ev, room) {
onRoomReceipt: function(ev: MatrixEvent, room: Room) {
if (room.getUnreadNotificationCount() === 0) {
// ideally we would clear each notification when it was read,
// but we have no way, given a read receipt, to know whether
@ -383,8 +386,8 @@ const Notifier = {
},
};
if (!global.mxNotifier) {
global.mxNotifier = Notifier;
if (!window.mxNotifier) {
window.mxNotifier = Notifier;
}
export default global.mxNotifier;
export default window.mxNotifier;

View File

@ -1,184 +0,0 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import SdkConfig from "./SdkConfig";
import ToastStore from "./stores/ToastStore";
import GenericToast from "./components/views/toasts/GenericToast";
import RebrandDialog from "./components/views/dialogs/RebrandDialog";
import { RebrandDialogKind } from "./components/views/dialogs/RebrandDialog";
import Modal from './Modal';
import { _t } from './languageHandler';
const TOAST_KEY = 'rebrand';
const NAG_INTERVAL = 24 * 60 * 60 * 1000;
function getRedirectUrl(url): string {
const redirectUrl = new URL(url);
redirectUrl.hash = '';
if (SdkConfig.get()['redirectToNewBrandUrl']) {
const newUrl = new URL(SdkConfig.get()['redirectToNewBrandUrl']);
if (url.hostname !== newUrl.hostname || url.pathname !== newUrl.pathname) {
redirectUrl.hostname = newUrl.hostname;
redirectUrl.pathname = newUrl.pathname;
return redirectUrl.toString();
}
return null;
} else if (url.hostname === 'riot.im') {
if (url.pathname.startsWith('/app')) {
redirectUrl.hostname = 'app.element.io';
redirectUrl.pathname = '/';
} else if (url.pathname.startsWith('/staging')) {
redirectUrl.hostname = 'staging.element.io';
redirectUrl.pathname = '/';
} else if (url.pathname.startsWith('/develop')) {
redirectUrl.hostname = 'develop.element.io';
redirectUrl.pathname = '/';
}
return redirectUrl.href;
} else if (url.hostname.endsWith('.riot.im')) {
redirectUrl.hostname = url.hostname.substr(0, url.hostname.length - '.riot.im'.length) + '.element.io';
return redirectUrl.href;
} else {
return null;
}
}
/**
* Shows toasts informing the user that the name of the app has changed and,
* potentially, that they should head to a different URL and log in there
*/
export default class RebrandListener {
private _reshowTimer?: number;
private nagAgainAt?: number = null;
static sharedInstance() {
if (!window.mxRebrandListener) window.mxRebrandListener = new RebrandListener();
return window.mxRebrandListener;
}
constructor() {
this._reshowTimer = null;
}
start() {
this.recheck();
}
stop() {
if (this._reshowTimer) {
clearTimeout(this._reshowTimer);
this._reshowTimer = null;
}
}
onNagToastLearnMore = async () => {
const [doneClicked] = await Modal.createDialog(RebrandDialog, {
kind: RebrandDialogKind.NAG,
targetUrl: getRedirectUrl(window.location),
}).finished;
if (doneClicked) {
// open in new tab: they should come back here & log out
window.open(getRedirectUrl(window.location), '_blank');
}
// whatever the user clicks, we go away & nag again after however long:
// If they went to the new URL, we want to nag them to log out if they
// come back to this tab, and if they clicked, 'remind me later' we want
// to, well, remind them later.
this.nagAgainAt = Date.now() + NAG_INTERVAL;
this.recheck();
};
onOneTimeToastLearnMore = async () => {
const [doneClicked] = await Modal.createDialog(RebrandDialog, {
kind: RebrandDialogKind.ONE_TIME,
}).finished;
if (doneClicked) {
localStorage.setItem('mx_rename_dialog_dismissed', 'true');
this.recheck();
}
};
onOneTimeToastDismiss = async () => {
localStorage.setItem('mx_rename_dialog_dismissed', 'true');
this.recheck();
};
onNagTimerFired = () => {
this._reshowTimer = null;
this.nagAgainAt = null;
this.recheck();
};
private async recheck() {
// There are two types of toast/dialog we show: a 'one time' informing the user that
// the app is now called a different thing but no action is required from them (they
// may need to look for a different name name/icon to launch the app but don't need to
// log in again) and a nag toast where they need to log in to the app on a different domain.
let nagToast = false;
let oneTimeToast = false;
if (getRedirectUrl(window.location)) {
if (!this.nagAgainAt) {
// if we have redirectUrl, show the nag toast
nagToast = true;
}
} else {
// otherwise we show the 'one time' toast / dialog
const renameDialogDismissed = localStorage.getItem('mx_rename_dialog_dismissed');
if (renameDialogDismissed !== 'true') {
oneTimeToast = true;
}
}
if (nagToast || oneTimeToast) {
let description;
let rejectLabel = null;
let onReject = null;
if (nagToast) {
description = _t("Use your account to sign in to the latest version");
} else {
description = _t("Were excited to announce Riot is now Element");
rejectLabel = _t("Dismiss");
onReject = this.onOneTimeToastDismiss;
}
ToastStore.sharedInstance().addOrReplaceToast({
key: TOAST_KEY,
title: _t("Riot is now Element!"),
icon: 'element_logo',
props: {
description,
acceptLabel: _t("Learn More"),
onAccept: nagToast ? this.onNagToastLearnMore : this.onOneTimeToastLearnMore,
rejectLabel,
onReject,
},
component: GenericToast,
priority: 20,
});
} else {
ToastStore.sharedInstance().dismissToast(TOAST_KEY);
}
if (!this._reshowTimer && this.nagAgainAt) {
// XXX: Our build system picks up NodeJS bindings when we need browser bindings.
this._reshowTimer = setTimeout(this.onNagTimerFired, (this.nagAgainAt - Date.now()) + 100) as any as number;
}
}
}

View File

@ -52,7 +52,7 @@ export async function startAnyRegistrationFlow(options) {
// caution though.
// XXX: ILAG is disabled for now,
// see https://github.com/vector-im/riot-web/issues/8222
// see https://github.com/vector-im/element-web/issues/8222
// const flows = await _getRegistrationFlows();
// const hasIlagFlow = flows.some((flow) => {

View File

@ -45,7 +45,7 @@ export default class Resend {
});
}, function(err) {
// XXX: temporary logging to try to diagnose
// https://github.com/vector-im/riot-web/issues/3148
// https://github.com/vector-im/element-web/issues/3148
console.log('Resend got send failure: ' + err.name + '(' + err + ')');
dis.dispatch({

View File

@ -23,6 +23,8 @@ import Modal from './Modal';
import * as sdk from './';
import { _t } from './languageHandler';
import {KIND_DM, KIND_INVITE} from "./components/views/dialogs/InviteDialog";
import CommunityPrototypeInviteDialog from "./components/views/dialogs/CommunityPrototypeInviteDialog";
import {CommunityPrototypeStore} from "./stores/CommunityPrototypeStore";
/**
* Invites multiple addresses to a room
@ -56,6 +58,23 @@ export function showRoomInviteDialog(roomId) {
);
}
export function showCommunityRoomInviteDialog(roomId, communityName) {
Modal.createTrackedDialog(
'Invite Users to Community', '', CommunityPrototypeInviteDialog, {communityName, roomId},
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
);
}
export function showCommunityInviteDialog(communityId) {
const chat = CommunityPrototypeStore.instance.getGeneralChat(communityId);
if (chat) {
const name = CommunityPrototypeStore.instance.getCommunityName(communityId);
showCommunityRoomInviteDialog(chat.roomId, name);
} else {
throw new Error("Failed to locate appropriate room to start an invite in");
}
}
/**
* Checks if the given MatrixEvent is a valid 3rd party user invite.
* @param {MatrixEvent} event The event to check
@ -77,7 +96,7 @@ export function isValid3pidInvite(event) {
export function inviteUsersToRoom(roomId, userIds) {
return inviteMultipleToRoom(roomId, userIds).then((result) => {
const room = MatrixClientPeg.get().getRoom(roomId);
return _showAnyInviteErrors(result.states, room, result.inviter);
showAnyInviteErrors(result.states, room, result.inviter);
}).catch((err) => {
console.error(err.stack);
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
@ -88,7 +107,7 @@ export function inviteUsersToRoom(roomId, userIds) {
});
}
function _showAnyInviteErrors(addrs, room, inviter) {
export function showAnyInviteErrors(addrs, room, inviter) {
// Show user any errors
const failedUsers = Object.keys(addrs).filter(a => addrs[a] === 'error');
if (failedUsers.length === 1 && inviter.fatal) {
@ -100,6 +119,7 @@ function _showAnyInviteErrors(addrs, room, inviter) {
title: _t("Failed to invite users to the room:", {roomName: room.name}),
description: inviter.getErrorText(failedUsers[0]),
});
return false;
} else {
const errorList = [];
for (const addr of failedUsers) {
@ -118,8 +138,9 @@ function _showAnyInviteErrors(addrs, room, inviter) {
title: _t("Failed to invite the following users to the %(roomName)s room:", {roomName: room.name}),
description,
});
return false;
}
}
return addrs;
return true;
}

View File

@ -174,7 +174,7 @@ Request:
Response:
[
{
// TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
type: "im.vector.modular.widgets",
state_key: "wid1",
content: {
@ -193,7 +193,7 @@ Example:
room_id: "!foo:bar",
response: [
{
// TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
type: "im.vector.modular.widgets",
state_key: "wid1",
content: {

View File

@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import _clamp from 'lodash/clamp';
import {clamp} from "lodash";
export default class SendHistoryManager {
history: Array<HistoryItem> = [];
@ -54,7 +54,7 @@ export default class SendHistoryManager {
}
getItem(offset: number): ?HistoryItem {
this.currentIndex = _clamp(this.currentIndex + offset, 0, this.history.length - 1);
this.currentIndex = clamp(this.currentIndex + offset, 0, this.history.length - 1);
return this.history[this.currentIndex];
}
}

View File

@ -43,7 +43,7 @@ import SdkConfig from "./SdkConfig";
import { ensureDMExists } from "./createRoom";
import { ViewUserPayload } from "./dispatcher/payloads/ViewUserPayload";
import { Action } from "./dispatcher/actions";
import { EffectiveMembership, getEffectiveMembership } from "./utils/membership";
import { EffectiveMembership, getEffectiveMembership, leaveRoomBehaviour } from "./utils/membership";
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
interface HTMLInputEvent extends Event {
@ -479,7 +479,7 @@ export const Commands = [
const parsedUrl = new URL(params[0]);
const hostname = parsedUrl.host || parsedUrl.hostname; // takes first non-falsey value
// if we're using a Riot permalink handler, this will catch it before we get much further.
// if we're using a Element permalink handler, this will catch it before we get much further.
// see below where we make assumptions about parsing the URL.
if (isPermalinkHost(hostname)) {
isPermalink = true;
@ -601,11 +601,7 @@ export const Commands = [
}
if (!targetRoomId) targetRoomId = roomId;
return success(
cli.leaveRoomChain(targetRoomId).then(function() {
dis.dispatch({action: 'view_next_room'});
}),
);
return success(leaveRoomBehaviour(targetRoomId));
},
category: CommandCategories.actions,
}),
@ -733,7 +729,7 @@ export const Commands = [
const cli = MatrixClientPeg.get();
const room = cli.getRoom(roomId);
if (!room) return reject(_t("Command failed"));
const member = room.getMember(args);
const member = room.getMember(userId);
if (!member || getEffectiveMembership(member.membership) === EffectiveMembership.Leave) {
return reject(_t("Could not find user in room"));
}
@ -864,12 +860,12 @@ export const Commands = [
_t('WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session' +
' %(deviceId)s is "%(fprint)s" which does not match the provided key ' +
'"%(fingerprint)s". This could mean your communications are being intercepted!',
{
fprint,
userId,
deviceId,
fingerprint,
}));
{
fprint,
userId,
deviceId,
fingerprint,
}));
}
await cli.setDeviceVerified(userId, deviceId, true);
@ -883,7 +879,7 @@ export const Commands = [
{
_t('The signing key you provided matches the signing key you received ' +
'from %(userId)s\'s session %(deviceId)s. Session marked as verified.',
{userId, deviceId})
{userId, deviceId})
}
</p>
</div>,

View File

@ -345,7 +345,7 @@ function textForCallHangupEvent(event) {
} else if (eventContent.reason === "invite_timeout") {
reason = _t('(no answer)');
} else if (eventContent.reason === "user hangup") {
// workaround for https://github.com/vector-im/riot-web/issues/5178
// workaround for https://github.com/vector-im/element-web/issues/5178
// it seems Android randomly sets a reason of "user hangup" which is
// interpreted as an error code :(
// https://github.com/vector-im/riot-android/issues/2623
@ -603,7 +603,7 @@ const stateHandlers = {
'm.room.guest_access': textForGuestAccessEvent,
'm.room.related_groups': textForRelatedGroupsEvent,
// TODO: Enable support for m.widget event type (https://github.com/vector-im/riot-web/issues/13111)
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
'im.vector.modular.widgets': textForWidgetEvent,
};

View File

@ -327,7 +327,7 @@ class Tinter {
// Vector Green as its primary color?
// --richvdh
// Yes, tinting assumes that you are using the Riot skin for now.
// Yes, tinting assumes that you are using the Element skin for now.
// The right solution will be to move the CSS over to react-sdk.
// And yes, the default assets for the base skin might as well use
// Vector Green as any other colour.

View File

@ -52,10 +52,10 @@ export function doesRoomHaveUnreadMessages(room) {
// as we don't send RRs for our own messages, make sure we special case that
// if *we* sent the last message into the room, we consider it not unread!
// Should fix: https://github.com/vector-im/riot-web/issues/3263
// https://github.com/vector-im/riot-web/issues/2427
// Should fix: https://github.com/vector-im/element-web/issues/3263
// https://github.com/vector-im/element-web/issues/2427
// ...and possibly some of the others at
// https://github.com/vector-im/riot-web/issues/3363
// https://github.com/vector-im/element-web/issues/3363
if (room.timeline.length &&
room.timeline[room.timeline.length - 1].sender &&
room.timeline[room.timeline.length - 1].sender.userId === myUserId) {

View File

@ -19,13 +19,13 @@ import {createNewMatrixCall as jsCreateNewMatrixCall, Room} from "matrix-js-sdk"
import CallHandler from './CallHandler';
import {MatrixClientPeg} from "./MatrixClientPeg";
// FIXME: this is Riot (Vector) specific code, but will be removed shortly when
// we switch over to jitsi entirely for video conferencing.
// FIXME: this is Element specific code, but will be removed shortly when we
// switch over to Jitsi entirely for video conferencing.
// FIXME: This currently forces Vector to try to hit the matrix.org AS for conferencing.
// This is bad because it prevents people running their own ASes from being used.
// This isn't permanent and will be customisable in the future: see the proposal
// at docs/conferencing.md for more info.
// FIXME: This currently forces Element to try to hit the matrix.org AS for
// conferencing. This is bad because it prevents people running their own ASes
// from being used. This isn't permanent and will be customisable in the future:
// see the proposal at docs/conferencing.md for more info.
const USER_PREFIX = "fs_";
const DOMAIN = "matrix.org";

View File

@ -76,7 +76,7 @@ export default class WidgetMessaging {
console.error(err._error);
}
// Potential XSS attack if 'msg' is not appropriately sanitized,
// as it is untrusted input by our parent window (which we assume is Riot).
// as it is untrusted input by our parent window (which we assume is Element).
// We can't aggressively sanitize [A-z0-9] since it might be a translation.
throw new Error(msg);
}

Some files were not shown because too many files have changed in this diff Show More