diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 0b4266c0b5..2ccf83489c 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -1,14 +1,8 @@ # autogenerated file: run scripts/generate-eslint-error-ignore-file to update. -src/autocomplete/AutocompleteProvider.js -src/autocomplete/Autocompleter.js -src/autocomplete/UserProvider.js src/component-index.js src/components/structures/BottomLeftMenu.js -src/components/structures/CompatibilityPage.js src/components/structures/CreateRoom.js -src/components/structures/LoggedInView.js -src/components/structures/login/ForgotPassword.js src/components/structures/MessagePanel.js src/components/structures/NotificationPanel.js src/components/structures/RoomDirectory.js @@ -18,7 +12,6 @@ src/components/structures/ScrollPanel.js src/components/structures/SearchBox.js src/components/structures/TimelinePanel.js src/components/structures/UploadBar.js -src/components/structures/UserSettings.js src/components/views/avatars/BaseAvatar.js src/components/views/avatars/MemberAvatar.js src/components/views/create_room/RoomAlias.js @@ -35,11 +28,6 @@ src/components/views/elements/UserSelector.js src/components/views/globals/MatrixToolbar.js src/components/views/globals/NewVersionBar.js src/components/views/globals/UpdateCheckBar.js -src/components/views/login/CountryDropdown.js -src/components/views/login/InteractiveAuthEntryComponents.js -src/components/views/login/PasswordLogin.js -src/components/views/login/RegistrationForm.js -src/components/views/login/ServerConfig.js src/components/views/messages/MFileBody.js src/components/views/messages/RoomAvatarEvent.js src/components/views/messages/TextualBody.js @@ -52,9 +40,7 @@ src/components/views/rooms/LinkPreviewWidget.js src/components/views/rooms/MemberDeviceInfo.js src/components/views/rooms/MemberInfo.js src/components/views/rooms/MemberList.js -src/components/views/rooms/MemberTile.js src/components/views/rooms/MessageComposer.js -src/components/views/rooms/MessageComposerInput.js src/components/views/rooms/PinnedEventTile.js src/components/views/rooms/RoomList.js src/components/views/rooms/RoomPreviewBar.js @@ -76,7 +62,6 @@ src/HtmlUtils.js src/ImageUtils.js src/languageHandler.js src/linkify-matrix.js -src/Login.js src/Markdown.js src/MatrixClientPeg.js src/Modal.js @@ -104,12 +89,10 @@ src/VectorConferenceHandler.js src/Velociraptor.js src/WhoIsTyping.js src/wrappers/withMatrixClient.js -test/components/structures/login/Registration-test.js test/components/structures/MessagePanel-test.js test/components/structures/ScrollPanel-test.js test/components/structures/TimelinePanel-test.js test/components/views/dialogs/InteractiveAuthDialog-test.js -test/components/views/login/RegistrationForm-test.js test/components/views/rooms/MessageComposerInput-test.js test/components/views/rooms/RoomSettings-test.js test/mock-clock.js diff --git a/.eslintrc.js b/.eslintrc.js index 971809f851..ec48f6b2ff 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -42,9 +42,8 @@ module.exports = { // bind or arrow function in props causes performance issues // (but we currently use them in some places) - "react/jsx-no-bind": ["warn", { - "ignoreRefs": true, - }], + // It's disabled here, but we should using it sparingly. + "react/jsx-no-bind": "off", "react/jsx-key": ["error"], // Components in JSX should always be defined. diff --git a/.travis.yml b/.travis.yml index 0def6d50f7..ebb772fd0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,22 @@ node_js: addons: chrome: stable install: - - npm install -# install synapse prerequisites for end to end tests - - sudo apt-get install build-essential python2.7-dev libffi-dev python-pip python-setuptools sqlite3 libssl-dev python-virtualenv libjpeg-dev libxslt1-dev -script: - ./scripts/travis.sh + - ./scripts/travis/install-deps.sh +matrix: + include: + - name: Linting Checks + script: + # run the linter, but exclude any files known to have errors or warnings. + - npm run lintwithexclusions + # - name: End-to-End Tests + # if: branch = develop + # install: + # - sudo apt-get install build-essential python2.7-dev libffi-dev python-pip python-setuptools sqlite3 libssl-dev python-virtualenv libjpeg-dev libxslt1-dev + # script: + # - ./scripts/travis/end-to-end-tests.sh + - name: Unit Tests + script: + - ./scripts/travis/unit-tests.sh + - name: Riot-web Unit Tests + script: + - ./scripts/travis/riot-unit-tests.sh diff --git a/README.md b/README.md index ec95fbd132..c70f68902b 100644 --- a/README.md +++ b/README.md @@ -127,3 +127,36 @@ Github Issues All issues should be filed under https://github.com/vector-im/riot-web/issues for now. + +Development +=========== + +Ensure you have the latest stable Node JS runtime installed (v8.x is the best choice). Then check out +the code and pull in dependencies: + +```bash +git clone https://github.com/matrix-org/matrix-react-sdk.git +cd matrix-react-sdk +git checkout develop +npm install +``` + +`matrix-react-sdk` depends on `matrix-js-sdk`. To make use of changes in the +latter and to ensure tests run against the develop branch of `matrix-js-sdk`, +you should run the following which will sync changes from the JS sdk here. + +```bash +npm link ../matrix-js-sdk +``` + +Command assumes a checked out and installed `matrix-js-sdk` folder in parent +folder. + +Running tests +============= + +Ensure you've followed the above development instructions and then: + +```bash +npm run test +``` diff --git a/karma.conf.js b/karma.conf.js index 4d699599cb..93063dbc04 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -168,6 +168,10 @@ module.exports = function (config) { path.resolve('./test'), ] }, + { + test: /\.(gif|png|svg|ttf)$/, + loader: 'file-loader', + }, ], noParse: [ // for cross platform compatibility use [\\\/] as the path separator diff --git a/package.json b/package.json index 5d765a5bb2..9ea3989f20 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "scripts": { "reskindex": "node scripts/reskindex.js -h header", "reskindex:watch": "node scripts/reskindex.js -h header -w", + "rethemendex": "res/css/rethemendex.sh", "i18n": "matrix-gen-i18n", "prunei18n": "matrix-prune-i18n", "build": "npm run reskindex && npm run start:init", @@ -47,7 +48,7 @@ "start:init": "babel src -d lib --source-maps --copy-files", "lint": "eslint src/", "lintall": "eslint src/ test/", - "lintwithexclusions": "eslint --max-warnings 20 --ignore-path .eslintignore.errorfiles src test", + "lintwithexclusions": "eslint --max-warnings 0 --ignore-path .eslintignore.errorfiles src test", "clean": "rimraf lib", "prepublish": "npm run clean && npm run build && git rev-parse HEAD > git-revision.txt", "test": "karma start --single-run=true --browsers ChromeHeadless", @@ -118,13 +119,14 @@ "babel-preset-react": "^6.24.1", "chokidar": "^1.6.1", "concurrently": "^4.0.1", - "eslint": "^5.8.0", + "eslint": "^5.12.0", "eslint-config-google": "^0.7.1", "eslint-plugin-babel": "^5.2.1", "eslint-plugin-flowtype": "^2.30.0", "eslint-plugin-react": "^7.7.0", "estree-walker": "^0.5.0", "expect": "^23.6.0", + "file-loader": "^3.0.1", "flow-parser": "^0.57.3", "jest-mock": "^23.2.0", "karma": "^3.0.0", diff --git a/res/css/_common.scss b/res/css/_common.scss index 97ae5412e1..56af1ab519 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -30,8 +30,6 @@ body { color: $primary-fg-color; border: 0px; margin: 0px; - /* This should render the fonts the same accross browsers */ - -webkit-font-smoothing: subpixel-antialiased; } .error, .warning { @@ -49,20 +47,14 @@ h2 { a:hover, a:link, a:visited { - color: $accent-color; + color: $accent-color-alt; } input[type=text], input[type=password], textarea { background-color: transparent; - color: $primary-fg-color; -} - -input[type=text].error, input[type=password].error { - border: 1px solid $warning-color; } input[type=text]:focus, input[type=password]:focus, textarea:focus { - border: 1px solid $accent-color; outline: none; box-shadow: none; } @@ -83,11 +75,6 @@ textarea { transition: opacity 0.2s ease-in-out; } -.mx_fadable.mx_fadable_faded { - opacity: 0.3; - pointer-events: none; -} - /* XXX: critical hack to GeminiScrollbar to allow them to work in FF 42 and Chrome 48. Stop the scrollbar view from pushing out the container's overall sizing, which causes flexbox to adapt to the new size and cause the view to keep growing. @@ -170,10 +157,10 @@ textarea { font-weight: 300; font-size: 15px; position: relative; - padding: 0 58px 36px; + padding: 40px 58px 36px 58px; width: 60%; max-width: 704px; - box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2); + box-shadow: 2px 15px 30px 0 $dialog-shadow-color; max-height: 80%; overflow-y: auto; } @@ -184,7 +171,7 @@ textarea { left: 0; width: 100%; height: 100%; - background-color: $dialog-background-bg-color; + background-color: $dialog-backdrop-color; opacity: 0.8; } @@ -203,15 +190,36 @@ textarea { pointer-events: none; } -.mx_Dialog_cancelButton { - position: absolute; - right: 11px; - top: 13px; - cursor: pointer; +.mx_Dialog_header { + position: relative; } -.mx_Dialog_cancelButton object { - pointer-events: none; +.mx_Dialog_title { + font-weight: bold; + font-size: 22px; + line-height: 36px; + color: $primary-fg-color; +} + +.mx_Dialog_header.mx_Dialog_headerWithButton > .mx_Dialog_title { + text-align: center; +} + +.mx_Dialog_title.danger { + color: $warning-color; +} + +.mx_Dialog_cancelButton { + mask: url('$(res)/img/feather-icons/cancel.svg'); + mask-repeat: no-repeat; + mask-position: center; + width: 36px; + height: 36px; + background-color: $primary-fg-color; + cursor: pointer; + position: absolute; + top: 20px; + right: 20px; } .mx_Dialog_content { @@ -267,19 +275,6 @@ textarea { color: $accent-color; } -.mx_Dialog_title { - min-height: 16px; - padding-top: 40px; - font-weight: bold; - font-size: 22px; - line-height: 1.4; - color: $primary-fg-color; -} - -.mx_Dialog_title.danger { - color: $warning-color; -} - .mx_TextInputDialog_label { text-align: left; padding-bottom: 12px; @@ -314,7 +309,7 @@ textarea { } .mx_textButton { - @mixin mx_DialogButton_small; + @mixin mx_DialogButton_small; } .mx_textButton:hover { diff --git a/res/css/_components.scss b/res/css/_components.scss index 5633b7ec8f..e017d4b95a 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -1,6 +1,6 @@ // autogenerated by rethemendex.sh @import "./_common.scss"; -@import "./_fonts.scss"; +@import "./structures/_AutoHideScrollbar.scss"; @import "./structures/_CompatibilityPage.scss"; @import "./structures/_ContextualMenu.scss"; @import "./structures/_CreateRoom.scss"; @@ -8,7 +8,6 @@ @import "./structures/_GroupView.scss"; @import "./structures/_HomePage.scss"; @import "./structures/_LeftPanel.scss"; -@import "./structures/_LoginBox.scss"; @import "./structures/_MatrixChat.scss"; @import "./structures/_MyGroups.scss"; @import "./structures/_NotificationPanel.scss"; @@ -18,17 +17,31 @@ @import "./structures/_RoomSubList.scss"; @import "./structures/_RoomView.scss"; @import "./structures/_SearchBox.scss"; +@import "./structures/_TabbedView.scss"; @import "./structures/_TagPanel.scss"; +@import "./structures/_TopLeftMenuButton.scss"; @import "./structures/_UploadBar.scss"; @import "./structures/_UserSettings.scss"; @import "./structures/_ViewSource.scss"; -@import "./structures/login/_Login.scss"; +@import "./structures/auth/_Login.scss"; +@import "./views/auth/_AuthBody.scss"; +@import "./views/auth/_AuthButtons.scss"; +@import "./views/auth/_AuthFooter.scss"; +@import "./views/auth/_AuthHeader.scss"; +@import "./views/auth/_AuthHeaderLogo.scss"; +@import "./views/auth/_AuthPage.scss"; +@import "./views/auth/_CountryDropdown.scss"; +@import "./views/auth/_InteractiveAuthEntryComponents.scss"; +@import "./views/auth/_LanguageSelector.scss"; +@import "./views/auth/_ServerConfig.scss"; +@import "./views/auth/_ServerTypeSelector.scss"; @import "./views/avatars/_BaseAvatar.scss"; @import "./views/avatars/_MemberStatusMessageAvatar.scss"; @import "./views/context_menus/_MessageContextMenu.scss"; @import "./views/context_menus/_RoomTileContextMenu.scss"; @import "./views/context_menus/_StatusMessageContextMenu.scss"; @import "./views/context_menus/_TagTileContextMenu.scss"; +@import "./views/context_menus/_TopLeftMenu.scss"; @import "./views/dialogs/_BugReportDialog.scss"; @import "./views/dialogs/_ChangelogDialog.scss"; @import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss"; @@ -41,14 +54,17 @@ @import "./views/dialogs/_EncryptedEventDialog.scss"; @import "./views/dialogs/_GroupAddressPicker.scss"; @import "./views/dialogs/_RestoreKeyBackupDialog.scss"; +@import "./views/dialogs/_RoomSettingsDialog.scss"; @import "./views/dialogs/_RoomUpgradeDialog.scss"; @import "./views/dialogs/_SetEmailDialog.scss"; @import "./views/dialogs/_SetMxIdDialog.scss"; @import "./views/dialogs/_SetPasswordDialog.scss"; +@import "./views/dialogs/_SettingsDialog.scss"; @import "./views/dialogs/_ShareDialog.scss"; @import "./views/dialogs/_UnknownDeviceDialog.scss"; +@import "./views/dialogs/_UserSettingsDialog.scss"; @import "./views/dialogs/keybackup/_CreateKeyBackupDialog.scss"; -@import "./views/dialogs/keybackup/_NewRecoveryMethodDialog.scss"; +@import "./views/dialogs/keybackup/_KeyBackupFailedDialog.scss"; @import "./views/dialogs/keybackup/_RestoreKeyBackupDialog.scss"; @import "./views/directory/_NetworkDropdown.scss"; @import "./views/elements/_AccessibleButton.scss"; @@ -57,22 +73,24 @@ @import "./views/elements/_DirectorySearchBox.scss"; @import "./views/elements/_Dropdown.scss"; @import "./views/elements/_EditableItemList.scss"; +@import "./views/elements/_Field.scss"; +@import "./views/elements/_HexVerify.scss"; @import "./views/elements/_ImageView.scss"; @import "./views/elements/_InlineSpinner.scss"; @import "./views/elements/_MemberEventListSummary.scss"; @import "./views/elements/_ProgressBar.scss"; @import "./views/elements/_ReplyThread.scss"; +@import "./views/elements/_ResizeHandle.scss"; @import "./views/elements/_RichText.scss"; @import "./views/elements/_RoleButton.scss"; @import "./views/elements/_Spinner.scss"; @import "./views/elements/_SyntaxHighlight.scss"; +@import "./views/elements/_ToggleSwitch.scss"; @import "./views/elements/_ToolTipButton.scss"; @import "./views/globals/_MatrixToolbar.scss"; @import "./views/groups/_GroupPublicityToggle.scss"; @import "./views/groups/_GroupRoomList.scss"; @import "./views/groups/_GroupUserSettings.scss"; -@import "./views/login/_InteractiveAuthEntryComponents.scss"; -@import "./views/login/_ServerConfig.scss"; @import "./views/messages/_CreateEvent.scss"; @import "./views/messages/_DateSeparator.scss"; @import "./views/messages/_MEmoteBody.scss"; @@ -88,8 +106,10 @@ @import "./views/messages/_UnknownBody.scss"; @import "./views/rooms/_AppsDrawer.scss"; @import "./views/rooms/_Autocomplete.scss"; +@import "./views/rooms/_AuxPanel.scss"; @import "./views/rooms/_EntityTile.scss"; @import "./views/rooms/_EventTile.scss"; +@import "./views/rooms/_JumpToBottomButton.scss"; @import "./views/rooms/_LinkPreviewWidget.scss"; @import "./views/rooms/_MemberDeviceInfo.scss"; @import "./views/rooms/_MemberInfo.scss"; @@ -112,10 +132,24 @@ @import "./views/rooms/_SearchableEntityList.scss"; @import "./views/rooms/_Stickers.scss"; @import "./views/rooms/_TopUnreadMessagesBar.scss"; +@import "./views/rooms/_WhoIsTypingTile.scss"; @import "./views/settings/_DevicesPanel.scss"; +@import "./views/settings/_EmailAddresses.scss"; @import "./views/settings/_IntegrationsManager.scss"; @import "./views/settings/_KeyBackupPanel.scss"; @import "./views/settings/_Notifications.scss"; +@import "./views/settings/_PhoneNumbers.scss"; +@import "./views/settings/_ProfileSettings.scss"; +@import "./views/settings/tabs/_GeneralRoomSettingsTab.scss"; +@import "./views/settings/tabs/_GeneralUserSettingsTab.scss"; +@import "./views/settings/tabs/_HelpSettingsTab.scss"; +@import "./views/settings/tabs/_NotificationSettingsTab.scss"; +@import "./views/settings/tabs/_PreferencesSettingsTab.scss"; +@import "./views/settings/tabs/_RolesRoomSettingsTab.scss"; +@import "./views/settings/tabs/_SecurityRoomSettingsTab.scss"; +@import "./views/settings/tabs/_SecuritySettingsTab.scss"; +@import "./views/settings/tabs/_SettingsTab.scss"; +@import "./views/settings/tabs/_VoiceSettingsTab.scss"; @import "./views/voip/_CallView.scss"; @import "./views/voip/_IncomingCallbox.scss"; @import "./views/voip/_VideoView.scss"; diff --git a/res/css/structures/_AutoHideScrollbar.scss b/res/css/structures/_AutoHideScrollbar.scss new file mode 100644 index 0000000000..cb0d6f7f09 --- /dev/null +++ b/res/css/structures/_AutoHideScrollbar.scss @@ -0,0 +1,83 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +1. for browsers that support native overlay auto-hiding scrollbars +*/ +.mx_AutoHideScrollbar { + overflow-x: hidden; + overflow-y: auto; + -ms-overflow-style: -ms-autohiding-scrollbar; +} +/* +2. webkit also supports overflow:overlay where the scrollbars don't take any space +in the layout but they don't autohide, so do that only on hover +*/ +body.mx_scrollbar_overlay_noautohide .mx_AutoHideScrollbar { + overflow-y: hidden; +} + +body.mx_scrollbar_overlay_noautohide .mx_AutoHideScrollbar:hover { + overflow-y: overlay; +} +/* +3. as a last fallback, compensate for the scrollbar taking up space in the layout +by having giving the child element (.mx_AutoHideScrollbar_offset) a +negative right margin of the width of the scrollbar when the container +is overflowing. This is what Firefox ends up using. Overflow is detected +in javascript, and adds the mx_AutoHideScrollbar_overflow class to the container. +This only works in Firefox, which should be fine as this fallback is only needed there. +*/ +body.mx_scrollbar_nooverlay { + .mx_AutoHideScrollbar { + overflow-y: hidden; + } + + .mx_AutoHideScrollbar:hover { + overflow-y: auto; + } + + /* + offset scrollbar width with negative margin-right + + include before and after psuedo-elements here so they can + be used to do something interesting like scroll-indicating + gradients (see IndicatorScrollBar) + */ + .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow > .mx_AutoHideScrollbar_offset, + .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow::before, + .mx_AutoHideScrollbar:hover.mx_AutoHideScrollbar_overflow::after + { + margin-right: calc(-1 * var(--scrollbar-width)); + } +} + +// style the native scrollbars ... +// ... standard css scrollbars (firefox at time of writing) +.mx_AutoHideScrollbar { + scrollbar-color: $scrollbar-thumb-color $scrollbar-track-color; + scrollbar-width: thin; +} +// or fallback for webkit browsers +::-webkit-scrollbar { + width: 6px; + background-color: $scrollbar-track-color; +} + +::-webkit-scrollbar-thumb { + background-color: $scrollbar-thumb-color; + border-radius: 3px; +} diff --git a/res/css/structures/_ContextualMenu.scss b/res/css/structures/_ContextualMenu.scss index 7474c3d107..001c405e15 100644 --- a/res/css/structures/_ContextualMenu.scss +++ b/res/css/structures/_ContextualMenu.scss @@ -30,12 +30,11 @@ limitations under the License. } .mx_ContextualMenu { - border: solid 1px $menu-border-color; border-radius: 4px; + box-shadow: 4px 4px 12px 0 rgba(118, 131, 156, 0.6);; background-color: $menu-bg-color; color: $primary-fg-color; position: absolute; - padding: 6px; font-size: 14px; z-index: 5001; } @@ -51,7 +50,7 @@ limitations under the License. width: 0; height: 0; border-top: 8px solid transparent; - border-left: 8px solid $menu-border-color; + border-left: 8px solid $menu-bg-color; border-bottom: 8px solid transparent; } @@ -78,7 +77,7 @@ limitations under the License. width: 0; height: 0; border-top: 8px solid transparent; - border-right: 8px solid $menu-border-color; + border-right: 8px solid $menu-bg-color; border-bottom: 8px solid transparent; } @@ -105,7 +104,7 @@ limitations under the License. width: 0; height: 0; border-left: 8px solid transparent; - border-bottom: 8px solid $menu-border-color; + border-bottom: 8px solid $menu-bg-color; border-right: 8px solid transparent; } @@ -132,7 +131,7 @@ limitations under the License. width: 0; height: 0; border-left: 8px solid transparent; - border-top: 8px solid $menu-border-color; + border-top: 8px solid $menu-bg-color; border-right: 8px solid transparent; } diff --git a/res/css/structures/_FilePanel.scss b/res/css/structures/_FilePanel.scss index 87dc0aa756..677fa34c6f 100644 --- a/res/css/structures/_FilePanel.scss +++ b/res/css/structures/_FilePanel.scss @@ -16,11 +16,7 @@ limitations under the License. .mx_FilePanel { order: 2; - flex: 1 1 0; - - width: 100%; - overflow-y: auto; } diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss index 02e5a948e9..398c51ba91 100644 --- a/res/css/structures/_GroupView.scss +++ b/res/css/structures/_GroupView.scss @@ -15,10 +15,6 @@ limitations under the License. */ .mx_GroupView { - max-width: 960px; - width: 100%; - margin-left: auto; - margin-right: auto; display: flex; flex-direction: column; overflow: hidden; @@ -29,7 +25,6 @@ limitations under the License. } .mx_GroupView_header { - max-width: 960px; min-height: 70px; align-items: center; display: flex; @@ -39,6 +34,8 @@ limitations under the License. .mx_GroupView_header_view { border-bottom: 1px solid $primary-hairline-color; padding-bottom: 0px; + padding-left: 8px; + padding-right: 8px; } .mx_GroupView_header_avatar, .mx_GroupView_header_info { @@ -162,6 +159,11 @@ limitations under the License. line-height: 2em; } +.mx_GroupView > .mx_MainSplit { + flex: 1; + display: flex; +} + .mx_GroupView_body { flex-grow: 1; } diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index 7cf6dd1119..941417eccc 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -15,32 +15,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_LeftPanel { - position: relative; - - display: flex; - flex-direction: column; -} - .mx_LeftPanel_container { display: flex; - /* LeftPanel 235px */ - flex: 0 0 235px; + /* LeftPanel 260px */ + min-width: 260px; + flex: 0 0 auto; } -.mx_LeftPanel_container.mx_LeftPanel_container_hasTagPanel { - /* TagPanel 60px + LeftPanel 235px */ - flex: 0 0 295px; +.mx_LeftPanel_container.collapsed { + min-width: unset; + /* Collapsed LeftPanel 70px */ + flex: 0 0 70px; } -.mx_LeftPanel_container_collapsed { - /* Collapsed LeftPanel 60px */ - flex: 0 0 60px; -} - -.mx_LeftPanel_container_collapsed.mx_LeftPanel_container_hasTagPanel { - /* TagPanel 60px + Collapsed LeftPanel 60px */ - flex: 0 0 120px; +.mx_LeftPanel_container.collapsed.mx_LeftPanel_container_hasTagPanel { + /* TagPanel 70px + Collapsed LeftPanel 70px */ + flex: 0 0 140px; } .mx_LeftPanel_hideButton { @@ -51,8 +41,12 @@ limitations under the License. cursor: pointer; } -.mx_LeftPanel_callView { - +.mx_LeftPanel { + flex: 1; + overflow-x: hidden; + display: flex; + flex-direction: column; + min-height: 0; } .mx_LeftPanel .mx_AppTile_mini { @@ -68,7 +62,7 @@ limitations under the License. z-index: 6; } -.mx_LeftPanel.collapsed .mx_BottomLeftMenu { +.mx_LeftPanel_container.collapsed .mx_BottomLeftMenu { flex: 0 0 160px; margin-bottom: 9px; } @@ -91,12 +85,6 @@ limitations under the License. pointer-events: none; } -.collapsed .mx_RoleButton { - margin-right: 0px ! important; - padding-top: 3px ! important; - padding-bottom: 3px ! important; -} - .mx_BottomLeftMenu_options > div { display: inline-block; } @@ -115,7 +103,7 @@ limitations under the License. margin-right: 0px; } -.mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings { +.mx_LeftPanel_container.collapsed .mx_BottomLeftMenu_settings { float: none; } @@ -124,7 +112,7 @@ limitations under the License. flex: 0 0 50px; } - .mx_LeftPanel.collapsed .mx_BottomLeftMenu { + .mx_LeftPanel_container.collapsed .mx_BottomLeftMenu { flex: 0 0 160px; } diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index eae1f56180..f2ce7e1d5c 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -54,6 +54,7 @@ limitations under the License. order: 2; flex: 1; + min-height: 0; } .mx_MatrixChat_syncError { @@ -68,26 +69,12 @@ limitations under the License. transform: translateX(-50%); } -.mx_MatrixChat .mx_LeftPanel { - order: 1; - - background-color: $secondary-accent-color; - - flex: 0 0 235px; -} - -.mx_MatrixChat .mx_LeftPanel.collapsed { - flex: 0 0 60px; -} - -.mx_MatrixChat .mx_MatrixChat_middlePanel { - order: 2; - - padding-left: 20px; - padding-right: 22px; +/* not the left panel, and not the resize handle, so the roomview/groupview/... */ +.mx_MatrixChat > :not(.mx_LeftPanel_container):not(.mx_ResizeHandle) { background-color: $primary-bg-color; - flex: 1; + flex: 1 1 0; + min-width: 0; /* Experimental fix for https://github.com/vector-im/vector-web/issues/947 and https://github.com/vector-im/vector-web/issues/946. @@ -96,21 +83,9 @@ limitations under the License. */ overflow-x: auto; - display: flex; - /* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari needed height 100% all the way down to the HomePage. Height does not have to be auto, empirically. */ height: 100%; } - -.mx_MatrixChat .mx_RightPanel { - order: 3; - - flex: 0 0 235px; -} - -.mx_MatrixChat .mx_RightPanel.collapsed { - flex: 0 0 122px; -} diff --git a/res/css/structures/_MyGroups.scss b/res/css/structures/_MyGroups.scss index 6d140721c8..b3a5c4f473 100644 --- a/res/css/structures/_MyGroups.scss +++ b/res/css/structures/_MyGroups.scss @@ -15,10 +15,6 @@ limitations under the License. */ .mx_MyGroups { - max-width: 960px; - margin-left: auto; - margin-right: auto; - display: flex; flex-direction: column; } @@ -34,6 +30,11 @@ limitations under the License. flex-wrap: wrap; } +.mx_MyGroups > :not(.mx_RoomHeader) { + max-width: 960px; + margin: 40px; +} + .mx_MyGroups_headerCard { flex: 1 0 50%; margin-bottom: 30px; @@ -43,14 +44,31 @@ limitations under the License. } .mx_MyGroups_headerCard .mx_MyGroups_headerCard_button { + flex: 0 0 auto; margin-right: 13px; - height: 50px; + height: 40px; + width: 40px; + border-radius: 20px; + background-color: $roomheader-addroom-color; + position: relative; + + &:before { + background-color: $accent-fg-color; + mask: url('$(res)/img/icons-create-room.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: 80%; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + } } -.mx_MyGroups_headerCard_button object { - /* Otherwise the SVG object absorbs clicks and the button doesn't work */ - pointer-events: none; -} + + .mx_MyGroups_headerCard_header { font-weight: bold; diff --git a/res/css/structures/_NotificationPanel.scss b/res/css/structures/_NotificationPanel.scss index a899808d57..b171aa3e36 100644 --- a/res/css/structures/_NotificationPanel.scss +++ b/res/css/structures/_NotificationPanel.scss @@ -16,11 +16,7 @@ limitations under the License. .mx_NotificationPanel { order: 2; - flex: 1 1 0; - - width: 100%; - overflow-y: auto; } @@ -97,4 +93,4 @@ limitations under the License. .mx_NotificationPanel .mx_EventTile_content { margin-right: 0px; -} \ No newline at end of file +} diff --git a/res/css/structures/_RightPanel.scss b/res/css/structures/_RightPanel.scss index 554aabfcd1..592eea067e 100644 --- a/res/css/structures/_RightPanel.scss +++ b/res/css/structures/_RightPanel.scss @@ -15,8 +15,10 @@ limitations under the License. */ .mx_RightPanel { + overflow-x: hidden; + flex: 0 0 auto; position: relative; - + min-width: 250px; display: flex; flex-direction: column; } @@ -25,59 +27,57 @@ limitations under the License. order: 1; border-bottom: 1px solid $primary-hairline-color; - margin-right: 20px; - flex: 0 0 70px; + flex: 0 0 52px; } /** Fixme - factor this out with the main header **/ .mx_RightPanel_headerButtonGroup { - margin-top: 6px; + height: 100%; display: flex; - width: 100%; background-color: $primary-bg-color; - margin-left: 0px; + padding: 0 9px; + align-items: center; } .mx_RightPanel_headerButton { cursor: pointer; flex: 0 0 auto; vertical-align: top; - padding-left: 4px; + margin-top: 4px; + padding-left: 5px; padding-right: 5px; text-align: center; position: relative; + border-bottom: 2px solid transparent; } .mx_RightPanel_headerButton object { pointer-events: none; - padding-bottom: 3px; -} - -.mx_RightPanel_headerButton_badgeHighlight .mx_RightPanel_headerButton_badge { - color: $warning-color; } .mx_RightPanel_headerButton_highlight { - width: 25px; - height: 5px; - border-radius: 5px; - background-color: $accent-color; - opacity: 0.2; + border-color: $button-bg-color; } .mx_RightPanel_headerButton_badge { - font-size: 11px; - color: $accent-color; + font-size: 8px; + border-radius: 8px; + color: $accent-fg-color; + background-color: $accent-color; font-weight: bold; - padding-bottom: 2px; + position: absolute; + top: -4px; + left: 20px; + padding: 2px 4px; } .mx_RightPanel_collapsebutton { flex: 1; text-align: right; - margin-top: 20px; + height: 16px; + border: none; } .mx_RightPanel .mx_MemberList, @@ -92,46 +92,3 @@ limitations under the License. order: 2; margin: auto; } - -.mx_RightPanel_footer { - order: 3; - - border-top: 1px solid $primary-hairline-color; - margin-right: 20px; - - flex: 0 0 60px; -} - -.mx_RightPanel_footer .mx_RightPanel_invite { - font-size: 14px; - color: $primary-fg-color; - padding-top: 13px; - padding-left: 5px; - cursor: pointer; - display: flex; - align-items: center; -} - -.collapsed .mx_RightPanel_footer .mx_RightPanel_invite { - display: none; -} - -.mx_RightPanel_invite .mx_RightPanel_icon object { - pointer-events: none; -} - -.mx_RightPanel_invite .mx_RightPanel_message { - padding-left: 10px; - line-height: 18px; -} - -.mx_MatrixChat_useCompactLayout { - .mx_RightPanel_footer { - flex: 0 0 50px; - } - - .mx_RightPanel_footer .mx_RightPanel_invite { - line-height: 25px; - padding-top: 8px; - } -} diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index 9cd3e7284c..bcfe3aefd6 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -14,29 +14,48 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_RoomDirectory { +.mx_RoomDirectory_dialogWrapper > .mx_Dialog { max-width: 960px; - width: 100%; - margin-left: auto; - margin-right: auto; - margin-bottom: 12px; - color: $primary-fg-color; - word-break: break-word; + height: 100%; + padding: 20px; +} +.mx_RoomDirectory_dialog { + height: 100%; display: flex; - flex-direction: column; } -.mx_RoomDirectory .mx_RoomHeader_simpleHeader { - margin-left: 0px; +.mx_RoomDirectory { + margin-bottom: 12px; + color: $primary-fg-color; + word-break: break-word; + display: flex; + flex-direction: column; + flex: 1; +} + +.mx_RoomDirectory .gm-scroll-view { + // little hack because gemini doesn't seem to detect + // the scrollbar width well in this instance + // when using css scrollbars + scrollbar-width: thin; +} + +.mx_RoomDirectory_createRoom { + background-color: $button-bg-color; + border-radius: 4px; + padding: 8px; + color: $button-fg-color; + font-weight: 600; + position: absolute; + top: 0; + left: 0; } .mx_RoomDirectory_list { flex: 1; - display: flex; - flex-direction: column; } @@ -45,22 +64,17 @@ limitations under the License. } .mx_RoomDirectory_listheader { - display: table; - table-layout: fixed; - width: 100%; + display: flex; margin-top: 12px; margin-bottom: 12px; - border-spacing: 5px; } .mx_RoomDirectory_searchbox { - display: table-cell; - vertical-align: middle; + flex: 1 !important; } .mx_RoomDirectory_listheader .mx_NetworkDropdown { - display: table-cell; - width: 200px; + flex: 0 0 200px; } .mx_RoomDirectory_tableWrapper { diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 6798f75a14..e403057cd3 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -14,235 +14,168 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_RoomSubList { - display: table; - table-layout: fixed; - width: 100%; +/* a word of explanation about the flex-shrink values employed here: + there are 3 priotized categories of screen real-estate grabbing, + each with a flex-shrink difference of 4 order of magnitude, + so they ideally wouldn't affect each other. + lowest category: .mx_RoomSubList + flex-shrink: 10000000 + distribute size of items within the same categery by their size + middle category: .mx_RoomSubList.resized-sized + flex-shrink: 1000 + applied when using the resizer, will have a max-height set to it, + to limit the size + highest category: .mx_RoomSubList.resized-all + flex-shrink: 1 + small flex-shrink value (1), is only added if you can drag the resizer so far + so in practice you can only assign this category if there is enough space. +*/ - background-color: $roomsublist-background; +.mx_RoomSubList { + display: flex; + flex-direction: column; +} + + +.mx_RoomSubList_nonEmpty .mx_AutoHideScrollbar_offset { + padding-bottom: 4px; } .mx_RoomSubList_labelContainer { - height: 31px; /* mx_RoomSubList_label height including border */ - width: 235px; /* LHS Panel width */ - position: relative; + display: flex; + flex-direction: row; + align-items: center; + flex: 0 0 auto; + margin: 0 16px; + height: 36px; } .mx_RoomSubList_label { - position: relative; + flex: 1; + cursor: pointer; + display: flex; + align-items: center; + padding: 0 6px; +} + +.mx_RoomSubList_label > span { + flex: 1 1 auto; text-transform: uppercase; color: $roomsublist-label-fg-color; - font-weight: 600; + font-weight: 700; font-size: 12px; - width: 203px; /* padding + width = LHS Panel width */ - height: 19px; /* height + padding = 31px = mx_RoomSubList_label height */ - padding-left: 16px; /* gutter */ - padding-right: 16px; /* gutter */ - padding-top: 6px; - padding-bottom: 6px; - cursor: pointer; - background-color: $secondary-accent-color; -} - -.mx_RoomSubList_label.mx_RoomSubList_fixed { - position: fixed; - top: 0; - z-index: 5; - /* pointer-events: none; */ -} - -.collapsed .mx_RoomSubList_label { - height: 17px; - width: 28px; /* collapsed LHS Panel width */ -} - -.collapsed .mx_RoomSubList_labelContainer { - width: 28px; /* collapsed LHS Panel width */ -} - -.mx_RoomSubList_roomCount { - display: inline-block; - font-size: 12px; - font-weight: normal; - color: $accent-color; - padding-left: 5px; - text-transform: none; -} - -.collapsed .mx_RoomSubList_roomCount { - display: none; + margin-left: 8px; } .mx_RoomSubList_badge { - display: inline-block; - min-width: 15px; - height: 15px; - position: absolute; - right: 8px; /*gutter */ - top: 7px; + flex: 0 0 auto; border-radius: 8px; color: $accent-fg-color; font-weight: 600; - font-size: 10px; - text-align: center; - padding-top: 1px; - padding-left: 4px; - padding-right: 4px; - background-color: $accent-color; + font-size: 12px; + padding: 0 5px; + background-color: $roomtile-name-color; } -.mx_RoomSubList_label .mx_RoomSubList_badge:hover { - filter: brightness($focus-brightness); +.mx_RoomSubList_addRoom, .mx_RoomSubList_badge { + margin-left: 7px; } -/* -.collapsed .mx_RoomSubList_badge { - display: none; +.mx_RoomSubList_addRoom { + background-color: $roomheader-addroom-color; + color: $roomsublist-background; + background-image: url('$(res)/img/icons-room-add.svg'); + background-repeat: no-repeat; + background-position: center; + border-radius: 10px; // 16/2 + 2 padding + height: 16px; + flex: 0 0 16px; + background-clip: content-box; } -*/ .mx_RoomSubList_badgeHighlight { background-color: $warning-color; } -/* This is the bottom of the speech bubble */ -.mx_RoomSubList_badgeHighlight:after { - content: ""; - position: absolute; - display: block; - width: 0; - height: 0; - margin-left: 5px; - border-top: 5px solid $warning-color; - border-right: 7px solid transparent; -} - -/* Hide the bottom of speech bubble */ -.collapsed .mx_RoomSubList_badgeHighlight:after { - display: none; -} - .mx_RoomSubList_chevron { pointer-events: none; - position: absolute; - right: 41px; - top: 11px; + background-image: url('$(res)/img/topleft-chevron.svg'); + background-repeat: no-repeat; + transition: transform 0.2s ease-in; + width: 10px; + height: 10px; + background-position: center; + margin-left: 2px; } .mx_RoomSubList_chevronDown { - width: 0; - height: 0; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-top: 6px solid $roomsublist-chevron-color; + transform: rotateZ(0deg); } .mx_RoomSubList_chevronUp { - width: 0; - height: 0; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-bottom: 6px solid $roomsublist-chevron-color; + transform: rotateZ(180deg); } .mx_RoomSubList_chevronRight { - width: 0; - height: 0; - border-top: 5px solid transparent; - border-left: 6px solid $roomsublist-chevron-color; - border-bottom: 5px solid transparent; + transform: rotateZ(-90deg); } -/* The overflow section */ -.mx_RoomSubList_ellipsis { - display: block; - line-height: 11px; - height: 18px; - position: relative; - cursor: pointer; - font-size: 13px; - - background-color: $secondary-accent-color; +.mx_RoomSubList_scroll { + /* let rooms list grab as much space as it needs (auto), + potentially overflowing and showing a scrollbar */ + flex: 0 1 auto; + padding: 0 8px; } -.collapsed .mx_RoomSubList_ellipsis { - height: 20px; +// overflow indicators +.mx_RoomSubList:not(.resized-all) > .mx_RoomSubList_scroll { + &.mx_IndicatorScrollbar_topOverflow::before, + &.mx_IndicatorScrollbar_bottomOverflow::after { + position: sticky; + left: 0; + right: 0; + height: 35px; + content: ""; + display: block; + z-index: 100; + pointer-events: none; + } + + &.mx_IndicatorScrollbar_topOverflow > .mx_AutoHideScrollbar_offset { + margin-top: -35px; + } + &.mx_IndicatorScrollbar_bottomOverflow > .mx_AutoHideScrollbar_offset { + margin-bottom: -35px; + } + + &.mx_IndicatorScrollbar_topOverflow::before { + top: 0; + background: linear-gradient(to top, rgba(242,245,248,0), rgba(242,245,248,1)); + } + + &.mx_IndicatorScrollbar_bottomOverflow::after { + bottom: 0; + background: linear-gradient(to bottom, rgba(242,245,248,0), rgba(242,245,248,1)); + } } -.mx_RoomSubList_line { - display: inline-block; - width: 159px; - border-top: dotted 2px $accent-color; - vertical-align: middle; +.collapsed { + + .mx_RoomSubList_scroll { + padding: 0; + } + + .mx_RoomSubList_labelContainer { + margin-right: 14px; + margin-left: 2px; + } + + .mx_RoomSubList_addRoom { + margin-left: 3px; + margin-right: 10px; + } + + .mx_RoomSubList_label > span { + display: none; + } } - -.collapsed .mx_RoomSubList_line { - display: none; -} - -.mx_RoomSubList_more { - display: inline-block; - text-transform: uppercase; - font-size: 10px; - font-weight: 600; - text-align: left; - color: $accent-color; - padding-left: 7px; - padding-right: 7px; - padding-left: 7px; - vertical-align: middle; -} - -.collapsed .mx_RoomSubList_more { - display: none; -} - -.mx_RoomSubList_moreBadge { - display: inline-block; - min-width: 15px; - height: 13px; - position: absolute; - right: 8px; /*gutter */ - top: -2px; - border-radius: 8px; - border: solid 1px $accent-color; - color: $accent-fg-color; - font-weight: 600; - font-size: 10px; - text-align: center; - padding-top: 1px; - padding-left: 3px; - padding-right: 3px; - background-color: $primary-bg-color; - vertical-align: middle; -} - -.mx_RoomSubList_moreBadge.mx_RoomSubList_moreBadgeNotify { - background-color: $accent-color; - border: 0; - padding-top: 3px; - padding-left: 4px; - padding-right: 4px; -} - -.mx_RoomSubList_moreBadge.mx_RoomSubList_moreBadgeHighlight { - background-color: $warning-color; - border: 0; - padding-top: 3px; - padding-left: 4px; - padding-right: 4px; -} - -.collapsed .mx_RoomSubList_moreBadge { - position: static; - margin-left: 16px; - margin-top: 2px; -} - -.mx_RoomSubList_ellipsis .mx_RoomSubList_chevronDown { - position: relative; - top: 4px; - left: 2px; -} - - diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 02418f70db..77b868e391 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -16,23 +16,12 @@ limitations under the License. .mx_RoomView { word-wrap: break-word; - position: relative; - display: flex; - width: 100%; - flex-direction: column; } -.mx_RoomView .mx_RoomHeader { - order: 1; - - flex: 0 0 70px; -} - .mx_RoomView_fileDropTarget { min-width: 0px; - max-width: 960px; width: 100%; font-size: 18px; text-align: center; @@ -50,7 +39,7 @@ limitations under the License. border: 2px #e1dddd solid; border-bottom: none; position: absolute; - top: 70px; + top: 52px; bottom: 0px; z-index: 3000; } @@ -63,42 +52,53 @@ limitations under the License. } .mx_RoomView_auxPanel { - order: 2; - min-width: 0px; - max-width: 960px; width: 100%; margin: 0px auto; overflow: auto; - border-bottom: 1px solid $primary-hairline-color; - flex: 0 0 auto; } +.mx_RoomView_auxPanel_fullHeight { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 3000; + background-color: $primary-bg-color; +} + .mx_RoomView_auxPanel_apps { max-width: 1920px ! important; } -.mx_RoomView_body { - order: 3; +.mx_RoomView .mx_MainSplit { flex: 1 1 0; - flex-direction: column; display: flex; } -.mx_RoomView_body .mx_RoomView_topUnreadMessagesBar { - order: 1; +.mx_RoomView_body { + position: relative; //for .mx_RoomView_auxPanel_fullHeight + display: flex; + flex-direction: column; + flex: 1; } -.mx_RoomView_body .mx_RoomView_messagePanel { - order: 2; +.mx_RoomView_body .mx_RoomView_timeline { + /* offset parent for mx_RoomView_topUnreadMessagesBar */ + position: relative; + flex: 1; + display: flex; + flex-direction: column; } -.mx_RoomView_body .mx_RoomView_messagePanelSpinner { - order: 2; - margin: auto; +.mx_RoomView_body { + .mx_RoomView_messagePanel, .mx_RoomView_messagePanelSpinner, .mx_RoomView_messagePanelSearchSpinner{ + order: 2; + } } .mx_RoomView_body .mx_RoomView_statusArea { @@ -114,10 +114,30 @@ limitations under the License. overflow-y: auto; } -.mx_RoomView_messageListWrapper { - max-width: 960px; - margin: auto; +.mx_RoomView_messagePanelSearchSpinner { + flex: 1; + background-image: url('$(res)/img/typing-indicator-2x.gif'); + background-position: center 367px; + background-size: 25px; + background-repeat: no-repeat; + position: relative; +} +.mx_RoomView_messagePanelSearchSpinner:before { + background-color: $greyed-fg-color; + mask: url('$(res)/img/feather-icons/search-input.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: 50px; + content: ''; + position: absolute; + top: 286px; + left: 0; + right: 0; + height: 50px; +} + +.mx_RoomView_messageListWrapper { min-height: 100%; display: flex; @@ -127,8 +147,15 @@ limitations under the License. justify-content: flex-end; } -.mx_RoomView_searchResultsPanel .mx_RoomView_messageListWrapper { - justify-content: flex-start; +.mx_RoomView_searchResultsPanel { + .mx_RoomView_messageListWrapper { + justify-content: flex-start; + } + + a { + text-decoration: none; + color: inherit; + } } .mx_RoomView_empty { @@ -142,9 +169,12 @@ limitations under the License. } .mx_RoomView_MessageList { - width: 100%; list-style-type: none; - padding: 0px; + padding: 18px; + margin: 0; + /* needed as min-height is set to clientHeight in ScrollPanel + to prevent shrinking when WhoIsTypingTile is hidden */ + box-sizing: border-box; } .mx_RoomView_MessageList li { @@ -184,7 +214,6 @@ hr.mx_RoomView_myReadMarker { } .mx_RoomView_statusAreaBox { - max-width: 960px; margin: auto; min-height: 50px; } diff --git a/res/css/structures/_SearchBox.scss b/res/css/structures/_SearchBox.scss index 6f08fd47b2..9434d93bd2 100644 --- a/res/css/structures/_SearchBox.scss +++ b/res/css/structures/_SearchBox.scss @@ -14,55 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_SearchBox { - height: 24px; - margin-left: 16px; - margin-right: 16px; - padding-top: 24px; - padding-bottom: 22px; - - border-bottom: 1px solid $panel-divider-color; - - display: flex; -} - -.mx_SearchBox_searchButton { - margin-right: 10px; - margin-top: 5px; - pointer-events: none; -} - .mx_SearchBox_closeButton { cursor: pointer; - margin-top: -5px; -} - -.mx_SearchBox_search { - flex: 1 1 auto; - width: 0px; - font-family: $font-family; - font-size: 12px; - margin-top: -2px; - height: 24px; - border: 0px ! important; - /* border-bottom: 1px solid rgba(0, 0, 0, 0.1) ! important; */ - border: 0px; -} - -.mx_SearchBox_minimise, -.mx_SearchBox_maximise { - margin-top: 3px; - cursor: pointer; -} - -.mx_SearchBox_minimise { - margin-left: 10px; -} - -.mx_SearchBox_maximise { - margin-left: 9px; -} - -.mx_SearchBox object { - pointer-events: none; + background-image: url('$(res)/img/icons-close.svg'); + background-repeat: no-repeat; + width: 16px; + height: 16px; + background-position: center; + padding: 9px; } diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss new file mode 100644 index 0000000000..ed9fa368e3 --- /dev/null +++ b/res/css/structures/_TabbedView.scss @@ -0,0 +1,94 @@ +/* +Copyright 2017 Travis Ralston +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_TabbedView { + margin: 0; + padding: 0; + display: flex; + width: 100%; + height: 100%; +} + +.mx_TabbedView_tabLabels { + width: 150px; + max-width: 150px; + height: 100%; + color: $tab-label-fg-color; +} + +.mx_TabbedView_tabLabel { + vertical-align: text-top; + cursor: pointer; + display: block; + border-radius: 3px; + font-size: 12px; + font-weight: 600; + min-height: 20px; // use min-height instead of height to allow the label to overflow a bit + margin-bottom: 6px; + position: relative; +} + +.mx_TabbedView_tabLabel_active { + background-color: $tab-label-active-bg-color; + color: $tab-label-active-fg-color; +} + +// TODO: Remove temporary hack alongside "visit old settings" tab +.mx_TabbedView_tabLabel_TEMP_HACK { + background-color: orange; +} + +.mx_TabbedView_maskedIcon {; + margin-left: 6px; + margin-right: 9px; + margin-top: 1px; + width: 14px; + height: 14px; + display: inline-block; +} + +.mx_TabbedView_maskedIcon:before { + display: inline-block; + background-color: $tab-label-icon-bg-color; + mask-repeat: no-repeat; + mask-size: 14px; + width: 14px; + height: 18px; + mask-position: center; + content: ''; + vertical-align: middle; +} + +.mx_TabbedView_tabLabel_active .mx_TabbedView_maskedIcon:before { + background-color: $tab-label-active-icon-bg-color; +} + +.mx_TabbedView_tabLabel_text { + vertical-align: middle; +} + +.mx_TabbedView_tabPanel { + width: calc(100% - 320px); + display: inline-block; + margin-left: 70px; + flex-grow: 1; +} + +.mx_TabbedView_tabPanelContent { + flex-grow: 1; + min-width: 560px; +} \ No newline at end of file diff --git a/res/css/structures/_TagPanel.scss b/res/css/structures/_TagPanel.scss index 415aafd924..bf1746bd0e 100644 --- a/res/css/structures/_TagPanel.scss +++ b/res/css/structures/_TagPanel.scss @@ -15,8 +15,9 @@ limitations under the License. */ .mx_TagPanel { - flex: 0 0 60px; - background-color: $tertiary-accent-color; + flex: 0 0 70px; + background-color: $tagpanel-bg-color; + cursor: pointer; display: flex; flex-direction: column; @@ -38,6 +39,8 @@ limitations under the License. display: flex; justify-content: center; align-items: flex-start; + + display: none; } .mx_TagPanel .mx_TagPanel_clearButton object { @@ -50,6 +53,7 @@ limitations under the License. height: 0px; width: 42px; border-bottom: 1px solid $panel-divider-color; + display: none; } .mx_TagPanel .mx_TagPanel_scroller { @@ -60,19 +64,21 @@ limitations under the License. display: flex; flex-direction: column; align-items: center; + margin-top: 5px; height: 100%; } .mx_TagPanel .mx_TagTile { - padding: 6px 3px; - opacity: 0.5; + padding-top: 9px; + padding-bottom: 9px; +// opacity: 0.5; position: relative; } .mx_TagPanel .mx_TagTile:focus, .mx_TagPanel .mx_TagTile:hover, .mx_TagPanel .mx_TagTile.mx_TagTile_selected { - opacity: 1; +// opacity: 1; } .mx_TagPanel .mx_TagTile.mx_TagTile_selected { @@ -83,12 +89,12 @@ limitations under the License. .mx_TagPanel .mx_TagTile.mx_TagTile_selected .mx_TagTile_avatar .mx_BaseAvatar { border: 3px solid $accent-color; background-color: $accent-color; - border-radius: 60px; + border-radius: 40px; /* In case this is a "initial" avatar */ display: block; - height: 35px; - width: 35px; + height: 40px; + width: 40px; } .mx_TagPanel .mx_TagTile.mx_AccessibleButton:focus { @@ -119,11 +125,38 @@ limitations under the License. } .mx_TagPanel_groupsButton { - margin-bottom: 17px; - margin-top: 18px; - height: 25px; + flex: 0; + margin: 17px 0 3px 0; } -.mx_TagPanel_groupsButton object { - pointer-events: none; +.mx_TagPanel_groupsButton > .mx_GroupsButton:before { + mask: url('$(res)/img/feather-icons/users.svg'); + mask-position: center 11px; +} + +.mx_TagPanel_groupsButton > .mx_TagPanel_report:before { + mask: url('$(res)/img/feather-icons/life-buoy.svg'); + mask-position: center 9px; +} + +.mx_TagPanel_groupsButton > .mx_AccessibleButton { + margin-bottom: 12px; + height: 40px; + width: 40px; + border-radius: 20px; + background-color: $roomheader-addroom-color; + position: relative; + /* overwrite mx_RoleButton inline-block */ + display: block !important; + + &:before { + background-color: $tagpanel-bg-color; + mask-repeat: no-repeat; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + } } diff --git a/res/css/structures/_TopLeftMenuButton.scss b/res/css/structures/_TopLeftMenuButton.scss new file mode 100644 index 0000000000..43a1e27ee4 --- /dev/null +++ b/res/css/structures/_TopLeftMenuButton.scss @@ -0,0 +1,44 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_TopLeftMenuButton { + flex: 0 0 52px; + border-bottom: 1px solid $panel-divider-color; + color: $topleftmenu-color; + background-color: $primary-bg-color; + display: flex; + align-items: center; + min-width: 0; + padding: 0 7px; + overflow: hidden; +} + +.mx_TopLeftMenuButton .mx_BaseAvatar { + margin: 0 7px; +} + +.mx_TopLeftMenuButton_name { + margin: 0 7px; + font-size: 18px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + font-weight: 600; +} + +.mx_TopLeftMenuButton_chevron { + margin: 0 7px; +} diff --git a/res/css/structures/_UserSettings.scss b/res/css/structures/_UserSettings.scss index 6fae8d6c1a..b078a4e242 100644 --- a/res/css/structures/_UserSettings.scss +++ b/res/css/structures/_UserSettings.scss @@ -173,7 +173,7 @@ limitations under the License. padding: 0px; width: 240px; color: $input-fg-color; - font-family: 'Open Sans', Helvetica, Arial, Sans-Serif; + font-family: $font-family; font-size: 16px; } @@ -255,3 +255,15 @@ input.mx_UserSettings_phoneNumberField { .mx_UserSettings_analyticsModal table { margin: 10px 0px; } + + +// Temp styles to keep the layout moderately usable. Not perfect, but better +// than 30 options being impossible to understand. +.mx_UserSettings .mx_SettingsFlag { + height: 30px; +} + +.mx_UserSettings .mx_SettingsFlag .mx_ToggleSwitch { + float: left; + margin-right: 5px; +} \ No newline at end of file diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss new file mode 100644 index 0000000000..b48021c27a --- /dev/null +++ b/res/css/structures/auth/_Login.scss @@ -0,0 +1,142 @@ +/* +Copyright 2015, 2016 OpenMarket Ltd +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_Login_field { + width: 100%; + box-sizing: border-box; + border-radius: 3px; + border: 1px solid $strong-input-border-color; + font-weight: 300; + font-size: 13px; + padding: 9px; + margin-bottom: 14px; +} + +.mx_Login_submit { + @mixin mx_DialogButton; + width: 100%; + margin-top: 35px; + margin-bottom: 24px; + box-sizing: border-box; + text-align: center; +} + +.mx_Login_submit:hover { + @mixin mx_DialogButton_hover; +} + +.mx_Login_submit:disabled { + opacity: 0.3; +} + +.mx_AuthBody a.mx_Login_sso_link:link, +.mx_AuthBody a.mx_Login_sso_link:hover, +.mx_AuthBody a.mx_Login_sso_link:visited { + color: $button-primary-fg-color; +} + +.mx_Login_loader { + display: inline; + position: relative; + top: 2px; + left: 8px; +} + +.mx_Login_loader .mx_Spinner { + display: inline; +} + +.mx_Login_loader .mx_Spinner img { + width: 16px; + height: 16px; +} + +.mx_Login_error { + color: $warning-color; + font-weight: bold; + text-align: center; +/* + height: 24px; +*/ + margin-top: 12px; + margin-bottom: 12px; +} + +.mx_Login_type_container { + display: flex; + margin-bottom: 14px; + color: $primary-fg-color; +} + +.mx_Login_type_label { + flex-grow: 1; + line-height: 35px; +} + +.mx_Login_type_dropdown { + display: inline-block; + min-width: 170px; + align-self: flex-end; + flex: 1 1 auto; +} + +.mx_Login_field_prefix { + height: 38px; + padding: 0px 5px; + line-height: 38px; + + background-color: #eee; + border: 1px solid #c7c7c7; + border-right: 0px; + border-radius: 3px 0px 0px 3px; + + text-align: center; +} + +.mx_Login_field_has_prefix { + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; +} + +.mx_Login_phoneSection { + display:flex; +} + +.mx_Login_phoneCountry { + margin-bottom: 14px; + + /* To override mx_Login_field_prefix */ + text-align: left; + padding: 0px; + background-color: $primary-bg-color; +} + +.mx_Login_field_prefix .mx_Dropdown_input { + /* To use prefix border instead of dropdown border */ + border: 0; +} + +.mx_Login_phoneCountry .mx_Dropdown_option { + /* To match height of mx_Login_field */ + height: 38px; + line-height: 38px; +} + +.mx_Login_phoneCountry .mx_Dropdown_option img { + margin: 3px; + vertical-align: top; +} diff --git a/res/css/structures/login/_Login.scss b/res/css/structures/login/_Login.scss deleted file mode 100644 index 1264d2a30f..0000000000 --- a/res/css/structures/login/_Login.scss +++ /dev/null @@ -1,295 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -.mx_Login { - width: 100%; - height: 100%; - - display: flex; - align-items: center; - justify-content: center; - - overflow: auto; -} - -.mx_Login h2 { - font-weight: 300; - margin-top: 32px; - margin-bottom: 20px; -} - -.mx_Login_box { - width: 300px; - min-height: 450px; - padding-top: 50px; - padding-bottom: 50px; - margin: auto; -} - -.mx_Login_logo { - text-align: center; - height: 150px; - margin-bottom: 45px; -} - -.mx_Login_logo img { - max-height: 100% -} - -.mx_Login_support { - text-align: center; - font-size: 13px; - margin-top: 0px; - opacity: 0.7; -} - -.mx_Login_field { - width: 280px; - border-radius: 3px; - border: 1px solid $strong-input-border-color; - font-weight: 300; - font-size: 13px; - padding: 9px; - margin-bottom: 14px; -} - -.mx_Login_field_disabled { - opacity: 0.3; -} - -.mx_Login_fieldLabel { - margin-top: -10px; - margin-left: 8px; - margin-bottom: 14px; - font-size: 13px; - opacity: 0.8; -} - -.mx_Login_submit { - @mixin mx_DialogButton; - width: 100%; - margin-top: 35px; - margin-bottom: 24px; -} - -.mx_Login_submit:hover { - @mixin mx_DialogButton_hover; -} - -.mx_Login_submit:disabled { - opacity: 0.3; -} - -.mx_Login_label { - font-size: 13px; - opacity: 0.8; -} - -.mx_Login_checkbox, -.mx_Login_radio { - margin-right: 10px; -} - -.mx_Login_create { - display: block; - text-align: center; - width: 100%; - font-size: 13px; - opacity: 0.8; -} - -.mx_Login_create:link { - color: $primary-fg-color; -} - -.mx_Login_links { - display: block; - text-align: center; - margin-top: 15px; - width: 100%; - font-size: 13px; - opacity: 0.8; -} - -.mx_Login_links a:link { - color: $primary-fg-color; -} - -.mx_Login_prompt { - padding-top: 15px; - padding-bottom: 15px; - font-size: 13px; -} - -.mx_Login_forgot { - font-size: 15px; -} - -.mx_Login_forgot:link { - color: $primary-fg-color; -} - -.mx_Login_sso_link { - display: block; - text-align: center; - font-size: 15px; - margin-bottom: 20px; -} - -.mx_Login_sso_link:link { - color: $primary-fg-color; -} - -.mx_Login_loader { - display: inline; - position: relative; - top: 2px; - left: 8px; -} - -.mx_Login_loader .mx_Spinner { - display: inline; -} - -.mx_Login_loader .mx_Spinner img { - width: 16px; - height: 16px; -} - -.mx_Login_error { - color: $warning-color; - font-weight: bold; - text-align: center; -/* - height: 24px; -*/ - margin-top: 12px; - margin-bottom: 12px; -} - -.mx_Login_type_container { - display: flex; - margin-bottom: 14px; -} - -.mx_Login_type_label { - flex-grow: 1; - line-height: 35px; -} - -.mx_Login_type_dropdown { - display: inline-block; - min-width: 170px; - align-self: flex-end; - flex: 1 1 auto; -} - -.mx_Login_field_group { - display: flex; -} - -.mx_Login_field_prefix { - height: 34px; - padding: 0px 5px; - line-height: 33px; - - background-color: #eee; - border: 1px solid #c7c7c7; - border-right: 0px; - border-radius: 3px 0px 0px 3px; - - text-align: center; -} - -.mx_Login_field_suffix { - height: 34px; - padding: 0px 5px; - line-height: 33px; - - background-color: #eee; - border: 1px solid #c7c7c7; - border-left: 0px; - border-radius: 0px 3px 3px 0px; - - text-align: center; - flex-grow: 1; -} - -.mx_Login_username { - height: 16px; - flex-shrink: 1; - min-width: 0px; -} - -.mx_Login_phoneNumberField { - height: 16px; -} - -.mx_Login_field_has_prefix { - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; -} - -.mx_Login_field_has_suffix { - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; -} - -.mx_Login_phoneSection { - display:flex; -} - -.mx_Login_phoneCountry { - margin-bottom: 14px; - width: 150px; - - /* To override mx_Login_field_prefix */ - text-align: left; - padding: 0px; - background-color: $primary-bg-color; -} - -.mx_Login_field_prefix .mx_Dropdown_input { - /* To use prefix border instead of dropdown border */ - border: 0; -} - -.mx_Login_phoneCountry .mx_Dropdown_option { - /* - To match height of mx_Login_field - 33px + 2px border from mx_Dropdown_option = 35px - */ - height: 33px; - line-height: 33px; -} - -.mx_Login_phoneCountry .mx_Dropdown_option img { - margin: 3px; - vertical-align: top; -} - -.mx_Login_language { - margin-left: auto; - margin-right: auto; - min-width: 60%; -} - -.mx_Login_language_div { - display: flex; - margin-top: 12px; - margin-bottom: 12px; -} - diff --git a/res/css/views/auth/_AuthBody.scss b/res/css/views/auth/_AuthBody.scss new file mode 100644 index 0000000000..08a8b4ff4a --- /dev/null +++ b/res/css/views/auth/_AuthBody.scss @@ -0,0 +1,79 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_AuthBody { + width: 500px; + background-color: $authpage-body-bg-color; + border-radius: 0 4px 4px 0; + padding: 25px 60px; + box-sizing: border-box; + font-size: 12px; + color: $authpage-body-color; +} + +.mx_AuthBody h2 { + font-size: 24px; + font-weight: 600; + margin-top: 8px; +} + +.mx_AuthBody h3 { + font-size: 14px; + font-weight: 600; + color: $primary-fg-color; +} + +.mx_Auth_editServerDetails { + padding-left: 1em; + font-size: 12px; + font-weight: normal; +} + +.mx_AuthBody .mx_Field input { + width: 100%; + box-sizing: border-box; +} + +.mx_Auth_fieldRow { + display: flex; + margin-bottom: 10px; +} + +.mx_Auth_fieldRow > * { + margin: 0 5px; + flex: 1; +} + +.mx_Auth_fieldRow > *:first-child { + margin-left: 0; +} + +.mx_Auth_fieldRow > *:last-child { + margin-right: 0; +} + +.mx_AuthBody a:link, +.mx_AuthBody a:hover, +.mx_AuthBody a:visited { + color: $accent-color; + text-decoration: none; +} + +.mx_Auth_changeFlow { + display: block; + text-align: center; + width: 100%; +} diff --git a/res/css/structures/_LoginBox.scss b/res/css/views/auth/_AuthButtons.scss similarity index 87% rename from res/css/structures/_LoginBox.scss rename to res/css/views/auth/_AuthButtons.scss index 0a3e21a980..553adeee14 100644 --- a/res/css/structures/_LoginBox.scss +++ b/res/css/views/auth/_AuthButtons.scss @@ -1,5 +1,6 @@ /* Copyright 2017 OpenMarket Ltd +Copyright 2019 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_LoginBox { +.mx_AuthButtons { min-height: 24px; height: unset !important; padding-top: 13px !important; @@ -22,13 +23,13 @@ limitations under the License. order: 4; } -.mx_LoginBox_loginButton_wrapper { +.mx_AuthButtons_loginButton_wrapper { text-align: center; width: 100%; } -.mx_LoginBox_loginButton, -.mx_LoginBox_registerButton { +.mx_AuthButtons_loginButton, +.mx_AuthButtons_registerButton { margin-top: 3px; height: 40px; border: 0px; diff --git a/res/css/views/auth/_AuthFooter.scss b/res/css/views/auth/_AuthFooter.scss new file mode 100644 index 0000000000..741be49a69 --- /dev/null +++ b/res/css/views/auth/_AuthFooter.scss @@ -0,0 +1,30 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_AuthFooter { + text-align: center; + width: 100%; + font-size: 14px; + opacity: 0.72; + margin: 20px 0; +} + +.mx_AuthFooter a:link, +.mx_AuthFooter a:hover, +.mx_AuthFooter a:visited { + color: $accent-fg-color; + margin: 0 22px; +} diff --git a/res/css/views/auth/_AuthHeader.scss b/res/css/views/auth/_AuthHeader.scss new file mode 100644 index 0000000000..e1e8802437 --- /dev/null +++ b/res/css/views/auth/_AuthHeader.scss @@ -0,0 +1,23 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_AuthHeader { + display: flex; + flex-direction: column; + width: 206px; + padding: 25px 50px; + box-sizing: border-box; +} diff --git a/res/css/views/auth/_AuthHeaderLogo.scss b/res/css/views/auth/_AuthHeaderLogo.scss new file mode 100644 index 0000000000..b6f107d9c4 --- /dev/null +++ b/res/css/views/auth/_AuthHeaderLogo.scss @@ -0,0 +1,24 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_AuthHeaderLogo { + margin-top: 15px; + flex: 1; +} + +.mx_AuthHeaderLogo img { + width: 100%; +} diff --git a/res/css/views/auth/_AuthPage.scss b/res/css/views/auth/_AuthPage.scss new file mode 100644 index 0000000000..64b69c750f --- /dev/null +++ b/res/css/views/auth/_AuthPage.scss @@ -0,0 +1,33 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_AuthPage { + width: 100%; + min-height: 100%; + display: flex; + flex-direction: column; + background-color: $authpage-bg-color; +} + +.mx_AuthPage_modal { + display: flex; + margin: 100px auto auto; + border-radius: 4px; + // Not currently supported in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1178765 + backdrop-filter: blur(10px); + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.33); + background-color: $authpage-modal-bg-color; +} diff --git a/res/css/views/auth/_CountryDropdown.scss b/res/css/views/auth/_CountryDropdown.scss new file mode 100644 index 0000000000..6fd3c0182c --- /dev/null +++ b/res/css/views/auth/_CountryDropdown.scss @@ -0,0 +1,34 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_CountryDropdown .mx_Dropdown_input .mx_Dropdown_option { + padding: 0 3px; +} + +.mx_CountryDropdown .mx_Dropdown_arrow { + padding-right: 3px; +} + +.mx_CountryDropdown_shortOption { + display: inline-flex; + align-items: center; + height: 100%; +} + +.mx_CountryDropdown_option { + display: flex; + align-items: center; +} diff --git a/res/css/views/login/_InteractiveAuthEntryComponents.scss b/res/css/views/auth/_InteractiveAuthEntryComponents.scss similarity index 100% rename from res/css/views/login/_InteractiveAuthEntryComponents.scss rename to res/css/views/auth/_InteractiveAuthEntryComponents.scss diff --git a/res/css/views/auth/_LanguageSelector.scss b/res/css/views/auth/_LanguageSelector.scss new file mode 100644 index 0000000000..be40c9e6cd --- /dev/null +++ b/res/css/views/auth/_LanguageSelector.scss @@ -0,0 +1,30 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_Auth_language { + width: 100%; +} + +.mx_Auth_language .mx_Dropdown_input { + border: none; + font-size: 14px; + font-weight: 600; + color: $authpage-lang-color; +} + +.mx_Auth_language .mx_Dropdown_arrow::before { + background: $authpage-lang-color; +} diff --git a/res/css/views/login/_ServerConfig.scss b/res/css/views/auth/_ServerConfig.scss similarity index 69% rename from res/css/views/login/_ServerConfig.scss rename to res/css/views/auth/_ServerConfig.scss index 894ce19827..79ad9e8238 100644 --- a/res/css/views/login/_ServerConfig.scss +++ b/res/css/views/auth/_ServerConfig.scss @@ -14,23 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_ServerConfig { - margin-top: 7px; +.mx_ServerConfig_fields { + display: flex; + margin: 1em 0; } -.mx_ServerConfig .mx_Login_field { - margin-top: 4px; - margin-bottom: 5px; +.mx_ServerConfig_fields .mx_Field { + flex: 1; + margin: 0 5px; +} + +.mx_ServerConfig_fields .mx_Field:first-child { + margin-left: 0; +} + +.mx_ServerConfig_fields .mx_Field:last-child { + margin-right: 0; } .mx_ServerConfig_help:link { opacity: 0.8; - font-size: 13px; - font-weight: 300; - color: $primary-fg-color; } - -.mx_ServerConfig_selector { - text-align: center; - width: 302px; // for fr i18n -} \ No newline at end of file diff --git a/res/css/views/auth/_ServerTypeSelector.scss b/res/css/views/auth/_ServerTypeSelector.scss new file mode 100644 index 0000000000..03f5386501 --- /dev/null +++ b/res/css/views/auth/_ServerTypeSelector.scss @@ -0,0 +1,69 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_ServerTypeSelector { + display: flex; + margin-bottom: 28px; +} + +.mx_ServerTypeSelector_type { + margin: 0 5px; +} + +.mx_ServerTypeSelector_type:first-child { + margin-left: 0; +} + +.mx_ServerTypeSelector_type:last-child { + margin-right: 0; +} + +.mx_ServerTypeSelector_label { + text-align: center; + font-weight: 600; + color: $primary-fg-color; + margin: 8px 0; +} + +.mx_ServerTypeSelector_type .mx_AccessibleButton { + padding: 10px; + border: 1px solid $input-border-color; + border-radius: 4px; +} + +.mx_ServerTypeSelector_type.mx_ServerTypeSelector_type_selected .mx_AccessibleButton { + border-color: $input-valid-border-color; +} + +.mx_ServerTypeSelector_logo { + display: flex; + justify-content: center; + height: 18px; + margin-bottom: 12px; + font-weight: 600; + color: $primary-fg-color; +} + +.mx_ServerTypeSelector_logo > div { + display: flex; + width: 70%; + align-items: center; + justify-content: space-evenly; +} + +.mx_ServerTypeSelector_description { + font-size: 10px; +} diff --git a/res/css/views/avatars/_MemberStatusMessageAvatar.scss b/res/css/views/avatars/_MemberStatusMessageAvatar.scss index c857b9807b..c101a5d8a8 100644 --- a/res/css/views/avatars/_MemberStatusMessageAvatar.scss +++ b/res/css/views/avatars/_MemberStatusMessageAvatar.scss @@ -14,7 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_MemberStatusMessageAvatar_hasStatus { - border: 2px solid $accent-color; - border-radius: 40px; +.mx_MessageComposer_avatar .mx_BaseAvatar { + padding: 2px; + border: 1px solid transparent; + border-radius: 15px; +} + +.mx_MessageComposer_avatar .mx_BaseAvatar_initial { + left: 2px; +} + +.mx_MemberStatusMessageAvatar_hasStatus .mx_BaseAvatar { + border-color: $accent-color; } diff --git a/res/css/views/context_menus/_MessageContextMenu.scss b/res/css/views/context_menus/_MessageContextMenu.scss index 85e8080c88..d15d566bdb 100644 --- a/res/css/views/context_menus/_MessageContextMenu.scss +++ b/res/css/views/context_menus/_MessageContextMenu.scss @@ -14,6 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_MessageContextMenu { + padding: 6px; +} + .mx_MessageContextMenu_field { padding: 3px 6px 3px 6px; cursor: pointer; diff --git a/res/css/views/context_menus/_RoomTileContextMenu.scss b/res/css/views/context_menus/_RoomTileContextMenu.scss index 598f8ac249..f832691be4 100644 --- a/res/css/views/context_menus/_RoomTileContextMenu.scss +++ b/res/css/views/context_menus/_RoomTileContextMenu.scss @@ -14,6 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_RoomTileContextMenu { + padding: 6px; +} + .mx_RoomTileContextMenu_tag_field, .mx_RoomTileContextMenu_leave { padding-top: 8px; padding-right: 20px; diff --git a/res/css/views/context_menus/_StatusMessageContextMenu.scss b/res/css/views/context_menus/_StatusMessageContextMenu.scss index 873ad99495..972f608caf 100644 --- a/res/css/views/context_menus/_StatusMessageContextMenu.scss +++ b/res/css/views/context_menus/_StatusMessageContextMenu.scss @@ -14,42 +14,52 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_StatusMessageContextMenu_message { - display: inline-block; - border-radius: 3px 0 0 3px; +.mx_StatusMessageContextMenu { + padding: 10px; +} + +.mx_StatusMessageContextMenu_form { + display: flex; + flex-direction: column; +} + +input.mx_StatusMessageContextMenu_message { + border-radius: 4px; border: 1px solid $input-border-color; - font-size: 13px; - padding: 7px 7px 7px 9px; - width: 135px; - background-color: $primary-bg-color !important; + padding: 6.5px 11px; + background-color: $primary-bg-color; + font-weight: normal; + margin: 0 0 10px; } -.mx_StatusMessageContextMenu_submit { - display: inline-block; +.mx_StatusMessageContextMenu_message::placeholder { + color: $memberstatus-placeholder-color; } -.mx_StatusMessageContextMenu_submitFaded { - opacity: 0.5; +.mx_StatusMessageContextMenu_actionContainer { + display: flex; } -.mx_StatusMessageContextMenu_submit img { - vertical-align: middle; - margin-left: 8px; +.mx_StatusMessageContextMenu_submit, +.mx_StatusMessageContextMenu_clear { + @mixin mx_DialogButton; + align-self: start; + font-size: 12px; + padding: 6px 1em; + border: 1px solid transparent; + margin-right: 10px; } -.mx_StatusMessageContextMenu hr { - border: 0.5px solid $menu-border-color; -} - -.mx_StatusMessageContextMenu_clearIcon { - margin: 5px 15px 5px 5px; - vertical-align: middle; +.mx_StatusMessageContextMenu_submit[disabled] { + opacity: 0.49; } .mx_StatusMessageContextMenu_clear { - padding: 2px; + color: $warning-color; + background-color: transparent; + border: 1px solid $warning-color; } -.mx_StatusMessageContextMenu_hasStatus .mx_StatusMessageContextMenu_clear { - color: $warning-color; +.mx_StatusMessageContextMenu_actionContainer .mx_Spinner { + justify-content: start; } diff --git a/res/css/views/context_menus/_TopLeftMenu.scss b/res/css/views/context_menus/_TopLeftMenu.scss new file mode 100644 index 0000000000..18463da824 --- /dev/null +++ b/res/css/views/context_menus/_TopLeftMenu.scss @@ -0,0 +1,63 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_TopLeftMenu { + min-width: 180px; + border-radius: 4px; + + .mx_TopLeftMenu_section:not(:last-child) { + border-bottom: 1px solid $menu-border-color; + } + + .mx_TopLeftMenu_section { + list-style: none; + margin: 5px 0; + padding: 0; + + li.mx_TopLeftMenu_icon_settings::after { + mask-image: url('$(res)/img/feather-icons/settings.svg'); + } + + li.mx_TopLeftMenu_icon_signout::after { + mask-image: url('$(res)/img/feather-icons/sign-out.svg'); + } + + li::after { + mask-repeat: no-repeat; + mask-position: 0 center; + mask-size: 16px; + position: absolute; + width: 16px; + height: 16px; + content: ""; + top: 5px; + left: 14px; + background-color: $primary-fg-color; + } + + li { + position: relative; + cursor: pointer; + white-space: nowrap; + padding: 5px 20px 5px 43px; + } + + li:hover { + background-color: $menu-selected-color; + } + } + +} diff --git a/res/css/views/dialogs/_DevtoolsDialog.scss b/res/css/views/dialogs/_DevtoolsDialog.scss index a4a868bd11..572d6ee8c7 100644 --- a/res/css/views/dialogs/_DevtoolsDialog.scss +++ b/res/css/views/dialogs/_DevtoolsDialog.scss @@ -61,7 +61,7 @@ limitations under the License. padding: 0; width: 240px; color: $input-fg-color; - font-family: 'Open Sans', Helvetica, Arial, Sans-Serif; + font-family: $font-family; font-size: 16px; } diff --git a/res/css/views/dialogs/_EncryptedEventDialog.scss b/res/css/views/dialogs/_EncryptedEventDialog.scss index 58ed8b2527..ff73df509d 100644 --- a/res/css/views/dialogs/_EncryptedEventDialog.scss +++ b/res/css/views/dialogs/_EncryptedEventDialog.scss @@ -14,10 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_EncryptedEventDialog .mx_MemberDeviceInfo { +.mx_EncryptedEventDialog .mx_DeviceVerifyButtons { float: right; padding: 0px; margin-right: 42px; + display: flex; + flex-wrap: wrap; + justify-content: space-between; } .mx_EncryptedEventDialog .mx_MemberDeviceInfo_textButton { diff --git a/res/css/views/dialogs/_RoomSettingsDialog.scss b/res/css/views/dialogs/_RoomSettingsDialog.scss new file mode 100644 index 0000000000..de675abe32 --- /dev/null +++ b/res/css/views/dialogs/_RoomSettingsDialog.scss @@ -0,0 +1,34 @@ +/* +Copyright 2019 New Vector Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// ICONS +// ========================================================== + +.mx_RoomSettingsDialog_settingsIcon:before { + mask-image: url('$(res)/img/feather-icons/settings.svg'); +} + +.mx_RoomSettingsDialog_securityIcon:before { + mask-image: url('$(res)/img/feather-icons/lock.svg'); +} + +.mx_RoomSettingsDialog_rolesIcon:before { + mask-image: url('$(res)/img/feather-icons/users-sm.svg'); +} + +.mx_RoomSettingsDialog_warningIcon:before { + mask-image: url('$(res)/img/feather-icons/warning-triangle.svg'); +} diff --git a/res/css/views/dialogs/_SettingsDialog.scss b/res/css/views/dialogs/_SettingsDialog.scss new file mode 100644 index 0000000000..2cc7c08039 --- /dev/null +++ b/res/css/views/dialogs/_SettingsDialog.scss @@ -0,0 +1,70 @@ +/* +Copyright 2019 New Vector Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_SettingsDialog { + .mx_Dialog { + max-width: 784px; // 900px - 58px (left padding) - 58px (right padding) + width: 80%; + height: 80%; + border-radius: 4px; + + .mx_TabbedView_tabLabels { + // Force the sidebar to be always visible, letting the rest of the content scroll + position: fixed; + } + + .mx_TabbedView_tabPanel { + max-width: 485px; + margin-left: 206px; // 70px margin + 136px for the sidebar + } + + .mx_SettingsDialog_header { + font-size: 24px; + display: block; + text-align: center; + color: $dialog-title-fg-color; + margin-top: 16px; + margin-bottom: 24px; + padding: 0; + } + + .mx_SettingsDialog_close { + position: absolute; + top: 16px; + right: 25px; + } + + .mx_SettingsDialog_closeIcon { + width: 16px; + height: 16px; + display: inline-block; + } + + .mx_SettingsDialog_closeIcon:before { + mask: url('$(res)/img/feather-icons/cancel.svg'); + background-color: $dialog-close-fg-color; + mask-repeat: no-repeat; + mask-size: 16px; + mask-position: center; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + } + } +} diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss new file mode 100644 index 0000000000..814a738b5f --- /dev/null +++ b/res/css/views/dialogs/_UserSettingsDialog.scss @@ -0,0 +1,50 @@ +/* +Copyright 2019 New Vector Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// ICONS +// ========================================================== + +.mx_UserSettingsDialog_settingsIcon:before { + mask-image: url('$(res)/img/feather-icons/settings.svg'); +} + +.mx_UserSettingsDialog_voiceIcon:before { + mask-image: url('$(res)/img/feather-icons/phone.svg'); +} + +.mx_UserSettingsDialog_bellIcon:before { + mask-image: url('$(res)/img/feather-icons/notifications.svg'); +} + +.mx_UserSettingsDialog_preferencesIcon:before { + mask-image: url('$(res)/img/feather-icons/sliders.svg'); +} + +.mx_UserSettingsDialog_securityIcon:before { + mask-image: url('$(res)/img/feather-icons/lock.svg'); +} + +.mx_UserSettingsDialog_helpIcon:before { + mask-image: url('$(res)/img/feather-icons/help-circle.svg'); +} + +.mx_UserSettingsDialog_labsIcon:before { + mask-image: url('$(res)/img/feather-icons/flag.svg'); +} + +.mx_UserSettingsDialog_flairIcon:before { + mask-image: url('$(res)/img/feather-icons/flair.svg'); +} diff --git a/res/css/views/dialogs/keybackup/_CreateKeyBackupDialog.scss b/res/css/views/dialogs/keybackup/_CreateKeyBackupDialog.scss index 424ffbd0a8..3f4c8d2da4 100644 --- a/res/css/views/dialogs/keybackup/_CreateKeyBackupDialog.scss +++ b/res/css/views/dialogs/keybackup/_CreateKeyBackupDialog.scss @@ -14,8 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_CreateKeyBackupDialog { - padding-right: 40px; +.mx_CreateKeyBackupDialog .mx_Dialog_title { + /* TODO: Consider setting this for all dialog titles. */ + margin-bottom: 1em; } .mx_CreateKeyBackupDialog_primaryContainer { @@ -79,3 +80,8 @@ limitations under the License. display: flex; align-items: center; } + +.mx_CreateKeyBackupDialog_recoveryKeyButtons button { + flex: 1; + white-space: nowrap; +} diff --git a/res/css/views/dialogs/keybackup/_NewRecoveryMethodDialog.scss b/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss similarity index 82% rename from res/css/views/dialogs/keybackup/_NewRecoveryMethodDialog.scss rename to res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss index 370f82d9ab..bd703badaa 100644 --- a/res/css/views/dialogs/keybackup/_NewRecoveryMethodDialog.scss +++ b/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss @@ -14,17 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_NewRecoveryMethodDialog .mx_Dialog_title { +.mx_KeyBackupFailedDialog .mx_Dialog_title { margin-bottom: 32px; } -.mx_NewRecoveryMethodDialog_title { +.mx_KeyBackupFailedDialog_title { position: relative; padding-left: 45px; padding-bottom: 10px; &:before { - mask: url("../../../img/e2e/lock-warning.svg"); + mask: url("$(res)/img/e2e/lock-warning.svg"); mask-repeat: no-repeat; background-color: $primary-fg-color; content: ""; @@ -36,6 +36,6 @@ limitations under the License. } } -.mx_NewRecoveryMethodDialog .mx_Dialog_buttons { +.mx_KeyBackupFailedDialog .mx_Dialog_buttons { margin-top: 36px; } diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index 9850379597..8d5fa5dc7b 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -35,13 +35,13 @@ limitations under the License. height: 0; position: absolute; right: 10px; - top: 14px; + top: 16px; width: 0 } .mx_NetworkDropdown_networkoption { - height: 35px; - line-height: 35px; + height: 37px; + line-height: 37px; padding-left: 8px; padding-right: 8px; overflow: hidden; diff --git a/res/css/views/elements/_AccessibleButton.scss b/res/css/views/elements/_AccessibleButton.scss index edf455049b..8de0b82554 100644 --- a/res/css/views/elements/_AccessibleButton.scss +++ b/res/css/views/elements/_AccessibleButton.scss @@ -16,9 +16,62 @@ limitations under the License. .mx_AccessibleButton:focus { outline: 0; - filter: brightness($focus-brightness); } .mx_AccessibleButton { cursor: pointer; +} + +.mx_AccessibleButton_disabled { + cursor: default; +} + +.mx_AccessibleButton_hasKind { + padding: 7px 18px; + text-align: center; + border-radius: 4px; + display: inline-block; + font-size: 14px; +} + +.mx_AccessibleButton_kind_primary { + color: $button-primary-fg-color; + background-color: $button-primary-bg-color; +} + +.mx_AccessibleButton_kind_primary.mx_AccessibleButton_disabled { + color: $button-primary-disabled-fg-color; + background-color: $button-primary-disabled-bg-color; +} + +.mx_AccessibleButton_hasKind.mx_AccessibleButton_kind_primary_sm { + padding: 5px 12px; + color: $button-primary-fg-color; + background-color: $button-primary-bg-color; +} + +.mx_AccessibleButton_kind_primary_sm.mx_AccessibleButton_disabled { + color: $button-primary-disabled-fg-color; + background-color: $button-primary-disabled-bg-color; +} + +.mx_AccessibleButton_kind_danger { + color: $button-danger-fg-color; + background-color: $button-danger-bg-color; +} + +.mx_AccessibleButton_kind_danger.mx_AccessibleButton_disabled { + color: $button-danger-disabled-fg-color; + background-color: $button-danger-disabled-bg-color; +} + +.mx_AccessibleButton_hasKind.mx_AccessibleButton_kind_danger_sm { + padding: 5px 12px; + color: $button-danger-fg-color; + background-color: $button-danger-bg-color; +} + +.mx_AccessibleButton_kind_danger_sm.mx_AccessibleButton_disabled { + color: $button-danger-disabled-fg-color; + background-color: $button-danger-disabled-bg-color; } \ No newline at end of file diff --git a/res/css/views/elements/_DirectorySearchBox.scss b/res/css/views/elements/_DirectorySearchBox.scss index 94a92b23ce..ef944f6fa0 100644 --- a/res/css/views/elements/_DirectorySearchBox.scss +++ b/res/css/views/elements/_DirectorySearchBox.scss @@ -15,26 +15,10 @@ limitations under the License. */ .mx_DirectorySearchBox { - position: relative; - border-radius: 3px; - border: 1px solid $strong-input-border-color; -} - -.mx_DirectorySearchBox_container { display: flex; padding-left: 9px; padding-right: 9px; -} - -.mx_DirectorySearchBox_input { - flex-grow: 1; - border: 0; - padding: 0; - font-weight: 300; - font-size: 13px; -} -input[type=text].mx_DirectorySearchBox_input:focus { - border: 0; + margin: 0 5px 0 0 !important; } .mx_DirectorySearchBox_joinButton { @@ -44,7 +28,7 @@ input[type=text].mx_DirectorySearchBox_input:focus { padding-right: 10px; background-color: $plinth-bg-color; border-radius: 3px; - background-image: url('../../img/icon-return.svg'); + background-image: url('$(res)/img/icon-return.svg'); background-position: 8px 70%; background-repeat: no-repeat; text-indent: 18px; @@ -54,16 +38,12 @@ input[type=text].mx_DirectorySearchBox_input:focus { cursor: pointer; } -.mx_DirectorySearchBox_clear_wrapper { - display: table-cell; -} - .mx_DirectorySearchBox_clear { - display: inline-block; - vertical-align: middle; - background: url('../../img/icon_context_delete.svg'); - background-position: 0 50%; - background-repeat: no-repeat; + background-color: $warning-color; + mask: url('$(res)/img/cancel.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: 10px; width: 15px; height: 15px; cursor: pointer; diff --git a/res/css/views/elements/_Dropdown.scss b/res/css/views/elements/_Dropdown.scss index 69dd1703ee..9d4fb5c4a9 100644 --- a/res/css/views/elements/_Dropdown.scss +++ b/res/css/views/elements/_Dropdown.scss @@ -23,11 +23,12 @@ limitations under the License. } .mx_Dropdown_input { + display: flex; + align-items: center; position: relative; border-radius: 3px; border: 1px solid $strong-input-border-color; - font-weight: 300; - font-size: 13px; + font-size: 12px; user-select: none; } @@ -41,19 +42,23 @@ limitations under the License. } .mx_Dropdown_arrow { - border-color: $primary-fg-color transparent transparent; - border-style: solid; - border-width: 5px 5px 0; display: block; - height: 0; - position: absolute; - right: 10px; - top: 14px; - width: 0 + position: relative; + width: 10px; + height: 6px; + padding-right: 8px; } -.mx_Dropdown.left_aligned .mx_Dropdown_arrow { - left: 10px; +.mx_Dropdown_arrow::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + mask: url('$(res)/img/feather-icons/dropdown-arrow.svg'); + mask-repeat: no-repeat; + background: $primary-fg-color; } .mx_Dropdown_input > .mx_Dropdown_option { @@ -62,10 +67,6 @@ limitations under the License. white-space: nowrap; } -.mx_Dropdown.left_aligned .mx_Dropdown_input > .mx_Dropdown_option { - padding-left: 25px; -} - .mx_Dropdown_option { height: 35px; line-height: 35px; @@ -81,7 +82,7 @@ limitations under the License. .mx_Dropdown_option img { margin: 5px; - width: 27px; + width: 16px; vertical-align: middle; } diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss new file mode 100644 index 0000000000..d2877ca741 --- /dev/null +++ b/res/css/views/elements/_Field.scss @@ -0,0 +1,95 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* TODO: Consider unifying with general input styles in _dharma.scss */ + +.mx_Field { + position: relative; + margin: 1em 0; +} + +.mx_Field input, +.mx_Field select, +.mx_Field textarea { + font-weight: normal; + font-family: $font-family; + border-radius: 4px; + transition: border-color 0.25s; + border: 1px solid $input-border-color; + padding: 8px 9px; +} + +.mx_Field input:focus, +.mx_Field select:focus, +.mx_Field textarea:focus { + outline: 0; + border-color: $input-focused-border-color; +} + +.mx_Field input::placeholder, +.mx_Field textarea::placeholder { + transition: color 0.25s ease-in 0s; + color: transparent; +} + +.mx_Field input:placeholder-shown:focus::placeholder, +.mx_Field textarea:placeholder-shown:focus::placeholder { + transition: color 0.25s ease-in 0.1s; + color: $greyed-fg-color; +} + +.mx_Field label { + transition: + font-size 0.25s ease-out 0.1s, + color 0.25s ease-out 0.1s, + top 0.25s ease-out 0.1s, + background-color 0.25s ease-out 0.1s; + color: $primary-fg-color; + background-color: transparent; + font-size: 14px; + position: absolute; + left: 0px; + top: 0px; + margin: 7px 8px; + padding: 2px; +} + +.mx_Field input:focus + label, +.mx_Field input:not(:placeholder-shown) + label, +.mx_Field textarea:focus + label, +.mx_Field textarea:not(:placeholder-shown) + label, +.mx_Field select + label /* Always show a select's label on top to not collide with the value */ { + transition: + font-size 0.25s ease-out 0s, + color 0.25s ease-out 0s, + top 0.25s ease-out 0s, + background-color 0.25s ease-out 0s; + font-size: 10px; + top: -14px; + background-color: $field-focused-label-bg-color; +} + +.mx_Field input:focus + label, +.mx_Field select:focus + label, +.mx_Field textarea:focus + label { + color: $input-focused-border-color; +} + +.mx_Field select:disabled, +.mx_Field input:disabled { + background-color: $field-focused-label-bg-color; + color: $greyed-fg-color; +} diff --git a/res/css/views/elements/_HexVerify.scss b/res/css/views/elements/_HexVerify.scss new file mode 100644 index 0000000000..3f3ee4b7ea --- /dev/null +++ b/res/css/views/elements/_HexVerify.scss @@ -0,0 +1,34 @@ +/* +Copyright 2019 New Vector Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_HexVerify { + text-align: center; +} + +.mx_HexVerify_pair { + display: inline-block; + font-weight: bold; + padding-left: 3px; + padding-right: 3px; +} + +.mx_HexVerify_pair_verified { + color: $accent-color; +} + +.mx_HexVerify_pair:hover{ + color: $accent-color; +} diff --git a/res/css/views/elements/_ImageView.scss b/res/css/views/elements/_ImageView.scss index 8ed0698a72..9bf23b1025 100644 --- a/res/css/views/elements/_ImageView.scss +++ b/res/css/views/elements/_ImageView.scss @@ -50,7 +50,7 @@ limitations under the License. max-height: 100%; /* object-fit hack needed for Chrome due to Chrome not re-laying-out until you refresh */ object-fit: contain; - /* background-image: url('../../img/trans.png'); */ + /* background-image: url('$(res)/img/trans.png'); */ pointer-events: all; } diff --git a/res/css/views/elements/_ResizeHandle.scss b/res/css/views/elements/_ResizeHandle.scss new file mode 100644 index 0000000000..5544799a34 --- /dev/null +++ b/res/css/views/elements/_ResizeHandle.scss @@ -0,0 +1,51 @@ +/* +Copyright 2018 New Vector Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_ResizeHandle { + cursor: row-resize; + flex: 0 0 auto; + z-index: 100; +} + +.mx_ResizeHandle.mx_ResizeHandle_horizontal { + margin: 0 -5px; + padding: 0 5px; + cursor: col-resize; +} + +.mx_ResizeHandle.mx_ResizeHandle_vertical { + margin: -5px 0; + padding: 5px 0; + cursor: row-resize; +} + +.mx_MatrixChat > .mx_ResizeHandle.mx_ResizeHandle_horizontal { + margin: 0 -10px 0 0; + padding: 0 10px 0 0; +} + +.mx_ResizeHandle > div { + background: $panel-divider-color; +} + +.mx_ResizeHandle.mx_ResizeHandle_horizontal > div { + width: 1px; + height: 100%; +} + +.mx_ResizeHandle.mx_ResizeHandle_vertical > div { + height: 1px; +} diff --git a/res/css/views/elements/_RichText.scss b/res/css/views/elements/_RichText.scss index cea4b7897d..0847aa7c9b 100644 --- a/res/css/views/elements/_RichText.scss +++ b/res/css/views/elements/_RichText.scss @@ -19,6 +19,11 @@ cursor: pointer; } +/* More specific to override `.markdown-body a` text-decoration */ +.mx_EventTile_content .markdown-body a.mx_Pill { + text-decoration: none; +} + /* More specific to override `.markdown-body a` color */ .mx_EventTile_content .markdown-body a.mx_UserPill, .mx_UserPill { @@ -31,7 +36,9 @@ background-color: $accent-color ! important; } +/* More specific to override `.markdown-body a` color */ .mx_EventTile_highlight .mx_EventTile_content .markdown-body a.mx_UserPill_me, +.mx_EventTile_content .markdown-body a.mx_AtRoomPill, .mx_EventTile_content .mx_AtRoomPill, .mx_MessageComposer_input .mx_AtRoomPill { color: $accent-fg-color; @@ -72,6 +79,11 @@ .mx_Markdown_ITALIC { font-style: italic; + + // compensate for Nunito italics being terrible + // https://github.com/google/fonts/issues/1726 + transform: skewX(-14deg); + display: inline-block; } .mx_Markdown_CODE { diff --git a/res/css/views/elements/_ToggleSwitch.scss b/res/css/views/elements/_ToggleSwitch.scss new file mode 100644 index 0000000000..1bb3a74ab1 --- /dev/null +++ b/res/css/views/elements/_ToggleSwitch.scss @@ -0,0 +1,53 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_ToggleSwitch { + transition: background-color 0.20s ease-out 0.1s; + width: 48px; + height: 24px; + border-radius: 14px; + background-color: $togglesw-off-color; + position: relative; + opacity: 0.5; +} + +.mx_ToggleSwitch_enabled { + cursor: pointer; + opacity: 1; +} + +.mx_ToggleSwitch.mx_ToggleSwitch_on { + background-color: $togglesw-on-color; +} + +.mx_ToggleSwitch_ball { + transition: left 0.15s ease-out 0.1s; + margin: 2px; + width: 20px; + height: 20px; + border-radius: 20px; + background-color: $togglesw-ball-color; + position: absolute; + top: 0; +} + +.mx_ToggleSwitch:not(.mx_ToggleSwitch_on) > .mx_ToggleSwitch_ball { + left: 2px; +} + +.mx_ToggleSwitch_on > .mx_ToggleSwitch_ball { + left: 23px; // 48px switch - 20px ball - 5px padding = 23px +} diff --git a/res/css/views/groups/_GroupPublicityToggle.scss b/res/css/views/groups/_GroupPublicityToggle.scss index 3ea4aa07d6..b8be2711ca 100644 --- a/res/css/views/groups/_GroupPublicityToggle.scss +++ b/res/css/views/groups/_GroupPublicityToggle.scss @@ -20,23 +20,14 @@ limitations under the License. margin: 8px; } -.mx_GroupPublicity_toggle > label { - display: flex; - align-items: flex-start; -} - -.mx_GroupPublicity_toggle > label, -.mx_GroupPublicity_toggle .mx_GroupTile { - width: 50%; -} - -.mx_GroupPublicity_toggle input { - margin-right: 8px; - vertical-align: -4px; -} - .mx_GroupPublicity_toggle .mx_GroupTile { display: flex; align-items: flex-start; cursor: pointer; + box-sizing: border-box; + width: 100%; +} + +.mx_GroupPublicity_toggle .mx_ToggleSwitch { + float: right; } diff --git a/res/css/views/groups/_GroupRoomList.scss b/res/css/views/groups/_GroupRoomList.scss index fb41ebaa9e..fefd17849c 100644 --- a/res/css/views/groups/_GroupRoomList.scss +++ b/res/css/views/groups/_GroupRoomList.scss @@ -18,4 +18,10 @@ limitations under the License. position: relative; color: $primary-fg-color; cursor: pointer; + display: flex; + align-items: center; +} + +.mx_GroupRoomList_wrapper { + padding: 10px; } diff --git a/res/css/views/groups/_GroupUserSettings.scss b/res/css/views/groups/_GroupUserSettings.scss index 0c909b7cf7..b207aa2958 100644 --- a/res/css/views/groups/_GroupUserSettings.scss +++ b/res/css/views/groups/_GroupUserSettings.scss @@ -18,6 +18,5 @@ limitations under the License. height: 200px; border: 1px solid $primary-hairline-color; border-radius: 3px; - margin-right: 32px; overflow: hidden; } diff --git a/res/css/views/messages/_DateSeparator.scss b/res/css/views/messages/_DateSeparator.scss index f676d24bef..f8738f10e3 100644 --- a/res/css/views/messages/_DateSeparator.scss +++ b/res/css/views/messages/_DateSeparator.scss @@ -16,10 +16,21 @@ limitations under the License. .mx_DateSeparator { clear: both; - margin-top: 32px; - margin-bottom: 8px; - margin-left: 63px; - padding-bottom: 6px; - border-bottom: 1px solid $primary-hairline-color; + margin: 4px 0; + display: flex; + align-items: center; + font-size: 14px; + color: $roomtopic-color; } +.mx_DateSeparator > hr { + flex: 1 1 0; + height: 0; + border: none; + border-bottom: 1px solid $panel-divider-color; +} + +.mx_DateSeparator > date { + margin: 0 25px; + flex: 0 0 auto; +} diff --git a/res/css/views/messages/_MImageBody.scss b/res/css/views/messages/_MImageBody.scss index a5a1e66a3b..86bc022829 100644 --- a/res/css/views/messages/_MImageBody.scss +++ b/res/css/views/messages/_MImageBody.scss @@ -56,4 +56,6 @@ limitations under the License. border-radius: 5px; background: $imagebody-giflabel; border: 2px solid $imagebody-giflabel-border; + color: $imagebody-giflabel-color; + pointer-events: none; } diff --git a/res/css/views/messages/_SenderProfile.scss b/res/css/views/messages/_SenderProfile.scss index 060709b82e..a4a2aba11f 100644 --- a/res/css/views/messages/_SenderProfile.scss +++ b/res/css/views/messages/_SenderProfile.scss @@ -13,3 +13,41 @@ 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_SenderProfile_name { + font-weight: 600; +} + +.mx_SenderProfile_color1 { + color: $username-variant1-color; +} + +.mx_SenderProfile_color2 { + color: $username-variant2-color; +} + +.mx_SenderProfile_color3 { + color: $username-variant3-color; +} + +.mx_SenderProfile_color4 { + color: $username-variant4-color; +} + +.mx_SenderProfile_color5 { + color: $username-variant5-color; +} + +.mx_SenderProfile_color6 { + color: $username-variant6-color; +} + +.mx_SenderProfile_color7 { + color: $username-variant7-color; +} + +.mx_SenderProfile_color8 { + color: $username-variant8-color; +} + + diff --git a/res/css/views/rooms/_AuxPanel.scss b/res/css/views/rooms/_AuxPanel.scss new file mode 100644 index 0000000000..34ef5e01d4 --- /dev/null +++ b/res/css/views/rooms/_AuxPanel.scss @@ -0,0 +1,50 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.m_RoomView_auxPanel_stateViews { + padding: 5px; + padding-left: 19px; + border-bottom: 1px solid #e5e5e5; +} + +.m_RoomView_auxPanel_stateViews_span a { + text-decoration: none; + color: inherit; +} + +.m_RoomView_auxPanel_stateViews_span[data-severity=warning] { + font-weight: bold; + color: orange; +} + +.m_RoomView_auxPanel_stateViews_span[data-severity=alert] { + font-weight: bold; + color: red; +} + +.m_RoomView_auxPanel_stateViews_span[data-severity=normal] { + font-weight: normal; +} + +.m_RoomView_auxPanel_stateViews_span[data-severity=notice] { + font-weight: normal; + color: $settings-grey-fg-color; +} + +.m_RoomView_auxPanel_stateViews_delim { + padding: 0 5px; + color: $settings-grey-fg-color; +} diff --git a/res/css/views/rooms/_EntityTile.scss b/res/css/views/rooms/_EntityTile.scss index 90d5dc9aa5..80b8126b54 100644 --- a/res/css/views/rooms/_EntityTile.scss +++ b/res/css/views/rooms/_EntityTile.scss @@ -15,12 +15,19 @@ limitations under the License. */ .mx_EntityTile { - display: table-row; - position: relative; + display: flex; + align-items: center; color: $primary-fg-color; cursor: pointer; } +.mx_EntityTile:hover { + background-image: url('$(res)/img/member_chevron.png'); + background-position: center right 10px; + background-repeat: no-repeat; + padding-right: 30px; +} + .mx_EntityTile_invite { display: table-cell; vertical-align: middle; @@ -30,12 +37,10 @@ limitations under the License. .mx_EntityTile_avatar, .mx_GroupRoomTile_avatar { - display: table-cell; padding-left: 3px; padding-right: 12px; padding-top: 4px; padding-bottom: 4px; - vertical-align: middle; width: 36px; height: 36px; position: relative; @@ -51,32 +56,21 @@ limitations under the License. .mx_EntityTile_name, .mx_GroupRoomTile_name { - display: table-cell; - vertical-align: middle; + flex: 1 1 0; overflow: hidden; font-size: 14px; text-overflow: ellipsis; white-space: nowrap; - max-width: 155px; } .mx_EntityTile_details { - display: table-cell; - padding-right: 14px; - vertical-align: middle; + overflow: hidden; } .mx_EntityTile_name_hover { font-size: 13px; } -.mx_EntityTile_chevron { - margin-top: 8px; - margin-right: -4px; - margin-left: 6px; - float: right; -} - .mx_EntityTile_ellipsis .mx_EntityTile_name { font-style: italic; color: $primary-fg-color; @@ -87,6 +81,7 @@ limitations under the License. color: $primary-fg-color; } +/* .mx_EntityTile_unavailable .mx_EntityTile_avatar, .mx_EntityTile_unavailable .mx_EntityTile_name, .mx_EntityTile_unavailable .mx_EntityTile_name_hover, @@ -110,6 +105,7 @@ limitations under the License. { opacity: 0.25; } +*/ .mx_EntityTile_subtext { font-size: 11px; @@ -118,5 +114,3 @@ limitations under the License. white-space: nowrap; text-overflow: clip; } - - diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index f74e2e0850..ee9971887e 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -55,11 +55,6 @@ limitations under the License. line-height: 22px; } -.mx_EventTile .mx_SenderProfile .mx_SenderProfile_name, -.mx_EventTile .mx_SenderProfile .mx_SenderProfile_aux { - opacity: 0.5; -} - .mx_EventTile .mx_SenderProfile .mx_Flair { opacity: 0.7; margin-left: 5px; @@ -296,8 +291,8 @@ limitations under the License. } /* always override hidden attribute for blocked and warning */ -.mx_EventTile_e2eIcon_hidden[src="img/e2e-blocked.svg"], -.mx_EventTile_e2eIcon_hidden[src="img/e2e-warning.svg"] { +.mx_EventTile_e2eIcon_hidden[src*="img/e2e-blocked.svg"], +.mx_EventTile_e2eIcon_hidden[src*="img/e2e-warning.svg"] { display: block; } @@ -450,13 +445,21 @@ limitations under the License. } .mx_EventTile_content .markdown-body a { - color: $accent-color; + color: $accent-color-alt; + text-decoration: underline; } .mx_EventTile_content .markdown-body .hljs { display: inline ! important; } +// compensate for Nunito italics being terrible +// https://github.com/google/fonts/issues/1726 +.mx_EventTile_content .markdown-body em { + transform: skewX(-14deg); + display: inline-block; +} + /* end of overrides */ .mx_MatrixChat_useCompactLayout { diff --git a/res/css/views/rooms/_JumpToBottomButton.scss b/res/css/views/rooms/_JumpToBottomButton.scss new file mode 100644 index 0000000000..968139671f --- /dev/null +++ b/res/css/views/rooms/_JumpToBottomButton.scss @@ -0,0 +1,69 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +@charset "utf-8"; + +.mx_JumpToBottomButton { + z-index: 1000; + position: absolute; + // 12 because height is 50 but button is only 38 = 12+(50-38) = 24 + bottom: 12px; + right: 24px; + width: 38px; + // give it a fixed height so the badge doesn't make + // it taller and pop upwards when visible + height: 50px; + text-align: center; +} + +.mx_JumpToBottomButton_badge { + position: relative; + top: -12px; + border-radius: 16px; + font-weight: bold; + font-size: 12px; + line-height: 14px; + text-align: center; + // to be able to get it centered + // with text-align in parent + display: inline-block; + padding: 0 4px; + color: $secondary-accent-color; + background-color: $warning-color; +} + +.mx_JumpToBottomButton_scrollDown { + position: relative; + height: 38px; + border-radius: 19px; + box-sizing: border-box; + background: $primary-bg-color; + border: 1.3px solid $roomtile-name-color; + cursor: pointer; +} + +.mx_JumpToBottomButton_scrollDown:before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + mask: url('$(res)/img/icon-jump-to-bottom.svg'); + mask-repeat: no-repeat; + mask-position: 9px 14px; + background: $roomtile-name-color; +} diff --git a/res/css/views/rooms/_MemberDeviceInfo.scss b/res/css/views/rooms/_MemberDeviceInfo.scss index d4e4bb1adf..6ccc4c7ae3 100644 --- a/res/css/views/rooms/_MemberDeviceInfo.scss +++ b/res/css/views/rooms/_MemberDeviceInfo.scss @@ -15,13 +15,16 @@ limitations under the License. */ .mx_MemberDeviceInfo { - padding: 10px 0px; + display: flex; + padding-bottom: 10px; + align-items: start; } -.mx_MemberDeviceInfo.mx_DeviceVerifyButtons { +.mx_MemberDeviceInfo > .mx_DeviceVerifyButtons { display: flex; - flex-wrap: wrap; - justify-content: space-between; + flex-direction: column; + flex: 0 1 auto; + align-items: stretch; } .mx_MemberDeviceInfo_textButton { @@ -39,16 +42,14 @@ limitations under the License. } .mx_MemberDeviceInfo_deviceInfo { - margin-bottom: 10px; - padding-bottom: 10px; - border-bottom: 1px solid rgba(0,0,0,0.1); + margin: 0 5px 5px 8px; + flex: 1; } /* "Unblacklist" is too long for a regular button: make it wider and reduce the padding. */ .mx_EncryptedEventDialog .mx_MemberDeviceInfo_blacklist, .mx_EncryptedEventDialog .mx_MemberDeviceInfo_unblacklist { - width: 8em; padding-left: 1em; padding-right: 1em; } diff --git a/res/css/views/rooms/_MemberInfo.scss b/res/css/views/rooms/_MemberInfo.scss index 2270e83743..99771fece0 100644 --- a/res/css/views/rooms/_MemberInfo.scss +++ b/res/css/views/rooms/_MemberInfo.scss @@ -15,14 +15,35 @@ limitations under the License. */ .mx_MemberInfo { - margin-top: 20px; - padding-right: 20px; - height: 100%; + display: flex; + flex-direction: column; + flex: 1; overflow-y: auto; } +.mx_MemberInfo_name { + align-items: center; + display: flex; +} + +.mx_MemberInfo_cancel { + height: 16px; + padding: 10px 15px; + cursor: pointer; +} + +.mx_MemberInfo_name h2 { + flex: 1; +} + .mx_MemberInfo h2 { - margin-top: 6px; + font-size: 18px; + font-weight: 600; + margin: 16px 0; +} + +.mx_MemberInfo_container { + margin: 0 16px 16px 16px; } .mx_MemberInfo .mx_RoomTile_nameContainer { @@ -37,14 +58,17 @@ limitations under the License. width: 160px; } -.mx_MemberInfo_cancel { - float: right; - margin-right: 10px; - cursor: pointer; +.mx_MemberInfo_avatar { + background: $tagpanel-bg-color; + margin-bottom: 16px; } -.mx_MemberInfo_avatar { - clear: both; +.mx_MemberInfo_avatar > img { + height: auto; + width: 100%; + max-height: 30vh; + object-fit: contain; + display: block; } .mx_MemberInfo_avatar .mx_BaseAvatar { @@ -60,17 +84,15 @@ limitations under the License. .mx_MemberInfo h3 { text-transform: uppercase; - color: $h3-color; - font-weight: 600; - font-size: 13px; - margin-top: 16px; - margin-bottom: 14px; + color: $input-darker-fg-color; + font-weight: bold; + font-size: 12px; + margin: 4px 0; } .mx_MemberInfo_profileField { - font-size: 13px; + font-size: 15px; position: relative; - background-color: $primary-bg-color; } .mx_MemberInfo_buttons { @@ -79,14 +101,17 @@ limitations under the License. .mx_MemberInfo_field { cursor: pointer; - font-size: 13px; - color: $accent-color; + font-size: 15px; + color: $primary-fg-color; margin-left: 8px; line-height: 23px; } .mx_MemberInfo_createRoom { cursor: pointer; + display: flex; + align-items: center; + padding: 0 8px; } .mx_MemberInfo_createRoom_label { @@ -117,3 +142,6 @@ limitations under the License. white-space: nowrap; text-overflow: clip; } +.mx_MemberInfo .mx_MemberInfo_scrollContainer { + flex: 1; +} diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss index cfac8797b9..ab3b68b346 100644 --- a/res/css/views/rooms/_MemberList.scss +++ b/res/css/views/rooms/_MemberList.scss @@ -17,20 +17,24 @@ limitations under the License. .mx_MemberList, .mx_GroupMemberList, .mx_GroupRoomList { - height: 100%; - - margin-top: 12px; - margin-right: 20px; - flex: 1; - display: flex; - flex-direction: column; -} -.mx_MemberList .mx_Spinner { - flex: 0 0 auto; + .mx_Spinner { + flex: 1 0 auto; + } + + h2 { + text-transform: uppercase; + color: $h3-color; + font-weight: 600; + font-size: 13px; + padding-left: 3px; + padding-right: 12px; + margin-top: 8px; + margin-bottom: 4px; + } } .mx_MemberList_chevron { @@ -49,65 +53,39 @@ limitations under the License. .mx_MemberList_query, .mx_GroupMemberList_query, .mx_GroupRoomList_query { - font-family: $font-family; - border-radius: 3px; - border: 1px solid $input-border-color; - padding: 9px; - color: $primary-fg-color; - background-color: $primary-bg-color; - margin-left: 3px; - font-size: 14px; - margin-bottom: 8px; - width: 189px; + flex: 1 1 0; } -.mx_MemberList_query::-moz-placeholder, -.mx_GroupMemberList_query::-moz-placeholder, -.mx_GroupRoomList_query::-moz-placeholder { - color: $primary-fg-color; - opacity: 0.5; - font-size: 14px; -} -.mx_MemberList_query::-webkit-input-placeholder, -.mx_GroupMemberList_query::-webkit-input-placeholder, -.mx_GroupRoomList_query::-webkit-input-placeholder { - color: $primary-fg-color; - opacity: 0.5; - font-size: 14px; -} -.mx_MemberList_joined { - order: 2; - flex: 1 0 0; - - overflow-y: auto; -} - -/* -.mx_MemberList_invited { - order: 3; - flex: 0 0 100px; - overflow-y: auto; -} -*/ - -.mx_GroupMemberList_invited h2, -.mx_MemberList_invited h2 { - text-transform: uppercase; - color: $h3-color; - font-weight: 600; - font-size: 13px; - padding-left: 3px; - padding-right: 12px; - margin-top: 8px; - margin-bottom: 4px; -} - -/* we have to have display: table in order for the horizontal wrapping to work */ .mx_MemberList_wrapper { - display: table; - table-layout: fixed; - width: 100%; + padding: 10px; } + +.mx_MemberList_invite, +.mx_RightPanel_invite { + flex: 0 0 auto; + position: relative; + background-color: $button-bg-color; + border-radius: 4px; + padding: 8px; + margin: 9px; + display: flex; + color: $button-fg-color; + font-weight: 600; + + .mx_RightPanel_icon { + padding-right: 5px; + padding-top: 2px; + } +} + +.mx_MemberList_invite span { + margin: 0 auto; + background-image: url('$(res)/img/feather-icons/user-add.svg'); + background-repeat: no-repeat; + background-position: center left; + padding-left: 25px; + +} diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index e6a532d072..f3dfebfe11 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -16,7 +16,6 @@ limitations under the License. */ .mx_MessageComposer_wrapper { - max-width: 960px; vertical-align: middle; margin: auto; border-top: 1px solid $primary-hairline-color; @@ -58,13 +57,8 @@ limitations under the License. width: 100%; } -.mx_MessageComposer_row > div:last-child{ - padding-right: 0; -} - .mx_MessageComposer .mx_MessageComposer_avatar { - padding-left: 10px; - padding-right: 28px; + padding: 0 27px; } .mx_MessageComposer .mx_MessageComposer_avatar .mx_BaseAvatar { @@ -77,7 +71,7 @@ limitations under the License. .mx_MessageComposer_e2eIcon { position: absolute; - left: 44px; + left: 60px; } .mx_MessageComposer_noperm_error { @@ -113,7 +107,8 @@ limitations under the License. width: 100%; max-height: 120px; min-height: 19px; - overflow: auto; + overflow-y: auto; + overflow-x: hidden; word-break: break-word; } @@ -187,7 +182,7 @@ limitations under the License. /*display: table-cell;*/ /*vertical-align: middle;*/ /*padding-left: 10px;*/ - padding-right: 5px; + padding-right: 12px; cursor: pointer; padding-top: 4px; } @@ -216,7 +211,6 @@ limitations under the License. .mx_MessageComposer_formatbar { margin: auto; - max-width: 960px; display: flex; height: 30px; diff --git a/res/css/views/rooms/_RoomHeader.scss b/res/css/views/rooms/_RoomHeader.scss index 9c1349adbc..1359bc5f57 100644 --- a/res/css/views/rooms/_RoomHeader.scss +++ b/res/css/views/rooms/_RoomHeader.scss @@ -14,29 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. */ -/* add 20px to the height of the header when editing */ -.mx_RoomHeader_editing { - flex: 0 0 93px ! important; +.mx_RoomHeader { + flex: 0 0 52px; + border-bottom: 1px solid $primary-hairline-color; } .mx_RoomHeader_wrapper { - max-width: 960px; margin: auto; - height: 70px; + height: 52px; align-items: center; display: flex; -} - -.mx_RoomHeader_leftRow { - margin-left: -2px; - order: 1; - flex: 1; - overflow: hidden; + align-items: center; + min-width: 0; + padding: 0 10px 0 19px; } .mx_RoomHeader_spinner { + flex: 1; height: 36px; - order: 2; padding-left: 12px; padding-right: 12px; } @@ -45,7 +40,6 @@ limitations under the License. @mixin mx_DialogButton; margin-right: 8px; margin-top: -5px; - order: 2; } .mx_RoomHeader_textButton:hover { @@ -57,31 +51,29 @@ limitations under the License. } .mx_RoomHeader_cancelButton { - order: 2; cursor: pointer; padding-left: 12px; padding-right: 12px; } -.mx_RoomHeader_rightRow { - margin-top: 4px; - background-color: $primary-bg-color; +.mx_RoomHeader_buttons { display: flex; align-items: center; - order: 3; + background-color: $primary-bg-color; + padding-right: 5px; } .mx_RoomHeader_info { - display: table-cell; - width: 100%; - vertical-align: middle; + display: flex; + flex: 1; + align-items: center; } .mx_RoomHeader_simpleHeader { - line-height: 70px; - color: $primary-fg-color; - font-size: 22px; - font-weight: bold; + line-height: 52px; + color: $roomheader-color; + font-size: 18px; + font-weight: 600; overflow: hidden; margin-left: 63px; text-overflow: ellipsis; @@ -99,22 +91,20 @@ limitations under the License. } .mx_RoomHeader_name { - vertical-align: middle; - width: 100%; - height: 31px; + flex: 0 1 auto; overflow: hidden; - color: $primary-fg-color; - font-weight: bold; - font-size: 22px; - padding-left: 19px; - padding-right: 16px; - /* why isn't text-overflow working? */ - text-overflow: ellipsis; + color: $roomheader-color; + font-weight: 600; + font-size: 18px; + margin: 0 7px; border-bottom: 1px solid transparent; + display: flex; } .mx_RoomHeader_nametext { - display: inline-block; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; } .mx_RoomHeader_settingsHint { @@ -122,7 +112,6 @@ limitations under the License. } .mx_RoomHeader_searchStatus { - display: inline-block; font-weight: normal; opacity: 0.6; } @@ -166,25 +155,23 @@ limitations under the License. } .mx_RoomHeader_topic { - vertical-align: bottom; - float: left; - max-height: 38px; - color: $settings-grey-fg-color; - font-weight: 300; + flex: 1; + color: $roomtopic-color; + font-weight: 400; font-size: 13px; - margin-left: 19px; - margin-right: 16px; + margin: 0 7px; overflow: hidden; text-overflow: ellipsis; border-bottom: 1px solid transparent; - column-width: 960px; + line-height: 1.2em; + max-height: 2.4em; } .mx_RoomHeader_avatar { - display: table-cell; - width: 48px; - height: 50px; - vertical-align: middle; + flex: 0; + width: 28px; + height: 28px; + margin: 0 7px; } .mx_RoomHeader_avatar .mx_BaseAvatar_image { @@ -192,13 +179,13 @@ limitations under the License. } .mx_RoomHeader_avatarPicker { - margin-top: 23px; position: relative; } .mx_RoomHeader_avatarPicker_edit { - margin-left: 16px; - margin-top: 4px; + position: absolute; + left: 16px; + top: 18px; } .mx_RoomHeader_avatarPicker_edit > label { @@ -210,7 +197,7 @@ limitations under the License. } .mx_RoomHeader_button { - margin-left: 12px; + margin-left: 10px; cursor: pointer; } @@ -218,6 +205,10 @@ limitations under the License. pointer-events: none; } +.mx_RoomHeader_showPanel { + height: 16px; +} + .mx_RoomHeader_voipButton { display: table-cell; } diff --git a/res/css/views/rooms/_RoomList.scss b/res/css/views/rooms/_RoomList.scss index a346a06a20..886f10dc4c 100644 --- a/res/css/views/rooms/_RoomList.scss +++ b/res/css/views/rooms/_RoomList.scss @@ -16,8 +16,24 @@ limitations under the License. */ .mx_RoomList { - padding-bottom: 12px; - min-height: 400px; + /* take up remaining space below TopLeftMenu */ + flex: 1; + min-height: 0; + overflow-y: hidden; +} + +.mx_RoomList .mx_ResizeHandle { + // needed so the z-index takes effect + position: relative; +} + +.mx_SearchBox { + flex: none; +} + +/* hide resize handles next to collapsed / empty sublists */ +.mx_RoomList .mx_RoomSubList:not(.mx_RoomSubList_nonEmpty) + .mx_ResizeHandle { + display: none; } .mx_RoomList_expandButton { @@ -27,20 +43,7 @@ limitations under the License. padding-right: 12px; } -/* Evil hacky override until Chrome fixes drop and drag table cells - and we can correctly fix horizontal wrapping in the sidebar again */ -.mx_RoomList_scrollbar .gm-scroll-view { - overflow-x: hidden ! important; - overflow-y: scroll ! important; -} - -/* Make sure the scrollbar is above the sticky headers from RoomList */ -.mx_RoomList_scrollbar .gm-scrollbar.-vertical { - z-index: 6; -} - .mx_RoomList_emptySubListTip_container { - background-color: $secondary-accent-color; padding-left: 18px; padding-right: 18px; padding-top: 8px; diff --git a/res/css/views/rooms/_RoomSettings.scss b/res/css/views/rooms/_RoomSettings.scss index b3858f3ba7..5ed9168aab 100644 --- a/res/css/views/rooms/_RoomSettings.scss +++ b/res/css/views/rooms/_RoomSettings.scss @@ -16,8 +16,7 @@ limitations under the License. */ .mx_RoomSettings { - margin-left: 65px; - margin-bottom: 20px; + margin: 40px; } .mx_RoomSettings_upgradeButton, @@ -67,15 +66,16 @@ limitations under the License. .mx_RoomSettings_integrationsButton_errorPopup { position: absolute; top: 110%; - left: -125%; - width: 348%; - padding: 2%; + left: -275%; + width: 550%; + padding: 30%; font-size: 10pt; line-height: 1.5em; border-radius: 5px; background-color: $accent-color; color: $accent-fg-color; text-align: center; + z-index: 1000; } .mx_RoomSettings_unbanButton { display: inline; diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index b5ac9aadc6..395dcd68d9 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -15,13 +15,30 @@ limitations under the License. */ .mx_RoomTile { - position: relative; + display: flex; + flex-direction: row; + align-items: center; cursor: pointer; - font-size: 13px; - display: block; height: 34px; + margin: 0; + padding: 0 8px 0 10px; + position: relative; +} - background-color: $secondary-accent-color; +.mx_RoomTile_menuButton { + display: none; + flex: 0 0 16px; + height: 16px; + background-image: url('$(res)/img/icon_context.svg'); + background-repeat: no-repeat; + background-position: center; +} + +// toggle menuButton and badge on hover/menu displayed +.mx_LeftPanel_container:not(.collapsed) .mx_RoomTile:hover, .mx_RoomTile_menuDisplayed { + .mx_RoomTile_menuButton { + display: block; + } } .mx_RoomTile_tooltip { @@ -33,9 +50,18 @@ limitations under the License. .mx_RoomTile_nameContainer { - display: inline-block; - width: 180px; + display: flex; + align-items: center; + flex: 1; vertical-align: middle; + min-width: 0; +} + +.mx_RoomTile_labelContainer { + display: flex; + flex-direction: column; + flex: 1; + min-width: 0; } .mx_RoomTile_subtext { @@ -55,11 +81,8 @@ limitations under the License. } .mx_RoomTile_avatar { - display: inline-block; - padding-top: 5px; - padding-bottom: 5px; - padding-left: 16px; - padding-right: 6px; + flex: 0; + padding: 4px; width: 24px; vertical-align: middle; } @@ -78,87 +101,52 @@ limitations under the License. } .mx_RoomTile_name { - display: inline-block; - position: relative; - width: 165px; - vertical-align: middle; - padding-left: 6px; - padding-right: 6px; - padding-top: 2px; - padding-bottom: 3px; + font-size: 14px; + font-weight: 600; + padding: 0 6px; color: $roomtile-name-color; white-space: nowrap; - overflow: hidden; + overflow-x: hidden; text-overflow: ellipsis; } -.mx_RoomTile_invite { -/* color: rgba(69, 69, 69, 0.5); */ -} +.collapsed { + .mx_RoomTile { + margin: 0 2px; + padding: 0 2px; + position: relative; + justify-content: center; + } -.collapsed .mx_RoomTile_nameContainer { - width: 60px; /* colapsed panel width */ -} + .mx_RoomTile_name { + display: none; + } -.collapsed .mx_RoomTile_name { - display: none; -} + .mx_RoomTile_badge { + position: absolute; + right: 6px; + top: 0px; + border-radius: 16px; + z-index: 3; + border: 0.18em solid $secondary-accent-color; + } -.collapsed .mx_RoomTile_badge { - top: 0px; - min-width: 12px; - border-radius: 16px; - padding: 0px 4px 0px 4px; - z-index: 3; -} - -/* Hide the bottom of speech bubble */ -.collapsed .mx_RoomTile_highlight .mx_RoomTile_badge:after { - display: none; -} - -/* This is the bottom of the speech bubble */ -.mx_RoomTile_highlight .mx_RoomTile_badge:after { - content: ""; - position: absolute; - display: block; - width: 0; - height: 0; - margin-left: 5px; - border-top: 5px solid $warning-color; - border-right: 7px solid transparent; + .mx_RoomTile_menuButton { + display: none; //no design for this for now + } } .mx_RoomTile_badge { - display: inline-block; - min-width: 15px; - height: 15px; - position: absolute; - right: 8px; /*gutter */ - top: 9px; - border-radius: 8px; + flex: 0 1 content; + border-radius: 0.8em; + padding: 0 0.4em; color: $accent-fg-color; font-weight: 600; - font-size: 10px; - text-align: center; - padding-top: 1px; - padding-left: 4px; - padding-right: 4px; -} - -.mx_RoomTile .mx_RoomTile_badge.mx_RoomTile_badgeButton, -.mx_RoomTile.mx_RoomTile_menuDisplayed .mx_RoomTile_badge { - letter-spacing: 0.1em; - opacity: 1; -} - -.mx_RoomTile.mx_RoomTile_noBadges .mx_RoomTile_badge.mx_RoomTile_badgeButton, -.mx_RoomTile.mx_RoomTile_menuDisplayed.mx_RoomTile_noBadges .mx_RoomTile_badge { - background-color: $neutral-badge-color; + font-size: 12px; } .mx_RoomTile_unreadNotify .mx_RoomTile_badge { - background-color: $accent-color; + background-color: $roomtile-name-color; } .mx_RoomTile_highlight .mx_RoomTile_badge { @@ -167,9 +155,14 @@ limitations under the License. .mx_RoomTile_unread, .mx_RoomTile_highlight { font-weight: 800; + + .mx_RoomTile_name { + color: $roomtile-selected-color; + } } .mx_RoomTile_selected { + border-radius: 4px; background-color: $roomtile-selected-bg-color; } @@ -187,10 +180,6 @@ limitations under the License. background-color: $roomtile-focused-bg-color; } -.mx_RoomTile .mx_RoomTile_name.mx_RoomTile_badgeShown { - width: 140px; -} - .mx_RoomTile_arrow { position: absolute; right: 0px; @@ -203,4 +192,3 @@ limitations under the License. .mx_RoomTile.mx_RoomTile_transparent:focus { background-color: $roomtile-transparent-focused-color; } - diff --git a/res/css/views/rooms/_RoomTooltip.scss b/res/css/views/rooms/_RoomTooltip.scss index 9988425b8f..295786d2d3 100644 --- a/res/css/views/rooms/_RoomTooltip.scss +++ b/res/css/views/rooms/_RoomTooltip.scss @@ -21,7 +21,7 @@ limitations under the License. width: 0; height: 0; border-top: 8px solid transparent; - border-right: 8px solid $menu-border-color; + border-right: 8px solid $menu-bg-color; border-bottom: 8px solid transparent; } @@ -40,8 +40,8 @@ limitations under the License. .mx_RoomTooltip { display: none; position: fixed; - border: 1px solid $menu-border-color; border-radius: 5px; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.21); background-color: $primary-bg-color; z-index: 2000; padding: 5px; diff --git a/res/css/views/rooms/_SearchBar.scss b/res/css/views/rooms/_SearchBar.scss index 079ea16c68..b89cb0ce13 100644 --- a/res/css/views/rooms/_SearchBar.scss +++ b/res/css/views/rooms/_SearchBar.scss @@ -15,69 +15,52 @@ limitations under the License. */ .mx_SearchBar { - padding-top: 5px; - padding-bottom: 5px; + height: 56px; display: flex; align-items: center; -} + border-bottom: 1px solid $primary-hairline-color; -.mx_SearchBar_input { - display: inline block; - border-radius: 3px 0px 0px 3px; - border: 1px solid $input-border-color; - font-size: 15px; - padding: 9px; - padding-left: 11px; - width: auto; - flex: 1 1 0; -} + .mx_SearchBar_input { + // border: 1px solid $input-border-color; + // font-size: 15px; + flex: 1 1 0; + margin-left: 22px; + } -.mx_SearchBar_searchButton { - cursor: pointer; - margin-right: 10px; - width: 37px; - height: 37px; - border-radius: 0px 3px 3px 0px; - background-color: $accent-color; -} + .mx_SearchBar_searchButton { + cursor: pointer; + width: 37px; + height: 37px; + background-color: $accent-color; + mask: url('$(res)/img/feather-icons/search-input.svg'); + mask-repeat: no-repeat; + mask-position: center; + } -@keyframes pulsate { - 0% { opacity: 1.0; } - 50% { opacity: 0.1; } - 100% { opacity: 1.0; } -} + .mx_SearchBar_button { + border: 0; + margin: 0 0 0 22px; + padding: 5px; + font-size: 15px; + cursor: pointer; + color: $primary-fg-color; + border-bottom: 2px solid $accent-color; + font-weight: 600; + } -.mx_SearchBar_searching img { - animation: pulsate 0.5s ease-out; - animation-iteration-count: infinite; -} + .mx_SearchBar_unselected { + color: $input-darker-fg-color; + border-color: transparent; + } -.mx_SearchBar_button { - display: inline; - border: 0px; - border-radius: 36px; - font-weight: 400; - font-size: 15px; - color: $accent-fg-color; - background-color: $accent-color; - width: auto; - margin: auto; - margin-left: 7px; - padding-top: 6px; - padding-bottom: 4px; - padding-left: 24px; - padding-right: 24px; - cursor: pointer; -} - -.mx_SearchBar_unselected { - background-color: $primary-bg-color; - color: $accent-color; - border: $accent-color 1px solid; -} - -.mx_SearchBar_cancel { - padding-left: 14px; - padding-right: 14px; - cursor: pointer; + .mx_SearchBar_cancel { + background-color: $warning-color; + mask: url('$(res)/img/cancel.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: 14px; + padding: 9px; + margin: 0 12px 0 3px; + cursor: pointer; + } } diff --git a/res/css/views/rooms/_TopUnreadMessagesBar.scss b/res/css/views/rooms/_TopUnreadMessagesBar.scss index 1ee56d9532..a4b7a6aa51 100644 --- a/res/css/views/rooms/_TopUnreadMessagesBar.scss +++ b/res/css/views/rooms/_TopUnreadMessagesBar.scss @@ -14,40 +14,48 @@ See the License for the specific language governing permissions and limitations under the License. */ +@charset "utf-8"; + .mx_TopUnreadMessagesBar { - margin: auto; /* centre horizontally */ - max-width: 960px; - padding-top: 10px; - padding-bottom: 10px; - border-bottom: 1px solid $primary-hairline-color; + z-index: 1000; + position: absolute; + top: 24px; + right: 24px; + width: 38px; +} + +.mx_TopUnreadMessagesBar:after { + content: "·"; + position: absolute; + top: -8px; + left: 11px; + width: 16px; + height: 16px; + border-radius: 16px; + font-weight: 600; + font-size: 30px; + line-height: 14px; + text-align: center; + color: $secondary-accent-color; + background-color: $accent-color; } .mx_TopUnreadMessagesBar_scrollUp { - display: inline; - cursor: pointer; - text-decoration: underline; -} - -.mx_TopUnreadMessagesBar_scrollUp img { - padding-left: 10px; - padding-right: 31px; - vertical-align: middle; -} - -.mx_TopUnreadMessagesBar_scrollUp span { - opacity: 0.5; -} - -.mx_TopUnreadMessagesBar_close { - float: right; - padding-right: 14px; - padding-top: 3px; + height: 38px; + border-radius: 19px; + box-sizing: border-box; + background: $primary-bg-color; + border: 1.3px solid $roomtile-name-color; cursor: pointer; } -.mx_MatrixChat_useCompactLayout { - .mx_TopUnreadMessagesBar { - padding-top: 4px; - padding-bottom: 4px; - } +.mx_TopUnreadMessagesBar_scrollUp:before { + content: ""; + position: absolute; + width: 38px; + height: 38px; + mask: url('$(res)/img/icon-jump-to-first-unread.svg'); + mask-repeat: no-repeat; + mask-position: 9px 13px; + background: $roomtile-name-color; } diff --git a/res/css/views/rooms/_WhoIsTypingTile.scss b/res/css/views/rooms/_WhoIsTypingTile.scss new file mode 100644 index 0000000000..eb51595858 --- /dev/null +++ b/res/css/views/rooms/_WhoIsTypingTile.scss @@ -0,0 +1,77 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_WhoIsTypingTile { + margin-left: -18px; //offset padding from mx_RoomView_MessageList to center avatars + padding-top: 18px; + display: flex; + align-items: center; +} + +/* position the indicator in the same place horizontally as .mx_EventTile_avatar. */ +.mx_WhoIsTypingTile_avatars { + flex: 0 0 83px; // 18 + 65 + text-align: center; +} + +.mx_WhoIsTypingTile_avatars > :not(:first-child) { + margin-left: -12px; +} + +.mx_WhoIsTypingTile_avatars .mx_BaseAvatar_image { + border: 1px solid $primary-bg-color; +} + +.mx_WhoIsTypingTile_avatars .mx_BaseAvatar_initial { + padding-top: 1px; +} + +.mx_WhoIsTypingTile_remainingAvatarPlaceholder { + 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; +} + +.mx_WhoIsTypingTile_label { + flex: 1; + font-size: 14px; + font-weight: 600; + color: $eventtile-meta-color; +} + +.mx_WhoIsTypingTile_label > span { + background-image: url('$(res)/img/typing-indicator-2x.gif'); + background-size: 25px; + background-position: left bottom; + background-repeat: no-repeat; + padding-bottom: 15px; + display: block; +} + +.mx_MatrixChat_useCompactLayout { + + .mx_WhoIsTypingTile { + padding-top: 4px; + } +} diff --git a/res/css/views/settings/_EmailAddresses.scss b/res/css/views/settings/_EmailAddresses.scss new file mode 100644 index 0000000000..eef804a33b --- /dev/null +++ b/res/css/views/settings/_EmailAddresses.scss @@ -0,0 +1,43 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_ExistingEmailAddress { + margin-bottom: 5px; +} + +.mx_ExistingEmailAddress_delete { + margin-right: 5px; + cursor: pointer; + vertical-align: middle; +} + +.mx_ExistingEmailAddress_email { + vertical-align: middle; +} + +.mx_ExistingEmailAddress_promptText { + margin-right: 10px; +} + +.mx_ExistingEmailAddress_confirmBtn { + margin-right: 5px; +} + +.mx_EmailAddresses_new .mx_Field input { + // Use 100% of the space available for the input, but don't let the 10px + // padding on either side of the input to push it out of alignment. + width: calc(100% - 20px); +} diff --git a/res/css/views/settings/_Notifications.scss b/res/css/views/settings/_Notifications.scss index 4c88e44952..171b4c2e05 100644 --- a/res/css/views/settings/_Notifications.scss +++ b/res/css/views/settings/_Notifications.scss @@ -44,12 +44,10 @@ limitations under the License. .mx_UserNotifSettings_pushRulesTable thead { font-weight: bold; - font-size: 15px; } .mx_UserNotifSettings_pushRulesTable tbody th { font-weight: 400; - font-size: 15px; } .mx_UserNotifSettings_pushRulesTable tbody th:first-child { diff --git a/res/css/views/settings/_PhoneNumbers.scss b/res/css/views/settings/_PhoneNumbers.scss new file mode 100644 index 0000000000..2f54babd6f --- /dev/null +++ b/res/css/views/settings/_PhoneNumbers.scss @@ -0,0 +1,56 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_ExistingPhoneNumber { + margin-bottom: 5px; +} + +.mx_ExistingPhoneNumber_delete { + margin-right: 5px; + cursor: pointer; + vertical-align: middle; +} + +.mx_ExistingPhoneNumber_address { + vertical-align: middle; +} + +.mx_ExistingPhoneNumber_promptText { + margin-right: 10px; +} + +.mx_ExistingPhoneNumber_confirmBtn { + margin-right: 5px; +} + +.mx_PhoneNumbers_new .mx_Field input { + // Use 100% of the space available for the input, but don't let the 10px + // padding on either side of the input to push it out of alignment. + width: calc(100% - 20px); +} + +.mx_PhoneNumbers_input { + display: flex; + align-items: center; +} + +.mx_PhoneNumbers_input > .mx_Field { + flex-grow: 1; +} + +.mx_PhoneNumbers_country { + width: 80px; +} diff --git a/res/css/views/settings/_ProfileSettings.scss b/res/css/views/settings/_ProfileSettings.scss new file mode 100644 index 0000000000..27dfae61a1 --- /dev/null +++ b/res/css/views/settings/_ProfileSettings.scss @@ -0,0 +1,125 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_ProfileSettings_profile { + display: flex; +} + +.mx_ProfileSettings_controls { + flex-grow: 1; +} + +.mx_ProfileSettings_controls .mx_Field #profileDisplayName, +.mx_ProfileSettings_controls .mx_Field #profileTopic { + width: calc(100% - 20px); // subtract 10px padding on left and right +} + +.mx_ProfileSettings_controls .mx_Field #profileTopic { + height: 4em; +} + +.mx_ProfileSettings_controls .mx_Field:first-child { + margin-top: 0; +} + +.mx_ProfileSettings_avatar { + width: 88px; + height: 88px; + margin-left: 13px; + position: relative; + cursor: pointer; +} + +.mx_ProfileSettings_avatar > * { + display: block; + width: 88px; + height: 88px; + border-radius: 4px; +} + +.mx_ProfileSettings_avatar .mx_ProfileSettings_avatarOverlay_disabled { + cursor: default; +} + +.mx_ProfileSettings_avatar .mx_ProfileSettings_avatarPlaceholder { + background-color: $settings-profile-placeholder-bg-color; +} + +.mx_ProfileSettings_avatarOverlay { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + display: none; + text-align: center; + vertical-align: middle; + font-size: 10px; +} + +.mx_ProfileSettings_avatar:hover .mx_ProfileSettings_avatarOverlay:not(.mx_ProfileSettings_avatarOverlay_disabled) { + display: inline-block; + opacity: 0.5 !important; + color: $settings-profile-overlay-fg-color !important; + background-color: $settings-profile-overlay-bg-color !important; +} + +.mx_ProfileSettings_avatarOverlay_show { + display: inline-block; + opacity: 1; + color: $settings-profile-overlay-placeholder-fg-color; + background-color: $settings-profile-overlay-placeholder-bg-color; +} + +.mx_ProfileSettings_avatarOverlayText { + display: block; + margin-top: 17px; + margin-bottom: 8px; +} + +.mx_ProfileSettings_noAvatarText { + display: block; + margin: 34px auto auto; +} + +.mx_ProfileSettings_avatarOverlayImgContainer { + position: relative; + width: 14px; + height: 14px; + margin: auto; +} + +.mx_ProfileSettings_avatarOverlayImg:before { + background-color: $settings-profile-overlay-placeholder-fg-color; + mask: url("$(res)/img/feather-icons/upload.svg"); + mask-repeat: no-repeat; + mask-size: 14px; + mask-position: center; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.mx_ProfileSettings_avatar:hover .mx_ProfileSettings_avatarOverlayImg:before { + background-color: $settings-profile-overlay-fg-color !important; +} + +.mx_ProfileSettings_avatarUpload { + display: none; +} diff --git a/res/css/views/settings/tabs/_GeneralRoomSettingsTab.scss b/res/css/views/settings/tabs/_GeneralRoomSettingsTab.scss new file mode 100644 index 0000000000..91d7ed2c7d --- /dev/null +++ b/res/css/views/settings/tabs/_GeneralRoomSettingsTab.scss @@ -0,0 +1,23 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_GeneralRoomSettingsTab_profileSection { + margin-top: 10px; +} + +.mx_GeneralRoomSettingsTab .mx_AliasSettings .mx_Field select { + width: 100%; +} diff --git a/res/css/views/settings/tabs/_GeneralUserSettingsTab.scss b/res/css/views/settings/tabs/_GeneralUserSettingsTab.scss new file mode 100644 index 0000000000..bec013674a --- /dev/null +++ b/res/css/views/settings/tabs/_GeneralUserSettingsTab.scss @@ -0,0 +1,46 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_GeneralUserSettingsTab_changePassword, +.mx_GeneralUserSettingsTab_themeSection { + display: block; +} + +.mx_GeneralUserSettingsTab_changePassword .mx_Field, +.mx_GeneralUserSettingsTab_themeSection .mx_Field { + display: block; + margin-right: 100px; // Align with the other fields on the page +} + +.mx_GeneralUserSettingsTab_changePassword .mx_Field input { + display: block; + width: calc(100% - 20px); // subtract 10px padding on left and right +} + +.mx_GeneralUserSettingsTab_changePassword .mx_Field:first-child { + margin-top: 0; +} + +.mx_GeneralUserSettingsTab_themeSection .mx_Field select { + display: block; + width: 100%; +} + +.mx_GeneralUserSettingsTab_accountSection > .mx_EmailAddresses, +.mx_GeneralUserSettingsTab_accountSection > .mx_PhoneNumbers, +.mx_GeneralUserSettingsTab_languageInput { + margin-right: 100px; // Align with the other fields on the page +} \ No newline at end of file diff --git a/res/css/views/settings/tabs/_HelpSettingsTab.scss b/res/css/views/settings/tabs/_HelpSettingsTab.scss new file mode 100644 index 0000000000..249f06ca95 --- /dev/null +++ b/res/css/views/settings/tabs/_HelpSettingsTab.scss @@ -0,0 +1,24 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_HelpSettingsTab_debugButton { + margin-bottom: 5px; + margin-top: 5px; +} + +.mx_HelpSettingsTab span.mx_AccessibleButton { + word-break: break-word; +} \ No newline at end of file diff --git a/res/css/views/settings/tabs/_NotificationSettingsTab.scss b/res/css/views/settings/tabs/_NotificationSettingsTab.scss new file mode 100644 index 0000000000..8fdb688496 --- /dev/null +++ b/res/css/views/settings/tabs/_NotificationSettingsTab.scss @@ -0,0 +1,19 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_NotificationSettingsTab .mx_SettingsTab_heading { + margin-bottom: 10px; // Give some spacing between the title and the first elements +} \ No newline at end of file diff --git a/res/css/views/settings/tabs/_PreferencesSettingsTab.scss b/res/css/views/settings/tabs/_PreferencesSettingsTab.scss new file mode 100644 index 0000000000..b59b69e63b --- /dev/null +++ b/res/css/views/settings/tabs/_PreferencesSettingsTab.scss @@ -0,0 +1,27 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_PreferencesSettingsTab .mx_Field { + margin-right: 100px; // Align with the rest of the controls +} + +.mx_PreferencesSettingsTab .mx_Field input { + display: block; + + // Subtract 10px padding on left and right + // This is to keep the input aligned with the rest of the tab's controls. + width: calc(100% - 20px); +} diff --git a/res/css/views/settings/tabs/_RolesRoomSettingsTab.scss b/res/css/views/settings/tabs/_RolesRoomSettingsTab.scss new file mode 100644 index 0000000000..8bfc792dc3 --- /dev/null +++ b/res/css/views/settings/tabs/_RolesRoomSettingsTab.scss @@ -0,0 +1,24 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_RolesRoomSettingsTab ul { + margin-bottom: 0; +} + +.mx_RolesRoomSettingsTab_unbanBtn { + margin-right: 10px; + margin-bottom: 5px; +} \ No newline at end of file diff --git a/res/css/views/settings/tabs/_SecurityRoomSettingsTab.scss b/res/css/views/settings/tabs/_SecurityRoomSettingsTab.scss new file mode 100644 index 0000000000..dfd046e672 --- /dev/null +++ b/res/css/views/settings/tabs/_SecurityRoomSettingsTab.scss @@ -0,0 +1,34 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_SecurityRoomSettingsTab label { + display: block; +} + +.mx_SecurityRoomSettingsTab_warning { + display: block; + + img { + vertical-align: middle; + margin-right: 5px; + margin-left: 3px; + margin-bottom: 5px; + } +} + +.mx_SecurityRoomSettingsTab_encryptionSection { + margin-bottom: 25px; +} \ No newline at end of file diff --git a/res/css/views/settings/tabs/_SecuritySettingsTab.scss b/res/css/views/settings/tabs/_SecuritySettingsTab.scss new file mode 100644 index 0000000000..ba357f16c3 --- /dev/null +++ b/res/css/views/settings/tabs/_SecuritySettingsTab.scss @@ -0,0 +1,53 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_SecuritySettingsTab .mx_DevicesPanel { + // Normally the panel is 880px, however this can easily overflow the container. + // TODO: Fix the table to not be squishy + width: auto; + max-width: 880px; +} + +.mx_SecuritySettingsTab_deviceInfo { + display: table; + padding-left: 0; +} + +.mx_SecuritySettingsTab_deviceInfo > li { + display: table-row; +} + +.mx_SecuritySettingsTab_deviceInfo > li > label, +.mx_SecuritySettingsTab_deviceInfo > li > span { + display: table-cell; + padding-right: 1em; +} + +.mx_SecuritySettingsTab_importExportButtons .mx_AccessibleButton { + margin-right: 10px; +} + +.mx_SecuritySettingsTab_importExportButtons { + margin-bottom: 15px; +} + +.mx_SecuritySettingsTab_ignoredUser { + margin-bottom: 5px; +} + +.mx_SecuritySettingsTab_ignoredUser .mx_AccessibleButton { + margin-right: 10px; +} \ No newline at end of file diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss new file mode 100644 index 0000000000..a899aec0fa --- /dev/null +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -0,0 +1,69 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_SettingsTab_heading { + font-size: 20px; + font-weight: 600; + color: $primary-fg-color; +} + +.mx_SettingsTab_subheading { + font-size: 14px; + display: block; + font-family: $font-family; + font-weight: 600; + color: $primary-fg-color; + margin-bottom: 10px; + margin-top: 12px; +} + +.mx_SettingsTab_subsectionText { + color: $settings-subsection-fg-color; + font-size: 12px; + padding-bottom: 12px; + display: block; + margin: 0 100px 0 0; // Align with the rest of the view +} + +.mx_SettingsTab_section .mx_SettingsFlag { + margin-right: 100px; + height: 25px; + margin-bottom: 10px; +} + +.mx_SettingsTab_section .mx_SettingsFlag .mx_SettingsFlag_label { + vertical-align: bottom; + display: inline-block; + font-size: 12px; + color: $primary-fg-color; + max-width: calc(100% - 48px); // Force word wrap instead of colliding with the switch +} + +.mx_SettingsTab_section .mx_SettingsFlag .mx_ToggleSwitch { + float: right; +} + +.mx_SettingsTab_linkBtn { + cursor: pointer; + color: $accent-color; + word-break: break-all; +} + +.mx_SettingsTab .mx_SettingsTab_subheading:nth-child(n + 2) { + // These views have a lot of the same repetitive information on it, so + // give them more visual distinction between the sections. + margin-top: 30px; +} diff --git a/res/css/views/settings/tabs/_VoiceSettingsTab.scss b/res/css/views/settings/tabs/_VoiceSettingsTab.scss new file mode 100644 index 0000000000..5ddd57b0e2 --- /dev/null +++ b/res/css/views/settings/tabs/_VoiceSettingsTab.scss @@ -0,0 +1,28 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_VoiceSettingsTab .mx_Field select { + width: 100%; + max-width: 100%; +} + +.mx_VoiceSettingsTab .mx_Field { + margin-right: 100px; // align with the rest of the fields +} + +.mx_VoiceSettingsTab_missingMediaPermissions { + margin-bottom: 15px; +} diff --git a/res/fonts/Nunito/XRXQ3I6Li01BKofIMN44Y9vKUTo.ttf b/res/fonts/Nunito/XRXQ3I6Li01BKofIMN44Y9vKUTo.ttf new file mode 100644 index 0000000000..4387fb67c4 Binary files /dev/null and b/res/fonts/Nunito/XRXQ3I6Li01BKofIMN44Y9vKUTo.ttf differ diff --git a/res/fonts/Nunito/XRXQ3I6Li01BKofIMN5cYtvKUTo.ttf b/res/fonts/Nunito/XRXQ3I6Li01BKofIMN5cYtvKUTo.ttf new file mode 100644 index 0000000000..68fb3ff5cb Binary files /dev/null and b/res/fonts/Nunito/XRXQ3I6Li01BKofIMN5cYtvKUTo.ttf differ diff --git a/res/fonts/Nunito/XRXV3I6Li01BKofINeaE.ttf b/res/fonts/Nunito/XRXV3I6Li01BKofINeaE.ttf new file mode 100644 index 0000000000..c40e599260 Binary files /dev/null and b/res/fonts/Nunito/XRXV3I6Li01BKofINeaE.ttf differ diff --git a/res/fonts/Nunito/XRXW3I6Li01BKofA6sKUYevN.ttf b/res/fonts/Nunito/XRXW3I6Li01BKofA6sKUYevN.ttf new file mode 100644 index 0000000000..0c4fd17dfa Binary files /dev/null and b/res/fonts/Nunito/XRXW3I6Li01BKofA6sKUYevN.ttf differ diff --git a/res/fonts/Nunito/XRXW3I6Li01BKofAjsOUYevN.ttf b/res/fonts/Nunito/XRXW3I6Li01BKofAjsOUYevN.ttf new file mode 100644 index 0000000000..339d59ac00 Binary files /dev/null and b/res/fonts/Nunito/XRXW3I6Li01BKofAjsOUYevN.ttf differ diff --git a/res/fonts/Nunito/XRXX3I6Li01BKofIMNaDRss.ttf b/res/fonts/Nunito/XRXX3I6Li01BKofIMNaDRss.ttf new file mode 100644 index 0000000000..b5fcd891af Binary files /dev/null and b/res/fonts/Nunito/XRXX3I6Li01BKofIMNaDRss.ttf differ diff --git a/res/img/feather-icons/cancel.svg b/res/img/feather-icons/cancel.svg new file mode 100644 index 0000000000..6b734e4053 --- /dev/null +++ b/res/img/feather-icons/cancel.svg @@ -0,0 +1,10 @@ + + + + Slice 1 + Created with Sketch. + + + + + \ No newline at end of file diff --git a/res/img/feather-icons/dropdown-arrow.svg b/res/img/feather-icons/dropdown-arrow.svg new file mode 100644 index 0000000000..a1d46fa61a --- /dev/null +++ b/res/img/feather-icons/dropdown-arrow.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-icons/face.svg b/res/img/feather-icons/face.svg new file mode 100644 index 0000000000..0a359b2dea --- /dev/null +++ b/res/img/feather-icons/face.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/res/img/feather-icons/files.svg b/res/img/feather-icons/files.svg new file mode 100644 index 0000000000..c66d9ad121 --- /dev/null +++ b/res/img/feather-icons/files.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/res/img/feather-icons/flag.svg b/res/img/feather-icons/flag.svg new file mode 100644 index 0000000000..983c02762b --- /dev/null +++ b/res/img/feather-icons/flag.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/feather-icons/flair.svg b/res/img/feather-icons/flair.svg new file mode 100644 index 0000000000..ce3a5ed6ad --- /dev/null +++ b/res/img/feather-icons/flair.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-icons/globe.svg b/res/img/feather-icons/globe.svg new file mode 100644 index 0000000000..8af7dc41dc --- /dev/null +++ b/res/img/feather-icons/globe.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/res/img/feather-icons/grid.svg b/res/img/feather-icons/grid.svg new file mode 100644 index 0000000000..e6912b0cc7 --- /dev/null +++ b/res/img/feather-icons/grid.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/img/feather-icons/help-circle.svg b/res/img/feather-icons/help-circle.svg new file mode 100644 index 0000000000..7ecb0a8f35 --- /dev/null +++ b/res/img/feather-icons/help-circle.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-icons/life-buoy.svg b/res/img/feather-icons/life-buoy.svg new file mode 100644 index 0000000000..20bd0f0b5d --- /dev/null +++ b/res/img/feather-icons/life-buoy.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/img/feather-icons/lock.svg b/res/img/feather-icons/lock.svg new file mode 100644 index 0000000000..1330903b30 --- /dev/null +++ b/res/img/feather-icons/lock.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-icons/matrix-org-bw-logo.svg b/res/img/feather-icons/matrix-org-bw-logo.svg new file mode 100644 index 0000000000..39a7b173e8 --- /dev/null +++ b/res/img/feather-icons/matrix-org-bw-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/img/feather-icons/modular-bw-logo.svg b/res/img/feather-icons/modular-bw-logo.svg new file mode 100644 index 0000000000..924a587805 --- /dev/null +++ b/res/img/feather-icons/modular-bw-logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/img/feather-icons/notifications.svg b/res/img/feather-icons/notifications.svg new file mode 100644 index 0000000000..2fe85e810c --- /dev/null +++ b/res/img/feather-icons/notifications.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/img/feather-icons/paperclip.svg b/res/img/feather-icons/paperclip.svg new file mode 100644 index 0000000000..ed2bb88681 --- /dev/null +++ b/res/img/feather-icons/paperclip.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/img/feather-icons/phone.svg b/res/img/feather-icons/phone.svg new file mode 100644 index 0000000000..58b257f113 --- /dev/null +++ b/res/img/feather-icons/phone.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/img/feather-icons/search-input.svg b/res/img/feather-icons/search-input.svg new file mode 100644 index 0000000000..3be5acb32e --- /dev/null +++ b/res/img/feather-icons/search-input.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/res/img/feather-icons/search.svg b/res/img/feather-icons/search.svg new file mode 100644 index 0000000000..8b14246f64 --- /dev/null +++ b/res/img/feather-icons/search.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/res/img/feather-icons/settings.svg b/res/img/feather-icons/settings.svg new file mode 100644 index 0000000000..ea7ce5c55b --- /dev/null +++ b/res/img/feather-icons/settings.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/res/img/feather-icons/share.svg b/res/img/feather-icons/share.svg new file mode 100644 index 0000000000..a012e1b7a5 --- /dev/null +++ b/res/img/feather-icons/share.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/res/img/feather-icons/sign-out.svg b/res/img/feather-icons/sign-out.svg new file mode 100644 index 0000000000..06ab9903ec --- /dev/null +++ b/res/img/feather-icons/sign-out.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/feather-icons/sliders.svg b/res/img/feather-icons/sliders.svg new file mode 100644 index 0000000000..5b5ec8656c --- /dev/null +++ b/res/img/feather-icons/sliders.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/feather-icons/upload.svg b/res/img/feather-icons/upload.svg new file mode 100644 index 0000000000..8ec5d95c2c --- /dev/null +++ b/res/img/feather-icons/upload.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/feather-icons/user-add.svg b/res/img/feather-icons/user-add.svg new file mode 100644 index 0000000000..cbb25934c1 --- /dev/null +++ b/res/img/feather-icons/user-add.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/img/feather-icons/user.svg b/res/img/feather-icons/user.svg new file mode 100644 index 0000000000..a789e580d5 --- /dev/null +++ b/res/img/feather-icons/user.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/res/img/feather-icons/users-sm.svg b/res/img/feather-icons/users-sm.svg new file mode 100644 index 0000000000..6098be38c3 --- /dev/null +++ b/res/img/feather-icons/users-sm.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/res/img/feather-icons/users.svg b/res/img/feather-icons/users.svg new file mode 100644 index 0000000000..b0deac0a9e --- /dev/null +++ b/res/img/feather-icons/users.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/res/img/feather-icons/video.svg b/res/img/feather-icons/video.svg new file mode 100644 index 0000000000..a4c456832f --- /dev/null +++ b/res/img/feather-icons/video.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/res/img/feather-icons/warning-triangle.svg b/res/img/feather-icons/warning-triangle.svg new file mode 100644 index 0000000000..02196cbf43 --- /dev/null +++ b/res/img/feather-icons/warning-triangle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/icon-call.svg b/res/img/icon-call.svg index 0ca5c29e9d..98677e3c70 100644 --- a/res/img/icon-call.svg +++ b/res/img/icon-call.svg @@ -1,8 +1,3 @@ - - - - - - - + + diff --git a/res/img/icon-invite-people.svg b/res/img/icon-invite-people.svg index f13a03ed70..73500ebe06 100644 --- a/res/img/icon-invite-people.svg +++ b/res/img/icon-invite-people.svg @@ -1,24 +1,5 @@ - - - - 9BA71BF4-DC4F-42D2-B2D0-9EAE0F7F8D45 - Created with sketchtool. - - - - - - - - - - - - - - - - - - + + + + diff --git a/res/img/icon-jump-to-bottom.svg b/res/img/icon-jump-to-bottom.svg new file mode 100644 index 0000000000..c4210b4ebe --- /dev/null +++ b/res/img/icon-jump-to-bottom.svg @@ -0,0 +1,32 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/res/img/icon-jump-to-first-unread.svg b/res/img/icon-jump-to-first-unread.svg new file mode 100644 index 0000000000..652ccec20d --- /dev/null +++ b/res/img/icon-jump-to-first-unread.svg @@ -0,0 +1,16 @@ + + + + + diff --git a/res/img/icon_context.svg b/res/img/icon_context.svg new file mode 100644 index 0000000000..600c5bbd1d --- /dev/null +++ b/res/img/icon_context.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/icon_context_copy.svg b/res/img/icon_context_copy.svg new file mode 100644 index 0000000000..1f9c0b01e8 --- /dev/null +++ b/res/img/icon_context_copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/icon_context_edit.svg b/res/img/icon_context_edit.svg new file mode 100644 index 0000000000..6f7f1fd385 --- /dev/null +++ b/res/img/icon_context_edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/icon_context_fave.svg b/res/img/icon_context_fave.svg index da7b14a1f4..5c287787bb 100644 --- a/res/img/icon_context_fave.svg +++ b/res/img/icon_context_fave.svg @@ -1,12 +1,3 @@ - - - - - - - - - - - + + diff --git a/res/img/icon_context_leave.svg b/res/img/icon_context_leave.svg new file mode 100644 index 0000000000..3fdd452a59 --- /dev/null +++ b/res/img/icon_context_leave.svg @@ -0,0 +1,4 @@ + + + + diff --git a/res/img/icon_context_reply.svg b/res/img/icon_context_reply.svg new file mode 100644 index 0000000000..0a85f8e606 --- /dev/null +++ b/res/img/icon_context_reply.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/icons-apps.svg b/res/img/icons-apps.svg index affd8e6408..e2fe49b005 100644 --- a/res/img/icons-apps.svg +++ b/res/img/icons-apps.svg @@ -1,14 +1,12 @@ - - - - - - - - - - - + + + + + + + + + + diff --git a/res/img/icons-checkmark.svg b/res/img/icons-checkmark.svg deleted file mode 100644 index 3c5392003d..0000000000 --- a/res/img/icons-checkmark.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - Tick - Created with Sketch. - - - - - - - - - - - - diff --git a/res/img/icons-close.svg b/res/img/icons-close.svg index 453b51082f..b2dd44fc26 100644 --- a/res/img/icons-close.svg +++ b/res/img/icons-close.svg @@ -1,23 +1,96 @@ - - - - -icons_create_room -Created with sketchtool. - - - - - - - - - - - - - - + + + +image/svg+xmlicons_create_room + +icons_create_room +Created with sketchtool. + + + + + + + + + + + + + + diff --git a/res/img/icons-create-room.svg b/res/img/icons-create-room.svg index 252bd2df3b..78c45563d1 100644 --- a/res/img/icons-create-room.svg +++ b/res/img/icons-create-room.svg @@ -1,18 +1,4 @@ - - - - 0F9BCC43-B3A7-4C9F-8E34-1F38194362C2 - Created with sketchtool. - - - - - - - - - - - - + + + diff --git a/res/img/icons-files.svg b/res/img/icons-files.svg index 97ba4228e3..ea270fbc73 100644 --- a/res/img/icons-files.svg +++ b/res/img/icons-files.svg @@ -1,29 +1,5 @@ - - - - 7C98C075-AB4D-45A3-85F9-CCD46F84DA7F - Created with sketchtool. - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + diff --git a/res/img/icons-groups-nobg.svg b/res/img/icons-groups-nobg.svg new file mode 100644 index 0000000000..a3d223b76d --- /dev/null +++ b/res/img/icons-groups-nobg.svg @@ -0,0 +1,60 @@ + +image/svg+xml + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/img/icons-notifications.svg b/res/img/icons-notifications.svg index 66a49d6c0c..cde30713e1 100644 --- a/res/img/icons-notifications.svg +++ b/res/img/icons-notifications.svg @@ -1,19 +1,3 @@ - - - - 5E723325-BD0B-454D-BE25-638AF09A97AC - Created with sketchtool. - - - - - - - - - - - - - - \ No newline at end of file + + + diff --git a/res/img/icons-people.svg b/res/img/icons-people.svg index 8854506127..f3761c6c5f 100644 --- a/res/img/icons-people.svg +++ b/res/img/icons-people.svg @@ -1,22 +1,3 @@ - - - - 81230A28-D944-4572-B5DB-C03CAA2B1FCA - Created with sketchtool. - - - - - - - - - - - - - - - - + + diff --git a/res/img/icons-room-add.svg b/res/img/icons-room-add.svg index fc0ab750b6..f0b7584df9 100644 --- a/res/img/icons-room-add.svg +++ b/res/img/icons-room-add.svg @@ -1,23 +1,9 @@ - - - - - - - - - - - - - - + + + + + + + + diff --git a/res/img/icons-room-nobg.svg b/res/img/icons-room-nobg.svg new file mode 100644 index 0000000000..8ca7ab272b --- /dev/null +++ b/res/img/icons-room-nobg.svg @@ -0,0 +1,28 @@ + +image/svg+xml + + + + + + + \ No newline at end of file diff --git a/res/img/icons-search-copy.svg b/res/img/icons-search-copy.svg deleted file mode 100644 index b026718b84..0000000000 --- a/res/img/icons-search-copy.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/res/img/icons-search.svg b/res/img/icons-search.svg index d85709e66c..9d3e98106b 100644 --- a/res/img/icons-search.svg +++ b/res/img/icons-search.svg @@ -1,9 +1,15 @@ - - - - - - - - + + + Shape + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/res/img/icons-settings-room.svg b/res/img/icons-settings-room.svg index 117d134c95..421eefdefa 100644 --- a/res/img/icons-settings-room.svg +++ b/res/img/icons-settings-room.svg @@ -1,15 +1,6 @@ - - - - 69011392-CE9D-4404-A85C-A8548C5D850B - Created with sketchtool. - - - - - - - - - + + + + + diff --git a/res/img/icons-share.svg b/res/img/icons-share.svg index b27616d5d5..aac19080f4 100644 --- a/res/img/icons-share.svg +++ b/res/img/icons-share.svg @@ -1,6 +1,6 @@ - + diff --git a/res/img/icons-stickers.svg b/res/img/icons-stickers.svg new file mode 100644 index 0000000000..564ebdac97 --- /dev/null +++ b/res/img/icons-stickers.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/icons-upload.svg b/res/img/icons-upload.svg index b0101e87a0..3aea924478 100644 --- a/res/img/icons-upload.svg +++ b/res/img/icons-upload.svg @@ -1,12 +1,3 @@ - - - - - - - - - - - + + diff --git a/res/img/icons-video.svg b/res/img/icons-video.svg index d367f49609..c61a782cc4 100644 --- a/res/img/icons-video.svg +++ b/res/img/icons-video.svg @@ -1,20 +1,3 @@ - - - - 05D354CE-86A7-4B6F-B9BE-F1CEBBD81B21 - Created with sketchtool. - - - - - - - - - - - - - - + + diff --git a/res/img/maximise.svg b/res/img/maximise.svg index 79c6c0ab8b..981e3796de 100644 --- a/res/img/maximise.svg +++ b/res/img/maximise.svg @@ -1,19 +1,19 @@ - - - -minimise -Created with sketchtool. - - - - - - - - - - - - + + + +minimise +Created with sketchtool. + + + + + + + + + + + + diff --git a/res/img/minimise.svg b/res/img/minimise.svg index 491756b15a..eecf181f61 100644 --- a/res/img/minimise.svg +++ b/res/img/minimise.svg @@ -5,7 +5,7 @@ Created with sketchtool. - + diff --git a/res/img/search.svg b/res/img/search.svg deleted file mode 100644 index bd4cd9200c..0000000000 --- a/res/img/search.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - icons_search - Created with bin/sketchtool. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/topleft-chevron.svg b/res/img/topleft-chevron.svg new file mode 100644 index 0000000000..1cfeaf6352 --- /dev/null +++ b/res/img/topleft-chevron.svg @@ -0,0 +1,86 @@ + + + + + + image/svg+xml + + dropdown + + + + + + dropdown + Created with Sketch. + + + + + + + + + + + + diff --git a/res/img/typing-indicator-2x.gif b/res/img/typing-indicator-2x.gif new file mode 100644 index 0000000000..86e34c7555 Binary files /dev/null and b/res/img/typing-indicator-2x.gif differ diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 5dbc00af4e..ee5e1cf5d6 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -1,6 +1,6 @@ // typical text (dark-on-white in light skin) -$primary-fg-color: #dddddd; +$primary-fg-color: #212121; $primary-bg-color: #2d2d2d; // used for focusing form controls @@ -12,6 +12,7 @@ $light-fg-color: #747474; // button UI (white-on-green in light skin) $accent-fg-color: $primary-bg-color; $accent-color: #76CFA6; +$accent-color-alt: $accent-color; $accent-color-50pct: #76CFA67F; $selection-fg-color: $primary-fg-color; @@ -63,19 +64,27 @@ $primary-hairline-color: #474747; // used for the border of input text fields $input-border-color: #3a3a3a; +$input-darker-bg-color: #c1c9d6; +$input-darker-fg-color: #9fa9ba; +$button-bg-color: #7ac9a1; +$button-fg-color: white; // apart from login forms, which have stronger border $strong-input-border-color: #656565; // used for UserSettings EditableText $input-underline-color: $primary-fg-color; $input-fg-color: $primary-fg-color; - +// scrollbars +$scrollbar-thumb-color: rgba(255, 255, 255, 0.2); +$scrollbar-track-color: transparent; // context menus $menu-border-color: rgba(187, 187, 187, 0.5); $menu-bg-color: #373737; +$menu-selected-color: #f5f8fa; $avatar-initial-color: #2d2d2d; $avatar-bg-color: #ffffff; +$menu-selected-color: #f5f8fa; $h3-color: $primary-fg-color; @@ -108,6 +117,15 @@ $roomtile-name-color: rgba(186, 186, 186, 0.8); $roomtile-selected-bg-color: #333; $roomtile-focused-bg-color: rgba(255, 255, 255, 0.2); +$username-variant1-color: #1e7ddc; +$username-variant2-color: #a756a8; +$username-variant3-color: #7ac9a1; +$username-variant4-color: #f2809d; +$username-variant5-color: #ffc666; +$username-variant6-color: #76ddd7; +$username-variant7-color: #45529b; +$username-variant8-color: #bfd251; + $roomsublist-background: rgba(0, 0, 0, 0.2); $roomsublist-label-fg-color: $h3-color; $roomsublist-label-bg-color: $tertiary-accent-color; @@ -133,8 +151,8 @@ $event-redacted-border-color: #000000; // event timestamp $event-timestamp-color: #acacac; -$edit-button-url: "../../img/icon_context_message_dark.svg"; -$copy-button-url: "../../img/icon_copy_message_dark.svg"; +$edit-button-url: "$(res)/img/icon_context_message_dark.svg"; +$copy-button-url: "$(res)/img/icon_copy_message_dark.svg"; // e2e $e2e-verified-color: #76cfa5; // N.B. *NOT* the same as $accent-color @@ -148,6 +166,7 @@ $lightbox-border-color: #ffffff; $imagebody-giflabel: rgba(1, 1, 1, 0.7); $imagebody-giflabel-border: rgba(1, 1, 1, 0.2); +$imagebody-giflabel-color: rgba(0, 0, 0, 1); // unused? $progressbar-color: #000; diff --git a/res/themes/dark/css/dark.scss b/res/themes/dark/css/dark.scss index b69f096db7..a7d18fa1a6 100644 --- a/res/themes/dark/css/dark.scss +++ b/res/themes/dark/css/dark.scss @@ -1,4 +1,5 @@ +@import "../../light/css/_paths.scss"; +@import "../../light/css/_fonts.scss"; @import "../../light/css/_base.scss"; @import "_dark.scss"; @import "../../../../res/css/_components.scss"; - diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss new file mode 100644 index 0000000000..f976180144 --- /dev/null +++ b/res/themes/dharma/css/_dharma.scss @@ -0,0 +1,388 @@ +// XXX: check this? +/* Nunito lacks combining diacritics, so these will fall through + to the next font. Helevetica's diacritics however do not combine + nicely with Open Sans (on OSX, at least) and result in a huge + horizontal mess. Arial empirically gets it right, hence prioritising + Arial here. */ +$font-family: 'Nunito', Arial, Helvetica, Sans-Serif; + +// typical text (dark-on-white in light skin) +$primary-fg-color: #454545; +$primary-bg-color: #ffffff; + +// used for dialog box text +$light-fg-color: #747474; + +// used for focusing form controls +$focus-bg-color: #dddddd; + +// button UI (white-on-green in light skin) +$accent-fg-color: #ffffff; +$accent-color: #7ac9a1; +$accent-color-50pct: #92caad; +$accent-color-alt: #238CF5; + +$selection-fg-color: $primary-bg-color; + +$focus-brightness: 105%; + +// red warning colour +$warning-color: #f56679; +// background colour for warnings +$warning-bg-color: #DF2A8B; +$info-bg-color: #2A9EDF; +$mention-user-pill-bg-color: $warning-color; +$other-user-pill-bg-color: rgba(0, 0, 0, 0.1); + +// pinned events indicator +$pinned-unread-color: #ff0064; // $warning-color +$pinned-color: #888; + +// informational plinth +$info-plinth-bg-color: #f7f7f7; +$info-plinth-fg-color: #888; + +$preview-bar-bg-color: #f7f7f7; + +// left-panel style muted accent color +$secondary-accent-color: #f2f5f8; +$tertiary-accent-color: #d3efe1; + +$tagpanel-bg-color: #2e3649; + +// used by RoomDirectory permissions +$plinth-bg-color: $secondary-accent-color; + +// used by RoomDropTarget +$droptarget-bg-color: rgba(255,255,255,0.5); + +// used by AddressSelector +$selected-color: $secondary-accent-color; + +// selected for hoverover & selected event tiles +$event-selected-color: #f7f7f7; + +// used for the hairline dividers in RoomView +$primary-hairline-color: #e5e5e5; + +// used for the border of input text fields +$input-border-color: #e7e7e7; +$input-darker-bg-color: rgba(193, 201, 214, 0.29); +$input-darker-fg-color: #9fa9ba; +$input-lighter-bg-color: #f2f5f8; +$input-lighter-fg-color: $input-darker-fg-color; +$input-focused-border-color: #238cf5; +$input-valid-border-color: #7ac9a1; + +$field-focused-label-bg-color: #ffffff; + +$button-bg-color: #7ac9a1; +$button-fg-color: white; + +// apart from login forms, which have stronger border +$strong-input-border-color: #c7c7c7; + +// used for UserSettings EditableText +$input-underline-color: rgba(151, 151, 151, 0.5); +$input-fg-color: rgba(74, 74, 74, 0.9); +// scrollbars +$scrollbar-thumb-color: rgba(0, 0, 0, 0.2); +$scrollbar-track-color: transparent; +// context menus +$menu-border-color: #ebedf8; +$menu-bg-color: #fff; +$menu-selected-color: #f5f8fa; + +$avatar-initial-color: #ffffff; +$avatar-bg-color: #ffffff; + +$h3-color: #3d3b39; + +$dialog-title-fg-color: #454545; +$dialog-backdrop-color: rgba(46, 48, 51, 0.38); +$dialog-shadow-color: rgba(0, 0, 0, 0.48); +$dialog-close-fg-color: #9fa9ba; + +$dialog-background-bg-color: #e9e9e9; +$lightbox-background-bg-color: #000; + +$imagebody-giflabel: rgba(0, 0, 0, 0.7); +$imagebody-giflabel-border: rgba(0, 0, 0, 0.2); +$imagebody-giflabel-color: rgba(255, 255, 255, 1); + +$greyed-fg-color: #888; + +$neutral-badge-color: #dbdbdb; + +$preview-widget-bar-color: #ddd; +$preview-widget-fg-color: $greyed-fg-color; + +$blockquote-bar-color: #ddd; +$blockquote-fg-color: #777; + +$settings-grey-fg-color: #a2a2a2; +$settings-profile-placeholder-bg-color: #e7e7e7; +$settings-profile-overlay-bg-color: #000; +$settings-profile-overlay-placeholder-bg-color: transparent; +$settings-profile-overlay-fg-color: #fff; +$settings-profile-overlay-placeholder-fg-color: #454545; +$settings-subsection-fg-color: #61708b; + +$voip-decline-color: #f48080; +$voip-accept-color: #80f480; + +$rte-bg-color: #e9e9e9; +$rte-code-bg-color: rgba(0, 0, 0, 0.04); +$rte-room-pill-color: #aaa; +$rte-group-pill-color: #aaa; + +$topleftmenu-color: #212121; +$roomheader-color: #45474a; +$roomheader-addroom-color: #91A1C0; +$roomtopic-color: #9fa9ba; +$eventtile-meta-color: $roomtopic-color; + +// ******************** + +$roomtile-name-color: #61708b; +$roomtile-selected-color: #212121; +$roomtile-notified-color: #212121; +$roomtile-selected-bg-color: #fff; +$roomtile-focused-bg-color: #fff; + +$username-variant1-color: #1e7ddc; +$username-variant2-color: #a756a8; +$username-variant3-color: #7ac9a1; +$username-variant4-color: #f2809d; +$username-variant5-color: #ffc666; +$username-variant6-color: #76ddd7; +$username-variant7-color: #45529b; +$username-variant8-color: #bfd251; + +$roomtile-transparent-focused-color: rgba(0, 0, 0, 0.1); + +$roomsublist-background: $secondary-accent-color; +$roomsublist-label-fg-color: $roomtile-name-color; +$roomsublist-label-bg-color: $tertiary-accent-color; +$roomsublist-chevron-color: $accent-color; + +$panel-divider-color: #dee1f3; + +// ******************** + +$widget-menu-bar-bg-color: $tertiary-accent-color; + +// ******************** + +// event tile lifecycle +$event-encrypting-color: #abddbc; +$event-sending-color: #ddd; +$event-notsent-color: #f44; + +// event redaction +$event-redacted-fg-color: #e2e2e2; +$event-redacted-border-color: #cccccc; + +// event timestamp +$event-timestamp-color: #acacac; + +$edit-button-url: "$(res)/img/icon_context_message.svg"; +$copy-button-url: "$(res)/img/icon_copy_message.svg"; + +// e2e +$e2e-verified-color: #76cfa5; // N.B. *NOT* the same as $accent-color +$e2e-unverified-color: #e8bf37; +$e2e-warning-color: #ba6363; + +/*** ImageView ***/ +$lightbox-bg-color: #454545; +$lightbox-fg-color: #ffffff; +$lightbox-border-color: #ffffff; + +// Tabbed views +$tab-label-fg-color: #45474a; +$tab-label-active-fg-color: #ffffff; +$tab-label-bg-color: transparent; +$tab-label-active-bg-color: #7ac9a1; +$tab-label-icon-bg-color: #454545; +$tab-label-active-icon-bg-color: #ffffff; + +// Buttons +$button-primary-fg-color: #ffffff; +$button-primary-bg-color: #7ac9a1; +$button-primary-disabled-fg-color: #ffffff; +$button-primary-disabled-bg-color: #bce4d0; +$button-danger-fg-color: #ffffff; +$button-danger-bg-color: #f56679; +$button-danger-disabled-fg-color: #ffffff; +$button-danger-disabled-bg-color: #f5b6bb; // TODO: Verify color + +// Toggle switch +$togglesw-off-color: #c1c9d6; +$togglesw-on-color: #7ac9a1; +$togglesw-ball-color: #fff; + +// unused? +$progressbar-color: #000; + +$room-warning-bg-color: #fff8e3; + +$memberstatus-placeholder-color: $roomtile-name-color; + +$authpage-bg-color: #2e3649; +$authpage-modal-bg-color: rgba(255, 255, 255, 0.59); +$authpage-body-bg-color: #ffffff; +$authpage-lang-color: #4e5054; +$authpage-body-color: #61708b; + +/*** form elements ***/ + +// .mx_textinput is a container for a text input +// + some other controls like buttons, ... +// it has the appearance of a text box so the controls +// appear to be part of the input + +.mx_Dialog, .mx_MatrixChat { + + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=text], + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=search], + .mx_textinput { + display: block; + box-sizing: border-box; + background-color: transparent; + color: $input-darker-fg-color; + border-radius: 4px; + border: 1px solid #c1c1c1; + // these things should probably not be defined + // globally + margin: 9px; + flex: 0 0 auto; + } + + .mx_textinput { + display: flex; + align-items: center; + + > input[type=text], + > input[type=search] { + border: none; + flex: 1; + color: $primary-fg-color; + }, + input::placeholder { + color: $roomsublist-label-fg-color; + } + } +} + +input[type=text], +input[type=search], +input[type=password] { + padding: 9px; + font-family: $font-family; + font-size: 14px; + font-weight: 600; + min-width: 0; +} + +/*** panels ***/ +.dark-panel { + background-color: $secondary-accent-color; +} + +.dark-panel { + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=text], + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=search], + .mx_textinput { + color: $input-darker-fg-color; + background-color: $input-darker-bg-color; + border: none; + } +} + +.light-panel { + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=text], + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=search], + .mx_textinput { + color: $input-lighter-fg-color; + background-color: $input-lighter-bg-color; + border: none; + } +} + +input[type=text].mx_textinput_icon, +input[type=search].mx_textinput_icon { + padding-left: 36px; + background-repeat: no-repeat; + background-position: 10px center; +} + + +// FIXME THEME - Tint by CSS rather than referencing a duplicate asset +input[type=text].mx_textinput_icon.mx_textinput_search, +input[type=search].mx_textinput_icon.mx_textinput_search { + background-image: url('$(res)/img/feather-icons/search-input.svg'); +} + +// dont search UI as not all browsers support it, +// we implement it ourselves where needed instead +input[type=search]::-webkit-search-decoration, +input[type=search]::-webkit-search-cancel-button, +input[type=search]::-webkit-search-results-button, +input[type=search]::-webkit-search-results-decoration { + display: none; +} + +.input[type=text]::-webkit-input-placeholder, +.input[type=text]::-moz-placeholder, +.input[type=search]::-webkit-input-placeholder, +.input[type=search]::-moz-placeholder { + color: #a5aab2; +} + +// Override Firefox's UA style so we get a consistent look across browsers +input::placeholder, +textarea::placeholder { + opacity: initial; +} + +// ***** Mixins! ***** + +@define-mixin mx_DialogButton { + /* align images in buttons (eg spinners) */ + vertical-align: middle; + border: 0px; + border-radius: 4px; + font-family: $font-family; + font-size: 14px; + color: $button-fg-color; + background-color: $button-bg-color; + width: auto; + padding: 7px; + padding-left: 1.5em; + padding-right: 1.5em; + cursor: pointer; + display: inline-block; + outline: none; +} + +@define-mixin mx_DialogButton_hover { +} + +@define-mixin mx_DialogButton_danger { + background-color: $accent-color; +} + +@define-mixin mx_DialogButton_small { + @mixin mx_DialogButton; + font-size: 15px; + padding: 0px 1.5em 0px 1.5em; +} + +@define-mixin mx_DialogButton_secondary { + // flip colours for the secondary ones + font-weight: 600; + border: 1px solid $accent-color ! important; + color: $accent-color; + background-color: $accent-fg-color; +} diff --git a/res/themes/dharma/css/_fonts.scss b/res/themes/dharma/css/_fonts.scss new file mode 100644 index 0000000000..93fa9afbfa --- /dev/null +++ b/res/themes/dharma/css/_fonts.scss @@ -0,0 +1,64 @@ +/* + * Nunito. + * Includes extended Latin and Vietnamese character sets + * Current URLs are v9, derived from the contents of + * https://fonts.googleapis.com/css?family=Nunito:400,400i,600,600i,700,700i&subset=latin-ext,vietnamese + */ + +/* the 'src' links are relative to the bundle.css, which is in a subdirectory. + */ +@font-face { + font-family: 'Nunito'; + font-style: italic; + font-weight: 400; + src: url('$(res)/fonts/Nunito/XRXX3I6Li01BKofIMNaDRss.ttf') format('truetype'); +} +@font-face { + font-family: 'Nunito'; + font-style: italic; + font-weight: 600; + src: url('$(res)/fonts/Nunito/XRXQ3I6Li01BKofIMN5cYtvKUTo.ttf') format('truetype'); +} +@font-face { + font-family: 'Nunito'; + font-style: italic; + font-weight: 700; + src: url('$(res)/fonts/Nunito/XRXQ3I6Li01BKofIMN44Y9vKUTo.ttf') format('truetype'); +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 400; + src: url('$(res)/fonts/Nunito/XRXV3I6Li01BKofINeaE.ttf') format('truetype'); +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 600; + src: url('$(res)/fonts/Nunito/XRXW3I6Li01BKofA6sKUYevN.ttf') format('truetype'); +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 700; + src: url('$(res)/fonts/Nunito/XRXW3I6Li01BKofAjsOUYevN.ttf') format('truetype'); +} + +/* + * Fira Mono + * Used for monospace copy, i.e. code + */ + +@font-face { + font-family: 'Fira Mono'; + src: url('$(res)/fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'Fira Mono'; + src: url('$(res)/fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} diff --git a/res/themes/dharma/css/dharma.scss b/res/themes/dharma/css/dharma.scss new file mode 100644 index 0000000000..24dc0ce18d --- /dev/null +++ b/res/themes/dharma/css/dharma.scss @@ -0,0 +1,4 @@ +@import "../../light/css/_paths.scss"; +@import "_fonts.scss"; +@import "_dharma.scss"; +@import "../../../../res/css/_components.scss"; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index c275b94fb5..998325e1b7 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -18,6 +18,7 @@ $focus-bg-color: #dddddd; // button UI (white-on-green in light skin) $accent-fg-color: #ffffff; $accent-color: #76CFA6; +$accent-color-alt: $accent-color; $accent-color-50pct: #76CFA67F; $selection-fg-color: $primary-bg-color; @@ -46,6 +47,8 @@ $preview-bar-bg-color: #f7f7f7; $secondary-accent-color: #eaf5f0; $tertiary-accent-color: #d3efe1; +$tagpanel-bg-color: $tertiary-accent-color; + // used by RoomDirectory permissions $plinth-bg-color: $secondary-accent-color; @@ -63,23 +66,40 @@ $primary-hairline-color: #e5e5e5; // used for the border of input text fields $input-border-color: #f0f0f0; +$input-border-dark-color: #b8b8b8; +$input-darker-bg-color: #c1c9d6; +$input-darker-fg-color: #9fa9ba; +$button-bg-color: #7ac9a1; +$button-fg-color: white; // apart from login forms, which have stronger border $strong-input-border-color: #c7c7c7; +$input-focused-border-color: #238cf5; +$input-valid-border-color: #7ac9a1; + +$field-focused-label-bg-color: #ffffff; // used for UserSettings EditableText $input-underline-color: rgba(151, 151, 151, 0.5); $input-fg-color: rgba(74, 74, 74, 0.9); - +// scrollbars +$scrollbar-thumb-color: rgba(0, 0, 0, 0.2); +$scrollbar-track-color: transparent; // context menus $menu-border-color: rgba(187, 187, 187, 0.5); $menu-bg-color: #f6f6f6; +$menu-selected-color: #f5f8fa; $avatar-initial-color: #ffffff; $avatar-bg-color: #ffffff; $h3-color: #3d3b39; +$dialog-title-fg-color: #454545; +$dialog-backdrop-color: rgba(46, 48, 51, 0.38); +$dialog-shadow-color: rgba(0, 0, 0, 0.48); +$dialog-close-fg-color: #9fa9ba; + $dialog-background-bg-color: #e9e9e9; $lightbox-background-bg-color: #000; @@ -94,6 +114,12 @@ $blockquote-bar-color: #ddd; $blockquote-fg-color: #777; $settings-grey-fg-color: #a2a2a2; +$settings-profile-placeholder-bg-color: #e7e7e7; +$settings-profile-overlay-bg-color: #000; +$settings-profile-overlay-placeholder-bg-color: transparent; +$settings-profile-overlay-fg-color: #fff; +$settings-profile-overlay-placeholder-fg-color: #454545; +$settings-subsection-fg-color: #61708b; $voip-decline-color: #f48080; $voip-accept-color: #80f480; @@ -103,12 +129,28 @@ $rte-code-bg-color: rgba(0, 0, 0, 0.04); $rte-room-pill-color: #aaa; $rte-group-pill-color: #aaa; +$topleftmenu-color: $primary-fg-color; +$roomheader-color: $primary-fg-color; +$roomheader-addroom-color: $primary-bg-color; +$roomtopic-color: $settings-grey-fg-color; +$eventtile-meta-color: $roomtopic-color; // ******************** $roomtile-name-color: rgba(69, 69, 69, 0.8); +$roomtile-selected-color: $roomtile-name-color; +$roomtile-notified-color: $roomtile-name-color; $roomtile-selected-bg-color: rgba(255, 255, 255, 0.8); $roomtile-focused-bg-color: rgba(255, 255, 255, 0.9); +$username-variant1-color: #1e7ddc; +$username-variant2-color: #a756a8; +$username-variant3-color: #7ac9a1; +$username-variant4-color: #f2809d; +$username-variant5-color: #ffc666; +$username-variant6-color: #76ddd7; +$username-variant7-color: #45529b; +$username-variant8-color: #bfd251; + $roomtile-transparent-focused-color: rgba(0, 0, 0, 0.1); $roomsublist-background: rgba(0, 0, 0, 0.05); @@ -136,8 +178,8 @@ $event-redacted-border-color: #cccccc; // event timestamp $event-timestamp-color: #acacac; -$edit-button-url: "../../img/icon_context_message.svg"; -$copy-button-url: "../../img/icon_copy_message.svg"; +$edit-button-url: "$(res)/img/icon_context_message.svg"; +$copy-button-url: "$(res)/img/icon_copy_message.svg"; // e2e $e2e-verified-color: #76cfa5; // N.B. *NOT* the same as $accent-color @@ -151,12 +193,44 @@ $lightbox-border-color: #ffffff; $imagebody-giflabel: rgba(0, 0, 0, 0.7); $imagebody-giflabel-border: rgba(0, 0, 0, 0.2); +$imagebody-giflabel-color: rgba(255, 255, 255, 1); + +// Tabbed views +$tab-label-fg-color: #45474a; +$tab-label-active-fg-color: #ffffff; +$tab-label-bg-color: transparent; +$tab-label-active-bg-color: #7ac9a1; +$tab-label-icon-bg-color: #454545; +$tab-label-active-icon-bg-color: #ffffff; + +// Buttons +$button-primary-fg-color: #ffffff; +$button-primary-bg-color: #7ac9a1; +$button-primary-disabled-fg-color: #ffffff; +$button-primary-disabled-bg-color: #bce4d0; +$button-danger-fg-color: #ffffff; +$button-danger-bg-color: #f56679; +$button-danger-disabled-fg-color: #ffffff; +$button-danger-disabled-bg-color: #f5b6bb; // TODO: Verify color + +// Toggle switch +$togglesw-off-color: #c1c9d6; +$togglesw-on-color: #7ac9a1; +$togglesw-ball-color: #fff; // unused? $progressbar-color: #000; $room-warning-bg-color: #fff8e3; +$memberstatus-placeholder-color: $roomtile-name-color; + +$authpage-bg-color: #2e3649; +$authpage-modal-bg-color: rgba(255, 255, 255, 0.59); +$authpage-body-bg-color: #ffffff; +$authpage-lang-color: #4e5054; +$authpage-body-color: #61708b; + // ***** Mixins! ***** @define-mixin mx_DialogButton { diff --git a/res/css/_fonts.scss b/res/themes/light/css/_fonts.scss similarity index 62% rename from res/css/_fonts.scss rename to res/themes/light/css/_fonts.scss index 52ac95b569..c080663acf 100644 --- a/res/css/_fonts.scss +++ b/res/themes/light/css/_fonts.scss @@ -7,42 +7,42 @@ */ @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Regular.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Italic.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-Italic.ttf') format('truetype'); font-weight: 400; font-style: italic; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Semibold.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-Semibold.ttf') format('truetype'); font-weight: 600; font-style: normal; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-SemiboldItalic.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-SemiboldItalic.ttf') format('truetype'); font-weight: 600; font-style: italic; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Bold.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; } @font-face { font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-BoldItalic.ttf') format('truetype'); + src: url('$(res)/fonts/Open_Sans/OpenSans-BoldItalic.ttf') format('truetype'); font-weight: 700; font-style: italic; } @@ -54,14 +54,14 @@ @font-face { font-family: 'Fira Mono'; - src: url('../../fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype'); + src: url('$(res)/fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Fira Mono'; - src: url('../../fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype'); + src: url('$(res)/fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; } diff --git a/res/themes/light/css/_paths.scss b/res/themes/light/css/_paths.scss new file mode 100644 index 0000000000..0744347826 --- /dev/null +++ b/res/themes/light/css/_paths.scss @@ -0,0 +1,3 @@ +// Path from root SCSS file (such as `light.scss`) to `res` dir in the source tree +// This value is overridden by external themes in `riot-web`. +$res: ../../..; diff --git a/res/themes/light/css/light.scss b/res/themes/light/css/light.scss index 2099f41f60..6ac8d0feba 100644 --- a/res/themes/light/css/light.scss +++ b/res/themes/light/css/light.scss @@ -1,3 +1,4 @@ +@import "_paths.scss"; +@import "_fonts.scss"; @import "_base.scss"; @import "../../../../res/css/_components.scss"; - diff --git a/scripts/fetchdep.sh b/scripts/fetchdep.sh index 4f42859439..95fc4b0603 100755 --- a/scripts/fetchdep.sh +++ b/scripts/fetchdep.sh @@ -1,7 +1,5 @@ #!/bin/sh -set -e - org="$1" repo="$2" defbranch="$3" @@ -10,16 +8,20 @@ defbranch="$3" rm -r "$repo" || true -curbranch="$TRAVIS_PULL_REQUEST_BRANCH" -[ -z "$curbranch" ] && curbranch="$TRAVIS_BRANCH" -[ -z "$curbranch" ] && curbranch=`"echo $GIT_BRANCH" | sed -e 's/^origin\///'` # jenkins +clone() { + branch=$1 + if [ -n "$branch" ] + then + echo "Trying to use the branch $branch" + git clone https://github.com/$org/$repo.git $repo --branch "$branch" && exit 0 + fi +} -if [ -n "$curbranch" ] -then - echo "Determined branch to be $curbranch" - - git clone https://github.com/$org/$repo.git $repo --branch "$curbranch" && exit 0 -fi - -echo "Checking out default branch $defbranch" -git clone https://github.com/$org/$repo.git $repo --branch $defbranch +# Try the PR author's branch in case it exists on the deps as well. +clone $TRAVIS_PULL_REQUEST_BRANCH +# Try the target branch of the push or PR. +clone $TRAVIS_BRANCH +# Try the current branch from Jenkins. +clone `"echo $GIT_BRANCH" | sed -e 's/^origin\///'` +# Use the default branch as the last resort. +clone $defbranch diff --git a/.travis-test-riot.sh b/scripts/travis/build.sh similarity index 61% rename from .travis-test-riot.sh rename to scripts/travis/build.sh index d1c2804b2a..a353e38a06 100755 --- a/.travis-test-riot.sh +++ b/scripts/travis/build.sh @@ -24,18 +24,4 @@ rm -r node_modules/matrix-react-sdk ln -s "$REACT_SDK_DIR" node_modules/matrix-react-sdk npm run build -npm run test popd - -if [ "$TRAVIS_BRANCH" = "develop" ] -then - # run end to end tests - scripts/fetchdep.sh matrix-org matrix-react-end-to-end-tests master - pushd matrix-react-end-to-end-tests - ln -s $REACT_SDK_DIR/$RIOT_WEB_DIR riot/riot-web - # PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true ./install.sh - # CHROME_PATH=$(which google-chrome-stable) ./run.sh - ./install.sh - ./run.sh --travis - popd -fi diff --git a/scripts/travis/end-to-end-tests.sh b/scripts/travis/end-to-end-tests.sh new file mode 100755 index 0000000000..361b053d2b --- /dev/null +++ b/scripts/travis/end-to-end-tests.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# script which is run by the travis build (after `npm run test`). +# +# clones riot-web develop and runs the tests against our version of react-sdk. + +set -ev + +RIOT_WEB_DIR=riot-web +REACT_SDK_DIR=`pwd` + +scripts/travis/build.sh +# run end to end tests +scripts/fetchdep.sh matrix-org matrix-react-end-to-end-tests master +pushd matrix-react-end-to-end-tests +ln -s $REACT_SDK_DIR/$RIOT_WEB_DIR riot/riot-web +# PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true ./install.sh +# CHROME_PATH=$(which google-chrome-stable) ./run.sh +./install.sh +./run.sh --travis +popd diff --git a/scripts/travis.sh b/scripts/travis/install-deps.sh similarity index 57% rename from scripts/travis.sh rename to scripts/travis/install-deps.sh index 48410ea904..04cd728157 100755 --- a/scripts/travis.sh +++ b/scripts/travis/install-deps.sh @@ -1,7 +1,7 @@ #!/bin/sh set -ex - +npm install scripts/fetchdep.sh matrix-org matrix-js-sdk rm -r node_modules/matrix-js-sdk || true ln -s ../matrix-js-sdk node_modules/matrix-js-sdk @@ -9,9 +9,3 @@ ln -s ../matrix-js-sdk node_modules/matrix-js-sdk cd matrix-js-sdk npm install cd .. - -npm run test -./.travis-test-riot.sh - -# run the linter, but exclude any files known to have errors or warnings. -npm run lintwithexclusions diff --git a/scripts/travis/riot-unit-tests.sh b/scripts/travis/riot-unit-tests.sh new file mode 100755 index 0000000000..a2f0d61112 --- /dev/null +++ b/scripts/travis/riot-unit-tests.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# +# script which is run by the travis build (after `npm run test`). +# +# clones riot-web develop and runs the tests against our version of react-sdk. + +set -ev + +RIOT_WEB_DIR=riot-web + +scripts/travis/build.sh +pushd "$RIOT_WEB_DIR" +npm run test +popd diff --git a/scripts/travis/unit-tests.sh b/scripts/travis/unit-tests.sh new file mode 100755 index 0000000000..a8e0a63b31 --- /dev/null +++ b/scripts/travis/unit-tests.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# +# script which is run by the travis build (after `npm run test`). +# +# clones riot-web develop and runs the tests against our version of react-sdk. + +set -ev + +scripts/travis/build.sh +npm run test diff --git a/src/AddThreepid.js b/src/AddThreepid.js index 337e38d867..8de7e9e21c 100644 --- a/src/AddThreepid.js +++ b/src/AddThreepid.js @@ -26,7 +26,7 @@ import { _t } from './languageHandler'; * the client owns the given email address, which is then passed to the * add threepid API on the homeserver. */ -class AddThreepid { +export default class AddThreepid { constructor() { this.clientSecret = MatrixClientPeg.get().generateClientSecret(); } @@ -124,5 +124,3 @@ class AddThreepid { }); } } - -module.exports = AddThreepid; diff --git a/src/Analytics.js b/src/Analytics.js index d85d635b28..3a8c5d6e10 100644 --- a/src/Analytics.js +++ b/src/Analytics.js @@ -66,7 +66,7 @@ const customVariables = { }, 'User Type': { id: 3, - expl: _td('Whether or not you\'re logged in (we don\'t record your user name)'), + expl: _td('Whether or not you\'re logged in (we don\'t record your username)'), example: 'Logged In', }, 'Chosen Language': { diff --git a/src/Avatar.js b/src/Avatar.js index d41a3f6a79..d3df12eb49 100644 --- a/src/Avatar.js +++ b/src/Avatar.js @@ -56,6 +56,6 @@ module.exports = { for (let i = 0; i < s.length; ++i) { total += s.charCodeAt(i); } - return 'img/' + images[total % images.length] + '.png'; + return require('../res/img/' + images[total % images.length] + '.png'); }, }; diff --git a/src/CallMediaHandler.js b/src/CallMediaHandler.js index 2330f86b99..9a1c9d70b8 100644 --- a/src/CallMediaHandler.js +++ b/src/CallMediaHandler.js @@ -69,4 +69,16 @@ export default { SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId); Matrix.setMatrixCallVideoInput(deviceId); }, + + getAudioOutput: function() { + return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audiooutput"); + }, + + getAudioInput: function() { + return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audioinput"); + }, + + getVideoInput: function() { + return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_videoinput"); + }, }; diff --git a/src/Lifecycle.js b/src/Lifecycle.js index ed057eb020..54ac605c65 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -27,7 +27,6 @@ import UserActivity from './UserActivity'; import Presence from './Presence'; import dis from './dispatcher'; import DMRoomMap from './utils/DMRoomMap'; -import RtsClient from './RtsClient'; import Modal from './Modal'; import sdk from './index'; import ActiveWidgetStore from './stores/ActiveWidgetStore'; @@ -224,7 +223,7 @@ function _registerAsGuest(hsUrl, isUrl, defaultDeviceDisplayName) { // // The plan is to gradually move the localStorage access done here into // SessionStore to avoid bugs where the view becomes out-of-sync with -// localStorage (e.g. teamToken, isGuest etc.) +// localStorage (e.g. isGuest etc.) async function _restoreFromLocalStorage() { if (!localStorage) { return false; @@ -286,15 +285,6 @@ function _handleLoadSessionFailure(e) { }); } -let rtsClient = null; -export function initRtsClient(url) { - if (url) { - rtsClient = new RtsClient(url); - } else { - rtsClient = null; - } -} - /** * Transitions to a logged-in state using the given credentials. * @@ -333,7 +323,7 @@ async function _doSetLoggedIn(credentials, clearStorage) { ); // This is dispatched to indicate that the user is still in the process of logging in - // because `teamPromise` may take some time to resolve, breaking the assumption that + // because async code may take some time to resolve, breaking the assumption that // `setLoggedIn` takes an "instant" to complete, and dispatch `on_logged_in` a few ms // later than MatrixChat might assume. // @@ -347,10 +337,6 @@ async function _doSetLoggedIn(credentials, clearStorage) { Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl, credentials.identityServerUrl); - // Resolves by default - let teamPromise = Promise.resolve(null); - - if (localStorage) { try { _persistCredentialsToLocalStorage(credentials); @@ -367,27 +353,13 @@ async function _doSetLoggedIn(credentials, clearStorage) { } catch (e) { console.warn("Error using local storage: can't persist session!", e); } - - if (rtsClient && !credentials.guest) { - teamPromise = rtsClient.login(credentials.userId).then((body) => { - if (body.team_token) { - localStorage.setItem("mx_team_token", body.team_token); - } - return body.team_token; - }, (err) => { - console.warn(`Failed to get team token on login: ${err}` ); - return null; - }); - } } else { console.warn("No local storage available: can't persist session!"); } MatrixClientPeg.replaceUsingCreds(credentials); - teamPromise.then((teamToken) => { - dis.dispatch({action: 'on_logged_in', teamToken: teamToken}); - }); + dis.dispatch({ action: 'on_logged_in' }); await startMatrixClient(); return MatrixClientPeg.get(); diff --git a/src/Login.js b/src/Login.js index ca045e36cd..893ec42097 100644 --- a/src/Login.js +++ b/src/Login.js @@ -49,6 +49,7 @@ export default class Login { /** * Get a temporary MatrixClient, which can be used for login or register * requests. + * @returns {MatrixClient} */ _createTemporaryClient() { return Matrix.createClient({ @@ -144,8 +145,8 @@ export default class Login { const tryFallbackHs = (originalError) => { return sendLoginRequest( self._fallbackHsUrl, this._isUrl, 'm.login.password', loginParams, - ).catch((fallback_error) => { - console.log("fallback HS login failed", fallback_error); + ).catch((fallbackError) => { + console.log("fallback HS login failed", fallbackError); // throw the original error throw originalError; }); diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 9a77901d2e..b216f5740c 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -29,6 +29,7 @@ import SettingsStore from './settings/SettingsStore'; import MatrixActionCreators from './actions/MatrixActionCreators'; import {phasedRollOutExpiredForUser} from "./PhasedRollOut"; import Modal from './Modal'; +import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; interface MatrixClientCreds { homeserverUrl: string, @@ -183,7 +184,8 @@ class MatrixClientPeg { userId: creds.userId, deviceId: creds.deviceId, timelineSupport: true, - forceTURN: SettingsStore.getValue('webRtcForceTURN', false), + forceTURN: !SettingsStore.getValue('webRtcForcePeerToPeer', false), + verificationMethods: [verificationMethods.SAS] }; this.matrixClient = createMatrixClient(opts, useIndexedDb); diff --git a/src/Notifier.js b/src/Notifier.js index 8550f3bf95..80e8be1084 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -289,11 +289,6 @@ const Notifier = { const room = MatrixClientPeg.get().getRoom(ev.getRoomId()); const actions = MatrixClientPeg.get().getPushActionsForEvent(ev); if (actions && actions.notify) { - dis.dispatch({ - action: "event_notification", - event: ev, - room: room, - }); if (this.isEnabled()) { this._displayPopupNotification(ev, room); } diff --git a/src/PageTypes.js b/src/PageTypes.js index 66d930c288..60111723fb 100644 --- a/src/PageTypes.js +++ b/src/PageTypes.js @@ -20,7 +20,6 @@ export default { HomePage: "home_page", RoomView: "room_view", UserSettings: "user_settings", - CreateRoom: "create_room", RoomDirectory: "room_directory", UserView: "user_view", GroupView: "group_view", diff --git a/src/PhasedRollOut.js b/src/PhasedRollOut.js index a9029d07e6..b17ed37974 100644 --- a/src/PhasedRollOut.js +++ b/src/PhasedRollOut.js @@ -15,21 +15,7 @@ limitations under the License. */ import SdkConfig from './SdkConfig'; - -function hashCode(str) { - let hash = 0; - let i; - let chr; - if (str.length === 0) { - return hash; - } - for (i = 0; i < str.length; i++) { - chr = str.charCodeAt(i); - hash = ((hash << 5) - hash) + chr; - hash |= 0; - } - return Math.abs(hash); -} +import {hashCode} from './utils/FormattingUtils'; export function phasedRollOutExpiredForUser(username, feature, now, rollOutConfig = SdkConfig.get().phasedRollOut) { if (!rollOutConfig) { diff --git a/src/Presence.js b/src/Presence.js index b1e85e4bc7..849efdef1c 100644 --- a/src/Presence.js +++ b/src/Presence.js @@ -17,21 +17,33 @@ limitations under the License. const MatrixClientPeg = require("./MatrixClientPeg"); const dis = require("./dispatcher"); +import Timer from './utils/Timer'; // Time in ms after that a user is considered as unavailable/away const UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins const PRESENCE_STATES = ["online", "offline", "unavailable"]; class Presence { + + constructor() { + this._activitySignal = null; + this._unavailableTimer = null; + this._onAction = this._onAction.bind(this); + this._dispatcherRef = null; + } /** * Start listening the user activity to evaluate his presence state. * Any state change will be sent to the Home Server. */ - start() { - this.running = true; - if (undefined === this.state) { - this._resetTimer(); - this.dispatcherRef = dis.register(this._onAction.bind(this)); + async start() { + this._unavailableTimer = new Timer(UNAVAILABLE_TIME_MS); + // the user_activity_start action starts the timer + this._dispatcherRef = dis.register(this._onAction); + while (this._unavailableTimer) { + try { + await this._unavailableTimer.finished(); + this.setState("unavailable"); + } catch(e) { /* aborted, stop got called */ } } } @@ -39,13 +51,14 @@ class Presence { * Stop tracking user activity */ stop() { - this.running = false; - if (this.timer) { - clearInterval(this.timer); - this.timer = undefined; - dis.unregister(this.dispatcherRef); + if (this._dispatcherRef) { + dis.unregister(this._dispatcherRef); + this._dispatcherRef = null; + } + if (this._unavailableTimer) { + this._unavailableTimer.abort(); + this._unavailableTimer = null; } - this.state = undefined; } /** @@ -56,21 +69,25 @@ class Presence { return this.state; } + _onAction(payload) { + if (payload.action === 'user_activity') { + this.setState("online"); + this._unavailableTimer.restart(); + } + } + /** * Set the presence state. * If the state has changed, the Home Server will be notified. * @param {string} newState the new presence state (see PRESENCE enum) */ - setState(newState) { + async setState(newState) { if (newState === this.state) { return; } if (PRESENCE_STATES.indexOf(newState) === -1) { throw new Error("Bad presence state: " + newState); } - if (!this.running) { - return; - } const old_state = this.state; this.state = newState; @@ -78,42 +95,14 @@ class Presence { return; // don't try to set presence when a guest; it won't work. } - const self = this; - MatrixClientPeg.get().setPresence(this.state).done(function() { + try { + await MatrixClientPeg.get().setPresence(this.state); console.log("Presence: %s", newState); - }, function(err) { + } catch(err) { console.error("Failed to set presence: %s", err); - self.state = old_state; - }); - } - - /** - * Callback called when the user made no action on the page for UNAVAILABLE_TIME ms. - * @private - */ - _onUnavailableTimerFire() { - this.setState("unavailable"); - } - - _onAction(payload) { - if (payload.action === "user_activity") { - this._resetTimer(); + this.state = old_state; } } - - /** - * Callback called when the user made an action on the page - * @private - */ - _resetTimer() { - const self = this; - this.setState("online"); - // Re-arm the timer - clearTimeout(this.timer); - this.timer = setTimeout(function() { - self._onUnavailableTimerFire(); - }, UNAVAILABLE_TIME_MS); - } } module.exports = new Presence(); diff --git a/src/RtsClient.js b/src/RtsClient.js deleted file mode 100644 index 493b19599c..0000000000 --- a/src/RtsClient.js +++ /dev/null @@ -1,104 +0,0 @@ -import 'whatwg-fetch'; - -let fetchFunction = fetch; - -function checkStatus(response) { - if (!response.ok) { - return response.text().then((text) => { - throw new Error(text); - }); - } - return response; -} - -function parseJson(response) { - return response.json(); -} - -function encodeQueryParams(params) { - return '?' + Object.keys(params).map((k) => { - return k + '=' + encodeURIComponent(params[k]); - }).join('&'); -} - -const request = (url, opts) => { - if (opts && opts.qs) { - url += encodeQueryParams(opts.qs); - delete opts.qs; - } - if (opts && opts.body) { - if (!opts.headers) { - opts.headers = {}; - } - opts.body = JSON.stringify(opts.body); - opts.headers['Content-Type'] = 'application/json'; - } - return fetchFunction(url, opts) - .then(checkStatus) - .then(parseJson); -}; - - -export default class RtsClient { - constructor(url) { - this._url = url; - } - - getTeamsConfig() { - return request(this._url + '/teams'); - } - - /** - * Track a referral with the Riot Team Server. This should be called once a referred - * user has been successfully registered. - * @param {string} referrer the user ID of one who referred the user to Riot. - * @param {string} sid the sign-up identity server session ID . - * @param {string} clientSecret the sign-up client secret. - * @returns {Promise} a promise that resolves to { team_token: 'sometoken' } upon - * success. - */ - trackReferral(referrer, sid, clientSecret) { - return request(this._url + '/register', - { - body: { - referrer: referrer, - session_id: sid, - client_secret: clientSecret, - }, - method: 'POST', - }, - ); - } - - getTeam(teamToken) { - return request(this._url + '/teamConfiguration', - { - qs: { - team_token: teamToken, - }, - }, - ); - } - - /** - * Signal to the RTS that a login has occurred and that a user requires their team's - * token. - * @param {string} userId the user ID of the user who is a member of a team. - * @returns {Promise} a promise that resolves to { team_token: 'sometoken' } upon - * success. - */ - login(userId) { - return request(this._url + '/login', - { - qs: { - user_id: userId, - }, - }, - ); - } - - // allow fetch to be replaced, for testing. - static setFetch(fn) { - fetchFunction = fn; - } -} diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 5b5a53b83f..d70d970796 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -91,6 +91,18 @@ export const CommandMap = { hideCompletionAfterSpace: true, }), + upgraderoom: new Command({ + name: 'upgraderoom', + args: '', + description: _td('Upgrades a room to a new version'), + runFn: function(roomId, args) { + if (args) { + return success(MatrixClientPeg.get().upgradeRoom(roomId, args)); + } + return reject(this.getUsage()); + }, + }), + nick: new Command({ name: 'nick', args: '', @@ -154,6 +166,18 @@ export const CommandMap = { }, }), + roomname: new Command({ + name: 'roomname', + args: '', + description: _td('Sets the room name'), + runFn: function(roomId, args) { + if (args) { + return success(MatrixClientPeg.get().setRoomName(roomId, args)); + } + return reject(this.getUsage()); + }, + }), + invite: new Command({ name: 'invite', args: '', diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 96cccf07fb..2a37295f83 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -129,6 +129,11 @@ function textForRoomNameEvent(ev) { }); } +function textForTombstoneEvent(ev) { + const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + return _t('%(senderDisplayName)s upgraded this room.', {senderDisplayName}); +} + function textForServerACLEvent(ev) { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); const prevContent = ev.getPrevContent(); @@ -433,6 +438,7 @@ const stateHandlers = { 'm.room.power_levels': textForPowerEvent, 'm.room.pinned_events': textForPinnedEvent, 'm.room.server_acl': textForServerACLEvent, + 'm.room.tombstone': textForTombstoneEvent, 'im.vector.modular.widgets': textForWidgetEvent, }; diff --git a/src/Tinter.js b/src/Tinter.js index 9c2afd4fab..de9ae94097 100644 --- a/src/Tinter.js +++ b/src/Tinter.js @@ -154,6 +154,8 @@ class Tinter { } tint(primaryColor, secondaryColor, tertiaryColor) { + return; + // eslint-disable-next-line no-unreachable this.currentTint[0] = primaryColor; this.currentTint[1] = secondaryColor; this.currentTint[2] = tertiaryColor; @@ -390,7 +392,7 @@ class Tinter { // XXX: we could just move this all into TintableSvg, but as it's so similar // to the CSS fixup stuff in Tinter (just that the fixups are stored in TintableSvg) // keeping it here for now. - calcSvgFixups(svgs, forceColors) { + calcSvgFixups(svgs) { // go through manually fixing up SVG colours. // we could do this by stylesheets, but keeping the stylesheets // updated would be a PITA, so just brute-force search for the @@ -418,21 +420,13 @@ class Tinter { const tag = tags[j]; for (let k = 0; k < this.svgAttrs.length; k++) { const attr = this.svgAttrs[k]; - for (let m = 0; m < this.keyHex.length; m++) { // dev note: don't use L please. - // We use a different attribute from the one we're setting - // because we may also be using forceColors. If we were to - // check the keyHex against a forceColors value, it may not - // match and therefore not change when we need it to. - const valAttrName = "mx-val-" + attr; - let attribute = tag.getAttribute(valAttrName); - if (!attribute) attribute = tag.getAttribute(attr); // fall back to the original - if (attribute && (attribute.toUpperCase() === this.keyHex[m] || attribute.toLowerCase() === this.keyRgb[m])) { + for (let l = 0; l < this.keyHex.length; l++) { + if (tag.getAttribute(attr) && + tag.getAttribute(attr).toUpperCase() === this.keyHex[l]) { fixups.push({ node: tag, attr: attr, - refAttr: valAttrName, - index: m, - forceColors: forceColors, + index: l, }); } } @@ -448,9 +442,7 @@ class Tinter { if (DEBUG) console.log("applySvgFixups start for " + fixups); for (let i = 0; i < fixups.length; i++) { const svgFixup = fixups[i]; - const forcedColor = svgFixup.forceColors ? svgFixup.forceColors[svgFixup.index] : null; - svgFixup.node.setAttribute(svgFixup.attr, forcedColor ? forcedColor : this.colors[svgFixup.index]); - svgFixup.node.setAttribute(svgFixup.refAttr, this.colors[svgFixup.index]); + svgFixup.node.setAttribute(svgFixup.attr, this.colors[svgFixup.index]); } if (DEBUG) console.log("applySvgFixups end"); } diff --git a/src/UiEffects.js b/src/UiEffects.js index 76db0b7f12..06b0a0e3b7 100644 --- a/src/UiEffects.js +++ b/src/UiEffects.js @@ -22,6 +22,6 @@ limitations under the License. import Velocity from 'velocity-vector'; import 'velocity-vector/velocity.ui'; -export function field_input_incorrect(element) { +export function fieldInputIncorrect(element) { Velocity(element, "callout.shake", 300); } diff --git a/src/UserActivity.js b/src/UserActivity.js index c628ab4186..145b23e36e 100644 --- a/src/UserActivity.js +++ b/src/UserActivity.js @@ -15,32 +15,73 @@ limitations under the License. */ import dis from './dispatcher'; +import Timer from './utils/Timer'; -const MIN_DISPATCH_INTERVAL_MS = 500; -const CURRENTLY_ACTIVE_THRESHOLD_MS = 2000; +// important this is larger than the timeouts of timers +// used with UserActivity.timeWhileActive, +// such as READ_MARKER_INVIEW_THRESHOLD_MS, +// READ_MARKER_OUTOFVIEW_THRESHOLD_MS, +// READ_RECEIPT_INTERVAL_MS in TimelinePanel +const CURRENTLY_ACTIVE_THRESHOLD_MS = 2 * 60 * 1000; /** * This class watches for user activity (moving the mouse or pressing a key) - * and dispatches the user_activity action at times when the user is interacting - * with the app (but at a much lower frequency than mouse move events) + * and starts/stops attached timers while the user is active. */ class UserActivity { + constructor() { + this._attachedTimers = []; + this._activityTimeout = new Timer(CURRENTLY_ACTIVE_THRESHOLD_MS); + this._onUserActivity = this._onUserActivity.bind(this); + this._onDocumentBlurred = this._onDocumentBlurred.bind(this); + this._onPageVisibilityChanged = this._onPageVisibilityChanged.bind(this); + this.lastScreenX = 0; + this.lastScreenY = 0; + } + + /** + * Runs the given timer while the user is active, aborting when the user becomes inactive. + * Can be called multiple times with the same already running timer, which is a NO-OP. + * Can be called before the user becomes active, in which case it is only started + * later on when the user does become active. + * @param {Timer} timer the timer to use + */ + timeWhileActive(timer) { + // important this happens first + const index = this._attachedTimers.indexOf(timer); + if (index === -1) { + this._attachedTimers.push(timer); + // remove when done or aborted + timer.finished().finally(() => { + const index = this._attachedTimers.indexOf(timer); + if (index !== -1) { // should never be -1 + this._attachedTimers.splice(index, 1); + } + // as we fork the promise here, + // avoid unhandled rejection warnings + }).catch((err) => {}); + } + if (this.userCurrentlyActive()) { + timer.start(); + } + } + /** * Start listening to user activity */ start() { - document.onmousedown = this._onUserActivity.bind(this); - document.onmousemove = this._onUserActivity.bind(this); - document.onkeydown = this._onUserActivity.bind(this); + document.onmousedown = this._onUserActivity; + document.onmousemove = this._onUserActivity; + document.onkeydown = this._onUserActivity; + document.addEventListener("visibilitychange", this._onPageVisibilityChanged); + document.addEventListener("blur", this._onDocumentBlurred); + document.addEventListener("focus", this._onUserActivity); // can't use document.scroll here because that's only the document // itself being scrolled. Need to use addEventListener's useCapture. // also this needs to be the wheel event, not scroll, as scroll is // fired when the view scrolls down for a new message. - window.addEventListener('wheel', this._onUserActivity.bind(this), + window.addEventListener('wheel', this._onUserActivity, { passive: true, capture: true }); - this.lastActivityAtTs = new Date().getTime(); - this.lastDispatchAtTs = 0; - this.activityEndTimer = undefined; } /** @@ -50,8 +91,12 @@ class UserActivity { document.onmousedown = undefined; document.onmousemove = undefined; document.onkeydown = undefined; - window.removeEventListener('wheel', this._onUserActivity.bind(this), + window.removeEventListener('wheel', this._onUserActivity, { passive: true, capture: true }); + + document.removeEventListener("visibilitychange", this._onPageVisibilityChanged); + document.removeEventListener("blur", this._onDocumentBlurred); + document.removeEventListener("focus", this._onUserActivity); } /** @@ -60,10 +105,22 @@ class UserActivity { * @returns {boolean} true if user is currently/very recently active */ userCurrentlyActive() { - return this.lastActivityAtTs > new Date().getTime() - CURRENTLY_ACTIVE_THRESHOLD_MS; + return this._activityTimeout.isRunning(); } - _onUserActivity(event) { + _onPageVisibilityChanged(e) { + if (document.visibilityState === "hidden") { + this._activityTimeout.abort(); + } else { + this._onUserActivity(e); + } + } + + _onDocumentBlurred() { + this._activityTimeout.abort(); + } + + async _onUserActivity(event) { if (event.screenX && event.type === "mousemove") { if (event.screenX === this.lastScreenX && event.screenY === this.lastScreenY) { // mouse hasn't actually moved @@ -73,30 +130,20 @@ class UserActivity { this.lastScreenY = event.screenY; } - this.lastActivityAtTs = new Date().getTime(); - if (this.lastDispatchAtTs < this.lastActivityAtTs - MIN_DISPATCH_INTERVAL_MS) { - this.lastDispatchAtTs = this.lastActivityAtTs; - dis.dispatch({ - action: 'user_activity', - }); - if (!this.activityEndTimer) { - this.activityEndTimer = setTimeout(this._onActivityEndTimer.bind(this), MIN_DISPATCH_INTERVAL_MS); - } - } - } - - _onActivityEndTimer() { - const now = new Date().getTime(); - const targetTime = this.lastActivityAtTs + MIN_DISPATCH_INTERVAL_MS; - if (now >= targetTime) { - dis.dispatch({ - action: 'user_activity_end', - }); - this.activityEndTimer = undefined; + dis.dispatch({action: 'user_activity'}); + if (!this._activityTimeout.isRunning()) { + this._activityTimeout.start(); + dis.dispatch({action: 'user_activity_start'}); + this._attachedTimers.forEach((t) => t.start()); + try { + await this._activityTimeout.finished(); + } catch (_e) { /* aborted */ } + this._attachedTimers.forEach((t) => t.abort()); } else { - this.activityEndTimer = setTimeout(this._onActivityEndTimer.bind(this), targetTime - now); + this._activityTimeout.restart(); } } } + module.exports = new UserActivity(); diff --git a/src/WhoIsTyping.js b/src/WhoIsTyping.js index 0edad8d4a5..78ca77ce5a 100644 --- a/src/WhoIsTyping.js +++ b/src/WhoIsTyping.js @@ -63,16 +63,16 @@ module.exports = { if (whoIsTyping.length == 0) { return ''; } else if (whoIsTyping.length == 1) { - return _t('%(displayName)s is typing', {displayName: whoIsTyping[0].name}); + return _t('%(displayName)s is typing …', {displayName: whoIsTyping[0].name}); } const names = whoIsTyping.map(function(m) { return m.name; }); if (othersCount>=1) { - return _t('%(names)s and %(count)s others are typing', {names: names.slice(0, limit - 1).join(', '), count: othersCount}); + return _t('%(names)s and %(count)s others are typing …', {names: names.slice(0, limit - 1).join(', '), count: othersCount}); } else { const lastPerson = names.pop(); - return _t('%(names)s and %(lastPerson)s are typing', {names: names.join(', '), lastPerson: lastPerson}); + return _t('%(names)s and %(lastPerson)s are typing …', {names: names.join(', '), lastPerson: lastPerson}); } }, }; diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js index a097e84cdb..2c54344a30 100644 --- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js +++ b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +Copyright 2018, 2019 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import { scorePassword } from '../../../../utils/PasswordScorer'; import FileSaver from 'file-saver'; -import { _t, _td } from '../../../../languageHandler'; +import { _t } from '../../../../languageHandler'; const PHASE_PASSPHRASE = 0; const PHASE_PASSPHRASE_CONFIRM = 1; @@ -32,6 +32,7 @@ const PHASE_DONE = 5; const PHASE_OPTOUT_CONFIRM = 6; const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc. +const PASSPHRASE_FEEDBACK_DELAY = 500; // How long after keystroke to offer passphrase feedback, ms. // XXX: copied from ShareDialog: factor out into utils function selectText(target) { @@ -63,6 +64,13 @@ export default React.createClass({ componentWillMount: function() { this._recoveryKeyNode = null; this._keyBackupInfo = null; + this._setZxcvbnResultTimeout = null; + }, + + componentWillUnmount: function() { + if (this._setZxcvbnResultTimeout !== null) { + clearTimeout(this._setZxcvbnResultTimeout); + } }, _collectRecoveryKeyNode: function(n) { @@ -102,7 +110,7 @@ export default React.createClass({ info = await MatrixClientPeg.get().createKeyBackupVersion( this._keyBackupInfo, ); - await MatrixClientPeg.get().backupAllGroupSessions(info.version); + await MatrixClientPeg.get().scheduleAllGroupSessionsForBackup(); this.setState({ phase: PHASE_DONE, }); @@ -150,9 +158,23 @@ export default React.createClass({ this.setState({phase: PHASE_PASSPHRASE_CONFIRM}); }, - _onPassPhraseKeyPress: function(e) { - if (e.key === 'Enter' && this._passPhraseIsValid()) { - this._onPassPhraseNextClick(); + _onPassPhraseKeyPress: async function(e) { + if (e.key === 'Enter') { + // If we're waiting for the timeout before updating the result at this point, + // skip ahead and do it now, otherwise we'll deny the attempt to proceed + // even if the user entered a valid passphrase + if (this._setZxcvbnResultTimeout !== null) { + clearTimeout(this._setZxcvbnResultTimeout); + this._setZxcvbnResultTimeout = null; + await new Promise((resolve) => { + this.setState({ + zxcvbnResult: scorePassword(this.state.passPhrase), + }, resolve); + }); + } + if (this._passPhraseIsValid()) { + this._onPassPhraseNextClick(); + } } }, @@ -177,10 +199,11 @@ export default React.createClass({ passPhrase: '', passPhraseConfirm: '', phase: PHASE_PASSPHRASE, + zxcvbnResult: null, }); }, - _onKeepItSafeGotItClick: function() { + _onKeepItSafeBackClick: function() { this.setState({ phase: PHASE_SHOWKEY, }); @@ -189,11 +212,20 @@ export default React.createClass({ _onPassPhraseChange: function(e) { this.setState({ passPhrase: e.target.value, - // precompute this and keep it in state: zxcvbn is fast but - // we use it in a couple of different places so no point recomputing - // it unnecessarily. - zxcvbnResult: scorePassword(e.target.value), }); + + if (this._setZxcvbnResultTimeout !== null) { + clearTimeout(this._setZxcvbnResultTimeout); + } + this._setZxcvbnResultTimeout = setTimeout(() => { + this._setZxcvbnResultTimeout = null; + this.setState({ + // precompute this and keep it in state: zxcvbn is fast but + // we use it in a couple of different places so no point recomputing + // it unnecessarily. + zxcvbnResult: scorePassword(this.state.passPhrase), + }); + }, PASSPHRASE_FEEDBACK_DELAY); }, _onPassPhraseConfirmChange: function(e) { @@ -220,9 +252,7 @@ export default React.createClass({ for (let i = 0; i < this.state.zxcvbnResult.feedback.suggestions.length; ++i) { suggestions.push(
{this.state.zxcvbnResult.feedback.suggestions[i]}
); } - const suggestionBlock = suggestions.length > 0 ?
- {suggestions} -
: null; + const suggestionBlock =
{suggestions.length > 0 ? suggestions : _t("Keep going...")}
; helpText =
{this.state.zxcvbnResult.feedback.warning} @@ -246,6 +276,7 @@ export default React.createClass({ value={this.state.passPhrase} className="mx_CreateKeyBackupDialog_passPhraseInput" placeholder={_t("Enter a passphrase...")} + autoFocus={true} />
{strengthMeter} @@ -294,14 +325,22 @@ export default React.createClass({ _renderPhasePassPhraseConfirm: function() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + let matchText; + if (this.state.passPhraseConfirm === this.state.passPhrase) { + matchText = _t("That matches!"); + } else if (!this.state.passPhrase.startsWith(this.state.passPhraseConfirm)) { + // only tell them they're wrong if they've actually gone wrong. + // Security concious readers will note that if you left riot-web unattended + // on this screen, this would make it easy for a malicious person to guess + // your passphrase one letter at a time, but they could get this faster by + // just opening the browser's developer tools and reading it. + // Note that not having typed anything at all will not hit this clause and + // fall through so empty box === no hint. + matchText = _t("That doesn't match."); + } + let passPhraseMatch = null; - if (this.state.passPhraseConfirm.length > 0) { - let matchText; - if (this.state.passPhraseConfirm === this.state.passPhrase) { - matchText = _t("That matches!"); - } else { - matchText = _t("That doesn't match."); - } + if (matchText) { passPhraseMatch =
{matchText}
@@ -342,11 +381,12 @@ export default React.createClass({ }, _renderPhaseShowKey: function() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - let bodyText; if (this.state.setPassPhrase) { - bodyText = _t("As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase."); + bodyText = _t( + "As a safety net, you can use it to restore your encrypted message " + + "history if you forget your Recovery Passphrase.", + ); } else { bodyText = _t("As a safety net, you can use it to restore your encrypted message history."); } @@ -354,7 +394,7 @@ export default React.createClass({ return

{_t("Make a copy of this Recovery Key and keep it safe.")}

{bodyText}

-

+

{_t("Your Recovery Key")}
@@ -371,13 +411,7 @@ export default React.createClass({
-

-
- +
; }, @@ -402,17 +436,17 @@ export default React.createClass({
  • {_t("Save it on a USB key or backup drive", {}, {b: s => {s}})}
  • {_t("Copy it to your personal cloud storage", {}, {b: s => {s}})}
  • - + + +
    ; }, _renderBusyPhase: function(text) { const Spinner = sdk.getComponent('views.elements.Spinner'); return
    -

    {_t(text)}

    ; }, @@ -420,8 +454,10 @@ export default React.createClass({ _renderPhaseDone: function() { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return
    -

    {_t("Backup created")}

    -

    {_t("Your encryption keys are now being backed up to your Homeserver.")}

    +

    {_t( + "Your encryption keys are now being backed up in the background " + + "to your Homeserver. The initial backup could take several minutes. " + + "You can view key backup upload progress in Settings.")}

    {content} diff --git a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js index 194842ffa5..db86178b5a 100644 --- a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js +++ b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +Copyright 2018-2019 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,9 +24,15 @@ import Modal from "../../../../Modal"; export default class NewRecoveryMethodDialog extends React.PureComponent { static propTypes = { + // As returned by js-sdk getKeyBackupVersion() + newVersionInfo: PropTypes.object, onFinished: PropTypes.func.isRequired, } + onOkClick = () => { + this.props.onFinished(); + } + onGoToSettingsClick = () => { this.props.onFinished(); dis.dispatch({ action: 'view_user_settings' }); @@ -41,8 +47,7 @@ export default class NewRecoveryMethodDialog extends React.PureComponent { // sending our own new keys to it. let backupSigStatus; try { - const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); - backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo); + backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(this.props.newVersionInfo); } catch (e) { console.log("Unable to fetch key backup status", e); return; @@ -71,39 +76,62 @@ export default class NewRecoveryMethodDialog extends React.PureComponent { render() { const BaseDialog = sdk.getComponent("views.dialogs.BaseDialog"); const DialogButtons = sdk.getComponent("views.elements.DialogButtons"); - const title = + + const title = {_t("New Recovery Method")} ; + const newMethodDetected =

    {_t( + "A new recovery passphrase and key for Secure " + + "Messages have been detected.", + )}

    ; + + const hackWarning =

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

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

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

    + {hackWarning} + +
    ; + } else { + content =
    + {newMethodDetected} +

    {_t( + "Setting up Secure Messages on this device " + + "will re-encrypt this device's message history with " + + "the new recovery method.", + )}

    + {hackWarning} + +
    ; + } + return ( - -
    -

    {_t( - "A new recovery passphrase and key for Secure " + - "Messages has been detected.", - )}

    -

    {_t( - "Setting up Secure Messages on this device " + - "will re-encrypt this device's message history with " + - "the new recovery method.", - )}

    -

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

    - -
    + {content}
    ); } diff --git a/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js b/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js new file mode 100644 index 0000000000..1975fbe6d6 --- /dev/null +++ b/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js @@ -0,0 +1,80 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import PropTypes from "prop-types"; +import sdk from "../../../../index"; +import dis from "../../../../dispatcher"; +import { _t } from "../../../../languageHandler"; +import Modal from "../../../../Modal"; + +export default class RecoveryMethodRemovedDialog extends React.PureComponent { + static propTypes = { + onFinished: PropTypes.func.isRequired, + } + + onGoToSettingsClick = () => { + this.props.onFinished(); + dis.dispatch({ action: 'view_user_settings' }); + } + + onSetupClick = () => { + this.props.onFinished(); + Modal.createTrackedDialogAsync("Key Backup", "Key Backup", + import("./CreateKeyBackupDialog"), + ); + } + + render() { + const BaseDialog = sdk.getComponent("views.dialogs.BaseDialog"); + const DialogButtons = sdk.getComponent("views.elements.DialogButtons"); + + const title = + {_t("Recovery Method Removed")} + ; + + return ( + +
    +

    {_t( + "This device has detected that your recovery passphrase and key " + + "for Secure Messages have been removed.", + )}

    +

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

    +

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

    + +
    +
    + ); + } +} diff --git a/src/autocomplete/AutocompleteProvider.js b/src/autocomplete/AutocompleteProvider.js index f9fb61d3a3..98ae83c526 100644 --- a/src/autocomplete/AutocompleteProvider.js +++ b/src/autocomplete/AutocompleteProvider.js @@ -41,8 +41,12 @@ export default class AutocompleteProvider { /** * Of the matched commands in the query, returns the first that contains or is contained by the selection, or null. + * @param {string} query The query string + * @param {SelectionRange} selection Selection to search + * @param {boolean} force True if the user is forcing completion + * @return {object} { command, range } where both objects fields are null if no match */ - getCurrentCommand(query: string, selection: SelectionRange, force: boolean = false): ?string { + getCurrentCommand(query: string, selection: SelectionRange, force: boolean = false) { let commandRegex = this.commandRegex; if (force && this.shouldForceComplete()) { diff --git a/src/autocomplete/Autocompleter.js b/src/autocomplete/Autocompleter.js index e7b89fe576..af2744950f 100644 --- a/src/autocomplete/Autocompleter.js +++ b/src/autocomplete/Autocompleter.js @@ -60,8 +60,8 @@ const PROVIDER_COMPLETION_TIMEOUT = 3000; export default class Autocompleter { constructor(room: Room) { this.room = room; - this.providers = PROVIDERS.map((p) => { - return new p(room); + this.providers = PROVIDERS.map((Prov) => { + return new Prov(room); }); } diff --git a/src/autocomplete/EmojiProvider.js b/src/autocomplete/EmojiProvider.js index 8c6495101f..704cdbd55d 100644 --- a/src/autocomplete/EmojiProvider.js +++ b/src/autocomplete/EmojiProvider.js @@ -97,7 +97,7 @@ export default class EmojiProvider extends AutocompleteProvider { } async getCompletions(query: string, selection: SelectionRange, force?: boolean): Array { - if (SettingsStore.getValue("MessageComposerInput.dontSuggestEmoji")) { + if (!SettingsStore.getValue("MessageComposerInput.suggestEmoji")) { return []; // don't give any suggestions if the user doesn't want them } diff --git a/src/autocomplete/UserProvider.js b/src/autocomplete/UserProvider.js index 2eae053d72..d4a5ec5e74 100644 --- a/src/autocomplete/UserProvider.js +++ b/src/autocomplete/UserProvider.js @@ -41,7 +41,7 @@ export default class UserProvider extends AutocompleteProvider { users: Array = null; room: Room = null; - constructor(room) { + constructor(room: Room) { super(USER_REGEX, FORCED_USER_REGEX); this.room = room; this.matcher = new QueryMatcher([], { diff --git a/src/components/structures/AutoHideScrollbar.js b/src/components/structures/AutoHideScrollbar.js new file mode 100644 index 0000000000..a385df0401 --- /dev/null +++ b/src/components/structures/AutoHideScrollbar.js @@ -0,0 +1,127 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; + +// derived from code from github.com/noeldelgado/gemini-scrollbar +// Copyright (c) Noel Delgado (pixelia.me) +function getScrollbarWidth(alternativeOverflow) { + const div = document.createElement('div'); + div.className = 'mx_AutoHideScrollbar'; //to get width of css scrollbar + div.style.position = 'absolute'; + div.style.top = '-9999px'; + div.style.width = '100px'; + div.style.height = '100px'; + div.style.overflow = "scroll"; + if (alternativeOverflow) { + div.style.overflow = alternativeOverflow; + } + div.style.msOverflowStyle = '-ms-autohiding-scrollbar'; + document.body.appendChild(div); + const scrollbarWidth = (div.offsetWidth - div.clientWidth); + document.body.removeChild(div); + return scrollbarWidth; +} + +function install() { + const scrollbarWidth = getScrollbarWidth(); + if (scrollbarWidth !== 0) { + const hasForcedOverlayScrollbar = getScrollbarWidth('overlay') === 0; + // overflow: overlay on webkit doesn't auto hide the scrollbar + if (hasForcedOverlayScrollbar) { + document.body.classList.add("mx_scrollbar_overlay_noautohide"); + } else { + document.body.classList.add("mx_scrollbar_nooverlay"); + const style = document.createElement('style'); + style.type = 'text/css'; + style.innerText = + `body.mx_scrollbar_nooverlay { --scrollbar-width: ${scrollbarWidth}px; }`; + document.head.appendChild(style); + } + } +} + +const installBodyClassesIfNeeded = (function() { + let installed = false; + return function() { + if (!installed) { + install(); + installed = true; + } + }; +})(); + +export default class AutoHideScrollbar extends React.Component { + constructor(props) { + super(props); + this.onOverflow = this.onOverflow.bind(this); + this.onUnderflow = this.onUnderflow.bind(this); + this._collectContainerRef = this._collectContainerRef.bind(this); + this._needsOverflowListener = null; + } + + onOverflow() { + this.containerRef.classList.add("mx_AutoHideScrollbar_overflow"); + this.containerRef.classList.remove("mx_AutoHideScrollbar_underflow"); + } + + onUnderflow() { + this.containerRef.classList.remove("mx_AutoHideScrollbar_overflow"); + this.containerRef.classList.add("mx_AutoHideScrollbar_underflow"); + } + + checkOverflow() { + if (!this._needsOverflowListener) { + return; + } + if (this.containerRef.scrollHeight > this.containerRef.clientHeight) { + this.onOverflow(); + } else { + this.onUnderflow(); + } + } + + componentDidUpdate() { + this.checkOverflow(); + } + + componentDidMount() { + installBodyClassesIfNeeded(); + this._needsOverflowListener = + document.body.classList.contains("mx_scrollbar_nooverlay"); + this.checkOverflow(); + } + + _collectContainerRef(ref) { + if (ref && !this.containerRef) { + this.containerRef = ref; + } + if (this.props.wrappedRef) { + this.props.wrappedRef(ref); + } + } + + render() { + return (
    +
    + { this.props.children } +
    +
    ); + } +} diff --git a/src/components/structures/BottomLeftMenu.js b/src/components/structures/BottomLeftMenu.js index ed8b8a00b7..47b30be450 100644 --- a/src/components/structures/BottomLeftMenu.js +++ b/src/components/structures/BottomLeftMenu.js @@ -170,7 +170,7 @@ module.exports = React.createClass({ const SettingsButton = sdk.getComponent('elements.SettingsButton'); const GroupsButton = sdk.getComponent('elements.GroupsButton'); - const groupsButton = SettingsStore.getValue("TagPanel.disableTagPanel") ? + const groupsButton = !SettingsStore.getValue("TagPanel.enableTagPanel") ? : null; return ( diff --git a/src/components/structures/CompatibilityPage.js b/src/components/structures/CompatibilityPage.js index 3c5005c053..28521cb1b7 100644 --- a/src/components/structures/CompatibilityPage.js +++ b/src/components/structures/CompatibilityPage.js @@ -41,10 +41,15 @@ module.exports = React.createClass({

    { _t("Sorry, your browser is not able to run Riot.", {}, { 'b': (sub) => {sub} }) }

    - { _t("Riot uses many advanced browser features, some of which are not available or experimental in your current browser.") } + { _t( + "Riot uses many advanced browser features, some of which are not available " + + "or experimental in your current browser.", + ) }

    - { _t('Please install Chrome or Firefox for the best experience.', + { _t( + 'Please install Chrome or Firefox ' + + 'for the best experience.', {}, { 'chromeLink': (sub) => {sub}, @@ -60,7 +65,12 @@ module.exports = React.createClass({ )}

    - { _t("With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!") } + { _t( + "With your current browser, the look and feel of the application may be " + + "completely incorrect, and some or all features may not function. " + + "If you want to try it anyway you can continue, but you are on your own in terms " + + "of any issues you may encounter!", + ) }