Merge branch 'develop' into matthew/homepages
Conflicts: src/component-index.js src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomPreviewBar.scss
2
.eslintignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
src/vector/modernizr.js
|
||||||
|
src/component-index.js
|
3
.eslintrc.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ["./node_modules/matrix-react-sdk/.eslintrc.js"],
|
||||||
|
}
|
2
.gitignore
vendored
@ -7,6 +7,8 @@
|
|||||||
/node_modules
|
/node_modules
|
||||||
/packages/
|
/packages/
|
||||||
/webapp
|
/webapp
|
||||||
|
/.npmrc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
electron/dist
|
electron/dist
|
||||||
|
electron/pub
|
||||||
|
@ -3,4 +3,5 @@ node_js:
|
|||||||
- 6 # node v6, to match jenkins
|
- 6 # node v6, to match jenkins
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
|
- (cd node_modules/matrix-js-sdk && npm install)
|
||||||
- (cd node_modules/matrix-react-sdk && npm run build)
|
- (cd node_modules/matrix-react-sdk && npm run build)
|
||||||
|
166
CHANGELOG.md
@ -1,4 +1,168 @@
|
|||||||
hanges in [0.8.4](https://github.com/vector-im/vector-web/releases/tag/v0.8.4) (2016-11-04)
|
Changes in [0.9.6](https://github.com/vector-im/riot-web/releases/tag/v0.9.6) (2017-01-16)
|
||||||
|
==========================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.6-rc.1...v0.9.6)
|
||||||
|
|
||||||
|
* Update to matrix-js-sdk 0.9.6 for video calling fix
|
||||||
|
|
||||||
|
Changes in [0.9.6-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.6-rc.1) (2017-01-13)
|
||||||
|
====================================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.5...v0.9.6-rc.1)
|
||||||
|
|
||||||
|
* Build the js-sdk in the CI script
|
||||||
|
[\#2920](https://github.com/vector-im/riot-web/pull/2920)
|
||||||
|
* Hopefully fix Windows shortcuts
|
||||||
|
[\#2917](https://github.com/vector-im/riot-web/pull/2917)
|
||||||
|
* Update README now the js-sdk has a transpile step
|
||||||
|
[\#2921](https://github.com/vector-im/riot-web/pull/2921)
|
||||||
|
* Use the role for 'toggle dev tools'
|
||||||
|
[\#2915](https://github.com/vector-im/riot-web/pull/2915)
|
||||||
|
* Enable screen sharing easter-egg in desktop app
|
||||||
|
[\#2909](https://github.com/vector-im/riot-web/pull/2909)
|
||||||
|
* make electron send email validation URLs with a nextlink of riot.im
|
||||||
|
[\#2808](https://github.com/vector-im/riot-web/pull/2808)
|
||||||
|
* add Debian Stretch install steps to readme
|
||||||
|
[\#2809](https://github.com/vector-im/riot-web/pull/2809)
|
||||||
|
* Update desktop build instructions fixes #2792
|
||||||
|
[\#2793](https://github.com/vector-im/riot-web/pull/2793)
|
||||||
|
* CSS for the delete threepid button
|
||||||
|
[\#2784](https://github.com/vector-im/riot-web/pull/2784)
|
||||||
|
|
||||||
|
Changes in [0.9.5](https://github.com/vector-im/riot-web/releases/tag/v0.9.5) (2016-12-24)
|
||||||
|
==========================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.4...v0.9.5)
|
||||||
|
|
||||||
|
* make electron send email validation URLs with a nextlink of riot.im rather than file:///
|
||||||
|
* add gnu-tar to debian electron build deps
|
||||||
|
* fix win32 shortcut in start menu
|
||||||
|
|
||||||
|
Changes in [0.9.4](https://github.com/vector-im/riot-web/releases/tag/v0.9.4) (2016-12-22)
|
||||||
|
==========================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.3...v0.9.4)
|
||||||
|
|
||||||
|
* Update to libolm 2.1.0. This should help resolve a problem with browser
|
||||||
|
sessions being logged out ([\#2726](https://github.com/vector-im/riot-web/issues/2726)).
|
||||||
|
|
||||||
|
Changes in [0.9.3](https://github.com/vector-im/riot-web/releases/tag/v0.9.3) (2016-12-22)
|
||||||
|
==========================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.2...v0.9.3)
|
||||||
|
|
||||||
|
* (from matrix-react-sdk) Fix regression where the date separator would be displayed
|
||||||
|
at the wrong time of day.
|
||||||
|
* README.md: fix GFMD for nativefier
|
||||||
|
[\#2755](https://github.com/vector-im/riot-web/pull/2755)
|
||||||
|
|
||||||
|
Changes in [0.9.2](https://github.com/vector-im/riot-web/releases/tag/v0.9.2) (2016-12-16)
|
||||||
|
==========================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.1...v0.9.2)
|
||||||
|
|
||||||
|
* Remove the client side filtering from the room dir
|
||||||
|
[\#2750](https://github.com/vector-im/riot-web/pull/2750)
|
||||||
|
* Configure olm memory size
|
||||||
|
[\#2745](https://github.com/vector-im/riot-web/pull/2745)
|
||||||
|
* Support room dir 3rd party network filtering
|
||||||
|
[\#2747](https://github.com/vector-im/riot-web/pull/2747)
|
||||||
|
|
||||||
|
Changes in [0.9.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.1) (2016-12-09)
|
||||||
|
==========================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.1-rc.2...v0.9.1)
|
||||||
|
|
||||||
|
* Update README to say how to build the desktop app
|
||||||
|
[\#2732](https://github.com/vector-im/riot-web/pull/2732)
|
||||||
|
* Add signing ID in release_config.yaml
|
||||||
|
[\#2731](https://github.com/vector-im/riot-web/pull/2731)
|
||||||
|
* Makeover!
|
||||||
|
[\#2722](https://github.com/vector-im/riot-web/pull/2722)
|
||||||
|
* Fix broken tests
|
||||||
|
[\#2730](https://github.com/vector-im/riot-web/pull/2730)
|
||||||
|
* Make the 'loading' tests work in isolation
|
||||||
|
[\#2727](https://github.com/vector-im/riot-web/pull/2727)
|
||||||
|
* Use a PNG for the icon on non-Windows
|
||||||
|
[\#2708](https://github.com/vector-im/riot-web/pull/2708)
|
||||||
|
* Add missing brackets to call to toUpperCase
|
||||||
|
[\#2703](https://github.com/vector-im/riot-web/pull/2703)
|
||||||
|
|
||||||
|
Changes in [0.9.1-rc.2](https://github.com/vector-im/riot-web/releases/tag/v0.9.1-rc.2) (2016-12-06)
|
||||||
|
====================================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.1-rc.1...v0.9.1-rc.2)
|
||||||
|
|
||||||
|
* Fix clicking on notifications
|
||||||
|
[\#2700](https://github.com/vector-im/riot-web/pull/2700)
|
||||||
|
* Desktop app: Only show window when ready
|
||||||
|
[\#2697](https://github.com/vector-im/riot-web/pull/2697)
|
||||||
|
|
||||||
|
Changes in [0.9.1-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.1-rc.1) (2016-12-05)
|
||||||
|
====================================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.0...v0.9.1-rc.1)
|
||||||
|
|
||||||
|
* Final bits to prepare electron distribtion:
|
||||||
|
[\#2653](https://github.com/vector-im/riot-web/pull/2653)
|
||||||
|
* Update name & repo to reflect renamed repository
|
||||||
|
[\#2692](https://github.com/vector-im/riot-web/pull/2692)
|
||||||
|
* Document cross_origin_renderer_url
|
||||||
|
[\#2680](https://github.com/vector-im/riot-web/pull/2680)
|
||||||
|
* Add css for the iframes for e2e attachments
|
||||||
|
[\#2659](https://github.com/vector-im/riot-web/pull/2659)
|
||||||
|
* Fix config location in some more places
|
||||||
|
[\#2670](https://github.com/vector-im/riot-web/pull/2670)
|
||||||
|
* CSS updates for s/block/blacklist for e2e
|
||||||
|
[\#2662](https://github.com/vector-im/riot-web/pull/2662)
|
||||||
|
* Update to electron 1.4.8
|
||||||
|
[\#2660](https://github.com/vector-im/riot-web/pull/2660)
|
||||||
|
* Add electron config
|
||||||
|
[\#2644](https://github.com/vector-im/riot-web/pull/2644)
|
||||||
|
* Move getDefaultDeviceName into the Platforms
|
||||||
|
[\#2643](https://github.com/vector-im/riot-web/pull/2643)
|
||||||
|
* Add Freenode & Mozilla domains
|
||||||
|
[\#2641](https://github.com/vector-im/riot-web/pull/2641)
|
||||||
|
* Include config.sample.json in dist tarball
|
||||||
|
[\#2614](https://github.com/vector-im/riot-web/pull/2614)
|
||||||
|
|
||||||
|
Changes in [0.9.0](https://github.com/vector-im/vector-web/releases/tag/v0.9.0) (2016-11-19)
|
||||||
|
============================================================================================
|
||||||
|
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.8.4...v0.9.0)
|
||||||
|
|
||||||
|
* Add a cachebuster to /version
|
||||||
|
[\#2596](https://github.com/vector-im/vector-web/pull/2596)
|
||||||
|
* Add a 'View decrypted source' button
|
||||||
|
[\#2587](https://github.com/vector-im/vector-web/pull/2587)
|
||||||
|
* Fix changelog dialog to read new version format
|
||||||
|
[\#2577](https://github.com/vector-im/vector-web/pull/2577)
|
||||||
|
* Build all of the vector dir in the build process
|
||||||
|
[\#2558](https://github.com/vector-im/vector-web/pull/2558)
|
||||||
|
* Support for get_app_version
|
||||||
|
[\#2553](https://github.com/vector-im/vector-web/pull/2553)
|
||||||
|
* Add CSS for mlist truncation
|
||||||
|
[\#2565](https://github.com/vector-im/vector-web/pull/2565)
|
||||||
|
* Add menu option for `external_url` if present
|
||||||
|
[\#2560](https://github.com/vector-im/vector-web/pull/2560)
|
||||||
|
* Make auto-update configureable
|
||||||
|
[\#2555](https://github.com/vector-im/vector-web/pull/2555)
|
||||||
|
* Missed files electron windows fixes
|
||||||
|
[\#2556](https://github.com/vector-im/vector-web/pull/2556)
|
||||||
|
* Add some CSS for scalar error popup
|
||||||
|
[\#2554](https://github.com/vector-im/vector-web/pull/2554)
|
||||||
|
* Catch unhandled errors in the electron process
|
||||||
|
[\#2552](https://github.com/vector-im/vector-web/pull/2552)
|
||||||
|
* Slight grab-bag of fixes for electron on Windows
|
||||||
|
[\#2551](https://github.com/vector-im/vector-web/pull/2551)
|
||||||
|
* Electron app (take 3)
|
||||||
|
[\#2535](https://github.com/vector-im/vector-web/pull/2535)
|
||||||
|
* Use webpack-dev-server instead of http-server
|
||||||
|
[\#2542](https://github.com/vector-im/vector-web/pull/2542)
|
||||||
|
* Better support no-config when loading from file
|
||||||
|
[\#2541](https://github.com/vector-im/vector-web/pull/2541)
|
||||||
|
* Fix loading with no config from HTTP
|
||||||
|
[\#2540](https://github.com/vector-im/vector-web/pull/2540)
|
||||||
|
* Move 'new version' support into Platform
|
||||||
|
[\#2532](https://github.com/vector-im/vector-web/pull/2532)
|
||||||
|
* Add Notification support to the Web Platform
|
||||||
|
[\#2533](https://github.com/vector-im/vector-web/pull/2533)
|
||||||
|
* Use the defaults if given a blank config file
|
||||||
|
[\#2534](https://github.com/vector-im/vector-web/pull/2534)
|
||||||
|
* Implement Platforms
|
||||||
|
[\#2531](https://github.com/vector-im/vector-web/pull/2531)
|
||||||
|
|
||||||
|
Changes in [0.8.4](https://github.com/vector-im/vector-web/releases/tag/v0.8.4) (2016-11-04)
|
||||||
============================================================================================
|
============================================================================================
|
||||||
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.8.4-rc.2...v0.8.4)
|
[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.8.4-rc.2...v0.8.4)
|
||||||
|
|
||||||
|
142
README.md
@ -14,7 +14,7 @@ https://riot.im/develop for those who like living dangerously.
|
|||||||
To host your own copy of Riot, the quickest bet is to use a pre-built
|
To host your own copy of Riot, the quickest bet is to use a pre-built
|
||||||
released version of Riot:
|
released version of Riot:
|
||||||
|
|
||||||
1. Download the latest version from https://github.com/vector-im/vector-web/releases
|
1. Download the latest version from https://github.com/vector-im/riot-web/releases
|
||||||
1. Untar the tarball on your web server
|
1. Untar the tarball on your web server
|
||||||
1. Move (or symlink) the vector-x.x.x directory to an appropriate name
|
1. Move (or symlink) the vector-x.x.x directory to an appropriate name
|
||||||
1. If desired, copy `config.sample.json` to `config.json` and edit it
|
1. If desired, copy `config.sample.json` to `config.json` and edit it
|
||||||
@ -25,6 +25,14 @@ Note that Chrome does not allow microphone or webcam access for sites served
|
|||||||
over http (except localhost), so for working VoIP you will need to serve Riot
|
over http (except localhost), so for working VoIP you will need to serve Riot
|
||||||
over https.
|
over https.
|
||||||
|
|
||||||
|
### Installation Steps for Debian Stretch
|
||||||
|
1. Add the repository to your sources.list using either of the following two options:
|
||||||
|
- Directly to sources.list: `echo "deb https://riot.im/packages/debian/ stretch main" | sudo tee -a /etc/apt/sources.list`
|
||||||
|
- As a separate entry in sources.list.d: `echo "deb https://riot.im/packages/debian/ stretch main" | sudo tee /etc/apt/sources.list.d/riot.list`
|
||||||
|
2. Add the gpg signing key for the riot repository: `curl -s https://riot.im/packages/debian/repo-key.asc | sudo apt-key add -`
|
||||||
|
3. Update your package lists: `sudo apt-get update`
|
||||||
|
4. Install Riot: `sudo apt-get install riot-web`
|
||||||
|
|
||||||
Important Security Note
|
Important Security Note
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
@ -36,7 +44,7 @@ access to Riot (or other apps) due to sharing the same domain.
|
|||||||
|
|
||||||
We have put some coarse mitigations into place to try to protect against this
|
We have put some coarse mitigations into place to try to protect against this
|
||||||
situation, but it's still not good practice to do it in the first place. See
|
situation, but it's still not good practice to do it in the first place. See
|
||||||
https://github.com/vector-im/vector-web/issues/1977 for more details.
|
https://github.com/vector-im/riot-web/issues/1977 for more details.
|
||||||
|
|
||||||
Building From Source
|
Building From Source
|
||||||
====================
|
====================
|
||||||
@ -45,13 +53,17 @@ Riot is a modular webapp built with modern ES6 and requires a npm build system
|
|||||||
to build.
|
to build.
|
||||||
|
|
||||||
1. Install or update `node.js` so that your `npm` is at least at version `2.0.0`
|
1. Install or update `node.js` so that your `npm` is at least at version `2.0.0`
|
||||||
1. Clone the repo: `git clone https://github.com/vector-im/vector-web.git`
|
1. Clone the repo: `git clone https://github.com/vector-im/riot-web.git`
|
||||||
1. Switch to the vector-web directory: `cd vector-web`
|
1. Switch to the riot-web directory: `cd riot-web`
|
||||||
1. Install the prerequisites: `npm install`
|
1. Install the prerequisites: `npm install`
|
||||||
1. If you are using the `develop` branch of vector-web, you will probably need
|
1. If you are using the `develop` branch of vector-web, you will probably need
|
||||||
to rebuild one of the dependencies, due to
|
to rebuild some of the dependencies, due to
|
||||||
https://github.com/npm/npm/issues/3055: `(cd node_modules/matrix-react-sdk
|
https://github.com/npm/npm/issues/3055:
|
||||||
&& npm install)`
|
|
||||||
|
```
|
||||||
|
(cd node_modules/matrix-js-sdk && npm install)
|
||||||
|
(cd node_modules/matrix-react-sdk && npm install)
|
||||||
|
```
|
||||||
1. Configure the app by copying `config.sample.json` to `config.json` and
|
1. Configure the app by copying `config.sample.json` to `config.json` and
|
||||||
modifying it (see below for details)
|
modifying it (see below for details)
|
||||||
1. `npm run dist` to build a tarball to deploy. Untaring this file will give
|
1. `npm run dist` to build a tarball to deploy. Untaring this file will give
|
||||||
@ -59,16 +71,16 @@ to build.
|
|||||||
web server.
|
web server.
|
||||||
|
|
||||||
Note that `npm run dist` is not supported on Windows, so Windows users can run `npm
|
Note that `npm run dist` is not supported on Windows, so Windows users can run `npm
|
||||||
run build`, which will build all the necessary files into the `vector`
|
run build`, which will build all the necessary files into the `webapp`
|
||||||
directory. The version of Vector will not appear in Settings without
|
directory. The version of Riot will not appear in Settings without
|
||||||
using the dist script. You can then mount the vector directory on your
|
using the dist script. You can then mount the `webapp` directory on your
|
||||||
webserver to actually serve up the app, which is entirely static content.
|
webserver to actually serve up the app, which is entirely static content.
|
||||||
|
|
||||||
config.json
|
config.json
|
||||||
===========
|
===========
|
||||||
|
|
||||||
You can configure the app by copying `vector/config.sample.json` to
|
You can configure the app by copying `config.sample.json` to
|
||||||
`vector/config.json` and customising it:
|
`config.json` and customising it:
|
||||||
|
|
||||||
1. `default_hs_url` is the default home server url.
|
1. `default_hs_url` is the default home server url.
|
||||||
1. `default_is_url` is the default identity server url (this is the server used
|
1. `default_is_url` is the default identity server url (this is the server used
|
||||||
@ -81,55 +93,73 @@ You can configure the app by copying `vector/config.sample.json` to
|
|||||||
and https://vector.im. In future identity servers will be decentralised.
|
and https://vector.im. In future identity servers will be decentralised.
|
||||||
1. `integrations_ui_url`: URL to the web interface for the integrations server.
|
1. `integrations_ui_url`: URL to the web interface for the integrations server.
|
||||||
1. `integrations_rest_url`: URL to the REST interface for the integrations server.
|
1. `integrations_rest_url`: URL to the REST interface for the integrations server.
|
||||||
1. `roomDirectory`: config for the public room directory. This section encodes behaviour
|
1. `roomDirectory`: config for the public room directory. This section is optional.
|
||||||
on the room directory screen for filtering the list by server / network type and joining
|
|
||||||
third party networks. This config section will disappear once APIs are available to
|
|
||||||
get this information for home servers. This section is optional.
|
|
||||||
1. `roomDirectory.servers`: List of other Home Servers' directories to include in the drop
|
1. `roomDirectory.servers`: List of other Home Servers' directories to include in the drop
|
||||||
down list. Optional.
|
down list. Optional.
|
||||||
1. `roomDirectory.serverConfig`: Config for each server in `roomDirectory.servers`. Optional.
|
1. `update_base_url` (electron app only): HTTPS URL to a web server to download
|
||||||
1. `roomDirectory.serverConfig.<server_name>.networks`: List of networks (named
|
updates from. This should be the path to the directory containing `macos`
|
||||||
in `roomDirectory.networks`) to include for this server. Optional.
|
and `win32` (for update packages, not installer packages).
|
||||||
1. `roomDirectory.networks`: config for each network type. Optional.
|
1. `cross_origin_renderer_url`: URL to a static HTML page hosting code to help display
|
||||||
1. `roomDirectory.<network_type>.name`: Human-readable name for the network. Required.
|
encrypted file attachments. This MUST be hosted on a completely separate domain to
|
||||||
1. `roomDirectory.<network_type>.protocol`: Protocol as given by the server in
|
anything else since it is used to isolate the privileges of file attachments to this
|
||||||
`/_matrix/client/unstable/thirdparty/protocols` response. Required to be able to join
|
domain. Default: `usercontent.riot.im`. This needs to contain v1.html from
|
||||||
this type of third party network.
|
https://github.com/matrix-org/usercontent/blob/master/v1.html
|
||||||
1. `roomDirectory.<network_type>.domain`: Domain as given by the server in
|
|
||||||
`/_matrix/client/unstable/thirdparty/protocols` response, if present. Required to be
|
|
||||||
able to join this type of third party network, if present in `thirdparty/protocols`.
|
|
||||||
1. `roomDirectory.<network_type>.portalRoomPattern`: Regular expression matching aliases
|
|
||||||
for portal rooms to locations on this network. Required.
|
|
||||||
1. `roomDirectory.<network_type>.icon`: URL to an icon to be displayed for this network. Required.
|
|
||||||
1. `roomDirectory.<network_type>.example`: Textual example of a location on this network,
|
|
||||||
eg. '#channel' for an IRC network. Optional.
|
|
||||||
1. `roomDirectory.<network_type>.nativePattern`: Regular expression that matches a
|
|
||||||
valid location on this network. This is used as a hint to the user to indicate
|
|
||||||
when a valid location has been entered so it's not necessary for this to be
|
|
||||||
exactly correct. Optional.
|
|
||||||
|
|
||||||
Running as a Desktop app
|
Running as a Desktop app
|
||||||
========================
|
========================
|
||||||
|
|
||||||
In future we'll do an official distribution of Riot as an desktop app. Meanwhile,
|
Riot can also be run as a desktop app, wrapped in electron. You can download a
|
||||||
there are a few options:
|
pre-built version from https://riot.im/desktop.html or, if you prefer,
|
||||||
|
built it yourself.
|
||||||
|
|
||||||
@asdf:matrix.org points out that you can use nativefier and it just works(tm):
|
To run as a desktop app:
|
||||||
|
|
||||||
|
1. Follow the instructions in 'Building From Source' above
|
||||||
|
2. Install electron and run it:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install electron
|
||||||
|
node_modules/.bin/electron .
|
||||||
|
```
|
||||||
|
|
||||||
|
To build packages, use electron-builder. This is configured to output:
|
||||||
|
* dmg + zip for macOS
|
||||||
|
* exe + nupkg for Windows
|
||||||
|
* deb for Linux
|
||||||
|
But this can be customised by editing the `build` section of package.json
|
||||||
|
as per https://github.com/electron-userland/electron-builder/wiki/Options
|
||||||
|
|
||||||
|
See https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build
|
||||||
|
for dependencies required for building packages for various platforms.
|
||||||
|
|
||||||
|
The only platform that can build packages for all three platforms is macOS:
|
||||||
|
```
|
||||||
|
brew install wine --without-x11
|
||||||
|
brew install mono
|
||||||
|
brew install gnu-tar
|
||||||
|
npm install
|
||||||
|
npm run build:electron
|
||||||
|
```
|
||||||
|
|
||||||
|
For other packages, use electron-builder manually. For example, to build a package
|
||||||
|
for 64 bit Linux:
|
||||||
|
|
||||||
|
1. Follow the instructions in 'Building From Source' above
|
||||||
|
2. `node_modules/.bin/build -l --x64`
|
||||||
|
|
||||||
|
All electron packages go into `electron/dist/`
|
||||||
|
|
||||||
|
Many thanks to @aviraldg for the initial work on the electron integration.
|
||||||
|
|
||||||
|
Other options for running as a desktop app:
|
||||||
|
* https://github.com/krisak/vector-electron-desktop
|
||||||
|
* @asdf:matrix.org points out that you can use nativefier and it just works(tm)
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo npm install nativefier -g
|
sudo npm install nativefier -g
|
||||||
nativefier https://riot.im/app/
|
nativefier https://riot.im/app/
|
||||||
```
|
```
|
||||||
|
|
||||||
krisa has a dedicated electron project at
|
|
||||||
https://github.com/krisak/vector-electron-desktop (although you should swap out
|
|
||||||
the 'vector' folder for the latest vector tarball you want to run. Get a
|
|
||||||
tarball from https://github.com/vector-im/vector-web/releases or build your own
|
|
||||||
- see Building From Source above).
|
|
||||||
|
|
||||||
There's also a (much) older electron distribution at https://github.com/stevenhammerton/vector-desktop
|
|
||||||
|
|
||||||
|
|
||||||
Development
|
Development
|
||||||
===========
|
===========
|
||||||
|
|
||||||
@ -149,13 +179,13 @@ the `component-index.js` for the app (used in future for skinning)
|
|||||||
development on Riot forcing `matrix-react-sdk` to move fast at the expense of
|
development on Riot forcing `matrix-react-sdk` to move fast at the expense of
|
||||||
maintaining a clear abstraction between the two.** Hacking on Riot inevitably
|
maintaining a clear abstraction between the two.** Hacking on Riot inevitably
|
||||||
means hacking equally on `matrix-react-sdk`, and there are bits of
|
means hacking equally on `matrix-react-sdk`, and there are bits of
|
||||||
`matrix-react-sdk` behaviour incorrectly residing in the `vector-web` project
|
`matrix-react-sdk` behaviour incorrectly residing in the `riot-web` project
|
||||||
(e.g. matrix-react-sdk specific CSS), and a bunch of Riot specific behaviour
|
(e.g. matrix-react-sdk specific CSS), and a bunch of Riot specific behaviour
|
||||||
in the `matrix-react-sdk` (grep for `vector` / `riot`). This separation problem will be
|
in the `matrix-react-sdk` (grep for `vector` / `riot`). This separation problem will be
|
||||||
solved asap once development on Riot (and thus matrix-react-sdk) has
|
solved asap once development on Riot (and thus matrix-react-sdk) has
|
||||||
stabilised. Until then, the two projects should basically be considered as a
|
stabilised. Until then, the two projects should basically be considered as a
|
||||||
single unit. In particular, `matrix-react-sdk` issues are currently filed
|
single unit. In particular, `matrix-react-sdk` issues are currently filed
|
||||||
against `vector-web` in github.
|
against `riot-web` in github.
|
||||||
|
|
||||||
Please note that Riot is intended to run correctly without access to the public
|
Please note that Riot is intended to run correctly without access to the public
|
||||||
internet. So please don't depend on resources (JS libs, CSS, images, fonts)
|
internet. So please don't depend on resources (JS libs, CSS, images, fonts)
|
||||||
@ -190,8 +220,8 @@ Then similarly with `matrix-react-sdk`:
|
|||||||
|
|
||||||
Finally, build and start Riot itself:
|
Finally, build and start Riot itself:
|
||||||
|
|
||||||
1. `git clone git@github.com:vector-im/vector-web.git`
|
1. `git clone git@github.com:vector-im/riot-web.git`
|
||||||
1. `cd vector-web`
|
1. `cd riot-web`
|
||||||
1. `git checkout develop`
|
1. `git checkout develop`
|
||||||
1. `npm install`
|
1. `npm install`
|
||||||
1. `rm -r node_modules/matrix-js-sdk; ln -s ../../matrix-js-sdk node_modules/`
|
1. `rm -r node_modules/matrix-js-sdk; ln -s ../../matrix-js-sdk node_modules/`
|
||||||
@ -215,10 +245,10 @@ Finally, build and start Riot itself:
|
|||||||
disables caching, so do NOT use it in production.
|
disables caching, so do NOT use it in production.
|
||||||
1. Open http://127.0.0.1:8080/ in your browser to see your newly built Riot.
|
1. Open http://127.0.0.1:8080/ in your browser to see your newly built Riot.
|
||||||
|
|
||||||
When you make changes to `matrix-react-sdk`, you will need to run `npm run
|
When you make changes to `matrix-react-sdk` or `matrix-js-sdk`, you will need
|
||||||
build` in the relevant directory. You can do this automatically by instead
|
to run `npm run build` in the relevant directory. You can do this automatically
|
||||||
running `npm start` in the directory, to start a development builder which
|
by instead running `npm start` in the directory, to start a development builder
|
||||||
will watch for changes to the files and rebuild automatically.
|
which will watch for changes to the files and rebuild automatically.
|
||||||
|
|
||||||
If you add or remove any components from the Riot skin, you will need to rebuild
|
If you add or remove any components from the Riot skin, you will need to rebuild
|
||||||
the skin's index by running, `npm run reskindex`.
|
the skin's index by running, `npm run reskindex`.
|
||||||
|
@ -4,64 +4,11 @@
|
|||||||
"brand": "Riot",
|
"brand": "Riot",
|
||||||
"integrations_ui_url": "https://scalar.vector.im/",
|
"integrations_ui_url": "https://scalar.vector.im/",
|
||||||
"integrations_rest_url": "https://scalar.vector.im/api",
|
"integrations_rest_url": "https://scalar.vector.im/api",
|
||||||
|
"bug_report_endpoint_url": "https://vector.im/bugs",
|
||||||
"enableLabs": true,
|
"enableLabs": true,
|
||||||
"roomDirectory": {
|
"roomDirectory": {
|
||||||
"servers": [
|
"servers": [
|
||||||
"matrix.org"
|
"matrix.org"
|
||||||
],
|
|
||||||
"serverConfig": {
|
|
||||||
"matrix.org": {
|
|
||||||
"networks": [
|
|
||||||
"_matrix",
|
|
||||||
"gitter",
|
|
||||||
"irc:freenode",
|
|
||||||
"irc:mozilla",
|
|
||||||
"irc:snoonet",
|
|
||||||
"irc:oftc"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"networks": {
|
|
||||||
"gitter": {
|
|
||||||
"protocol": "gitter",
|
|
||||||
"portalRoomPattern": "#gitter_.*:matrix.org",
|
|
||||||
"name": "Gitter",
|
|
||||||
"icon": "//gitter.im/favicon.ico",
|
|
||||||
"example": "org/community",
|
|
||||||
"nativePattern": "[^\\s]+/[^\\s]+$"
|
|
||||||
},
|
|
||||||
"irc:freenode": {
|
|
||||||
"portalRoomPattern": "#freenode_.*:matrix.org",
|
|
||||||
"name": "Freenode",
|
|
||||||
"icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
|
||||||
"example": "#channel",
|
|
||||||
"nativePattern": "^#[^\\s]+$"
|
|
||||||
},
|
|
||||||
"irc:mozilla": {
|
|
||||||
"portalRoomPattern": "#mozilla_.*:matrix.org",
|
|
||||||
"name": "Mozilla",
|
|
||||||
"icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
|
||||||
"example": "#channel",
|
|
||||||
"nativePattern": "^#[^\\s]+$"
|
|
||||||
},
|
|
||||||
"irc:snoonet": {
|
|
||||||
"protocol": "irc",
|
|
||||||
"domain": "ipv6-irc.snoonet.org",
|
|
||||||
"portalRoomPattern": "#_snoonet_.*:matrix.org",
|
|
||||||
"name": "Snoonet",
|
|
||||||
"icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
|
||||||
"example": "#channel",
|
|
||||||
"nativePattern": "^#[^\\s]+$"
|
|
||||||
},
|
|
||||||
"irc:oftc": {
|
|
||||||
"protocol": "irc",
|
|
||||||
"domain": "irc.oftc.net",
|
|
||||||
"portalRoomPattern": "#_oftc_.*:matrix.org",
|
|
||||||
"name": "OFTC",
|
|
||||||
"icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
|
||||||
"example": "#channel",
|
|
||||||
"nativePattern": "^#[^\\s]+$"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
25
docs/theming.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Theming Riot
|
||||||
|
============
|
||||||
|
|
||||||
|
Themes are a very basic way of providing simple alternative look & feels to the
|
||||||
|
riot-web app via CSS & custom imagery.
|
||||||
|
|
||||||
|
They are *NOT* co be confused with 'skins', which describe apps which sit on top
|
||||||
|
of matrix-react-sdk - e.g. in theory Riot itself is a react-sdk skin.
|
||||||
|
As of Jan 2017, skins are not fully supported; riot is the only available skin.
|
||||||
|
|
||||||
|
To define a theme for Riot:
|
||||||
|
|
||||||
|
1. Pick a name, e.g. `teal`. at time of writing we have `light` and `dark`.
|
||||||
|
2. Fork `src/skins/vector/css/themes/dark.scss` to be teal.scss
|
||||||
|
3. Fork `src/skins/vector/css/themes/_base.scss` to be _teal.scss
|
||||||
|
4. Override variables in _teal.scss as desired. You may wish to delete ones
|
||||||
|
which don't differ from _base.scss, to make it clear which are being
|
||||||
|
overridden. If every single colour is being changed (as per _dark.scss)
|
||||||
|
then you might as well keep them all.
|
||||||
|
5. Add the theme to the list of entrypoints in webpack.config.js
|
||||||
|
6. Add the theme to the list of themes in matrix-react-sdk's UserSettings.js
|
||||||
|
7. Sit back and admire your handywork.
|
||||||
|
|
||||||
|
In future, the assets for a theme will probably be gathered together into a
|
||||||
|
single directory tree.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 102 KiB |
BIN
electron/build/icons/128x128.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
electron/build/icons/16x16.png
Normal file
After Width: | Height: | Size: 673 B |
BIN
electron/build/icons/24x24.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
electron/build/icons/256x256.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
electron/build/icons/48x48.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
electron/build/icons/512x512.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
electron/build/icons/64x64.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
electron/build/icons/96x96.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
electron/img/riot.png
Normal file
After Width: | Height: | Size: 14 KiB |
4
electron/riot.im/README
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
This directory contains the config file for the official riot.im distribution
|
||||||
|
of Riot Desktop. You probably do not want to build with this config unless
|
||||||
|
you're building the official riot.im distribution, or you'll find your builds
|
||||||
|
will replace themselves with the riot.im build.
|
72
electron/riot.im/config.json
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"update_base_url": "https://riot.im/download/desktop/update/",
|
||||||
|
"default_hs_url": "https://matrix.org",
|
||||||
|
"default_is_url": "https://vector.im",
|
||||||
|
"brand": "Riot",
|
||||||
|
"integrations_ui_url": "https://scalar.vector.im/",
|
||||||
|
"integrations_rest_url": "https://scalar.vector.im/api",
|
||||||
|
"enableLabs": true,
|
||||||
|
"roomDirectory": {
|
||||||
|
"servers": [
|
||||||
|
"matrix.org"
|
||||||
|
],
|
||||||
|
"serverConfig": {
|
||||||
|
"matrix.org": {
|
||||||
|
"networks": [
|
||||||
|
"_matrix",
|
||||||
|
"gitter",
|
||||||
|
"irc:freenode",
|
||||||
|
"irc:mozilla",
|
||||||
|
"irc:snoonet",
|
||||||
|
"irc:oftc"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"networks": {
|
||||||
|
"gitter": {
|
||||||
|
"protocol": "gitter",
|
||||||
|
"portalRoomPattern": "#gitter_.*:matrix.org",
|
||||||
|
"name": "Gitter",
|
||||||
|
"icon": "https://gitter.im/favicon.ico",
|
||||||
|
"example": "org/community",
|
||||||
|
"nativePattern": "[^\\s]+/[^\\s]+$"
|
||||||
|
},
|
||||||
|
"irc:freenode": {
|
||||||
|
"protocol": "irc",
|
||||||
|
"domain": "chat.freenode.net",
|
||||||
|
"portalRoomPattern": "#freenode_.*:matrix.org",
|
||||||
|
"name": "Freenode",
|
||||||
|
"icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
||||||
|
"example": "#channel",
|
||||||
|
"nativePattern": "^#[^\\s]+$"
|
||||||
|
},
|
||||||
|
"irc:mozilla": {
|
||||||
|
"protocol": "irc",
|
||||||
|
"domain": "chat.freenode.net",
|
||||||
|
"portalRoomPattern": "#mozilla_.*:matrix.org",
|
||||||
|
"name": "Mozilla",
|
||||||
|
"icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
||||||
|
"example": "#channel",
|
||||||
|
"nativePattern": "^#[^\\s]+$"
|
||||||
|
},
|
||||||
|
"irc:snoonet": {
|
||||||
|
"protocol": "irc",
|
||||||
|
"domain": "ipv6-irc.snoonet.org",
|
||||||
|
"portalRoomPattern": "#_snoonet_.*:matrix.org",
|
||||||
|
"name": "Snoonet",
|
||||||
|
"icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
||||||
|
"example": "#channel",
|
||||||
|
"nativePattern": "^#[^\\s]+$"
|
||||||
|
},
|
||||||
|
"irc:oftc": {
|
||||||
|
"protocol": "irc",
|
||||||
|
"domain": "irc.oftc.net",
|
||||||
|
"portalRoomPattern": "#_oftc_.*:matrix.org",
|
||||||
|
"name": "OFTC",
|
||||||
|
"icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX",
|
||||||
|
"example": "#channel",
|
||||||
|
"nativePattern": "^#[^\\s]+$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,11 +26,13 @@ if (check_squirrel_hooks()) return;
|
|||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
|
|
||||||
|
const tray = require('./tray');
|
||||||
|
|
||||||
const VectorMenu = require('./vectormenu');
|
const VectorMenu = require('./vectormenu');
|
||||||
|
|
||||||
let vectorConfig = {};
|
let vectorConfig = {};
|
||||||
try {
|
try {
|
||||||
vectorConfig = require('../../vector/config.json');
|
vectorConfig = require('../../webapp/config.json');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// it would be nice to check the error code here and bail if the config
|
// it would be nice to check the error code here and bail if the config
|
||||||
// is unparseable, but we get MODULE_NOT_FOUND in the case of a missing
|
// is unparseable, but we get MODULE_NOT_FOUND in the case of a missing
|
||||||
@ -101,9 +103,9 @@ function pollForUpdates() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startAutoUpdate(update_url) {
|
function startAutoUpdate(update_base_url) {
|
||||||
if (update_url.slice(-1) !== '/') {
|
if (update_base_url.slice(-1) !== '/') {
|
||||||
update_url = update_url + '/';
|
update_base_url = update_base_url + '/';
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// For reasons best known to Squirrel, the way it checks for updates
|
// For reasons best known to Squirrel, the way it checks for updates
|
||||||
@ -112,9 +114,18 @@ function startAutoUpdate(update_url) {
|
|||||||
// 204 No Content. On windows it takes a base path and looks for
|
// 204 No Content. On windows it takes a base path and looks for
|
||||||
// files under that path.
|
// files under that path.
|
||||||
if (process.platform == 'darwin') {
|
if (process.platform == 'darwin') {
|
||||||
electron.autoUpdater.setFeedURL(update_url);
|
// include the current version in the URL we hit. Electron doesn't add
|
||||||
|
// it anywhere (apart from the User-Agent) so it's up to us. We could
|
||||||
|
// (and previously did) just use the User-Agent, but this doesn't
|
||||||
|
// rely on NSURLConnection setting the User-Agent to what we expect,
|
||||||
|
// and also acts as a convenient cache-buster to ensure that when the
|
||||||
|
// app updates it always gets a fresh value to avoid update-looping.
|
||||||
|
electron.autoUpdater.setFeedURL(
|
||||||
|
update_base_url +
|
||||||
|
'macos/?localVersion=' + encodeURIComponent(electron.app.getVersion())
|
||||||
|
);
|
||||||
} else if (process.platform == 'win32') {
|
} else if (process.platform == 'win32') {
|
||||||
electron.autoUpdater.setFeedURL(update_url + 'win32/');
|
electron.autoUpdater.setFeedURL(update_base_url + 'win32/' + process.arch + '/');
|
||||||
} else {
|
} else {
|
||||||
// Squirrel / electron only supports auto-update on these two platforms.
|
// Squirrel / electron only supports auto-update on these two platforms.
|
||||||
// I'm not even going to try to guess which feed style they'd use if they
|
// I'm not even going to try to guess which feed style they'd use if they
|
||||||
@ -148,26 +159,56 @@ process.on('uncaughtException', function (error) {
|
|||||||
|
|
||||||
electron.ipcMain.on('install_update', installUpdate);
|
electron.ipcMain.on('install_update', installUpdate);
|
||||||
|
|
||||||
electron.app.on('ready', () => {
|
electron.app.commandLine.appendSwitch('--enable-usermedia-screen-capturing');
|
||||||
if (vectorConfig.update_url) {
|
|
||||||
console.log("Starting auto update with URL: " + vectorConfig.update_url);
|
const shouldQuit = electron.app.makeSingleInstance((commandLine, workingDirectory) => {
|
||||||
startAutoUpdate(vectorConfig.update_url);
|
// Someone tried to run a second instance, we should focus our window.
|
||||||
} else {
|
if (mainWindow) {
|
||||||
console.log("No update_url is defined: auto update is disabled");
|
if (!mainWindow.isVisible()) mainWindow.show();
|
||||||
|
if (mainWindow.isMinimized()) mainWindow.restore();
|
||||||
|
mainWindow.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shouldQuit) {
|
||||||
|
electron.app.quit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
electron.app.on('ready', () => {
|
||||||
|
if (vectorConfig.update_base_url) {
|
||||||
|
console.log("Starting auto update with base URL: " + vectorConfig.update_base_url);
|
||||||
|
startAutoUpdate(vectorConfig.update_base_url);
|
||||||
|
} else {
|
||||||
|
console.log("No update_base_url is defined: auto update is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
const icon_path = `${__dirname}/../img/riot.` + (
|
||||||
|
process.platform == 'win32' ? 'ico' : 'png'
|
||||||
|
);
|
||||||
|
|
||||||
mainWindow = new electron.BrowserWindow({
|
mainWindow = new electron.BrowserWindow({
|
||||||
icon: `${__dirname}/../img/riot.ico`,
|
icon: icon_path,
|
||||||
width: 1024, height: 768,
|
width: 1024, height: 768,
|
||||||
|
show: false,
|
||||||
|
autoHideMenuBar: true,
|
||||||
});
|
});
|
||||||
mainWindow.loadURL(`file://${__dirname}/../../webapp/index.html`);
|
mainWindow.loadURL(`file://${__dirname}/../../webapp/index.html`);
|
||||||
electron.Menu.setApplicationMenu(VectorMenu);
|
electron.Menu.setApplicationMenu(VectorMenu);
|
||||||
|
|
||||||
|
// Create trayIcon icon
|
||||||
|
tray.create(mainWindow, {
|
||||||
|
icon_path: icon_path,
|
||||||
|
brand: vectorConfig.brand || 'Riot'
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow.once('ready-to-show', () => {
|
||||||
|
mainWindow.show();
|
||||||
|
});
|
||||||
mainWindow.on('closed', () => {
|
mainWindow.on('closed', () => {
|
||||||
mainWindow = null;
|
mainWindow = null;
|
||||||
});
|
});
|
||||||
mainWindow.on('close', (e) => {
|
mainWindow.on('close', (e) => {
|
||||||
if (process.platform == 'darwin' && !appQuitting) {
|
if (!appQuitting && (tray.hasTray() || process.platform == 'darwin')) {
|
||||||
// On Mac, closing the window just hides it
|
// On Mac, closing the window just hides it
|
||||||
// (this is generally how single-window Mac apps
|
// (this is generally how single-window Mac apps
|
||||||
// behave, eg. Mail.app)
|
// behave, eg. Mail.app)
|
||||||
@ -198,3 +239,9 @@ electron.app.on('activate', () => {
|
|||||||
electron.app.on('before-quit', () => {
|
electron.app.on('before-quit', () => {
|
||||||
appQuitting = true;
|
appQuitting = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set the App User Model ID to match what the squirrel
|
||||||
|
// installer uses for the shortcut icon.
|
||||||
|
// This makes notifications work on windows 8.1 (and is
|
||||||
|
// a noop on other platforms).
|
||||||
|
electron.app.setAppUserModelId('com.squirrel.riot-web.Riot');
|
||||||
|
@ -1,9 +1,30 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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.
|
||||||
|
*/
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const spawn = require('child_process').spawn;
|
const spawn = require('child_process').spawn;
|
||||||
const app = require('electron').app;
|
const app = require('electron').app;
|
||||||
|
|
||||||
function run_update_exe(args, done) {
|
function run_update_exe(args, done) {
|
||||||
|
// Invokes Squirrel's Update.exe which will do things for us like create shortcuts
|
||||||
|
// Note that there's an Update.exe in the app-x.x.x directory and one in the parent
|
||||||
|
// directory: we need to run the one in the parent directory, because it discovers
|
||||||
|
// information about the app by inspecting the directory it's run from.
|
||||||
const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
|
const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
|
||||||
|
console.log('Spawning `%s` with args `%s`', updateExe, args);
|
||||||
spawn(updateExe, args, {
|
spawn(updateExe, args, {
|
||||||
detached: true
|
detached: true
|
||||||
}).on('close', done);
|
}).on('close', done);
|
||||||
|
67
electron/src/tray.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 Karl Glatz <karl@glatz.biz>
|
||||||
|
Copyright 2017 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const electron = require('electron');
|
||||||
|
|
||||||
|
const app = electron.app;
|
||||||
|
const Tray = electron.Tray;
|
||||||
|
const MenuItem = electron.MenuItem;
|
||||||
|
|
||||||
|
let trayIcon = null;
|
||||||
|
|
||||||
|
exports.hasTray = function hasTray() {
|
||||||
|
return (trayIcon !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.create = function (win, config) {
|
||||||
|
// no trays on darwin
|
||||||
|
if (process.platform === 'darwin' || trayIcon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleWin = function () {
|
||||||
|
if (win.isVisible() && !win.isMinimized()) {
|
||||||
|
win.hide();
|
||||||
|
} else {
|
||||||
|
if (win.isMinimized()) win.restore();
|
||||||
|
if (!win.isVisible()) win.show();
|
||||||
|
win.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const contextMenu = electron.Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: 'Show/Hide ' + config.brand,
|
||||||
|
click: toggleWin
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Quit',
|
||||||
|
click: function () {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
trayIcon = new Tray(config.icon_path);
|
||||||
|
trayIcon.setToolTip(config.brand);
|
||||||
|
trayIcon.setContextMenu(contextMenu);
|
||||||
|
trayIcon.on('click', toggleWin);
|
||||||
|
};
|
@ -72,11 +72,7 @@ const template = [
|
|||||||
role: 'togglefullscreen'
|
role: 'togglefullscreen'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Toggle Developer Tools',
|
role: 'toggledevtools'
|
||||||
accelerator: process.platform == 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
|
||||||
click: function(item, focusedWindow) {
|
|
||||||
if (focusedWindow) focusedWindow.toggleDevTools();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -29,12 +29,22 @@ module.exports = function (config) {
|
|||||||
files: [
|
files: [
|
||||||
'node_modules/babel-polyfill/browser.js',
|
'node_modules/babel-polyfill/browser.js',
|
||||||
testFile,
|
testFile,
|
||||||
{pattern: 'vector/img/*', watched: false, included: false, served: true, nocache: false},
|
|
||||||
|
// make the images available via our httpd. They will be avaliable
|
||||||
|
// below http://localhost:[PORT]/base/. See also `proxies` which
|
||||||
|
// defines alternative URLs for them.
|
||||||
|
//
|
||||||
|
// This isn't required by any of the tests, but it stops karma
|
||||||
|
// logging warnings when it serves a 404 for them.
|
||||||
|
{
|
||||||
|
pattern: 'src/skins/vector/img/*',
|
||||||
|
watched: false, included: false, served: true, nocache: false,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
// redirect img links to the karma server
|
|
||||||
proxies: {
|
proxies: {
|
||||||
"/img/": "/base/vector/img/",
|
// redirect img links to the karma server. See above.
|
||||||
|
"/img/": "/base/src/skins/vector/img/",
|
||||||
},
|
},
|
||||||
|
|
||||||
// preprocess matching files before serving them to the browser
|
// preprocess matching files before serving them to the browser
|
||||||
@ -86,6 +96,12 @@ module.exports = function (config) {
|
|||||||
|
|
||||||
webpack: {
|
webpack: {
|
||||||
module: {
|
module: {
|
||||||
|
preLoaders: [
|
||||||
|
// use the source-map-loader for javascript. This means
|
||||||
|
// that we have a better chance of seeing line numbers from
|
||||||
|
// the pre-babeled source.
|
||||||
|
{ test: /\.js$/, loader: "source-map-loader" },
|
||||||
|
],
|
||||||
loaders: [
|
loaders: [
|
||||||
{ test: /\.json$/, loader: "json" },
|
{ test: /\.json$/, loader: "json" },
|
||||||
{
|
{
|
||||||
|
75
package.json
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "vector-web",
|
"name": "riot-web",
|
||||||
"productName": "Riot",
|
"productName": "Riot",
|
||||||
"main": "electron/src/electron-main.js",
|
"main": "electron/src/electron-main.js",
|
||||||
"version": "0.8.4",
|
"version": "0.9.6",
|
||||||
"description": "A feature-rich client for Matrix.org",
|
"description": "A feature-rich client for Matrix.org",
|
||||||
"author": "Vector Creations Ltd.",
|
"author": "Vector Creations Ltd.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/vector-im/vector-web"
|
"url": "https://github.com/vector-im/riot-web"
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"files": [
|
"files": [
|
||||||
@ -27,27 +27,23 @@
|
|||||||
"matrix-react-parent": "matrix-react-sdk",
|
"matrix-react-parent": "matrix-react-sdk",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"reskindex": "reskindex -h src/header",
|
"reskindex": "reskindex -h src/header",
|
||||||
"build:res": "cpx \"{src/skins/vector/fonts,src/skins/vector/img}/**\" webapp/ && cpx \"{res/media,res/vector-icons}/**\" webapp/",
|
"build:res": "node scripts/copy-res.js",
|
||||||
"build:config": "cpx config.json webapp/",
|
|
||||||
"build:emojione": "cpx \"node_modules/emojione/assets/svg/*\" webapp/emojione/svg/",
|
|
||||||
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
|
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
|
||||||
"build:css": "mkdirp build && catw \"src/skins/vector/css/**/*.css\" -o build/components.css --no-watch",
|
|
||||||
"build:compile": "babel --source-maps -d lib src",
|
"build:compile": "babel --source-maps -d lib src",
|
||||||
"build:bundle": "NODE_ENV=production webpack -p --progress",
|
"build:bundle": "NODE_ENV=production webpack -p --progress",
|
||||||
"build:bundle:dev": "webpack --optimize-occurence-order --progress",
|
"build:bundle:dev": "webpack --optimize-occurence-order --progress",
|
||||||
"build:electron": "build -lwm",
|
"build:electron": "npm run clean && npm run build && build -wml --ia32 --x64",
|
||||||
"build": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle",
|
"build": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle",
|
||||||
"build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle:dev",
|
"build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle:dev",
|
||||||
"dist": "scripts/package.sh",
|
"dist": "scripts/package.sh",
|
||||||
"start:res": "parallelshell \"cpx -w \\\"{src/skins/vector/fonts,src/skins/vector/img}/**\\\" webapp/\" \"cpx -w \\\"{res/media,res/vector-icons}/**\\\" webapp/\"",
|
"start:res": "node scripts/copy-res.js -w",
|
||||||
"start:config": "cpx -w config.json webapp/",
|
"start:js": "webpack-dev-server --output-filename=bundles/_dev_/[name].js --output-chunk-file=bundles/_dev_/[name].js -w --progress",
|
||||||
"start:emojione": "cpx \"node_modules/emojione/assets/svg/*\" webapp/emojione/svg/ -w",
|
|
||||||
"start:js": "webpack-dev-server -w --progress",
|
|
||||||
"start:js:prod": "NODE_ENV=production webpack-dev-server -w --progress",
|
"start:js:prod": "NODE_ENV=production webpack-dev-server -w --progress",
|
||||||
"start:skins:css": "mkdirp build && catw \"src/skins/vector/css/**/*.css\" -o build/components.css",
|
"start": "node scripts/babelcheck.js && parallelshell \"npm run start:res\" \"npm run start:js\"",
|
||||||
"start": "node scripts/babelcheck.js && parallelshell \"npm run start:emojione\" \"npm run start:res\" \"npm run start:config\" \"npm run start:js\" \"npm run start:skins:css\"",
|
"start:prod": "parallelshell \"npm run start:res\" \"npm run start:js:prod\"",
|
||||||
"start:prod": "parallelshell \"npm run start:emojione\" \"npm run start:js:prod\" \"npm run start:skins:css\"",
|
"lint": "eslint src/",
|
||||||
"clean": "rimraf build lib webapp",
|
"lintall": "eslint src/ test/",
|
||||||
|
"clean": "rimraf lib webapp electron/dist",
|
||||||
"prepublish": "npm run build:compile",
|
"prepublish": "npm run build:compile",
|
||||||
"test": "karma start --single-run=true --autoWatch=false --browsers PhantomJS --colors=false",
|
"test": "karma start --single-run=true --autoWatch=false --browsers PhantomJS --colors=false",
|
||||||
"test:multi": "karma start"
|
"test:multi": "karma start"
|
||||||
@ -70,16 +66,17 @@
|
|||||||
"matrix-react-sdk": "matrix-org/matrix-react-sdk#develop",
|
"matrix-react-sdk": "matrix-org/matrix-react-sdk#develop",
|
||||||
"modernizr": "^3.1.0",
|
"modernizr": "^3.1.0",
|
||||||
"q": "^1.4.1",
|
"q": "^1.4.1",
|
||||||
"react": "^15.2.1",
|
"react": "^15.4.0",
|
||||||
"react-dnd": "^2.1.4",
|
"react-dnd": "^2.1.4",
|
||||||
"react-dnd-html5-backend": "^2.1.2",
|
"react-dnd-html5-backend": "^2.1.2",
|
||||||
"react-dom": "^15.2.1",
|
"react-dom": "^15.4.0",
|
||||||
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
|
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
|
||||||
"sanitize-html": "^1.11.1",
|
"sanitize-html": "^1.11.1",
|
||||||
"ua-parser-js": "^0.7.10",
|
"ua-parser-js": "^0.7.10",
|
||||||
"url": "^0.11.0"
|
"url": "^0.11.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"autoprefixer": "^6.6.0",
|
||||||
"babel-cli": "^6.5.2",
|
"babel-cli": "^6.5.2",
|
||||||
"babel-core": "^6.14.0",
|
"babel-core": "^6.14.0",
|
||||||
"babel-eslint": "^6.1.0",
|
"babel-eslint": "^6.1.0",
|
||||||
@ -94,11 +91,16 @@
|
|||||||
"babel-preset-es2017": "^6.16.0",
|
"babel-preset-es2017": "^6.16.0",
|
||||||
"babel-preset-react": "^6.16.0",
|
"babel-preset-react": "^6.16.0",
|
||||||
"babel-preset-stage-2": "^6.17.0",
|
"babel-preset-stage-2": "^6.17.0",
|
||||||
"catw": "^1.0.1",
|
"chokidar": "^1.6.1",
|
||||||
"cpx": "^1.3.2",
|
"cpx": "^1.3.2",
|
||||||
"css-raw-loader": "^0.1.1",
|
"css-raw-loader": "^0.1.1",
|
||||||
"electron-builder": "^7.23.2",
|
"electron-builder": "^11.2.4",
|
||||||
|
"electron-builder-squirrel-windows": "^11.2.1",
|
||||||
"emojione": "^2.2.3",
|
"emojione": "^2.2.3",
|
||||||
|
"eslint": "^3.14.0",
|
||||||
|
"eslint-config-google": "^0.7.1",
|
||||||
|
"eslint-plugin-flowtype": "^2.30.0",
|
||||||
|
"eslint-plugin-react": "^6.9.0",
|
||||||
"expect": "^1.16.0",
|
"expect": "^1.16.0",
|
||||||
"fs-extra": "^0.30.0",
|
"fs-extra": "^0.30.0",
|
||||||
"html-webpack-plugin": "^2.24.0",
|
"html-webpack-plugin": "^2.24.0",
|
||||||
@ -111,37 +113,52 @@
|
|||||||
"karma-phantomjs-launcher": "^1.0.0",
|
"karma-phantomjs-launcher": "^1.0.0",
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-webpack": "^1.7.0",
|
"karma-webpack": "^1.7.0",
|
||||||
|
"minimist": "^1.2.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mocha": "^2.4.5",
|
"mocha": "^2.4.5",
|
||||||
"parallelshell": "^1.2.0",
|
"parallelshell": "^1.2.0",
|
||||||
"phantomjs-prebuilt": "^2.1.7",
|
"phantomjs-prebuilt": "^2.1.7",
|
||||||
"react-addons-perf": "^15.0",
|
"postcss-extend": "^1.0.5",
|
||||||
"react-addons-test-utils": "^15.0.1",
|
"postcss-import": "^9.0.0",
|
||||||
|
"postcss-loader": "^1.2.2",
|
||||||
|
"postcss-mixins": "^5.4.1",
|
||||||
|
"postcss-nested": "^1.0.0",
|
||||||
|
"postcss-scss": "^0.4.0",
|
||||||
|
"postcss-simple-vars": "^3.0.0",
|
||||||
|
"postcss-strip-inline-comments": "^0.1.5",
|
||||||
|
"react-addons-perf": "^15.4.0",
|
||||||
|
"react-addons-test-utils": "^15.4.0",
|
||||||
"rimraf": "^2.4.3",
|
"rimraf": "^2.4.3",
|
||||||
"source-map-loader": "^0.1.5",
|
"source-map-loader": "^0.1.5",
|
||||||
"webpack": "^1.12.14",
|
"webpack": "^1.12.14",
|
||||||
"webpack-dev-server": "^1.16.2"
|
"webpack-dev-server": "^1.16.2"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"olm": "https://matrix.org/packages/npm/olm/olm-2.0.0.tgz"
|
"olm": "https://matrix.org/packages/npm/olm/olm-2.1.0.tgz"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "im.riot.app",
|
"appId": "im.riot.app",
|
||||||
"category": "Network",
|
"category": "Network",
|
||||||
"electronVersion": "1.4.2",
|
"electronVersion": "1.4.14",
|
||||||
"//asar=false": "https://github.com/electron-userland/electron-builder/issues/675",
|
"//asar=false": "https://github.com/electron-userland/electron-builder/issues/675",
|
||||||
"asar": false,
|
"asar": false,
|
||||||
"dereference": true,
|
"dereference": true,
|
||||||
"//files": "We bundle everything, so we only need to include webapp/",
|
"//files": "We bundle everything, so we only need to include webapp/",
|
||||||
"files": [
|
"files": [
|
||||||
"!**/*",
|
|
||||||
"electron/src/**",
|
"electron/src/**",
|
||||||
"electron/img/**",
|
"electron/img/**",
|
||||||
"webapp/**",
|
"webapp/**",
|
||||||
"package.json"
|
"package.json"
|
||||||
],
|
],
|
||||||
"squirrelWindows": {
|
"linux": {
|
||||||
"iconUrl": "https://riot.im/favicon.ico"
|
"target": "deb",
|
||||||
|
"maintainer": "support@riot.im",
|
||||||
|
"desktop": {
|
||||||
|
"StartupWMClass": "riot-web"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"target": "squirrel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"directories": {
|
"directories": {
|
||||||
|
13
postcss.config.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
require("postcss-import")(),
|
||||||
|
require("autoprefixer")(),
|
||||||
|
require("postcss-simple-vars")(),
|
||||||
|
require("postcss-extend")(),
|
||||||
|
require("postcss-nested")(),
|
||||||
|
require("postcss-mixins")(),
|
||||||
|
require("postcss-strip-inline-comments")(),
|
||||||
|
],
|
||||||
|
"parser": "postcss-scss",
|
||||||
|
"local-plugins": true,
|
||||||
|
};
|
1
release_config.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
signing_id: packages@riot.im
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 673 B |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 3.9 KiB |
81
scripts/copy-res.js
Executable file
@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
// copies the resources into the webapp directory.
|
||||||
|
//
|
||||||
|
|
||||||
|
// cpx includes globbed parts of the filename in the destination, but excludes
|
||||||
|
// common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and
|
||||||
|
// "dest/b/...".
|
||||||
|
const COPY_LIST = [
|
||||||
|
["res/{media,vector-icons}/**", "webapp"],
|
||||||
|
["src/skins/vector/{fonts,img}/**", "webapp"],
|
||||||
|
["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"],
|
||||||
|
["./config.json", "webapp", {directwatch: 1}],
|
||||||
|
];
|
||||||
|
|
||||||
|
const parseArgs = require('minimist');
|
||||||
|
const Cpx = require('cpx');
|
||||||
|
const chokidar = require('chokidar');
|
||||||
|
|
||||||
|
const argv = parseArgs(
|
||||||
|
process.argv.slice(2), {}
|
||||||
|
);
|
||||||
|
|
||||||
|
var watch = argv.w;
|
||||||
|
var verbose = argv.v;
|
||||||
|
|
||||||
|
function errCheck(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function next(i, err) {
|
||||||
|
errCheck(err);
|
||||||
|
|
||||||
|
if (i >= COPY_LIST.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ent = COPY_LIST[i];
|
||||||
|
const source = ent[0];
|
||||||
|
const dest = ent[1];
|
||||||
|
const opts = ent[2] || {};
|
||||||
|
|
||||||
|
const cpx = new Cpx.Cpx(source, dest);
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
cpx.on("copy", (event) => {
|
||||||
|
console.log(`Copied: ${event.srcPath} --> ${event.dstPath}`);
|
||||||
|
});
|
||||||
|
cpx.on("remove", (event) => {
|
||||||
|
console.log(`Removed: ${event.path}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const cb = (err) => {next(i+1, err)};
|
||||||
|
|
||||||
|
if (watch) {
|
||||||
|
if (opts.directwatch) {
|
||||||
|
// cpx -w creates a watcher for the parent of any files specified,
|
||||||
|
// which in the case of config.json is '.', which inevitably takes
|
||||||
|
// ages to crawl. So we create our own watcher on the files
|
||||||
|
// instead.
|
||||||
|
const copy = () => {cpx.copy(errCheck)};
|
||||||
|
chokidar.watch(source)
|
||||||
|
.on('add', copy)
|
||||||
|
.on('change', copy)
|
||||||
|
.on('ready', cb)
|
||||||
|
.on('error', errCheck);
|
||||||
|
} else {
|
||||||
|
cpx.on('watch-ready', cb);
|
||||||
|
cpx.on("watch-error", cb);
|
||||||
|
cpx.watch();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cpx.copy(cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next(0);
|
183
scripts/deploy.py
Executable file
@ -0,0 +1,183 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# download and unpack a riot-web tarball.
|
||||||
|
#
|
||||||
|
# Allows `bundles` to be extracted to a common directory, and a link to
|
||||||
|
# config.json to be added.
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tarfile
|
||||||
|
|
||||||
|
try:
|
||||||
|
# python3
|
||||||
|
from urllib.request import urlretrieve
|
||||||
|
except ImportError:
|
||||||
|
# python2
|
||||||
|
from urllib import urlretrieve
|
||||||
|
|
||||||
|
class DeployException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_relative_symlink(linkname, target):
|
||||||
|
relpath = os.path.relpath(target, os.path.dirname(linkname))
|
||||||
|
print ("Symlink %s -> %s" % (linkname, relpath))
|
||||||
|
os.symlink(relpath, linkname)
|
||||||
|
|
||||||
|
|
||||||
|
def move_bundles(source, dest):
|
||||||
|
"""Move the contents of the 'bundles' directory to a common dir
|
||||||
|
|
||||||
|
We check that we will not be overwriting anything before we proceed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source (str): path to 'bundles' within the extracted tarball
|
||||||
|
dest (str): target common directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not os.path.isdir(dest):
|
||||||
|
os.mkdir(dest)
|
||||||
|
|
||||||
|
# build a map from source to destination, checking for non-existence as we go.
|
||||||
|
renames = {}
|
||||||
|
for f in os.listdir(source):
|
||||||
|
dst = os.path.join(dest, f)
|
||||||
|
if os.path.exists(dst):
|
||||||
|
raise DeployException(
|
||||||
|
"Not deploying. The bundle includes '%s' which we have previously deployed."
|
||||||
|
% f
|
||||||
|
)
|
||||||
|
renames[os.path.join(source, f)] = dst
|
||||||
|
|
||||||
|
for (src, dst) in renames.iteritems():
|
||||||
|
print ("Move %s -> %s" % (src, dst))
|
||||||
|
os.rename(src, dst)
|
||||||
|
|
||||||
|
class Deployer:
|
||||||
|
def __init__(self):
|
||||||
|
self.packages_path = "."
|
||||||
|
self.bundles_path = None
|
||||||
|
self.should_clean = False
|
||||||
|
self.config_location = None
|
||||||
|
self.verify_signature = True
|
||||||
|
|
||||||
|
def deploy(self, tarball, extract_path):
|
||||||
|
"""Download a tarball if necessary, and unpack it
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(str) the path to the unpacked deployment
|
||||||
|
"""
|
||||||
|
print("Deploying %s to %s" % (tarball, extract_path))
|
||||||
|
|
||||||
|
name_str = os.path.basename(tarball).replace(".tar.gz", "")
|
||||||
|
extracted_dir = os.path.join(extract_path, name_str)
|
||||||
|
if os.path.exists(extracted_dir):
|
||||||
|
raise DeployException('Cannot unpack %s: %s already exists' % (
|
||||||
|
tarball, extracted_dir))
|
||||||
|
|
||||||
|
downloaded = False
|
||||||
|
if tarball.startswith("http://") or tarball.startswith("https://"):
|
||||||
|
tarball = self.download_and_verify(tarball)
|
||||||
|
print("Downloaded file: %s" % tarball)
|
||||||
|
downloaded = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
with tarfile.open(tarball) as tar:
|
||||||
|
tar.extractall(extract_path)
|
||||||
|
finally:
|
||||||
|
if self.should_clean and downloaded:
|
||||||
|
os.remove(tarball)
|
||||||
|
|
||||||
|
print ("Extracted into: %s" % extracted_dir)
|
||||||
|
|
||||||
|
if self.config_location:
|
||||||
|
create_relative_symlink(
|
||||||
|
target=self.config_location,
|
||||||
|
linkname=os.path.join(extracted_dir, 'config.json')
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.bundles_path:
|
||||||
|
extracted_bundles = os.path.join(extracted_dir, 'bundles')
|
||||||
|
move_bundles(source=extracted_bundles, dest=self.bundles_path)
|
||||||
|
|
||||||
|
# replace the (hopefully now empty) extracted_bundles dir with a
|
||||||
|
# symlink to the common dir.
|
||||||
|
os.rmdir(extracted_bundles)
|
||||||
|
create_relative_symlink(
|
||||||
|
target=self.bundles_path,
|
||||||
|
linkname=extracted_bundles,
|
||||||
|
)
|
||||||
|
return extracted_dir
|
||||||
|
|
||||||
|
def download_and_verify(self, url):
|
||||||
|
tarball = self.download_file(url)
|
||||||
|
|
||||||
|
if self.verify_signature:
|
||||||
|
sigfile = self.download_file(url + ".asc")
|
||||||
|
subprocess.check_call(["gpg", "--verify", sigfile, tarball])
|
||||||
|
|
||||||
|
return tarball
|
||||||
|
|
||||||
|
def download_file(self, url):
|
||||||
|
if not os.path.isdir(self.packages_path):
|
||||||
|
os.mkdir(self.packages_path)
|
||||||
|
local_filename = os.path.join(self.packages_path,
|
||||||
|
url.split('/')[-1])
|
||||||
|
sys.stdout.write("Downloading %s -> %s..." % (url, local_filename))
|
||||||
|
sys.stdout.flush()
|
||||||
|
urlretrieve(url, local_filename)
|
||||||
|
print ("Done")
|
||||||
|
return local_filename
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser("Deploy a Riot build on a web server.")
|
||||||
|
parser.add_argument(
|
||||||
|
"-p", "--packages-dir", default="./packages", help=(
|
||||||
|
"The directory to download the tarball into. (Default: '%(default)s')"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-e", "--extract-path", default="./deploys", help=(
|
||||||
|
"The location to extract .tar.gz files to. (Default: '%(default)s')"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-b", "--bundles-dir", nargs='?', default="./bundles", help=(
|
||||||
|
"A directory to move the contents of the 'bundles' directory to. A \
|
||||||
|
symlink to the bundles directory will also be written inside the \
|
||||||
|
extracted tarball. Example: './bundles'. \
|
||||||
|
(Default: '%(default)s')"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-c", "--clean", action="store_true", default=False, help=(
|
||||||
|
"Remove .tar.gz files after they have been downloaded and extracted. \
|
||||||
|
(Default: %(default)s)"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--config", nargs='?', default='./config.json', help=(
|
||||||
|
"Write a symlink at config.json in the extracted tarball to this \
|
||||||
|
location. (Default: '%(default)s')"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"tarball", help=(
|
||||||
|
"filename of tarball, or URL to download."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
deployer = Deployer()
|
||||||
|
deployer.packages_path = args.packages_dir
|
||||||
|
deployer.bundles_path = args.bundles_dir
|
||||||
|
deployer.should_clean = args.clean
|
||||||
|
deployer.config_location = args.config
|
||||||
|
|
||||||
|
deployer.deploy(args.tarball, args.extract_path)
|
130
scripts/electron-package.sh
Executable file
@ -0,0 +1,130 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 -v <version> -c <config file> [-n]"
|
||||||
|
echo
|
||||||
|
echo "version: commit-ish to check out and build"
|
||||||
|
echo "config file: a path to a json config file to"
|
||||||
|
echo "ship with the build. In addition, update_base_url:"
|
||||||
|
echo "from this file is used to set up auto-update."
|
||||||
|
echo "-n: build with no config file."
|
||||||
|
echo
|
||||||
|
echo "Values may also be passed as environment variables"
|
||||||
|
}
|
||||||
|
|
||||||
|
conffile=
|
||||||
|
version=
|
||||||
|
skipcfg=0
|
||||||
|
while getopts "c:v:n" opt; do
|
||||||
|
case $opt in
|
||||||
|
c)
|
||||||
|
conffile=$OPTARG
|
||||||
|
;;
|
||||||
|
v)
|
||||||
|
version=$OPTARG
|
||||||
|
;;
|
||||||
|
n)
|
||||||
|
skipcfg=1
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "Invalid option: -$OPTARG" >&2
|
||||||
|
usage
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$version" ]; then
|
||||||
|
echo "No version supplied"
|
||||||
|
usage
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$conffile" ] && [ "$skipcfg" = 0 ]; then
|
||||||
|
echo "No config file given. Use -c to supply a config file or"
|
||||||
|
echo "-n to build with no config file (and no auto update)."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$conffile" ]; then
|
||||||
|
update_base_url=`jq -r .update_base_url $conffile`
|
||||||
|
|
||||||
|
if [ -z "$update_base_url" ]; then
|
||||||
|
echo "No update URL supplied. Use update_base_url: null if you really"
|
||||||
|
echo "want a build with no auto-update."
|
||||||
|
usage
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
# Make sure the base URL ends in a slash if it doesn't already
|
||||||
|
update_base_url=`echo $update_base_url | sed -e 's#\([^\/]\)$#\1\/#'`
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f package.json ]; then
|
||||||
|
echo "No package.json found. This script must be run from"
|
||||||
|
echo "the vector-web directory."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building $version using Update base URL $update_base_url"
|
||||||
|
|
||||||
|
projdir=`pwd`
|
||||||
|
builddir=`mktemp -d 2>/dev/null || mktemp -d -t 'buildtmp'`
|
||||||
|
pushd "$builddir"
|
||||||
|
|
||||||
|
git clone "$projdir" .
|
||||||
|
git checkout "$version"
|
||||||
|
|
||||||
|
# Figure out what version we're building
|
||||||
|
vername=`jq -r .version package.json`
|
||||||
|
|
||||||
|
if [ -n "$conffile" ]; then
|
||||||
|
popd
|
||||||
|
cp "$conffile" "$builddir/"
|
||||||
|
pushd "$builddir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
npm install
|
||||||
|
npm run build:electron
|
||||||
|
|
||||||
|
popd
|
||||||
|
|
||||||
|
distdir="$builddir/electron/dist"
|
||||||
|
pubdir="$projdir/electron/pub"
|
||||||
|
rm -r "$pubdir" || true
|
||||||
|
mkdir -p "$pubdir"
|
||||||
|
|
||||||
|
# Install packages: what the user downloads the first time,
|
||||||
|
# (DMGs for mac, exe installer for windows)
|
||||||
|
mkdir -p "$pubdir/install/macos"
|
||||||
|
cp $distdir/mac/*.dmg "$pubdir/install/macos/"
|
||||||
|
|
||||||
|
mkdir -p "$pubdir/install/win32/ia32/"
|
||||||
|
cp $distdir/win-ia32/*.exe "$pubdir/install/win32/ia32/"
|
||||||
|
|
||||||
|
mkdir -p "$pubdir/install/win32/x64/"
|
||||||
|
cp $distdir/win/*.exe "$pubdir/install/win32/x64/"
|
||||||
|
|
||||||
|
# Packages for auto-update
|
||||||
|
mkdir -p "$pubdir/update/macos"
|
||||||
|
cp $distdir/mac/*.zip "$pubdir/update/macos/"
|
||||||
|
echo "$vername" > "$pubdir/update/macos/latest"
|
||||||
|
|
||||||
|
mkdir -p "$pubdir/update/win32/ia32/"
|
||||||
|
cp $distdir/win-ia32/*.nupkg "$pubdir/update/win32/ia32/"
|
||||||
|
cp $distdir/win-ia32/RELEASES "$pubdir/update/win32/ia32/"
|
||||||
|
|
||||||
|
mkdir -p "$pubdir/update/win32/x64/"
|
||||||
|
cp $distdir/win/*.nupkg "$pubdir/update/win32/x64/"
|
||||||
|
cp $distdir/win/RELEASES "$pubdir/update/win32/x64/"
|
||||||
|
|
||||||
|
# Move the debs to the main project dir's dist folder
|
||||||
|
rm -r "$projdir/electron/dist" || true
|
||||||
|
mkdir -p "$projdir/electron/dist"
|
||||||
|
cp $distdir/*.deb "$projdir/electron/dist/"
|
||||||
|
|
||||||
|
rm -rf "$builddir"
|
||||||
|
|
||||||
|
echo "Riot Desktop is ready to go in $pubdir: this directory can be hosted on your web server."
|
||||||
|
echo "deb archives are in electron/dist/ - these should be added into your debian repository"
|
@ -19,12 +19,16 @@ tar -C olm -xz < olm/olm-*.tgz
|
|||||||
rm -r node_modules/olm
|
rm -r node_modules/olm
|
||||||
cp -r olm/package node_modules/olm
|
cp -r olm/package node_modules/olm
|
||||||
|
|
||||||
# we may be using a dev branch of react-sdk, in which case we need to build it
|
# we may be using dev branches of js-sdk and react-sdk, in which case we need to build them
|
||||||
|
(cd node_modules/matrix-js-sdk && npm run build)
|
||||||
(cd node_modules/matrix-react-sdk && npm run build)
|
(cd node_modules/matrix-react-sdk && npm run build)
|
||||||
|
|
||||||
# run the mocha tests
|
# run the mocha tests
|
||||||
npm run test
|
npm run test
|
||||||
|
|
||||||
|
# run eslint
|
||||||
|
npm run lintall -- -f checkstyle -o eslint.xml || true
|
||||||
|
|
||||||
rm dist/vector-*.tar.gz || true # rm previous artifacts without failing if it doesn't exist
|
rm dist/vector-*.tar.gz || true # rm previous artifacts without failing if it doesn't exist
|
||||||
|
|
||||||
# node_modules deps from 'npm install' don't have a .git dir so can't
|
# node_modules deps from 'npm install' don't have a .git dir so can't
|
||||||
|
93
scripts/make-icons.sh
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ $# != 1 ]
|
||||||
|
then
|
||||||
|
echo "Usage: $0 <svg file>"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
tmpdir=`mktemp -d 2>/dev/null || mktemp -d -t 'icontmp'`
|
||||||
|
|
||||||
|
for i in 1024 512 310 256 192 180 152 150 144 128 120 114 96 76 72 70 64 60 57 48 36 32 24 16
|
||||||
|
do
|
||||||
|
#convert -background none -density 1000 -resize $i -extent $i -gravity center "$1" "$tmpdir/$i.png"
|
||||||
|
|
||||||
|
# Above is the imagemagick command to render an svg to png. Unfortunately, its support for SVGs
|
||||||
|
# with CSS isn't very good (with rsvg and even moreso the built in renderer) so we use cairosvg.
|
||||||
|
# This can be installed with:
|
||||||
|
# pip install cairosvg==1.0.22 # Version 2 doesn't support python 2
|
||||||
|
# pip install tinycss
|
||||||
|
# pip install cssselect # These are necessary for CSS support
|
||||||
|
# You'll also need xmlstarlet from your favourite package manager
|
||||||
|
#
|
||||||
|
# Cairosvg doesn't suport rendering at a specific size (https://github.com/Kozea/CairoSVG/issues/83#issuecomment-215720176)
|
||||||
|
# so we have to 'resize the svg' first (add width and height attributes to the svg element) to make it render at the
|
||||||
|
# size we need.
|
||||||
|
# XXX: This will break if the svg already has width and height attributes
|
||||||
|
cp "$1" "$tmpdir/tmp.svg"
|
||||||
|
xmlstarlet ed -N x="http://www.w3.org/2000/svg" --insert "/x:svg" --type attr -n width -v $i "$tmpdir/tmp.svg" > "$tmpdir/tmp2.svg"
|
||||||
|
xmlstarlet ed -N x="http://www.w3.org/2000/svg" --insert "/x:svg" --type attr -n height -v $i "$tmpdir/tmp2.svg" > "$tmpdir/tmp3.svg"
|
||||||
|
cairosvg -f png -o "$tmpdir/$i.png" "$tmpdir/tmp3.svg"
|
||||||
|
rm "$tmpdir/tmp.svg" "$tmpdir/tmp2.svg" "$tmpdir/tmp3.svg"
|
||||||
|
done
|
||||||
|
|
||||||
|
# one more for the non-square mstile
|
||||||
|
cp "$1" "$tmpdir/tmp.svg"
|
||||||
|
xmlstarlet ed -N x="http://www.w3.org/2000/svg" --insert "/x:svg" --type attr -n width -v 310 "$tmpdir/tmp.svg" > "$tmpdir/tmp2.svg"
|
||||||
|
xmlstarlet ed -N x="http://www.w3.org/2000/svg" --insert "/x:svg" --type attr -n height -v 150 "$tmpdir/tmp2.svg" > "$tmpdir/tmp3.svg"
|
||||||
|
cairosvg -f png -o "$tmpdir/310x150.png" "$tmpdir/tmp3.svg"
|
||||||
|
rm "$tmpdir/tmp.svg" "$tmpdir/tmp2.svg" "$tmpdir/tmp3.svg"
|
||||||
|
|
||||||
|
mkdir "$tmpdir/Riot.iconset"
|
||||||
|
cp "$tmpdir/16.png" "$tmpdir/Riot.iconset/icon_16x16.png"
|
||||||
|
cp "$tmpdir/32.png" "$tmpdir/Riot.iconset/icon_16x16@2x.png"
|
||||||
|
cp "$tmpdir/32.png" "$tmpdir/Riot.iconset/icon_32x32.png"
|
||||||
|
cp "$tmpdir/64.png" "$tmpdir/Riot.iconset/icon_32x32@2x.png"
|
||||||
|
cp "$tmpdir/128.png" "$tmpdir/Riot.iconset/icon_128x128.png"
|
||||||
|
cp "$tmpdir/256.png" "$tmpdir/Riot.iconset/icon_128x128@2x.png"
|
||||||
|
cp "$tmpdir/256.png" "$tmpdir/Riot.iconset/icon_256x256.png"
|
||||||
|
cp "$tmpdir/512.png" "$tmpdir/Riot.iconset/icon_256x256@2x.png"
|
||||||
|
cp "$tmpdir/512.png" "$tmpdir/Riot.iconset/icon_512x512.png"
|
||||||
|
cp "$tmpdir/1024.png" "$tmpdir/Riot.iconset/icon_512x512@2x.png"
|
||||||
|
iconutil -c icns -o electron/build/icon.icns "$tmpdir/Riot.iconset"
|
||||||
|
|
||||||
|
cp "$tmpdir/36.png" "res/vector-icons/android-chrome-36x36.png"
|
||||||
|
cp "$tmpdir/48.png" "res/vector-icons/android-chrome-48x48.png"
|
||||||
|
cp "$tmpdir/72.png" "res/vector-icons/android-chrome-72x72.png"
|
||||||
|
cp "$tmpdir/96.png" "res/vector-icons/android-chrome-96x96.png"
|
||||||
|
cp "$tmpdir/144.png" "res/vector-icons/android-chrome-144x144.png"
|
||||||
|
cp "$tmpdir/192.png" "res/vector-icons/android-chrome-192x192.png"
|
||||||
|
cp "$tmpdir/180.png" "res/vector-icons/apple-touch-icon.png"
|
||||||
|
cp "$tmpdir/180.png" "res/vector-icons/apple-touch-icon-precomposed.png"
|
||||||
|
cp "$tmpdir/57.png" "res/vector-icons/apple-touch-icon-57x57.png"
|
||||||
|
cp "$tmpdir/60.png" "res/vector-icons/apple-touch-icon-60x60.png"
|
||||||
|
cp "$tmpdir/72.png" "res/vector-icons/apple-touch-icon-72x72.png"
|
||||||
|
cp "$tmpdir/76.png" "res/vector-icons/apple-touch-icon-76x76.png"
|
||||||
|
cp "$tmpdir/114.png" "res/vector-icons/apple-touch-icon-114x114.png"
|
||||||
|
cp "$tmpdir/120.png" "res/vector-icons/apple-touch-icon-120x120.png"
|
||||||
|
cp "$tmpdir/144.png" "res/vector-icons/apple-touch-icon-144x144.png"
|
||||||
|
cp "$tmpdir/152.png" "res/vector-icons/apple-touch-icon-152x152.png"
|
||||||
|
cp "$tmpdir/180.png" "res/vector-icons/apple-touch-icon-180x180.png"
|
||||||
|
cp "$tmpdir/16.png" "res/vector-icons/favicon-16x16.png"
|
||||||
|
cp "$tmpdir/32.png" "res/vector-icons/favicon-32x32.png"
|
||||||
|
cp "$tmpdir/96.png" "res/vector-icons/favicon-96x96.png"
|
||||||
|
cp "$tmpdir/70.png" "res/vector-icons/mstile-70x70.png"
|
||||||
|
cp "$tmpdir/144.png" "res/vector-icons/mstile-144x144.png"
|
||||||
|
cp "$tmpdir/150.png" "res/vector-icons/mstile-150x150.png"
|
||||||
|
cp "$tmpdir/310.png" "res/vector-icons/mstile-310x310.png"
|
||||||
|
cp "$tmpdir/310x150.png" "res/vector-icons/mstile-310x150.png"
|
||||||
|
|
||||||
|
convert "$tmpdir/16.png" "$tmpdir/32.png" "$tmpdir/64.png" "$tmpdir/128.png" "$tmpdir/256.png" "res/vector-icons/favicon.ico"
|
||||||
|
|
||||||
|
cp "res/vector-icons/favicon.ico" "electron/build/icon.ico"
|
||||||
|
|
||||||
|
# https://github.com/electron-userland/electron-builder/blob/3f97b86993d4ea5172e562b182230a194de0f621/src/targets/LinuxTargetHelper.ts#L127
|
||||||
|
for i in 24 96 16 48 64 128 256 512
|
||||||
|
do
|
||||||
|
cp "$tmpdir/$i.png" "electron/build/icons/${i}x${i}.png"
|
||||||
|
done
|
||||||
|
|
||||||
|
rm -r "$tmpdir"
|
@ -15,6 +15,11 @@ fi
|
|||||||
|
|
||||||
npm run clean
|
npm run clean
|
||||||
npm run build$dev
|
npm run build$dev
|
||||||
|
|
||||||
|
# include the sample config in the tarball. Arguably this should be done by
|
||||||
|
# `npm run build`, but it's just too painful.
|
||||||
|
cp config.sample.json webapp/
|
||||||
|
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
cp -r webapp vector-$version
|
cp -r webapp vector-$version
|
||||||
echo $version > vector-$version/version
|
echo $version > vector-$version/version
|
||||||
|
@ -1,26 +1,30 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# auto-deploy script for https://riot.im/develop
|
||||||
|
#
|
||||||
|
# Listens for HTTP hits. When it gets one, downloads the artifact from jenkins
|
||||||
|
# and deploys it as the new version.
|
||||||
|
#
|
||||||
|
# Requires the following python packages:
|
||||||
|
#
|
||||||
|
# - requests
|
||||||
|
# - flask
|
||||||
|
#
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import json, requests, tarfile, argparse, os, errno
|
import json, requests, tarfile, argparse, os, errno
|
||||||
|
import time
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
|
|
||||||
from flask import Flask, jsonify, request, abort
|
from flask import Flask, jsonify, request, abort
|
||||||
|
|
||||||
|
from deploy import Deployer, DeployException
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
arg_jenkins_url, arg_extract_path, arg_should_clean, arg_symlink, arg_config_location = (
|
arg_jenkins_url = None
|
||||||
None, None, None, None, None
|
deployer = None
|
||||||
)
|
arg_extract_path = None
|
||||||
|
arg_symlink = None
|
||||||
def download_file(url):
|
|
||||||
local_filename = url.split('/')[-1]
|
|
||||||
r = requests.get(url, stream=True)
|
|
||||||
with open(local_filename, 'wb') as f:
|
|
||||||
for chunk in r.iter_content(chunk_size=1024):
|
|
||||||
if chunk: # filter out keep-alive new chunks
|
|
||||||
f.write(chunk)
|
|
||||||
return local_filename
|
|
||||||
|
|
||||||
def untar_to(tarball, dest):
|
|
||||||
with tarfile.open(tarball) as tar:
|
|
||||||
tar.extractall(dest)
|
|
||||||
|
|
||||||
def create_symlink(source, linkname):
|
def create_symlink(source, linkname):
|
||||||
try:
|
try:
|
||||||
@ -57,6 +61,9 @@ def on_receive_jenkins_poke():
|
|||||||
abort(400, "Missing or bad build number")
|
abort(400, "Missing or bad build number")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
return fetch_jenkins_build(job_name, build_num)
|
||||||
|
|
||||||
|
def fetch_jenkins_build(job_name, build_num):
|
||||||
artifact_url = urljoin(
|
artifact_url = urljoin(
|
||||||
arg_jenkins_url, "job/%s/%s/api/json" % (job_name, build_num)
|
arg_jenkins_url, "job/%s/%s/api/json" % (job_name, build_num)
|
||||||
)
|
)
|
||||||
@ -106,28 +113,45 @@ def on_receive_jenkins_poke():
|
|||||||
arg_jenkins_url, "job/%s/%s/artifact/%s" % (job_name, build_num, tar_gz_path)
|
arg_jenkins_url, "job/%s/%s/artifact/%s" % (job_name, build_num, tar_gz_path)
|
||||||
)
|
)
|
||||||
|
|
||||||
print("Retrieving .tar.gz file: %s" % tar_gz_url)
|
# we extract into a directory based on the build number. This avoids the
|
||||||
filename = download_file(tar_gz_url)
|
# problem of multiple builds building the same git version and thus having
|
||||||
print("Downloaded file: %s" % filename)
|
# the same tarball name. That would lead to two potential problems:
|
||||||
name_str = filename.replace(".tar.gz", "")
|
# (a) sometimes jenkins serves corrupted artifacts; we would replace
|
||||||
untar_to(filename, arg_extract_path)
|
# a good deploy with a bad one
|
||||||
|
# (b) we'll be overwriting the live deployment, which means people might
|
||||||
extracted_dir = os.path.join(arg_extract_path, name_str)
|
# see half-written files.
|
||||||
|
build_dir = os.path.join(arg_extract_path, "%s-#%s" % (job_name, build_num))
|
||||||
if arg_should_clean:
|
try:
|
||||||
os.remove(filename)
|
extracted_dir = deploy_tarball(tar_gz_url, build_dir)
|
||||||
|
except DeployException as e:
|
||||||
|
abort(400, e.message)
|
||||||
|
|
||||||
create_symlink(source=extracted_dir, linkname=arg_symlink)
|
create_symlink(source=extracted_dir, linkname=arg_symlink)
|
||||||
|
|
||||||
if arg_config_location:
|
|
||||||
create_symlink(source=arg_config_location, linkname=os.path.join(extracted_dir, 'config.json'))
|
|
||||||
|
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
|
def deploy_tarball(tar_gz_url, build_dir):
|
||||||
|
"""Download a tarball from jenkins and unpack it
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(str) the path to the unpacked deployment
|
||||||
|
"""
|
||||||
|
if os.path.exists(build_dir):
|
||||||
|
raise DeployException(
|
||||||
|
"Not deploying. We have previously deployed this build."
|
||||||
|
)
|
||||||
|
os.mkdir(build_dir)
|
||||||
|
|
||||||
|
# we rely on the fact that flask only serves one request at a time to
|
||||||
|
# ensure that we do not overwrite a tarball from a concurrent request.
|
||||||
|
|
||||||
|
return deployer.deploy(tar_gz_url, build_dir)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser("Runs a Vector redeployment server.")
|
parser = argparse.ArgumentParser("Runs a Vector redeployment server.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-j", "--jenkins", dest="jenkins", default="http://matrix.org/jenkins/", help=(
|
"-j", "--jenkins", dest="jenkins", default="https://matrix.org/jenkins/", help=(
|
||||||
"The base URL of the Jenkins web server. This will be hit to get the\
|
"The base URL of the Jenkins web server. This will be hit to get the\
|
||||||
built artifacts (the .gz file) for redeploying."
|
built artifacts (the .gz file) for redeploying."
|
||||||
)
|
)
|
||||||
@ -142,6 +166,13 @@ if __name__ == "__main__":
|
|||||||
"The location to extract .tar.gz files to."
|
"The location to extract .tar.gz files to."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-b", "--bundles-dir", dest="bundles_dir", help=(
|
||||||
|
"A directory to move the contents of the 'bundles' directory to. A \
|
||||||
|
symlink to the bundles directory will also be written inside the \
|
||||||
|
extracted tarball. Example: './bundles'."
|
||||||
|
)
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-c", "--clean", dest="clean", action="store_true", default=False, help=(
|
"-c", "--clean", dest="clean", action="store_true", default=False, help=(
|
||||||
"Remove .tar.gz files after they have been downloaded and extracted."
|
"Remove .tar.gz files after they have been downloaded and extracted."
|
||||||
@ -160,18 +191,47 @@ if __name__ == "__main__":
|
|||||||
To this location."
|
To this location."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--test", dest="tarball_uri", help=(
|
||||||
|
"Don't start an HTTP listener. Instead download a build from Jenkins \
|
||||||
|
immediately."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.jenkins.endswith("/"): # important for urljoin
|
if args.jenkins.endswith("/"): # important for urljoin
|
||||||
arg_jenkins_url = args.jenkins
|
arg_jenkins_url = args.jenkins
|
||||||
else:
|
else:
|
||||||
arg_jenkins_url = args.jenkins + "/"
|
arg_jenkins_url = args.jenkins + "/"
|
||||||
arg_extract_path = args.extract
|
arg_extract_path = args.extract
|
||||||
arg_should_clean = args.clean
|
|
||||||
arg_symlink = args.symlink
|
arg_symlink = args.symlink
|
||||||
arg_config_location = args.config
|
|
||||||
|
if not os.path.isdir(arg_extract_path):
|
||||||
|
os.mkdir(arg_extract_path)
|
||||||
|
|
||||||
|
deployer = Deployer()
|
||||||
|
deployer.bundles_path = args.bundles_dir
|
||||||
|
deployer.should_clean = args.clean
|
||||||
|
deployer.config_location = args.config
|
||||||
|
|
||||||
|
# we don't pgp-sign jenkins artifacts; instead we rely on HTTPS access to
|
||||||
|
# the jenkins server (and the jenkins server not being compromised and/or
|
||||||
|
# github not serving it compromised source). If that's not good enough for
|
||||||
|
# you, don't use riot.im/develop.
|
||||||
|
deployer.verify_signature = False
|
||||||
|
|
||||||
|
if args.tarball_uri is not None:
|
||||||
|
build_dir = os.path.join(arg_extract_path, "test-%i" % (time.time()))
|
||||||
|
deploy_tarball(args.tarball_uri, build_dir)
|
||||||
|
else:
|
||||||
print(
|
print(
|
||||||
"Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s. Config location: %s" %
|
"Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s. Config location: %s" %
|
||||||
(args.port, arg_extract_path,
|
(args.port,
|
||||||
" (clean after)" if arg_should_clean else "", arg_symlink, arg_jenkins_url, arg_config_location)
|
arg_extract_path,
|
||||||
|
" (clean after)" if deployer.should_clean else "",
|
||||||
|
arg_symlink,
|
||||||
|
arg_jenkins_url,
|
||||||
|
deployer.config_location,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
app.run(host="0.0.0.0", port=args.port, debug=True)
|
app.run(host="0.0.0.0", port=args.port, debug=True)
|
||||||
|
@ -27,62 +27,64 @@ limitations under the License.
|
|||||||
module.exports.components = require('matrix-react-sdk/lib/component-index').components;
|
module.exports.components = require('matrix-react-sdk/lib/component-index').components;
|
||||||
|
|
||||||
import structures$BottomLeftMenu from './components/structures/BottomLeftMenu';
|
import structures$BottomLeftMenu from './components/structures/BottomLeftMenu';
|
||||||
module.exports.components['structures.BottomLeftMenu'] = structures$BottomLeftMenu;
|
structures$BottomLeftMenu && (module.exports.components['structures.BottomLeftMenu'] = structures$BottomLeftMenu);
|
||||||
import structures$CompatibilityPage from './components/structures/CompatibilityPage';
|
import structures$CompatibilityPage from './components/structures/CompatibilityPage';
|
||||||
module.exports.components['structures.CompatibilityPage'] = structures$CompatibilityPage;
|
structures$CompatibilityPage && (module.exports.components['structures.CompatibilityPage'] = structures$CompatibilityPage);
|
||||||
import structures$LeftPanel from './components/structures/LeftPanel';
|
import structures$LeftPanel from './components/structures/LeftPanel';
|
||||||
module.exports.components['structures.LeftPanel'] = structures$LeftPanel;
|
structures$LeftPanel && (module.exports.components['structures.LeftPanel'] = structures$LeftPanel);
|
||||||
import structures$RightPanel from './components/structures/RightPanel';
|
import structures$RightPanel from './components/structures/RightPanel';
|
||||||
module.exports.components['structures.RightPanel'] = structures$RightPanel;
|
structures$RightPanel && (module.exports.components['structures.RightPanel'] = structures$RightPanel);
|
||||||
import structures$HomePage from './components/structures/HomePage';
|
import structures$HomePage from './components/structures/HomePage';
|
||||||
module.exports.components['structures.HomePage'] = structures$HomePage;
|
structures$HomePage && (module.exports.components['structures.HomePage'] = structures$HomePage);
|
||||||
import structures$RoomDirectory from './components/structures/RoomDirectory';
|
import structures$RoomDirectory from './components/structures/RoomDirectory';
|
||||||
module.exports.components['structures.RoomDirectory'] = structures$RoomDirectory;
|
structures$RoomDirectory && (module.exports.components['structures.RoomDirectory'] = structures$RoomDirectory);
|
||||||
import structures$RoomSubList from './components/structures/RoomSubList';
|
import structures$RoomSubList from './components/structures/RoomSubList';
|
||||||
module.exports.components['structures.RoomSubList'] = structures$RoomSubList;
|
structures$RoomSubList && (module.exports.components['structures.RoomSubList'] = structures$RoomSubList);
|
||||||
import structures$SearchBox from './components/structures/SearchBox';
|
import structures$SearchBox from './components/structures/SearchBox';
|
||||||
module.exports.components['structures.SearchBox'] = structures$SearchBox;
|
structures$SearchBox && (module.exports.components['structures.SearchBox'] = structures$SearchBox);
|
||||||
import structures$ViewSource from './components/structures/ViewSource';
|
import structures$ViewSource from './components/structures/ViewSource';
|
||||||
module.exports.components['structures.ViewSource'] = structures$ViewSource;
|
structures$ViewSource && (module.exports.components['structures.ViewSource'] = structures$ViewSource);
|
||||||
import views$context_menus$MessageContextMenu from './components/views/context_menus/MessageContextMenu';
|
import views$context_menus$MessageContextMenu from './components/views/context_menus/MessageContextMenu';
|
||||||
module.exports.components['views.context_menus.MessageContextMenu'] = views$context_menus$MessageContextMenu;
|
views$context_menus$MessageContextMenu && (module.exports.components['views.context_menus.MessageContextMenu'] = views$context_menus$MessageContextMenu);
|
||||||
import views$context_menus$NotificationStateContextMenu from './components/views/context_menus/NotificationStateContextMenu';
|
import views$context_menus$NotificationStateContextMenu from './components/views/context_menus/NotificationStateContextMenu';
|
||||||
module.exports.components['views.context_menus.NotificationStateContextMenu'] = views$context_menus$NotificationStateContextMenu;
|
views$context_menus$NotificationStateContextMenu && (module.exports.components['views.context_menus.NotificationStateContextMenu'] = views$context_menus$NotificationStateContextMenu);
|
||||||
import views$context_menus$RoomTagContextMenu from './components/views/context_menus/RoomTagContextMenu';
|
import views$context_menus$RoomTagContextMenu from './components/views/context_menus/RoomTagContextMenu';
|
||||||
module.exports.components['views.context_menus.RoomTagContextMenu'] = views$context_menus$RoomTagContextMenu;
|
views$context_menus$RoomTagContextMenu && (module.exports.components['views.context_menus.RoomTagContextMenu'] = views$context_menus$RoomTagContextMenu);
|
||||||
|
import views$dialogs$BugReportDialog from './components/views/dialogs/BugReportDialog';
|
||||||
|
views$dialogs$BugReportDialog && (module.exports.components['views.dialogs.BugReportDialog'] = views$dialogs$BugReportDialog);
|
||||||
import views$dialogs$ChangelogDialog from './components/views/dialogs/ChangelogDialog';
|
import views$dialogs$ChangelogDialog from './components/views/dialogs/ChangelogDialog';
|
||||||
module.exports.components['views.dialogs.ChangelogDialog'] = views$dialogs$ChangelogDialog;
|
views$dialogs$ChangelogDialog && (module.exports.components['views.dialogs.ChangelogDialog'] = views$dialogs$ChangelogDialog);
|
||||||
import views$directory$NetworkDropdown from './components/views/directory/NetworkDropdown';
|
import views$directory$NetworkDropdown from './components/views/directory/NetworkDropdown';
|
||||||
module.exports.components['views.directory.NetworkDropdown'] = views$directory$NetworkDropdown;
|
views$directory$NetworkDropdown && (module.exports.components['views.directory.NetworkDropdown'] = views$directory$NetworkDropdown);
|
||||||
import views$elements$ImageView from './components/views/elements/ImageView';
|
import views$elements$ImageView from './components/views/elements/ImageView';
|
||||||
module.exports.components['views.elements.ImageView'] = views$elements$ImageView;
|
views$elements$ImageView && (module.exports.components['views.elements.ImageView'] = views$elements$ImageView);
|
||||||
import views$elements$Spinner from './components/views/elements/Spinner';
|
import views$elements$Spinner from './components/views/elements/Spinner';
|
||||||
module.exports.components['views.elements.Spinner'] = views$elements$Spinner;
|
views$elements$Spinner && (module.exports.components['views.elements.Spinner'] = views$elements$Spinner);
|
||||||
import views$globals$GuestWarningBar from './components/views/globals/GuestWarningBar';
|
import views$globals$GuestWarningBar from './components/views/globals/GuestWarningBar';
|
||||||
module.exports.components['views.globals.GuestWarningBar'] = views$globals$GuestWarningBar;
|
views$globals$GuestWarningBar && (module.exports.components['views.globals.GuestWarningBar'] = views$globals$GuestWarningBar);
|
||||||
import views$globals$MatrixToolbar from './components/views/globals/MatrixToolbar';
|
import views$globals$MatrixToolbar from './components/views/globals/MatrixToolbar';
|
||||||
module.exports.components['views.globals.MatrixToolbar'] = views$globals$MatrixToolbar;
|
views$globals$MatrixToolbar && (module.exports.components['views.globals.MatrixToolbar'] = views$globals$MatrixToolbar);
|
||||||
import views$globals$NewVersionBar from './components/views/globals/NewVersionBar';
|
import views$globals$NewVersionBar from './components/views/globals/NewVersionBar';
|
||||||
module.exports.components['views.globals.NewVersionBar'] = views$globals$NewVersionBar;
|
views$globals$NewVersionBar && (module.exports.components['views.globals.NewVersionBar'] = views$globals$NewVersionBar);
|
||||||
import views$login$VectorCustomServerDialog from './components/views/login/VectorCustomServerDialog';
|
import views$login$VectorCustomServerDialog from './components/views/login/VectorCustomServerDialog';
|
||||||
module.exports.components['views.login.VectorCustomServerDialog'] = views$login$VectorCustomServerDialog;
|
views$login$VectorCustomServerDialog && (module.exports.components['views.login.VectorCustomServerDialog'] = views$login$VectorCustomServerDialog);
|
||||||
import views$login$VectorLoginFooter from './components/views/login/VectorLoginFooter';
|
import views$login$VectorLoginFooter from './components/views/login/VectorLoginFooter';
|
||||||
module.exports.components['views.login.VectorLoginFooter'] = views$login$VectorLoginFooter;
|
views$login$VectorLoginFooter && (module.exports.components['views.login.VectorLoginFooter'] = views$login$VectorLoginFooter);
|
||||||
import views$login$VectorLoginHeader from './components/views/login/VectorLoginHeader';
|
import views$login$VectorLoginHeader from './components/views/login/VectorLoginHeader';
|
||||||
module.exports.components['views.login.VectorLoginHeader'] = views$login$VectorLoginHeader;
|
views$login$VectorLoginHeader && (module.exports.components['views.login.VectorLoginHeader'] = views$login$VectorLoginHeader);
|
||||||
import views$messages$DateSeparator from './components/views/messages/DateSeparator';
|
import views$messages$DateSeparator from './components/views/messages/DateSeparator';
|
||||||
module.exports.components['views.messages.DateSeparator'] = views$messages$DateSeparator;
|
views$messages$DateSeparator && (module.exports.components['views.messages.DateSeparator'] = views$messages$DateSeparator);
|
||||||
import views$messages$MessageTimestamp from './components/views/messages/MessageTimestamp';
|
import views$messages$MessageTimestamp from './components/views/messages/MessageTimestamp';
|
||||||
module.exports.components['views.messages.MessageTimestamp'] = views$messages$MessageTimestamp;
|
views$messages$MessageTimestamp && (module.exports.components['views.messages.MessageTimestamp'] = views$messages$MessageTimestamp);
|
||||||
import views$rooms$DNDRoomTile from './components/views/rooms/DNDRoomTile';
|
import views$rooms$DNDRoomTile from './components/views/rooms/DNDRoomTile';
|
||||||
module.exports.components['views.rooms.DNDRoomTile'] = views$rooms$DNDRoomTile;
|
views$rooms$DNDRoomTile && (module.exports.components['views.rooms.DNDRoomTile'] = views$rooms$DNDRoomTile);
|
||||||
import views$rooms$RoomDropTarget from './components/views/rooms/RoomDropTarget';
|
import views$rooms$RoomDropTarget from './components/views/rooms/RoomDropTarget';
|
||||||
module.exports.components['views.rooms.RoomDropTarget'] = views$rooms$RoomDropTarget;
|
views$rooms$RoomDropTarget && (module.exports.components['views.rooms.RoomDropTarget'] = views$rooms$RoomDropTarget);
|
||||||
import views$rooms$RoomTooltip from './components/views/rooms/RoomTooltip';
|
import views$rooms$RoomTooltip from './components/views/rooms/RoomTooltip';
|
||||||
module.exports.components['views.rooms.RoomTooltip'] = views$rooms$RoomTooltip;
|
views$rooms$RoomTooltip && (module.exports.components['views.rooms.RoomTooltip'] = views$rooms$RoomTooltip);
|
||||||
import views$rooms$SearchBar from './components/views/rooms/SearchBar';
|
import views$rooms$SearchBar from './components/views/rooms/SearchBar';
|
||||||
module.exports.components['views.rooms.SearchBar'] = views$rooms$SearchBar;
|
views$rooms$SearchBar && (module.exports.components['views.rooms.SearchBar'] = views$rooms$SearchBar);
|
||||||
import views$settings$IntegrationsManager from './components/views/settings/IntegrationsManager';
|
import views$settings$IntegrationsManager from './components/views/settings/IntegrationsManager';
|
||||||
module.exports.components['views.settings.IntegrationsManager'] = views$settings$IntegrationsManager;
|
views$settings$IntegrationsManager && (module.exports.components['views.settings.IntegrationsManager'] = views$settings$IntegrationsManager);
|
||||||
import views$settings$Notifications from './components/views/settings/Notifications';
|
import views$settings$Notifications from './components/views/settings/Notifications';
|
||||||
module.exports.components['views.settings.Notifications'] = views$settings$Notifications;
|
views$settings$Notifications && (module.exports.components['views.settings.Notifications'] = views$settings$Notifications);
|
||||||
|
@ -45,10 +45,8 @@ module.exports = React.createClass({
|
|||||||
available or experimental in your current browser.
|
available or experimental in your current browser.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Please install <a href="https://www.google.com/chrome">Chrome</a> or
|
Please install <a href="https://www.google.com/chrome">Chrome</a> or <a href="https://getfirefox.com">Firefox</a> for
|
||||||
<a href="https://getfirefox.com">Firefox</a> for the best experience.
|
the best experience. <a href="http://apple.com/safari">Safari</a> and <a href="http://opera.com">Opera</a> work too.
|
||||||
<a href="http://apple.com/safari">Safari</a> and
|
|
||||||
<a href="http://opera.com">Opera</a> work too.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
With your current browser, the look and feel of the application may
|
With your current browser, the look and feel of the application may
|
||||||
|
@ -31,6 +31,8 @@ var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix');
|
|||||||
var sanitizeHtml = require('sanitize-html');
|
var sanitizeHtml = require('sanitize-html');
|
||||||
var q = require('q');
|
var q = require('q');
|
||||||
|
|
||||||
|
import {instanceForInstanceId, protocolNameForInstanceId} from '../../utils/DirectoryUtils';
|
||||||
|
|
||||||
linkifyMatrix(linkify);
|
linkifyMatrix(linkify);
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
@ -42,9 +44,7 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
getDefaultProps: function() {
|
getDefaultProps: function() {
|
||||||
return {
|
return {
|
||||||
config: {
|
config: {},
|
||||||
networks: [],
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -52,36 +52,26 @@ module.exports = React.createClass({
|
|||||||
return {
|
return {
|
||||||
publicRooms: [],
|
publicRooms: [],
|
||||||
loading: true,
|
loading: true,
|
||||||
network: null,
|
protocolsLoading: true,
|
||||||
|
instanceId: null,
|
||||||
|
includeAll: false,
|
||||||
roomServer: null,
|
roomServer: null,
|
||||||
filterString: null,
|
filterString: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
// precompile Regexps
|
|
||||||
this.portalRoomPatterns = {};
|
|
||||||
this.nativePatterns = {};
|
|
||||||
if (this.props.config.networks) {
|
|
||||||
for (const network of Object.keys(this.props.config.networks)) {
|
|
||||||
const network_info = this.props.config.networks[network];
|
|
||||||
if (network_info.portalRoomPattern) {
|
|
||||||
this.portalRoomPatterns[network] = new RegExp(network_info.portalRoomPattern);
|
|
||||||
}
|
|
||||||
if (network_info.nativePattern) {
|
|
||||||
this.nativePatterns[network] = new RegExp(network_info.nativePattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.nextBatch = null;
|
this.nextBatch = null;
|
||||||
this.filterTimeout = null;
|
this.filterTimeout = null;
|
||||||
this.scrollPanel = null;
|
this.scrollPanel = null;
|
||||||
this.protocols = null;
|
this.protocols = null;
|
||||||
|
|
||||||
|
this.setState({protocolsLoading: true});
|
||||||
MatrixClientPeg.get().getThirdpartyProtocols().done((response) => {
|
MatrixClientPeg.get().getThirdpartyProtocols().done((response) => {
|
||||||
this.protocols = response;
|
this.protocols = response;
|
||||||
|
this.setState({protocolsLoading: false});
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
|
this.setState({protocolsLoading: false});
|
||||||
if (MatrixClientPeg.get().isGuest()) {
|
if (MatrixClientPeg.get().isGuest()) {
|
||||||
// Guests currently aren't allowed to use this API, so
|
// Guests currently aren't allowed to use this API, so
|
||||||
// ignore this as otherwise this error is literally the
|
// ignore this as otherwise this error is literally the
|
||||||
@ -131,6 +121,11 @@ module.exports = React.createClass({
|
|||||||
if (my_server != MatrixClientPeg.getHomeServerName()) {
|
if (my_server != MatrixClientPeg.getHomeServerName()) {
|
||||||
opts.server = my_server;
|
opts.server = my_server;
|
||||||
}
|
}
|
||||||
|
if (this.state.instanceId) {
|
||||||
|
opts.third_party_instance_id = this.state.instanceId;
|
||||||
|
} else if (this.state.includeAll) {
|
||||||
|
opts.include_all_networks = true;
|
||||||
|
}
|
||||||
if (this.nextBatch) opts.since = this.nextBatch;
|
if (this.nextBatch) opts.since = this.nextBatch;
|
||||||
if (my_filter_string) opts.filter = { generic_search_term: my_filter_string } ;
|
if (my_filter_string) opts.filter = { generic_search_term: my_filter_string } ;
|
||||||
return MatrixClientPeg.get().publicRooms(opts).then((data) => {
|
return MatrixClientPeg.get().publicRooms(opts).then((data) => {
|
||||||
@ -231,7 +226,7 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onOptionChange: function(server, network) {
|
onOptionChange: function(server, instanceId, includeAll) {
|
||||||
// clear next batch so we don't try to load more rooms
|
// clear next batch so we don't try to load more rooms
|
||||||
this.nextBatch = null;
|
this.nextBatch = null;
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -240,7 +235,8 @@ module.exports = React.createClass({
|
|||||||
// to clear the list anyway.
|
// to clear the list anyway.
|
||||||
publicRooms: [],
|
publicRooms: [],
|
||||||
roomServer: server,
|
roomServer: server,
|
||||||
network: network,
|
instanceId: instanceId,
|
||||||
|
includeAll: includeAll,
|
||||||
}, this.refreshRoomList);
|
}, this.refreshRoomList);
|
||||||
// We also refresh the room list each time even though this
|
// We also refresh the room list each time even though this
|
||||||
// filtering is client-side. It hopefully won't be client side
|
// filtering is client-side. It hopefully won't be client side
|
||||||
@ -271,7 +267,7 @@ module.exports = React.createClass({
|
|||||||
this.filterTimeout = setTimeout(() => {
|
this.filterTimeout = setTimeout(() => {
|
||||||
this.filterTimeout = null;
|
this.filterTimeout = null;
|
||||||
this.refreshRoomList();
|
this.refreshRoomList();
|
||||||
}, 300);
|
}, 700);
|
||||||
},
|
},
|
||||||
|
|
||||||
onFilterClear: function() {
|
onFilterClear: function() {
|
||||||
@ -286,14 +282,19 @@ module.exports = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onJoinClick: function(alias) {
|
onJoinClick: function(alias) {
|
||||||
// If we're on the 'Matrix' network (or all networks),
|
// If we don't have a particular instance id selected, just show that rooms alias
|
||||||
// just show that rooms alias
|
if (!this.state.instanceId) {
|
||||||
if (this.state.network == null || this.state.network == '_matrix') {
|
// If the user specified an alias without a domain, add on whichever server is selected
|
||||||
|
// in the dropdown
|
||||||
|
if (alias.indexOf(':') == -1) {
|
||||||
|
alias = alias + ':' + this.state.roomServer;
|
||||||
|
}
|
||||||
this.showRoomAlias(alias);
|
this.showRoomAlias(alias);
|
||||||
} else {
|
} else {
|
||||||
// This is a 3rd party protocol. Let's see if we
|
// This is a 3rd party protocol. Let's see if we can join it
|
||||||
// can join it
|
const protocolName = protocolNameForInstanceId(this.protocols, this.state.instanceId);
|
||||||
const fields = this._getFieldsForThirdPartyLocation(alias, this.state.network);
|
const instance = instanceForInstanceId(this.protocols, this.state.instanceId);
|
||||||
|
const fields = protocolName ? this._getFieldsForThirdPartyLocation(alias, this.protocols[protocolName], instance) : null;
|
||||||
if (!fields) {
|
if (!fields) {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
@ -302,8 +303,7 @@ module.exports = React.createClass({
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const protocol = this._protocolForThirdPartyNetwork(this.state.network);
|
MatrixClientPeg.get().getThirdpartyLocation(protocolName, fields).done((resp) => {
|
||||||
MatrixClientPeg.get().getThirdpartyLocation(protocol, fields).done((resp) => {
|
|
||||||
if (resp.length > 0 && resp[0].alias) {
|
if (resp.length > 0 && resp[0].alias) {
|
||||||
this.showRoomAlias(resp[0].alias);
|
this.showRoomAlias(resp[0].alias);
|
||||||
} else {
|
} else {
|
||||||
@ -372,13 +372,7 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
if (!this.state.publicRooms) return [];
|
if (!this.state.publicRooms) return [];
|
||||||
|
|
||||||
var rooms = this.state.publicRooms.filter((a) => {
|
var rooms = this.state.publicRooms;
|
||||||
if (this.state.network) {
|
|
||||||
if (!this._isRoomInNetwork(a, this.state.roomServer, this.state.network)) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
var rows = [];
|
var rows = [];
|
||||||
var self = this;
|
var self = this;
|
||||||
var guestRead, guestJoin, perms;
|
var guestRead, guestJoin, perms;
|
||||||
@ -440,119 +434,46 @@ module.exports = React.createClass({
|
|||||||
this.scrollPanel = element;
|
this.scrollPanel = element;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
_stringLooksLikeId: function(s, field_type) {
|
||||||
* Terrible temporary function that guess what network a public room
|
|
||||||
* entry is in, until synapse is able to tell us
|
|
||||||
*/
|
|
||||||
_isRoomInNetwork: function(room, server, network) {
|
|
||||||
// We carve rooms into two categories here. 'portal' rooms are
|
|
||||||
// rooms created by a user joining a bridge 'portal' alias to
|
|
||||||
// participate in that room or a foreign network. A room is a
|
|
||||||
// portal room if it has exactly one alias and that alias matches
|
|
||||||
// a pattern defined in the config. Its network is the key
|
|
||||||
// of the pattern that it matches.
|
|
||||||
// All other rooms are considered 'native matrix' rooms, and
|
|
||||||
// go into the special '_matrix' network.
|
|
||||||
|
|
||||||
let roomNetwork = '_matrix';
|
|
||||||
if (room.aliases && room.aliases.length == 1) {
|
|
||||||
if (this.props.config.serverConfig && this.props.config.serverConfig[server] && this.props.config.serverConfig[server].networks) {
|
|
||||||
for (const n of this.props.config.serverConfig[server].networks) {
|
|
||||||
const pat = this.portalRoomPatterns[n];
|
|
||||||
if (pat && pat.test(room.aliases[0])) {
|
|
||||||
roomNetwork = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return roomNetwork == network;
|
|
||||||
},
|
|
||||||
|
|
||||||
_stringLooksLikeId: function(s, network) {
|
|
||||||
let pat = /^#[^\s]+:[^\s]/;
|
let pat = /^#[^\s]+:[^\s]/;
|
||||||
if (
|
if (field_type && field_type.regexp) {
|
||||||
network && network != '_matrix' &&
|
pat = new RegExp(field_type.regexp);
|
||||||
this.nativePatterns[network]
|
|
||||||
) {
|
|
||||||
pat = this.nativePatterns[network];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pat.test(s);
|
return pat.test(s);
|
||||||
},
|
},
|
||||||
|
|
||||||
_protocolForThirdPartyNetwork: function(network) {
|
_getFieldsForThirdPartyLocation: function(userInput, protocol, instance) {
|
||||||
if (
|
// make an object with the fields specified by that protocol. We
|
||||||
this.props.config.networks &&
|
|
||||||
this.props.config.networks[network] &&
|
|
||||||
this.props.config.networks[network].protocol
|
|
||||||
) {
|
|
||||||
return this.props.config.networks[network].protocol;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_getFieldsForThirdPartyLocation: function(user_input, network) {
|
|
||||||
if (!this.props.config.networks || !this.props.config.networks[network]) return null;
|
|
||||||
|
|
||||||
const network_info = this.props.config.networks[network];
|
|
||||||
if (!network_info.protocol) return null;
|
|
||||||
|
|
||||||
if (!this.protocols) return null;
|
|
||||||
|
|
||||||
let matched_instance;
|
|
||||||
// Try to find which instance in the 'protocols' response
|
|
||||||
// matches this network. We look for a matching protocol
|
|
||||||
// and the existence of a 'domain' field and if present,
|
|
||||||
// its value.
|
|
||||||
if (
|
|
||||||
this.protocols[network_info.protocol] &&
|
|
||||||
this.protocols[network_info.protocol].instances &&
|
|
||||||
this.protocols[network_info.protocol].instances.length == 1
|
|
||||||
) {
|
|
||||||
const the_instance = this.protocols[network_info.protocol].instances[0];
|
|
||||||
// If there's only one instance in this protocol, use it
|
|
||||||
// as long as it has no domain (which we assume to mean it's
|
|
||||||
// there is only one possible instance).
|
|
||||||
if (
|
|
||||||
(
|
|
||||||
the_instance.fields.domain === undefined &&
|
|
||||||
network_info.domain === undefined
|
|
||||||
) ||
|
|
||||||
(
|
|
||||||
the_instance.fields.domain !== undefined &&
|
|
||||||
the_instance.fields.domain == network_info.domain
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
matched_instance = the_instance;
|
|
||||||
}
|
|
||||||
} else if (network_info.domain) {
|
|
||||||
// otherwise, we look for one with a matching domain.
|
|
||||||
for (const this_instance of this.protocols[network_info.protocol].instances) {
|
|
||||||
if (this_instance.fields.domain == network_info.domain) {
|
|
||||||
matched_instance = this_instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matched_instance === undefined) return null;
|
|
||||||
|
|
||||||
// now make an object with the fields specified by that protocol. We
|
|
||||||
// require that the values of all but the last field come from the
|
// require that the values of all but the last field come from the
|
||||||
// instance. The last is the user input.
|
// instance. The last is the user input.
|
||||||
const required_fields = this.protocols[network_info.protocol].location_fields;
|
const requiredFields = protocol.location_fields;
|
||||||
|
if (!requiredFields) return null;
|
||||||
const fields = {};
|
const fields = {};
|
||||||
for (let i = 0; i < required_fields.length - 1; ++i) {
|
for (let i = 0; i < requiredFields.length - 1; ++i) {
|
||||||
const this_field = required_fields[i];
|
const thisField = requiredFields[i];
|
||||||
if (matched_instance.fields[this_field] === undefined) return null;
|
if (instance.fields[thisField] === undefined) return null;
|
||||||
fields[this_field] = matched_instance.fields[this_field];
|
fields[thisField] = instance.fields[thisField];
|
||||||
}
|
}
|
||||||
fields[required_fields[required_fields.length - 1]] = user_input;
|
fields[requiredFields[requiredFields.length - 1]] = userInput;
|
||||||
return fields;
|
return fields;
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
|
||||||
|
const Loader = sdk.getComponent("elements.Spinner");
|
||||||
|
|
||||||
|
if (this.state.protocolsLoading) {
|
||||||
|
return (
|
||||||
|
<div className="mx_RoomDirectory">
|
||||||
|
<SimpleRoomHeader title="Directory" />
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
if (this.state.loading) {
|
if (this.state.loading) {
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
|
||||||
content = <div className="mx_RoomDirectory">
|
content = <div className="mx_RoomDirectory">
|
||||||
<Loader />
|
<Loader />
|
||||||
</div>;
|
</div>;
|
||||||
@ -583,26 +504,35 @@ module.exports = React.createClass({
|
|||||||
</ScrollPanel>;
|
</ScrollPanel>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let placeholder = 'Search for a room';
|
const protocolName = protocolNameForInstanceId(this.protocols, this.state.instanceId);
|
||||||
if (this.state.network === null || this.state.network === '_matrix') {
|
let instance_expected_field_type;
|
||||||
placeholder = '#example:' + this.state.roomServer;
|
if (
|
||||||
} else if (
|
protocolName &&
|
||||||
this.props.config.networks &&
|
this.protocols &&
|
||||||
this.props.config.networks[this.state.network] &&
|
this.protocols[protocolName] &&
|
||||||
this.props.config.networks[this.state.network].example &&
|
this.protocols[protocolName].location_fields.length > 0 &&
|
||||||
this._getFieldsForThirdPartyLocation(this.state.filterString, this.state.network)
|
this.protocols[protocolName].field_types
|
||||||
) {
|
) {
|
||||||
placeholder = this.props.config.networks[this.state.network].example;
|
const last_field = this.protocols[protocolName].location_fields.slice(-1)[0];
|
||||||
|
instance_expected_field_type = this.protocols[protocolName].field_types[last_field];
|
||||||
}
|
}
|
||||||
|
|
||||||
let showJoinButton = this._stringLooksLikeId(this.state.filterString, this.state.network);
|
|
||||||
if (this.state.network && this.state.network != '_matrix') {
|
let placeholder = 'Search for a room';
|
||||||
if (this._getFieldsForThirdPartyLocation(this.state.filterString, this.state.network) === null) {
|
if (!this.state.instanceId) {
|
||||||
|
placeholder = '#example:' + this.state.roomServer;
|
||||||
|
} else if (instance_expected_field_type) {
|
||||||
|
placeholder = instance_expected_field_type.placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
let showJoinButton = this._stringLooksLikeId(this.state.filterString, instance_expected_field_type);
|
||||||
|
if (protocolName) {
|
||||||
|
const instance = instanceForInstanceId(this.protocols, this.state.instanceId);
|
||||||
|
if (this._getFieldsForThirdPartyLocation(this.state.filterString, this.protocols[protocolName], instance) === null) {
|
||||||
showJoinButton = false;
|
showJoinButton = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
|
|
||||||
const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown');
|
const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown');
|
||||||
const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
|
const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
|
||||||
return (
|
return (
|
||||||
@ -615,7 +545,7 @@ module.exports = React.createClass({
|
|||||||
onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
|
onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
|
||||||
placeholder={placeholder} showJoinButton={showJoinButton}
|
placeholder={placeholder} showJoinButton={showJoinButton}
|
||||||
/>
|
/>
|
||||||
<NetworkDropdown config={this.props.config} onOptionChange={this.onOptionChange} />
|
<NetworkDropdown config={this.props.config} protocols={this.protocols} onOptionChange={this.onOptionChange} />
|
||||||
</div>
|
</div>
|
||||||
{content}
|
{content}
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +22,8 @@ module.exports = React.createClass({
|
|||||||
displayName: 'ViewSource',
|
displayName: 'ViewSource',
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
onFinished: React.PropTypes.func.isRequired
|
content: React.PropTypes.object.isRequired,
|
||||||
|
onFinished: React.PropTypes.func.isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
@ -45,10 +46,9 @@ module.exports = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div className="mx_ViewSource">
|
<div className="mx_ViewSource">
|
||||||
<pre>
|
<pre>
|
||||||
{JSON.stringify(this.props.mxEvent.event, null, 2)}
|
{JSON.stringify(this.props.content, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -47,7 +47,16 @@ module.exports = React.createClass({
|
|||||||
onViewSourceClick: function() {
|
onViewSourceClick: function() {
|
||||||
var ViewSource = sdk.getComponent('structures.ViewSource');
|
var ViewSource = sdk.getComponent('structures.ViewSource');
|
||||||
Modal.createDialog(ViewSource, {
|
Modal.createDialog(ViewSource, {
|
||||||
mxEvent: this.props.mxEvent
|
content: this.props.mxEvent.event,
|
||||||
|
}, 'mx_Dialog_viewsource');
|
||||||
|
if (this.props.onFinished) this.props.onFinished();
|
||||||
|
},
|
||||||
|
|
||||||
|
onViewClearSourceClick: function() {
|
||||||
|
const ViewSource = sdk.getComponent('structures.ViewSource');
|
||||||
|
Modal.createDialog(ViewSource, {
|
||||||
|
// FIXME: _clearEvent is private
|
||||||
|
content: this.props.mxEvent._clearEvent,
|
||||||
}, 'mx_Dialog_viewsource');
|
}, 'mx_Dialog_viewsource');
|
||||||
if (this.props.onFinished) this.props.onFinished();
|
if (this.props.onFinished) this.props.onFinished();
|
||||||
},
|
},
|
||||||
@ -97,6 +106,7 @@ module.exports = React.createClass({
|
|||||||
var eventStatus = this.props.mxEvent.status;
|
var eventStatus = this.props.mxEvent.status;
|
||||||
var resendButton;
|
var resendButton;
|
||||||
var viewSourceButton;
|
var viewSourceButton;
|
||||||
|
var viewClearSourceButton;
|
||||||
var redactButton;
|
var redactButton;
|
||||||
var cancelButton;
|
var cancelButton;
|
||||||
var permalinkButton;
|
var permalinkButton;
|
||||||
@ -133,6 +143,14 @@ module.exports = React.createClass({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (this.props.mxEvent.getType() !== this.props.mxEvent.getWireType()) {
|
||||||
|
viewClearSourceButton = (
|
||||||
|
<div className="mx_MessageContextMenu_field" onClick={this.onViewClearSourceClick}>
|
||||||
|
View Decrypted Source
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.props.eventTileOps) {
|
if (this.props.eventTileOps) {
|
||||||
if (this.props.eventTileOps.isWidgetHidden()) {
|
if (this.props.eventTileOps.isWidgetHidden()) {
|
||||||
unhidePreviewButton = (
|
unhidePreviewButton = (
|
||||||
@ -174,6 +192,7 @@ module.exports = React.createClass({
|
|||||||
{redactButton}
|
{redactButton}
|
||||||
{cancelButton}
|
{cancelButton}
|
||||||
{viewSourceButton}
|
{viewSourceButton}
|
||||||
|
{viewClearSourceButton}
|
||||||
{unhidePreviewButton}
|
{unhidePreviewButton}
|
||||||
{permalinkButton}
|
{permalinkButton}
|
||||||
{UserSettingsStore.isFeatureEnabled('rich_text_editor') ? quoteButton : null}
|
{UserSettingsStore.isFeatureEnabled('rich_text_editor') ? quoteButton : null}
|
||||||
|
@ -120,22 +120,22 @@ module.exports = React.createClass({
|
|||||||
</div>
|
</div>
|
||||||
<div className={ alertMeClasses } onClick={this._onClickAlertMe} >
|
<div className={ alertMeClasses } onClick={this._onClickAlertMe} >
|
||||||
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
||||||
<img className="mx_NotificationStateContextMenu_icon" src="img/icon-context-mute-off-copy.svg" width="16" height="12" />
|
<img className="mx_NotificationStateContextMenu_icon mx_filterFlipColor" src="img/icon-context-mute-off-copy.svg" width="16" height="12" />
|
||||||
All messages (loud)
|
All messages (loud)
|
||||||
</div>
|
</div>
|
||||||
<div className={ allNotifsClasses } onClick={this._onClickAllNotifs} >
|
<div className={ allNotifsClasses } onClick={this._onClickAllNotifs} >
|
||||||
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
||||||
<img className="mx_NotificationStateContextMenu_icon" src="img/icon-context-mute-off.svg" width="16" height="12" />
|
<img className="mx_NotificationStateContextMenu_icon mx_filterFlipColor" src="img/icon-context-mute-off.svg" width="16" height="12" />
|
||||||
All messages
|
All messages
|
||||||
</div>
|
</div>
|
||||||
<div className={ mentionsClasses } onClick={this._onClickMentions} >
|
<div className={ mentionsClasses } onClick={this._onClickMentions} >
|
||||||
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
||||||
<img className="mx_NotificationStateContextMenu_icon" src="img/icon-context-mute-mentions.svg" width="16" height="12" />
|
<img className="mx_NotificationStateContextMenu_icon mx_filterFlipColor" src="img/icon-context-mute-mentions.svg" width="16" height="12" />
|
||||||
Mentions only
|
Mentions only
|
||||||
</div>
|
</div>
|
||||||
<div className={ muteNotifsClasses } onClick={this._onClickMute} >
|
<div className={ muteNotifsClasses } onClick={this._onClickMute} >
|
||||||
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
<img className="mx_NotificationStateContextMenu_activeIcon" src="img/notif-active.svg" width="12" height="12" />
|
||||||
<img className="mx_NotificationStateContextMenu_icon" src="img/icon-context-mute.svg" width="16" height="12" />
|
<img className="mx_NotificationStateContextMenu_icon mx_filterFlipColor" src="img/icon-context-mute.svg" width="16" height="12" />
|
||||||
Mute
|
Mute
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
127
src/components/views/dialogs/BugReportDialog.js
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import sdk from 'matrix-react-sdk';
|
||||||
|
import rageshake from '../../../vector/rageshake';
|
||||||
|
|
||||||
|
export default class BugReportDialog extends React.Component {
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.state = {
|
||||||
|
sendLogs: true,
|
||||||
|
busy: false,
|
||||||
|
err: null,
|
||||||
|
text: "",
|
||||||
|
};
|
||||||
|
this._onSubmit = this._onSubmit.bind(this);
|
||||||
|
this._onCancel = this._onCancel.bind(this);
|
||||||
|
this._onTextChange = this._onTextChange.bind(this);
|
||||||
|
this._onSendLogsChange = this._onSendLogsChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onCancel(ev) {
|
||||||
|
this.props.onFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onSubmit(ev) {
|
||||||
|
const sendLogs = this.state.sendLogs;
|
||||||
|
const userText = this.state.text;
|
||||||
|
if (!sendLogs && userText.trim().length === 0) {
|
||||||
|
this.setState({
|
||||||
|
err: "Please describe the bug and/or send logs.",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({ busy: true, err: null });
|
||||||
|
rageshake.sendBugReport(userText, sendLogs).then(() => {
|
||||||
|
this.setState({ busy: false });
|
||||||
|
this.props.onFinished(false);
|
||||||
|
}, (err) => {
|
||||||
|
this.setState({ busy: false, err: `Failed: ${err.message}` });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_onTextChange(ev) {
|
||||||
|
this.setState({ text: ev.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
_onSendLogsChange(ev) {
|
||||||
|
this.setState({ sendLogs: ev.target.checked });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const Loader = sdk.getComponent("elements.Spinner");
|
||||||
|
|
||||||
|
let error = null;
|
||||||
|
if (this.state.err) {
|
||||||
|
error = <div className="error">
|
||||||
|
{this.state.err}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const okLabel = this.state.busy ? <Loader /> : 'Send';
|
||||||
|
|
||||||
|
let cancelButton = null;
|
||||||
|
if (!this.state.busy) {
|
||||||
|
cancelButton = <button onClick={this._onCancel}>
|
||||||
|
Cancel
|
||||||
|
</button>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx_BugReportDialog">
|
||||||
|
<div className="mx_Dialog_title">
|
||||||
|
Report a bug
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_content">
|
||||||
|
<p>Please describe the bug. What did you do?
|
||||||
|
What did you expect to happen?
|
||||||
|
What actually happened?</p>
|
||||||
|
<textarea
|
||||||
|
className="mx_BugReportDialog_input"
|
||||||
|
rows={5}
|
||||||
|
onChange={this._onTextChange}
|
||||||
|
value={this.state.text}
|
||||||
|
placeholder="Describe your problem here."
|
||||||
|
/>
|
||||||
|
<p>In order to diagnose problems, logs from this client will be sent with
|
||||||
|
this bug report.
|
||||||
|
If you would prefer to only send the text above, please untick:</p>
|
||||||
|
<input type="checkbox" checked={this.state.sendLogs}
|
||||||
|
onChange={this._onSendLogsChange} id="mx_BugReportDialog_logs"/>
|
||||||
|
<label htmlFor="mx_BugReportDialog_logs">Send logs</label>
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
<div className="mx_Dialog_buttons">
|
||||||
|
<button
|
||||||
|
className="mx_Dialog_primary danger"
|
||||||
|
onClick={this._onSubmit}
|
||||||
|
autoFocus={true}
|
||||||
|
>
|
||||||
|
{okLabel}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{cancelButton}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BugReportDialog.propTypes = {
|
||||||
|
onFinished: React.PropTypes.func.isRequired,
|
||||||
|
};
|
@ -31,9 +31,10 @@ export default class ChangelogDialog extends React.Component {
|
|||||||
const version = this.props.newVersion.split('-');
|
const version = this.props.newVersion.split('-');
|
||||||
const version2 = this.props.version.split('-');
|
const version2 = this.props.version.split('-');
|
||||||
if(version == null || version2 == null) return;
|
if(version == null || version2 == null) return;
|
||||||
|
// parse versions of form: [vectorversion]-react-[react-sdk-version]-js-[js-sdk-version]
|
||||||
for(let i=0; i<REPOS.length; i++) {
|
for(let i=0; i<REPOS.length; i++) {
|
||||||
const oldVersion = version2[2*i+1];
|
const oldVersion = version2[2*i];
|
||||||
const newVersion = version[2*i+1];
|
const newVersion = version[2*i];
|
||||||
request(`https://api.github.com/repos/${REPOS[i]}/compare/${oldVersion}...${newVersion}`, (a, b, body) => {
|
request(`https://api.github.com/repos/${REPOS[i]}/compare/${oldVersion}...${newVersion}`, (a, b, body) => {
|
||||||
if(body == null) return;
|
if(body == null) return;
|
||||||
this.setState({[REPOS[i]]: JSON.parse(body).commits});
|
this.setState({[REPOS[i]]: JSON.parse(body).commits});
|
||||||
|
@ -16,6 +16,9 @@ limitations under the License.
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
|
||||||
|
import {instanceForInstanceId} from '../../../utils/DirectoryUtils';
|
||||||
|
|
||||||
|
const DEFAULT_ICON_URL = "img/network-matrix.svg";
|
||||||
|
|
||||||
export default class NetworkDropdown extends React.Component {
|
export default class NetworkDropdown extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -35,20 +38,11 @@ export default class NetworkDropdown extends React.Component {
|
|||||||
this.inputTextBox = null;
|
this.inputTextBox = null;
|
||||||
|
|
||||||
const server = MatrixClientPeg.getHomeServerName();
|
const server = MatrixClientPeg.getHomeServerName();
|
||||||
let defaultNetwork = null;
|
|
||||||
if (
|
|
||||||
this.props.config.serverConfig &&
|
|
||||||
this.props.config.serverConfig[server] &&
|
|
||||||
this.props.config.serverConfig[server].networks &&
|
|
||||||
this.props.config.serverConfig[server].networks.indexOf('_matrix') > -1
|
|
||||||
) {
|
|
||||||
defaultNetwork = '_matrix';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
expanded: false,
|
expanded: false,
|
||||||
selectedServer: server,
|
selectedServer: server,
|
||||||
selectedNetwork: defaultNetwork,
|
selectedInstance: null,
|
||||||
|
includeAllNetworks: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +52,7 @@ export default class NetworkDropdown extends React.Component {
|
|||||||
document.addEventListener('click', this.onDocumentClick, false);
|
document.addEventListener('click', this.onDocumentClick, false);
|
||||||
|
|
||||||
// fire this now so the defaults can be set up
|
// fire this now so the defaults can be set up
|
||||||
this.props.onOptionChange(this.state.selectedServer, this.state.selectedNetwork);
|
this.props.onOptionChange(this.state.selectedServer, this.state.selectedInstance, this.state.includeAllNetworks);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@ -98,13 +92,14 @@ export default class NetworkDropdown extends React.Component {
|
|||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMenuOptionClick(server, network, ev) {
|
onMenuOptionClick(server, instance, includeAll) {
|
||||||
this.setState({
|
this.setState({
|
||||||
expanded: false,
|
expanded: false,
|
||||||
selectedServer: server,
|
selectedServer: server,
|
||||||
selectedNetwork: network,
|
selectedInstanceId: instance ? instance.instance_id : null,
|
||||||
|
includeAll: includeAll,
|
||||||
});
|
});
|
||||||
this.props.onOptionChange(server, network);
|
this.props.onOptionChange(server, instance ? instance.instance_id : null, includeAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
onInputKeyUp(e) {
|
onInputKeyUp(e) {
|
||||||
@ -144,11 +139,22 @@ export default class NetworkDropdown extends React.Component {
|
|||||||
servers.unshift(MatrixClientPeg.getHomeServerName());
|
servers.unshift(MatrixClientPeg.getHomeServerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For our own HS, we can use the instance_ids given in the third party protocols
|
||||||
|
// response to get the server to filter the room list by network for us.
|
||||||
|
// We can't get thirdparty protocols for remote server yet though, so for those
|
||||||
|
// we can only show the default room list.
|
||||||
for (const server of servers) {
|
for (const server of servers) {
|
||||||
options.push(this._makeMenuOption(server, null));
|
options.push(this._makeMenuOption(server, null, true));
|
||||||
if (this.props.config.serverConfig && this.props.config.serverConfig[server] && this.props.config.serverConfig[server].networks) {
|
if (server == MatrixClientPeg.getHomeServerName()) {
|
||||||
for (const network of this.props.config.serverConfig[server].networks) {
|
options.push(this._makeMenuOption(server, null, false));
|
||||||
options.push(this._makeMenuOption(server, network));
|
if (this.props.protocols) {
|
||||||
|
for (const proto of Object.keys(this.props.protocols)) {
|
||||||
|
if (!this.props.protocols[proto].instances) continue;
|
||||||
|
for (const instance of this.props.protocols[proto].instances) {
|
||||||
|
if (!instance.instance_id) continue;
|
||||||
|
options.push(this._makeMenuOption(server, instance, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,50 +162,36 @@ export default class NetworkDropdown extends React.Component {
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
_makeMenuOption(server, network, wire_onclick) {
|
_makeMenuOption(server, instance, includeAll, handleClicks) {
|
||||||
if (wire_onclick === undefined) wire_onclick = true;
|
if (handleClicks === undefined) handleClicks = true;
|
||||||
|
|
||||||
let icon;
|
let icon;
|
||||||
let name;
|
let name;
|
||||||
let span_class;
|
let span_class;
|
||||||
|
let key;
|
||||||
|
|
||||||
if (network === null) {
|
if (!instance && includeAll) {
|
||||||
|
key = server;
|
||||||
name = server;
|
name = server;
|
||||||
span_class = 'mx_NetworkDropdown_menu_all';
|
span_class = 'mx_NetworkDropdown_menu_all';
|
||||||
} else if (network == '_matrix') {
|
} else if (!instance) {
|
||||||
|
key = server + '_all';
|
||||||
name = 'Matrix';
|
name = 'Matrix';
|
||||||
icon = <img src="img/network-matrix.svg" width="16" height="16" />;
|
icon = <img src="img/network-matrix.svg" />;
|
||||||
span_class = 'mx_NetworkDropdown_menu_network';
|
span_class = 'mx_NetworkDropdown_menu_network';
|
||||||
} else {
|
} else {
|
||||||
if (this.props.config.networks[network] === undefined) {
|
key = server + '_inst_' + instance.instance_id;
|
||||||
throw new Error(network + ' network missing from config');
|
icon = <img src={instance.icon || DEFAULT_ICON_URL} />;
|
||||||
}
|
name = instance.desc;
|
||||||
if (this.props.config.networks[network].name) {
|
|
||||||
name = this.props.config.networks[network].name;
|
|
||||||
} else {
|
|
||||||
name = network;
|
|
||||||
}
|
|
||||||
if (this.props.config.networks[network].icon) {
|
|
||||||
// omit height here so if people define a non-square logo in the config, it
|
|
||||||
// will keep the aspect when it scales
|
|
||||||
icon = <img src={this.props.config.networks[network].icon} width="16" />;
|
|
||||||
} else {
|
|
||||||
icon = <img src={iconPath} width="16" height="16" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
span_class = 'mx_NetworkDropdown_menu_network';
|
span_class = 'mx_NetworkDropdown_menu_network';
|
||||||
}
|
}
|
||||||
|
|
||||||
const click_handler = wire_onclick ? this.onMenuOptionClick.bind(this, server, network) : null;
|
const click_handler = handleClicks ? this.onMenuOptionClick.bind(this, server, instance, includeAll) : null;
|
||||||
|
|
||||||
let key = server;
|
|
||||||
if (network !== null) {
|
|
||||||
key += '_' + network;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div key={key} className="mx_NetworkDropdown_networkoption" onClick={click_handler}>
|
return <div key={key} className="mx_NetworkDropdown_networkoption" onClick={click_handler}>
|
||||||
{icon}
|
{icon}
|
||||||
<span className={span_class}>{name}</span>
|
<span className="mx_NetworkDropdown_menu_network">{name}</span>
|
||||||
</div>;
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -216,8 +208,9 @@ export default class NetworkDropdown extends React.Component {
|
|||||||
placeholder="matrix.org" // 'matrix.org' as an example of an HS name
|
placeholder="matrix.org" // 'matrix.org' as an example of an HS name
|
||||||
/>
|
/>
|
||||||
} else {
|
} else {
|
||||||
|
const instance = instanceForInstanceId(this.props.protocols, this.state.selectedInstanceId);
|
||||||
current_value = this._makeMenuOption(
|
current_value = this._makeMenuOption(
|
||||||
this.state.selectedServer, this.state.selectedNetwork, false
|
this.state.selectedServer, instance, this.state.includeAll, false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,12 +226,12 @@ export default class NetworkDropdown extends React.Component {
|
|||||||
|
|
||||||
NetworkDropdown.propTypes = {
|
NetworkDropdown.propTypes = {
|
||||||
onOptionChange: React.PropTypes.func.isRequired,
|
onOptionChange: React.PropTypes.func.isRequired,
|
||||||
|
protocols: React.PropTypes.object,
|
||||||
|
// The room directory config. May have a 'servers' key that is a list of server names to include in the dropdown
|
||||||
config: React.PropTypes.object,
|
config: React.PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
NetworkDropdown.defaultProps = {
|
NetworkDropdown.defaultProps = {
|
||||||
config: {
|
protocols: {},
|
||||||
networks: [],
|
config: {},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,11 +23,11 @@ import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check a version string is compatible with the Changelog
|
* Check a version string is compatible with the Changelog
|
||||||
* dialog
|
* dialog ([vectorversion]-react-[react-sdk-version]-js-[js-sdk-version])
|
||||||
*/
|
*/
|
||||||
function checkVersion(ver) {
|
function checkVersion(ver) {
|
||||||
const parts = ver.split('-');
|
const parts = ver.split('-');
|
||||||
return parts[0] == 'vector' && parts[2] == 'react' && parts[4] == 'js';
|
return parts.length == 5 && parts[1] == 'react' && parts[3] == 'js';
|
||||||
}
|
}
|
||||||
|
|
||||||
export default React.createClass({
|
export default React.createClass({
|
||||||
|
@ -23,11 +23,14 @@ module.exports = React.createClass({
|
|||||||
statics: {
|
statics: {
|
||||||
replaces: 'LoginHeader',
|
replaces: 'LoginHeader',
|
||||||
},
|
},
|
||||||
|
propTypes: {
|
||||||
|
icon: React.PropTypes.string,
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div className="mx_Login_logo">
|
<div className="mx_Login_logo">
|
||||||
<img src="img/logo.png" width="195" height="195" alt="Riot"/>
|
<img src={this.props.icon || "img/logo.png"} alt="Riot"/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,8 @@ body {
|
|||||||
Arial here. */
|
Arial here. */
|
||||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #454545;
|
background-color: $primary-bg-color;
|
||||||
|
color: $primary-fg-color;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
/* This should render the fonts the same accross browsers */
|
/* This should render the fonts the same accross browsers */
|
||||||
@ -41,7 +42,7 @@ div.error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
color: #454545;
|
color: $primary-fg-color;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
@ -51,15 +52,20 @@ h2 {
|
|||||||
a:hover,
|
a:hover,
|
||||||
a:link,
|
a:link,
|
||||||
a:visited {
|
a:visited {
|
||||||
color: #76cfa6;
|
color: $accent-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text], input[type=password], textarea {
|
||||||
|
background-color: transparent;
|
||||||
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=text].error, input[type=password].error {
|
input[type=text].error, input[type=password].error {
|
||||||
border: 1px solid red;
|
border: 1px solid $warning-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=text]:focus, textarea:focus {
|
input[type=text]:focus, textarea:focus {
|
||||||
border: 1px solid #76CFA6;
|
border: 1px solid $accent-color;
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
@ -77,10 +83,7 @@ textarea {
|
|||||||
/* applied to side-panels and messagepanel when in RoomSettings */
|
/* applied to side-panels and messagepanel when in RoomSettings */
|
||||||
.mx_fadable {
|
.mx_fadable {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
-webkit-transition: opacity 0.2s ease-in-out;
|
transition: opacity 0.2s ease-in-out;
|
||||||
-moz-transition: opacity 0.2s ease-in-out;
|
|
||||||
-ms-transition: opacity 0.2s ease-in-out;
|
|
||||||
-o-transition: opacity 0.2s ease-in-out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: critical hack to GeminiScrollbar to allow them to work in FF 42 and Chrome 48.
|
/* XXX: critical hack to GeminiScrollbar to allow them to work in FF 42 and Chrome 48.
|
||||||
@ -122,14 +125,8 @@ textarea {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -moz-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
-webkit-align-items: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
-webkit-justify-content: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,8 +145,8 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_Dialog {
|
.mx_Dialog {
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
color: #747474;
|
color: $light-fg-color;
|
||||||
z-index: 4010;
|
z-index: 4010;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
@ -168,13 +165,13 @@ textarea {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #e9e9e9;
|
background-color: $dialog-background-bg-color;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Dialog_lightbox .mx_Dialog_background {
|
.mx_Dialog_lightbox .mx_Dialog_background {
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
background-color: #000;
|
background-color: $lightbox-background-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Dialog_lightbox .mx_Dialog {
|
.mx_Dialog_lightbox .mx_Dialog {
|
||||||
@ -190,7 +187,7 @@ textarea {
|
|||||||
.mx_Dialog_content {
|
.mx_Dialog_content {
|
||||||
margin: 24px 58px 68px 0;
|
margin: 24px 58px 68px 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +199,7 @@ textarea {
|
|||||||
border: 0px;
|
border: 0px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
border-radius: 40px;
|
border-radius: 40px;
|
||||||
border: solid 1px #76cfa6;
|
border: solid 1px $accent-color;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||||
@ -212,26 +209,26 @@ textarea {
|
|||||||
padding-right: 1.5em;
|
padding-right: 1.5em;
|
||||||
outline: none;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #76cfa6;
|
color: $accent-color;
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
|
|
||||||
/* align images in buttons (eg spinners) */
|
/* align images in buttons (eg spinners) */
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Dialog button.mx_Dialog_primary, .mx_Dialog input[type="submit"].mx_Dialog_primary {
|
.mx_Dialog button.mx_Dialog_primary, .mx_Dialog input[type="submit"].mx_Dialog_primary {
|
||||||
color: #fff;
|
color: $accent-fg-color;
|
||||||
background-color: #76cfa6;
|
background-color: $accent-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Dialog button.danger, .mx_Dialog input[type="submit"].danger {
|
.mx_Dialog button.danger, .mx_Dialog input[type="submit"].danger {
|
||||||
background-color: #ff0064;
|
background-color: $warning-color;
|
||||||
border: solid 1px #ff0064;
|
border: solid 1px $warning-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Dialog button:disabled, .mx_Dialog input[type="submit"]:disabled {
|
.mx_Dialog button:disabled, .mx_Dialog input[type="submit"]:disabled {
|
||||||
background-color: #777777;
|
background-color: $light-fg-color;
|
||||||
border: solid 1px #777777;
|
border: solid 1px $light-fg-color;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,11 +238,11 @@ textarea {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
color: #454545;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Dialog_title.danger {
|
.mx_Dialog_title.danger {
|
||||||
color: #ff0064;
|
color: $warning-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_TextInputDialog_label {
|
.mx_TextInputDialog_label {
|
||||||
@ -256,10 +253,10 @@ textarea {
|
|||||||
.mx_TextInputDialog_input {
|
.mx_TextInputDialog_input {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid $input-border-color;
|
||||||
padding: 9px;
|
padding: 9px;
|
||||||
color: #454545;
|
color: $primary-fg-color;
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_emojione {
|
.mx_emojione {
|
||||||
@ -268,19 +265,19 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
::-moz-selection {
|
::-moz-selection {
|
||||||
background-color: #76CFA6;
|
background-color: $accent-color;
|
||||||
color: white;
|
color: $selection-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
::selection {
|
||||||
background-color: #76CFA6;
|
background-color: $accent-color;
|
||||||
color: white;
|
color: $selection-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** green button with rounded corners */
|
/** green button with rounded corners */
|
||||||
.mx_textButton {
|
.mx_textButton {
|
||||||
color: #fff;
|
color: $accent-fg-color;
|
||||||
background-color: #76cfa6;
|
background-color: $accent-color;
|
||||||
border-radius: 17px;
|
border-radius: 17px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
75
src/skins/vector/css/_components.scss
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// autogenerated by rethemendex.sh
|
||||||
|
@import "./_common.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_ContextualMenu.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_CreateRoom.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_FilePanel.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_MatrixChat.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_NotificationPanel.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_RoomStatusBar.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_RoomView.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_SearchBox.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_UploadBar.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/_UserSettings.scss";
|
||||||
|
@import "./matrix-react-sdk/structures/login/_Login.scss";
|
||||||
|
@import "./matrix-react-sdk/views/avatars/_BaseAvatar.scss";
|
||||||
|
@import "./matrix-react-sdk/views/dialogs/_BugReportDialog.scss";
|
||||||
|
@import "./matrix-react-sdk/views/dialogs/_ChatInviteDialog.scss";
|
||||||
|
@import "./matrix-react-sdk/views/dialogs/_EncryptedEventDialog.scss";
|
||||||
|
@import "./matrix-react-sdk/views/dialogs/_SetDisplayNameDialog.scss";
|
||||||
|
@import "./matrix-react-sdk/views/dialogs/_UnknownDeviceDialog.scss";
|
||||||
|
@import "./matrix-react-sdk/views/elements/_AddressSelector.scss";
|
||||||
|
@import "./matrix-react-sdk/views/elements/_AddressTile.scss";
|
||||||
|
@import "./matrix-react-sdk/views/elements/_DirectorySearchBox.scss";
|
||||||
|
@import "./matrix-react-sdk/views/elements/_MemberEventListSummary.scss";
|
||||||
|
@import "./matrix-react-sdk/views/elements/_ProgressBar.scss";
|
||||||
|
@import "./matrix-react-sdk/views/elements/_RichText.scss";
|
||||||
|
@import "./matrix-react-sdk/views/login/_ServerConfig.scss";
|
||||||
|
@import "./matrix-react-sdk/views/messages/_MImageBody.scss";
|
||||||
|
@import "./matrix-react-sdk/views/messages/_MNoticeBody.scss";
|
||||||
|
@import "./matrix-react-sdk/views/messages/_MTextBody.scss";
|
||||||
|
@import "./matrix-react-sdk/views/messages/_TextualEvent.scss";
|
||||||
|
@import "./matrix-react-sdk/views/messages/_UnknownBody.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_Autocomplete.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_EntityTile.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_EventTile.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_LinkPreviewWidget.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_MemberDeviceInfo.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_MemberInfo.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_MemberList.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_MessageComposer.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_PresenceLabel.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_RoomHeader.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_RoomList.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_RoomPreviewBar.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_RoomSettings.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_RoomTile.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_SearchableEntityList.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_TabCompleteBar.scss";
|
||||||
|
@import "./matrix-react-sdk/views/rooms/_TopUnreadMessagesBar.scss";
|
||||||
|
@import "./matrix-react-sdk/views/settings/_DevicesPanel.scss";
|
||||||
|
@import "./matrix-react-sdk/views/settings/_IntegrationsManager.scss";
|
||||||
|
@import "./matrix-react-sdk/views/voip/_CallView.scss";
|
||||||
|
@import "./matrix-react-sdk/views/voip/_IncomingCallbox.scss";
|
||||||
|
@import "./matrix-react-sdk/views/voip/_VideoView.scss";
|
||||||
|
@import "./vector-web/_fonts.scss";
|
||||||
|
@import "./vector-web/structures/_CompatibilityPage.scss";
|
||||||
|
@import "./vector-web/structures/_LeftPanel.scss";
|
||||||
|
@import "./vector-web/structures/_RightPanel.scss";
|
||||||
|
@import "./vector-web/structures/_RoomDirectory.scss";
|
||||||
|
@import "./vector-web/structures/_RoomSubList.scss";
|
||||||
|
@import "./vector-web/structures/_ViewSource.scss";
|
||||||
|
@import "./vector-web/views/context_menus/_MessageContextMenu.scss";
|
||||||
|
@import "./vector-web/views/context_menus/_NotificationStateContextMenu.scss";
|
||||||
|
@import "./vector-web/views/context_menus/_RoomTagContextMenu.scss";
|
||||||
|
@import "./vector-web/views/dialogs/_ChangelogDialog.scss";
|
||||||
|
@import "./vector-web/views/directory/_NetworkDropdown.scss";
|
||||||
|
@import "./vector-web/views/elements/_ImageView.scss";
|
||||||
|
@import "./vector-web/views/elements/_Spinner.scss";
|
||||||
|
@import "./vector-web/views/globals/_GuestWarningBar.scss";
|
||||||
|
@import "./vector-web/views/globals/_MatrixToolbar.scss";
|
||||||
|
@import "./vector-web/views/messages/_MessageTimestamp.scss";
|
||||||
|
@import "./vector-web/views/messages/_SenderProfile.scss";
|
||||||
|
@import "./vector-web/views/rooms/_RoomDropTarget.scss";
|
||||||
|
@import "./vector-web/views/rooms/_RoomTooltip.scss";
|
||||||
|
@import "./vector-web/views/rooms/_SearchBar.scss";
|
||||||
|
@import "./vector-web/views/settings/_Notifications.scss";
|
@ -30,10 +30,10 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_ContextualMenu {
|
.mx_ContextualMenu {
|
||||||
border: solid 1px rgba(187, 187, 187, 0.5);
|
border: solid 1px $menu-border-color;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: #f6f6f6;
|
background-color: $menu-bg-color;
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@ -51,7 +51,7 @@ limitations under the License.
|
|||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-top: 8px solid transparent;
|
border-top: 8px solid transparent;
|
||||||
border-left: 8px solid rgba(187, 187, 187, 0.5);
|
border-left: 8px solid $menu-border-color;
|
||||||
border-bottom: 8px solid transparent;
|
border-bottom: 8px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ limitations under the License.
|
|||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-top: 7px solid transparent;
|
border-top: 7px solid transparent;
|
||||||
border-left: 7px solid #f6f6f6;
|
border-left: 7px solid $menu-bg-color;
|
||||||
border-bottom: 7px solid transparent;
|
border-bottom: 7px solid transparent;
|
||||||
position:absolute;
|
position:absolute;
|
||||||
top: -7px;
|
top: -7px;
|
||||||
@ -78,7 +78,7 @@ limitations under the License.
|
|||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-top: 8px solid transparent;
|
border-top: 8px solid transparent;
|
||||||
border-right: 8px solid rgba(187, 187, 187, 0.5);
|
border-right: 8px solid $menu-border-color;
|
||||||
border-bottom: 8px solid transparent;
|
border-bottom: 8px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ limitations under the License.
|
|||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-top: 7px solid transparent;
|
border-top: 7px solid transparent;
|
||||||
border-right: 7px solid #f6f6f6;
|
border-right: 7px solid $menu-bg-color;
|
||||||
border-bottom: 7px solid transparent;
|
border-bottom: 7px solid transparent;
|
||||||
position:absolute;
|
position:absolute;
|
||||||
top: -7px;
|
top: -7px;
|
@ -18,13 +18,13 @@ limitations under the License.
|
|||||||
width: 960px;
|
width: 960px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_CreateRoom input,
|
.mx_CreateRoom input,
|
||||||
.mx_CreateRoom textarea {
|
.mx_CreateRoom textarea {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border: 1px solid #c7c7c7;
|
border: 1px solid $strong-input-border-color;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 9px;
|
padding: 9px;
|
@ -15,13 +15,8 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_FilePanel {
|
.mx_FilePanel {
|
||||||
-webkit-box-ordinal-group: 2;
|
|
||||||
-moz-box-ordinal-group: 2;
|
|
||||||
-ms-flex-order: 2;
|
|
||||||
-webkit-order: 2;
|
|
||||||
order: 2;
|
order: 2;
|
||||||
|
|
||||||
-webkit-flex: 1 1 0;
|
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -58,12 +53,12 @@ limitations under the License.
|
|||||||
.mx_FilePanel .mx_EventTile .mx_MImageBody_download {
|
.mx_FilePanel .mx_EventTile .mx_MImageBody_download {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #acacac;
|
color: $event-timestamp-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_FilePanel .mx_EventTile .mx_MImageBody_downloadLink {
|
.mx_FilePanel .mx_EventTile .mx_MImageBody_downloadLink {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
color: #747474;
|
color: $light-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_FilePanel .mx_EventTile .mx_MImageBody_size {
|
.mx_FilePanel .mx_EventTile .mx_MImageBody_size {
|
||||||
@ -90,7 +85,7 @@ limitations under the License.
|
|||||||
padding: 0px;
|
padding: 0px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
color: #acacac;
|
color: $event-timestamp-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_FilePanel .mx_EventTile .mx_MessageTimestamp {
|
.mx_FilePanel .mx_EventTile .mx_MessageTimestamp {
|
||||||
@ -100,7 +95,7 @@ limitations under the License.
|
|||||||
position: initial;
|
position: initial;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
color: #acacac;
|
color: $event-timestamp-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overrides for the wrappers around the body tile */
|
/* Overrides for the wrappers around the body tile */
|
||||||
@ -111,7 +106,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_FilePanel .mx_EventTile:hover .mx_EventTile_line {
|
.mx_FilePanel .mx_EventTile:hover .mx_EventTile_line {
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_FilePanel .mx_EventTile_selected .mx_EventTile_line {
|
.mx_FilePanel .mx_EventTile_selected .mx_EventTile_line {
|
@ -27,34 +27,21 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixChat_wrapper {
|
.mx_MatrixChat_wrapper {
|
||||||
display: -webkit-box;
|
|
||||||
display: -moz-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
-webkit-flex-direction: column;
|
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixToolbar {
|
.mx_MatrixToolbar {
|
||||||
-webkit-box-ordinal-group: 1;
|
|
||||||
-moz-box-ordinal-group: 1;
|
|
||||||
-ms-flex-order: 1;
|
|
||||||
-webkit-order: 1;
|
|
||||||
order: 1;
|
order: 1;
|
||||||
|
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_GuestWarningBar {
|
.mx_GuestWarningBar {
|
||||||
-webkit-box-ordinal-group: 1;
|
|
||||||
-moz-box-ordinal-group: 1;
|
|
||||||
-ms-flex-order: 1;
|
|
||||||
-webkit-order: 1;
|
|
||||||
order: 1;
|
order: 1;
|
||||||
|
|
||||||
height: 40px;
|
height: 40px;
|
||||||
@ -68,52 +55,32 @@ limitations under the License.
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -moz-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
-webkit-box-ordinal-group: 2;
|
|
||||||
-moz-box-ordinal-group: 2;
|
|
||||||
-ms-flex-order: 2;
|
|
||||||
-webkit-order: 2;
|
|
||||||
order: 2;
|
order: 2;
|
||||||
|
|
||||||
-webkit-flex: 1;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixChat .mx_LeftPanel {
|
.mx_MatrixChat .mx_LeftPanel {
|
||||||
-webkit-box-ordinal-group: 1;
|
|
||||||
-moz-box-ordinal-group: 1;
|
|
||||||
-ms-flex-order: 1;
|
|
||||||
-webkit-order: 1;
|
|
||||||
order: 1;
|
order: 1;
|
||||||
|
|
||||||
background-color: #eaf5f0;
|
background-color: $secondary-accent-color;
|
||||||
|
|
||||||
-webkit-flex: 0 0 235px;
|
|
||||||
flex: 0 0 235px;
|
flex: 0 0 235px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixChat .mx_LeftPanel.collapsed {
|
.mx_MatrixChat .mx_LeftPanel.collapsed {
|
||||||
-webkit-flex: 0 0 60px;
|
|
||||||
flex: 0 0 60px;
|
flex: 0 0 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixChat .mx_MatrixChat_middlePanel {
|
.mx_MatrixChat .mx_MatrixChat_middlePanel {
|
||||||
-webkit-box-ordinal-group: 2;
|
|
||||||
-moz-box-ordinal-group: 2;
|
|
||||||
-ms-flex-order: 2;
|
|
||||||
-webkit-order: 2;
|
|
||||||
order: 2;
|
order: 2;
|
||||||
|
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
padding-right: 22px;
|
padding-right: 22px;
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
|
|
||||||
-webkit-flex: 1;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
/* Experimental fix for https://github.com/vector-im/vector-web/issues/947
|
/* Experimental fix for https://github.com/vector-im/vector-web/issues/947
|
||||||
@ -132,25 +99,15 @@ limitations under the License.
|
|||||||
* point, but instead we fudge it and make the middlePanel
|
* point, but instead we fudge it and make the middlePanel
|
||||||
* flex itself.
|
* flex itself.
|
||||||
*/
|
*/
|
||||||
display: -webkit-box;
|
|
||||||
display: -moz-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixChat .mx_RightPanel {
|
.mx_MatrixChat .mx_RightPanel {
|
||||||
-webkit-box-ordinal-group: 3;
|
|
||||||
-moz-box-ordinal-group: 3;
|
|
||||||
-ms-flex-order: 3;
|
|
||||||
-webkit-order: 3;
|
|
||||||
order: 3;
|
order: 3;
|
||||||
|
|
||||||
-webkit-flex: 0 0 235px;
|
|
||||||
flex: 0 0 235px;
|
flex: 0 0 235px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixChat .mx_RightPanel.collapsed {
|
.mx_MatrixChat .mx_RightPanel.collapsed {
|
||||||
-webkit-flex: 0 0 122px;
|
|
||||||
flex: 0 0 122px;
|
flex: 0 0 122px;
|
||||||
}
|
}
|
@ -15,13 +15,8 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_NotificationPanel {
|
.mx_NotificationPanel {
|
||||||
-webkit-box-ordinal-group: 2;
|
|
||||||
-moz-box-ordinal-group: 2;
|
|
||||||
-ms-flex-order: 2;
|
|
||||||
-webkit-order: 2;
|
|
||||||
order: 2;
|
order: 2;
|
||||||
|
|
||||||
-webkit-flex: 1 1 0;
|
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -51,7 +46,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_NotificationPanel .mx_EventTile_roomName a {
|
.mx_NotificationPanel .mx_EventTile_roomName a {
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_NotificationPanel .mx_EventTile_avatar {
|
.mx_NotificationPanel .mx_EventTile_avatar {
|
||||||
@ -61,8 +56,7 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_NotificationPanel .mx_EventTile .mx_SenderProfile,
|
.mx_NotificationPanel .mx_EventTile .mx_SenderProfile,
|
||||||
.mx_NotificationPanel .mx_EventTile .mx_MessageTimestamp {
|
.mx_NotificationPanel .mx_EventTile .mx_MessageTimestamp {
|
||||||
color: #000;
|
color: $primary-fg-color;
|
||||||
opacity: 0.3;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
display: inline;
|
display: inline;
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
@ -94,7 +88,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_NotificationPanel .mx_EventTile:hover .mx_EventTile_line {
|
.mx_NotificationPanel .mx_EventTile:hover .mx_EventTile_line {
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_NotificationPanel .mx_EventTile_selected .mx_EventTile_line {
|
.mx_NotificationPanel .mx_EventTile_selected .mx_EventTile_line {
|
@ -21,10 +21,10 @@ limitations under the License.
|
|||||||
|
|
||||||
/* position the indicator in the same place horizontally as .mx_EventTile_avatar. */
|
/* position the indicator in the same place horizontally as .mx_EventTile_avatar. */
|
||||||
.mx_RoomStatusBar_indicator {
|
.mx_RoomStatusBar_indicator {
|
||||||
padding-left: 18px;
|
padding-left: 17px;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
margin-left: -73px;
|
margin-left: -73px;
|
||||||
margin-top: 13px;
|
margin-top: 8px;
|
||||||
float: left;
|
float: left;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -36,7 +36,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_placeholderIndicator span {
|
.mx_RoomStatusBar_placeholderIndicator span {
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -4px;
|
top: -4px;
|
||||||
@ -70,13 +70,43 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_RoomStatusBar_typingIndicatorAvatars {
|
||||||
|
width: 52px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomStatusBar_typingIndicatorAvatars .mx_BaseAvatar_image {
|
||||||
|
margin-right: -12px;
|
||||||
|
border: 1px solid $primary-bg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomStatusBar_typingIndicatorAvatars .mx_BaseAvatar_initial {
|
||||||
|
padding-left: 1px;
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomStatusBar_typingIndicatorRemaining {
|
||||||
|
display: inline-block;
|
||||||
|
color: #acacac;
|
||||||
|
background-color: #ddd;
|
||||||
|
border: 1px solid $primary-bg-color;
|
||||||
|
border-radius: 40px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_scrollDownIndicator {
|
.mx_RoomStatusBar_scrollDownIndicator {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_unreadMessagesBar {
|
.mx_RoomStatusBar_unreadMessagesBar {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
color: #ff0064;
|
color: $warning-color;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,29 +123,29 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_connectionLostBar_title {
|
.mx_RoomStatusBar_connectionLostBar_title {
|
||||||
color: #ff0064;
|
color: $warning-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_connectionLostBar_desc {
|
.mx_RoomStatusBar_connectionLostBar_desc {
|
||||||
color: #454545;
|
color: $primary-fg-color;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_resend_link {
|
.mx_RoomStatusBar_resend_link {
|
||||||
color: #454545 ! important;
|
color: $primary-fg-color ! important;
|
||||||
text-decoration: underline ! important;
|
text-decoration: underline ! important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_tabCompleteBar {
|
.mx_RoomStatusBar_tabCompleteBar {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_typingBar {
|
.mx_RoomStatusBar_typingBar {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
display: block;
|
display: block;
|
||||||
@ -123,19 +153,16 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_RoomStatusBar_tabCompleteWrapper {
|
.mx_RoomStatusBar_tabCompleteWrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
display: -webkit-flex;
|
|
||||||
height: 26px;
|
height: 26px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_tabCompleteWrapper .mx_TabCompleteBar {
|
.mx_RoomStatusBar_tabCompleteWrapper .mx_TabCompleteBar {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
-webkit-flex: 1 1 auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_tabCompleteEol {
|
.mx_RoomStatusBar_tabCompleteEol {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
-webkit-flex: 0 0 auto;
|
color: $accent-color;
|
||||||
color: #76CFA6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomStatusBar_tabCompleteEol object {
|
.mx_RoomStatusBar_tabCompleteEol object {
|
@ -18,25 +18,15 @@ limitations under the License.
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -moz-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
-webkit-flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView .mx_RoomHeader {
|
.mx_RoomView .mx_RoomHeader {
|
||||||
-webkit-box-ordinal-group: 1;
|
|
||||||
-moz-box-ordinal-group: 1;
|
|
||||||
-ms-flex-order: 1;
|
|
||||||
-webkit-order: 1;
|
|
||||||
order: 1;
|
order: 1;
|
||||||
|
|
||||||
-webkit-flex: 0 0 70px;
|
|
||||||
flex: 0 0 70px;
|
flex: 0 0 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,14 +43,10 @@ limitations under the License.
|
|||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
margin-left: -12px;
|
margin-left: -12px;
|
||||||
|
|
||||||
-webkit-border-top-left-radius: 10px;
|
|
||||||
-webkit-border-top-right-radius: 10px;
|
|
||||||
-moz-border-radius-topleft: 10px;
|
|
||||||
-moz-border-radius-topright: 10px;
|
|
||||||
border-top-left-radius: 10px;
|
border-top-left-radius: 10px;
|
||||||
border-top-right-radius: 10px;
|
border-top-right-radius: 10px;
|
||||||
|
|
||||||
background-color: rgba(255, 255, 255, 0.9);
|
background-color: $droptarget-bg-color;
|
||||||
border: 2px #e1dddd solid;
|
border: 2px #e1dddd solid;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -77,10 +63,6 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_auxPanel {
|
.mx_RoomView_auxPanel {
|
||||||
-webkit-box-ordinal-group: 2;
|
|
||||||
-moz-box-ordinal-group: 2;
|
|
||||||
-ms-flex-order: 2;
|
|
||||||
-webkit-order: 2;
|
|
||||||
order: 2;
|
order: 2;
|
||||||
|
|
||||||
min-width: 0px;
|
min-width: 0px;
|
||||||
@ -89,28 +71,18 @@ limitations under the License.
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
border-bottom: 1px solid #e5e5e5;
|
border-bottom: 1px solid $primary-hairline-color;
|
||||||
|
|
||||||
-webkit-flex: 0 0 auto;
|
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_topUnreadMessagesBar {
|
.mx_RoomView_topUnreadMessagesBar {
|
||||||
-webkit-box-ordinal-group: 3;
|
|
||||||
-moz-box-ordinal-group: 3;
|
|
||||||
-ms-flex-order: 3;
|
|
||||||
-webkit-order: 3;
|
|
||||||
order: 3;
|
order: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_messagePanel {
|
.mx_RoomView_messagePanel {
|
||||||
-webkit-box-ordinal-group: 4;
|
|
||||||
-moz-box-ordinal-group: 4;
|
|
||||||
-ms-flex-order: 4;
|
|
||||||
-webkit-order: 4;
|
|
||||||
order: 4;
|
order: 4;
|
||||||
|
|
||||||
-webkit-flex: 1 1 0;
|
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -124,22 +96,15 @@ limitations under the License.
|
|||||||
|
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -moz-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
-webkit-flex-direction: column;
|
|
||||||
|
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
-webkit-justify-content: flex-end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_searchResultsPanel .mx_RoomView_messageListWrapper {
|
.mx_RoomView_searchResultsPanel .mx_RoomView_messageListWrapper {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
-webkit-justify-content: flex-start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_MessageList {
|
.mx_RoomView_MessageList {
|
||||||
@ -158,14 +123,10 @@ limitations under the License.
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
margin-left: 63px;
|
margin-left: 63px;
|
||||||
padding-bottom: 6px;
|
padding-bottom: 6px;
|
||||||
border-bottom: 1px solid #e5e5e5;
|
border-bottom: 1px solid $primary-hairline-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_invitePrompt {
|
.mx_RoomView_invitePrompt {
|
||||||
-webkit-box-ordinal-group: 2;
|
|
||||||
-moz-box-ordinal-group: 2;
|
|
||||||
-ms-flex-order: 2;
|
|
||||||
-webkit-order: 2;
|
|
||||||
order: 2;
|
order: 2;
|
||||||
|
|
||||||
min-width: 0px;
|
min-width: 0px;
|
||||||
@ -185,23 +146,32 @@ li.mx_RoomView_myReadMarker_container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hr.mx_RoomView_myReadMarker {
|
hr.mx_RoomView_myReadMarker {
|
||||||
border-top: solid 1px #76cfa6;
|
border-top: solid 1px $accent-color;
|
||||||
border-bottom: solid 1px #76cfa6;
|
border-bottom: solid 1px $accent-color;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_statusArea {
|
.mx_RoomView_statusArea {
|
||||||
-webkit-box-ordinal-group: 5;
|
|
||||||
-moz-box-ordinal-group: 5;
|
|
||||||
-ms-flex-order: 5;
|
|
||||||
-webkit-order: 5;
|
|
||||||
order: 5;
|
order: 5;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
-webkit-flex: 0 0 auto;
|
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
max-height: 0px;
|
||||||
|
background-color: $primary-bg-color;
|
||||||
|
z-index: 1000;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
-webkit-transition: all .2s ease-out;
|
||||||
|
-moz-transition: all .2s ease-out;
|
||||||
|
-ms-transition: all .2s ease-out;
|
||||||
|
-o-transition: all .2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomView_statusArea_expanded {
|
||||||
|
max-height: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_statusAreaBox {
|
.mx_RoomView_statusAreaBox {
|
||||||
@ -212,16 +182,16 @@ hr.mx_RoomView_myReadMarker {
|
|||||||
|
|
||||||
.mx_RoomView_statusAreaBox_line {
|
.mx_RoomView_statusAreaBox_line {
|
||||||
margin-left: 65px;
|
margin-left: 65px;
|
||||||
border-top: 1px solid #e5e5e5;
|
border-top: 1px solid $primary-hairline-color;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_callStatusBar .mx_UploadBar_uploadProgressInner {
|
.mx_RoomView_callStatusBar .mx_UploadBar_uploadProgressInner {
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_callStatusBar .mx_UploadBar_uploadFilename {
|
.mx_RoomView_callStatusBar .mx_UploadBar_uploadFilename {
|
||||||
color: #fff;
|
color: $accent-fg-color;
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,8 +204,8 @@ hr.mx_RoomView_myReadMarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_inCall .mx_RoomView_statusAreaBox {
|
.mx_RoomView_inCall .mx_RoomView_statusAreaBox {
|
||||||
background-color: #76CFA6;
|
background-color: $accent-color;
|
||||||
color: #fff;
|
color: $accent-fg-color;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,14 +227,9 @@ hr.mx_RoomView_myReadMarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView .mx_MessageComposer {
|
.mx_RoomView .mx_MessageComposer {
|
||||||
-webkit-box-ordinal-group: 6;
|
|
||||||
-moz-box-ordinal-group: 6;
|
|
||||||
-ms-flex-order: 6;
|
|
||||||
-webkit-order: 6;
|
|
||||||
order: 6;
|
order: 6;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
-webkit-flex: 0 0 auto;
|
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
}
|
}
|
||||||
@ -272,13 +237,13 @@ hr.mx_RoomView_myReadMarker {
|
|||||||
.mx_RoomView_ongoingConfCallNotification {
|
.mx_RoomView_ongoingConfCallNotification {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: #ff0064;
|
background-color: $warning-color;
|
||||||
color: #fff;
|
color: $accent-fg-color;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_ongoingConfCallNotification a {
|
.mx_RoomView_ongoingConfCallNotification a {
|
||||||
color: #fff ! important;
|
color: $accent-fg-color ! important;
|
||||||
}
|
}
|
@ -22,7 +22,6 @@ limitations under the License.
|
|||||||
padding-bottom: 22px;
|
padding-bottom: 22px;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
display: -webkit-flex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_SearchBox_searchButton {
|
.mx_SearchBox_searchButton {
|
||||||
@ -38,7 +37,6 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_SearchBox_search {
|
.mx_SearchBox_search {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
-webkit-flex: 1 1 auto;
|
|
||||||
width: 0px;
|
width: 0px;
|
||||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@ -46,7 +44,6 @@ limitations under the License.
|
|||||||
height: 24px;
|
height: 24px;
|
||||||
border: 0px ! important;
|
border: 0px ! important;
|
||||||
/* border-bottom: 1px solid rgba(0, 0, 0, 0.1) ! important; */
|
/* border-bottom: 1px solid rgba(0, 0, 0, 0.1) ! important; */
|
||||||
background-color: transparent;
|
|
||||||
border: 0px;
|
border: 0px;
|
||||||
}
|
}
|
||||||
|
|
@ -26,7 +26,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_UploadBar_uploadProgressInner {
|
.mx_UploadBar_uploadProgressInner {
|
||||||
background-color: #76cfa6;
|
background-color: $accent-color;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ limitations under the License.
|
|||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-left: 65px;
|
margin-left: 65px;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_UploadBar_uploadIcon {
|
.mx_UploadBar_uploadIcon {
|
||||||
@ -57,5 +57,5 @@ limitations under the License.
|
|||||||
float: right;
|
float: right;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-right: 30px;
|
margin-right: 30px;
|
||||||
color: #76cfa6;
|
color: $accent-color;
|
||||||
}
|
}
|
@ -20,34 +20,19 @@ limitations under the License.
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -moz-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
-webkit-flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_UserSettings .mx_RoomHeader {
|
.mx_UserSettings .mx_RoomHeader {
|
||||||
-webkit-box-ordinal-group: 1;
|
|
||||||
-moz-box-ordinal-group: 1;
|
|
||||||
-ms-flex-order: 1;
|
|
||||||
-webkit-order: 1;
|
|
||||||
order: 1;
|
order: 1;
|
||||||
|
|
||||||
-webkit-flex: 0 0 70px;
|
|
||||||
flex: 0 0 70px;
|
flex: 0 0 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_UserSettings_body {
|
.mx_UserSettings_body {
|
||||||
-webkit-box-ordinal-group: 2;
|
|
||||||
-moz-box-ordinal-group: 2;
|
|
||||||
-ms-flex-order: 2;
|
|
||||||
-webkit-order: 2;
|
|
||||||
order: 2;
|
order: 2;
|
||||||
|
|
||||||
-webkit-flex: 1 1 0;
|
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
|
|
||||||
margin-top: -20px;
|
margin-top: -20px;
|
||||||
@ -58,7 +43,7 @@ limitations under the License.
|
|||||||
clear: both;
|
clear: both;
|
||||||
margin-left: 63px;
|
margin-left: 63px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: #3d3b39;
|
color: $h3-color;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
margin-top: 26px;
|
margin-top: 26px;
|
||||||
@ -84,8 +69,8 @@ limitations under the License.
|
|||||||
border-radius: 36px;
|
border-radius: 36px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #fff;
|
color: $accent-fg-color;
|
||||||
background-color: #76cfa6;
|
background-color: $accent-color;
|
||||||
width: auto;
|
width: auto;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 7px;
|
padding: 7px;
|
||||||
@ -95,7 +80,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_UserSettings_button.danger {
|
.mx_UserSettings_button.danger {
|
||||||
background-color: #ff0064;
|
background-color: $warning-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_UserSettings_section {
|
.mx_UserSettings_section {
|
||||||
@ -166,15 +151,15 @@ limitations under the License.
|
|||||||
{
|
{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
border-bottom: 1px solid rgba(151, 151, 151, 0.5);
|
border-bottom: 1px solid $input-underline-color;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
width: 240px;
|
width: 240px;
|
||||||
color: rgba(74, 74, 74, 0.9);
|
color: $input-fg-color;
|
||||||
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
|
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_UserSettings_addThreepid {
|
.mx_UserSettings_threepidButton {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
padding-left: 0.5em;
|
padding-left: 0.5em;
|
||||||
position: relative;
|
position: relative;
|
@ -18,21 +18,15 @@ limitations under the License.
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -moz-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: -webkit-flex;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
-webkit-align-items: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
-webkit-justify-content: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login h2 {
|
.mx_Login h2 {
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
margin-top: 32px;
|
margin-top: 32px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
@ -48,12 +42,24 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_Login_logo {
|
.mx_Login_logo {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
height: 195px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_logo img {
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Login_support {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 0px;
|
||||||
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_field {
|
.mx_Login_field {
|
||||||
width: 100%;
|
width: 280px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border: 1px solid #c7c7c7;
|
border: 1px solid $strong-input-border-color;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 9px;
|
padding: 9px;
|
||||||
@ -75,9 +81,9 @@ limitations under the License.
|
|||||||
border-radius: 40px;
|
border-radius: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
background-color: #76cfa6;
|
background-color: $accent-color;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #fff;
|
color: $accent-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_label {
|
.mx_Login_label {
|
||||||
@ -99,7 +105,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_create:link {
|
.mx_Login_create:link {
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_links {
|
.mx_Login_links {
|
||||||
@ -112,7 +118,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_links a:link {
|
.mx_Login_links a:link {
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_prompt {
|
.mx_Login_prompt {
|
||||||
@ -127,7 +133,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_forgot:link {
|
.mx_Login_forgot:link {
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_loader {
|
.mx_Login_loader {
|
||||||
@ -147,7 +153,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_Login_error {
|
.mx_Login_error {
|
||||||
color: #ff2020;
|
color: $warning-color;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
/*
|
/*
|
@ -21,7 +21,7 @@ limitations under the License.
|
|||||||
.mx_BaseAvatar_initial {
|
.mx_BaseAvatar_initial {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
color: #fff;
|
color: $avatar-initial-color;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
speak: none;
|
speak: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@ -31,4 +31,5 @@ limitations under the License.
|
|||||||
.mx_BaseAvatar_image {
|
.mx_BaseAvatar_image {
|
||||||
border-radius: 40px;
|
border-radius: 40px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
background-color: #fff;
|
||||||
}
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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_BugReportDialog_input {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
@ -36,7 +36,7 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_ChatInviteDialog_inputContainer {
|
.mx_ChatInviteDialog_inputContainer {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border: solid 1px #f0f0f0;
|
border: solid 1px $input-border-color;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
@ -49,7 +49,7 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_ChatInviteDialog_error {
|
.mx_ChatInviteDialog_error {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
color: #ff0064;
|
color: $warning-color;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,3 +63,9 @@ limitations under the License.
|
|||||||
.mx_ChatInviteDialog_cancel object {
|
.mx_ChatInviteDialog_cancel object {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_ChatInviteDialog_addressSelectHeader {
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 150%;
|
||||||
|
text-indent: 4px;
|
||||||
|
}
|
@ -24,7 +24,7 @@ limitations under the License.
|
|||||||
border: 0px;
|
border: 0px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
border-radius: 40px;
|
border-radius: 40px;
|
||||||
border: solid 1px #76cfa6;
|
border: solid 1px $accent-color;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||||
@ -34,6 +34,6 @@ limitations under the License.
|
|||||||
padding-right: 1.5em;
|
padding-right: 1.5em;
|
||||||
outline: none;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #76cfa6;
|
color: $accent-color;
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
}
|
}
|
@ -16,9 +16,9 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_SetDisplayNameDialog_input {
|
.mx_SetDisplayNameDialog_input {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid $input-border-color;
|
||||||
padding: 9px;
|
padding: 9px;
|
||||||
color: #454545;
|
color: $primary-fg-color;
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
Copyright 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_UnknownDeviceDialog .mx_MemberDeviceInfo {
|
||||||
|
float: right;
|
||||||
|
clear: both;
|
||||||
|
padding: 0px;
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_UnknownDeviceDialog .mx_MemberDeviceInfo_textButton {
|
||||||
|
border: 0px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 40px;
|
||||||
|
border: solid 1px $accent-color;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: 'Open Sans', Arial, Helvetica, Sans-Serif;
|
||||||
|
margin-left: 0px;
|
||||||
|
margin-right: 8px;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
width: 70px;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: $accent-color;
|
||||||
|
background-color: $primary-bg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_UnknownDeviceDialog .mx_UnknownDeviceDialog_deviceList li {
|
||||||
|
height: 40px;
|
||||||
|
border-bottom: 1px solid $primary-hairline-color;
|
||||||
|
}
|
@ -16,13 +16,13 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_AddressSelector {
|
.mx_AddressSelector {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
width: 485px;
|
width: 485px;
|
||||||
max-height: 116px;
|
max-height: 116px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
border: solid 1px #76cfa6;
|
border: solid 1px $accent-color;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,15 +31,15 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_AddressSelector_addressListElement .mx_AddressTile {
|
.mx_AddressSelector_addressListElement .mx_AddressTile {
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
border: solid 1px #fff;
|
border: solid 1px $primary-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_AddressSelector_addressListElement.mx_AddressSelector_selected {
|
.mx_AddressSelector_addressListElement.mx_AddressSelector_selected {
|
||||||
background-color: #eaf5f0; /* selected colour */
|
background-color: $selected-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_AddressSelector_addressListElement.mx_AddressSelector_selected .mx_AddressTile {
|
.mx_AddressSelector_addressListElement.mx_AddressSelector_selected .mx_AddressTile {
|
||||||
background-color: #eaf5f0; /* selected colour */
|
background-color: $selected-color;
|
||||||
border: solid 1px #eaf5f0; /* selected colour */
|
border: solid 1px $selected-color;
|
||||||
}
|
}
|
@ -18,9 +18,9 @@ limitations under the License.
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-color: rgba(74, 73, 74, 0.1);
|
background-color: rgba(74, 73, 74, 0.1);
|
||||||
border: solid 1px #f0f0f0;
|
border: solid 1px $input-border-color;
|
||||||
line-height: 26px;
|
line-height: 26px;
|
||||||
color: #454545;
|
color: $primary-fg-color;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
@ -28,8 +28,8 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_AddressTile.mx_AddressTile_error {
|
.mx_AddressTile.mx_AddressTile_error {
|
||||||
background-color: rgba(255, 0, 100, 0.1);
|
background-color: rgba(255, 0, 100, 0.1);
|
||||||
color: #ff0064;
|
color: $warning-color;
|
||||||
border-color: #ff0064;
|
border-color: $warning-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_AddressTile_network {
|
.mx_AddressTile_network {
|
||||||
@ -106,7 +106,7 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_AddressTile_email.mx_AddressTile_justified {
|
.mx_AddressTile_email.mx_AddressTile_justified {
|
||||||
width: 380px; /* name + id width */
|
width: 200px; /* same as id width */
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
@ -17,19 +17,17 @@ limitations under the License.
|
|||||||
.mx_DirectorySearchBox {
|
.mx_DirectorySearchBox {
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border: 1px solid #c7c7c7;
|
border: 1px solid $strong-input-border-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_DirectorySearchBox_container {
|
.mx_DirectorySearchBox_container {
|
||||||
display: flex;
|
display: flex;
|
||||||
display: -webkit-flex;
|
|
||||||
padding-left: 9px;
|
padding-left: 9px;
|
||||||
padding-right: 9px;
|
padding-right: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_DirectorySearchBox_input {
|
.mx_DirectorySearchBox_input {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
-webkit-flex-grow: 1;
|
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
@ -44,9 +42,9 @@ input[type=text].mx_DirectorySearchBox_input:focus {
|
|||||||
padding: 3px;
|
padding: 3px;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
background-color: #efefef;
|
background-color: $plinth-bg-color;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-image: url('img/icon-return.svg');
|
background-image: url('../../img/icon-return.svg');
|
||||||
background-position: 8px 70%;
|
background-position: 8px 70%;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
text-indent: 18px;
|
text-indent: 18px;
|
||||||
@ -63,7 +61,7 @@ input[type=text].mx_DirectorySearchBox_input:focus {
|
|||||||
.mx_DirectorySearchBox_clear {
|
.mx_DirectorySearchBox_clear {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
background: url('img/icon_context_delete.svg');
|
background: url('../../img/icon_context_delete.svg');
|
||||||
background-position: 0 50%;
|
background-position: 0 50%;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
width: 15px;
|
width: 15px;
|
@ -31,6 +31,6 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mx_MemberEventListSummary_toggle {
|
.mx_MemberEventListSummary_toggle {
|
||||||
color:#76cfa6;
|
color:$accent-color;
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
}
|
}
|
@ -16,10 +16,10 @@ limitations under the License.
|
|||||||
|
|
||||||
.mx_ProgressBar {
|
.mx_ProgressBar {
|
||||||
height: 5px;
|
height: 5px;
|
||||||
border: 1px solid black;
|
border: 1px solid $progressbar-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ProgressBar_fill {
|
.mx_ProgressBar_fill {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #000;
|
background-color: $progressbar-color;
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
.mx_UserPill {
|
.mx_UserPill {
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #76cfa6;
|
background-color: $accent-color;
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomPill {
|
.mx_RoomPill {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
color: #76cfa6;
|
color: $accent-color;
|
||||||
border: 1px solid #76cfa6;
|
border: 1px solid $accent-color;
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
@ -27,5 +27,5 @@ limitations under the License.
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
color: #4a4a4a;
|
color: $primary-fg-color;
|
||||||
}
|
}
|
@ -22,18 +22,18 @@ limitations under the License.
|
|||||||
.mx_MImageBody_thumbnail {
|
.mx_MImageBody_thumbnail {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
/*
|
/*
|
||||||
background-color: #fff;
|
background-color: $primary-bg-color;
|
||||||
border: 2px solid #fff;
|
border: 2px solid $primary-bg-color;
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MImageBody_download {
|
.mx_MImageBody_download {
|
||||||
color: #76cfa6;
|
color: $accent-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MImageBody_download a {
|
.mx_MImageBody_download a {
|
||||||
color: #76cfa6;
|
color: $accent-color;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,3 +44,17 @@ limitations under the License.
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove the border and padding for iframes for download links. */
|
||||||
|
.mx_MImageBody_download iframe {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
/* Set the height of the iframe to be 1 line of text.
|
||||||
|
* Iframes don't automatically size themselves to fit their content.
|
||||||
|
* So either we have to fix the height of the iframe using CSS or
|
||||||
|
* use javascript's cross-origin postMessage API to communicate how
|
||||||
|
* big the content of the iframe is. */
|
||||||
|
height: 1.5em;
|
||||||
|
}
|