diff --git a/.babelrc b/.babelrc index fc5bd1788f..3fb847ad18 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,21 @@ { - "presets": ["react", "es2015", "es2016"], - "plugins": ["transform-class-properties", "transform-object-rest-spread", "transform-async-to-bluebird", "transform-runtime", "add-module-exports", "syntax-dynamic-import"] + "presets": [ + "react", + "es2015", + "es2016" + ], + "plugins": [ + [ + "transform-builtin-extend", + { + "globals": ["Error"] + } + ], + "transform-class-properties", + "transform-object-rest-spread", + "transform-async-to-bluebird", + "transform-runtime", + "add-module-exports", + "syntax-dynamic-import" + ] } diff --git a/.buildkite/pipeline.yaml b/.buildkite/pipeline.yaml new file mode 100644 index 0000000000..6a347ec002 --- /dev/null +++ b/.buildkite/pipeline.yaml @@ -0,0 +1,74 @@ +steps: + - label: ":eslint: Lint" + command: + - "yarn install" + - "yarn lintwithexclusions" + plugins: + - docker#v3.0.1: + image: "node:10" + +# - label: ":chains: End-to-End Tests" +# command: +# # TODO: Remove hacky chmod for BuildKite +# - "chmod +x ./scripts/ci/*.sh" +# - "chmod +x ./scripts/*" +# - "sudo apt-get install build-essential python2.7-dev libffi-dev python-pip python-setuptools sqlite3 libssl-dev python-virtualenv libjpeg-dev libxslt1-dev" +# - "./scripts/ci/install-deps.sh" +# - "./scripts/ci/end-to-end-tests.sh" +# plugins: +# - docker#v3.0.1: +# image: "node:10" + + - label: ":karma: Tests" + agents: + # We use a medium sized instance instead of the normal small ones because + # webpack loves to gorge itself on resources. + queue: "medium" + command: + # Install chrome + - "echo '--- Installing Chrome'" + - "wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -" + - "sh -c 'echo \"deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main\" >> /etc/apt/sources.list.d/google.list'" + - "apt-get update" + - "apt-get install -y google-chrome-stable" + # Run tests + # TODO: Remove hacky chmod for BuildKite + - "chmod +x ./scripts/ci/*.sh" + - "chmod +x ./scripts/*" + - "echo '--- Installing Dependencies'" + - "./scripts/ci/install-deps.sh" + - "echo '+++ Running Tests'" + - "./scripts/ci/unit-tests.sh" + env: + CHROME_BIN: "/usr/bin/google-chrome-stable" + plugins: + - docker#v3.0.1: + image: "node:10" + propagate-environment: true + + - label: "🔧 Riot Tests" + agents: + # We use a medium sized instance instead of the normal small ones because + # webpack loves to gorge itself on resources. + queue: "medium" + command: + # Install chrome + - "echo '--- Installing Chrome'" + - "wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -" + - "sh -c 'echo \"deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main\" >> /etc/apt/sources.list.d/google.list'" + - "apt-get update" + - "apt-get install -y google-chrome-stable" + # Run tests + # TODO: Remove hacky chmod for BuildKite + - "chmod +x ./scripts/ci/*.sh" + - "chmod +x ./scripts/*" + - "echo '--- Installing Dependencies'" + - "./scripts/ci/install-deps.sh" + - "echo '+++ Running Tests'" + - "./scripts/ci/riot-unit-tests.sh" + env: + CHROME_BIN: "/usr/bin/google-chrome-stable" + plugins: + - docker#v3.0.1: + image: "node:10" + propagate-environment: true diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 2b57d4e9e2..6d1874b872 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -2,10 +2,7 @@ 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 @@ -21,7 +18,6 @@ src/components/views/create_room/RoomAlias.js src/components/views/dialogs/DeactivateAccountDialog.js src/components/views/dialogs/SetPasswordDialog.js src/components/views/dialogs/UnknownDeviceDialog.js -src/components/views/directory/NetworkDropdown.js src/components/views/elements/AddressSelector.js src/components/views/elements/DirectorySearchBox.js src/components/views/elements/ImageView.js @@ -31,15 +27,9 @@ 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 -src/components/views/room_settings/AliasSettings.js src/components/views/room_settings/ColorSettings.js src/components/views/rooms/Autocomplete.js src/components/views/rooms/AuxPanel.js @@ -48,30 +38,25 @@ 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/PinnedEventTile.js src/components/views/rooms/RoomList.js src/components/views/rooms/RoomPreviewBar.js -src/components/views/rooms/RoomSettings.js src/components/views/rooms/SearchableEntityList.js src/components/views/rooms/SearchBar.js src/components/views/rooms/SearchResultTile.js src/components/views/rooms/TopUnreadMessagesBar.js src/components/views/rooms/UserTile.js -src/components/views/settings/AddPhoneNumber.js src/components/views/settings/ChangeAvatar.js src/components/views/settings/ChangePassword.js src/components/views/settings/DevicesPanel.js src/components/views/settings/IntegrationsManager.js src/components/views/settings/Notifications.js -src/ContentMessages.js src/GroupAddressPicker.js 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 @@ -99,12 +84,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..fdf0bb351e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,6 +15,9 @@ module.exports = { "flowtype", "babel" ], + globals: { + LANGUAGES_FILE: "readonly", + }, env: { es6: true, }, @@ -42,9 +45,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. @@ -92,13 +94,13 @@ module.exports = { // to JSX. ignorePattern: '^\\s*<', ignoreComments: true, + ignoreRegExpLiterals: true, code: 120, }], "valid-jsdoc": ["warn"], "new-cap": ["warn"], "key-spacing": ["warn"], "prefer-const": ["warn"], - "arrow-parens": "off", // crashes currently: https://github.com/eslint/eslint/issues/6274 "generator-star-spacing": "off", diff --git a/.gitignore b/.gitignore index 6acf1b565a..7a3b1061b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ -npm-debug.log +/.npmrc +/*.log +package-lock.json /node_modules /lib -# version file and tarball created by 'npm pack' +# version file and tarball created by `npm pack` / `yarn pack` /git-revision.txt /matrix-react-sdk-*.tgz @@ -14,6 +16,3 @@ npm-debug.log /src/component-index.js .DS_Store - -# https://github.com/vector-im/riot-web/issues/7083 -package-lock.json diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0746cc0dff..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,35 +0,0 @@ -# we need trusty for the chrome addon -dist: trusty - -# we don't need sudo, so can run in a container, which makes startup much -# quicker. -# -# unfortunately we do temporarily require sudo as a workaround for -# https://github.com/travis-ci/travis-ci/issues/8836 -sudo: required - -language: node_js -node_js: - - node # Latest stable version of nodejs. -addons: - chrome: stable -install: - - ./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/CHANGELOG.md b/CHANGELOG.md index 742b8b4529..ef08c15a70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,1035 @@ +Changes in [1.0.6](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.6) (2019-04-01) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.6-rc.1...v1.0.6) + + * Handle storage fallback cases in consistency check + [\#2853](https://github.com/matrix-org/matrix-react-sdk/pull/2853) + * Set title attribute on images in lightbox + [\#2852](https://github.com/matrix-org/matrix-react-sdk/pull/2852) + * Download PDFs as blobs to avoid empty grey screens + [\#2851](https://github.com/matrix-org/matrix-react-sdk/pull/2851) + * Add MemberInfo for 3pid invites and support revoking those invites + [\#2850](https://github.com/matrix-org/matrix-react-sdk/pull/2850) + +Changes in [1.0.6-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.6-rc.1) (2019-03-27) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.5...v1.0.6-rc.1) + + * Catch errors when checking IndexedDB + [\#2836](https://github.com/matrix-org/matrix-react-sdk/pull/2836) + * Remove noreferrer on widget pop-out + [\#2835](https://github.com/matrix-org/matrix-react-sdk/pull/2835) + * Rework room directory so that new room is always available + [\#2834](https://github.com/matrix-org/matrix-react-sdk/pull/2834) + * Send telemetry about storage consistency + [\#2832](https://github.com/matrix-org/matrix-react-sdk/pull/2832) + * Widget OpenID reauth implementation + [\#2781](https://github.com/matrix-org/matrix-react-sdk/pull/2781) + * Log results of basic storage consistency check + [\#2826](https://github.com/matrix-org/matrix-react-sdk/pull/2826) + * Clarify devices affected by notification settings + [\#2828](https://github.com/matrix-org/matrix-react-sdk/pull/2828) + * Add a command for creating custom widgets without an integration manager + [\#2824](https://github.com/matrix-org/matrix-react-sdk/pull/2824) + * Minimize stickerpicker when the title is clicked + [\#2822](https://github.com/matrix-org/matrix-react-sdk/pull/2822) + * Add blocks around homeserver and identity server urls + [\#2825](https://github.com/matrix-org/matrix-react-sdk/pull/2825) + * Fixed drop shadow for tooltip. + [\#2815](https://github.com/matrix-org/matrix-react-sdk/pull/2815) + * Ask the user for debug logs when the timeline explodes + [\#2820](https://github.com/matrix-org/matrix-react-sdk/pull/2820) + * Fix typo preventing users from adding more widgets easily + [\#2823](https://github.com/matrix-org/matrix-react-sdk/pull/2823) + * Attach an onChange listener to the room's blacklist devices option + [\#2817](https://github.com/matrix-org/matrix-react-sdk/pull/2817) + * Use leaveRoomChain when leaving a room + [\#2818](https://github.com/matrix-org/matrix-react-sdk/pull/2818) + * Fix bug with NetworkList dropdown + [\#2821](https://github.com/matrix-org/matrix-react-sdk/pull/2821) + * Trim the logging for URL previews + [\#2816](https://github.com/matrix-org/matrix-react-sdk/pull/2816) + * Explicitly create `cryptoStore` in React SDK + [\#2814](https://github.com/matrix-org/matrix-react-sdk/pull/2814) + * Change to new consistent name for `MemoryStore` + [\#2812](https://github.com/matrix-org/matrix-react-sdk/pull/2812) + * Use medium agents for the more resource intensive builds + [\#2813](https://github.com/matrix-org/matrix-react-sdk/pull/2813) + * Add log grouping to buildkite + [\#2810](https://github.com/matrix-org/matrix-react-sdk/pull/2810) + * Switch to `git` protocol for CI dependencies + [\#2809](https://github.com/matrix-org/matrix-react-sdk/pull/2809) + * Go back to using mainine velocity + [\#2808](https://github.com/matrix-org/matrix-react-sdk/pull/2808) + * Warn that members won't be autojoined to upgraded rooms + [\#2796](https://github.com/matrix-org/matrix-react-sdk/pull/2796) + * Support CI for matching branches on forks + [\#2807](https://github.com/matrix-org/matrix-react-sdk/pull/2807) + * Discard old sticker picker when the URL changes + [\#2801](https://github.com/matrix-org/matrix-react-sdk/pull/2801) + * Reload widget messaging when widgets reload + [\#2799](https://github.com/matrix-org/matrix-react-sdk/pull/2799) + * Don't show calculated room name in room settings name input field + [\#2806](https://github.com/matrix-org/matrix-react-sdk/pull/2806) + * Disable big emoji for m.emote messages as it looks weird + [\#2805](https://github.com/matrix-org/matrix-react-sdk/pull/2805) + * Remove Edge from browser support statements + [\#2803](https://github.com/matrix-org/matrix-react-sdk/pull/2803) + * Update from Weblate + [\#2802](https://github.com/matrix-org/matrix-react-sdk/pull/2802) + * Really fix tag panel + [\#2800](https://github.com/matrix-org/matrix-react-sdk/pull/2800) + * Update CompatibilityPage to match officially supported browsers + [\#2793](https://github.com/matrix-org/matrix-react-sdk/pull/2793) + * Use Buildkite for CI + [\#2788](https://github.com/matrix-org/matrix-react-sdk/pull/2788) + * Fix CSS syntax errors preventing offline member opacity from working + [\#2794](https://github.com/matrix-org/matrix-react-sdk/pull/2794) + * Make the EntityTile chevron a masked SVG for theming + [\#2795](https://github.com/matrix-org/matrix-react-sdk/pull/2795) + * Remove refs from `RegistrationForm` + [\#2791](https://github.com/matrix-org/matrix-react-sdk/pull/2791) + * Fix initial letter avatar vertical offset in Firefox + [\#2792](https://github.com/matrix-org/matrix-react-sdk/pull/2792) + * Fix the custom tag panel + [\#2797](https://github.com/matrix-org/matrix-react-sdk/pull/2797) + * Ensure freshly invited members don't count towards the alone warning + [\#2786](https://github.com/matrix-org/matrix-react-sdk/pull/2786) + * Fix 'forgot password' warning to represent the reality of e2ee + [\#2787](https://github.com/matrix-org/matrix-react-sdk/pull/2787) + * Restore `Field` value getter for `RegistrationForm` + [\#2790](https://github.com/matrix-org/matrix-react-sdk/pull/2790) + * Initial portions of support for Field validation + [\#2780](https://github.com/matrix-org/matrix-react-sdk/pull/2780) + +Changes in [1.0.5](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.5) (2019-03-21) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.4...v1.0.5) + + * Hotfix: disable typing notifs jumping prevention for now + [\#2811](https://github.com/matrix-org/matrix-react-sdk/pull/2811) + +Changes in [1.0.4](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.4) (2019-03-18) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.4-rc.1...v1.0.4) + + * No changes since rc.1 + +Changes in [1.0.4-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.4-rc.1) (2019-03-13) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.3...v1.0.4-rc.1) + + * Update from Weblate + [\#2785](https://github.com/matrix-org/matrix-react-sdk/pull/2785) + * Remove padlock click handler to show unknown devices + [\#2784](https://github.com/matrix-org/matrix-react-sdk/pull/2784) + * Use modern Yarn version on Travis CI + [\#2783](https://github.com/matrix-org/matrix-react-sdk/pull/2783) + * Add versioning to integration manager API /register and /account calls + [\#2782](https://github.com/matrix-org/matrix-react-sdk/pull/2782) + * Ensure scalar_token is valid before opening integrations manager + [\#2777](https://github.com/matrix-org/matrix-react-sdk/pull/2777) + * Switch to `yarn` for dependency management + [\#2773](https://github.com/matrix-org/matrix-react-sdk/pull/2773) + * Use a distinct color for selected autocomplete items + [\#2778](https://github.com/matrix-org/matrix-react-sdk/pull/2778) + * Provide an escape from the registration process + [\#2775](https://github.com/matrix-org/matrix-react-sdk/pull/2775) + * Fix instantly sending RRs + [\#2770](https://github.com/matrix-org/matrix-react-sdk/pull/2770) + * Fix simple header counters to correctly handle zero, take two + [\#2776](https://github.com/matrix-org/matrix-react-sdk/pull/2776) + * Fix sticky hover state by listening for hover on the document + [\#2764](https://github.com/matrix-org/matrix-react-sdk/pull/2764) + * Fix header counters to correctly handle zero + [\#2772](https://github.com/matrix-org/matrix-react-sdk/pull/2772) + * Pass correct args when creating event permalink in context menu + [\#2774](https://github.com/matrix-org/matrix-react-sdk/pull/2774) + * Update from Weblate + [\#2771](https://github.com/matrix-org/matrix-react-sdk/pull/2771) + * Scroll investigation changes + [\#2766](https://github.com/matrix-org/matrix-react-sdk/pull/2766) + * Ability to bulk accept all invites (and fix rejecting all invites) + [\#2757](https://github.com/matrix-org/matrix-react-sdk/pull/2757) + * Don't trample over existing sessions when verifying email addresses + [\#2768](https://github.com/matrix-org/matrix-react-sdk/pull/2768) + * Misc fixes to StatusMessageContextMenu + [\#2767](https://github.com/matrix-org/matrix-react-sdk/pull/2767) + * Fix erroneously sending RRs, pt1. + [\#2769](https://github.com/matrix-org/matrix-react-sdk/pull/2769) + * Tweak country dropdown for redesign + [\#2765](https://github.com/matrix-org/matrix-react-sdk/pull/2765) + * Prevent space characters from stopping big emoji messages + [\#2745](https://github.com/matrix-org/matrix-react-sdk/pull/2745) + * Tweak auth components when dark theme is default + [\#2763](https://github.com/matrix-org/matrix-react-sdk/pull/2763) + * Move country dropdown inside field in Settings + [\#2756](https://github.com/matrix-org/matrix-react-sdk/pull/2756) + * npm audit fix --force + [\#2758](https://github.com/matrix-org/matrix-react-sdk/pull/2758) + * Use Field component in auth flows + [\#2749](https://github.com/matrix-org/matrix-react-sdk/pull/2749) + * Add /shrug command + [\#2660](https://github.com/matrix-org/matrix-react-sdk/pull/2660) + * Support linking to hosting providers + [\#2748](https://github.com/matrix-org/matrix-react-sdk/pull/2748) + * Get confirmation before enabling encryption + [\#2728](https://github.com/matrix-org/matrix-react-sdk/pull/2728) + * clear min-height for typing notifs when the timeline viewport changes size + [\#2747](https://github.com/matrix-org/matrix-react-sdk/pull/2747) + * Prevent flair pushing timeline downwards + [\#2746](https://github.com/matrix-org/matrix-react-sdk/pull/2746) + * Include tag name when warning about rooms running off lists + [\#2741](https://github.com/matrix-org/matrix-react-sdk/pull/2741) + * Reorganise props handling in Field + [\#2740](https://github.com/matrix-org/matrix-react-sdk/pull/2740) + * Limit Field label to size of input + [\#2742](https://github.com/matrix-org/matrix-react-sdk/pull/2742) + * Don't loop forever if you demote yourself via Enter on a PowerSelector + [\#2743](https://github.com/matrix-org/matrix-react-sdk/pull/2743) + * Check if users are already in the room before inviting them + [\#2734](https://github.com/matrix-org/matrix-react-sdk/pull/2734) + * Don't duplicate direct chats from other tags + [\#2735](https://github.com/matrix-org/matrix-react-sdk/pull/2735) + * Fix media device selectors not updating + [\#2739](https://github.com/matrix-org/matrix-react-sdk/pull/2739) + * Fix Room Directory custom homeserver entry not showing properly + [\#2708](https://github.com/matrix-org/matrix-react-sdk/pull/2708) + * Add missing permalinkCreator prop + [\#2729](https://github.com/matrix-org/matrix-react-sdk/pull/2729) + * Patch users not existing when opening settings + [\#2738](https://github.com/matrix-org/matrix-react-sdk/pull/2738) + * Use a mask for the continuation icon + [\#2737](https://github.com/matrix-org/matrix-react-sdk/pull/2737) + * Always insert rooms into lists when they get lost + [\#2736](https://github.com/matrix-org/matrix-react-sdk/pull/2736) + * Convert objects and such to usable strings in rageshake + [\#2732](https://github.com/matrix-org/matrix-react-sdk/pull/2732) + * Support stacking dialogs to prevent unmounting + [\#2724](https://github.com/matrix-org/matrix-react-sdk/pull/2724) + * Convert PowerSelector to use mxField instead + [\#2725](https://github.com/matrix-org/matrix-react-sdk/pull/2725) + * Don't re-enable the save button after saving profiles + [\#2726](https://github.com/matrix-org/matrix-react-sdk/pull/2726) + * Support multiple email pushers and remove the legacy UserSettingsStore + [\#2727](https://github.com/matrix-org/matrix-react-sdk/pull/2727) + * Bring back #528 fix as it still seems broken on OSX + [\#2731](https://github.com/matrix-org/matrix-react-sdk/pull/2731) + * Fix margin on e2e icon in member panel + [\#2721](https://github.com/matrix-org/matrix-react-sdk/pull/2721) + * Improved scrolling & pagination + [\#2676](https://github.com/matrix-org/matrix-react-sdk/pull/2676) + * Nudge karma to 3.1.2 + [\#2719](https://github.com/matrix-org/matrix-react-sdk/pull/2719) + * Stop listening to account data when the stickerpicker is unmounted + [\#2723](https://github.com/matrix-org/matrix-react-sdk/pull/2723) + +Changes in [1.0.3](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.3) (2019-03-06) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.2...v1.0.3) + + * Don't duplicate direct chats from other tags + [\#2762](https://github.com/matrix-org/matrix-react-sdk/pull/2762) + * Include tag name when warning about rooms running off lists + [\#2761](https://github.com/matrix-org/matrix-react-sdk/pull/2761) + * Always insert rooms into lists when they get lost + [\#2760](https://github.com/matrix-org/matrix-react-sdk/pull/2760) + * Fix the ctrl+k shortcut + [\#2759](https://github.com/matrix-org/matrix-react-sdk/pull/2759) + +Changes in [1.0.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.2) (2019-03-06) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.2-rc.4...v1.0.2) + + * Only show hosting link if group admin + [\#2755](https://github.com/matrix-org/matrix-react-sdk/pull/2755) + * Only show hosting link if domain == matrix.org + [\#2754](https://github.com/matrix-org/matrix-react-sdk/pull/2754) + +Changes in [1.0.2-rc.4](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.2-rc.4) (2019-03-05) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.2-rc.3...v1.0.2-rc.4) + + * Patch users not existing when opening settings + [\#2752](https://github.com/matrix-org/matrix-react-sdk/pull/2752) + * Fix media device selectors not updating + [\#2751](https://github.com/matrix-org/matrix-react-sdk/pull/2751) + * Support linking to hosting providers + [\#2750](https://github.com/matrix-org/matrix-react-sdk/pull/2750) + +Changes in [1.0.2-rc.3](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.2-rc.3) (2019-03-01) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.2-rc.2...v1.0.2-rc.3) + + * Misc room list improvements & invite fix + [\#2722](https://github.com/matrix-org/matrix-react-sdk/pull/2722) + * Move complex part of room sorting to a dedicated function + [\#2716](https://github.com/matrix-org/matrix-react-sdk/pull/2716) + +Changes in [1.0.2-rc.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.2-rc.2) (2019-03-01) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.2-rc.1...v1.0.2-rc.2) + + * Use webpack alias to resolve the languages file + [\#2730](https://github.com/matrix-org/matrix-react-sdk/pull/2730) + +Changes in [1.0.2-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.2-rc.1) (2019-02-28) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.1...v1.0.2-rc.1) + + * Remove unnecessary ref from Stickerpicker + [\#2718](https://github.com/matrix-org/matrix-react-sdk/pull/2718) + * Update from Weblate + [\#2720](https://github.com/matrix-org/matrix-react-sdk/pull/2720) + * Update from Weblate. + [\#2715](https://github.com/matrix-org/matrix-react-sdk/pull/2715) + * Show nearest lower badge, e.g show Mod for 51... etc + [\#2709](https://github.com/matrix-org/matrix-react-sdk/pull/2709) + * Send Field label pointer events to input + [\#2714](https://github.com/matrix-org/matrix-react-sdk/pull/2714) + * move canSendMessages into state so that it will re-render the composer + [\#2710](https://github.com/matrix-org/matrix-react-sdk/pull/2710) + * Use a global WatchManager for settings + [\#2705](https://github.com/matrix-org/matrix-react-sdk/pull/2705) + * Move non-feather icons out of feather dir + [\#2706](https://github.com/matrix-org/matrix-react-sdk/pull/2706) + * Fix backup button in logout dialog + [\#2713](https://github.com/matrix-org/matrix-react-sdk/pull/2713) + * Keep registration spinner inside the auth modal + [\#2712](https://github.com/matrix-org/matrix-react-sdk/pull/2712) + * Try to clarify that "Show read receipts" is just for visibility + [\#2707](https://github.com/matrix-org/matrix-react-sdk/pull/2707) + * Make sure direct chat invites are treated as invites + [\#2711](https://github.com/matrix-org/matrix-react-sdk/pull/2711) + * Report validity state of all registration fields on any change + [\#2672](https://github.com/matrix-org/matrix-react-sdk/pull/2672) + * Export the defaults for SdkConfig + [\#2687](https://github.com/matrix-org/matrix-react-sdk/pull/2687) + * Change the room list algo to eagerly delete and carefully insert + [\#2701](https://github.com/matrix-org/matrix-react-sdk/pull/2701) + * Improve permalink performance + [\#2671](https://github.com/matrix-org/matrix-react-sdk/pull/2671) + * Normalise room list font weight, bold unreads + [\#2702](https://github.com/matrix-org/matrix-react-sdk/pull/2702) + * Settings button in Room Context Menu + [\#2692](https://github.com/matrix-org/matrix-react-sdk/pull/2692) + * add roomnick SlashCommand + [\#2689](https://github.com/matrix-org/matrix-react-sdk/pull/2689) + * replace text Inputs in Devtools with Field bcuz prettier + [\#2697](https://github.com/matrix-org/matrix-react-sdk/pull/2697) + * Maintenance: Clean up some stuff around settings + [\#2685](https://github.com/matrix-org/matrix-react-sdk/pull/2685) + * Support the old room sorting algorithm and SettingsStore watchers + [\#2686](https://github.com/matrix-org/matrix-react-sdk/pull/2686) + * pin highlight.js as they seem to have broken something in 9.15.2 + [\#2703](https://github.com/matrix-org/matrix-react-sdk/pull/2703) + * Fix NPE relating to toggling notifications + [\#2699](https://github.com/matrix-org/matrix-react-sdk/pull/2699) + * Only set e2e info callback if the event is encrypted + [\#2684](https://github.com/matrix-org/matrix-react-sdk/pull/2684) + * Revert "Add some logging for riot-web#7838" + [\#2700](https://github.com/matrix-org/matrix-react-sdk/pull/2700) + * Add abilities to clear Filter room members input + [\#2698](https://github.com/matrix-org/matrix-react-sdk/pull/2698) + * make ViewSource less awkward + [\#2696](https://github.com/matrix-org/matrix-react-sdk/pull/2696) + * Fix share community for guests + [\#2695](https://github.com/matrix-org/matrix-react-sdk/pull/2695) + * Fix z ordering of the overflow tile + [\#2694](https://github.com/matrix-org/matrix-react-sdk/pull/2694) + * Toggle Search using Room Header button + [\#2693](https://github.com/matrix-org/matrix-react-sdk/pull/2693) + * view user on click typing tile + [\#2691](https://github.com/matrix-org/matrix-react-sdk/pull/2691) + * Change Share Message to Share Permalink if !m.room.message||redacted + [\#2690](https://github.com/matrix-org/matrix-react-sdk/pull/2690) + * Allow configuration of whether closing window closes or minimizes to tray + [\#2688](https://github.com/matrix-org/matrix-react-sdk/pull/2688) + * Remove duplicated conversion from `enableRichText` + [\#2682](https://github.com/matrix-org/matrix-react-sdk/pull/2682) + * Use correct initial phase for server type + [\#2683](https://github.com/matrix-org/matrix-react-sdk/pull/2683) + * Fix AliasSettings and RelatedGroups UX + [\#2679](https://github.com/matrix-org/matrix-react-sdk/pull/2679) + * Add `onClick` to Markdown buttons + [\#2677](https://github.com/matrix-org/matrix-react-sdk/pull/2677) + * Fix toggle for email notifications + [\#2678](https://github.com/matrix-org/matrix-react-sdk/pull/2678) + * Fix categorization of favourites and new rooms + [\#2681](https://github.com/matrix-org/matrix-react-sdk/pull/2681) + * Skip server details on registration with a default HS + [\#2675](https://github.com/matrix-org/matrix-react-sdk/pull/2675) + * Clarify what the username error refers to + [\#2673](https://github.com/matrix-org/matrix-react-sdk/pull/2673) + * RoomDirectory Dropdown should use roomDirectory.servers + [\#2680](https://github.com/matrix-org/matrix-react-sdk/pull/2680) + * Fix favourites losing rooms and sorting weirdly + [\#2674](https://github.com/matrix-org/matrix-react-sdk/pull/2674) + * "Breadcrumb" room sorting algorithm + [\#2634](https://github.com/matrix-org/matrix-react-sdk/pull/2634) + * Bring back user view + [\#2666](https://github.com/matrix-org/matrix-react-sdk/pull/2666) + * Restores support for `default_server_name` which discovers URLs via `.well- + known` + [\#2669](https://github.com/matrix-org/matrix-react-sdk/pull/2669) + * Remove unreferenced images + [\#2670](https://github.com/matrix-org/matrix-react-sdk/pull/2670) + * Only show the first line of each commit in changelog dialog + [\#2667](https://github.com/matrix-org/matrix-react-sdk/pull/2667) + * Cache-bust languages.json with file-loader + [\#2658](https://github.com/matrix-org/matrix-react-sdk/pull/2658) + * Fix off by one error for username colors + [\#2664](https://github.com/matrix-org/matrix-react-sdk/pull/2664) + * Set event-sending-color in dark theme + [\#2665](https://github.com/matrix-org/matrix-react-sdk/pull/2665) + * Allow captchas on Riot desktop builds + [\#2663](https://github.com/matrix-org/matrix-react-sdk/pull/2663) + * Show link to login even during UI auth + [\#2661](https://github.com/matrix-org/matrix-react-sdk/pull/2661) + * Dark theme follow ups round 2 + [\#2659](https://github.com/matrix-org/matrix-react-sdk/pull/2659) + * Rename default theme to light theme + [\#2662](https://github.com/matrix-org/matrix-react-sdk/pull/2662) + * make mx_SenderProfile inline-block, reduces clickable area around usernames + [\#2653](https://github.com/matrix-org/matrix-react-sdk/pull/2653) + * Add a bit of safety around reading events for room settings + [\#2648](https://github.com/matrix-org/matrix-react-sdk/pull/2648) + * Update dark theme bg-color to show hover effect on messages + [\#2654](https://github.com/matrix-org/matrix-react-sdk/pull/2654) + * Make pre use the same text color as code + [\#2655](https://github.com/matrix-org/matrix-react-sdk/pull/2655) + * Bring back the lowered opacity for offline/unavailable avatars. + [\#2649](https://github.com/matrix-org/matrix-react-sdk/pull/2649) + * Set h3-color in dark theme + [\#2656](https://github.com/matrix-org/matrix-react-sdk/pull/2656) + * Fix typo "Scisors" -> "Scissors" + [\#2652](https://github.com/matrix-org/matrix-react-sdk/pull/2652) + * highlight e2e icon on event when hovering whole event + [\#2647](https://github.com/matrix-org/matrix-react-sdk/pull/2647) + * Skinnified more icons + [\#2633](https://github.com/matrix-org/matrix-react-sdk/pull/2633) + +Changes in [1.0.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.1) (2019-02-15) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.0...v1.0.1) + + * Fix community invites crashing the app + [\#2650](https://github.com/matrix-org/matrix-react-sdk/pull/2650) + +Changes in [1.0.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.0) (2019-02-14) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.0-rc.2...v1.0.0) + + * Update from Weblate. + [\#2646](https://github.com/matrix-org/matrix-react-sdk/pull/2646) + * Remove 'welcome' from top-left menu + [\#2641](https://github.com/matrix-org/matrix-react-sdk/pull/2641) + * Turn on pin unread rooms for everyone + [\#2645](https://github.com/matrix-org/matrix-react-sdk/pull/2645) + * Update help buoy text and issue links + [\#2640](https://github.com/matrix-org/matrix-react-sdk/pull/2640) + * Fix icons being cut off in settings + [\#2644](https://github.com/matrix-org/matrix-react-sdk/pull/2644) + * Add credit for cover photo usage + [\#2643](https://github.com/matrix-org/matrix-react-sdk/pull/2643) + * make e2e icons on message transparent + [\#2642](https://github.com/matrix-org/matrix-react-sdk/pull/2642) + * fix close button being half off screen + [\#2639](https://github.com/matrix-org/matrix-react-sdk/pull/2639) + * Fix excessive timeline whitespace + [\#2638](https://github.com/matrix-org/matrix-react-sdk/pull/2638) + * Remove the white screen of welcome + [\#2637](https://github.com/matrix-org/matrix-react-sdk/pull/2637) + * always rerender room tiles + [\#2636](https://github.com/matrix-org/matrix-react-sdk/pull/2636) + +Changes in [1.0.0-rc.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.0-rc.2) (2019-02-14) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.0-rc.1...v1.0.0-rc.2) + + * Update from Weblate. + [\#2635](https://github.com/matrix-org/matrix-react-sdk/pull/2635) + * use throttle as its more responsive + [\#2632](https://github.com/matrix-org/matrix-react-sdk/pull/2632) + * update range when items size changes + [\#2631](https://github.com/matrix-org/matrix-react-sdk/pull/2631) + * Fix registration after clicking email link + [\#2630](https://github.com/matrix-org/matrix-react-sdk/pull/2630) + * Re-check key backup status when settings opened + [\#2626](https://github.com/matrix-org/matrix-react-sdk/pull/2626) + * Improve room list rendering performance + [\#2629](https://github.com/matrix-org/matrix-react-sdk/pull/2629) + * Adjust top left menu items + [\#2628](https://github.com/matrix-org/matrix-react-sdk/pull/2628) + * Normalised icon strokes to 1px + [\#2627](https://github.com/matrix-org/matrix-react-sdk/pull/2627) + * Security: Force TURN setting was inverted + [\#2623](https://github.com/matrix-org/matrix-react-sdk/pull/2623) + * Add redesigned dark theme + [\#2619](https://github.com/matrix-org/matrix-react-sdk/pull/2619) + * Fix mx_RoomTile_name weighting + [\#2610](https://github.com/matrix-org/matrix-react-sdk/pull/2610) + * Add divider between tabs and regular buttons in room header + [\#2621](https://github.com/matrix-org/matrix-react-sdk/pull/2621) + * Update from Weblate. + [\#2622](https://github.com/matrix-org/matrix-react-sdk/pull/2622) + * Change taking a community off the left-left panel less scary + [\#2609](https://github.com/matrix-org/matrix-react-sdk/pull/2609) + * Fixes and styling related to e2e icons and dialogs + [\#2620](https://github.com/matrix-org/matrix-react-sdk/pull/2620) + * Fix: stickers layout + [\#2618](https://github.com/matrix-org/matrix-react-sdk/pull/2618) + * Fix: dont assume settings label only has one line + [\#2616](https://github.com/matrix-org/matrix-react-sdk/pull/2616) + * Labs feature: recent room breadcrumbs + [\#2615](https://github.com/matrix-org/matrix-react-sdk/pull/2615) + * Fix: roomlist reordering lags + [\#2612](https://github.com/matrix-org/matrix-react-sdk/pull/2612) + * Change text in e2e UX to new copy + [\#2617](https://github.com/matrix-org/matrix-react-sdk/pull/2617) + * Add display name / avatar to incoming sas dialog + [\#2613](https://github.com/matrix-org/matrix-react-sdk/pull/2613) + * Restore backup on new recovery method dialog + [\#2614](https://github.com/matrix-org/matrix-react-sdk/pull/2614) + * Welcome page cleanup + [\#2611](https://github.com/matrix-org/matrix-react-sdk/pull/2611) + * Scale up settings UI to be easier to read + [\#2604](https://github.com/matrix-org/matrix-react-sdk/pull/2604) + * !important shouldn't have a space + [\#2608](https://github.com/matrix-org/matrix-react-sdk/pull/2608) + * Add legacy verification button on wait + [\#2607](https://github.com/matrix-org/matrix-react-sdk/pull/2607) + * Update from Weblate. + [\#2606](https://github.com/matrix-org/matrix-react-sdk/pull/2606) + +Changes in [1.0.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.0-rc.1) (2019-02-08) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.14.8...v1.0.0-rc.1) + + * Call isGuest correctly + [\#2603](https://github.com/matrix-org/matrix-react-sdk/pull/2603) + * Update from Weblate. + [\#2602](https://github.com/matrix-org/matrix-react-sdk/pull/2602) + * Prompt to restore backup rather than verify + [\#2594](https://github.com/matrix-org/matrix-react-sdk/pull/2594) + * Remove key backup & sas from labs + [\#2599](https://github.com/matrix-org/matrix-react-sdk/pull/2599) + * Update avatar colors + [\#2600](https://github.com/matrix-org/matrix-react-sdk/pull/2600) + * Fix: typeerror when creating DM + [\#2601](https://github.com/matrix-org/matrix-react-sdk/pull/2601) + * Render disabled mxField textareas as disabled + [\#2591](https://github.com/matrix-org/matrix-react-sdk/pull/2591) + * SDK support for welcome page + [\#2597](https://github.com/matrix-org/matrix-react-sdk/pull/2597) + * Change SAS to decimal / emoji + [\#2596](https://github.com/matrix-org/matrix-react-sdk/pull/2596) + * Render join rules and guest access changes in the timeline + [\#2592](https://github.com/matrix-org/matrix-react-sdk/pull/2592) + * Ensure toggle switches listen to property changes + [\#2590](https://github.com/matrix-org/matrix-react-sdk/pull/2590) + * Local echo on room access settings + [\#2593](https://github.com/matrix-org/matrix-react-sdk/pull/2593) + * guard custom tags with feature flag + [\#2589](https://github.com/matrix-org/matrix-react-sdk/pull/2589) + * remove ll feature flag, it's time! + [\#2588](https://github.com/matrix-org/matrix-react-sdk/pull/2588) + * Trust on decrypt + [\#2583](https://github.com/matrix-org/matrix-react-sdk/pull/2583) + * Remove click-to-verify from SAS + [\#2586](https://github.com/matrix-org/matrix-react-sdk/pull/2586) + * Fix: make sure custom tag scroller doesn't overflow parent + [\#2587](https://github.com/matrix-org/matrix-react-sdk/pull/2587) + * Fix: throttle custom tags updating in LLP + [\#2585](https://github.com/matrix-org/matrix-react-sdk/pull/2585) + * Fix firefox scrolling settings tabs differently + [\#2579](https://github.com/matrix-org/matrix-react-sdk/pull/2579) + * Actually change power levels when they are changed + [\#2580](https://github.com/matrix-org/matrix-react-sdk/pull/2580) + * Fix: logging in again breaks CustomRoomTagStore + [\#2584](https://github.com/matrix-org/matrix-react-sdk/pull/2584) + * Fix: click on notif badge + [\#2582](https://github.com/matrix-org/matrix-react-sdk/pull/2582) + * Extend slash command '/topic' to display the room topic + [\#2532](https://github.com/matrix-org/matrix-react-sdk/pull/2532) + * Fix: community badges + [\#2581](https://github.com/matrix-org/matrix-react-sdk/pull/2581) + * Bring back custom tags, also badges on communities + [\#2575](https://github.com/matrix-org/matrix-react-sdk/pull/2575) + * Style reset password to match design + [\#2578](https://github.com/matrix-org/matrix-react-sdk/pull/2578) + * Key Backup: Don't fail if no keys + [\#2577](https://github.com/matrix-org/matrix-react-sdk/pull/2577) + * Remove old user and room settings + [\#2554](https://github.com/matrix-org/matrix-react-sdk/pull/2554) + * increase debouncing of filtering because its quite laggy atm + [\#2576](https://github.com/matrix-org/matrix-react-sdk/pull/2576) + * Tweak field padding to avoid overlapping with selected text + [\#2573](https://github.com/matrix-org/matrix-react-sdk/pull/2573) + * Adapt login flow for the v2 design + [\#2574](https://github.com/matrix-org/matrix-react-sdk/pull/2574) + * Remove the arrow-paren lint rule + [\#2572](https://github.com/matrix-org/matrix-react-sdk/pull/2572) + * Ensure we show registration form when custom URLs are disabled + [\#2571](https://github.com/matrix-org/matrix-react-sdk/pull/2571) + * Fix: search term disappears when collapsing and expanding left panel + [\#2568](https://github.com/matrix-org/matrix-react-sdk/pull/2568) + * Fix: 'jump to bottom' creates big amounts of whitespace at the bottom + [\#2567](https://github.com/matrix-org/matrix-react-sdk/pull/2567) + * Fix: being able to size sections in leftpanel larger than their content + while filtering + [\#2566](https://github.com/matrix-org/matrix-react-sdk/pull/2566) + * Redesign: widget makeover + [\#2565](https://github.com/matrix-org/matrix-react-sdk/pull/2565) + * Restore dropdown chevron to right + [\#2564](https://github.com/matrix-org/matrix-react-sdk/pull/2564) + * Remove warning about encryption being beta + [\#2563](https://github.com/matrix-org/matrix-react-sdk/pull/2563) + * Add e2e icon to room header/composer/member info, more ... + [\#2557](https://github.com/matrix-org/matrix-react-sdk/pull/2557) + * Remove guest warning bar + [\#2562](https://github.com/matrix-org/matrix-react-sdk/pull/2562) + * Style tweaks to support auth background + [\#2561](https://github.com/matrix-org/matrix-react-sdk/pull/2561) + * Set a minimum width on the settings tab content + [\#2560](https://github.com/matrix-org/matrix-react-sdk/pull/2560) + * Fix exception while saving room settings + [\#2555](https://github.com/matrix-org/matrix-react-sdk/pull/2555) + * Disable old settings, making tabbed settings the default + [\#2559](https://github.com/matrix-org/matrix-react-sdk/pull/2559) + * fix UnknownDeviceDialog layout + [\#2558](https://github.com/matrix-org/matrix-react-sdk/pull/2558) + * Misc fixes to settings + [\#2553](https://github.com/matrix-org/matrix-react-sdk/pull/2553) + * Add error message when registration is disabled + [\#2548](https://github.com/matrix-org/matrix-react-sdk/pull/2548) + * Hide registration fields that aren't used by any flow + [\#2551](https://github.com/matrix-org/matrix-react-sdk/pull/2551) + * Ensure correct server URLs with .well-known and server type + [\#2547](https://github.com/matrix-org/matrix-react-sdk/pull/2547) + * Spell homeserver correctly + [\#2552](https://github.com/matrix-org/matrix-react-sdk/pull/2552) + * Auto-focus username on registration + [\#2546](https://github.com/matrix-org/matrix-react-sdk/pull/2546) + * Fixed settings dialog header; Adjust padding on dialog + [\#2549](https://github.com/matrix-org/matrix-react-sdk/pull/2549) + * Fix empty lightbox when there is no avatarUrl + [\#2314](https://github.com/matrix-org/matrix-react-sdk/pull/2314) + * make overflow gradients much smaller and turn bottom into drop shadow + [\#2544](https://github.com/matrix-org/matrix-react-sdk/pull/2544) + * Make auth validation less annoying + [\#2539](https://github.com/matrix-org/matrix-react-sdk/pull/2539) + * layout composer independent of avatar being present + [\#2545](https://github.com/matrix-org/matrix-react-sdk/pull/2545) + * Matthew/cyrillic + [\#2543](https://github.com/matrix-org/matrix-react-sdk/pull/2543) + * Allow expanding the left panel manually when in narrow mode + [\#2541](https://github.com/matrix-org/matrix-react-sdk/pull/2541) + * Redesign: community page cleanup + [\#2538](https://github.com/matrix-org/matrix-react-sdk/pull/2538) + * Redesign: Disable ILAG + [\#2536](https://github.com/matrix-org/matrix-react-sdk/pull/2536) + * Use custom appearance and arrow for field selects + [\#2540](https://github.com/matrix-org/matrix-react-sdk/pull/2540) + * Fix typo + [\#2537](https://github.com/matrix-org/matrix-react-sdk/pull/2537) + * Merge redesign into develop + [\#2535](https://github.com/matrix-org/matrix-react-sdk/pull/2535) + * disable e2e tests everywhere as redesign breaks them for now + [\#2534](https://github.com/matrix-org/matrix-react-sdk/pull/2534) + * avoid horizontal scrollbar in composer when placeholder doesn't fit + [\#2533](https://github.com/matrix-org/matrix-react-sdk/pull/2533) + * fix dropdown style when input is shown + [\#2531](https://github.com/matrix-org/matrix-react-sdk/pull/2531) + * Redesign: tiny fix: stretch device label in member info if content doesn't + fill it + [\#2530](https://github.com/matrix-org/matrix-react-sdk/pull/2530) + * Style registration flow + [\#2527](https://github.com/matrix-org/matrix-react-sdk/pull/2527) + * Redesign: small member info panel makeover + [\#2522](https://github.com/matrix-org/matrix-react-sdk/pull/2522) + * Render the home page when viewing the directory + [\#2529](https://github.com/matrix-org/matrix-react-sdk/pull/2529) + * Fix indentation on all new settings CSS + [\#2528](https://github.com/matrix-org/matrix-react-sdk/pull/2528) + * Round 1 of misc fixes for settings + [\#2526](https://github.com/matrix-org/matrix-react-sdk/pull/2526) + * Implement the Security & Privacy tab of new room settings + [\#2523](https://github.com/matrix-org/matrix-react-sdk/pull/2523) + * Implement the Advanced tab of new room settings + [\#2525](https://github.com/matrix-org/matrix-react-sdk/pull/2525) + * Implement the Roles & Permissions tab of new room settings + [\#2524](https://github.com/matrix-org/matrix-react-sdk/pull/2524) + * Redesign: room directory makeover + [\#2519](https://github.com/matrix-org/matrix-react-sdk/pull/2519) + * Iterate upon the room upgrade warning bar + [\#2518](https://github.com/matrix-org/matrix-react-sdk/pull/2518) + * redesign: small fixes + [\#2520](https://github.com/matrix-org/matrix-react-sdk/pull/2520) + * Implement the "general" tab of new room settings + [\#2516](https://github.com/matrix-org/matrix-react-sdk/pull/2516) + * Tweak auth overflow on Windows and Linux + [\#2521](https://github.com/matrix-org/matrix-react-sdk/pull/2521) + * Redesign: switch layout when filtering room sublists + [\#2515](https://github.com/matrix-org/matrix-react-sdk/pull/2515) + * Make native scrollbars prettier + [\#2470](https://github.com/matrix-org/matrix-react-sdk/pull/2470) + * Add server type selector and style login flow + [\#2517](https://github.com/matrix-org/matrix-react-sdk/pull/2517) + * Implement flair tab in user settings + [\#2512](https://github.com/matrix-org/matrix-react-sdk/pull/2512) + * Override UA/OS styles for disabled Field selects + [\#2502](https://github.com/matrix-org/matrix-react-sdk/pull/2502) + * Be more positive with setting labels + [\#2504](https://github.com/matrix-org/matrix-react-sdk/pull/2504) + * Redesign: new roomlist layout fixes + [\#2514](https://github.com/matrix-org/matrix-react-sdk/pull/2514) + * Redesign: new layout algorithm for room sublists. + [\#2507](https://github.com/matrix-org/matrix-react-sdk/pull/2507) + * Short-Authentication-String Verification + [\#2461](https://github.com/matrix-org/matrix-react-sdk/pull/2461) + * Fix unmount TypeError in `DeviceVerifyButtons` + [\#2513](https://github.com/matrix-org/matrix-react-sdk/pull/2513) + * Remove support for team servers + [\#2511](https://github.com/matrix-org/matrix-react-sdk/pull/2511) + * Initial structure for new room settings + [\#2510](https://github.com/matrix-org/matrix-react-sdk/pull/2510) + * Tweak wording on logout warning + [\#2509](https://github.com/matrix-org/matrix-react-sdk/pull/2509) + * Fix NPE in RoomRecoveryReminder + [\#2508](https://github.com/matrix-org/matrix-react-sdk/pull/2508) + * New text/caption for key backup by verifying device + [\#2506](https://github.com/matrix-org/matrix-react-sdk/pull/2506) + * Implement the "Security & Privacy" tab of new user settings + [\#2499](https://github.com/matrix-org/matrix-react-sdk/pull/2499) + * Add simple animations to toggle switches + [\#2505](https://github.com/matrix-org/matrix-react-sdk/pull/2505) + * Default a Field's placeholder to the label + [\#2503](https://github.com/matrix-org/matrix-react-sdk/pull/2503) + * Have the settings dialog be fixed in size + [\#2501](https://github.com/matrix-org/matrix-react-sdk/pull/2501) + * Implement the "Help & About" tab of new user settings + [\#2500](https://github.com/matrix-org/matrix-react-sdk/pull/2500) + * Implement the "Voice & Video" tab of new user settings + [\#2498](https://github.com/matrix-org/matrix-react-sdk/pull/2498) + * Add widget screenshots to the Labs section + [\#2497](https://github.com/matrix-org/matrix-react-sdk/pull/2497) + * Implement the "Preferences" tab on new user settings + [\#2495](https://github.com/matrix-org/matrix-react-sdk/pull/2495) + * Add target="_blank" to links that don't have it + [\#2496](https://github.com/matrix-org/matrix-react-sdk/pull/2496) + * Implement the "Notifications" tab of new user settings + [\#2494](https://github.com/matrix-org/matrix-react-sdk/pull/2494) + * Implement the "Labs" tab of new user settings + [\#2492](https://github.com/matrix-org/matrix-react-sdk/pull/2492) + * Implement the "General" tab of new user settings + [\#2491](https://github.com/matrix-org/matrix-react-sdk/pull/2491) + * Appease linter in auth related files + [\#2493](https://github.com/matrix-org/matrix-react-sdk/pull/2493) + * Update text and links in authentication flows + [\#2489](https://github.com/matrix-org/matrix-react-sdk/pull/2489) + * Move LanguageSelector to views + [\#2490](https://github.com/matrix-org/matrix-react-sdk/pull/2490) + * Restyle auth page language selector + [\#2488](https://github.com/matrix-org/matrix-react-sdk/pull/2488) + * Fix desktop captcha check + [\#2487](https://github.com/matrix-org/matrix-react-sdk/pull/2487) + * Basic structure for tabbed user settings + [\#2476](https://github.com/matrix-org/matrix-react-sdk/pull/2476) + * Token encouragement if zxcvbn gives no feedback + [\#2471](https://github.com/matrix-org/matrix-react-sdk/pull/2471) + * Fix: show rooms and people section when empty while filtering + [\#2481](https://github.com/matrix-org/matrix-react-sdk/pull/2481) + * Fix AuthFooter CSS rules conflicting with anchors all over the app + [\#2486](https://github.com/matrix-org/matrix-react-sdk/pull/2486) + * Support selects on Field + [\#2484](https://github.com/matrix-org/matrix-react-sdk/pull/2484) + * Fix integrations server error popup being hidden behind right panel + [\#2482](https://github.com/matrix-org/matrix-react-sdk/pull/2482) + * Fix: apparently room can be null here + [\#2480](https://github.com/matrix-org/matrix-react-sdk/pull/2480) + * Redesign: pull jump to bottom button out of room status bar + [\#2478](https://github.com/matrix-org/matrix-react-sdk/pull/2478) + * Redesign: set default size of 350px for left panel + [\#2479](https://github.com/matrix-org/matrix-react-sdk/pull/2479) + * Avoid "jumpiness" with inline typing indicator + [\#2456](https://github.com/matrix-org/matrix-react-sdk/pull/2456) + * De-lint CompatabilityPage & LoggedInView + [\#2472](https://github.com/matrix-org/matrix-react-sdk/pull/2472) + * Remove Status theme-specific hacks + [\#2473](https://github.com/matrix-org/matrix-react-sdk/pull/2473) + * Error if no sessions decrypted + [\#2469](https://github.com/matrix-org/matrix-react-sdk/pull/2469) + * Fix settings direct chat + [\#2466](https://github.com/matrix-org/matrix-react-sdk/pull/2466) + * Show verify button when we have a device to verify + [\#2464](https://github.com/matrix-org/matrix-react-sdk/pull/2464) + * Redesign: Add a form field component + [\#2463](https://github.com/matrix-org/matrix-react-sdk/pull/2463) + * Load fonts and images via source-relative URLs and requires + [\#2460](https://github.com/matrix-org/matrix-react-sdk/pull/2460) + * Say when backup is signed by unknown device + [\#2455](https://github.com/matrix-org/matrix-react-sdk/pull/2455) + * Add an /upgraderoom command to make upgrading easier for development + [\#2458](https://github.com/matrix-org/matrix-react-sdk/pull/2458) + * Merge develop->experimental + [\#2457](https://github.com/matrix-org/matrix-react-sdk/pull/2457) + * Fix: show hand cursor in topleft menu so its clear you can click it + [\#2454](https://github.com/matrix-org/matrix-react-sdk/pull/2454) + * Fix: search makeover missing icons + [\#2453](https://github.com/matrix-org/matrix-react-sdk/pull/2453) + * Redesign: search makeover + [\#2448](https://github.com/matrix-org/matrix-react-sdk/pull/2448) + * Revert "Tiled room UI" + [\#2451](https://github.com/matrix-org/matrix-react-sdk/pull/2451) + * Update from Weblate. + [\#2452](https://github.com/matrix-org/matrix-react-sdk/pull/2452) + * Improve room sublist resizing + [\#2440](https://github.com/matrix-org/matrix-react-sdk/pull/2440) + * Different dialog for new trusted backup + [\#2435](https://github.com/matrix-org/matrix-react-sdk/pull/2435) + * De-lint a few more files + [\#2436](https://github.com/matrix-org/matrix-react-sdk/pull/2436) + * Recalculate the visible rooms when rooms are upgraded + [\#2433](https://github.com/matrix-org/matrix-react-sdk/pull/2433) + * Navigate to the upgraded room's create event where possible + [\#2432](https://github.com/matrix-org/matrix-react-sdk/pull/2432) + * Don't show rooms with tombstones in the address picker + [\#2429](https://github.com/matrix-org/matrix-react-sdk/pull/2429) + * Add separate dialog for recovery method removed + [\#2427](https://github.com/matrix-org/matrix-react-sdk/pull/2427) + * Set which servers to try and join upgraded rooms through + [\#2428](https://github.com/matrix-org/matrix-react-sdk/pull/2428) + * Render a tile for tombstone events + [\#2430](https://github.com/matrix-org/matrix-react-sdk/pull/2430) + * Regenerate en_EN.json to sort entries + [\#2431](https://github.com/matrix-org/matrix-react-sdk/pull/2431) + * Key backup: Debounce passphrase feedback + [\#2426](https://github.com/matrix-org/matrix-react-sdk/pull/2426) + * Set backup niggles: 2 + [\#2425](https://github.com/matrix-org/matrix-react-sdk/pull/2425) + * Fix lint errors in MessageComposerInput + [\#2423](https://github.com/matrix-org/matrix-react-sdk/pull/2423) + * Set backup niggles: 1 + [\#2424](https://github.com/matrix-org/matrix-react-sdk/pull/2424) + * PoC: Add simple state counters to room heading + [\#2388](https://github.com/matrix-org/matrix-react-sdk/pull/2388) + * Fix a few things with cancelling recovery reminder + [\#2420](https://github.com/matrix-org/matrix-react-sdk/pull/2420) + * Add spaces back to async arrow functions + [\#2422](https://github.com/matrix-org/matrix-react-sdk/pull/2422) + * fix grid growing wider than viewport on chrome + [\#2421](https://github.com/matrix-org/matrix-react-sdk/pull/2421) + * Tiled room UI + [\#2348](https://github.com/matrix-org/matrix-react-sdk/pull/2348) + * Fix path to New Recovery Method icon + [\#2417](https://github.com/matrix-org/matrix-react-sdk/pull/2417) + * run unit tests on riot-web like before + [\#2419](https://github.com/matrix-org/matrix-react-sdk/pull/2419) + * Refactor travis-ci to use parallel jobs + [\#2414](https://github.com/matrix-org/matrix-react-sdk/pull/2414) + * Fix black-on-black GIF icon for stickers + [\#2408](https://github.com/matrix-org/matrix-react-sdk/pull/2408) + * Don't reset cached room list values when they are falsey + [\#2413](https://github.com/matrix-org/matrix-react-sdk/pull/2413) + * Make logout warning nag about key backups + [\#2407](https://github.com/matrix-org/matrix-react-sdk/pull/2407) + * Clarify readme instructions for developers + [\#2404](https://github.com/matrix-org/matrix-react-sdk/pull/2404) + * Add slash command for changing room name + [\#2401](https://github.com/matrix-org/matrix-react-sdk/pull/2401) + * Flatten and simplify the memberlist sorting algorithm + [\#2381](https://github.com/matrix-org/matrix-react-sdk/pull/2381) + * Tiny fixes for custom status messages on experimental + [\#2403](https://github.com/matrix-org/matrix-react-sdk/pull/2403) + * Part 3 of 3: Apply today's changes to experimental again + [\#2400](https://github.com/matrix-org/matrix-react-sdk/pull/2400) + * Part 2 of 3: Merge develop->experimental minus #2336 + [\#2399](https://github.com/matrix-org/matrix-react-sdk/pull/2399) + * Part 1 of 3: Back out bad merge for develop->experimental + [\#2398](https://github.com/matrix-org/matrix-react-sdk/pull/2398) + * Fix browser navigation not working between /home, /login, /register, etc + [\#2383](https://github.com/matrix-org/matrix-react-sdk/pull/2383) + * Don't re-sort the room list if the user is hovering over it + [\#2396](https://github.com/matrix-org/matrix-react-sdk/pull/2396) + * Merge develop into experimental + [\#2395](https://github.com/matrix-org/matrix-react-sdk/pull/2395) + * Added colour var to all themes + [\#2379](https://github.com/matrix-org/matrix-react-sdk/pull/2379) + * Colour, contrast & legibility improvements + [\#2378](https://github.com/matrix-org/matrix-react-sdk/pull/2378) + * Redesign: add feedback dialog & button in tag panel + [\#2376](https://github.com/matrix-org/matrix-react-sdk/pull/2376) + * Redesign: add badge with dot to rm button, to see it catches your eye better + [\#2371](https://github.com/matrix-org/matrix-react-sdk/pull/2371) + * Fix misaligned (+) icon + [\#2374](https://github.com/matrix-org/matrix-react-sdk/pull/2374) + * Avoid 'transparent black' gradients in left panel + [\#2373](https://github.com/matrix-org/matrix-react-sdk/pull/2373) + * Normalised icons + [\#2370](https://github.com/matrix-org/matrix-react-sdk/pull/2370) + * Redesign: give right panel default width + [\#2369](https://github.com/matrix-org/matrix-react-sdk/pull/2369) + * Redesign: Fix login field looking inline + [\#2368](https://github.com/matrix-org/matrix-react-sdk/pull/2368) + * Redesign: select search query on focus + [\#2367](https://github.com/matrix-org/matrix-react-sdk/pull/2367) + * Redesign: fix remaining right panel collapse issues. + [\#2366](https://github.com/matrix-org/matrix-react-sdk/pull/2366) + * Redesign: left panel fixes + [\#2364](https://github.com/matrix-org/matrix-react-sdk/pull/2364) + * Redesign: allow to hide the right panel when clicking already active button + & persist + [\#2361](https://github.com/matrix-org/matrix-react-sdk/pull/2361) + * Redesign: make room tiles less high so more rooms fit on the screen + [\#2359](https://github.com/matrix-org/matrix-react-sdk/pull/2359) + * Redesign: ignore any unknown tags + [\#2358](https://github.com/matrix-org/matrix-react-sdk/pull/2358) + * Redesign: disable setting theme completely + [\#2357](https://github.com/matrix-org/matrix-react-sdk/pull/2357) + * Force use of dharma theme + [\#2355](https://github.com/matrix-org/matrix-react-sdk/pull/2355) + * Redesign: some small fixes + [\#2354](https://github.com/matrix-org/matrix-react-sdk/pull/2354) + * Redesign: restyle jump to first unread message & rework read marker logic + (rebased) + [\#2345](https://github.com/matrix-org/matrix-react-sdk/pull/2345) + * Redesign: fix add room button alignment when collapsed + [\#2343](https://github.com/matrix-org/matrix-react-sdk/pull/2343) + * Redesign: confirm sign out from top left menu + [\#2342](https://github.com/matrix-org/matrix-react-sdk/pull/2342) + * Redesign: fix room header avatar in edit mode + [\#2344](https://github.com/matrix-org/matrix-react-sdk/pull/2344) + * Redesign: make community UX usable + [\#2341](https://github.com/matrix-org/matrix-react-sdk/pull/2341) + * Redesign: resizer persistence + [\#2321](https://github.com/matrix-org/matrix-react-sdk/pull/2321) + * Redesign: improve room sub list sizing & persist sizes + [\#2297](https://github.com/matrix-org/matrix-react-sdk/pull/2297) + * Redesign: temp solution to make room settings usable + [\#2298](https://github.com/matrix-org/matrix-react-sdk/pull/2298) + * Redesign: typing notifications in timeline + [\#2276](https://github.com/matrix-org/matrix-react-sdk/pull/2276) + * Redesign: add scroll indicator gradients to top and bottom of room sub list + [\#2275](https://github.com/matrix-org/matrix-react-sdk/pull/2275) + * Redesign: move member query field to bottom of member list + [\#2270](https://github.com/matrix-org/matrix-react-sdk/pull/2270) + * Redesign: room list visual polish + [\#2269](https://github.com/matrix-org/matrix-react-sdk/pull/2269) + * Redesign: bring back & restyle room filter field + [\#2267](https://github.com/matrix-org/matrix-react-sdk/pull/2267) + * Redesign: increase interaction rectangle of resize handles + [\#2262](https://github.com/matrix-org/matrix-react-sdk/pull/2262) + * Redesign: move right panel below room/group header + [\#2260](https://github.com/matrix-org/matrix-react-sdk/pull/2260) + * Redesign: use native auto-hiding scrollbars in room sub lists + [\#2264](https://github.com/matrix-org/matrix-react-sdk/pull/2264) + * Redesign: basic makeover of member info panel + [\#2248](https://github.com/matrix-org/matrix-react-sdk/pull/2248) + * Redesign: memberlist basic makeover + [\#2245](https://github.com/matrix-org/matrix-react-sdk/pull/2245) + * Redesign: tweak room list font sizes + [\#2246](https://github.com/matrix-org/matrix-react-sdk/pull/2246) + * Redesign: Fix room lists sizing + [\#2234](https://github.com/matrix-org/matrix-react-sdk/pull/2234) + * Redesign: fix import path + [\#2243](https://github.com/matrix-org/matrix-react-sdk/pull/2243) + * Redesign: update (most) icons + [\#2241](https://github.com/matrix-org/matrix-react-sdk/pull/2241) + * Redesign: fix basic room header layout + [\#2240](https://github.com/matrix-org/matrix-react-sdk/pull/2240) + * Redesign: 1st go at top left menu & restyling context menus + [\#2239](https://github.com/matrix-org/matrix-react-sdk/pull/2239) + * Redesign: Initial timeline tweaks + [\#2238](https://github.com/matrix-org/matrix-react-sdk/pull/2238) + * Redesign: Align visuals of room list with design + [\#2233](https://github.com/matrix-org/matrix-react-sdk/pull/2233) + * Redesign: room section header tidbits + [\#2229](https://github.com/matrix-org/matrix-react-sdk/pull/2229) + * Redesign: Add (+) button in room section header to add rooms + [\#2228](https://github.com/matrix-org/matrix-react-sdk/pull/2228) + * Redesign: 1st go at resizing room sublists + [\#2226](https://github.com/matrix-org/matrix-react-sdk/pull/2226) + * Redesign: remove room list truncation and DND + [\#2224](https://github.com/matrix-org/matrix-react-sdk/pull/2224) + * Redesign: resizeable/collapsible sections + [\#2210](https://github.com/matrix-org/matrix-react-sdk/pull/2210) + +Changes in [0.14.8](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.14.8) (2019-01-22) +===================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.14.8-rc.1...v0.14.8) + + * Fix settings direct chat + [\#2467](https://github.com/matrix-org/matrix-react-sdk/pull/2467) + +Changes in [0.14.8-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.14.8-rc.1) (2019-01-17) +=============================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.14.7...v0.14.8-rc.1) + + * Change wording of 'invite anyway' setting + [\#2450](https://github.com/matrix-org/matrix-react-sdk/pull/2450) + * Minimal lint-fixes to make develop CI build + [\#2449](https://github.com/matrix-org/matrix-react-sdk/pull/2449) + * Develop->Experimental + [\#2445](https://github.com/matrix-org/matrix-react-sdk/pull/2445) + * Limit line length in the room directory + [\#2438](https://github.com/matrix-org/matrix-react-sdk/pull/2438) + * Develop->Experimental + [\#2444](https://github.com/matrix-org/matrix-react-sdk/pull/2444) + * Fix setting label for unknown invites + [\#2443](https://github.com/matrix-org/matrix-react-sdk/pull/2443) + * Merge develop -> experimental + [\#2441](https://github.com/matrix-org/matrix-react-sdk/pull/2441) + * Give a route for retrying invites for users which may not exist + [\#2434](https://github.com/matrix-org/matrix-react-sdk/pull/2434) + * Show in-room reminder when key backup creating device unverified + [\#2394](https://github.com/matrix-org/matrix-react-sdk/pull/2394) + * Consistent flair ordering. + [\#2389](https://github.com/matrix-org/matrix-react-sdk/pull/2389) + * Fetch matching e2e-test branch + [\#2387](https://github.com/matrix-org/matrix-react-sdk/pull/2387) + * Add some logging for riot-web#7838 + [\#2385](https://github.com/matrix-org/matrix-react-sdk/pull/2385) + * Handle well-known data in the login response + [\#2384](https://github.com/matrix-org/matrix-react-sdk/pull/2384) + * Custom status messages + [\#2347](https://github.com/matrix-org/matrix-react-sdk/pull/2347) + * React-sdk changes to support sandboxed electron + [\#2372](https://github.com/matrix-org/matrix-react-sdk/pull/2372) + * Make sure to grab the InlineSpinner object + [\#2363](https://github.com/matrix-org/matrix-react-sdk/pull/2363) + * Standardize errors about localpart structure + [\#2351](https://github.com/matrix-org/matrix-react-sdk/pull/2351) + * Fix translation error on notification icon + [\#2352](https://github.com/matrix-org/matrix-react-sdk/pull/2352) + * Introduce a default_server_name for aesthetics and rework .well-known + [\#2327](https://github.com/matrix-org/matrix-react-sdk/pull/2327) + * Show the number of unread notifications above the bell on the right + [\#2336](https://github.com/matrix-org/matrix-react-sdk/pull/2336) + * Check to make sure email addresses look roughly valid before inviting them + to rooms + [\#2338](https://github.com/matrix-org/matrix-react-sdk/pull/2338) + * Expose hidden notification rules in UI + [\#2346](https://github.com/matrix-org/matrix-react-sdk/pull/2346) + * Avoid preserving HS url at logout + [\#2340](https://github.com/matrix-org/matrix-react-sdk/pull/2340) + * Speed up room unread checks by not hitting the SettingsStore so often + [\#2339](https://github.com/matrix-org/matrix-react-sdk/pull/2339) + * Remove outdated info about custom skins + [\#2337](https://github.com/matrix-org/matrix-react-sdk/pull/2337) + * Show the IncomingCallBox if the call is for the RoomSubList + [\#2333](https://github.com/matrix-org/matrix-react-sdk/pull/2333) + * Don't consider ACL'd servers as permalink candidates + [\#2331](https://github.com/matrix-org/matrix-react-sdk/pull/2331) + * Fix pinning of rooms without badges + [\#2330](https://github.com/matrix-org/matrix-react-sdk/pull/2330) + * Sort translations by file name + [\#2329](https://github.com/matrix-org/matrix-react-sdk/pull/2329) + * Update React guide in code style + [\#2335](https://github.com/matrix-org/matrix-react-sdk/pull/2335) + * Remove temporary account_deactivation_preferences + [\#2259](https://github.com/matrix-org/matrix-react-sdk/pull/2259) + Changes in [0.14.7](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.14.7) (2018-12-10) ===================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.14.7-rc.2...v0.14.7) @@ -4006,7 +5038,7 @@ Changes in [0.6.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v [\#297](https://github.com/matrix-org/matrix-react-sdk/pull/297) * multiple URL preview support [\#290](https://github.com/matrix-org/matrix-react-sdk/pull/290) - * Add a fallback home server to log into + * Add a fallback homeserver to log into [\#293](https://github.com/matrix-org/matrix-react-sdk/pull/293) * Hopefully fix memory leak with velocity [\#291](https://github.com/matrix-org/matrix-react-sdk/pull/291) diff --git a/README.md b/README.md index c70f68902b..e944b04ff2 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,6 @@ Developer Guide Platform Targets: * Chrome, Firefox and Safari. - * Edge should also work, but we're not testing it proactively. * WebRTC features (VoIP and Video calling) are only available in Chrome & Firefox. * Mobile Web is not currently a target platform - instead please use the native iOS (https://github.com/matrix-org/matrix-ios-kit) and Android @@ -66,7 +65,7 @@ practices that anyone working with the SDK needs to be be aware of and uphold: component is a view or a structure, and then a broad functional grouping (e.g. 'rooms' here) - * After creating a new component you must run `npm run reskindex` to regenerate + * After creating a new component you must run `yarn reskindex` to regenerate the `component-index.js` for the SDK (used in future for skinning) * The view's CSS file MUST have the same name (e.g. view/rooms/MessageTile.css). @@ -131,26 +130,35 @@ 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: +Ensure you have the latest LTS version of Node.js installed. + +Using `yarn` instead of `npm` is recommended. Please see the Yarn [install +guide](https://yarnpkg.com/docs/install/) if you do not have it already. + +`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 set up `matrix-js-sdk`: ```bash -git clone https://github.com/matrix-org/matrix-react-sdk.git +git clone https://github.com/matrix-org/matrix-js-sdk +cd matrix-js-sdk +git checkout develop +yarn link +yarn install +``` + +Then check out `matrix-react-sdk` and pull in dependencies: + +```bash +git clone https://github.com/matrix-org/matrix-react-sdk cd matrix-react-sdk git checkout develop -npm install +yarn link matrix-js-sdk +yarn 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. +See the [help for `yarn link`](https://yarnpkg.com/docs/cli/link) for more +details about this. Running tests ============= @@ -158,5 +166,5 @@ Running tests Ensure you've followed the above development instructions and then: ```bash -npm run test +yarn test ``` diff --git a/docs/settings.md b/docs/settings.md index cdba01e04a..c88888663b 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -1,11 +1,15 @@ # Settings Reference -This document serves as developer documentation for using "Granular Settings". Granular Settings allow users to specify different values for a setting at particular levels of interest. For example, a user may say that in a particular room they want URL previews off, but in all other rooms they want them enabled. The `SettingsStore` helps mask the complexity of dealing with the different levels and exposes easy to use getters and setters. +This document serves as developer documentation for using "Granular Settings". Granular Settings allow users to specify +different values for a setting at particular levels of interest. For example, a user may say that in a particular room +they want URL previews off, but in all other rooms they want them enabled. The `SettingsStore` helps mask the complexity +of dealing with the different levels and exposes easy to use getters and setters. ## Levels -Granular Settings rely on a series of known levels in order to use the correct value for the scenario. These levels, in order of prioirty, are: +Granular Settings rely on a series of known levels in order to use the correct value for the scenario. These levels, in +order of prioirty, are: * `device` - The current user's device * `room-device` - The current user's device, but only when in a specific room * `room-account` - The current user's account, but only when in a specific room @@ -14,12 +18,14 @@ Granular Settings rely on a series of known levels in order to use the correct v * `config` - Values are defined by `config.json` * `default` - The hardcoded default for the settings -Individual settings may control which levels are appropriate for them as part of the defaults. This is often to ensure that room administrators cannot force account-only settings upon participants. +Individual settings may control which levels are appropriate for them as part of the defaults. This is often to ensure +that room administrators cannot force account-only settings upon participants. ## Settings -Settings are the different options a user may set or experience in the application. These are pre-defined in `src/settings/Settings.js` under the `SETTINGS` constant and have the following minimum requirements: +Settings are the different options a user may set or experience in the application. These are pre-defined in +`src/settings/Settings.js` under the `SETTINGS` constant and have the following minimum requirements: ``` // The ID is used to reference the setting throughout the application. This must be unique. "theSettingId": { @@ -47,13 +53,21 @@ Settings are the different options a user may set or experience in the applicati ### Getting values for a setting -After importing `SettingsStore`, simply make a call to `SettingsStore.getValue`. The `roomId` parameter should always be supplied where possible, even if the setting does not have a per-room level value. This is to ensure that the value returned is best represented in the room, particularly if the setting ever gets a per-room level in the future. +After importing `SettingsStore`, simply make a call to `SettingsStore.getValue`. The `roomId` parameter should always +be supplied where possible, even if the setting does not have a per-room level value. This is to ensure that the value +returned is best represented in the room, particularly if the setting ever gets a per-room level in the future. -In settings pages it is often desired to have the value at a particular level instead of getting the calculated value. Call `SettingsStore.getValueAt` to get the value of a setting at a particular level, and optionally make it explicitly at that level. By default `getValueAt` will traverse the tree starting at the provided level; making it explicit means it will not go beyond the provided level. When using `getValueAt`, please be sure to use `SettingLevel` to represent the target level. +In settings pages it is often desired to have the value at a particular level instead of getting the calculated value. +Call `SettingsStore.getValueAt` to get the value of a setting at a particular level, and optionally make it explicitly +at that level. By default `getValueAt` will traverse the tree starting at the provided level; making it explicit means +it will not go beyond the provided level. When using `getValueAt`, please be sure to use `SettingLevel` to represent the +target level. ### Setting values for a setting -Values are defined at particular levels and should be done in a safe manner. There are two checks to perform to ensure a clean save: is the level supported and can the user actually set the value. In most cases, neither should be an issue although there are circumstances where this changes. An example of a safe call is: +Values are defined at particular levels and should be done in a safe manner. There are two checks to perform to ensure a +clean save: is the level supported and can the user actually set the value. In most cases, neither should be an issue +although there are circumstances where this changes. An example of a safe call is: ```javascript const isSupported = SettingsStore.isLevelSupported(SettingLevel.ROOM); if (isSupported) { @@ -64,11 +78,13 @@ if (isSupported) { } ``` -These checks may also be performed in different areas of the application to avoid the verbose example above. For instance, the component which allows changing the setting may be hidden conditionally on the above conditions. +These checks may also be performed in different areas of the application to avoid the verbose example above. For +instance, the component which allows changing the setting may be hidden conditionally on the above conditions. ##### `SettingsFlag` component -Where possible, the `SettingsFlag` component should be used to set simple "flip-a-bit" (true/false) settings. The `SettingsFlag` also supports simple radio button options, such as the theme the user would like to use. +Where possible, the `SettingsFlag` component should be used to set simple "flip-a-bit" (true/false) settings. The +`SettingsFlag` also supports simple radio button options, such as the theme the user would like to use. ```html { @@ -131,24 +170,69 @@ SettingsStore.getValue(...); // this will return the value set in `setValue` abo ``` +## Watching for changes + +Most use cases do not need to set up a watcher because they are able to react to changes as they are made, or the +changes which are made are not significant enough for it to matter. Watchers are intended to be used in scenarios where +it is important to react to changes made by other logged in devices. Typically, this would be done within the component +itself, however the component should not be aware of the intricacies of setting inversion or remapping to particular +data structures. Instead, a generic watcher interface is provided on `SettingsStore` to watch (and subsequently unwatch) +for changes in a setting. + +An example of a watcher in action would be: + +```javascript +class MyComponent extends React.Component { + + settingWatcherRef = null; + + componentWillMount() { + const callback = (settingName, roomId, level, newValAtLevel, newVal) => { + this.setState({color: newVal}); + }; + this.settingWatcherRef = SettingsStore.watchSetting("roomColor", "!example:matrix.org", callback); + } + + componentWillUnmount() { + SettingsStore.unwatchSetting(this.settingWatcherRef); + } +} +``` + # Maintainers Reference -The granular settings system has a few complex parts to power it. This section is to document how the `SettingsStore` is supposed to work. +The granular settings system has a few complex parts to power it. This section is to document how the `SettingsStore` is +supposed to work. ### General information -The `SettingsStore` uses the hardcoded `LEVEL_ORDER` constant to ensure that it is using the correct override procedure. The array is checked from left to right, simulating the behaviour of overriding values from the higher levels. Each level should be defined in this array, including `default`. +The `SettingsStore` uses the hardcoded `LEVEL_ORDER` constant to ensure that it is using the correct override procedure. +The array is checked from left to right, simulating the behaviour of overriding values from the higher levels. Each +level should be defined in this array, including `default`. -Handlers (`src/settings/handlers/SettingsHandler.js`) represent a single level and are responsible for getting and setting values at that level. Handlers also provide additional information to the `SettingsStore` such as if the level is supported or if the current user may set values at the level. The `SettingsStore` will use the handler to enforce checks and manipulate settings. Handlers are also responsible for dealing with migration patterns or legacy settings for their level (for example, a setting being renamed or using a different key from other settings in the underlying store). Handlers are provided to the `SettingsStore` via the `LEVEL_HANDLERS` constant. `SettingsStore` will optimize lookups by only considering handlers that are supported on the platform. +Handlers (`src/settings/handlers/SettingsHandler.js`) represent a single level and are responsible for getting and +setting values at that level. Handlers also provide additional information to the `SettingsStore` such as if the level +is supported or if the current user may set values at the level. The `SettingsStore` will use the handler to enforce +checks and manipulate settings. Handlers are also responsible for dealing with migration patterns or legacy settings for +their level (for example, a setting being renamed or using a different key from other settings in the underlying store). +Handlers are provided to the `SettingsStore` via the `LEVEL_HANDLERS` constant. `SettingsStore` will optimize lookups by +only considering handlers that are supported on the platform. -Local echo is achieved through `src/settings/handlers/LocalEchoWrapper.js` which acts as a wrapper around a given handler. This is automatically applied to all defined `LEVEL_HANDLERS` and proxies the calls to the wrapped handler where possible. The echo is achieved by a simple object cache stored within the class itself. The cache is invalidated immediately upon the proxied save call succeeding or failing. +Local echo is achieved through `src/settings/handlers/LocalEchoWrapper.js` which acts as a wrapper around a given +handler. This is automatically applied to all defined `LEVEL_HANDLERS` and proxies the calls to the wrapped handler +where possible. The echo is achieved by a simple object cache stored within the class itself. The cache is invalidated +immediately upon the proxied save call succeeding or failing. -Controllers are notified of changes by the `SettingsStore`, and are given the opportunity to override values after the `SettingsStore` has deemed the value calculated. Controllers are invoked as the last possible step in the code. +Controllers are notified of changes by the `SettingsStore`, and are given the opportunity to override values after the +`SettingsStore` has deemed the value calculated. Controllers are invoked as the last possible step in the code. ### Features -Features automatically get considered as `disabled` if they are not listed in the `SdkConfig` or `enable_labs` is false/not set. Features are always checked against the configuration before going through the level order as they have the option of being forced-on or forced-off for the application. This is done by the `features` section and looks something like this: +Features automatically get considered as `disabled` if they are not listed in the `SdkConfig` or `enable_labs` is +false/not set. Features are always checked against the configuration before going through the level order as they have +the option of being forced-on or forced-off for the application. This is done by the `features` section and looks +something like this: ``` "features": { @@ -159,3 +243,21 @@ Features automatically get considered as `disabled` if they are not listed in th ``` If `enableLabs` is true in the configuration, the default for features becomes `"labs"`. + +### Watchers + +Watchers can appear complicated under the hood: there is a central `WatchManager` which handles the actual invocation +of callbacks, and callbacks are managed by the SettingsStore by redirecting the caller's callback to a dedicated +callback. This is done so that the caller can reuse the same function as their callback without worrying about whether +or not it'll unsubscribe all watchers. + +Setting changes are emitted into the default `WatchManager`, which calculates the new value for the setting. Ideally, +we'd also try and suppress updates which don't have a consequence on this value, however there's not an easy way to do +this. Instead, we just dispatch an update for all changes and leave it up to the consumer to deduplicate. + +In practice, handlers which rely on remote changes (account data, room events, etc) will always attach a listener to the +`MatrixClient`. They then watch for changes to events they care about and send off appropriate updates to the +generalized `WatchManager` - a class specifically designed to deduplicate the logic of managing watchers. The handlers +which are localized to the local client (device) generally just trigger the `WatchManager` when they manipulate the +setting themselves as there's nothing to really 'watch'. + \ No newline at end of file diff --git a/jenkins.sh b/jenkins.sh index f4bb8da449..548373739c 100755 --- a/jenkins.sh +++ b/jenkins.sh @@ -8,25 +8,29 @@ nvm use 10 set -x -# install the other dependencies -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 -(cd matrix-js-sdk && npm install) + +pushd matrix-js-sdk +yarn link +yarn install +popd + +yarn link matrix-js-sdk + +# install the other dependencies +yarn install # run the mocha tests -npm run test -- --no-colors +yarn test --no-colors # run eslint -npm run lintall -- -f checkstyle -o eslint.xml || true +yarn lintall -f checkstyle -o eslint.xml || true # re-run the linter, excluding any files known to have errors or warnings. -npm run lintwithexclusions +yarn lintwithexclusions # delete the old tarball, if it exists rm -f matrix-react-sdk-*.tgz # build our tarball -npm pack +yarn pack diff --git a/karma.conf.js b/karma.conf.js index 4d699599cb..b687be78fa 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -8,7 +8,7 @@ var fs = require('fs'); * to build everything; however it's the easiest way to load our dependencies * from node_modules. * - * If you run karma in multi-run mode (with `npm run test-multi`), it will watch + * If you run karma in multi-run mode (with `yarn test-multi`), it will watch * the tests for changes, and webpack will rebuild using a cache. This is much quicker * than a clean rebuild. */ @@ -35,7 +35,7 @@ function fileExists(name) { } } -// try find the gemini-scrollbar css in an npm-version-agnostic way +// try find the gemini-scrollbar css in an version-agnostic way var gsCss = 'node_modules/gemini-scrollbar/gemini-scrollbar.css'; if (!fileExists(gsCss)) { gsCss = 'node_modules/react-gemini-scrollbar/'+gsCss; @@ -135,9 +135,10 @@ module.exports = function (config) { ], customLaunchers: { - 'ChromeHeadless': { + 'VectorChromeHeadless': { base: 'Chrome', flags: [ + '--no-sandbox', // See https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md '--headless', '--disable-gpu', @@ -168,6 +169,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 @@ -194,7 +199,7 @@ module.exports = function (config) { alias: { // alias any requires to the react module to the one in our // path, otherwise we tend to get the react source included - // twice when using npm link. + // twice when using `npm link` / `yarn link`. react: path.resolve('./node_modules/react'), 'matrix-react-sdk': path.resolve('test/skinned-sdk.js'), diff --git a/package.json b/package.json index 82246534a2..1459b06f4c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "0.14.7", + "version": "1.0.6", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { @@ -37,20 +37,21 @@ "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", + "build": "yarn reskindex && yarn start:init", "build:watch": "babel src -w --skip-initial-build -d lib --source-maps --copy-files", "emoji-data-strip": "node scripts/emoji-data-strip.js", - "start": "npm run start:init && npm run start:all", - "start:all": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n build,reskindex \"npm run build:watch\" \"npm run reskindex:watch\"", + "start": "yarn start:init && yarn start:all", + "start:all": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n build,reskindex \"yarn build:watch\" \"yarn reskindex:watch\"", "start:init": "babel src -d lib --source-maps --copy-files", "lint": "eslint src/", "lintall": "eslint src/ test/", - "lintwithexclusions": "eslint --max-warnings 18 --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", + "prepare": "yarn clean && yarn build && git rev-parse HEAD > git-revision.txt", + "test": "karma start --single-run=true --browsers VectorChromeHeadless", "test-multi": "karma start" }, "dependencies": { @@ -72,18 +73,19 @@ "gemini-scrollbar": "github:matrix-org/gemini-scrollbar#b302279", "gfm.css": "^1.1.1", "glob": "^5.0.14", - "highlight.js": "^9.13.0", + "highlight.js": "9.14.2", "is-ip": "^2.0.0", "isomorphic-fetch": "^2.2.1", "linkifyjs": "^2.1.6", "lodash": "^4.13.1", "lolex": "2.3.2", - "matrix-js-sdk": "0.14.2", + "matrix-js-sdk": "1.0.3", "optimist": "^0.6.1", "pako": "^1.0.5", "png-chunks-extract": "^1.0.0", "prop-types": "^15.5.8", "qrcode-react": "^0.1.16", + "qs": "^6.6.0", "querystring": "^0.2.0", "react": "^15.6.0", "react-addons-css-transition-group": "15.3.2", @@ -98,7 +100,7 @@ "slate-react": "^0.18.10", "text-encoding-utf-8": "^1.0.1", "url": "^0.11.0", - "velocity-vector": "github:vector-im/velocity#059e3b2", + "velocity-animate": "^1.5.2", "whatwg-fetch": "^1.1.1", "zxcvbn": "^4.4.2" }, @@ -109,6 +111,7 @@ "babel-loader": "^7.1.5", "babel-plugin-add-module-exports": "^0.2.1", "babel-plugin-transform-async-to-bluebird": "^1.1.1", + "babel-plugin-transform-builtin-extend": "^1.1.2", "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-plugin-transform-runtime": "^6.23.0", @@ -117,7 +120,7 @@ "babel-preset-es2016": "^6.24.1", "babel-preset-es2017": "^6.24.1", "babel-preset-react": "^6.24.1", - "chokidar": "^1.6.1", + "chokidar": "^2.1.2", "concurrently": "^4.0.1", "eslint": "^5.12.0", "eslint-config-google": "^0.7.1", @@ -125,20 +128,21 @@ "eslint-plugin-flowtype": "^2.30.0", "eslint-plugin-react": "^7.7.0", "estree-walker": "^0.5.0", - "expect": "^23.6.0", + "expect": "^24.1.0", + "file-loader": "^3.0.1", "flow-parser": "^0.57.3", "jest-mock": "^23.2.0", - "karma": "^3.0.0", - "karma-chrome-launcher": "^0.2.3", + "karma": "^4.0.1", + "karma-chrome-launcher": "^2.2.0", "karma-cli": "^1.0.1", - "karma-junit-reporter": "^0.4.2", + "karma-junit-reporter": "^2.0.0", "karma-logcapture-reporter": "0.0.1", "karma-mocha": "^1.3.0", "karma-sourcemap-loader": "^0.3.7", "karma-spec-reporter": "^0.0.31", "karma-summary-reporter": "^1.5.1", "karma-webpack": "^4.0.0-beta.0", - "matrix-mock-request": "^1.2.1", + "matrix-mock-request": "^1.2.3", "matrix-react-test-utils": "^0.1.1", "mocha": "^5.0.5", "react-addons-test-utils": "^15.4.0", diff --git a/res/css/_common.scss b/res/css/_common.scss index bec4c02c18..1e388c4531 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -50,8 +50,47 @@ a:visited { color: $accent-color-alt; } +input[type=text], +input[type=search], +input[type=password] { + padding: 9px; + font-family: $font-family; + font-size: 14px; + font-weight: 600; + min-width: 0; +} + +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-customised/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; +} + +// Override Firefox's UA style so we get a consistent look across browsers +input::placeholder, +textarea::placeholder { + opacity: initial; +} + input[type=text], input[type=password], textarea { background-color: transparent; + color: $primary-fg-color; } input[type=text]:focus, input[type=password]:focus, textarea:focus { @@ -62,6 +101,72 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { /* Required by Firefox */ textarea { font-family: $font-family; + color: $primary-fg-color; +} + +// .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; + } + } + + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=text]::placeholder, + :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=search]::placeholder, + .mx_textinput input::placeholder { + color: $roomsublist-label-fg-color; + } +} + +/*** panels ***/ +.dark-panel { + background-color: $dark-panel-bg-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; + } } /* Prevent ugly dotted highlight around selected elements in Firefox */ @@ -123,6 +228,17 @@ textarea { color: $roomsublist-label-bg-color; } +/* Expected z-indexes for dialogs: + 4000 - Default wrapper index + 4009 - Static dialog background + 4010 - Static dialog itself + 4011 - Standard dialog background + 4012 - Standard dialog itself + + These are set up such that the static dialog always appears + underneath the standard dialogs. + */ + .mx_Dialog_wrapper { position: fixed; z-index: 4000; @@ -144,35 +260,44 @@ textarea { box-shadow: none; } -/* View Source Dialog overide */ -.mx_Dialog_wrapper.mx_Dialog_viewsource .mx_Dialog { - padding-left: 10px; - padding-right: 10px; -} - .mx_Dialog { background-color: $primary-bg-color; color: $light-fg-color; - z-index: 4010; + z-index: 4012; 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; } +.mx_Dialog_staticWrapper .mx_Dialog { + z-index: 4010; +} + .mx_Dialog_background { position: fixed; top: 0; left: 0; width: 100%; height: 100%; - background-color: $dialog-background-bg-color; + background-color: $dialog-backdrop-color; opacity: 0.8; + z-index: 4011; +} + +.mx_Dialog_background.mx_Dialog_staticBackground { + z-index: 4009; +} + +.mx_Dialog_wrapperWithStaticUnder .mx_Dialog_background { + // Roughly half of what it would normally be - we don't want to black out + // the app, just make it clear that the dialogs are stacked. + opacity: 0.4; } .mx_Dialog_lightbox .mx_Dialog_background { @@ -190,15 +315,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-customised/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 { @@ -221,7 +367,7 @@ textarea { font-weight: 600; border: 1px solid $accent-color ! important; color: $accent-color; - background-color: $accent-fg-color; + background-color: $button-secondary-bg-color; } .mx_Dialog button:hover, .mx_Dialog input[type="submit"]:hover { @@ -249,24 +395,25 @@ textarea { opacity: 0.7; } +// TODO: Review mx_GeneralButton usage to see if it can use a different class +// These classes were brought in from the old UserSettings and are included here to avoid +// breaking the app. +// Ref: https://github.com/vector-im/riot-web/issues/8420 +.mx_GeneralButton { + @mixin mx_DialogButton; + display: inline; + margin: auto; +} + +.mx_GeneralButton:hover { + @mixin mx_DialogButton_hover; +} + .mx_linkButton { cursor: pointer; 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; diff --git a/res/css/_components.scss b/res/css/_components.scss index 1e2d7ae156..b7d0c7a2a5 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -4,12 +4,13 @@ @import "./structures/_CompatibilityPage.scss"; @import "./structures/_ContextualMenu.scss"; @import "./structures/_CreateRoom.scss"; +@import "./structures/_CustomRoomTagPanel.scss"; @import "./structures/_FilePanel.scss"; -@import "./structures/_GroupGridView.scss"; @import "./structures/_GroupView.scss"; +@import "./structures/_HeaderButtons.scss"; @import "./structures/_HomePage.scss"; @import "./structures/_LeftPanel.scss"; -@import "./structures/_LoginBox.scss"; +@import "./structures/_MainSplit.scss"; @import "./structures/_MatrixChat.scss"; @import "./structures/_MyGroups.scss"; @import "./structures/_NotificationPanel.scss"; @@ -18,13 +19,27 @@ @import "./structures/_RoomStatusBar.scss"; @import "./structures/_RoomSubList.scss"; @import "./structures/_RoomView.scss"; +@import "./structures/_ScrollPanel.scss"; @import "./structures/_SearchBox.scss"; +@import "./structures/_TabbedView.scss"; @import "./structures/_TagPanel.scss"; +@import "./structures/_TagPanelButtons.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/auth/_Welcome.scss"; @import "./views/avatars/_BaseAvatar.scss"; @import "./views/avatars/_MemberStatusMessageAvatar.scss"; @import "./views/context_menus/_MessageContextMenu.scss"; @@ -32,6 +47,7 @@ @import "./views/context_menus/_StatusMessageContextMenu.scss"; @import "./views/context_menus/_TagTileContextMenu.scss"; @import "./views/context_menus/_TopLeftMenu.scss"; +@import "./views/dialogs/_Analytics.scss"; @import "./views/dialogs/_BugReportDialog.scss"; @import "./views/dialogs/_ChangelogDialog.scss"; @import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss"; @@ -40,16 +56,23 @@ @import "./views/dialogs/_CreateGroupDialog.scss"; @import "./views/dialogs/_CreateRoomDialog.scss"; @import "./views/dialogs/_DeactivateAccountDialog.scss"; +@import "./views/dialogs/_DeviceVerifyDialog.scss"; @import "./views/dialogs/_DevtoolsDialog.scss"; @import "./views/dialogs/_EncryptedEventDialog.scss"; @import "./views/dialogs/_GroupAddressPicker.scss"; +@import "./views/dialogs/_IncomingSasDialog.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/_UploadConfirmDialog.scss"; +@import "./views/dialogs/_UserSettingsDialog.scss"; +@import "./views/dialogs/_WidgetOpenIDPermissionsDialog.scss"; @import "./views/dialogs/keybackup/_CreateKeyBackupDialog.scss"; @import "./views/dialogs/keybackup/_KeyBackupFailedDialog.scss"; @import "./views/dialogs/keybackup/_RestoreKeyBackupDialog.scss"; @@ -60,9 +83,12 @@ @import "./views/elements/_DirectorySearchBox.scss"; @import "./views/elements/_Dropdown.scss"; @import "./views/elements/_EditableItemList.scss"; +@import "./views/elements/_Field.scss"; @import "./views/elements/_ImageView.scss"; @import "./views/elements/_InlineSpinner.scss"; +@import "./views/elements/_ManageIntegsButton.scss"; @import "./views/elements/_MemberEventListSummary.scss"; +@import "./views/elements/_PowerSelector.scss"; @import "./views/elements/_ProgressBar.scss"; @import "./views/elements/_ReplyThread.scss"; @import "./views/elements/_ResizeHandle.scss"; @@ -70,13 +96,13 @@ @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/elements/_Tooltip.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"; @@ -90,11 +116,15 @@ @import "./views/messages/_SenderProfile.scss"; @import "./views/messages/_TextualEvent.scss"; @import "./views/messages/_UnknownBody.scss"; +@import "./views/room_settings/_AliasSettings.scss"; +@import "./views/room_settings/_ColorSettings.scss"; @import "./views/rooms/_AppsDrawer.scss"; @import "./views/rooms/_Autocomplete.scss"; @import "./views/rooms/_AuxPanel.scss"; +@import "./views/rooms/_E2EIcon.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"; @@ -104,14 +134,13 @@ @import "./views/rooms/_PinnedEventsPanel.scss"; @import "./views/rooms/_PresenceLabel.scss"; @import "./views/rooms/_ReplyPreview.scss"; +@import "./views/rooms/_RoomBreadcrumbs.scss"; @import "./views/rooms/_RoomDropTarget.scss"; @import "./views/rooms/_RoomHeader.scss"; @import "./views/rooms/_RoomList.scss"; @import "./views/rooms/_RoomPreviewBar.scss"; @import "./views/rooms/_RoomRecoveryReminder.scss"; -@import "./views/rooms/_RoomSettings.scss"; @import "./views/rooms/_RoomTile.scss"; -@import "./views/rooms/_RoomTooltip.scss"; @import "./views/rooms/_RoomUpgradeWarningBar.scss"; @import "./views/rooms/_SearchBar.scss"; @import "./views/rooms/_SearchableEntityList.scss"; @@ -119,9 +148,23 @@ @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/_SettingsTab.scss"; +@import "./views/settings/tabs/room/_GeneralRoomSettingsTab.scss"; +@import "./views/settings/tabs/room/_RolesRoomSettingsTab.scss"; +@import "./views/settings/tabs/room/_SecurityRoomSettingsTab.scss"; +@import "./views/settings/tabs/user/_GeneralUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_HelpUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_NotificationUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_PreferencesUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_SecurityUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_VoiceUserSettingsTab.scss"; +@import "./views/verification/_VerificationShowSas.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 index 60aea7ce8f..0e1faf727d 100644 --- a/res/css/structures/_AutoHideScrollbar.scss +++ b/res/css/structures/_AutoHideScrollbar.scss @@ -64,3 +64,21 @@ body.mx_scrollbar_nooverlay { 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; + height: 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 fa69c6fb90..3788929bf3 100644 --- a/res/css/structures/_ContextualMenu.scss +++ b/res/css/structures/_ContextualMenu.scss @@ -30,8 +30,8 @@ limitations under the License. } .mx_ContextualMenu { - border-radius: 2px; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.21); + border-radius: 4px; + box-shadow: 4px 4px 12px 0 $menu-box-shadow-color; background-color: $menu-bg-color; color: $primary-fg-color; position: absolute; @@ -43,10 +43,6 @@ limitations under the License. right: 8px; } -.mx_ContextualMenu_noChevron { - border-radius: unset !important; -} - .mx_ContextualMenu_chevron_right { position: absolute; right: -8px; diff --git a/res/css/structures/_CustomRoomTagPanel.scss b/res/css/structures/_CustomRoomTagPanel.scss new file mode 100644 index 0000000000..45961d7be1 --- /dev/null +++ b/res/css/structures/_CustomRoomTagPanel.scss @@ -0,0 +1,45 @@ +/* +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_LeftPanel_tagPanelContainer { + display: flex; + flex-direction: column; +} + +.mx_CustomRoomTagPanel { + background-color: $tagpanel-bg-color; + max-height: 40vh; +} + +.mx_CustomRoomTagPanel_scroller { + max-height: inherit; +} + +.mx_CustomRoomTagPanel .mx_AccessibleButton { + margin: 9px auto; + width: 40px; +} + +.mx_CustomRoomTagPanel .mx_BaseAvatar_image { + box-sizing: border-box; + width: 40px; + height: 40px; +} + +.mx_CustomRoomTagPanel .mx_AccessibleButton.CustomRoomTagPanel_tileSelected .mx_BaseAvatar_image { + border: 3px solid $warning-color; + border-radius: 40px; +} diff --git a/res/css/structures/_GroupGridView.scss b/res/css/structures/_GroupGridView.scss deleted file mode 100644 index 541052175d..0000000000 --- a/res/css/structures/_GroupGridView.scss +++ /dev/null @@ -1,130 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -.mx_GroupGridView { - display: flex; - flex-direction: column; -} - -.mx_GroupGridView_rooms { - display: grid; - grid-template-columns: repeat(3, calc(100% / 3)); - grid-template-rows: repeat(2, calc(100% / 2)); - flex: 1 1 0; - min-width: 0; -} - -.mx_GroupGridView_rightPanel { - display: flex; - flex-direction: column; - - .mx_GroupGridView_tabs { - flex: 0 0 52px; - border-bottom: 1px solid $primary-hairline-color; - display: flex; - align-items: center; - - > div { - justify-content: flex-end; - width: 100%; - margin-right: 10px; - } - } - - .mx_RightPanel { - flex: 1 0 auto !important; - } -} - - -.mx_GroupGridView > .mx_MainSplit { - flex: 1 1 0; - display: flex; -} - -.mx_GroupGridView_emptyTile { - display: block; - margin-top: 100px; - text-align: center; - user-select: none; -} - -.mx_GroupGridView_tile { - border-right: 1px solid $panel-divider-color; - border-bottom: 1px solid $panel-divider-color; -} - -.mx_GroupGridView_activeTile { - position: relative; -} - -.mx_GroupGridView_activeTile:before, -.mx_GroupGridView_activeTile:after { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - content: ""; - pointer-events: none; - z-index: 3500; -} - -.mx_GroupGridView_activeTile:before { - border-radius: 14px; - border: 8px solid $gridview-focus-border-glow-color; - margin: -8px; -} - -.mx_GroupGridView_activeTile:after { - border-radius: 8px; - border: 2px solid $gridview-focus-border-color; - margin: -2px; -} - -.mx_GroupGridView_tile > .mx_RoomView { - height: 100%; -} - -.mx_GroupGridView_rooms > *:nth-child(1) { - grid-column: 1; - grid-row: 1; -} - -.mx_GroupGridView_rooms > *:nth-child(2) { - grid-column: 2; - grid-row: 1; -} - -.mx_GroupGridView_rooms > *:nth-child(3) { - grid-column: 3; - grid-row: 1; -} - -.mx_GroupGridView_rooms > *:nth-child(4) { - grid-column: 1; - grid-row: 2; -} - -.mx_GroupGridView_rooms > *:nth-child(5) { - grid-column: 2; - grid-row: 2; -} - -.mx_GroupGridView_rooms > *:nth-child(6) { - grid-column: 3; - grid-row: 2; -} diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss index 398c51ba91..4f33617344 100644 --- a/res/css/structures/_GroupView.scss +++ b/res/css/structures/_GroupView.scss @@ -25,7 +25,7 @@ limitations under the License. } .mx_GroupView_header { - min-height: 70px; + min-height: 52px; align-items: center; display: flex; padding-bottom: 10px; @@ -34,7 +34,7 @@ limitations under the License. .mx_GroupView_header_view { border-bottom: 1px solid $primary-hairline-color; padding-bottom: 0px; - padding-left: 8px; + padding-left: 19px; padding-right: 8px; } @@ -44,13 +44,26 @@ limitations under the License. } .mx_GroupHeader_button { - margin-left: 12px; + margin-left: 5px; + margin-right: 5px; cursor: pointer; + height: 20px; + width: 20px; + background-color: $groupheader-button-color; + mask-repeat: no-repeat; + mask-size: contain; } -.mx_GroupHeader_button object { - // prevents clicks from being swallowed by svg in 'object' tag - pointer-events: none; +.mx_GroupHeader_editButton { + mask-image: url('$(res)/img/icons-settings-room.svg'); +} + +.mx_GroupHeader_shareButton { + mask-image: url('$(res)/img/icons-share.svg'); +} + +.mx_GroupView_hostingSignup img { + margin-left: 5px; } .mx_GroupView_editable { @@ -161,7 +174,6 @@ limitations under the License. .mx_GroupView > .mx_MainSplit { flex: 1; - display: flex; } .mx_GroupView_body { @@ -349,3 +361,8 @@ limitations under the License. .mx_GroupView_changeDelayWarning { padding: 40px 20px; } + +.mx_GroupView .mx_MemberInfo .gm-scroll-view > :not(.mx_MemberInfo_avatar) { + padding-left: 16px; + padding-right: 16px; +} diff --git a/res/css/structures/_HeaderButtons.scss b/res/css/structures/_HeaderButtons.scss new file mode 100644 index 0000000000..eef7653b24 --- /dev/null +++ b/res/css/structures/_HeaderButtons.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_HeaderButtons { + display: flex; +} + +.mx_HeaderButtons::before { + content: ""; + background-color: $header-divider-color; + opacity: 0.5; + margin: 0 15px; + border-radius: 1px; + width: 1px; +} diff --git a/res/css/structures/_HomePage.scss b/res/css/structures/_HomePage.scss index dc3158b39d..3aa80f6f59 100644 --- a/res/css/structures/_HomePage.scss +++ b/res/css/structures/_HomePage.scss @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2017 Vector Creations 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. @@ -22,27 +23,3 @@ limitations under the License. margin-left: auto; margin-right: auto; } - -.mx_HomePage iframe { - display: block; - width: 100%; - height: 100%; - border: 0px; -} - -.mx_HomePage_body { -// margin-left: 63px; -} - -.mx_HomePage_guest_warning { - display: flex; - background-color: $secondary-accent-color; - border: 1px solid $accent-color; - margin: 20px; - padding: 20px 40px; - border-radius: 5px; -} - -.mx_HomePage_guest_warning img { - padding-right: 10px; -} diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index 941417eccc..9dbfe696a5 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -33,6 +33,11 @@ limitations under the License. flex: 0 0 140px; } +.mx_LeftPanel_tagPanelContainer { + flex: 0 0 70px; + height: 100%; +} + .mx_LeftPanel_hideButton { position: absolute; top: 10px; diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss new file mode 100644 index 0000000000..4d73953cd7 --- /dev/null +++ b/res/css/structures/_MainSplit.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_MainSplit { + display: flex; + flex-direction: row; + min-width: 0; +} + +// move hit area 5px to the right so it doesn't overlap with the timeline scrollbar +.mx_MainSplit > .mx_ResizeHandle.mx_ResizeHandle_horizontal { + margin: 0 -10px 0 0; + padding: 0 10px 0 0; +} diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index 6d8b79ecb2..f2ce7e1d5c 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -81,8 +81,7 @@ limitations under the License. Empirically this stops the MessagePanel's width exploding outwards when gemini is in 'prevented' mode */ - // disabling this for now as it clips the active room rect on the grid view - // overflow-x: auto; + overflow-x: auto; /* 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 diff --git a/res/css/structures/_MyGroups.scss b/res/css/structures/_MyGroups.scss index f9433909a5..4428eadc48 100644 --- a/res/css/structures/_MyGroups.scss +++ b/res/css/structures/_MyGroups.scss @@ -49,12 +49,12 @@ limitations under the License. height: 40px; width: 40px; border-radius: 20px; - background-color: $roomheader-addroom-color; + background-color: $roomheader-addroom-bg-color; position: relative; &:before { - background-color: $accent-fg-color; - mask: url('../../img/icons-create-room.svg'); + background-color: $roomheader-addroom-fg-color; + mask: url('$(res)/img/icons-create-room.svg'); mask-repeat: no-repeat; mask-position: center; mask-size: 80%; diff --git a/res/css/structures/_RightPanel.scss b/res/css/structures/_RightPanel.scss index 592eea067e..c63db5d274 100644 --- a/res/css/structures/_RightPanel.scss +++ b/res/css/structures/_RightPanel.scss @@ -25,9 +25,7 @@ limitations under the License. .mx_RightPanel_header { order: 1; - border-bottom: 1px solid $primary-hairline-color; - flex: 0 0 52px; } @@ -45,20 +43,55 @@ limitations under the License. cursor: pointer; flex: 0 0 auto; vertical-align: top; - margin-top: 4px; - padding-left: 5px; - padding-right: 5px; + margin-left: 5px; + margin-right: 5px; text-align: center; - position: relative; border-bottom: 2px solid transparent; + height: 20px; + width: 20px; + position: relative; } -.mx_RightPanel_headerButton object { - pointer-events: none; +.mx_RightPanel_headerButton::before { + content: ''; + position: absolute; + top: 0; + left: 0; + height: 20px; + width: 20px; + background-color: $rightpanel-button-color; + mask-repeat: no-repeat; + mask-size: contain; } -.mx_RightPanel_headerButton_highlight { - border-color: $button-bg-color; +.mx_RightPanel_membersButton::before { + mask-image: url('$(res)/img/feather-customised/user.svg'); +} + +.mx_RightPanel_filesButton::before { + mask-image: url('$(res)/img/feather-customised/files.svg'); +} + +.mx_RightPanel_notifsButton::before { + mask-image: url('$(res)/img/feather-customised/notifications.svg'); +} + +.mx_RightPanel_groupMembersButton::before { + mask-image: url('$(res)/img/icons-people.svg'); +} + +.mx_RightPanel_roomsButton::before { + mask-image: url('$(res)/img/icons-room-nobg.svg'); +} + +.mx_RightPanel_headerButton_highlight::after { + content: ''; + position: absolute; + bottom: -6px; + left: 0; + right: 0; + height: 2px; + background-color: $button-bg-color; } .mx_RightPanel_headerButton_badge { 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/_RoomStatusBar.scss b/res/css/structures/_RoomStatusBar.scss index 2a9cc9f6c7..1054654670 100644 --- a/res/css/structures/_RoomStatusBar.scss +++ b/res/css/structures/_RoomStatusBar.scss @@ -121,7 +121,7 @@ limitations under the License. .mx_RoomStatusBar_connectionLostBar img { padding-left: 10px; - padding-right: 22px; + padding-right: 10px; vertical-align: middle; float: left; } diff --git a/res/css/structures/_RoomSubList.scss b/res/css/structures/_RoomSubList.scss index 2d471ee198..2f1484d83f 100644 --- a/res/css/structures/_RoomSubList.scss +++ b/res/css/structures/_RoomSubList.scss @@ -32,33 +32,13 @@ limitations under the License. */ .mx_RoomSubList { - min-height: 31px; - flex: 0 100000000 auto; display: flex; flex-direction: column; } -.mx_RoomSubList_nonEmpty { - min-height: 70px; - .mx_AutoHideScrollbar_offset { - padding-bottom: 4px; - } -} - -.mx_RoomSubList_hidden { - flex: none !important; -} - -.mx_RoomSubList.resized-all { - flex: 0 1 auto; -} - -.mx_RoomSubList.resized-sized { - /* resizer set max-height on resized-sized, - so that limits the height and hence - needs a very small flex-shrink */ - flex: 0 10000 auto; +.mx_RoomSubList_nonEmpty .mx_AutoHideScrollbar_offset { + padding-bottom: 4px; } .mx_RoomSubList_labelContainer { @@ -95,6 +75,7 @@ limitations under the License. font-size: 12px; padding: 0 5px; background-color: $roomtile-name-color; + cursor: pointer; } .mx_RoomSubList_addRoom, .mx_RoomSubList_badge { @@ -102,15 +83,24 @@ limitations under the License. } .mx_RoomSubList_addRoom { - background-color: $roomheader-addroom-color; - color: $roomsublist-background; - background-image: url('../../img/icons-room-add.svg'); - background-repeat: no-repeat; - background-position: center; + background-color: $roomheader-addroom-bg-color; border-radius: 10px; // 16/2 + 2 padding height: 16px; flex: 0 0 16px; - background-clip: content-box; + position: relative; + + &:before { + background-color: $roomheader-addroom-fg-color; + mask: url('$(res)/img/icons-room-add.svg'); + mask-repeat: no-repeat; + mask-position: center; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + } } .mx_RoomSubList_badgeHighlight { @@ -119,13 +109,13 @@ limitations under the License. .mx_RoomSubList_chevron { pointer-events: none; - background-image: url('../../img/topleft-chevron.svg'); - background-repeat: no-repeat; + mask: url('$(res)/img/feather-customised/dropdown-arrow.svg'); + mask-repeat: no-repeat; transition: transform 0.2s ease-in; width: 10px; - height: 10px; - background-position: center; + height: 6px; margin-left: 2px; + background-color: $roomsublist-label-fg-color; } .mx_RoomSubList_chevronDown { @@ -154,7 +144,7 @@ limitations under the License. position: sticky; left: 0; right: 0; - height: 30px; + height: 8px; content: ""; display: block; z-index: 100; @@ -162,21 +152,30 @@ limitations under the License. } &.mx_IndicatorScrollbar_topOverflow > .mx_AutoHideScrollbar_offset { - margin-top: -30px; + margin-top: -8px; } &.mx_IndicatorScrollbar_bottomOverflow > .mx_AutoHideScrollbar_offset { - margin-bottom: -30px; + margin-bottom: -8px; } &.mx_IndicatorScrollbar_topOverflow::before { top: 0; - background: linear-gradient(to top, rgba(242,245,248,0), rgba(242,245,248,1)); + transition: background-image 0.1s ease-in; + background: linear-gradient(to top, $panel-gradient); } +/* + // for now, we remove the bottomOverflow entirely as we don't want to + // lose the screen real-estate due to a bg-colored gradient, but we also + // don't want to use drop shadows and risk a confusing hierarchy of cards. + // so, instead, we hard-clip at the bottom but soft-clip at the top. &.mx_IndicatorScrollbar_bottomOverflow::after { bottom: 0; - background: linear-gradient(to bottom, rgba(242,245,248,0), rgba(242,245,248,1)); + transition: background-image 0.1s ease-in; + margin: 0px -8px; + background: linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.0)); } +*/ } .collapsed { diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 72dca953f9..018176146c 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -70,6 +70,13 @@ limitations under the License. background-color: $primary-bg-color; } +.mx_RoomView_auxPanel_hiddenHighlights { + border-bottom: 1px solid $primary-hairline-color; + padding: 10px 26px; + color: $warning-color; + cursor: pointer; +} + .mx_RoomView_auxPanel_apps { max-width: 1920px ! important; } @@ -77,7 +84,6 @@ limitations under the License. .mx_RoomView .mx_MainSplit { flex: 1 1 0; - display: flex; } .mx_RoomView_body { @@ -85,6 +91,7 @@ limitations under the License. display: flex; flex-direction: column; flex: 1; + min-width: 0; } .mx_RoomView_body .mx_RoomView_timeline { @@ -95,12 +102,10 @@ limitations under the License. flex-direction: column; } -.mx_RoomView_body .mx_RoomView_messagePanel { - order: 2; -} - -.mx_RoomView_body .mx_RoomView_messagePanelSpinner { - order: 2; +.mx_RoomView_body { + .mx_RoomView_messagePanel, .mx_RoomView_messagePanelSpinner, .mx_RoomView_messagePanelSearchSpinner{ + order: 2; + } } .mx_RoomView_body .mx_RoomView_statusArea { @@ -114,6 +119,31 @@ limitations under the License. .mx_RoomView_messagePanel { width: 100%; overflow-y: auto; + flex: 1 1 0; + overflow-anchor: none; +} + +.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-customised/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 { @@ -126,8 +156,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 { @@ -143,6 +180,10 @@ limitations under the License. .mx_RoomView_MessageList { list-style-type: none; 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 { diff --git a/res/css/structures/_ScrollPanel.scss b/res/css/structures/_ScrollPanel.scss new file mode 100644 index 0000000000..699224949b --- /dev/null +++ b/res/css/structures/_ScrollPanel.scss @@ -0,0 +1,26 @@ +/* +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_ScrollPanel { + + .mx_RoomView_MessageList { + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-end; + overflow-y: hidden; + } +} diff --git a/res/css/structures/_SearchBox.scss b/res/css/structures/_SearchBox.scss index e559236569..9434d93bd2 100644 --- a/res/css/structures/_SearchBox.scss +++ b/res/css/structures/_SearchBox.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_SearchBox_closeButton { cursor: pointer; - background-image: url('../../img/icons-close.svg'); + background-image: url('$(res)/img/icons-close.svg'); background-repeat: no-repeat; width: 16px; height: 16px; diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss new file mode 100644 index 0000000000..29e7c401e6 --- /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 0 0 58px; + display: flex; + flex-direction: column; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.mx_TabbedView_tabLabels { + width: 170px; + max-width: 170px; + color: $tab-label-fg-color; + position: fixed; +} + +.mx_TabbedView_tabLabel { + vertical-align: text-top; + cursor: pointer; + display: block; + border-radius: 3px; + font-size: 14px; + min-height: 24px; // 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; +} + +.mx_TabbedView_maskedIcon {; + margin-left: 6px; + margin-right: 9px; + margin-top: 1px; + width: 16px; + height: 16px; + display: inline-block; +} + +.mx_TabbedView_maskedIcon:before { + display: inline-block; + background-color: $tab-label-icon-bg-color; + mask-repeat: no-repeat; + mask-size: 16px; + width: 16px; + height: 22px; + 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 { + margin-left: 240px; // 170px sidebar + 70px padding + flex-grow: 1; + display: flex; + flex-direction: column; + min-height: 0; // firefox +} + +.mx_TabbedView_tabPanelContent { + flex-grow: 1; + overflow: auto; + min-height: 0; // firefox +} \ No newline at end of file diff --git a/res/css/structures/_TagPanel.scss b/res/css/structures/_TagPanel.scss index 77eefc7e10..084dcbfb47 100644 --- a/res/css/structures/_TagPanel.scss +++ b/res/css/structures/_TagPanel.scss @@ -15,7 +15,7 @@ limitations under the License. */ .mx_TagPanel { - flex: 0 0 70px; + flex: 1; background-color: $tagpanel-bg-color; cursor: pointer; @@ -68,10 +68,13 @@ limitations under the License. height: 100%; } +.mx_TagPanel .mx_TagPanel_tagTileContainer > div { + height: 40px; + padding: 5px 0 4px 0; +} .mx_TagPanel .mx_TagTile { - padding-top: 9px; - padding-bottom: 9px; + margin: 9px 0; // opacity: 0.5; position: relative; } @@ -81,13 +84,7 @@ limitations under the License. // opacity: 1; } -.mx_TagPanel .mx_TagTile.mx_TagTile_selected { - /* To offset border of mx_TagTile_avatar */ - padding: 3px 0px; -} - .mx_TagPanel .mx_TagTile.mx_TagTile_selected .mx_TagTile_avatar .mx_BaseAvatar { - border: 3px solid $accent-color; background-color: $accent-color; border-radius: 40px; @@ -97,6 +94,13 @@ limitations under the License. width: 40px; } +.mx_TagPanel .mx_TagTile_selected .mx_BaseAvatar_image { + border: 3px solid $accent-color; + height: 40px; + width: 40px; + box-sizing: border-box; +} + .mx_TagPanel .mx_TagTile.mx_AccessibleButton:focus { filter: none; } @@ -112,7 +116,7 @@ limitations under the License. height: 15px; position: absolute; right: -5px; - top: 1px; + top: -8px; border-radius: 8px; background-color: $neutral-badge-color; color: #ffffff; @@ -124,39 +128,22 @@ limitations under the License. padding-right: 4px; } -.mx_TagPanel_groupsButton { - flex: 0; - margin: 17px 0 3px 0; -} - -.mx_TagPanel_groupsButton > .mx_GroupsButton:before { - mask: url('../../img/feather-icons/users.svg'); - mask-position: center 11px; -} - -.mx_TagPanel_groupsButton > .mx_TagPanel_report:before { - mask: url('../../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; +.mx_TagTile_avatar { 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; - } +} + +.mx_TagTile_badge { + position: absolute; + right: -4px; + top: -2px; + border-radius: 8px; + color: $accent-fg-color; + font-weight: 600; + font-size: 14px; + padding: 0 5px; + background-color: $roomtile-name-color; +} + +.mx_TagTile_badgeHighlight { + background-color: $warning-color; } diff --git a/res/css/structures/_TagPanelButtons.scss b/res/css/structures/_TagPanelButtons.scss new file mode 100644 index 0000000000..b14bb10bf8 --- /dev/null +++ b/res/css/structures/_TagPanelButtons.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_TagPanelButtons { + background-color: $tagpanel-bg-color; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + padding: 17px 0 3px 0; +} + +.mx_TagPanelButtons > .mx_GroupsButton:before { + mask: url('$(res)/img/feather-customised/users.svg'); + mask-position: center 11px; +} + +.mx_TagPanelButtons > .mx_TagPanelButtons_report:before { + mask: url('$(res)/img/feather-customised/life-buoy.svg'); + mask-position: center 9px; +} + +.mx_TagPanelButtons > .mx_AccessibleButton { + margin-bottom: 12px; + height: 40px; + width: 40px; + border-radius: 20px; + background-color: $tagpanel-button-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 index 43a1e27ee4..94a391ae70 100644 --- a/res/css/structures/_TopLeftMenuButton.scss +++ b/res/css/structures/_TopLeftMenuButton.scss @@ -41,4 +41,9 @@ limitations under the License. .mx_TopLeftMenuButton_chevron { margin: 0 7px; + mask: url('$(res)/img/feather-customised/dropdown-arrow.svg'); + mask-repeat: no-repeat; + width: 10px; + height: 6px; + background-color: $roomsublist-label-fg-color; } diff --git a/res/css/structures/_UserSettings.scss b/res/css/structures/_UserSettings.scss deleted file mode 100644 index 6fae8d6c1a..0000000000 --- a/res/css/structures/_UserSettings.scss +++ /dev/null @@ -1,257 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 Vector Creations Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -.mx_UserSettings { - max-width: 960px; - width: 100%; - margin-left: auto; - margin-right: auto; - - display: flex; - flex-direction: column; -} - -.mx_UserSettings .mx_RoomHeader { - order: 1; - - flex: 0 0 70px; -} - -.mx_UserSettings_body { - order: 2; - - flex: 1 1 0; - - margin-top: -20px; - overflow-y: auto; -} - -.mx_UserSettings h3 { - clear: both; - margin-left: 63px; - text-transform: uppercase; - color: $h3-color; - font-weight: 600; - font-size: 13px; - margin-top: 26px; - margin-bottom: 10px; -} - -.mx_UserSettings_section h3 { - margin-left: 0px; -} - -.mx_UserSettings_spinner { - display: inline-block; - vertical-align: middle; - margin-right: 12px; - width: 32px; - height: 32px; -} - -.mx_UserSettings_button { - @mixin mx_DialogButton; - display: inline; - margin: auto; -} - -.mx_UserSettings_button:hover { - @mixin mx_DialogButton_hover; -} - -.mx_UserSettings_button.danger { - background-color: $warning-color; -} - -.mx_UserSettings_section { - margin-left: 63px; - margin-top: 28px; - margin-bottom: 28px; -} - -.mx_UserSettings_cryptoSection ul { - display: table; -} -.mx_UserSettings_cryptoSection li { - display: table-row; -} -.mx_UserSettings_cryptoSection label, -.mx_UserSettings_cryptoSection span { - display: table-cell; - padding-right: 1em; -} - -.mx_UserSettings_passwordWarning { - /* To move the "Sign out" button out of the way */ - clear: both; - color: $warning-color; - margin-bottom: 5px; -} - -.mx_UserSettings_importExportButtons { - padding-top: 10px; - padding-left: 40px; -} - -.mx_UserSettings_importExportButtons .mx_UserSettings_button { - margin-right: 1em; -} - -.mx_UserSettings_toggle input { - width: 16px; - margin-right: 8px; - margin-bottom: 8px; -} - -.mx_UserSettings_toggle label { - padding-bottom: 21px; -} - -.mx_UserSettings_accountTable -.mx_UserSettings_notifTable -{ - display: table; -} - -.mx_UserSettings_notifTable .mx_Spinner { - position: absolute; -} - -.mx_UserSettings_language { - width: 200px; -} - -.mx_UserSettings_webRtcDevices_dropdown { - width: 50%; -} - -.mx_UserSettings_profileTable -{ - display: table; - float: left; -} - -.mx_UserSettings_profileTableRow -{ - display: table-row; -} - -.mx_UserSettings_profileLabelCell -{ - padding-bottom: 21px; - display: table-cell; - font-weight: bold; - padding-right: 24px; -} - -.mx_UserSettings_profileInputCell { - display: table-cell; - padding-bottom: 21px; - width: 240px; -} - -.mx_UserSettings_profileInputCell input, -.mx_UserSettings_profileInputCell .mx_EditableText -{ - display: inline-block; - border: 0px; - border-bottom: 1px solid $input-underline-color; - padding: 0px; - width: 240px; - color: $input-fg-color; - font-family: 'Open Sans', Helvetica, Arial, Sans-Serif; - font-size: 16px; -} - -.mx_UserSettings_threepidButton { - display: table-cell; - padding-left: 0.5em; - position: relative; - cursor: pointer; -} - -.mx_UserSettings_phoneSection { - display:table; -} - -.mx_UserSettings_phoneCountry { - width: 70px; - display: table-cell; -} - -input.mx_UserSettings_phoneNumberField { - margin-left: 3px; - width: 172px; - border: 1px solid transparent; -} - -.mx_UserSettings_changePasswordButton { - float: right; - margin-right: 32px; - margin-left: 32px; -} - -.mx_UserSettings_logout { - float: right; - margin-right: 32px; - margin-left: 32px; -} - -.mx_UserSettings_avatarPicker { - margin-left: 32px; - margin-right: 32px; - float: right; - cursor: pointer; -} - -.mx_UserSettings_avatarPicker_img .mx_BaseAvatar_image { - object-fit: cover; -} - -.mx_UserSettings_avatarPicker_edit { - text-align: center; - margin-top: 10px; -} - -.mx_UserSettings_avatarPicker_edit img { - cursor: pointer; -} - -.mx_UserSettings_avatarPicker_edit > input { - display: none; -} - -.mx_UserSettings_avatarPicker_imgContainer { - display: inline-block; -} - -.mx_UserSettings_avatarPicker_remove { - display: inline-block; - float: right; - margin-right: -15px; -} - -.mx_UserSettings_advanced_spoiler, -.mx_UserSettings_link { - cursor: pointer; - color: $accent-color; - word-break: break-all; -} - -.mx_UserSettings_analyticsModal table { - margin: 10px 0px; -} diff --git a/res/css/structures/_ViewSource.scss b/res/css/structures/_ViewSource.scss index a4c7dcf58a..b908861c6f 100644 --- a/res/css/structures/_ViewSource.scss +++ b/res/css/structures/_ViewSource.scss @@ -14,6 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_ViewSource_label_left { + float: left; +} + +.mx_ViewSource_label_right { + float: right; +} + +.mx_ViewSource_label_bottom { + clear: both; + border-bottom: 1px solid #e5e5e5; +} + .mx_ViewSource pre { text-align: left; font-size: 12px; diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss new file mode 100644 index 0000000000..2cf6276557 --- /dev/null +++ b/res/css/structures/auth/_Login.scss @@ -0,0 +1,81 @@ +/* +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_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; + margin-top: 12px; + margin-bottom: 12px; +} + +.mx_Login_type_container { + display: flex; + align-items: center; + color: $authpage-primary-color; + + .mx_Field { + margin: 0; + } +} + +.mx_Login_type_label { + flex-grow: 1; +} + +.mx_Login_type_dropdown { + min-width: 200px; +} 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..fa034095b6 --- /dev/null +++ b/res/css/views/auth/_AuthBody.scss @@ -0,0 +1,132 @@ +/* +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-secondary-color; + + h2 { + font-size: 24px; + font-weight: 600; + margin-top: 8px; + color: $authpage-primary-color; + } + + h3 { + font-size: 14px; + font-weight: 600; + color: $authpage-primary-color; + } + + a:link, + a:hover, + a:visited { + color: $accent-color; + text-decoration: none; + } + + input[type=text], + input[type=password] { + color: $authpage-primary-color; + } + + .mx_Field input, + .mx_Field select { + color: $authpage-primary-color; + background-color: $authpage-body-bg-color; + } + + .mx_Field label { + color: $authpage-primary-color; + } + + .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 */, + .mx_Field_labelAlwaysTopLeft label { + background-color: $authpage-body-bg-color; + } + + input.error { + color: $warning-color; + } + + .mx_Field input { + width: 100%; + box-sizing: border-box; + } + + .mx_Field_select::before { + background-color: $authpage-primary-color; + } + + .mx_Dropdown { + color: $authpage-primary-color; + } + + .mx_Dropdown_arrow { + background: $authpage-primary-color; + } + + .mx_Dropdown_menu { + background-color: $authpage-body-bg-color; + + .mx_Dropdown_option_highlight { + background-color: $authpage-focus-bg-color; + } + } +} + +.mx_AuthBody_editServerDetails { + padding-left: 1em; + font-size: 12px; + font-weight: normal; +} + +.mx_AuthBody_fieldRow { + display: flex; + margin-bottom: 10px; +} + +.mx_AuthBody_fieldRow > .mx_Field { + margin: 0 5px; + flex: 1; +} + +.mx_AuthBody_fieldRow > .mx_Field:first-child { + margin-left: 0; +} + +.mx_AuthBody_fieldRow > .mx_Field:last-child { + margin-right: 0; +} + +.mx_AuthBody_changeFlow { + display: block; + text-align: center; + width: 100%; +} + +.mx_AuthBody_spinner { + margin: 1em 0; +} 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..ab169a6898 --- /dev/null +++ b/res/css/views/auth/_AuthFooter.scss @@ -0,0 +1,31 @@ +/* +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; + padding: 20px 0; + background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.8)); +} + +.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..b3d07b1925 --- /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 40px; + 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..091fb0197b --- /dev/null +++ b/res/css/views/auth/_AuthHeaderLogo.scss @@ -0,0 +1,25 @@ +/* +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; + padding: 0 10px; +} + +.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..8ef48b6265 --- /dev/null +++ b/res/css/views/auth/_AuthPage.scss @@ -0,0 +1,31 @@ +/* +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; + 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/src/UiEffects.js b/res/css/views/auth/_LanguageSelector.scss similarity index 63% rename from src/UiEffects.js rename to res/css/views/auth/_LanguageSelector.scss index 76db0b7f12..6f7eac0cf6 100644 --- a/src/UiEffects.js +++ b/res/css/views/auth/_LanguageSelector.scss @@ -1,5 +1,5 @@ /* -Copyright 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. @@ -14,14 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -/** - * Functions for applying common thematic effects to UI elements. - * Ideally this would be themeable. - */ - -import Velocity from 'velocity-vector'; -import 'velocity-vector/velocity.ui'; - -export function field_input_incorrect(element) { - Velocity(element, "callout.shake", 300); +.mx_AuthBody_language { + width: 100%; +} + +.mx_AuthBody_language .mx_Dropdown_input { + border: none; + font-size: 14px; + font-weight: 600; + color: $authpage-lang-color; +} + +.mx_AuthBody_language .mx_Dropdown_arrow { + 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..ed781726b7 --- /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: $authpage-primary-color; + margin: 8px 0; +} + +.mx_ServerTypeSelector_type .mx_AccessibleButton { + padding: 10px; + border: 1px solid $input-border-color; + border-radius: 4px; +} + +.mx_ServerTypeSelector_type.mx_ServerTypeSelector_type_selected .mx_AccessibleButton { + border-color: $input-valid-border-color; +} + +.mx_ServerTypeSelector_logo { + display: flex; + justify-content: center; + height: 18px; + margin-bottom: 12px; + font-weight: 600; + color: $authpage-primary-color; +} + +.mx_ServerTypeSelector_logo > div { + display: flex; + width: 70%; + align-items: center; + justify-content: space-evenly; +} + +.mx_ServerTypeSelector_description { + font-size: 10px; +} diff --git a/res/css/views/auth/_Welcome.scss b/res/css/views/auth/_Welcome.scss new file mode 100644 index 0000000000..9043289184 --- /dev/null +++ b/res/css/views/auth/_Welcome.scss @@ -0,0 +1,26 @@ +/* +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_Welcome { + display: flex; + flex-direction: column; + align-items: center; +} + +.mx_Welcome .mx_AuthBody_language { + width: 120px; + margin-bottom: 10px; +} diff --git a/res/css/views/avatars/_BaseAvatar.scss b/res/css/views/avatars/_BaseAvatar.scss index ee2d9c190f..91b2d6c426 100644 --- a/res/css/views/avatars/_BaseAvatar.scss +++ b/res/css/views/avatars/_BaseAvatar.scss @@ -16,6 +16,16 @@ limitations under the License. .mx_BaseAvatar { position: relative; + // In at least Firefox, the case of relative positioned inline elements + // (such as mx_BaseAvatar) with absolute positioned children (such as + // mx_BaseAvatar_initial) is a dark corner full of spider webs. It will give + // different results during full reflow of the page vs. incremental reflow + // of small portions. While that's surely a browser bug, we can avoid it by + // using `inline-block` instead of the default `inline`. + // https://github.com/vector-im/riot-web/issues/5594 + // https://bugzilla.mozilla.org/show_bug.cgi?id=1535053 + // https://bugzilla.mozilla.org/show_bug.cgi?id=255139 + display: inline-block; } .mx_BaseAvatar_initial { diff --git a/res/css/views/avatars/_MemberStatusMessageAvatar.scss b/res/css/views/avatars/_MemberStatusMessageAvatar.scss index 29cae9df34..c101a5d8a8 100644 --- a/res/css/views/avatars/_MemberStatusMessageAvatar.scss +++ b/res/css/views/avatars/_MemberStatusMessageAvatar.scss @@ -14,8 +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; - padding-right: 0 !important; /* Override AccessibleButton styling */ +.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/_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 index 960e052a30..113da004b8 100644 --- a/res/css/views/context_menus/_TopLeftMenu.scss +++ b/res/css/views/context_menus/_TopLeftMenu.scss @@ -15,20 +15,74 @@ limitations under the License. */ .mx_TopLeftMenu { - min-width: 180px; + min-width: 210px; + border-radius: 4px; + + .mx_TopLeftMenu_greyedText { + font-size: 12px; + opacity: 0.5; + } + + .mx_TopLeftMenu_upgradeLink { + font-size: 12px; + + img { + margin-left: 5px; + } + } .mx_TopLeftMenu_section:not(:last-child) { border-bottom: 1px solid $menu-border-color; } - .mx_TopLeftMenu_section { - list-style: none; + .mx_TopLeftMenu_section_noIcon { + margin: 5px 0; + padding: 5px 20px 5px 15px; + + div:not(:first-child) { + margin-top: 5px; + } + } + + .mx_TopLeftMenu_section_withIcon { margin: 5px 0; padding: 0; + list-style: none; + + li.mx_TopLeftMenu_icon_home::after { + mask-image: url('$(res)/img/feather-customised/home.svg'); + } + + li.mx_TopLeftMenu_icon_settings::after { + mask-image: url('$(res)/img/feather-customised/settings.svg'); + } + + li.mx_TopLeftMenu_icon_signin::after { + mask-image: url('$(res)/img/feather-customised/sign-in.svg'); + } + + li.mx_TopLeftMenu_icon_signout::after { + mask-image: url('$(res)/img/feather-customised/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; + padding: 5px 20px 5px 43px; } li:hover { diff --git a/res/css/views/dialogs/_Analytics.scss b/res/css/views/dialogs/_Analytics.scss new file mode 100644 index 0000000000..e403d3b207 --- /dev/null +++ b/res/css/views/dialogs/_Analytics.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_AnalyticsModal table { + margin: 10px 0px; +} diff --git a/res/css/views/dialogs/_BugReportDialog.scss b/res/css/views/dialogs/_BugReportDialog.scss index e00d446eda..90ef55b945 100644 --- a/res/css/views/dialogs/_BugReportDialog.scss +++ b/res/css/views/dialogs/_BugReportDialog.scss @@ -14,39 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_BugReportDialog_field_container { - display: flex; -} - -.mx_BugReportDialog_field_label { - flex-basis: 150px; - - text-align: right; - - padding-top: 9px; - padding-right: 4px; - - line-height: 18px; +.mx_BugReportDialog .mx_Field { + flex: 1; } .mx_BugReportDialog_field_input { - flex-grow: 1; - - /* taken from mx_ChatInviteDialog_inputContainer */ - border-radius: 3px; - border: solid 1px $input-border-color; - - font-size: 14px; - - padding-left: 4px; - padding-right: 4px; - padding-top: 7px; - padding-bottom: 7px; - - margin-bottom: 4px; -} - -.mx_BugReportDialog_field_input[type="text" i] { - padding-top: 9px; - padding-bottom: 9px; + // TODO: We should really apply this to all .mx_Field inputs. + // See https://github.com/vector-im/riot-web/issues/9344. + flex: 1; } diff --git a/res/css/views/dialogs/_CreateGroupDialog.scss b/res/css/views/dialogs/_CreateGroupDialog.scss index 500e12ee49..128eacc3ce 100644 --- a/res/css/views/dialogs/_CreateGroupDialog.scss +++ b/res/css/views/dialogs/_CreateGroupDialog.scss @@ -43,10 +43,9 @@ limitations under the License. .mx_CreateGroupDialog_prefix, .mx_CreateGroupDialog_suffix { - height: 35px; padding: 0px 5px; line-height: 37px; - background-color: $input-border-color; + background-color: $input-darker-bg-color; border: 1px solid $input-border-color; text-align: center; } diff --git a/res/css/views/dialogs/_DeviceVerifyDialog.scss b/res/css/views/dialogs/_DeviceVerifyDialog.scss new file mode 100644 index 0000000000..1997e0c21d --- /dev/null +++ b/res/css/views/dialogs/_DeviceVerifyDialog.scss @@ -0,0 +1,29 @@ +/* +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_DeviceVerifyDialog_cryptoSection ul { + display: table; +} + +.mx_DeviceVerifyDialog_cryptoSection li { + display: table-row; +} + +.mx_DeviceVerifyDialog_cryptoSection label, +.mx_DeviceVerifyDialog_cryptoSection span { + display: table-cell; + padding-right: 1em; +} diff --git a/res/css/views/dialogs/_DevtoolsDialog.scss b/res/css/views/dialogs/_DevtoolsDialog.scss index a4a868bd11..815e8408b5 100644 --- a/res/css/views/dialogs/_DevtoolsDialog.scss +++ b/res/css/views/dialogs/_DevtoolsDialog.scss @@ -61,18 +61,26 @@ 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; } .mx_DevTools_textarea { font-size: 12px; - max-width: 624px; + max-width: 684px; min-height: 250px; padding: 10px; width: 100%; } +.mx_DevTools_content .mx_Field_input { + display: inline-block; +} + +.mx_DevTools_content .mx_Field_input + .mx_Field_input { + margin-left: 42px; +} + .mx_DevTools_tgl { display: none; 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/_IncomingSasDialog.scss b/res/css/views/dialogs/_IncomingSasDialog.scss new file mode 100644 index 0000000000..3a9d645a98 --- /dev/null +++ b/res/css/views/dialogs/_IncomingSasDialog.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_IncomingSasDialog_opponentProfile_image { + position: relative; +} + +.mx_IncomingSasDialog_opponentProfile h2 { + display: inline-block; + margin-left: 10px; +} diff --git a/res/css/views/dialogs/_RoomSettingsDialog.scss b/res/css/views/dialogs/_RoomSettingsDialog.scss new file mode 100644 index 0000000000..60b35528a1 --- /dev/null +++ b/res/css/views/dialogs/_RoomSettingsDialog.scss @@ -0,0 +1,44 @@ +/* +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-customised/settings.svg'); +} + +.mx_RoomSettingsDialog_securityIcon:before { + mask-image: url('$(res)/img/feather-customised/lock.svg'); +} + +.mx_RoomSettingsDialog_rolesIcon:before { + mask-image: url('$(res)/img/feather-customised/users-sm.svg'); +} + +.mx_RoomSettingsDialog_warningIcon:before { + mask-image: url('$(res)/img/feather-customised/warning-triangle.svg'); +} + +.mx_RoomSettingsDialog .mx_Dialog_title { + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + margin: 0 auto; + padding-left: 40px; + padding-right: 80px; +} diff --git a/res/css/views/dialogs/_SettingsDialog.scss b/res/css/views/dialogs/_SettingsDialog.scss new file mode 100644 index 0000000000..abf0048cfd --- /dev/null +++ b/res/css/views/dialogs/_SettingsDialog.scss @@ -0,0 +1,47 @@ +/* +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: 1000px; + width: 90%; + height: 80%; + border-radius: 4px; + padding-top: 0; + padding-right: 0; + padding-left: 0; + + .mx_TabbedView { + top: 65px; + } + + .mx_TabbedView .mx_SettingsTab { + box-sizing: border-box; + min-width: 580px; + padding-right: 130px; + + // Put some padding on the bottom to avoid the settings tab from + // colliding harshly with the dialog when scrolled down. + padding-bottom: 100px; + } + + .mx_Dialog_title { + text-align: center; + margin-top: 16px; + margin-bottom: 24px; + } + } +} diff --git a/res/css/views/dialogs/_UnknownDeviceDialog.scss b/res/css/views/dialogs/_UnknownDeviceDialog.scss index e3801e3550..02e0fb1fe5 100644 --- a/res/css/views/dialogs/_UnknownDeviceDialog.scss +++ b/res/css/views/dialogs/_UnknownDeviceDialog.scss @@ -28,24 +28,28 @@ limitations under the License. flex-direction: column; } +.mx_UnknownDeviceDialog ul { + list-style: none; + padding: 0; +} +// userid +.mx_UnknownDeviceDialog p { + font-weight: bold; + font-size: 16px; +} + +.mx_UnknownDeviceDialog .mx_DeviceVerifyButtons { + flex-direction: row !important; +} + .mx_UnknownDeviceDialog .mx_Dialog_content { margin-bottom: 24px; } -.mx_UnknownDeviceDialog .mx_MemberDeviceInfo { - float: right; - clear: both; - padding: 0px; - padding-top: 8px; +.mx_UnknownDeviceDialog_deviceList > li { + padding: 4px; } -.mx_UnknownDeviceDialog .mx_MemberDeviceInfo_textButton { - @mixin mx_DialogButton_small; - background-color: $primary-bg-color; - color: $accent-color; -} - -.mx_UnknownDeviceDialog .mx_UnknownDeviceDialog_deviceList li { - height: 40px; - border-bottom: 1px solid $primary-hairline-color; +.mx_UnknownDeviceDialog_deviceList > li > * { + padding-bottom: 0; } diff --git a/res/css/views/dialogs/_UploadConfirmDialog.scss b/res/css/views/dialogs/_UploadConfirmDialog.scss new file mode 100644 index 0000000000..116be798e3 --- /dev/null +++ b/res/css/views/dialogs/_UploadConfirmDialog.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_UploadConfirmDialog_fileIcon { + margin-right: 5px; +} + +.mx_UploadConfirmDialog_previewOuter { + text-align: center; +} + +.mx_UploadConfirmDialog_previewInner { + display: inline-block; + text-align: left; +} + +.mx_UploadConfirmDialog_imagePreview { + max-height: 300px; + max-width: 100%; +} diff --git a/res/css/views/dialogs/_UserSettingsDialog.scss b/res/css/views/dialogs/_UserSettingsDialog.scss new file mode 100644 index 0000000000..9665ee06b4 --- /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-customised/settings.svg'); +} + +.mx_UserSettingsDialog_voiceIcon:before { + mask-image: url('$(res)/img/feather-customised/phone.svg'); +} + +.mx_UserSettingsDialog_bellIcon:before { + mask-image: url('$(res)/img/feather-customised/notifications.svg'); +} + +.mx_UserSettingsDialog_preferencesIcon:before { + mask-image: url('$(res)/img/feather-customised/sliders.svg'); +} + +.mx_UserSettingsDialog_securityIcon:before { + mask-image: url('$(res)/img/feather-customised/lock.svg'); +} + +.mx_UserSettingsDialog_helpIcon:before { + mask-image: url('$(res)/img/feather-customised/help-circle.svg'); +} + +.mx_UserSettingsDialog_labsIcon:before { + mask-image: url('$(res)/img/feather-customised/flag.svg'); +} + +.mx_UserSettingsDialog_flairIcon:before { + mask-image: url('$(res)/img/feather-customised/flair.svg'); +} diff --git a/res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss b/res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss new file mode 100644 index 0000000000..a419c105a9 --- /dev/null +++ b/res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss @@ -0,0 +1,28 @@ +/* +Copyright 2019 Travis Ralston + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_WidgetOpenIDPermissionsDialog .mx_SettingsFlag { + .mx_ToggleSwitch { + display: inline-block; + vertical-align: middle; + margin-right: 8px; + } + + .mx_SettingsFlag_label { + display: inline-block; + vertical-align: middle; + } +} diff --git a/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss b/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss index 4a050b6fc4..f905516bd4 100644 --- a/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss +++ b/res/css/views/dialogs/keybackup/_KeyBackupFailedDialog.scss @@ -24,7 +24,7 @@ limitations under the License. padding-bottom: 10px; &:before { - mask: url("../../img/e2e/lock-warning.svg"); + mask: url("$(res)/img/e2e/lock-warning-filled.svg"); mask-repeat: no-repeat; background-color: $primary-fg-color; content: ""; 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 d6702a232c..25ad51a3fb 100644 --- a/res/css/views/elements/_AccessibleButton.scss +++ b/res/css/views/elements/_AccessibleButton.scss @@ -21,3 +21,55 @@ limitations under the License. .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 { + opacity: 0.4; +} + +.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 { + opacity: 0.4; +} + +.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; +} 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..2a59393499 100644 --- a/res/css/views/elements/_Dropdown.scss +++ b/res/css/views/elements/_Dropdown.scss @@ -16,6 +16,7 @@ limitations under the License. .mx_Dropdown { position: relative; + color: $primary-fg-color; } .mx_Dropdown_disabled { @@ -23,16 +24,17 @@ 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; } .mx_Dropdown_input:focus { - border-color: $accent-color; + border-color: $input-focused-border-color; } /* Disable dropdown highlight on focus */ @@ -41,29 +43,19 @@ 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 -} - -.mx_Dropdown.left_aligned .mx_Dropdown_arrow { - left: 10px; + width: 10px; + height: 6px; + padding-right: 9px; + mask: url('$(res)/img/feather-customised/dropdown-arrow.svg'); + mask-repeat: no-repeat; + background: $primary-fg-color; } .mx_Dropdown_input > .mx_Dropdown_option { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; -} - -.mx_Dropdown.left_aligned .mx_Dropdown_input > .mx_Dropdown_option { - padding-left: 25px; + flex: 1; } .mx_Dropdown_option { @@ -81,11 +73,13 @@ limitations under the License. .mx_Dropdown_option img { margin: 5px; - width: 27px; + width: 16px; vertical-align: middle; } -input.mx_Dropdown_option, input.mx_Dropdown_option:focus { +input.mx_Dropdown_option, +input.mx_Dropdown_option:focus { + font-weight: normal; border: 0; padding-top: 0; padding-bottom: 0; @@ -104,7 +98,7 @@ input.mx_Dropdown_option, input.mx_Dropdown_option:focus { margin: 0; padding: 0px; border-radius: 3px; - border: 1px solid $accent-color; + border: 1px solid $input-focused-border-color; background-color: $primary-bg-color; max-height: 200px; overflow-y: auto; @@ -119,10 +113,6 @@ input.mx_Dropdown_option, input.mx_Dropdown_option:focus { background-color: $focus-bg-color; } -.mx_Dropdown_menu { - font-weight: bold; -} - .mx_Dropdown_searchPrompt { font-weight: normal; margin-left: 5px; diff --git a/res/css/views/elements/_EditableItemList.scss b/res/css/views/elements/_EditableItemList.scss index 9fbb39aa17..be96d811d3 100644 --- a/res/css/views/elements/_EditableItemList.scss +++ b/res/css/views/elements/_EditableItemList.scss @@ -1,5 +1,5 @@ /* -Copyright 2017 New Vector Ltd. +Copyright 2017, 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. @@ -16,47 +16,38 @@ limitations under the License. .mx_EditableItemList { margin-top: 12px; - margin-bottom: 0px; + margin-bottom: 10px; } .mx_EditableItem { - display: flex; - margin-left: 56px; + margin-bottom: 5px; + margin-left: 15px; } -.mx_EditableItem .mx_EditableItem_editable { - border: 0px; - border-bottom: 1px solid $strong-input-border-color; - padding: 0px; - min-width: 240px; - max-width: 400px; - margin-bottom: 16px; -} - -.mx_EditableItem .mx_EditableItem_editable:focus { - border-bottom: 1px solid $accent-color; - outline: none; - box-shadow: none; -} - -.mx_EditableItem .mx_EditableItem_editablePlaceholder { - color: $settings-grey-fg-color; -} - -.mx_EditableItem .mx_EditableItem_addButton, -.mx_EditableItem .mx_EditableItem_removeButton { - padding-left: 0.5em; - position: relative; +.mx_EditableItem_delete { + margin-right: 5px; cursor: pointer; - - visibility: hidden; + vertical-align: middle; } -.mx_EditableItem:hover .mx_EditableItem_addButton, -.mx_EditableItem:hover .mx_EditableItem_removeButton { - visibility: visible; +.mx_EditableItem_email { + vertical-align: middle; +} + +.mx_EditableItem_promptText { + margin-right: 10px; +} + +.mx_EditableItem_confirmBtn { + margin-right: 5px; +} + +.mx_EditableItemList_newItem .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_EditableItemList_label { - margin-bottom: 8px; -} + margin-bottom: 5px; +} \ No newline at end of file diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss new file mode 100644 index 0000000000..20b1efd28b --- /dev/null +++ b/res/css/views/elements/_Field.scss @@ -0,0 +1,186 @@ +/* +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 _light.scss */ + +.mx_Field { + display: flex; + position: relative; + margin: 1em 0; + border-radius: 4px; + transition: border-color 0.25s; + border: 1px solid $input-border-color; +} + +.mx_Field_prefix { + border-right: 1px solid $input-border-color; +} + +.mx_Field input, +.mx_Field select, +.mx_Field textarea { + font-weight: normal; + font-family: $font-family; + font-size: 14px; + border: none; + // Even without a border here, we still need this avoid overlapping the rounded + // corners on the field above. + border-radius: 4px; + padding: 8px 9px; + color: $primary-fg-color; + background-color: $primary-bg-color; +} + +.mx_Field select { + -moz-appearance: none; + -webkit-appearance: none; +} + +// Can't add pseudo-elements to a select directly, so we use its parent. +.mx_Field_select::before { + content: ""; + position: absolute; + top: 15px; + right: 10px; + width: 10px; + height: 6px; + mask: url('$(res)/img/feather-customised/dropdown-arrow.svg'); + mask-repeat: no-repeat; + background-color: $primary-fg-color; + z-index: 1; + pointer-events: none; +} + +.mx_Field:focus-within { + border-color: $input-focused-border-color; +} + +.mx_Field input:focus, +.mx_Field select:focus, +.mx_Field textarea:focus { + outline: 0; +} + +.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; + pointer-events: none; // Allow clicks to fall through to the input + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + max-width: calc(100% - 20px); // 100% of parent minus margin and padding +} + +.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 */, +.mx_Field_labelAlwaysTopLeft label { + 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: -13px; + padding: 0 2px; + background-color: $field-focused-label-bg-color; + pointer-events: initial; +} + +.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 select:disabled + label, +.mx_Field input:disabled, +.mx_Field input:disabled + label, +.mx_Field textarea:disabled, +.mx_Field textarea:disabled + label { + background-color: $field-focused-label-bg-color; + color: $greyed-fg-color; +} + +.mx_Field_valid { + &.mx_Field, + &.mx_Field:focus-within { + border-color: $input-valid-border-color; + } + + &.mx_Field label, + &.mx_Field:focus-within label { + color: $input-valid-border-color; + } +} + +.mx_Field_invalid { + &.mx_Field, + &.mx_Field:focus-within { + border-color: $input-invalid-border-color; + } + + &.mx_Field label, + &.mx_Field:focus-within label { + color: $input-invalid-border-color; + } +} + +.mx_Field_tooltip { + margin-top: -12px; + margin-left: 4px; +} + +.mx_Field_tooltip.mx_Field_valid { + animation: mx_fadeout 1s 2s forwards; +} + +// Customise other components when placed inside a Field + +.mx_Field .mx_Dropdown_input { + border: initial; + border-radius: initial; +} + +.mx_Field .mx_CountryDropdown { + width: 67px; +} diff --git a/res/css/views/elements/_ImageView.scss b/res/css/views/elements/_ImageView.scss index 8ed0698a72..52b6a63699 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; } @@ -77,7 +77,8 @@ limitations under the License. .mx_ImageView_cancel { position: absolute; - top: 0px; + // hack for mx_Dialog having a top padding of 40px + top: 40px; right: 0px; padding: 35px; cursor: pointer; diff --git a/res/css/views/elements/_ManageIntegsButton.scss b/res/css/views/elements/_ManageIntegsButton.scss new file mode 100644 index 0000000000..7c91b9dbde --- /dev/null +++ b/res/css/views/elements/_ManageIntegsButton.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_ManageIntegsButton_error { + position: relative; + cursor: not-allowed; +} + +.mx_ManageIntegsButton_error img { + position: absolute; + right: -5px; + top: -5px; +} + +.mx_ManageIntegsButton_error { + float: right; +} + +.mx_ManageIntegsButton_error .mx_ManageIntegsButton_errorPopup { + display: none; +} + +.mx_ManageIntegsButton_error:hover .mx_ManageIntegsButton_errorPopup { + display: inline; +} + +.mx_ManageIntegsButton_errorPopup { + position: absolute; + top: 110%; + 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; +} diff --git a/res/css/views/elements/_PowerSelector.scss b/res/css/views/elements/_PowerSelector.scss new file mode 100644 index 0000000000..69f3a8eebb --- /dev/null +++ b/res/css/views/elements/_PowerSelector.scss @@ -0,0 +1,25 @@ +/* +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_PowerSelector { + width: 100%; +} + +.mx_PowerSelector .mx_Field select, +.mx_PowerSelector .mx_Field input { + width: 100%; + box-sizing: border-box; +} diff --git a/res/css/views/elements/_ResizeHandle.scss b/res/css/views/elements/_ResizeHandle.scss index 42ff6e3825..5544799a34 100644 --- a/res/css/views/elements/_ResizeHandle.scss +++ b/res/css/views/elements/_ResizeHandle.scss @@ -32,6 +32,11 @@ limitations under the License. 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; } diff --git a/res/css/views/elements/_RichText.scss b/res/css/views/elements/_RichText.scss index e35f4d60f4..cf2c066589 100644 --- a/res/css/views/elements/_RichText.scss +++ b/res/css/views/elements/_RichText.scss @@ -79,6 +79,15 @@ .mx_Markdown_ITALIC { font-style: italic; +/* + // interestingly, *not* using the explicit italic font + // variant seems yield better results. + + // 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/rooms/_RoomTooltip.scss b/res/css/views/elements/_Tooltip.scss similarity index 54% rename from res/css/views/rooms/_RoomTooltip.scss rename to res/css/views/elements/_Tooltip.scss index 295786d2d3..2f35bd338e 100644 --- a/res/css/views/rooms/_RoomTooltip.scss +++ b/res/css/views/elements/_Tooltip.scss @@ -1,5 +1,6 @@ /* 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. @@ -14,41 +15,55 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_RoomTooltip_chevron { - position: absolute; - left: -8px; - top: 4px; - width: 0; - height: 0; - border-top: 8px solid transparent; - border-right: 8px solid $menu-bg-color; - border-bottom: 8px solid transparent; +@keyframes mx_fadein { + from { opacity: 0; } + to { opacity: 1; } } -.mx_RoomTooltip_chevron:after { - content:''; +@keyframes mx_fadeout { + from { opacity: 1; } + to { opacity: 0; } +} + +.mx_Tooltip_chevron { + position: absolute; + left: -7px; + top: 10px; width: 0; height: 0; border-top: 7px solid transparent; - border-right: 7px solid $primary-bg-color; + border-right: 7px solid $menu-border-color; border-bottom: 7px solid transparent; - position:absolute; - top: -7px; +} + +.mx_Tooltip_chevron:after { + content:''; + width: 0; + height: 0; + border-top: 6px solid transparent; + border-right: 6px solid $menu-bg-color; + border-bottom: 6px solid transparent; + position: absolute; + top: -6px; left: 1px; } -.mx_RoomTooltip { +.mx_Tooltip { display: none; + animation: mx_fadein 0.2s; position: fixed; - border-radius: 5px; - box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.21); - background-color: $primary-bg-color; + border: 1px solid $menu-border-color; + border-radius: 4px; + box-shadow: 4px 4px 12px 0 $menu-box-shadow-color; + background-color: $menu-bg-color; z-index: 2000; - padding: 5px; + padding: 10px; pointer-events: none; line-height: 14px; - font-size: 13px; + font-size: 12px; + font-weight: 600; color: $primary-fg-color; - max-width: 600px; + max-width: 200px; + word-break: break-word; margin-right: 50px; } 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/_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/_CreateEvent.scss b/res/css/views/messages/_CreateEvent.scss index c095fc26af..adf16d6c4a 100644 --- a/res/css/views/messages/_CreateEvent.scss +++ b/res/css/views/messages/_CreateEvent.scss @@ -24,9 +24,14 @@ limitations under the License. .mx_CreateEvent_image { float: left; - padding-right: 20px; + margin-right: 20px; width: 72px; height: 34px; + + background-color: $primary-fg-color; + mask: url('$(res)/img/room-continuation.svg'); + mask-repeat: no-repeat; + mask-position: center; } .mx_CreateEvent_header { diff --git a/res/css/views/room_settings/_AliasSettings.scss b/res/css/views/room_settings/_AliasSettings.scss new file mode 100644 index 0000000000..d4ae58e5b0 --- /dev/null +++ b/res/css/views/room_settings/_AliasSettings.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_AliasSettings_editable { + border: 0px; + border-bottom: 1px solid $strong-input-border-color; + padding: 0px; + min-width: 240px; +} + +.mx_AliasSettings_editable:focus { + border-bottom: 1px solid $accent-color; + outline: none; + box-shadow: none; +} diff --git a/res/css/views/room_settings/_ColorSettings.scss b/res/css/views/room_settings/_ColorSettings.scss new file mode 100644 index 0000000000..39b087653d --- /dev/null +++ b/res/css/views/room_settings/_ColorSettings.scss @@ -0,0 +1,39 @@ +/* +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_ColorSettings_roomColor { + display: inline-block; + position: relative; + width: 37px; + height: 37px; + border: 1px solid #979797; + margin-right: 13px; + cursor: pointer; +} + +.mx_ColorSettings_roomColor_selected { + position: absolute; + left: 10px; + top: 4px; + cursor: default ! important; +} + +.mx_ColorSettings_roomColorPrimary { + height: 10px; + position: absolute; + bottom: 0px; + width: 100%; +} diff --git a/res/css/views/rooms/_AppsDrawer.scss b/res/css/views/rooms/_AppsDrawer.scss index 4a46063376..db38eebfca 100644 --- a/res/css/views/rooms/_AppsDrawer.scss +++ b/res/css/views/rooms/_AppsDrawer.scss @@ -14,6 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ +/* +the tile title bar is 5 (top border) + 12 (title, buttons) + 5 (bottom padding) px = 22px +the body is assumed to be 300px (assumed by at least the sticker pickerm, perhaps elsewhere), +so the body height would be 300px - 22px (room for title bar) = 278px +BUT! the sticker picker also assumes it's a little less high than that because the iframe +for the sticker picker doesn't have any padding or margin on it's bottom. +so subtracking another 5px, which brings us at 273px. +*/ +$AppsDrawerBodyHeight: 273px; + .mx_AppsDrawer { margin: 5px; } @@ -56,9 +66,8 @@ limitations under the License. max-width: 960px; width: 50%; margin-right: 5px; - border: 1px solid $primary-hairline-color; - border-radius: 2px; - background-color: $dialog-background-bg-color; + border: 5px solid $widget-menu-bar-bg-color; + border-radius: 4px; } .mx_AppTile:last-child { @@ -71,8 +80,8 @@ limitations under the License. height: 100%; margin: 0; padding: 0; - border: 1px solid $primary-hairline-color; - border-radius: 2px; + border: 5px solid $widget-menu-bar-bg-color; + border-radius: 4px; } .mx_AppTile_mini { @@ -84,7 +93,7 @@ limitations under the License. } .mx_AppTile_persistedWrapper { - height: 280px; + height: $AppsDrawerBodyHeight; } .mx_AppTile_mini .mx_AppTile_persistedWrapper { @@ -93,9 +102,7 @@ limitations under the License. .mx_AppTileMenuBar { margin: 0; - padding: 2px 10px; - border-bottom: 1px solid $primary-hairline-color; - font-size: 10px; + font-size: 12px; background-color: $widget-menu-bar-bg-color; display: flex; flex-direction: row; @@ -104,6 +111,10 @@ limitations under the License. cursor: pointer; } +.mx_AppTileMenuBar_expanded { + padding-bottom: 5px; +} + .mx_AppTileMenuBarTitle { display: flex; flex-direction: row; @@ -111,6 +122,10 @@ limitations under the License. pointer-events: none; } +.mx_AppTileMenuBarTitle > :last-child { + margin-left: 9px; +} + .mx_AppTileMenuBarWidgets { float: right; display: flex; @@ -118,6 +133,53 @@ limitations under the License. align-items: center; } +.mx_AppTileMenuBar_iconButton { + width: 12px; + height: 12px; + mask-repeat: no-repeat; + mask-position: 0 center; + mask-size: auto 12px; + background-color: $topleftmenu-color; + margin: 0 3px; +} + +.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_minimise { + mask-image: url('$(res)/img/feather-customised/widget/minimise.svg'); + background-color: $accent-color; +} + +.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_maximise { + mask-image: url('$(res)/img/feather-customised/widget/maximise.svg'); + background-color: $accent-color; +} + +.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_reload { + mask-image: url('$(res)/img/feather-customised/widget/refresh.svg'); + mask-size: 100%; +} + +.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_popout { + mask-image: url('$(res)/img/feather-customised/widget/external-link.svg'); +} + +.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_snapshot { + mask-image: url('$(res)/img/feather-customised/widget/camera.svg'); +} + +.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_edit { + mask-image: url('$(res)/img/feather-customised/widget/edit.svg'); +} + +.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_delete { + mask-image: url('$(res)/img/feather-customised/widget/bin.svg'); + background-color: $warning-color; +} + +.mx_AppTileMenuBar_iconButton.mx_AppTileMenuBar_iconButton_cancel { + mask-image: url('$(res)/img/feather-customised/widget/x-circle.svg'); +} + +/* delete ? */ .mx_AppTileMenuBarWidget { cursor: pointer; width: 10px; @@ -137,7 +199,7 @@ limitations under the License. } .mx_AppTileBody{ - height: 280px; + height: $AppsDrawerBodyHeight; width: 100%; overflow: hidden; } @@ -156,7 +218,7 @@ limitations under the License. .mx_AppTileBody iframe { width: 100%; - height: 280px; + height: $AppsDrawerBodyHeight; overflow: hidden; border: none; padding: 0; @@ -265,14 +327,11 @@ form.mx_Custom_Widget_Form div { } .mx_AppPermissionButton { - padding: 5px; + border: none; + padding: 5px 20px; border-radius: 5px; - color: $warning-color; - background-color: $primary-bg-color; -} - -.mx_AppPermissionButton:hover { - background-color: $primary-fg-color; + background-color: $button-bg-color; + color: $button-fg-color; cursor: pointer; } @@ -283,7 +342,7 @@ form.mx_Custom_Widget_Form div { align-items: center; font-weight: bold; position: relative; - height: 280px; + height: $AppsDrawerBodyHeight; } .mx_AppLoading .mx_Spinner { diff --git a/res/css/views/rooms/_Autocomplete.scss b/res/css/views/rooms/_Autocomplete.scss index 3e1016f60d..3bc0ea25a4 100644 --- a/res/css/views/rooms/_Autocomplete.scss +++ b/res/css/views/rooms/_Autocomplete.scss @@ -71,7 +71,7 @@ .mx_Autocomplete_Completion.selected, .mx_Autocomplete_Completion:hover { - background: $menu-bg-color; + background: $selected-color; outline: none; } diff --git a/res/css/views/rooms/_E2EIcon.scss b/res/css/views/rooms/_E2EIcon.scss new file mode 100644 index 0000000000..84a16611de --- /dev/null +++ b/res/css/views/rooms/_E2EIcon.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_E2EIcon { + width: 25px; + height: 25px; + mask-repeat: no-repeat; + mask-position: center 0; + margin: 0 9px; +} + +.mx_E2EIcon_verified { + mask-image: url('$(res)/img/e2e/lock-verified.svg'); + background-color: $accent-color; +} + +.mx_E2EIcon_warning { + mask-image: url('$(res)/img/e2e/lock-warning.svg'); + background-color: $warning-color; +} diff --git a/res/css/views/rooms/_EntityTile.scss b/res/css/views/rooms/_EntityTile.scss index c4d4d944a6..44528a5624 100644 --- a/res/css/views/rooms/_EntityTile.scss +++ b/res/css/views/rooms/_EntityTile.scss @@ -22,10 +22,28 @@ limitations under the License. } .mx_EntityTile:hover { - background-image: url('../../img/member_chevron.png'); - background-position: center right 10px; - background-repeat: no-repeat; padding-right: 30px; + position: relative; // to keep the chevron aligned +} + +.mx_EntityTile:hover::before { + content: ""; + position: absolute; + top: calc(50% - 8px); // center + right: 10px; + mask: url('$(res)/img/member_chevron.png'); + mask-repeat: no-repeat; + width: 16px; + height: 16px; + background-color: $rightpanel-button-color; +} + +.mx_EntityTile .mx_PresenceLabel { + display: none; +} + +.mx_EntityTile:not(.mx_EntityTile_noHover):hover .mx_PresenceLabel { + display: block; } .mx_EntityTile_invite { @@ -67,7 +85,7 @@ limitations under the License. overflow: hidden; } -.mx_EntityTile_name_hover { +.mx_EntityTile:not(.mx_EntityTile_noHover):hover .mx_EntityTile_name { font-size: 13px; } @@ -81,31 +99,25 @@ 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, .mx_EntityTile_offline_beenactive .mx_EntityTile_avatar, -.mx_EntityTile_offline_beenactive .mx_EntityTile_name, -.mx_EntityTile_offline_beenactive .mx_EntityTile_name_hover +.mx_EntityTile_offline_beenactive .mx_EntityTile_name { - opacity: 0.66; + opacity: 0.5; } .mx_EntityTile_offline_neveractive .mx_EntityTile_avatar, -.mx_EntityTile_offline_neveractive .mx_EntityTile_name, -.mx_EntityTile_offline_neveractive .mx_EntityTile_name_hover +.mx_EntityTile_offline_neveractive .mx_EntityTile_name { opacity: 0.25; } .mx_EntityTile_unknown .mx_EntityTile_avatar, -.mx_EntityTile_unknown .mx_EntityTile_name, -.mx_EntityTile_unknown .mx_EntityTile_name_hover +.mx_EntityTile_unknown .mx_EntityTile_name { opacity: 0.25; } -*/ .mx_EntityTile_subtext { font-size: 11px; diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 6b22c4fe66..42eab24051 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -45,25 +45,29 @@ limitations under the License. .mx_EventTile .mx_SenderProfile { color: $primary-fg-color; font-size: 14px; - display: block; /* anti-zalgo, with overflow hidden */ + display: inline-block; /* anti-zalgo, with overflow hidden */ overflow-y: hidden; cursor: pointer; padding-left: 65px; /* left gutter */ padding-bottom: 0px; padding-top: 0px; margin: 0px; - line-height: 22px; + line-height: 17px; } .mx_EventTile .mx_SenderProfile .mx_Flair { opacity: 0.7; margin-left: 5px; -} + display: inline-block; + vertical-align: top; + height: 16px; + overflow: hidden; -.mx_EventTile .mx_SenderProfile .mx_Flair img { - vertical-align: -2px; - margin-right: 2px; - border-radius: 8px; + img { + vertical-align: -2px; + margin-right: 2px; + border-radius: 8px; + } } .mx_EventTile .mx_MessageTimestamp { @@ -277,13 +281,32 @@ limitations under the License. } /* End to end encryption stuff */ +.mx_EventTile:hover .mx_EventTile_e2eIcon { + opacity: 1; +} .mx_EventTile_e2eIcon { display: block; position: absolute; - top: 9px; + top: 8px; left: 46px; + width: 15px; + height: 15px; cursor: pointer; + mask-size: 14px; + mask-repeat: no-repeat; + mask-position: 0; + opacity: 0.2; +} + +.mx_EventTile_e2eIcon_undecryptable, .mx_EventTile_e2eIcon_unverified { + mask-image: url('$(res)/img/e2e/warning.svg'); + background-color: $warning-color; +} + +.mx_EventTile_e2eIcon_unencrypted { + mask-image: url('$(res)/img/e2e/warning.svg'); + background-color: $composer-e2e-icon-color; } .mx_EventTile_e2eIcon_hidden { @@ -291,8 +314,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; } @@ -389,7 +412,13 @@ limitations under the License. .mx_EventTile_content .markdown-body code { // deliberate constants as we're behind an invert filter background-color: #f8f8f8; - color: #333; +} + +.mx_EventTile_content .markdown-body { + pre, code { + // deliberate constants as we're behind an invert filter + color: #333; + } } .mx_EventTile_pre_container { @@ -453,6 +482,18 @@ limitations under the License. display: inline ! important; } +/* +// actually, removing the Italic TTF provides +// better results seemingly + +// 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 { @@ -506,7 +547,7 @@ limitations under the License. } .mx_EventTile_e2eIcon { - top: 7px; + top: 3px; } .mx_EventTile_editButton { 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..3be6a0f7b4 100644 --- a/res/css/views/rooms/_MemberDeviceInfo.scss +++ b/res/css/views/rooms/_MemberDeviceInfo.scss @@ -15,13 +15,35 @@ limitations under the License. */ .mx_MemberDeviceInfo { - padding: 10px 0px; + display: flex; + padding-bottom: 10px; + align-items: start; } -.mx_MemberDeviceInfo.mx_DeviceVerifyButtons { +.mx_MemberDeviceInfo_icon { + margin-top: 4px; + width: 12px; + height: 12px; + mask-repeat: no-repeat; +} +.mx_MemberDeviceInfo_icon_blacklisted { + mask-image: url('$(res)/img/e2e/blacklisted.svg'); + background-color: $warning-color; +} +.mx_MemberDeviceInfo_icon_verified { + mask-image: url('$(res)/img/e2e/verified.svg'); + background-color: $accent-color; +} +.mx_MemberDeviceInfo_icon_unverified { + mask-image: url('$(res)/img/e2e/warning.svg'); + background-color: $warning-color; +} + +.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 +61,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 4af181a464..c3b3ca2f7d 100644 --- a/res/css/views/rooms/_MemberInfo.scss +++ b/res/css/views/rooms/_MemberInfo.scss @@ -26,10 +26,19 @@ limitations under the License. display: flex; } +.mx_MemberInfo_name > .mx_E2EIcon { + margin-right: 0; +} + .mx_MemberInfo_cancel { height: 16px; - padding: 10px 15px; + width: 16px; + padding: 10px 0 10px 10px; cursor: pointer; + mask-image: url('$(res)/img/minimise.svg'); + mask-repeat: no-repeat; + mask-position: 16px center; + background-color: $rightpanel-button-color; } .mx_MemberInfo_name h2 { @@ -39,11 +48,11 @@ limitations under the License. .mx_MemberInfo h2 { font-size: 18px; font-weight: 600; - margin: 16px 0; + margin: 16px 0 16px 15px; } .mx_MemberInfo_container { - padding: 8px; + margin: 0 16px 16px 16px; } .mx_MemberInfo .mx_RoomTile_nameContainer { @@ -60,6 +69,7 @@ limitations under the License. .mx_MemberInfo_avatar { background: $tagpanel-bg-color; + margin-bottom: 16px; } .mx_MemberInfo_avatar > img { @@ -83,15 +93,14 @@ 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; } @@ -101,14 +110,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 { diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss index 567727fb64..cac97cb60d 100644 --- a/res/css/views/rooms/_MemberList.scss +++ b/res/css/views/rooms/_MemberList.scss @@ -20,6 +20,7 @@ limitations under the License. flex: 1; display: flex; flex-direction: column; + min-height: 0; .mx_Spinner { flex: 1 0 auto; @@ -35,6 +36,10 @@ limitations under the License. margin-top: 8px; margin-bottom: 4px; } + + .mx_AutoHideScrollbar { + flex: 1 1 0; + } } .mx_MemberList_chevron { @@ -53,10 +58,6 @@ limitations under the License. .mx_MemberList_query, .mx_GroupMemberList_query, .mx_GroupRoomList_query { - flex: 0 0 auto; -} - -.mx_MemberList .gm-scrollbar-container { flex: 1 1 0; } @@ -76,6 +77,7 @@ limitations under the License. padding: 8px; margin: 9px; display: flex; + justify-content: center; color: $button-fg-color; font-weight: 600; @@ -86,8 +88,7 @@ limitations under the License. } .mx_MemberList_invite span { - margin: 0 auto; - background-image: url('../../img/feather-icons/user-add.svg'); + background-image: url('$(res)/img/feather-customised/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 39640575ba..708c29bb3e 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -20,6 +20,11 @@ limitations under the License. margin: auto; border-top: 1px solid $primary-hairline-color; position: relative; + padding-left: 84px; +} + +.mx_MessageComposer_wrapper.mx_MessageComposer_hasE2EIcon { + padding-left: 109px; } .mx_MessageComposer_replaced_wrapper { @@ -58,24 +63,22 @@ limitations under the License. } .mx_MessageComposer .mx_MessageComposer_avatar { - padding: 0 28px; + position: absolute; + left: 27px; } .mx_MessageComposer .mx_MessageComposer_avatar .mx_BaseAvatar { display: block; } -.mx_MessageComposer .mx_AccessibleButton { - padding: 0 12px 0 0; -} - .mx_MessageComposer_composecontrols { width: 100%; } -.mx_MessageComposer_e2eIcon { +.mx_MessageComposer_e2eIcon.mx_E2EIcon { position: absolute; left: 60px; + background-color: $composer-e2e-icon-color; } .mx_MessageComposer_noperm_error { @@ -111,7 +114,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; } @@ -176,27 +180,36 @@ limitations under the License. color: $accent-color; } -.mx_MessageComposer_upload, -.mx_MessageComposer_hangup, -.mx_MessageComposer_voicecall, -.mx_MessageComposer_videocall, -.mx_MessageComposer_apps, -.mx_MessageComposer_stickers { - /*display: table-cell;*/ - /*vertical-align: middle;*/ - /*padding-left: 10px;*/ - padding-right: 5px; +.mx_MessageComposer_button { + margin-right: 12px; cursor: pointer; padding-top: 4px; + height: 20px; + width: 20px; + background-color: $composer-button-color; + mask-repeat: no-repeat; + mask-size: contain; + mask-position: center; } -.mx_MessageComposer_upload object, -.mx_MessageComposer_hangup object, -.mx_MessageComposer_voicecall object, -.mx_MessageComposer_videocall object, -.mx_MessageComposer_apps object, -.mx_MessageComposer_stickers object { - pointer-events: none; +.mx_MessageComposer_upload { + mask-image: url('$(res)/img/feather-customised/paperclip.svg'); +} + +.mx_MessageComposer_hangup { + mask-image: url('$(res)/img/hangup.svg'); +} + +.mx_MessageComposer_voicecall { + mask-image: url('$(res)/img/feather-customised/phone.svg'); +} + +.mx_MessageComposer_videocall { + mask-image: url('$(res)/img/feather-customised/video.svg'); +} + +.mx_MessageComposer_stickers { + mask-image: url('$(res)/img/feather-customised/face.svg'); } .mx_MessageComposer_formatting { @@ -242,14 +255,29 @@ limitations under the License. } .mx_MessageComposer_formatbar_markdown { + height: 17px; + width: 30px; margin-right: 64px; } .mx_MessageComposer_input_markdownIndicator { - cursor: pointer; height: 10px; + width: 12px; padding: 4px 4px 4px 0; - opacity: 0.8; +} + +.mx_MessageComposer_formatbar_markdown, +.mx_MessageComposer_input_markdownIndicator { + cursor: pointer; + mask-image: url('$(res)/img/markdown.svg'); + mask-size: contain; + mask-position: center; + mask-repeat: no-repeat; + background-color: $composer-button-color; + + &.mx_MessageComposer_markdownDisabled { + opacity: 0.2; + } } .mx_MatrixChat_useCompactLayout { diff --git a/res/css/views/rooms/_RoomBreadcrumbs.scss b/res/css/views/rooms/_RoomBreadcrumbs.scss new file mode 100644 index 0000000000..67227c7115 --- /dev/null +++ b/res/css/views/rooms/_RoomBreadcrumbs.scss @@ -0,0 +1,82 @@ +/* +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_RoomBreadcrumbs { + position: relative; + height: 42px; + margin: 8px; + margin-bottom: 0; + overflow-x: visible; + display: flex; + flex-direction: row; + + .mx_AutoHideScrollbar_offset { + display: flex; + flex-direction: row; + height: 100%; + } + + .mx_RoomBreadcrumbs_crumb { + margin-left: 4px; + height: 32px; + display: inline-block; + transition: transform 0.3s, width 0.3s; + } + + .mx_RoomBreadcrumbs_animate { + margin-left: 0; + width: 32px; + transform: scale(1); + } + + .mx_RoomBreadcrumbs_preAnimate { + width: 0; + transform: scale(0); + } + + .mx_RoomBreadcrumbs_left { + opacity: 0.5; + } + + // Note: we have to manually control the gradient and stuff, but the IndicatorScrollbar + // will deal with left/right positioning for us. Normally we'd use position:sticky on + // a few key elements, however that doesn't work in horizontal scrolling scenarios. + + .mx_IndicatorScrollbar_leftOverflowIndicator, + .mx_IndicatorScrollbar_rightOverflowIndicator { + display: none; + } + + &.mx_IndicatorScrollbar_leftOverflow .mx_IndicatorScrollbar_leftOverflowIndicator, + &.mx_IndicatorScrollbar_rightOverflow .mx_IndicatorScrollbar_rightOverflowIndicator { + position: absolute; + top: 0; + bottom: 0; + width: 15px; + display: block; + pointer-events: none; + z-index: 100; + } + + .mx_IndicatorScrollbar_leftOverflowIndicator { + background: linear-gradient(to left, $panel-gradient); + } + + .mx_IndicatorScrollbar_rightOverflowIndicator { + background: linear-gradient(to right, $panel-gradient); + } +} + diff --git a/res/css/views/rooms/_RoomHeader.scss b/res/css/views/rooms/_RoomHeader.scss index 0697ccf40f..e7589f0e90 100644 --- a/res/css/views/rooms/_RoomHeader.scss +++ b/res/css/views/rooms/_RoomHeader.scss @@ -58,7 +58,6 @@ limitations under the License. .mx_RoomHeader_buttons { display: flex; - align-items: center; background-color: $primary-bg-color; padding-right: 5px; } @@ -98,6 +97,7 @@ limitations under the License. font-size: 18px; margin: 0 7px; border-bottom: 1px solid transparent; + display: flex; } .mx_RoomHeader_nametext { @@ -111,15 +111,10 @@ limitations under the License. } .mx_RoomHeader_searchStatus { - display: inline-block; font-weight: normal; opacity: 0.6; } -.mx_RoomHeader_settingsButton object { - pointer-events: none; -} - .mx_RoomHeader_name, .mx_RoomHeader_avatar, .mx_RoomHeader_avatarPicker, @@ -160,6 +155,7 @@ limitations under the License. font-weight: 400; font-size: 13px; margin: 0 7px; + margin-top: 4px; // to align baseline of topic with room name overflow: hidden; text-overflow: ellipsis; border-bottom: 1px solid transparent; @@ -199,10 +195,32 @@ limitations under the License. .mx_RoomHeader_button { margin-left: 10px; cursor: pointer; + height: 20px; + width: 20px; + background-color: $roomheader-button-color; + mask-repeat: no-repeat; + mask-size: contain; } -.mx_RoomHeader_button object { - pointer-events: none; +.mx_RoomHeader_settingsButton { + mask-image: url('$(res)/img/feather-customised/settings.svg'); +} + +.mx_RoomHeader_forgetButton { + mask-image: url('$(res)/img/leave.svg'); + width: 26px; +} + +.mx_RoomHeader_searchButton { + mask-image: url('$(res)/img/feather-customised/search.svg'); +} + +.mx_RoomHeader_shareButton { + mask-image: url('$(res)/img/feather-customised/share.svg'); +} + +.mx_RoomHeader_manageIntegsButton { + mask-image: url('$(res)/img/feather-customised/grid.svg'); } .mx_RoomHeader_showPanel { @@ -219,6 +237,7 @@ limitations under the License. .mx_RoomHeader_pinnedButton { position: relative; + mask-image: url('$(res)/img/icons-pin.svg'); } .mx_RoomHeader_pinsIndicator { diff --git a/res/css/views/rooms/_RoomList.scss b/res/css/views/rooms/_RoomList.scss index 8f78e3bb7a..886f10dc4c 100644 --- a/res/css/views/rooms/_RoomList.scss +++ b/res/css/views/rooms/_RoomList.scss @@ -17,11 +17,14 @@ limitations under the License. .mx_RoomList { /* take up remaining space below TopLeftMenu */ - flex: 1 1 auto; - /* use flexbox to layout sublists */ - display: flex; - flex-direction: column; + flex: 1; min-height: 0; + overflow-y: hidden; +} + +.mx_RoomList .mx_ResizeHandle { + // needed so the z-index takes effect + position: relative; } .mx_SearchBox { diff --git a/res/css/views/rooms/_RoomRecoveryReminder.scss b/res/css/views/rooms/_RoomRecoveryReminder.scss index e4e2d19b42..68e2bf861e 100644 --- a/res/css/views/rooms/_RoomRecoveryReminder.scss +++ b/res/css/views/rooms/_RoomRecoveryReminder.scss @@ -38,7 +38,6 @@ limitations under the License. margin: 0 10px; } -.mx_RoomRecoveryReminder_button.mx_RoomRecoveryReminder_secondary { - @mixin mx_DialogButton_secondary; - background-color: transparent; +.mx_RoomRecoveryReminder_secondary { + font-size: 90%; } diff --git a/res/css/views/rooms/_RoomSettings.scss b/res/css/views/rooms/_RoomSettings.scss deleted file mode 100644 index 4454cd479c..0000000000 --- a/res/css/views/rooms/_RoomSettings.scss +++ /dev/null @@ -1,259 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 Vector Creations Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -.mx_RoomSettings { - margin: 40px; -} - -.mx_RoomSettings_upgradeButton, -.mx_RoomSettings_leaveButton, -.mx_RoomSettings_unbanButton { - @mixin mx_DialogButton; - position: relative; - margin-right: 8px; -} - -.mx_RoomSettings_devtoolsButton { - @mixin mx_DialogButton; - position: relative; - padding: 4px 1.5em; - margin-top: 8px; -} - -.mx_RoomSettings_upgradeButton, -.mx_RoomSettings_leaveButton:hover, -.mx_RoomSettings_unbanButton:hover { - @mixin mx_DialogButton_hover; -} - -.mx_RoomSettings_upgradeButton.danger { - @mixin mx_DialogButton_danger; -} - -.mx_RoomSettings_integrationsButton_error { - position: relative; - cursor: not-allowed; -} -.mx_RoomSettings_integrationsButton_error img { - position: absolute; - right: -5px; - top: -5px; -} -.mx_RoomSettings_leaveButton, -.mx_RoomSettings_integrationsButton_error { - float: right; -} -.mx_RoomSettings_integrationsButton_error .mx_RoomSettings_integrationsButton_errorPopup { - display: none; -} -.mx_RoomSettings_integrationsButton_error:hover .mx_RoomSettings_integrationsButton_errorPopup { - display: inline; -} -.mx_RoomSettings_integrationsButton_errorPopup { - position: absolute; - top: 110%; - left: -125%; - width: 348%; - padding: 2%; - font-size: 10pt; - line-height: 1.5em; - border-radius: 5px; - background-color: $accent-color; - color: $accent-fg-color; - text-align: center; -} -.mx_RoomSettings_unbanButton { - display: inline; -} - -.mx_RoomSettings_e2eIcon { - padding-left: 4px; - padding-right: 7px; -} - -.mx_RoomSettings_leaveButton { - margin-right: 32px; -} - -.mx_RoomSettings_powerLevels { - display: table; -} - -.mx_RoomSettings_powerLevel { - display: table-row; -} - -.mx_RoomSettings_powerLevelKey, -.mx_RoomSettings_powerLevel .mx_PowerSelector { - display: table-cell; - padding-bottom: 5px; -} - -.mx_RoomSettings_powerLevelKey { - text-align: right; - padding-right: 0.3em; -} - -.mx_RoomSettings h3 { - text-transform: uppercase; - color: $h3-color; - font-weight: 600; - font-size: 13px; - margin-top: 36px; - margin-bottom: 10px; -} - -.mx_RoomSettings .mx_RoomSettings_toggles label { - margin-bottom: 8px; - display: block; -} - -.mx_RoomSettings .mx_RoomSettings_toggles input[type="checkbox"], -.mx_RoomSettings .mx_RoomSettings_toggles input[type="radio"] { - margin-right: 7px; -} - -.mx_RoomSettings .mx_RoomSettings_tags input[type="checkbox"] { - margin-left: 1em; - margin-right: 7px; -} - -.mx_RoomSettings .mx_RoomSettings_tags { - margin-bottom: 8px; -} - -.mx_RoomSettings .mx_RoomSettings_roomColor { - display: inline-block; - position: relative; - width: 37px; - height: 37px; - border: 1px solid #979797; - margin-right: 13px; - cursor: pointer; -} - -.mx_RoomSettings .mx_RoomSettings_roomColor_selected { - position: absolute; - left: 10px; - top: 4px; - cursor: default ! important; -} - -.mx_RoomSettings .mx_RoomSettings_roomColorPrimary { - height: 10px; - position: absolute; - bottom: 0px; - width: 100%; -} - -.mx_RoomSettings .mx_RoomSettings_aliasLabel { - margin-bottom: 8px; -} - -.mx_RoomSettings .mx_RoomSettings_aliasesTable { - margin-top: 12px; - margin-bottom: 0px; - margin-left: 56px; - display: table; -} - -.mx_RoomSettings .mx_RoomSettings_aliasesTableRow { - display: table-row; - margin-bottom: 16px; -} - -.mx_RoomSettings .mx_RoomSettings_alias { - max-width: 400px; - margin-bottom: 16px; - /* - commented out so margin applies - display: table-cell; */ -} - -.mx_RoomSettings .mx_RoomSettings_addAlias, -.mx_RoomSettings .mx_RoomSettings_deleteAlias { - display: table-cell; - padding-left: 0.5em; - position: relative; - cursor: pointer; -} - -.mx_RoomSettings .mx_RoomSettings_addAlias img, -.mx_RoomSettings .mx_RoomSettings_deleteAlias img { - visibility: hidden; -} - -.mx_RoomSettings .mx_RoomSettings_aliasesTableRow:hover .mx_RoomSettings_addAlias img, -.mx_RoomSettings .mx_RoomSettings_aliasesTableRow:hover .mx_RoomSettings_deleteAlias img { - visibility: visible; -} - -.mx_RoomSettings_warning { - color: $warning-color; - font-weight: bold; - margin-top: 8px; - margin-bottom: 8px; -} - -.mx_RoomSettings_editable { - border: 0px; - border-bottom: 1px solid $strong-input-border-color; - padding: 0px; - min-width: 240px; -} - -.mx_RoomSettings_editable:focus { - border-bottom: 1px solid $accent-color; - outline: none; - box-shadow: none; -} - -.mx_RoomSettings_deleteAlias, -.mx_RoomSettings_addAlias { - display: table-cell; - visibility: visible; -} - -.mx_RoomSettings_deleteAlias:hover, -.mx_RoomSettings_addAlias:hover { - visibility: visible; -} - -.mx_RoomSettings_aliasPlaceholder { - color: $settings-grey-fg-color; -} - -.mx_RoomSettings_buttons { - text-align: right; - margin-bottom: 16px; -} - -.mx_RoomSettings_button { - display: inline; - border: 0px; - height: 36px; - border-radius: 36px; - font-weight: 400; - font-size: 15px; - color: $accent-fg-color; - background-color: $accent-color; - width: auto; - margin: auto; - padding: 6px; - padding-left: 1em; - padding-right: 1em; -} diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index 56ca715b51..97b2c48236 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -29,7 +29,7 @@ limitations under the License. display: none; flex: 0 0 16px; height: 16px; - background-image: url('../../img/icon_context.svg'); + background-image: url('$(res)/img/icon_context.svg'); background-repeat: no-repeat; background-position: center; } @@ -102,7 +102,6 @@ limitations under the License. .mx_RoomTile_name { font-size: 14px; - font-weight: 600; padding: 0 6px; color: $roomtile-name-color; white-space: nowrap; @@ -154,9 +153,8 @@ limitations under the License. } .mx_RoomTile_unread, .mx_RoomTile_highlight { - font-weight: 800; - .mx_RoomTile_name { + font-weight: 600; color: $roomtile-selected-color; } } @@ -176,7 +174,7 @@ limitations under the License. } .mx_RoomTile:focus { - filter: none ! important; + filter: none !important; background-color: $roomtile-focused-bg-color; } @@ -192,3 +190,7 @@ limitations under the License. .mx_RoomTile.mx_RoomTile_transparent:focus { background-color: $roomtile-transparent-focused-color; } + +.mx_GroupInviteTile .mx_RoomTile_name { + flex: 1; +} diff --git a/res/css/views/rooms/_RoomUpgradeWarningBar.scss b/res/css/views/rooms/_RoomUpgradeWarningBar.scss index 82785b82d2..fe81d3801a 100644 --- a/res/css/views/rooms/_RoomUpgradeWarningBar.scss +++ b/res/css/views/rooms/_RoomUpgradeWarningBar.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_RoomUpgradeWarningBar { text-align: center; - height: 176px; + height: 235px; background-color: $event-selected-color; align-items: center; flex-direction: column; diff --git a/res/css/views/rooms/_SearchBar.scss b/res/css/views/rooms/_SearchBar.scss index 079ea16c68..894473a5fe 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-customised/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/_Stickers.scss b/res/css/views/rooms/_Stickers.scss index 669ca13545..d33ecc0bb6 100644 --- a/res/css/views/rooms/_Stickers.scss +++ b/res/css/views/rooms/_Stickers.scss @@ -7,8 +7,12 @@ height: 300px; } -.mx_Stickers_content .mx_AppTileFullWidth { - border: none; +#mx_persistedElement_stickerPicker .mx_AppTileFullWidth { + height: unset; + box-sizing: border-box; + border-left: none; + border-right: none; + border-bottom: none; } .mx_Stickers_contentPlaceholder { diff --git a/res/css/views/rooms/_TopUnreadMessagesBar.scss b/res/css/views/rooms/_TopUnreadMessagesBar.scss index 67579552c1..a4b7a6aa51 100644 --- a/res/css/views/rooms/_TopUnreadMessagesBar.scss +++ b/res/css/views/rooms/_TopUnreadMessagesBar.scss @@ -54,7 +54,7 @@ limitations under the License. position: absolute; width: 38px; height: 38px; - mask: url('../../img/icon-jump-to-first-unread.svg'); + 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 index 217a10be8d..ef20c24c84 100644 --- a/res/css/views/rooms/_WhoIsTypingTile.scss +++ b/res/css/views/rooms/_WhoIsTypingTile.scss @@ -40,6 +40,7 @@ limitations under the License. } .mx_WhoIsTypingTile_remainingAvatarPlaceholder { + position: relative; display: inline-block; color: #acacac; background-color: #ddd; @@ -61,7 +62,7 @@ limitations under the License. } .mx_WhoIsTypingTile_label > span { - background-image: url('../../img/typing-indicator-2x.gif'); + background-image: url('$(res)/img/typing-indicator-2x.gif'); background-size: 25px; background-position: left bottom; background-repeat: no-repeat; 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..d6c0b5dbeb 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 { @@ -61,10 +59,15 @@ limitations under the License. color: $accent-color; } -.mx_UserSettings_devicesTable td { +.mx_UserNotifSettings_devicesTable td { padding-left: 20px; padding-right: 20px; } -.mx_UserSettings_devicesTable_nodevices { - font-style: italic; + +.mx_UserNotifSettings_notifTable { + display: table; +} + +.mx_UserNotifSettings_notifTable .mx_Spinner { + position: absolute; } 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..b2e449ac34 --- /dev/null +++ b/res/css/views/settings/_ProfileSettings.scss @@ -0,0 +1,133 @@ +/* +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_hostingSignup { + margin-left: 20px; + + img { + margin-left: 5px; + } +} + +.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-customised/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/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss new file mode 100644 index 0000000000..88735f99b2 --- /dev/null +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -0,0 +1,74 @@ +/* +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_warningText { + color: $warning-color; +} + +.mx_SettingsTab_heading { + font-size: 20px; + font-weight: 600; + color: $primary-fg-color; +} + +.mx_SettingsTab_subheading { + font-size: 16px; + 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: 14px; + 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; + margin-bottom: 10px; +} + +.mx_SettingsTab_section .mx_SettingsFlag .mx_SettingsFlag_label { + vertical-align: middle; + display: inline-block; + font-size: 14px; + color: $primary-fg-color; + max-width: calc(100% - 48px); // Force word wrap instead of colliding with the switch + box-sizing: border-box; + padding-right: 10px; +} + +.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/room/_GeneralRoomSettingsTab.scss b/res/css/views/settings/tabs/room/_GeneralRoomSettingsTab.scss new file mode 100644 index 0000000000..91d7ed2c7d --- /dev/null +++ b/res/css/views/settings/tabs/room/_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/room/_RolesRoomSettingsTab.scss b/res/css/views/settings/tabs/room/_RolesRoomSettingsTab.scss new file mode 100644 index 0000000000..8bfc792dc3 --- /dev/null +++ b/res/css/views/settings/tabs/room/_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/room/_SecurityRoomSettingsTab.scss b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss new file mode 100644 index 0000000000..dfd046e672 --- /dev/null +++ b/res/css/views/settings/tabs/room/_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/user/_GeneralUserSettingsTab.scss b/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss new file mode 100644 index 0000000000..bec013674a --- /dev/null +++ b/res/css/views/settings/tabs/user/_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/user/_HelpUserSettingsTab.scss b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss new file mode 100644 index 0000000000..fa0d0edeb7 --- /dev/null +++ b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.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_HelpUserSettingsTab_debugButton { + margin-bottom: 5px; + margin-top: 5px; +} + +.mx_HelpUserSettingsTab span.mx_AccessibleButton { + word-break: break-word; +} \ No newline at end of file diff --git a/res/css/views/settings/tabs/user/_NotificationUserSettingsTab.scss b/res/css/views/settings/tabs/user/_NotificationUserSettingsTab.scss new file mode 100644 index 0000000000..3cebd2958e --- /dev/null +++ b/res/css/views/settings/tabs/user/_NotificationUserSettingsTab.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_NotificationUserSettingsTab .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/user/_PreferencesUserSettingsTab.scss b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss new file mode 100644 index 0000000000..f447221b7a --- /dev/null +++ b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.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_PreferencesUserSettingsTab .mx_Field { + margin-right: 100px; // Align with the rest of the controls +} + +.mx_PreferencesUserSettingsTab .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/user/_SecurityUserSettingsTab.scss b/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.scss new file mode 100644 index 0000000000..1c0a4b5864 --- /dev/null +++ b/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.scss @@ -0,0 +1,57 @@ +/* +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_SecurityUserSettingsTab .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_SecurityUserSettingsTab_deviceInfo { + display: table; + padding-left: 0; +} + +.mx_SecurityUserSettingsTab_deviceInfo > li { + display: table-row; +} + +.mx_SecurityUserSettingsTab_deviceInfo > li > label, +.mx_SecurityUserSettingsTab_deviceInfo > li > span { + display: table-cell; + padding-right: 1em; +} + +.mx_SecurityUserSettingsTab_importExportButtons .mx_AccessibleButton { + margin-right: 10px; +} + +.mx_SecurityUserSettingsTab_bulkOptions .mx_AccessibleButton { + margin-right: 10px; +} + +.mx_SecurityUserSettingsTab_importExportButtons { + margin-bottom: 15px; +} + +.mx_SecurityUserSettingsTab_ignoredUser { + margin-bottom: 5px; +} + +.mx_SecurityUserSettingsTab_ignoredUser .mx_AccessibleButton { + margin-right: 10px; +} \ No newline at end of file diff --git a/res/css/views/settings/tabs/user/_VoiceUserSettingsTab.scss b/res/css/views/settings/tabs/user/_VoiceUserSettingsTab.scss new file mode 100644 index 0000000000..f5dba9831e --- /dev/null +++ b/res/css/views/settings/tabs/user/_VoiceUserSettingsTab.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_VoiceUserSettingsTab .mx_Field select { + width: 100%; + max-width: 100%; +} + +.mx_VoiceUserSettingsTab .mx_Field { + margin-right: 100px; // align with the rest of the fields +} + +.mx_VoiceUserSettingsTab_missingMediaPermissions { + margin-bottom: 15px; +} diff --git a/res/css/views/verification/_VerificationShowSas.scss b/res/css/views/verification/_VerificationShowSas.scss new file mode 100644 index 0000000000..a0da7e2539 --- /dev/null +++ b/res/css/views/verification/_VerificationShowSas.scss @@ -0,0 +1,48 @@ +/* +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_VerificationShowSas_decimalSas { + text-align: center; + font-weight: bold; + padding-left: 3px; + padding-right: 3px; +} + +.mx_VerificationShowSas_decimalSas span { + margin-left: 5px; + margin-right: 5px; +} + +.mx_VerificationShowSas_emojiSas { + text-align: center; +} + +.mx_VerificationShowSas_emojiSas_block { + display: inline-block; + margin-left: 15px; + margin-right: 15px; + text-align: center; + margin-bottom: 20px; +} + +.mx_VerificationShowSas_emojiSas_emoji { + font-size: 48px; +} + +.mx_VerificationShowSas_emojiSas_label { + text-align: center; + font-weight: bold; +} diff --git a/res/fonts/Nunito/Nunito-Bold.ttf b/res/fonts/Nunito/Nunito-Bold.ttf new file mode 100644 index 0000000000..c70de76bbd Binary files /dev/null and b/res/fonts/Nunito/Nunito-Bold.ttf differ diff --git a/res/fonts/Nunito/Nunito-Regular.ttf b/res/fonts/Nunito/Nunito-Regular.ttf new file mode 100644 index 0000000000..064e805431 Binary files /dev/null and b/res/fonts/Nunito/Nunito-Regular.ttf differ diff --git a/res/fonts/Nunito/Nunito-SemiBold.ttf b/res/fonts/Nunito/Nunito-SemiBold.ttf new file mode 100644 index 0000000000..a84b3b35a6 Binary files /dev/null and b/res/fonts/Nunito/Nunito-SemiBold.ttf differ diff --git a/res/img/03b381.png b/res/img/03b381.png new file mode 100644 index 0000000000..cf28fc7e59 Binary files /dev/null and b/res/img/03b381.png differ diff --git a/res/img/368bd6.png b/res/img/368bd6.png new file mode 100644 index 0000000000..a2700bd0ae Binary files /dev/null and b/res/img/368bd6.png differ diff --git a/res/img/50e2c2.png b/res/img/50e2c2.png deleted file mode 100644 index ee0f855895..0000000000 Binary files a/res/img/50e2c2.png and /dev/null differ diff --git a/res/img/76cfa6.png b/res/img/76cfa6.png deleted file mode 100644 index de1ea60d54..0000000000 Binary files a/res/img/76cfa6.png and /dev/null differ diff --git a/res/img/80cef4.png b/res/img/80cef4.png deleted file mode 100644 index 637d03f63c..0000000000 Binary files a/res/img/80cef4.png and /dev/null differ diff --git a/res/img/ac3ba8.png b/res/img/ac3ba8.png new file mode 100644 index 0000000000..031471d85a Binary files /dev/null and b/res/img/ac3ba8.png differ diff --git a/res/img/avatar-error.svg b/res/img/avatar-error.svg deleted file mode 100644 index c5e168944c..0000000000 --- a/res/img/avatar-error.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - 5EF602F6-A36C-41EE-BAEC-50801DFD5492 - Created with sketchtool. - - - - - - - - - - diff --git a/res/img/button-md-false.png b/res/img/button-md-false.png deleted file mode 100644 index 6debbccc93..0000000000 Binary files a/res/img/button-md-false.png and /dev/null differ diff --git a/res/img/button-md-false.svg b/res/img/button-md-false.svg deleted file mode 100644 index 6414933d96..0000000000 --- a/res/img/button-md-false.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - D335F9E8-C813-47D7-B1BE-C8DEF2C8214F - Created with sketchtool. - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-md-false@2x.png b/res/img/button-md-false@2x.png deleted file mode 100644 index 497f5385d1..0000000000 Binary files a/res/img/button-md-false@2x.png and /dev/null differ diff --git a/res/img/button-md-false@3x.png b/res/img/button-md-false@3x.png deleted file mode 100644 index 1184e6b351..0000000000 Binary files a/res/img/button-md-false@3x.png and /dev/null differ diff --git a/res/img/button-md-true.png b/res/img/button-md-true.png deleted file mode 100644 index 2e39c55e1e..0000000000 Binary files a/res/img/button-md-true.png and /dev/null differ diff --git a/res/img/button-md-true.svg b/res/img/button-md-true.svg deleted file mode 100644 index 2acc4f675c..0000000000 --- a/res/img/button-md-true.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - 2A63B135-4281-4FBB-A88C-012AE22E9594 - Created with sketchtool. - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-md-true@2x.png b/res/img/button-md-true@2x.png deleted file mode 100644 index ad9067f385..0000000000 Binary files a/res/img/button-md-true@2x.png and /dev/null differ diff --git a/res/img/button-md-true@3x.png b/res/img/button-md-true@3x.png deleted file mode 100644 index d615867dc4..0000000000 Binary files a/res/img/button-md-true@3x.png and /dev/null differ diff --git a/res/img/button-new-window.svg b/res/img/button-new-window.svg deleted file mode 100644 index dd1225e798..0000000000 --- a/res/img/button-new-window.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - diff --git a/res/img/button-refresh.svg b/res/img/button-refresh.svg deleted file mode 100644 index b4990a2147..0000000000 --- a/res/img/button-refresh.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - diff --git a/res/img/call.svg b/res/img/call.svg deleted file mode 100644 index f528f9a24e..0000000000 --- a/res/img/call.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - icons_video - Created with bin/sketchtool. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/camera_green.svg b/res/img/camera_green.svg deleted file mode 100644 index 5aae5502cd..0000000000 --- a/res/img/camera_green.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - diff --git a/res/img/directory-big.svg b/res/img/directory-big.svg deleted file mode 100644 index 5631a2ae3e..0000000000 --- a/res/img/directory-big.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - icons_directory - Created with sketchtool. - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/e2e-blocked.svg b/res/img/e2e-blocked.svg deleted file mode 100644 index 0ab2c6efbe..0000000000 --- a/res/img/e2e-blocked.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - 2805649B-D39D-43EA-A357-659EF9B97BA4 - Created with sketchtool. - - - - - - - \ No newline at end of file diff --git a/res/img/e2e-encrypting.svg b/res/img/e2e-encrypting.svg deleted file mode 100644 index 469611cc8d..0000000000 --- a/res/img/e2e-encrypting.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - -48BF5D32-306C-4B20-88EB-24B1F743CAC9 -Created with sketchtool. - - - - - - - diff --git a/res/img/e2e-not_sent.svg b/res/img/e2e-not_sent.svg deleted file mode 100644 index fca79ae547..0000000000 --- a/res/img/e2e-not_sent.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - -48BF5D32-306C-4B20-88EB-24B1F743CAC9 -Created with sketchtool. - - - - - - - diff --git a/res/img/e2e-unencrypted.svg b/res/img/e2e-unencrypted.svg deleted file mode 100644 index 1467223638..0000000000 --- a/res/img/e2e-unencrypted.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - 16F5F38E-A6A3-472A-BC13-13F0F12876CF - Created with sketchtool. - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/e2e-verified.svg b/res/img/e2e-verified.svg deleted file mode 100644 index b65f50b2b6..0000000000 --- a/res/img/e2e-verified.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - 48BF5D32-306C-4B20-88EB-24B1F743CAC9 - Created with sketchtool. - - - - - - - \ No newline at end of file diff --git a/res/img/e2e-warning.svg b/res/img/e2e-warning.svg deleted file mode 100644 index 8a55f199ba..0000000000 --- a/res/img/e2e-warning.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - CCDDE6F6-B552-48FD-AD54-6939841CA2DD - Created with sketchtool. - - - - - - - \ No newline at end of file diff --git a/res/img/e2e/blacklisted.svg b/res/img/e2e/blacklisted.svg new file mode 100644 index 0000000000..ac99d23f05 --- /dev/null +++ b/res/img/e2e/blacklisted.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/e2e/lock-verified.svg b/res/img/e2e/lock-verified.svg new file mode 100644 index 0000000000..819dfacc49 --- /dev/null +++ b/res/img/e2e/lock-verified.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/e2e/lock-warning-filled.svg b/res/img/e2e/lock-warning-filled.svg new file mode 100644 index 0000000000..a984ed85a0 --- /dev/null +++ b/res/img/e2e/lock-warning-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/e2e/lock-warning.svg b/res/img/e2e/lock-warning.svg index a984ed85a0..de2bded7f8 100644 --- a/res/img/e2e/lock-warning.svg +++ b/res/img/e2e/lock-warning.svg @@ -1 +1,9 @@ - \ No newline at end of file + + + + + + + + + diff --git a/res/img/e2e/verified.svg b/res/img/e2e/verified.svg new file mode 100644 index 0000000000..459a552a40 --- /dev/null +++ b/res/img/e2e/verified.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/e2e/warning.svg b/res/img/e2e/warning.svg new file mode 100644 index 0000000000..3d5fba550c --- /dev/null +++ b/res/img/e2e/warning.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/edit.svg b/res/img/edit.svg deleted file mode 100644 index 9ba0060774..0000000000 --- a/res/img/edit.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/res/img/edit_green.svg b/res/img/edit_green.svg deleted file mode 100644 index f7f4c7adcb..0000000000 --- a/res/img/edit_green.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/res/img/eol.svg b/res/img/eol.svg deleted file mode 100644 index 02d1946cf4..0000000000 --- a/res/img/eol.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - icon_eol - Created with sketchtool. - - - - - - - - - - - diff --git a/res/img/external-link.svg b/res/img/external-link.svg new file mode 100644 index 0000000000..459e790fe3 --- /dev/null +++ b/res/img/external-link.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/f4c371.png b/res/img/f4c371.png deleted file mode 100644 index ad3b8f1616..0000000000 Binary files a/res/img/f4c371.png and /dev/null differ diff --git a/res/img/cancel_green.svg b/res/img/feather-customised/cancel.svg similarity index 83% rename from res/img/cancel_green.svg rename to res/img/feather-customised/cancel.svg index 2e3d759be2..6b734e4053 100644 --- a/res/img/cancel_green.svg +++ b/res/img/feather-customised/cancel.svg @@ -4,7 +4,7 @@ Slice 1 Created with Sketch. - - + + \ No newline at end of file diff --git a/res/img/feather-customised/dropdown-arrow.svg b/res/img/feather-customised/dropdown-arrow.svg new file mode 100644 index 0000000000..a1d46fa61a --- /dev/null +++ b/res/img/feather-customised/dropdown-arrow.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-icons/face.svg b/res/img/feather-customised/face.svg similarity index 67% rename from res/img/feather-icons/face.svg rename to res/img/feather-customised/face.svg index 0a359b2dea..a8ca856b67 100644 --- a/res/img/feather-icons/face.svg +++ b/res/img/feather-customised/face.svg @@ -3,9 +3,9 @@ - - - + + + diff --git a/res/img/feather-icons/files.svg b/res/img/feather-customised/files.svg similarity index 94% rename from res/img/feather-icons/files.svg rename to res/img/feather-customised/files.svg index c66d9ad121..e3bfe30ab0 100644 --- a/res/img/feather-icons/files.svg +++ b/res/img/feather-customised/files.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-customised/flag.svg b/res/img/feather-customised/flag.svg new file mode 100644 index 0000000000..983c02762b --- /dev/null +++ b/res/img/feather-customised/flag.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/feather-customised/flair.svg b/res/img/feather-customised/flair.svg new file mode 100644 index 0000000000..ce3a5ed6ad --- /dev/null +++ b/res/img/feather-customised/flair.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-customised/globe.svg b/res/img/feather-customised/globe.svg new file mode 100644 index 0000000000..8af7dc41dc --- /dev/null +++ b/res/img/feather-customised/globe.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/res/img/feather-icons/grid.svg b/res/img/feather-customised/grid.svg similarity index 95% rename from res/img/feather-icons/grid.svg rename to res/img/feather-customised/grid.svg index e6912b0cc7..4f7ab30d97 100644 --- a/res/img/feather-icons/grid.svg +++ b/res/img/feather-customised/grid.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-customised/help-circle.svg b/res/img/feather-customised/help-circle.svg new file mode 100644 index 0000000000..7ecb0a8f35 --- /dev/null +++ b/res/img/feather-customised/help-circle.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-customised/home.svg b/res/img/feather-customised/home.svg new file mode 100644 index 0000000000..7bb31b23dc --- /dev/null +++ b/res/img/feather-customised/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/feather-icons/life-buoy.svg b/res/img/feather-customised/life-buoy.svg similarity index 95% rename from res/img/feather-icons/life-buoy.svg rename to res/img/feather-customised/life-buoy.svg index 20bd0f0b5d..6318f7df9a 100644 --- a/res/img/feather-icons/life-buoy.svg +++ b/res/img/feather-customised/life-buoy.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-customised/lock.svg b/res/img/feather-customised/lock.svg new file mode 100644 index 0000000000..1330903b30 --- /dev/null +++ b/res/img/feather-customised/lock.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-icons/notifications.svg b/res/img/feather-customised/notifications.svg similarity index 94% rename from res/img/feather-icons/notifications.svg rename to res/img/feather-customised/notifications.svg index 2fe85e810c..a590031ac3 100644 --- a/res/img/feather-icons/notifications.svg +++ b/res/img/feather-customised/notifications.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-icons/paperclip.svg b/res/img/feather-customised/paperclip.svg similarity index 95% rename from res/img/feather-icons/paperclip.svg rename to res/img/feather-customised/paperclip.svg index ed2bb88681..74a90e0fa3 100644 --- a/res/img/feather-icons/paperclip.svg +++ b/res/img/feather-customised/paperclip.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-icons/phone.svg b/res/img/feather-customised/phone.svg similarity index 96% rename from res/img/feather-icons/phone.svg rename to res/img/feather-customised/phone.svg index 58b257f113..85661c5320 100644 --- a/res/img/feather-icons/phone.svg +++ b/res/img/feather-customised/phone.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-icons/search-input.svg b/res/img/feather-customised/search-input.svg similarity index 93% rename from res/img/feather-icons/search-input.svg rename to res/img/feather-customised/search-input.svg index 3be5acb32e..028b84d559 100644 --- a/res/img/feather-icons/search-input.svg +++ b/res/img/feather-customised/search-input.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-icons/search.svg b/res/img/feather-customised/search.svg similarity index 93% rename from res/img/feather-icons/search.svg rename to res/img/feather-customised/search.svg index 8b14246f64..9ce0724ea7 100644 --- a/res/img/feather-icons/search.svg +++ b/res/img/feather-customised/search.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-icons/settings.svg b/res/img/feather-customised/settings.svg similarity index 98% rename from res/img/feather-icons/settings.svg rename to res/img/feather-customised/settings.svg index ea7ce5c55b..a65a15a75f 100644 --- a/res/img/feather-icons/settings.svg +++ b/res/img/feather-customised/settings.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-icons/share.svg b/res/img/feather-customised/share.svg similarity index 95% rename from res/img/feather-icons/share.svg rename to res/img/feather-customised/share.svg index a012e1b7a5..7098af58aa 100644 --- a/res/img/feather-icons/share.svg +++ b/res/img/feather-customised/share.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-customised/sign-in.svg b/res/img/feather-customised/sign-in.svg new file mode 100644 index 0000000000..9fe617eee1 --- /dev/null +++ b/res/img/feather-customised/sign-in.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/res/img/feather-customised/sign-out.svg b/res/img/feather-customised/sign-out.svg new file mode 100644 index 0000000000..172eb98afb --- /dev/null +++ b/res/img/feather-customised/sign-out.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/feather-customised/sliders.svg b/res/img/feather-customised/sliders.svg new file mode 100644 index 0000000000..5b5ec8656c --- /dev/null +++ b/res/img/feather-customised/sliders.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/feather-customised/upload.svg b/res/img/feather-customised/upload.svg new file mode 100644 index 0000000000..30c89d3819 --- /dev/null +++ b/res/img/feather-customised/upload.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/feather-icons/user-add.svg b/res/img/feather-customised/user-add.svg similarity index 95% rename from res/img/feather-icons/user-add.svg rename to res/img/feather-customised/user-add.svg index cbb25934c1..6b5210c1d6 100644 --- a/res/img/feather-icons/user-add.svg +++ b/res/img/feather-customised/user-add.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-icons/user.svg b/res/img/feather-customised/user.svg similarity index 94% rename from res/img/feather-icons/user.svg rename to res/img/feather-customised/user.svg index a789e580d5..210ef99e6a 100644 --- a/res/img/feather-icons/user.svg +++ b/res/img/feather-customised/user.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-customised/users-sm.svg b/res/img/feather-customised/users-sm.svg new file mode 100644 index 0000000000..6098be38c3 --- /dev/null +++ b/res/img/feather-customised/users-sm.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/res/img/feather-icons/users.svg b/res/img/feather-customised/users.svg similarity index 96% rename from res/img/feather-icons/users.svg rename to res/img/feather-customised/users.svg index b0deac0a9e..b90aafdd4a 100644 --- a/res/img/feather-icons/users.svg +++ b/res/img/feather-customised/users.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-icons/video.svg b/res/img/feather-customised/video.svg similarity index 93% rename from res/img/feather-icons/video.svg rename to res/img/feather-customised/video.svg index a4c456832f..da77b6c57a 100644 --- a/res/img/feather-icons/video.svg +++ b/res/img/feather-customised/video.svg @@ -1,7 +1,7 @@ - + diff --git a/res/img/feather-customised/warning-triangle.svg b/res/img/feather-customised/warning-triangle.svg new file mode 100644 index 0000000000..3d18e30fb2 --- /dev/null +++ b/res/img/feather-customised/warning-triangle.svg @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/res/img/feather-customised/widget/bin.svg b/res/img/feather-customised/widget/bin.svg new file mode 100644 index 0000000000..7616d8931b --- /dev/null +++ b/res/img/feather-customised/widget/bin.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/res/img/feather-customised/widget/camera.svg b/res/img/feather-customised/widget/camera.svg new file mode 100644 index 0000000000..5502493068 --- /dev/null +++ b/res/img/feather-customised/widget/camera.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-customised/widget/edit.svg b/res/img/feather-customised/widget/edit.svg new file mode 100644 index 0000000000..749e83f982 --- /dev/null +++ b/res/img/feather-customised/widget/edit.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-customised/widget/external-link.svg b/res/img/feather-customised/widget/external-link.svg new file mode 100644 index 0000000000..6732f298f4 --- /dev/null +++ b/res/img/feather-customised/widget/external-link.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/img/feather-customised/widget/maximise.svg b/res/img/feather-customised/widget/maximise.svg new file mode 100644 index 0000000000..96185da135 --- /dev/null +++ b/res/img/feather-customised/widget/maximise.svg @@ -0,0 +1,63 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/res/img/feather-customised/widget/minimise.svg b/res/img/feather-customised/widget/minimise.svg new file mode 100644 index 0000000000..f05e939960 --- /dev/null +++ b/res/img/feather-customised/widget/minimise.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/res/img/feather-customised/widget/refresh.svg b/res/img/feather-customised/widget/refresh.svg new file mode 100644 index 0000000000..0994bbdd52 --- /dev/null +++ b/res/img/feather-customised/widget/refresh.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-customised/widget/x-circle.svg b/res/img/feather-customised/widget/x-circle.svg new file mode 100644 index 0000000000..951407b39c --- /dev/null +++ b/res/img/feather-customised/widget/x-circle.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/img/feather-icons/toggle-right-panel.svg b/res/img/feather-icons/toggle-right-panel.svg deleted file mode 100644 index 4cadf89564..0000000000 --- a/res/img/feather-icons/toggle-right-panel.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - Group 2 - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/icon-call.svg b/res/img/icon-call.svg deleted file mode 100644 index 98677e3c70..0000000000 --- a/res/img/icon-call.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/icon-context-delete.svg b/res/img/icon-context-delete.svg deleted file mode 100644 index fba9fa117b..0000000000 --- a/res/img/icon-context-delete.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/res/img/icon-context-fave-on.svg b/res/img/icon-context-fave-on.svg deleted file mode 100644 index 2ae172d8eb..0000000000 --- a/res/img/icon-context-fave-on.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - DAE17B64-40B5-478A-8E8D-97AD1A6E25C8 - Created with sketchtool. - - - - - - - - - - diff --git a/res/img/icon-context-fave.svg b/res/img/icon-context-fave.svg deleted file mode 100644 index 451e1849c8..0000000000 --- a/res/img/icon-context-fave.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - 8A6E1837-F0F1-432E-A0DA-6F3741F71EBF - Created with sketchtool. - - - - - - - - - - diff --git a/res/img/icon-context-low-on.svg b/res/img/icon-context-low-on.svg deleted file mode 100644 index 7578c6335c..0000000000 --- a/res/img/icon-context-low-on.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - CD51482C-F2D4-4F63-AF9E-86513F9AF87F - Created with sketchtool. - - - - - - - - - - diff --git a/res/img/icon-context-low.svg b/res/img/icon-context-low.svg deleted file mode 100644 index 663f3ca9eb..0000000000 --- a/res/img/icon-context-low.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - B160345F-40D3-4BE6-A860-6D04BF223EF7 - Created with sketchtool. - - - - - - - - - - diff --git a/res/img/icon-delete-pink.svg b/res/img/icon-delete-pink.svg deleted file mode 100644 index aafa87f1b2..0000000000 --- a/res/img/icon-delete-pink.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - 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-mx-user.svg b/res/img/icon-mx-user.svg deleted file mode 100644 index 5780277f38..0000000000 --- a/res/img/icon-mx-user.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - diff --git a/res/img/icon_context_copy.svg b/res/img/icon_context_copy.svg deleted file mode 100644 index 1f9c0b01e8..0000000000 --- a/res/img/icon_context_copy.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/icon_context_edit.svg b/res/img/icon_context_edit.svg deleted file mode 100644 index 6f7f1fd385..0000000000 --- a/res/img/icon_context_edit.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/icon_context_leave.svg b/res/img/icon_context_leave.svg deleted file mode 100644 index 3fdd452a59..0000000000 --- a/res/img/icon_context_leave.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/icon_context_message_dark.svg b/res/img/icon_context_message_dark.svg deleted file mode 100644 index b4336cc377..0000000000 --- a/res/img/icon_context_message_dark.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - ED5D3E59-2561-4AC1-9B43-82FBC51767FC - Created with sketchtool. - - - - - - - - - - diff --git a/res/img/icon_context_reply.svg b/res/img/icon_context_reply.svg deleted file mode 100644 index 0a85f8e606..0000000000 --- a/res/img/icon_context_reply.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/icon_copy_message_dark.svg b/res/img/icon_copy_message_dark.svg deleted file mode 100644 index b81e617d8c..0000000000 --- a/res/img/icon_copy_message_dark.svg +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - image/svg+xml - - ED5D3E59-2561-4AC1-9B43-82FBC51767FC - - - - - - ED5D3E59-2561-4AC1-9B43-82FBC51767FC - Created with sketchtool. - - - - - - - diff --git a/res/img/icons-apps-active.svg b/res/img/icons-apps-active.svg deleted file mode 100644 index ea222d0511..0000000000 --- a/res/img/icons-apps-active.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/res/img/icons-apps.svg b/res/img/icons-apps.svg deleted file mode 100644 index e2fe49b005..0000000000 --- a/res/img/icons-apps.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - 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-button.svg b/res/img/icons-close-button.svg deleted file mode 100644 index f960d73a3c..0000000000 --- a/res/img/icons-close-button.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - 206C270A-EB00-48E4-8CC3-5D403C59177C - Created with sketchtool. - - - - - - - - - - diff --git a/res/img/icons-files.svg b/res/img/icons-files.svg deleted file mode 100644 index ea270fbc73..0000000000 --- a/res/img/icons-files.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/res/img/icons-groups-nobg.svg b/res/img/icons-groups-nobg.svg deleted file mode 100644 index a3d223b76d..0000000000 --- a/res/img/icons-groups-nobg.svg +++ /dev/null @@ -1,60 +0,0 @@ - -image/svg+xml - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/icons-hide-apps.svg b/res/img/icons-hide-apps.svg deleted file mode 100644 index b622e97f71..0000000000 --- a/res/img/icons-hide-apps.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/img/icons-hide-stickers.svg b/res/img/icons-hide-stickers.svg deleted file mode 100644 index f28e8646e6..0000000000 --- a/res/img/icons-hide-stickers.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - diff --git a/res/img/icons-notifications.svg b/res/img/icons-notifications.svg deleted file mode 100644 index cde30713e1..0000000000 --- a/res/img/icons-notifications.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/icons-room.svg b/res/img/icons-room.svg deleted file mode 100644 index d2abb21301..0000000000 --- a/res/img/icons-room.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/res/img/icons-search.svg b/res/img/icons-search.svg deleted file mode 100644 index 9d3e98106b..0000000000 --- a/res/img/icons-search.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - Shape - Created with Sketch. - - - - - - - - - - \ No newline at end of file diff --git a/res/img/icons-show-apps.svg b/res/img/icons-show-apps.svg deleted file mode 100644 index 3438157301..0000000000 --- a/res/img/icons-show-apps.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/img/icons-stickers.svg b/res/img/icons-stickers.svg deleted file mode 100644 index 564ebdac97..0000000000 --- a/res/img/icons-stickers.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/res/img/icons-upload.svg b/res/img/icons-upload.svg deleted file mode 100644 index 3aea924478..0000000000 --- a/res/img/icons-upload.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/icons-video.svg b/res/img/icons-video.svg deleted file mode 100644 index c61a782cc4..0000000000 --- a/res/img/icons-video.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/icons_ellipsis.svg b/res/img/icons_ellipsis.svg deleted file mode 100644 index ba600ccacc..0000000000 --- a/res/img/icons_ellipsis.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/res/img/icons_global.svg b/res/img/icons_global.svg deleted file mode 100644 index 6c07d3c48e..0000000000 --- a/res/img/icons_global.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - icons_global copy 4 - Created with Sketch. - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/list-close.svg b/res/img/list-close.svg deleted file mode 100644 index cd88b2a88f..0000000000 --- a/res/img/list-close.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - -Slice 1 -Created with Sketch. - - - - diff --git a/res/img/list-open.svg b/res/img/list-open.svg deleted file mode 100644 index e180be8870..0000000000 --- a/res/img/list-open.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - -Slice 1 -Created with Sketch. - - - - diff --git a/res/img/markdown.svg b/res/img/markdown.svg new file mode 100644 index 0000000000..9aadd3cb7f --- /dev/null +++ b/res/img/markdown.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/matrix-org-bw-logo.svg b/res/img/matrix-org-bw-logo.svg new file mode 100644 index 0000000000..39a7b173e8 --- /dev/null +++ b/res/img/matrix-org-bw-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/img/maximise.svg b/res/img/maximise.svg deleted file mode 100644 index 981e3796de..0000000000 --- a/res/img/maximise.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - -minimise -Created with sketchtool. - - - - - - - - - - - - diff --git a/res/img/maximize.svg b/res/img/maximize.svg deleted file mode 100644 index 4f9e10191f..0000000000 --- a/res/img/maximize.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - diff --git a/res/img/minimize.svg b/res/img/minimize.svg deleted file mode 100644 index 410b0bc08e..0000000000 --- a/res/img/minimize.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/res/img/modular-bw-logo.svg b/res/img/modular-bw-logo.svg new file mode 100644 index 0000000000..924a587805 --- /dev/null +++ b/res/img/modular-bw-logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/img/newmessages.svg b/res/img/newmessages.svg deleted file mode 100644 index a2ffca9020..0000000000 --- a/res/img/newmessages.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - icon_newmessages - Created with Sketch. - - - - - - - - - - \ No newline at end of file diff --git a/res/img/right_search.svg b/res/img/right_search.svg deleted file mode 100644 index b430a6be19..0000000000 --- a/res/img/right_search.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - right_search - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/scrolldown.svg b/res/img/scrolldown.svg deleted file mode 100644 index d6599c5fc7..0000000000 --- a/res/img/scrolldown.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - icon_newmessages - Created with Sketch. - - - - - - - - - - \ No newline at end of file diff --git a/res/img/scrollto.svg b/res/img/scrollto.svg deleted file mode 100644 index 75df053a68..0000000000 --- a/res/img/scrollto.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - Slice 1 - Created with Sketch. - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/scrollup.svg b/res/img/scrollup.svg deleted file mode 100644 index 1692f2a6c0..0000000000 --- a/res/img/scrollup.svg +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - image/svg+xml - - - - - - - icon_newmessages - Created with Sketch. - - - - - - - - - - diff --git a/res/img/search-button.svg b/res/img/search-button.svg deleted file mode 100644 index f4808842ff..0000000000 --- a/res/img/search-button.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - icon_search - Created with Sketch. - - - - - - - - - - \ No newline at end of file diff --git a/res/img/settings-big.svg b/res/img/settings-big.svg deleted file mode 100644 index c9587d58c2..0000000000 --- a/res/img/settings-big.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - icons_settings - Created with sketchtool. - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/settings.svg b/res/img/settings.svg deleted file mode 100644 index 4190c7b8de..0000000000 --- a/res/img/settings.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - icon_settings_small - Created with bin/sketchtool. - - - - - - - \ No newline at end of file diff --git a/res/img/topleft-chevron.svg b/res/img/topleft-chevron.svg deleted file mode 100644 index 1cfeaf6352..0000000000 --- a/res/img/topleft-chevron.svg +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - image/svg+xml - - dropdown - - - - - - dropdown - Created with Sketch. - - - - - - - - - - - - diff --git a/res/img/upload.svg b/res/img/upload.svg deleted file mode 100644 index 039014a2f3..0000000000 --- a/res/img/upload.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - icons_upload - Created with bin/sketchtool. - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/voice.svg b/res/img/voice.svg deleted file mode 100644 index ff87270ba5..0000000000 --- a/res/img/voice.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - icon_voice - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/res/img/warning_yellow.svg b/res/img/warning_yellow.svg deleted file mode 100644 index 4d227517d2..0000000000 --- a/res/img/warning_yellow.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 257b723ccf..3112644a73 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -1,188 +1,162 @@ +// unified palette +// try to use these colors when possible +$bg-color: #181b21; +$base-color: #15171b; +$base-text-color: #edf3ff; +$header-panel-bg-color: #22262e; +$header-panel-border-color: #000000; +$header-panel-text-primary-color: #a1b2d1; +$header-panel-text-secondary-color: #c8c8cd; +$text-primary-color: #edf3ff; +$text-secondary-color: #a1b2d1; +$search-bg-color: #181b21; +$search-placeholder-color: #61708b; +$room-highlight-color: #343a46; // typical text (dark-on-white in light skin) -$primary-fg-color: #212121; -$primary-bg-color: #2d2d2d; - -// used for focusing form controls -$focus-bg-color: #101010; +$primary-fg-color: $text-primary-color; +$primary-bg-color: $bg-color; // used for dialog box text -$light-fg-color: #747474; +$light-fg-color: $header-panel-text-secondary-color; -// 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; +// used for focusing form controls +$focus-bg-color: $room-highlight-color; -$selection-fg-color: $primary-fg-color; +$mention-user-pill-bg-color: $warning-color; +$other-user-pill-bg-color: $room-highlight-color; +$rte-room-pill-color: $room-highlight-color; +$rte-group-pill-color: $room-highlight-color; -$focus-brightness: 200%; +// informational plinth +$info-plinth-bg-color: $header-panel-bg-color; +$info-plinth-fg-color: #888; -// red warning colour -$warning-color: #ff0064; -$warning-bg-color: #DF2A8B; -$info-bg-color: #2A9EDF; +$preview-bar-bg-color: $header-panel-bg-color; -// groups -$info-plinth-bg-color: #454545; - -$other-user-pill-bg-color: rgba(255, 255, 255, 0.1); - -$preview-bar-bg-color: #333; - -// left-panel style muted accent color -$secondary-accent-color: $primary-bg-color; -$tertiary-accent-color: #454545; - -// stop the tinter trying to change the secondary accent color -// by overriding the key to something untintable -// XXX: this is a bit of a hack. -#mx_theme_secondaryAccentColor { - color: #c0ffee ! important; -} - -#mx_theme_tertiaryAccentColor { - color: #c0ffee ! important; -} - -// used by RoomDirectory permissions -$plinth-bg-color: #474747; - -// used by RoomDropTarget -$droptarget-bg-color: rgba(45,45,45,0.5); +$tagpanel-bg-color: $base-color; // used by AddressSelector -$selected-color: #000000; +$selected-color: $room-highlight-color; // selected for hoverover & selected event tiles -$event-selected-color: #353535; +$event-selected-color: #111316; // used for the hairline dividers in RoomView -$primary-hairline-color: #474747; +$primary-hairline-color: $header-panel-border-color; // used for the border of input text fields -$input-border-color: #3a3a3a; +$input-border-color: #e7e7e7; +$input-darker-bg-color: $search-bg-color; +$input-darker-fg-color: $search-placeholder-color; +$input-lighter-bg-color: #f2f5f8; +$input-lighter-fg-color: $input-darker-fg-color; +$input-focused-border-color: #238cf5; +$input-valid-border-color: $accent-color; +$input-invalid-border-color: $warning-color; -$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; +$field-focused-label-bg-color: $bg-color; -// 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; +$menu-border-color: $header-panel-border-color; +$menu-bg-color: $header-panel-bg-color; +$menu-box-shadow-color: $bg-color; +$menu-selected-color: $room-highlight-color; -$avatar-initial-color: #2d2d2d; -$avatar-bg-color: #ffffff; -$menu-selected-color: #f5f8fa; +$avatar-initial-color: #ffffff; +$avatar-bg-color: $bg-color; $h3-color: $primary-fg-color; -$dialog-background-bg-color: #000; +$dialog-title-fg-color: #454545; +$dialog-backdrop-color: #000; +$dialog-shadow-color: rgba(0, 0, 0, 0.48); +$dialog-close-fg-color: #9fa9ba; + +$dialog-background-bg-color: $header-panel-bg-color; $lightbox-background-bg-color: #000; -$greyed-fg-color: #888; - -$neutral-badge-color: #888; - -$preview-widget-bar-color: $menu-bg-color; -$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: $text-secondary-color; -$voip-decline-color: #f48080; -$voip-accept-color: #80f480; +$topleftmenu-color: $text-primary-color; +$roomheader-color: $text-primary-color; +$roomheader-addroom-bg-color: #3c4556; // $search-placeholder-color at 0.5 opacity +$roomheader-addroom-fg-color: $text-primary-color; +$tagpanel-button-color: $header-panel-text-primary-color; +$roomheader-button-color: $header-panel-text-primary-color; +$groupheader-button-color: $header-panel-text-primary-color; +$rightpanel-button-color: $header-panel-text-primary-color; +$composer-button-color: $header-panel-text-primary-color; +$roomtopic-color: $text-secondary-color; +$eventtile-meta-color: $roomtopic-color; -$rte-bg-color: #353535; -$rte-code-bg-color: #000; +$header-divider-color: $header-panel-text-primary-color; -$room-warning-bg-color: #2d2d2d; +$roomtile-name-color: $header-panel-text-primary-color; +$roomtile-selected-color: $text-primary-color; +$roomtile-notified-color: $text-primary-color; +$roomtile-selected-bg-color: $room-highlight-color; +$roomtile-focused-bg-color: $room-highlight-color; -// ******************** +$roomtile-transparent-focused-color: rgba(0, 0, 0, 0.1); -$roomtile-name-color: rgba(186, 186, 186, 0.8); -$roomtile-selected-bg-color: #333; -$roomtile-focused-bg-color: rgba(255, 255, 255, 0.2); +$panel-divider-color: $header-panel-border-color; -$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; -$roomsublist-chevron-color: $accent-color; - -$panel-divider-color: rgba(118, 207, 166, 0.2); - -// ******************** - -$widget-menu-bar-bg-color: $tertiary-accent-color; - -// ******************** +$widget-menu-bar-bg-color: $header-panel-bg-color; // event tile lifecycle -$event-encrypting-color: rgba(171, 221, 188, 0.4); -$event-sending-color: #888; -$event-notsent-color: #f44; +$event-sending-color: $text-secondary-color; // event redaction $event-redacted-fg-color: #606060; $event-redacted-border-color: #000000; // event timestamp -$event-timestamp-color: #acacac; +$event-timestamp-color: $text-secondary-color; -$edit-button-url: "../../img/icon_context_message_dark.svg"; -$copy-button-url: "../../img/icon_copy_message_dark.svg"; +// Tabbed views +$tab-label-fg-color: $text-primary-color; +$tab-label-active-fg-color: $text-primary-color; +$tab-label-bg-color: transparent; +$tab-label-active-bg-color: $accent-color; +$tab-label-icon-bg-color: $text-primary-color; +$tab-label-active-icon-bg-color: $text-primary-color; -// e2e -$e2e-verified-color: #76cfa5; // N.B. *NOT* the same as $accent-color -$e2e-unverified-color: #e8bf37; -$e2e-warning-color: #ba6363; +// Buttons +$button-primary-fg-color: #ffffff; +$button-primary-bg-color: $accent-color; +$button-secondary-bg-color: transparent; +$button-danger-fg-color: #ffffff; +$button-danger-bg-color: $notice-primary-color; +$button-danger-disabled-fg-color: #ffffff; +$button-danger-disabled-bg-color: #f5b6bb; // TODO: Verify color -/*** ImageView ***/ -$lightbox-bg-color: #454545; -$lightbox-fg-color: #ffffff; -$lightbox-border-color: #ffffff; +$room-warning-bg-color: $header-panel-bg-color; -/*** GroupGridView ***/ -$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5); -$gridview-focus-border-color: rgba(134, 193, 165, 1); +$dark-panel-bg-color: $header-panel-bg-color; +$panel-gradient: rgba(34, 38, 46, 0), rgba(34, 38, 46, 1); -$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); +// ***** Mixins! ***** -// unused? -$progressbar-color: #000; - -// XXX: copypasted from _base in order to pick up the right FG color... @define-mixin mx_DialogButton { /* align images in buttons (eg spinners) */ vertical-align: middle; border: 0px; - border-radius: 36px; + border-radius: 4px; font-family: $font-family; font-size: 14px; - color: $accent-fg-color; - background-color: $accent-color; + color: $button-fg-color; + background-color: $button-bg-color; width: auto; padding: 7px; padding-left: 1.5em; @@ -192,12 +166,16 @@ $progressbar-color: #000; outline: none; } +@define-mixin mx_DialogButton_danger { + background-color: $accent-color; +} + @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; + background-color: $button-secondary-bg-color; } // Nasty hacks to apply a filter to arbitrary monochrome artwork to make it @@ -234,8 +212,3 @@ $progressbar-color: #000; } } } - -// Add a line to the right side of the left panel to distinguish it from the middle panel -.mx_LeftPanel { - border-right: 1px solid $tertiary-accent-color; -} diff --git a/res/themes/dark/css/dark.scss b/res/themes/dark/css/dark.scss index b69f096db7..e7ae7c8cf8 100644 --- a/res/themes/dark/css/dark.scss +++ b/res/themes/dark/css/dark.scss @@ -1,4 +1,5 @@ -@import "../../light/css/_base.scss"; +@import "../../light/css/_paths.scss"; +@import "../../light/css/_fonts.scss"; +@import "../../light/css/_light.scss"; @import "_dark.scss"; @import "../../../../res/css/_components.scss"; - diff --git a/res/themes/dharma/css/_fonts.scss b/res/themes/dharma/css/_fonts.scss deleted file mode 100644 index bb45432262..0000000000 --- a/res/themes/dharma/css/_fonts.scss +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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('../../fonts/Nunito/XRXX3I6Li01BKofIMNaDRss.ttf') format('truetype'); -} -@font-face { - font-family: 'Nunito'; - font-style: italic; - font-weight: 600; - src: url('../../fonts/Nunito/XRXQ3I6Li01BKofIMN5cYtvKUTo.ttf') format('truetype'); -} -@font-face { - font-family: 'Nunito'; - font-style: italic; - font-weight: 700; - src: url('../../fonts/Nunito/XRXQ3I6Li01BKofIMN44Y9vKUTo.ttf') format('truetype'); -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 400; - src: url('../../fonts/Nunito/XRXV3I6Li01BKofINeaE.ttf') format('truetype'); -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 600; - src: url('../../fonts/Nunito/XRXW3I6Li01BKofA6sKUYevN.ttf') format('truetype'); -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 700; - src: url('../../fonts/Nunito/XRXW3I6Li01BKofAjsOUYevN.ttf') format('truetype'); -} - -/* - * Fira Mono - * Used for monospace copy, i.e. code - */ - -@font-face { - font-family: 'Fira Mono'; - src: url('../../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'); - font-weight: 700; - font-style: normal; -} diff --git a/res/themes/dharma/css/dharma.scss b/res/themes/dharma/css/dharma.scss deleted file mode 100644 index 0f4db55fd2..0000000000 --- a/res/themes/dharma/css/dharma.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import "_dharma.scss"; -@import "../../../../res/css/_components.scss"; - diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss deleted file mode 100644 index 10a8fcd1e5..0000000000 --- a/res/themes/light/css/_base.scss +++ /dev/null @@ -1,230 +0,0 @@ -@import "_fonts.scss"; - -/* Open Sans 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: 'Open Sans', 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: #76CFA6; -$accent-color-alt: $accent-color; -$accent-color-50pct: #76CFA67F; - -$selection-fg-color: $primary-bg-color; - -$focus-brightness: 125%; - -// red warning colour -$warning-color: #ff0064; -// background colour for warnings -$warning-bg-color: #DF2A8B; -$info-bg-color: #2A9EDF; -$mention-user-pill-bg-color: #ff0064; -$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: #eaf5f0; -$tertiary-accent-color: #d3efe1; - -$tagpanel-bg-color: $tertiary-accent-color; - -// 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: #f0f0f0; - -$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; - -// used for UserSettings EditableText -$input-underline-color: rgba(151, 151, 151, 0.5); -$input-fg-color: rgba(74, 74, 74, 0.9); - -// 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-background-bg-color: #e9e9e9; -$lightbox-background-bg-color: #000; - -$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; - -$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: $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); -$roomsublist-label-fg-color: $h3-color; -$roomsublist-label-bg-color: $tertiary-accent-color; -$roomsublist-chevron-color: $accent-color; - -$panel-divider-color: rgba(118, 207, 166, 0.2); - -// ******************** - -$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: "../../img/icon_context_message.svg"; -$copy-button-url: "../../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; - -/*** GroupGridView ***/ -$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5); -$gridview-focus-border-color: rgba(134, 193, 165, 1); - -$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); - -// unused? -$progressbar-color: #000; - -$room-warning-bg-color: #fff8e3; - -// ***** Mixins! ***** - -@define-mixin mx_DialogButton { - /* align images in buttons (eg spinners) */ - vertical-align: middle; - border: 0px; - border-radius: 36px; - font-family: $font-family; - font-size: 14px; - color: $accent-fg-color; - background-color: $accent-color; - width: auto; - padding: 7px; - padding-left: 1.5em; - padding-right: 1.5em; - cursor: pointer; - display: inline-block; - outline: none; -} - -@define-mixin mx_DialogButton_danger { - background-color: $warning-color; -} - -@define-mixin mx_DialogButton_hover { -} - -@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/light/css/_fonts.scss b/res/themes/light/css/_fonts.scss index 52ac95b569..ac15847e44 100644 --- a/res/themes/light/css/_fonts.scss +++ b/res/themes/light/css/_fonts.scss @@ -1,50 +1,36 @@ /* - * Open Sans - * Includes extended Latin, Greek, Cyrillic and Vietnamese character sets + * Nunito. + * Includes extended Latin and Vietnamese character sets + * Current URLs are taken from + * https://github.com/alexeiva/NunitoFont/releases/tag/v3.500 + * ...in order to include cyrillic. + * + * Previously, they were + * https://fonts.googleapis.com/css?family=Nunito:400,400i,600,600i,700,700i&subset=latin-ext,vietnamese + * + * We explicitly do not include Nunito's italic variants, as they are not italic enough + * and it's better to rely on the browser's built-in obliquing behaviour. */ /* the 'src' links are relative to the bundle.css, which is in a subdirectory. */ @font-face { - font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Regular.ttf') format('truetype'); - font-weight: 400; - font-style: normal; + font-family: 'Nunito'; + font-style: normal; + font-weight: 400; + src: url('$(res)/fonts/Nunito/Nunito-Regular.ttf') format('truetype'); } - @font-face { - font-family: 'Open Sans'; - src: url('../../fonts/Open_Sans/OpenSans-Italic.ttf') format('truetype'); - font-weight: 400; - font-style: italic; + font-family: 'Nunito'; + font-style: normal; + font-weight: 600; + src: url('$(res)/fonts/Nunito/Nunito-SemiBold.ttf') format('truetype'); } - @font-face { - font-family: 'Open Sans'; - src: url('../../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'); - font-weight: 600; - font-style: italic; -} - -@font-face { - font-family: 'Open Sans'; - src: url('../../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'); - font-weight: 700; - font-style: italic; + font-family: 'Nunito'; + font-style: normal; + font-weight: 700; + src: url('$(res)/fonts/Nunito/Nunito-Bold.ttf') format('truetype'); } /* @@ -54,14 +40,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/dharma/css/_dharma.scss b/res/themes/light/css/_light.scss similarity index 58% rename from res/themes/dharma/css/_dharma.scss rename to res/themes/light/css/_light.scss index 732cabf494..879be67dda 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/light/css/_light.scss @@ -1,5 +1,3 @@ -@import "_fonts.scss"; - // XXX: check this? /* Nunito lacks combining diacritics, so these will fall through to the next font. Helevetica's diacritics however do not combine @@ -8,8 +6,15 @@ Arial here. */ $font-family: 'Nunito', Arial, Helvetica, Sans-Serif; +// unified palette +// try to use these colors when possible +$accent-color: #03b381; +$notice-primary-color: #ff4b55; +$notice-secondary-color: #61708b; +$header-panel-bg-color: #f2f5f8; + // typical text (dark-on-white in light skin) -$primary-fg-color: #454545; +$primary-fg-color: #2e2f32; $primary-bg-color: #ffffff; // used for dialog box text @@ -20,7 +25,6 @@ $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; @@ -29,7 +33,7 @@ $selection-fg-color: $primary-bg-color; $focus-brightness: 105%; // red warning colour -$warning-color: #f56679; +$warning-color: $notice-primary-color; // background colour for warnings $warning-bg-color: #DF2A8B; $info-bg-color: #2A9EDF; @@ -37,8 +41,8 @@ $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; +$pinned-unread-color: $notice-primary-color; +$pinned-color: $notice-secondary-color; // informational plinth $info-plinth-bg-color: #f7f7f7; @@ -50,7 +54,7 @@ $preview-bar-bg-color: #f7f7f7; $secondary-accent-color: #f2f5f8; $tertiary-accent-color: #d3efe1; -$tagpanel-bg-color: #2e3649; +$tagpanel-bg-color: #27303a; // used by RoomDirectory permissions $plinth-bg-color: $secondary-accent-color; @@ -68,13 +72,18 @@ $event-selected-color: #f7f7f7; $primary-hairline-color: #e5e5e5; // used for the border of input text fields -$input-border-color: #f0f0f0; +$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: $accent-color; +$input-invalid-border-color: $warning-color; -$button-bg-color: #7ac9a1; +$field-focused-label-bg-color: #ffffff; + +$button-bg-color: $accent-color; $button-fg-color: white; // apart from login forms, which have stronger border @@ -83,10 +92,13 @@ $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-border-color: #e7e7e7; $menu-bg-color: #fff; +$menu-box-shadow-color: rgba(118, 131, 156, 0.6); $menu-selected-color: #f5f8fa; $avatar-initial-color: #ffffff; @@ -94,6 +106,11 @@ $avatar-bg-color: #ffffff; $h3-color: #3d3b39; +$dialog-title-fg-color: #2e2f32; +$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; @@ -112,6 +129,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: #2e2f32; +$settings-subsection-fg-color: #61708b; $voip-decline-color: #f48080; $voip-accept-color: #80f480; @@ -123,10 +146,19 @@ $rte-group-pill-color: #aaa; $topleftmenu-color: #212121; $roomheader-color: #45474a; -$roomheader-addroom-color: #91A1C0; +$roomheader-addroom-bg-color: #91A1C0; +$roomheader-addroom-fg-color: $accent-fg-color; +$tagpanel-button-color: #91A1C0; +$roomheader-button-color: #91A1C0; +$groupheader-button-color: #91A1C0; +$rightpanel-button-color: #91A1C0; +$composer-button-color: #91A1C0; $roomtopic-color: #9fa9ba; $eventtile-meta-color: $roomtopic-color; +$composer-e2e-icon-color: #c9ced6; +$header-divider-color: #91A1C0; + // ******************** $roomtile-name-color: #61708b; @@ -135,14 +167,14 @@ $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; +$username-variant1-color: #368bd6; +$username-variant2-color: #ac3ba8; +$username-variant3-color: #03b381; +$username-variant4-color: #e64f7a; +$username-variant5-color: #ff812d; +$username-variant6-color: #2dc2c5; +$username-variant7-color: #5c56f5; +$username-variant8-color: #74d12c; $roomtile-transparent-focused-color: rgba(0, 0, 0, 0.1); @@ -155,7 +187,7 @@ $panel-divider-color: #dee1f3; // ******************** -$widget-menu-bar-bg-color: $tertiary-accent-color; +$widget-menu-bar-bg-color: $secondary-accent-color; // ******************** @@ -171,8 +203,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 @@ -184,116 +216,45 @@ $lightbox-bg-color: #454545; $lightbox-fg-color: #ffffff; $lightbox-border-color: #ffffff; -/*** GroupGridView ***/ -$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5); -$gridview-focus-border-color: rgba(134, 193, 165, 1); -// unused? +// Tabbed views +$tab-label-fg-color: #45474a; +$tab-label-active-fg-color: #ffffff; +$tab-label-bg-color: transparent; +$tab-label-active-bg-color: $accent-color; +$tab-label-icon-bg-color: #454545; +$tab-label-active-icon-bg-color: #ffffff; + +// Buttons +$button-primary-fg-color: #ffffff; +$button-primary-bg-color: $accent-color; +$button-secondary-bg-color: $accent-fg-color; +$button-danger-fg-color: #ffffff; +$button-danger-bg-color: $notice-primary-color; +$button-danger-disabled-fg-color: #ffffff; +$button-danger-disabled-bg-color: #f5b6bb; // TODO: Verify color + +// Toggle switch +$togglesw-off-color: #c1c9d6; +$togglesw-on-color: $accent-color; +$togglesw-ball-color: #fff; + $progressbar-color: #000; $room-warning-bg-color: #fff8e3; -/*** form elements ***/ +$memberstatus-placeholder-color: $roomtile-name-color; -// .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 +$authpage-bg-color: #2e3649; +$authpage-modal-bg-color: rgba(255, 255, 255, 0.59); +$authpage-body-bg-color: #ffffff; +$authpage-focus-bg-color: #dddddd; +$authpage-lang-color: #4e5054; +$authpage-primary-color: #232f32; +$authpage-secondary-color: #61708b; -.mx_MatrixChat { +$dark-panel-bg-color: $secondary-accent-color; +$panel-gradient: rgba(242, 245, 248, 0), rgba(242, 245, 248, 1); - :not(.mx_textinput) > input[type=text], - :not(.mx_textinput) > input[type=search], - .mx_textinput { - display: block; - margin: 9px; - box-sizing: border-box; - background-color: transparent; - color: $input-darker-fg-color; - border-radius: 4px; - border: 1px solid #c1c1c1; - 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) > input[type=text], - :not(.mx_textinput) > input[type=search], - .mx_textinput { - color: $input-darker-fg-color; - background-color: $input-darker-bg-color; - border: none; - } -} - -.light-panel { - :not(.mx_textinput) > input[type=text], - :not(.mx_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('../../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; -} // ***** Mixins! ***** @define-mixin mx_DialogButton { @@ -332,5 +293,5 @@ input[type=search]::-webkit-search-results-decoration { font-weight: 600; border: 1px solid $accent-color ! important; color: $accent-color; - background-color: $accent-fg-color; + background-color: $button-secondary-bg-color; } 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..6acb2d9d94 100644 --- a/res/themes/light/css/light.scss +++ b/res/themes/light/css/light.scss @@ -1,3 +1,4 @@ -@import "_base.scss"; +@import "_paths.scss"; +@import "_fonts.scss"; +@import "_light.scss"; @import "../../../../res/css/_components.scss"; - diff --git a/scripts/ci/build.sh b/scripts/ci/build.sh new file mode 100644 index 0000000000..0b1fa23093 --- /dev/null +++ b/scripts/ci/build.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# script which is run by the CI build (after `yarn 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` + +yarn link + +scripts/fetchdep.sh vector-im riot-web + +pushd "$RIOT_WEB_DIR" + +yarn link matrix-js-sdk +yarn link matrix-react-sdk + +yarn install + +yarn build + +popd diff --git a/scripts/travis/end-to-end-tests.sh b/scripts/ci/end-to-end-tests.sh old mode 100755 new mode 100644 similarity index 83% rename from scripts/travis/end-to-end-tests.sh rename to scripts/ci/end-to-end-tests.sh index 361b053d2b..d0b1a30ce2 --- a/scripts/travis/end-to-end-tests.sh +++ b/scripts/ci/end-to-end-tests.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# script which is run by the travis build (after `npm run test`). +# script which is run by the CI build (after `yarn test`). # # clones riot-web develop and runs the tests against our version of react-sdk. @@ -9,7 +9,7 @@ set -ev RIOT_WEB_DIR=riot-web REACT_SDK_DIR=`pwd` -scripts/travis/build.sh +scripts/ci/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 diff --git a/scripts/ci/install-deps.sh b/scripts/ci/install-deps.sh new file mode 100644 index 0000000000..6484ebab29 --- /dev/null +++ b/scripts/ci/install-deps.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -ex + +scripts/fetchdep.sh matrix-org matrix-js-sdk + +pushd matrix-js-sdk +yarn link +yarn install +popd + +yarn link matrix-js-sdk +yarn install diff --git a/scripts/travis/riot-unit-tests.sh b/scripts/ci/riot-unit-tests.sh old mode 100755 new mode 100644 similarity index 60% rename from scripts/travis/riot-unit-tests.sh rename to scripts/ci/riot-unit-tests.sh index a2f0d61112..215af13030 --- a/scripts/travis/riot-unit-tests.sh +++ b/scripts/ci/riot-unit-tests.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# script which is run by the travis build (after `npm run test`). +# script which is run by the CI build (after `yarn test`). # # clones riot-web develop and runs the tests against our version of react-sdk. @@ -8,7 +8,7 @@ set -ev RIOT_WEB_DIR=riot-web -scripts/travis/build.sh +scripts/ci/build.sh pushd "$RIOT_WEB_DIR" -npm run test +yarn test popd diff --git a/scripts/travis/unit-tests.sh b/scripts/ci/unit-tests.sh old mode 100755 new mode 100644 similarity index 50% rename from scripts/travis/unit-tests.sh rename to scripts/ci/unit-tests.sh index a8e0a63b31..5b86190963 --- a/scripts/travis/unit-tests.sh +++ b/scripts/ci/unit-tests.sh @@ -1,10 +1,10 @@ #!/bin/bash # -# script which is run by the travis build (after `npm run test`). +# script which is run by the CI build (after `yarn test`). # # clones riot-web develop and runs the tests against our version of react-sdk. set -ev -scripts/travis/build.sh -npm run test +scripts/ci/build.sh +yarn test diff --git a/scripts/fetchdep.sh b/scripts/fetchdep.sh index 95fc4b0603..f82752bfc5 100755 --- a/scripts/fetchdep.sh +++ b/scripts/fetchdep.sh @@ -1,27 +1,40 @@ -#!/bin/sh +#!/bin/bash -org="$1" -repo="$2" +set -x + +deforg="$1" +defrepo="$2" defbranch="$3" [ -z "$defbranch" ] && defbranch="develop" -rm -r "$repo" || true +rm -r "$defrepo" || true clone() { - branch=$1 + org=$1 + repo=$2 + branch=$3 if [ -n "$branch" ] then - echo "Trying to use the branch $branch" - git clone https://github.com/$org/$repo.git $repo --branch "$branch" && exit 0 + echo "Trying to use $org/$repo#$branch" + git clone git://github.com/$org/$repo.git $repo --branch "$branch" && exit 0 fi } # Try the PR author's branch in case it exists on the deps as well. -clone $TRAVIS_PULL_REQUEST_BRANCH +# If BUILDKITE_BRANCH is set, it will contain either: +# * "branch" when the author's branch and target branch are in the same repo +# * "author:branch" when the author's branch is in their fork +# We can split on `:` into an array to check. +BUILDKITE_BRANCH_ARRAY=(${BUILDKITE_BRANCH//:/ }) +if [[ "${#BUILDKITE_BRANCH_ARRAY[@]}" == "1" ]]; then + clone $deforg $defrepo $BUILDKITE_BRANCH +elif [[ "${#BUILDKITE_BRANCH_ARRAY[@]}" == "2" ]]; then + clone ${BUILDKITE_BRANCH_ARRAY[0]} $defrepo ${BUILDKITE_BRANCH_ARRAY[1]} +fi # Try the target branch of the push or PR. -clone $TRAVIS_BRANCH +clone $deforg $defrepo $BUILDKITE_PULL_REQUEST_BASE_BRANCH # Try the current branch from Jenkins. -clone `"echo $GIT_BRANCH" | sed -e 's/^origin\///'` +clone $deforg $defrepo `"echo $GIT_BRANCH" | sed -e 's/^origin\///'` # Use the default branch as the last resort. -clone $defbranch +clone $deforg $defrepo $defbranch diff --git a/scripts/travis/build.sh b/scripts/travis/build.sh deleted file mode 100755 index a353e38a06..0000000000 --- a/scripts/travis/build.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/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/fetchdep.sh vector-im riot-web -pushd "$RIOT_WEB_DIR" - -mkdir node_modules -npm install - -# use the version of js-sdk we just used in the react-sdk tests -rm -r node_modules/matrix-js-sdk -ln -s "$REACT_SDK_DIR/node_modules/matrix-js-sdk" node_modules/matrix-js-sdk - -# ... and, of course, the version of react-sdk we just built -rm -r node_modules/matrix-react-sdk -ln -s "$REACT_SDK_DIR" node_modules/matrix-react-sdk - -npm run build -popd diff --git a/scripts/travis/install-deps.sh b/scripts/travis/install-deps.sh deleted file mode 100755 index 04cd728157..0000000000 --- a/scripts/travis/install-deps.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/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 - -cd matrix-js-sdk -npm install -cd .. diff --git a/src/ActiveRoomObserver.js b/src/ActiveRoomObserver.js index c276cccb5d..d6fbb460b5 100644 --- a/src/ActiveRoomObserver.js +++ b/src/ActiveRoomObserver.js @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import OpenRoomsStore from './stores/OpenRoomsStore'; +import RoomViewStore from './stores/RoomViewStore'; /** - * Consumes changes from the OpenRoomsStore and notifies specific things + * Consumes changes from the RoomViewStore and notifies specific things * about when the active room changes. Unlike listening for RoomViewStore * changes, you can subscribe to only changes relevant to a particular * room. @@ -28,15 +28,11 @@ import OpenRoomsStore from './stores/OpenRoomsStore'; class ActiveRoomObserver { constructor() { this._listeners = {}; - const roomStore = OpenRoomsStore.getActiveRoomStore(); - this._activeRoomId = roomStore && roomStore.getRoomId(); + + this._activeRoomId = RoomViewStore.getRoomId(); // TODO: We could self-destruct when the last listener goes away, or at least // stop listening. - this._roomStoreToken = OpenRoomsStore.addListener(this._onOpenRoomsStoreUpdate.bind(this)); - } - - getActiveRoomId() { - return this._activeRoomId; + this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this)); } addListener(roomId, listener) { @@ -55,23 +51,23 @@ class ActiveRoomObserver { } } - _emit(roomId, newActiveRoomId) { + _emit(roomId) { if (!this._listeners[roomId]) return; for (const l of this._listeners[roomId]) { - l.call(l, newActiveRoomId); + l.call(); } } - _onOpenRoomsStoreUpdate() { - const activeRoomStore = OpenRoomsStore.getActiveRoomStore(); - const newActiveRoomId = activeRoomStore && activeRoomStore.getRoomId(); + _onRoomViewStoreUpdate() { // emit for the old room ID - if (this._activeRoomId) this._emit(this._activeRoomId, newActiveRoomId); + if (this._activeRoomId) this._emit(this._activeRoomId); + // update our cache - this._activeRoomId = newActiveRoomId; + this._activeRoomId = RoomViewStore.getRoomId(); + // and emit for the new one - if (this._activeRoomId) this._emit(this._activeRoomId, this._activeRoomId); + if (this._activeRoomId) this._emit(this._activeRoomId); } } diff --git a/src/AddThreepid.js b/src/AddThreepid.js index 337e38d867..adeaf84a69 100644 --- a/src/AddThreepid.js +++ b/src/AddThreepid.js @@ -19,14 +19,14 @@ import MatrixClientPeg from './MatrixClientPeg'; import { _t } from './languageHandler'; /** - * Allows a user to add a third party identifier to their Home Server and, + * Allows a user to add a third party identifier to their homeserver and, * optionally, the identity servers. * * This involves getting an email token from the identity server to "prove" that * 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..44b85e4842 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': { @@ -267,7 +267,7 @@ class Analytics { const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog'); Modal.createTrackedDialog('Analytics Details', '', ErrorDialog, { title: _t('Analytics'), - description:
+ description:
{ _t('The information being sent to us to help make Riot.im better includes:') }
diff --git a/src/Avatar.js b/src/Avatar.js index d41a3f6a79..99b558fa93 100644 --- a/src/Avatar.js +++ b/src/Avatar.js @@ -51,11 +51,11 @@ module.exports = { }, defaultAvatarUrlForString: function(s) { - const images = ['76cfa6', '50e2c2', 'f4c371']; + const images = ['03b381', '368bd6', 'ac3ba8']; let total = 0; 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/BasePlatform.js b/src/BasePlatform.js index 79f0d69e2c..54310d1849 100644 --- a/src/BasePlatform.js +++ b/src/BasePlatform.js @@ -113,4 +113,29 @@ export default class BasePlatform { reload() { throw new Error("reload not implemented!"); } + + supportsAutoLaunch(): boolean { + return false; + } + + // XXX: Surely this should be a setting like any other? + async getAutoLaunchEnabled(): boolean { + return false; + } + + async setAutoLaunchEnabled(enabled: boolean): void { + throw new Error("Unimplemented"); + } + + supportsMinimizeToTray(): boolean { + return false; + } + + async getMinimizeToTrayEnabled(): boolean { + return false; + } + + async setMinimizeToTrayEnabled(enabled: boolean): void { + throw new Error("Unimplemented"); + } } 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/ContentMessages.js b/src/ContentMessages.js index e4c62b5de1..6998973449 100644 --- a/src/ContentMessages.js +++ b/src/ContentMessages.js @@ -1,5 +1,6 @@ /* 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. @@ -17,18 +18,18 @@ limitations under the License. 'use strict'; import Promise from 'bluebird'; -const extend = require('./extend'); -const dis = require('./dispatcher'); -const MatrixClientPeg = require('./MatrixClientPeg'); -const sdk = require('./index'); +import extend from './extend'; +import dis from './dispatcher'; +import MatrixClientPeg from './MatrixClientPeg'; +import sdk from './index'; import { _t } from './languageHandler'; -const Modal = require('./Modal'); - -const encrypt = require("browser-encrypt-attachment"); -const png_chunks_extract = require("png-chunks-extract"); +import Modal from './Modal'; +import RoomViewStore from './stores/RoomViewStore'; +import encrypt from "browser-encrypt-attachment"; +import png_chunks_extract = from "png-chunks-extract"; // Polyfill for Canvas.toBlob API using Canvas.toDataURL -require("blueimp-canvas-to-blob"); +import "blueimp-canvas-to-blob"; const MAX_WIDTH = 800; const MAX_HEIGHT = 600; @@ -95,7 +96,7 @@ function createThumbnail(element, inputWidth, inputHeight, mimeType) { /** * Load a file into a newly created image element. * - * @param {File} file The file to load in an image element. + * @param {File} imageFile The file to load in an image element. * @return {Promise} A promise that resolves with the html image element. */ function loadImageElement(imageFile) { @@ -147,7 +148,7 @@ function loadImageElement(imageFile) { * * @param {MatrixClient} matrixClient A matrixClient to upload the thumbnail with. * @param {String} roomId The ID of the room the image will be uploaded in. - * @param {File} The image to read and thumbnail. + * @param {File} imageFile The image to read and thumbnail. * @return {Promise} A promise that resolves with the attachment info. */ function infoForImageFile(matrixClient, roomId, imageFile) { @@ -172,7 +173,7 @@ function infoForImageFile(matrixClient, roomId, imageFile) { /** * Load a file into a newly created video element. * - * @param {File} file The file to load in an video element. + * @param {File} videoFile The file to load in an video element. * @return {Promise} A promise that resolves with the video image element. */ function loadVideoElement(videoFile) { @@ -207,7 +208,7 @@ function loadVideoElement(videoFile) { * * @param {MatrixClient} matrixClient A matrixClient to upload the thumbnail with. * @param {String} roomId The ID of the room the video will be uploaded to. - * @param {File} The video to read and thumbnail. + * @param {File} videoFile The video to read and thumbnail. * @return {Promise} A promise that resolves with the attachment info. */ function infoForVideoFile(matrixClient, roomId, videoFile) { @@ -228,6 +229,7 @@ function infoForVideoFile(matrixClient, roomId, videoFile) { /** * Read the file as an ArrayBuffer. + * @param {File} file The file to read * @return {Promise} A promise that resolves with an ArrayBuffer when the file * is read. */ @@ -297,11 +299,43 @@ function uploadFile(matrixClient, roomId, file, progressHandler) { } } - -class ContentMessages { +export default class ContentMessages { constructor() { this.inprogress = []; this.nextId = 0; + this._mediaConfig = null; + } + + static sharedInstance() { + if (global.mx_ContentMessages === undefined) { + global.mx_ContentMessages = new ContentMessages(); + } + return global.mx_ContentMessages; + } + + _isFileSizeAcceptable(file) { + if (this._mediaConfig !== null && + this._mediaConfig["m.upload.size"] !== undefined && + file.size > this._mediaConfig["m.upload.size"]) { + return false; + } + return true; + } + + _ensureMediaConfigFetched() { + if (this._mediaConfig !== null) return; + + console.log("[Media Config] Fetching"); + return MatrixClientPeg.get().getMediaConfig().then((config) => { + console.log("[Media Config] Fetched config:", config); + return config; + }).catch(() => { + // Media repo can't or won't report limits, so provide an empty object (no limits). + console.log("[Media Config] Could not fetch config, so not limiting uploads."); + return {}; + }).then((config) => { + this._mediaConfig = config; + }); } sendStickerContentToRoom(url, roomId, info, text, matrixClient) { @@ -311,7 +345,90 @@ class ContentMessages { }); } - sendContentToRoom(file, roomId, matrixClient) { + getUploadLimit() { + if (this._mediaConfig !== null && this._mediaConfig["m.upload.size"] !== undefined) { + return this._mediaConfig["m.upload.size"]; + } else { + return null; + } + } + + async sendContentListToRoom(files, roomId, matrixClient) { + if (matrixClient.isGuest()) { + dis.dispatch({action: 'require_registration'}); + return; + } + + const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); + if (isQuoting) { + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + const shouldUpload = await new Promise((resolve) => { + Modal.createTrackedDialog('Upload Reply Warning', '', QuestionDialog, { + title: _t('Replying With Files'), + description: ( +
{_t( + 'At this time it is not possible to reply with a file. ' + + 'Would you like to upload this file without replying?', + )}
+ ), + hasCancelButton: true, + button: _t("Continue"), + onFinished: (shouldUpload) => { + resolve(shouldUpload); + }, + }); + }); + if (!shouldUpload) return; + } + + await this._ensureMediaConfigFetched(); + + const tooBigFiles = []; + const okFiles = []; + + for (let i = 0; i < files.length; ++i) { + if (this._isFileSizeAcceptable(files[i])) { + okFiles.push(files[i]); + } else { + tooBigFiles.push(files[i]); + } + } + + if (tooBigFiles.length > 0) { + const UploadFailureDialog = sdk.getComponent("dialogs.UploadFailureDialog"); + const uploadFailureDialogPromise = new Promise((resolve) => { + Modal.createTrackedDialog('Upload Failure', '', UploadFailureDialog, { + badFiles: tooBigFiles, + totalFiles: files.length, + contentMessages: this, + onFinished: (shouldContinue) => { + resolve(shouldContinue); + }, + }); + }); + const shouldContinue = await uploadFailureDialogPromise; + if (!shouldContinue) return; + } + + const UploadConfirmDialog = sdk.getComponent("dialogs.UploadConfirmDialog"); + for (let i = 0; i < okFiles.length; ++i) { + const file = okFiles[i]; + const shouldContinue = await new Promise((resolve) => { + Modal.createTrackedDialog('Upload Files confirmation', '', UploadConfirmDialog, { + file, + currentIndex: i, + totalFiles: okFiles.length, + onFinished: (shouldContinue) => { + resolve(shouldContinue); + }, + }); + }); + if (!shouldContinue) break; + this._sendContentToRoom(file, roomId, matrixClient); + } + } + + _sendContentToRoom(file, roomId, matrixClient) { const content = { body: file.name || 'Attachment', info: { @@ -385,9 +502,12 @@ class ContentMessages { }, function(err) { error = err; if (!upload.canceled) { - let desc = _t('The file \'%(fileName)s\' failed to upload', {fileName: upload.fileName}) + '.'; + let desc = _t("The file '%(fileName)s' failed to upload.", {fileName: upload.fileName}); if (err.http_status == 413) { - desc = _t('The file \'%(fileName)s\' exceeds this home server\'s size limit for uploads', {fileName: upload.fileName}); + desc = _t( + "The file '%(fileName)s' exceeds this homeserver's size limit for uploads", + {fileName: upload.fileName}, + ); } const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Upload failed', '', ErrorDialog, { @@ -405,9 +525,16 @@ class ContentMessages { } } if (error) { + // 413: File was too big or upset the server in some way: + // clear the media size limit so we fetch it again next time + // we try to upload + if (error && error.http_status === 413) { + this._mediaConfig = null; + } dis.dispatch({action: 'upload_failed', upload, error}); } else { dis.dispatch({action: 'upload_finished', upload}); + dis.dispatch({action: 'message_sent'}); } }); } @@ -432,9 +559,3 @@ class ContentMessages { } } } - -if (global.mx_ContentMessage === undefined) { - global.mx_ContentMessage = new ContentMessages(); -} - -module.exports = global.mx_ContentMessage; diff --git a/src/FromWidgetPostMessageApi.js b/src/FromWidgetPostMessageApi.js index ea7eeba756..4dd3ea6e6d 100644 --- a/src/FromWidgetPostMessageApi.js +++ b/src/FromWidgetPostMessageApi.js @@ -1,5 +1,6 @@ /* Copyright 2018 New Vector Ltd +Copyright 2019 Travis Ralston Licensed under the Apache License, Version 2.0 (the 'License'); you may not use this file except in compliance with the License. @@ -20,17 +21,19 @@ import IntegrationManager from './IntegrationManager'; import WidgetMessagingEndpoint from './WidgetMessagingEndpoint'; import ActiveWidgetStore from './stores/ActiveWidgetStore'; -const WIDGET_API_VERSION = '0.0.1'; // Current API version +const WIDGET_API_VERSION = '0.0.2'; // Current API version const SUPPORTED_WIDGET_API_VERSIONS = [ '0.0.1', + '0.0.2', ]; const INBOUND_API_NAME = 'fromWidget'; -// Listen for and handle incomming requests using the 'fromWidget' postMessage +// Listen for and handle incoming requests using the 'fromWidget' postMessage // API and initiate responses export default class FromWidgetPostMessageApi { constructor() { this.widgetMessagingEndpoints = []; + this.widgetListeners = {}; // {action: func[]} this.start = this.start.bind(this); this.stop = this.stop.bind(this); @@ -45,6 +48,32 @@ export default class FromWidgetPostMessageApi { window.removeEventListener('message', this.onPostMessage); } + /** + * Adds a listener for a given action + * @param {string} action The action to listen for. + * @param {Function} callbackFn A callback function to be called when the action is + * encountered. Called with two parameters: the interesting request information and + * the raw event received from the postMessage API. The raw event is meant to be used + * for sendResponse and similar functions. + */ + addListener(action, callbackFn) { + if (!this.widgetListeners[action]) this.widgetListeners[action] = []; + this.widgetListeners[action].push(callbackFn); + } + + /** + * Removes a listener for a given action. + * @param {string} action The action that was subscribed to. + * @param {Function} callbackFn The original callback function that was used to subscribe + * to updates. + */ + removeListener(action, callbackFn) { + if (!this.widgetListeners[action]) return; + + const idx = this.widgetListeners[action].indexOf(callbackFn); + if (idx !== -1) this.widgetListeners[action].splice(idx, 1); + } + /** * Register a widget endpoint for trusted postMessage communication * @param {string} widgetId Unique widget identifier @@ -117,6 +146,13 @@ export default class FromWidgetPostMessageApi { return; // don't log this - debugging APIs like to spam postMessage which floods the log otherwise } + // Call any listeners we have registered + if (this.widgetListeners[event.data.action]) { + for (const fn of this.widgetListeners[event.data.action]) { + fn(event.data, event); + } + } + // Although the requestId is required, we don't use it. We'll be nice and process the message // if the property is missing, but with a warning for widget developers. if (!event.data.requestId) { @@ -164,6 +200,8 @@ export default class FromWidgetPostMessageApi { if (ActiveWidgetStore.widgetHasCapability(widgetId, 'm.always_on_screen')) { ActiveWidgetStore.setWidgetPersistence(widgetId, val); } + } else if (action === 'get_openid') { + // Handled by caller } else { console.warn('Widget postMessage event unhandled'); this.sendError(event, {message: 'The postMessage was unhandled'}); diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index e72c0bfe4b..3315e86e71 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -19,16 +19,21 @@ limitations under the License. import ReplyThread from "./components/views/elements/ReplyThread"; -const React = require('react'); -const sanitizeHtml = require('sanitize-html'); -const highlight = require('highlight.js'); -const linkifyMatrix = require('./linkify-matrix'); +import React from 'react'; +import sanitizeHtml from 'sanitize-html'; +import highlight from 'highlight.js'; +import * as linkify from 'linkifyjs'; +import linkifyMatrix from './linkify-matrix'; +import _linkifyElement from 'linkifyjs/element'; +import _linkifyString from 'linkifyjs/string'; import escape from 'lodash/escape'; import emojione from 'emojione'; import classNames from 'classnames'; import MatrixClientPeg from './MatrixClientPeg'; import url from 'url'; +linkifyMatrix(linkify); + emojione.imagePathSVG = 'emojione/svg/'; // Store PNG path for displaying many flags at once (for increased performance over SVG) emojione.imagePathPNG = 'emojione/png/'; @@ -43,6 +48,12 @@ const SURROGATE_PAIR_PATTERN = /([\ud800-\udbff])([\udc00-\udfff])/; // (with plenty of false positives, but that's OK) const SYMBOL_PATTERN = /([\u2100-\u2bff])/; +// Regex pattern for Zero-Width joiner unicode characters +const ZWJ_REGEX = new RegExp("\u200D|\u2003", "g"); + +// Regex pattern for whitespace characters +const WHITESPACE_REGEX = new RegExp("\\s", "g"); + // And this is emojione's complete regex const EMOJI_REGEX = new RegExp(emojione.unicodeRegexp+"+", "gi"); const COLOR_REGEX = /^#[0-9a-fA-F]{6}$/; @@ -63,8 +74,10 @@ export function containsEmoji(str) { /* modified from https://github.com/Ranks/emojione/blob/master/lib/js/emojione.js * because we want to include emoji shortnames in title text */ -function unicodeToImage(str) { - let replaceWith; let unicode; let alt; let short; let fname; +function unicodeToImage(str, addAlt) { + if (addAlt === undefined) addAlt = true; + + let replaceWith; let unicode; let short; let fname; const mappedUnicode = emojione.mapUnicodeToShort(); str = str.replace(emojione.regUnicode, function(unicodeChar) { @@ -79,10 +92,14 @@ function unicodeToImage(str) { fname = emojione.emojioneList[short].fname; // depending on the settings, we'll either add the native unicode as the alt tag, otherwise the shortname - alt = (emojione.unicodeAlt) ? emojione.convert(unicode.toUpperCase()) : mappedUnicode[unicode]; const title = mappedUnicode[unicode]; - replaceWith = `${alt}`; + if (addAlt) { + const alt = (emojione.unicodeAlt) ? emojione.convert(unicode.toUpperCase()) : mappedUnicode[unicode]; + replaceWith = `${alt}`; + } else { + replaceWith = ``; + } return replaceWith; } }); @@ -220,7 +237,7 @@ const transformTags = { // custom to matrix 'code': function(tagName, attribs) { if (typeof attribs.class !== 'undefined') { // Filter out all classes other than ones starting with language- for syntax highlighting. - const classes = attribs.class.split(/\s+/).filter(function(cl) { + const classes = attribs.class.split(/\s/).filter(function(cl) { return cl.startsWith('language-'); }); attribs.class = classes.join(' '); @@ -487,7 +504,17 @@ export function bodyToHtml(content, highlights, opts={}) { let emojiBody = false; if (!opts.disableBigEmoji && bodyHasEmoji) { EMOJI_REGEX.lastIndex = 0; - const contentBodyTrimmed = strippedBody !== undefined ? strippedBody.trim() : ''; + let contentBodyTrimmed = strippedBody !== undefined ? strippedBody.trim() : ''; + + // Ignore spaces in body text. Emojis with spaces in between should + // still be counted as purely emoji messages. + contentBodyTrimmed = contentBodyTrimmed.replace(WHITESPACE_REGEX, ''); + + // Remove zero width joiner characters from emoji messages. This ensures + // that emojis that are made up of multiple unicode characters are still + // presented as large. + contentBodyTrimmed = contentBodyTrimmed.replace(ZWJ_REGEX, ''); + const match = EMOJI_REGEX.exec(contentBodyTrimmed); emojiBody = match && match[0] && match[0].length === contentBodyTrimmed.length; } @@ -503,8 +530,39 @@ export function bodyToHtml(content, highlights, opts={}) { { strippedBody }; } -export function emojifyText(text) { +export function emojifyText(text, addAlt) { return { - __html: unicodeToImage(escape(text)), + __html: unicodeToImage(escape(text), addAlt), }; } + +/** + * Linkifies the given string. This is a wrapper around 'linkifyjs/string'. + * + * @param {string} str + * @returns {string} + */ +export function linkifyString(str) { + return _linkifyString(str); +} + +/** + * Linkifies the given DOM element. This is a wrapper around 'linkifyjs/element'. + * + * @param {object} element DOM element to linkify + * @param {object} [options] Options for linkifyElement. Default: linkifyMatrix.options + * @returns {object} + */ +export function linkifyElement(element, options = linkifyMatrix.options) { + return _linkifyElement(element, options); +} + +/** + * Linkify the given string and sanitize the HTML afterwards. + * + * @param {string} dirtyHtml The HTML string to sanitize and linkify + * @returns {string} + */ +export function linkifyAndSanitizeHtml(dirtyHtml) { + return sanitizeHtml(linkifyString(dirtyHtml), sanitizeHtmlParams); +} diff --git a/src/IntegrationManager.js b/src/IntegrationManager.js index eb45a1f425..165ee6390d 100644 --- a/src/IntegrationManager.js +++ b/src/IntegrationManager.js @@ -51,6 +51,11 @@ export default class IntegrationManager { */ static async open(integName, integId, onFinished) { await IntegrationManager._init(); + if (global.mxIntegrationManager.client) { + await global.mxIntegrationManager.client.connect(); + } else { + return; + } const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager"); if (global.mxIntegrationManager.error || !(global.mxIntegrationManager.client && global.mxIntegrationManager.client.hasCredentials())) { diff --git a/src/Lifecycle.js b/src/Lifecycle.js index ed057eb020..f65dffa006 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -27,12 +27,12 @@ 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'; import PlatformPeg from "./PlatformPeg"; -import {sendLoginRequest} from "./Login"; +import { sendLoginRequest } from "./Login"; +import * as StorageManager from './utils/StorageManager'; /** * Called at startup, to attempt to build a logged-in Matrix session. It tries @@ -103,13 +103,29 @@ export async function loadSession(opts) { return _registerAsGuest(guestHsUrl, guestIsUrl, defaultDeviceDisplayName); } - // fall back to login screen + // fall back to welcome screen return false; } catch (e) { + if (e instanceof AbortLoginAndRebuildStorage) { + // If we're aborting login because of a storage inconsistency, we don't + // need to show the general failure dialog. Instead, just go back to welcome. + return false; + } return _handleLoadSessionFailure(e); } } +/** + * Gets the user ID of the persisted session, if one exists. This does not validate + * that the user's credentials still work, just that they exist and that a user ID + * is associated with them. The session is not loaded. + * @returns {String} The persisted session's owner, if an owner exists. Null otherwise. + */ +export function getStoredSessionOwner() { + const {hsUrl, userId, accessToken} = _getLocalStorageSessionVars(); + return hsUrl && userId && accessToken ? userId : null; +} + /** * @param {Object} queryParams string->string map of the * query-parameters extracted from the real query-string of the starting @@ -215,6 +231,16 @@ function _registerAsGuest(hsUrl, isUrl, defaultDeviceDisplayName) { }); } +function _getLocalStorageSessionVars() { + const hsUrl = localStorage.getItem("mx_hs_url"); + const isUrl = localStorage.getItem("mx_is_url") || 'https://matrix.org'; + const accessToken = localStorage.getItem("mx_access_token"); + const userId = localStorage.getItem("mx_user_id"); + const deviceId = localStorage.getItem("mx_device_id"); + + return {hsUrl, isUrl, accessToken, userId, deviceId}; +} + // returns a promise which resolves to true if a session is found in // localstorage // @@ -224,16 +250,13 @@ 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; } - const hsUrl = localStorage.getItem("mx_hs_url"); - const isUrl = localStorage.getItem("mx_is_url") || 'https://matrix.org'; - const accessToken = localStorage.getItem("mx_access_token"); - const userId = localStorage.getItem("mx_user_id"); - const deviceId = localStorage.getItem("mx_device_id"); + + const {hsUrl, isUrl, accessToken, userId, deviceId} = _getLocalStorageSessionVars(); let isGuest; if (localStorage.getItem("mx_is_guest") !== null) { @@ -261,7 +284,7 @@ async function _restoreFromLocalStorage() { } function _handleLoadSessionFailure(e) { - console.log("Unable to load session", e); + console.error("Unable to load session", e); const def = Promise.defer(); const SessionRestoreErrorDialog = @@ -286,15 +309,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 +347,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. // @@ -345,12 +359,24 @@ async function _doSetLoggedIn(credentials, clearStorage) { await _clearStorage(); } + const results = await StorageManager.checkConsistency(); + // If there's an inconsistency between account data in local storage and the + // crypto store, we'll be generally confused when handling encrypted data. + // Show a modal recommending a full reset of storage. + if (results.dataInLocalStorage && !results.dataInCryptoStore) { + const signOut = await _showStorageEvictedDialog(); + if (signOut) { + await _clearStorage(); + // This error feels a bit clunky, but we want to make sure we don't go any + // further and instead head back to sign in. + throw new AbortLoginAndRebuildStorage( + "Aborting login in progress because of storage inconsistency", + ); + } + } + Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl, credentials.identityServerUrl); - // Resolves by default - let teamPromise = Promise.resolve(null); - - if (localStorage) { try { _persistCredentialsToLocalStorage(credentials); @@ -367,32 +393,31 @@ 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(); } +function _showStorageEvictedDialog() { + const StorageEvictedDialog = sdk.getComponent('views.dialogs.StorageEvictedDialog'); + return new Promise(resolve => { + Modal.createTrackedDialog('Storage evicted', '', StorageEvictedDialog, { + onFinished: resolve, + }); + }); +} + +// Note: Babel 6 requires the `transform-builtin-extend` plugin for this to satisfy +// `instanceof`. Babel 7 supports this natively in their class handling. +class AbortLoginAndRebuildStorage extends Error { } + function _persistCredentialsToLocalStorage(credentials) { localStorage.setItem("mx_hs_url", credentials.homeserverUrl); localStorage.setItem("mx_is_url", credentials.identityServerUrl); @@ -467,7 +492,7 @@ async function startMatrixClient() { dis.dispatch({action: 'will_start_client'}, true); Notifier.start(); - UserActivity.start(); + UserActivity.sharedInstance().start(); Presence.start(); DMRoomMap.makeShared().start(); ActiveWidgetStore.start(); @@ -513,7 +538,7 @@ function _clearStorage() { */ export function stopMatrixClient() { Notifier.stop(); - UserActivity.stop(); + UserActivity.sharedInstance().stop(); Presence.stop(); ActiveWidgetStore.stop(); if (DMRoomMap.shared()) DMRoomMap.shared().stop(); 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..94a016d207 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -29,6 +29,8 @@ 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'; +import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler"; interface MatrixClientCreds { homeserverUrl: string, @@ -84,7 +86,7 @@ class MatrixClientPeg { /** * Replace this MatrixClientPeg's client with a client instance that has - * Home Server / Identity Server URLs and active credentials + * homeserver / identity server URLs and active credentials */ replaceUsingCreds(creds: MatrixClientCreds) { this._currentClientCreds = creds; @@ -101,7 +103,7 @@ class MatrixClientPeg { } catch (err) { if (dbType === 'indexeddb') { console.error('Error starting matrixclient store - falling back to memory store', err); - this.matrixClient.store = new Matrix.MatrixInMemoryStore({ + this.matrixClient.store = new Matrix.MemoryStore({ localStorage: global.localStorage, }); } else { @@ -118,7 +120,7 @@ class MatrixClientPeg { await this.matrixClient.initCrypto(); } } catch (e) { - if (e.name === 'InvalidCryptoStoreError') { + if (e && e.name === 'InvalidCryptoStoreError') { // The js-sdk found a crypto DB too new for it to use const CryptoStoreTooNewDialog = sdk.getComponent("views.dialogs.CryptoStoreTooNewDialog"); @@ -128,23 +130,17 @@ class MatrixClientPeg { } // this can happen for a number of reasons, the most likely being // that the olm library was missing. It's not fatal. - console.warn("Unable to initialise e2e: " + e); + console.warn("Unable to initialise e2e", e); } const opts = utils.deepCopy(this.opts); // the react sdk doesn't work without this, so don't allow opts.pendingEventOrdering = "detached"; + opts.lazyLoadMembers = true; - const LAZY_LOADING_FEATURE = "feature_lazyloading"; - if (SettingsStore.isFeatureEnabled(LAZY_LOADING_FEATURE)) { - const userId = this.matrixClient.credentials.userId; - if (phasedRollOutExpiredForUser(userId, LAZY_LOADING_FEATURE, Date.now())) { - opts.lazyLoadMembers = true; - } - } - - // Connect the matrix client to the dispatcher + // Connect the matrix client to the dispatcher and setting handlers MatrixActionCreators.start(this.matrixClient); + MatrixClientBackedSettingsHandler.matrixClient = this.matrixClient; console.log(`MatrixClientPeg: really starting MatrixClient`); await this.get().startClient(opts); @@ -163,19 +159,19 @@ class MatrixClientPeg { } /** - * Return the server name of the user's home server - * Throws an error if unable to deduce the home server name + * Return the server name of the user's homeserver + * Throws an error if unable to deduce the homeserver name * (eg. if the user is not logged in) */ getHomeServerName() { const matches = /^@.+:(.+)$/.exec(this.matrixClient.credentials.userId); if (matches === null || matches.length < 1) { - throw new Error("Failed to derive home server name from user ID!"); + throw new Error("Failed to derive homeserver name from user ID!"); } return matches[1]; } - _createClient(creds: MatrixClientCreds, useIndexedDb) { + _createClient(creds: MatrixClientCreds) { const opts = { baseUrl: creds.homeserverUrl, idBaseUrl: creds.identityServerUrl, @@ -183,10 +179,11 @@ class MatrixClientPeg { userId: creds.userId, deviceId: creds.deviceId, timelineSupport: true, - forceTURN: SettingsStore.getValue('webRtcForceTURN', false), + forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer', false), + verificationMethods: [verificationMethods.SAS] }; - this.matrixClient = createMatrixClient(opts, useIndexedDb); + this.matrixClient = createMatrixClient(opts); // we're going to add eventlisteners for each matrix event tile, so the // potential number of event listeners is quite high. diff --git a/src/Modal.js b/src/Modal.js index 960e0e5c30..96dbd49324 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -26,6 +26,7 @@ import dis from './dispatcher'; import { _t } from './languageHandler'; const DIALOG_CONTAINER_ID = "mx_Dialog_Container"; +const STATIC_DIALOG_CONTAINER_ID = "mx_Dialog_StaticContainer"; /** * Wrap an asynchronous loader function with a react component which shows a @@ -106,7 +107,12 @@ class ModalManager { // this modal. Remove all other modals from the stack when this modal // is closed. this._priorityModal = null; + // The modal to keep open underneath other modals if possible. Useful + // for cases like Settings where the modal should remain open while the + // user is prompted for more information/errors. + this._staticModal = null; // A list of the modals we have stacked up, with the most recent at [0] + // Neither the static nor priority modal will be in this list. this._modals = [ /* { elem: React component for this dialog @@ -118,6 +124,10 @@ class ModalManager { this.closeAll = this.closeAll.bind(this); } + hasDialogs() { + return this._priorityModal || this._staticModal || this._modals.length > 0; + } + getOrCreateContainer() { let container = document.getElementById(DIALOG_CONTAINER_ID); @@ -130,6 +140,18 @@ class ModalManager { return container; } + getOrCreateStaticContainer() { + let container = document.getElementById(STATIC_DIALOG_CONTAINER_ID); + + if (!container) { + container = document.createElement("div"); + container.id = STATIC_DIALOG_CONTAINER_ID; + document.body.appendChild(container); + } + + return container; + } + createTrackedDialog(analyticsAction, analyticsInfo, ...rest) { Analytics.trackEvent('Modal', analyticsAction, analyticsInfo); return this.createDialog(...rest); @@ -166,8 +188,13 @@ class ModalManager { * of other modals that are currently in the stack. * Also, when closed, all modals will be removed * from the stack. + * @param {boolean} isStaticModal if true, this modal will be displayed under other + * modals in the stack. When closed, all modals will + * also be removed from the stack. This is not compatible + * with being a priority modal. Only one modal can be + * static at a time. */ - createDialogAsync(prom, props, className, isPriorityModal) { + createDialogAsync(prom, props, className, isPriorityModal, isStaticModal) { const self = this; const modal = {}; @@ -188,6 +215,13 @@ class ModalManager { self._modals = []; } + if (self._staticModal === modal) { + self._staticModal = null; + + // XXX: This is destructive + self._modals = []; + } + self._reRender(); }; @@ -207,6 +241,9 @@ class ModalManager { if (isPriorityModal) { // XXX: This is destructive this._priorityModal = modal; + } else if (isStaticModal) { + // This is intentionally destructive + this._staticModal = modal; } else { this._modals.unshift(modal); } @@ -216,12 +253,18 @@ class ModalManager { } closeAll() { - const modals = this._modals; + const modalsToClose = [...this._modals, this._priorityModal]; this._modals = []; + this._priorityModal = null; - for (let i = 0; i < modals.length; i++) { - const m = modals[i]; - if (m.onFinished) { + if (this._staticModal && modalsToClose.length === 0) { + modalsToClose.push(this._staticModal); + this._staticModal = null; + } + + for (let i = 0; i < modalsToClose.length; i++) { + const m = modalsToClose[i]; + if (m && m.onFinished) { m.onFinished(false); } } @@ -230,13 +273,14 @@ class ModalManager { } _reRender() { - if (this._modals.length == 0 && !this._priorityModal) { + if (this._modals.length === 0 && !this._priorityModal && !this._staticModal) { // If there is no modal to render, make all of Riot available // to screen reader users again dis.dispatch({ action: 'aria_unhide_main_app', }); ReactDOM.unmountComponentAtNode(this.getOrCreateContainer()); + ReactDOM.unmountComponentAtNode(this.getOrCreateStaticContainer()); return; } @@ -247,17 +291,45 @@ class ModalManager { action: 'aria_hide_main_app', }); - const modal = this._priorityModal ? this._priorityModal : this._modals[0]; - const dialog = ( -
-
- { modal.elem } -
-
-
- ); + if (this._staticModal) { + const classes = "mx_Dialog_wrapper mx_Dialog_staticWrapper " + + (this._staticModal.className ? this._staticModal.className : ''); - ReactDOM.render(dialog, this.getOrCreateContainer()); + const staticDialog = ( +
+
+ { this._staticModal.elem } +
+
+
+ ); + + ReactDOM.render(staticDialog, this.getOrCreateStaticContainer()); + } else { + // This is safe to call repeatedly if we happen to do that + ReactDOM.unmountComponentAtNode(this.getOrCreateStaticContainer()); + } + + const modal = this._priorityModal ? this._priorityModal : this._modals[0]; + if (modal) { + const classes = "mx_Dialog_wrapper " + + (this._staticModal ? "mx_Dialog_wrapperWithStaticUnder " : '') + + (modal.className ? modal.className : ''); + + const dialog = ( +
+
+ {modal.elem} +
+
+
+ ); + + ReactDOM.render(dialog, this.getOrCreateContainer()); + } else { + // This is safe to call repeatedly if we happen to do that + ReactDOM.unmountComponentAtNode(this.getOrCreateContainer()); + } } } diff --git a/src/Notifier.js b/src/Notifier.js index 80e8be1084..6a4f9827f7 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -220,7 +220,17 @@ const Notifier = { } }, - isToolbarHidden: function() { + shouldShowToolbar: function() { + const client = MatrixClientPeg.get(); + if (!client) { + return false; + } + const isGuest = client.isGuest(); + return !isGuest && this.supportsDesktopNotifications() && + !this.isEnabled() && !this._isToolbarHidden(); + }, + + _isToolbarHidden: function() { // Check localStorage for any such meta data if (global.localStorage) { return global.localStorage.getItem("notifications_hidden") === "true"; diff --git a/src/PageTypes.js b/src/PageTypes.js index e4e1916c8b..09e0eadbd7 100644 --- a/src/PageTypes.js +++ b/src/PageTypes.js @@ -19,8 +19,6 @@ limitations under the License. export default { HomePage: "home_page", RoomView: "room_view", - GroupGridView: "group_grid_view", - UserSettings: "user_settings", RoomDirectory: "room_directory", UserView: "user_view", GroupView: "group_view", diff --git a/src/Presence.js b/src/Presence.js index 849efdef1c..8e00e95cdf 100644 --- a/src/Presence.js +++ b/src/Presence.js @@ -33,7 +33,7 @@ class Presence { } /** * Start listening the user activity to evaluate his presence state. - * Any state change will be sent to the Home Server. + * Any state change will be sent to the homeserver. */ async start() { this._unavailableTimer = new Timer(UNAVAILABLE_TIME_MS); @@ -78,7 +78,7 @@ class Presence { /** * Set the presence state. - * If the state has changed, the Home Server will be notified. + * If the state has changed, the homeserver will be notified. * @param {string} newState the new presence state (see PRESENCE enum) */ async setState(newState) { diff --git a/src/Registration.js b/src/Registration.js index 98aee3ac83..42e172ca0b 100644 --- a/src/Registration.js +++ b/src/Registration.js @@ -22,9 +22,9 @@ limitations under the License. import dis from './dispatcher'; import sdk from './index'; -import MatrixClientPeg from './MatrixClientPeg'; import Modal from './Modal'; import { _t } from './languageHandler'; +// import MatrixClientPeg from './MatrixClientPeg'; // Regex for what a "safe" or "Matrix-looking" localpart would be. // TODO: Update as needed for https://github.com/matrix-org/matrix-doc/issues/1514 @@ -35,30 +35,36 @@ export const SAFE_LOCALPART_REGEX = /^[a-z0-9=_\-./]+$/; * on what the HS supports * * @param {object} options - * @param {bool} options.go_home_on_cancel If true, goes to - * the hame page if the user cancels the action + * @param {bool} options.go_home_on_cancel + * If true, goes to the home page if the user cancels the action + * @param {bool} options.go_welcome_on_cancel + * If true, goes to the welcome page if the user cancels the action */ export async function startAnyRegistrationFlow(options) { if (options === undefined) options = {}; - const flows = await _getRegistrationFlows(); // look for an ILAG compatible flow. We define this as one // which has only dummy or recaptcha flows. In practice it // would support any stage InteractiveAuth supports, just not // ones like email & msisdn which require the user to supply // the relevant details in advance. We err on the side of // caution though. - const hasIlagFlow = flows.some((flow) => { - return flow.stages.every((stage) => { - return ['m.login.dummy', 'm.login.recaptcha', 'm.login.terms'].includes(stage); - }); - }); - if (hasIlagFlow) { - dis.dispatch({ - action: 'view_set_mxid', - go_home_on_cancel: options.go_home_on_cancel, - }); - } else { + // XXX: ILAG is disabled for now, + // see https://github.com/vector-im/riot-web/issues/8222 + + // const flows = await _getRegistrationFlows(); + // const hasIlagFlow = flows.some((flow) => { + // return flow.stages.every((stage) => { + // return ['m.login.dummy', 'm.login.recaptcha', 'm.login.terms'].includes(stage); + // }); + // }); + + // if (hasIlagFlow) { + // dis.dispatch({ + // action: 'view_set_mxid', + // go_home_on_cancel: options.go_home_on_cancel, + // }); + //} else { const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); Modal.createTrackedDialog('Registration required', '', QuestionDialog, { title: _t("Registration Required"), @@ -69,28 +75,30 @@ export async function startAnyRegistrationFlow(options) { dis.dispatch({action: 'start_registration'}); } else if (options.go_home_on_cancel) { dis.dispatch({action: 'view_home_page'}); + } else if (options.go_welcome_on_cancel) { + dis.dispatch({action: 'view_welcome_page'}); } }, }); - } + //} } -async function _getRegistrationFlows() { - try { - await MatrixClientPeg.get().register( - null, - null, - undefined, - {}, - {}, - ); - console.log("Register request succeeded when it should have returned 401!"); - } catch (e) { - if (e.httpStatus === 401) { - return e.data.flows; - } - throw e; - } - throw new Error("Register request succeeded when it should have returned 401!"); -} +// async function _getRegistrationFlows() { +// try { +// await MatrixClientPeg.get().register( +// null, +// null, +// undefined, +// {}, +// {}, +// ); +// console.log("Register request succeeded when it should have returned 401!"); +// } catch (e) { +// if (e.httpStatus === 401) { +// return e.data.flows; +// } +// throw e; +// } +// throw new Error("Register request succeeded when it should have returned 401!"); +// } diff --git a/src/RoomInvite.js b/src/RoomInvite.js index 3547b9195f..b808b935a6 100644 --- a/src/RoomInvite.js +++ b/src/RoomInvite.js @@ -65,6 +65,24 @@ export function showRoomInviteDialog(roomId) { }); } +/** + * Checks if the given MatrixEvent is a valid 3rd party user invite. + * @param {MatrixEvent} event The event to check + * @returns {boolean} True if valid, false otherwise + */ +export function isValid3pidInvite(event) { + if (!event || event.getType() !== "m.room.third_party_invite") return false; + + // any events without these keys are not valid 3pid invites, so we ignore them + const requiredKeys = ['key_validity_url', 'public_key', 'display_name']; + for (let i = 0; i < requiredKeys.length; ++i) { + if (!event.getContent()[requiredKeys[i]]) return false; + } + + // Valid enough by our standards + return true; +} + function _onStartChatFinished(shouldInvite, addrs) { if (!shouldInvite) return; diff --git a/src/RoomNotifs.js b/src/RoomNotifs.js index 91e49fe09b..77fb5efb76 100644 --- a/src/RoomNotifs.js +++ b/src/RoomNotifs.js @@ -23,6 +23,47 @@ export const ALL_MESSAGES = 'all_messages'; export const MENTIONS_ONLY = 'mentions_only'; export const MUTE = 'mute'; + +function _shouldShowNotifBadge(roomNotifState) { + const showBadgeInStates = [ALL_MESSAGES, ALL_MESSAGES_LOUD]; + return showBadgeInStates.indexOf(roomNotifState) > -1; +} + +function _shouldShowMentionBadge(roomNotifState) { + return roomNotifState !== MUTE; +} + +export function aggregateNotificationCount(rooms) { + return rooms.reduce((result, room, index) => { + const roomNotifState = getRoomNotifsState(room.roomId); + const highlight = room.getUnreadNotificationCount('highlight') > 0; + const notificationCount = room.getUnreadNotificationCount(); + + const notifBadges = notificationCount > 0 && _shouldShowNotifBadge(roomNotifState); + const mentionBadges = highlight && _shouldShowMentionBadge(roomNotifState); + const badges = notifBadges || mentionBadges; + + if (badges) { + result.count += notificationCount; + if (highlight) { + result.highlight = true; + } + } + return result; + }, {count: 0, highlight: false}); +} + +export function getRoomHasBadge(room) { + const roomNotifState = getRoomNotifsState(room.roomId); + const highlight = room.getUnreadNotificationCount('highlight') > 0; + const notificationCount = room.getUnreadNotificationCount(); + + const notifBadges = notificationCount > 0 && _shouldShowNotifBadge(roomNotifState); + const mentionBadges = highlight && _shouldShowMentionBadge(roomNotifState); + + return notifBadges || mentionBadges; +} + export function getRoomNotifsState(roomId) { if (MatrixClientPeg.get().isGuest()) return ALL_MESSAGES; diff --git a/src/Rooms.js b/src/Rooms.js index 6f73ea0659..c8f90ec39a 100644 --- a/src/Rooms.js +++ b/src/Rooms.js @@ -159,6 +159,10 @@ export function setDMRoom(roomId, userId) { /** * Given a room, estimate which of its members is likely to * be the target if the room were a DM room and return that user. + * + * @param {Object} room Target room + * @param {string} myUserId User ID of the current user + * @returns {string} User ID of the user that the room is probably a DM with */ function guessDMRoomTargetId(room, myUserId) { let oldestTs; @@ -173,7 +177,7 @@ function guessDMRoomTargetId(room, myUserId) { oldestTs = user.events.member.getTs(); } } - if (oldestUser) return oldestUser; + if (oldestUser) return oldestUser.userId; // if there are no joined members other than us, use the oldest member for (const user of room.currentState.getMembers()) { @@ -186,5 +190,5 @@ function guessDMRoomTargetId(room, myUserId) { } if (oldestUser === undefined) return myUserId; - return oldestUser; + return oldestUser.userId; } 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/ScalarAuthClient.js b/src/ScalarAuthClient.js index 0639e7ceae..24979aff65 100644 --- a/src/ScalarAuthClient.js +++ b/src/ScalarAuthClient.js @@ -21,6 +21,9 @@ const request = require('browser-request'); const SdkConfig = require('./SdkConfig'); const MatrixClientPeg = require('./MatrixClientPeg'); +// The version of the integration manager API we're intending to work with +const imApiVersion = "1.1"; + class ScalarAuthClient { constructor() { this.scalarToken = null; @@ -66,7 +69,7 @@ class ScalarAuthClient { request({ method: "GET", uri: url, - qs: {scalar_token: token}, + qs: {scalar_token: token, v: imApiVersion}, json: true, }, (err, response, body) => { if (err) { @@ -100,6 +103,7 @@ class ScalarAuthClient { request({ method: 'POST', uri: scalar_rest_url+'/register', + qs: {v: imApiVersion}, body: openid_token_object, json: true, }, (err, response, body) => { diff --git a/src/SdkConfig.js b/src/SdkConfig.js index 65982bd6f2..78dd050a1e 100644 --- a/src/SdkConfig.js +++ b/src/SdkConfig.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -const DEFAULTS = { +export const DEFAULTS = { // URL to a page we show in an iframe to configure integrations integrations_ui_url: "https://scalar.vector.im/", // Base URL to the REST interface of the integrations server diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 47c6c26b45..8db9c4400d 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -27,7 +27,9 @@ import SettingsStore, {SettingLevel} from './settings/SettingsStore'; import {MATRIXTO_URL_PATTERN} from "./linkify-matrix"; import * as querystring from "querystring"; import MultiInviter from './utils/MultiInviter'; - +import { linkifyAndSanitizeHtml } from './HtmlUtils'; +import QuestionDialog from "./components/views/dialogs/QuestionDialog"; +import WidgetUtils from "./utils/WidgetUtils"; class Command { constructor({name, args='', description, runFn, hideCompletionAfterSpace=false}) { @@ -70,6 +72,19 @@ function success(promise) { /* eslint-disable babel/no-invalid-this */ export const CommandMap = { + shrug: new Command({ + name: 'shrug', + args: '', + description: _td('Prepends ¯\\_(ツ)_/¯ to a plain-text message'), + runFn: function(roomId, args) { + let message = '¯\\_(ツ)_/¯'; + if (args) { + message = message + ' ' + args; + } + return success(MatrixClientPeg.get().sendTextMessage(roomId, message)); + }, + }), + ddg: new Command({ name: 'ddg', args: '', @@ -86,6 +101,83 @@ 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) { + const room = MatrixClientPeg.get().getRoom(roomId); + Modal.createTrackedDialog('Slash Commands', 'upgrade room confirmation', + QuestionDialog, { + title: _t('Room upgrade confirmation'), + description: ( +
+

{_t("Upgrading a room can be destructive and isn't always necessary.")}

+

+ {_t( + "Room upgrades are usually recommended when a room version is considered " + + "unstable. Unstable room versions might have bugs, missing features, or " + + "security vulnerabilities.", + {}, { + "i": (sub) => {sub}, + }, + )} +

+

+ {_t( + "Room upgrades usually only affect server-side processing of the " + + "room. If you're having problems with your Riot client, please file an issue " + + "with .", + {}, { + "i": (sub) => {sub}, + "issueLink": () => { + return + https://github.com/vector-im/riot-web/issues/new/choose + ; + }, + }, + )} +

+

+ {_t( + "Warning: Upgrading a room will not automatically migrate room " + + "members to the new version of the room. We'll post a link to the new room " + + "in the old version of the room - room members will have to click this link to " + + "join the new room.", + {}, { + "b": (sub) => {sub}, + "i": (sub) => {sub}, + }, + )} +

+

+ {_t( + "Please confirm that you'd like to go forward with upgrading this room " + + "from to ", + {}, + { + oldVersion: () => {room ? room.getVersion() : "1"}, + newVersion: () => {args}, + }, + )} +

+
+ ), + button: _t("Upgrade"), + onFinished: (confirm) => { + if (!confirm) return; + + MatrixClientPeg.get().upgradeRoom(roomId, args); + }, + }); + return success(); + } + return reject(this.getUsage()); + }, + }), + nick: new Command({ name: 'nick', args: '', @@ -98,6 +190,24 @@ export const CommandMap = { }, }), + roomnick: new Command({ + name: 'roomnick', + args: '', + description: _td('Changes your display nickname in the current room only'), + runFn: function(roomId, args) { + if (args) { + const cli = MatrixClientPeg.get(); + const ev = cli.getRoom(roomId).currentState.getStateEvents('m.room.member', cli.getUserId()); + const content = { + ...ev ? ev.getContent() : { membership: 'join' }, + displayname: args, + }; + return success(cli.sendStateEvent(roomId, 'm.room.member', content, cli.getUserId())); + } + return reject(this.getUsage()); + }, + }), + tint: new Command({ name: 'tint', args: ' []', @@ -125,13 +235,26 @@ export const CommandMap = { topic: new Command({ name: 'topic', - args: '', - description: _td('Sets the room topic'), + args: '[]', + description: _td('Gets or sets the room topic'), runFn: function(roomId, args) { + const cli = MatrixClientPeg.get(); if (args) { - return success(MatrixClientPeg.get().setRoomTopic(roomId, args)); + return success(cli.setRoomTopic(roomId, args)); } - return reject(this.getUsage()); + const room = cli.getRoom(roomId); + if (!room) return reject('Bad room ID: ' + roomId); + + const topicEvents = room.currentState.getStateEvents('m.room.topic', ''); + const topic = topicEvents && topicEvents.getContent().topic; + const topicHtml = topic ? linkifyAndSanitizeHtml(topic) : _t('This room has no topic.'); + + const InfoDialog = sdk.getComponent('dialogs.InfoDialog'); + Modal.createTrackedDialog('Slash Commands', 'Topic', InfoDialog, { + title: room.name, + description:
, + }); + return success(); }, }), @@ -309,7 +432,7 @@ export const CommandMap = { if (!targetRoomId) targetRoomId = roomId; return success( - cli.leave(targetRoomId).then(function() { + cli.leaveRoomChain(targetRoomId).then(function() { dis.dispatch({action: 'view_next_room'}); }), ); @@ -379,13 +502,12 @@ export const CommandMap = { ignoredUsers.push(userId); // de-duped internally in the js-sdk return success( cli.setIgnoredUsers(ignoredUsers).then(() => { - const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); - Modal.createTrackedDialog('Slash Commands', 'User ignored', QuestionDialog, { + const InfoDialog = sdk.getComponent('dialogs.InfoDialog'); + Modal.createTrackedDialog('Slash Commands', 'User ignored', InfoDialog, { title: _t('Ignored user'), description:

{ _t('You are now ignoring %(userId)s', {userId}) }

, - hasCancelButton: false, }); }), ); @@ -411,13 +533,12 @@ export const CommandMap = { if (index !== -1) ignoredUsers.splice(index, 1); return success( cli.setIgnoredUsers(ignoredUsers).then(() => { - const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); - Modal.createTrackedDialog('Slash Commands', 'User unignored', QuestionDialog, { + const InfoDialog = sdk.getComponent('dialogs.InfoDialog'); + Modal.createTrackedDialog('Slash Commands', 'User unignored', InfoDialog, { title: _t('Unignored user'), description:

{ _t('You are no longer ignoring %(userId)s', {userId}) }

, - hasCancelButton: false, }); }), ); @@ -486,6 +607,26 @@ export const CommandMap = { }, }), + addwidget: new Command({ + name: 'addwidget', + args: '', + description: _td('Adds a custom widget by URL to the room'), + runFn: function(roomId, args) { + if (!args || (!args.startsWith("https://") && !args.startsWith("http://"))) { + return reject(_t("Please supply a https:// or http:// widget URL")); + } + if (WidgetUtils.canUserModifyWidgets(roomId)) { + const userId = MatrixClientPeg.get().getUserId(); + const nowMs = (new Date()).getTime(); + const widgetId = encodeURIComponent(`${roomId}_${userId}_${nowMs}`); + return success(WidgetUtils.setRoomWidget( + roomId, widgetId, "m.custom", args, "Custom Widget", {})); + } else { + return reject(_t("You cannot modify widgets in this room.")); + } + }, + }), + // Verify a user, device, and pubkey tuple verify: new Command({ name: 'verify', @@ -534,8 +675,8 @@ export const CommandMap = { return cli.setDeviceVerified(userId, deviceId, true); }).then(() => { // Tell the user we verified everything - const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); - Modal.createTrackedDialog('Slash Commands', 'Verified key', QuestionDialog, { + const InfoDialog = sdk.getComponent('dialogs.InfoDialog'); + Modal.createTrackedDialog('Slash Commands', 'Verified key', InfoDialog, { title: _t('Verified key'), description:

@@ -546,7 +687,6 @@ export const CommandMap = { }

, - hasCancelButton: false, }); }), ); diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 2a37295f83..a700fe2a3c 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -17,6 +17,7 @@ import MatrixClientPeg from './MatrixClientPeg'; import CallHandler from './CallHandler'; import { _t } from './languageHandler'; import * as Roles from './Roles'; +import {isValid3pidInvite} from "./RoomInvite"; function textForMemberEvent(ev) { // XXX: SYJS-16 "sender is sometimes null for join messages" @@ -134,6 +135,68 @@ function textForTombstoneEvent(ev) { return _t('%(senderDisplayName)s upgraded this room.', {senderDisplayName}); } +function textForJoinRulesEvent(ev) { + const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + switch (ev.getContent().join_rule) { + case "public": + return _t('%(senderDisplayName)s made the room public to whoever knows the link.', {senderDisplayName}); + case "invite": + return _t('%(senderDisplayName)s made the room invite only.', {senderDisplayName}); + default: + // The spec supports "knock" and "private", however nothing implements these. + return _t('%(senderDisplayName)s changed the join rule to %(rule)s', { + senderDisplayName, + rule: ev.getContent().join_rule, + }); + } +} + +function textForGuestAccessEvent(ev) { + const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + switch (ev.getContent().guest_access) { + case "can_join": + return _t('%(senderDisplayName)s has allowed guests to join the room.', {senderDisplayName}); + case "forbidden": + return _t('%(senderDisplayName)s has prevented guests from joining the room.', {senderDisplayName}); + default: + // There's no other options we can expect, however just for safety's sake we'll do this. + return _t('%(senderDisplayName)s changed guest access to %(rule)s', { + senderDisplayName, + rule: ev.getContent().guest_access, + }); + } +} + +function textForRelatedGroupsEvent(ev) { + const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + const groups = ev.getContent().groups || []; + const prevGroups = ev.getPrevContent().groups || []; + const added = groups.filter((g) => !prevGroups.includes(g)); + const removed = prevGroups.filter((g) => !groups.includes(g)); + + if (added.length && !removed.length) { + return _t('%(senderDisplayName)s enabled flair for %(groups)s in this room.', { + senderDisplayName, + groups: added.join(', '), + }); + } else if (!added.length && removed.length) { + return _t('%(senderDisplayName)s disabled flair for %(groups)s in this room.', { + senderDisplayName, + groups: removed.join(', '), + }); + } else if (added.length && removed.length) { + return _t('%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for ' + + '%(oldGroups)s in this room.', { + senderDisplayName, + newGroups: added.join(', '), + oldGroups: removed.join(', '), + }); + } else { + // Don't bother rendering this change (because there were no changes) + return ''; + } +} + function textForServerACLEvent(ev) { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); const prevContent = ev.getPrevContent(); @@ -304,6 +367,15 @@ function textForCallInviteEvent(event) { function textForThreePidInviteEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); + + if (!isValid3pidInvite(event)) { + const targetDisplayName = event.getPrevContent().display_name || _t("Someone"); + return _t('%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.', { + senderName, + targetDisplayName, + }); + } + return _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', { senderName, targetDisplayName: event.getContent().display_name, @@ -439,6 +511,9 @@ const stateHandlers = { 'm.room.pinned_events': textForPinnedEvent, 'm.room.server_acl': textForServerACLEvent, 'm.room.tombstone': textForTombstoneEvent, + 'm.room.join_rules': textForJoinRulesEvent, + 'm.room.guest_access': textForGuestAccessEvent, + 'm.room.related_groups': textForRelatedGroupsEvent, 'im.vector.modular.widgets': textForWidgetEvent, }; diff --git a/src/Unread.js b/src/Unread.js index 55e60f2a9a..9514ec821b 100644 --- a/src/Unread.js +++ b/src/Unread.js @@ -32,7 +32,7 @@ module.exports = { return false; } else if (ev.getType() == 'm.call.answer' || ev.getType() == 'm.call.hangup') { return false; - } else if (ev.getType == 'm.room.message' && ev.getContent().msgtype == 'm.notify') { + } else if (ev.getType() == 'm.room.message' && ev.getContent().msgtype == 'm.notify') { return false; } const EventTile = sdk.getComponent('rooms.EventTile'); diff --git a/src/UserActivity.js b/src/UserActivity.js index 145b23e36e..0d1b4d0cc0 100644 --- a/src/UserActivity.js +++ b/src/UserActivity.js @@ -1,5 +1,6 @@ /* 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. @@ -17,110 +18,173 @@ limitations under the License. import dis from './dispatcher'; import Timer from './utils/Timer'; -// 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; +// important these are larger than the timeouts of timers +// used with UserActivity.timeWhileActive*, +// such as READ_MARKER_INVIEW_THRESHOLD_MS (timeWhileActiveRecently), +// READ_MARKER_OUTOFVIEW_THRESHOLD_MS (timeWhileActiveRecently), +// READ_RECEIPT_INTERVAL_MS (timeWhileActiveNow) in TimelinePanel + +// 'Under a few seconds'. Must be less than 'RECENTLY_ACTIVE_THRESHOLD_MS' +const CURRENTLY_ACTIVE_THRESHOLD_MS = 700; + +// 'Under a few minutes'. +const RECENTLY_ACTIVE_THRESHOLD_MS = 2 * 60 * 1000; /** * This class watches for user activity (moving the mouse or pressing a key) * and starts/stops attached timers while the user is active. + * + * There are two classes of 'active': 'active now' and 'active recently' + * see doc on the userActive* functions for what these mean. */ -class UserActivity { - constructor() { - this._attachedTimers = []; - this._activityTimeout = new Timer(CURRENTLY_ACTIVE_THRESHOLD_MS); +export default class UserActivity { + constructor(windowObj, documentObj) { + this._window = windowObj; + this._document = documentObj; + + this._attachedActiveNowTimers = []; + this._attachedActiveRecentlyTimers = []; + this._activeNowTimeout = new Timer(CURRENTLY_ACTIVE_THRESHOLD_MS); + this._activeRecentlyTimeout = new Timer(RECENTLY_ACTIVE_THRESHOLD_MS); this._onUserActivity = this._onUserActivity.bind(this); - this._onDocumentBlurred = this._onDocumentBlurred.bind(this); + this._onWindowBlurred = this._onWindowBlurred.bind(this); this._onPageVisibilityChanged = this._onPageVisibilityChanged.bind(this); this.lastScreenX = 0; this.lastScreenY = 0; } + static sharedInstance() { + if (global.mxUserActivity === undefined) { + global.mxUserActivity = new UserActivity(window, document); + } + return global.mxUserActivity; + } + /** - * Runs the given timer while the user is active, aborting when the user becomes inactive. + * Runs the given timer while the user is 'active now', aborting when the user is no longer + * considered currently active. + * See userActiveNow() for what it means for a user to be 'active'. * 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) { + timeWhileActiveNow(timer) { + this._timeWhile(timer, this._attachedActiveNowTimers); + if (this.userActiveNow()) { + timer.start(); + } + } + + /** + * Runs the given timer while the user is 'active' now or recently, + * aborting when the user becomes inactive. + * See userActiveRecently() for what it means for a user to be 'active recently'. + * 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 + */ + timeWhileActiveRecently(timer) { + this._timeWhile(timer, this._attachedActiveRecentlyTimers); + if (this.userActiveRecently()) { + timer.start(); + } + } + + _timeWhile(timer, attachedTimers) { // important this happens first - const index = this._attachedTimers.indexOf(timer); + const index = attachedTimers.indexOf(timer); if (index === -1) { - this._attachedTimers.push(timer); + attachedTimers.push(timer); // remove when done or aborted timer.finished().finally(() => { - const index = this._attachedTimers.indexOf(timer); + const index = attachedTimers.indexOf(timer); if (index !== -1) { // should never be -1 - this._attachedTimers.splice(index, 1); + 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; - document.onmousemove = this._onUserActivity; - document.onkeydown = this._onUserActivity; - document.addEventListener("visibilitychange", this._onPageVisibilityChanged); - document.addEventListener("blur", this._onDocumentBlurred); - document.addEventListener("focus", this._onUserActivity); + this._document.addEventListener('mousedown', this._onUserActivity); + this._document.addEventListener('mousemove', this._onUserActivity); + this._document.addEventListener('keydown', this._onUserActivity); + this._document.addEventListener("visibilitychange", this._onPageVisibilityChanged); + this._window.addEventListener("blur", this._onWindowBlurred); + this._window.addEventListener("focus", this._onUserActivity); // can't use document.scroll here because that's only the document // itself being scrolled. Need to use addEventListener's useCapture. // also this needs to be the wheel event, not scroll, as scroll is // fired when the view scrolls down for a new message. - window.addEventListener('wheel', this._onUserActivity, - { passive: true, capture: true }); + this._window.addEventListener('wheel', this._onUserActivity, { + passive: true, capture: true, + }); } /** * Stop tracking user activity */ stop() { - document.onmousedown = undefined; - document.onmousemove = undefined; - document.onkeydown = undefined; - window.removeEventListener('wheel', this._onUserActivity, - { passive: true, capture: true }); + this._document.removeEventListener('mousedown', this._onUserActivity); + this._document.removeEventListener('mousemove', this._onUserActivity); + this._document.removeEventListener('keydown', this._onUserActivity); + this._window.removeEventListener('wheel', this._onUserActivity, { + passive: true, capture: true, + }); - document.removeEventListener("visibilitychange", this._onPageVisibilityChanged); - document.removeEventListener("blur", this._onDocumentBlurred); - document.removeEventListener("focus", this._onUserActivity); + this._document.removeEventListener("visibilitychange", this._onPageVisibilityChanged); + this._window.removeEventListener("blur", this._onWindowBlurred); + this._window.removeEventListener("focus", this._onUserActivity); } /** - * Return true if there has been user activity very recently - * (ie. within a few seconds) - * @returns {boolean} true if user is currently/very recently active + * Return true if the user is currently 'active' + * A user is 'active' while they are interacting with the app and for a very short (<1s) + * time after that. This is intended to give a strong indication that the app has the + * user's attention at any given moment. + * @returns {boolean} true if user is currently 'active' */ - userCurrentlyActive() { - return this._activityTimeout.isRunning(); + userActiveNow() { + return this._activeNowTimeout.isRunning(); + } + + /** + * Return true if the user is currently active or has been recently + * A user is 'active recently' for a longer period of time (~2 mins) after + * they have been 'active' and while the app still has the focus. This is + * intended to indicate when the app may still have the user's attention + * (or they may have gone to make tea and left the window focused). + * @returns {boolean} true if user has been active recently + */ + userActiveRecently() { + return this._activeRecentlyTimeout.isRunning(); } _onPageVisibilityChanged(e) { - if (document.visibilityState === "hidden") { - this._activityTimeout.abort(); + if (this._document.visibilityState === "hidden") { + this._activeNowTimeout.abort(); + this._activeRecentlyTimeout.abort(); } else { this._onUserActivity(e); } } - _onDocumentBlurred() { - this._activityTimeout.abort(); + _onWindowBlurred() { + this._activeNowTimeout.abort(); + this._activeRecentlyTimeout.abort(); } - async _onUserActivity(event) { + _onUserActivity(event) { + // ignore anything if the window isn't focused + if (!this._document.hasFocus()) return; + if (event.screenX && event.type === "mousemove") { if (event.screenX === this.lastScreenX && event.screenY === this.lastScreenY) { // mouse hasn't actually moved @@ -131,19 +195,29 @@ class UserActivity { } dis.dispatch({action: 'user_activity'}); - if (!this._activityTimeout.isRunning()) { - this._activityTimeout.start(); + if (!this._activeNowTimeout.isRunning()) { + this._activeNowTimeout.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()); + + this._runTimersUntilTimeout(this._attachedActiveNowTimers, this._activeNowTimeout); } else { - this._activityTimeout.restart(); + this._activeNowTimeout.restart(); + } + + if (!this._activeRecentlyTimeout.isRunning()) { + this._activeRecentlyTimeout.start(); + + this._runTimersUntilTimeout(this._attachedActiveRecentlyTimers, this._activeRecentlyTimeout); + } else { + this._activeRecentlyTimeout.restart(); } } + + async _runTimersUntilTimeout(attachedTimers, timeout) { + attachedTimers.forEach((t) => t.start()); + try { + await timeout.finished(); + } catch (_e) { /* aborted */ } + attachedTimers.forEach((t) => t.abort()); + } } - - -module.exports = new UserActivity(); diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js deleted file mode 100644 index b40d0529a2..0000000000 --- a/src/UserSettingsStore.js +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 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 Promise from 'bluebird'; -import MatrixClientPeg from './MatrixClientPeg'; - -/* - * TODO: Make things use this. This is all WIP - see UserSettings.js for usage. - */ -export default { - loadProfileInfo: function() { - const cli = MatrixClientPeg.get(); - return cli.getProfileInfo(cli.credentials.userId); - }, - - saveDisplayName: function(newDisplayname) { - return MatrixClientPeg.get().setDisplayName(newDisplayname); - }, - - loadThreePids: function() { - if (MatrixClientPeg.get().isGuest()) { - return Promise.resolve({ - threepids: [], - }); // guests can't poke 3pid endpoint - } - return MatrixClientPeg.get().getThreePids(); - }, - - saveThreePids: function(threePids) { - // TODO - }, - - changePassword: function(oldPassword, newPassword) { - const cli = MatrixClientPeg.get(); - - const authDict = { - type: 'm.login.password', - user: cli.credentials.userId, - password: oldPassword, - }; - - return cli.setPassword(authDict, newPassword); - }, - - /* - * Returns the email pusher (pusher of type 'email') for a given - * email address. Email pushers all have the same app ID, so since - * pushers are unique over (app ID, pushkey), there will be at most - * one such pusher. - */ - getEmailPusher: function(pushers, address) { - if (pushers === undefined) { - return undefined; - } - for (let i = 0; i < pushers.length; ++i) { - if (pushers[i].kind === 'email' && pushers[i].pushkey === address) { - return pushers[i]; - } - } - return undefined; - }, - - hasEmailPusher: function(pushers, address) { - return this.getEmailPusher(pushers, address) !== undefined; - }, - - addEmailPusher: function(address, data) { - return MatrixClientPeg.get().setPusher({ - kind: 'email', - app_id: 'm.email', - pushkey: address, - app_display_name: 'Email Notifications', - device_display_name: address, - lang: navigator.language, - data: data, - append: true, // We always append for email pushers since we don't want to stop other accounts notifying to the same email address - }); - }, -}; diff --git a/src/Velociraptor.js b/src/Velociraptor.js index ad51f66ae3..d2cae5c2a7 100644 --- a/src/Velociraptor.js +++ b/src/Velociraptor.js @@ -1,7 +1,7 @@ const React = require('react'); const ReactDom = require('react-dom'); import PropTypes from 'prop-types'; -const Velocity = require('velocity-vector'); +const Velocity = require('velocity-animate'); /** * The Velociraptor contains components and animates transitions with velocity. diff --git a/src/VelocityBounce.js b/src/VelocityBounce.js index b9513249b8..db216f81fb 100644 --- a/src/VelocityBounce.js +++ b/src/VelocityBounce.js @@ -1,4 +1,4 @@ -const Velocity = require('velocity-vector'); +const Velocity = require('velocity-animate'); // courtesy of https://github.com/julianshapiro/velocity/issues/283 // We only use easeOutBounce (easeInBounce is just sort of nonsensical) diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js index 5b722df65f..1d8e1b9cd3 100644 --- a/src/WidgetMessaging.js +++ b/src/WidgetMessaging.js @@ -1,5 +1,6 @@ /* Copyright 2017 New Vector Ltd +Copyright 2019 Travis Ralston Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,6 +22,11 @@ limitations under the License. import FromWidgetPostMessageApi from './FromWidgetPostMessageApi'; import ToWidgetPostMessageApi from './ToWidgetPostMessageApi'; +import Modal from "./Modal"; +import MatrixClientPeg from "./MatrixClientPeg"; +import SettingsStore from "./settings/SettingsStore"; +import WidgetOpenIDPermissionsDialog from "./components/views/dialogs/WidgetOpenIDPermissionsDialog"; +import WidgetUtils from "./utils/WidgetUtils"; if (!global.mxFromWidgetMessaging) { global.mxFromWidgetMessaging = new FromWidgetPostMessageApi(); @@ -34,12 +40,14 @@ if (!global.mxToWidgetMessaging) { const OUTBOUND_API_NAME = 'toWidget'; export default class WidgetMessaging { - constructor(widgetId, widgetUrl, target) { + constructor(widgetId, widgetUrl, isUserWidget, target) { this.widgetId = widgetId; this.widgetUrl = widgetUrl; + this.isUserWidget = isUserWidget; this.target = target; this.fromWidget = global.mxFromWidgetMessaging; this.toWidget = global.mxToWidgetMessaging; + this._onOpenIdRequest = this._onOpenIdRequest.bind(this); this.start(); } @@ -109,9 +117,57 @@ export default class WidgetMessaging { start() { this.fromWidget.addEndpoint(this.widgetId, this.widgetUrl); + this.fromWidget.addListener("get_openid", this._onOpenIdRequest); } stop() { this.fromWidget.removeEndpoint(this.widgetId, this.widgetUrl); + this.fromWidget.removeListener("get_openid", this._onOpenIdRequest); + } + + async _onOpenIdRequest(ev, rawEv) { + if (ev.widgetId !== this.widgetId) return; // not interesting + + const widgetSecurityKey = WidgetUtils.getWidgetSecurityKey(this.widgetId, this.widgetUrl, this.isUserWidget); + + const settings = SettingsStore.getValue("widgetOpenIDPermissions"); + if (settings.deny && settings.deny.includes(widgetSecurityKey)) { + this.fromWidget.sendResponse(rawEv, {state: "blocked"}); + return; + } + if (settings.allow && settings.allow.includes(widgetSecurityKey)) { + const responseBody = {state: "allowed"}; + const credentials = await MatrixClientPeg.get().getOpenIdToken(); + Object.assign(responseBody, credentials); + this.fromWidget.sendResponse(rawEv, responseBody); + return; + } + + // Confirm that we received the request + this.fromWidget.sendResponse(rawEv, {state: "request"}); + + // Actually ask for permission to send the user's data + Modal.createTrackedDialog("OpenID widget permissions", '', + WidgetOpenIDPermissionsDialog, { + widgetUrl: this.widgetUrl, + widgetId: this.widgetId, + isUserWidget: this.isUserWidget, + + onFinished: async (confirm) => { + const responseBody = {success: confirm}; + if (confirm) { + const credentials = await MatrixClientPeg.get().getOpenIdToken(); + Object.assign(responseBody, credentials); + } + this.messageToWidget({ + api: OUTBOUND_API_NAME, + action: "openid_credentials", + data: responseBody, + }).catch((error) => { + console.error("Failed to send OpenID credentials: ", error); + }); + }, + }, + ); } } diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index c1d42ffd0d..c89ec44435 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -131,6 +131,24 @@ function createRoomTagsAction(matrixClient, roomTagsEvent, room) { return { action: 'MatrixActions.Room.tags', room }; } +/** + * Create a MatrixActions.Room.receipt action that represents a MatrixClient + * `Room.receipt` event, each parameter mapping to a key-value in the action. + * + * @param {MatrixClient} matrixClient the matrix client + * @param {MatrixEvent} event the receipt event. + * @param {Room} room the room the receipt happened in. + * @returns {Object} an action of type MatrixActions.Room.receipt. + */ +function createRoomReceiptAction(matrixClient, event, room) { + return { + action: 'MatrixActions.Room.receipt', + event, + room, + matrixClient, + }; +} + /** * @typedef RoomTimelineAction * @type {Object} @@ -233,6 +251,7 @@ export default { this._addMatrixClientListener(matrixClient, 'Room.accountData', createRoomAccountDataAction); this._addMatrixClientListener(matrixClient, 'Room', createRoomAction); this._addMatrixClientListener(matrixClient, 'Room.tags', createRoomTagsAction); + this._addMatrixClientListener(matrixClient, 'Room.receipt', createRoomReceiptAction); this._addMatrixClientListener(matrixClient, 'Room.timeline', createRoomTimelineAction); this._addMatrixClientListener(matrixClient, 'Room.myMembership', createSelfMembershipAction); this._addMatrixClientListener(matrixClient, 'Event.decrypted', createEventDecryptedAction); diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js index 4fb5df214b..9ceff69467 100644 --- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js +++ b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js @@ -240,7 +240,6 @@ export default React.createClass({ _renderPhasePassPhrase: function() { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); let strengthMeter; let helpText; @@ -252,9 +251,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} @@ -267,8 +264,15 @@ export default React.createClass({ } return
-

{_t("Secure your encrypted message history with a Recovery Passphrase.")}

-

{_t("You'll need it if you log out or lose access to this device.")}

+

{_t( + "Warning: you should only set up key backup from a trusted computer.", {}, + { b: sub => {sub} }, + )}

+

{_t( + "We'll store an encrypted copy of your keys on our server. " + + "Protect your backup with a passphrase to keep it secure.", + )}

+

{_t("For maximum security, this should be different from your account password.")}

@@ -293,34 +297,12 @@ export default React.createClass({ disabled={!this._passPhraseIsValid()} /> -

{_t( - "If you don't want encrypted message history to be available on other devices, "+ - ".", - {}, - { - button: sub => - {sub} - , - }, - )}

-

{_t( - "Or, if you don't want to create a Recovery Passphrase, skip this step and "+ - ".", - {}, - { - button: sub => - {sub} - , - }, - )}

+
+ {_t("Advanced")} +

+
; }, @@ -355,9 +337,7 @@ export default React.createClass({ const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return

{_t( - "Type in your Recovery Passphrase to confirm you remember it. " + - "If it helps, add it to your password manager or store it " + - "somewhere safe.", + "Please enter your passphrase a second time to confirm.", )}

@@ -394,7 +374,13 @@ export default React.createClass({ } return
-

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

+

{_t( + "Your recovery key is a safety net - you can use it to restore " + + "access to your encrypted messages if you forget your passphrase.", + )}

+

{_t( + "Keep your recovery key somewhere very secure, like a password manager (or a safe)", + )}

{bodyText}

@@ -457,10 +443,9 @@ export default React.createClass({ const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return

{_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.")}

- + @@ -486,19 +471,19 @@ export default React.createClass({ _titleForPhase: function(phase) { switch (phase) { case PHASE_PASSPHRASE: - return _t('Create a Recovery Passphrase'); + return _t('Secure your backup with a passphrase'); case PHASE_PASSPHRASE_CONFIRM: - return _t('Confirm Recovery Passphrase'); + return _t('Confirm your passphrase'); case PHASE_OPTOUT_CONFIRM: return _t('Warning!'); case PHASE_SHOWKEY: - return _t('Recovery Key'); + return _t('Recovery key'); case PHASE_KEEPITSAFE: return _t('Keep it safe'); case PHASE_BACKINGUP: return _t('Starting backup...'); case PHASE_DONE: - return _t('Backup Started'); + return _t('Success!'); default: return _t("Create Key Backup"); } diff --git a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js index db86178b5a..28281af771 100644 --- a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js +++ b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js @@ -39,36 +39,8 @@ export default class NewRecoveryMethodDialog extends React.PureComponent { } onSetupClick = async () => { - // TODO: Should change to a restore key backup flow that checks the - // recovery passphrase while at the same time also cross-signing the - // device as well in a single flow. Since we don't have that yet, we'll - // look for an unverified device and verify it. Note that this means - // we won't restore keys yet; instead we'll only trust the backup for - // sending our own new keys to it. - let backupSigStatus; - try { - backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(this.props.newVersionInfo); - } catch (e) { - console.log("Unable to fetch key backup status", e); - return; - } - - let unverifiedDevice; - for (const sig of backupSigStatus.sigs) { - if (!sig.device.isVerified()) { - unverifiedDevice = sig.device; - break; - } - } - if (!unverifiedDevice) { - console.log("Unable to find a device to verify."); - return; - } - - const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog'); - Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, { - userId: MatrixClientPeg.get().credentials.userId, - device: unverifiedDevice, + const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog'); + Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, { onFinished: this.props.onFinished, }); } @@ -111,11 +83,6 @@ export default class NewRecoveryMethodDialog extends React.PureComponent { } 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} { - 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/RoomProvider.js b/src/autocomplete/RoomProvider.js index 483506557f..f118a06b9e 100644 --- a/src/autocomplete/RoomProvider.js +++ b/src/autocomplete/RoomProvider.js @@ -56,7 +56,7 @@ export default class RoomProvider extends AutocompleteProvider { const {command, range} = this.getCurrentCommand(query, selection, force); if (command) { // the only reason we need to do this is because Fuse only matches on properties - this.matcher.setObjects(client.getRooms().filter( + let matcherObjects = client.getRooms().filter( (room) => !!room && !!getDisplayAliasForRoom(room), ).map((room) => { return { @@ -64,7 +64,21 @@ export default class RoomProvider extends AutocompleteProvider { name: room.name, displayedAlias: getDisplayAliasForRoom(room), }; - })); + }); + + // Filter out any matches where the user will have also autocompleted new rooms + matcherObjects = matcherObjects.filter((r) => { + const tombstone = r.room.currentState.getStateEvents("m.room.tombstone", ""); + if (tombstone && tombstone.getContent() && tombstone.getContent()['replacement_room']) { + const hasReplacementRoom = matcherObjects.some( + (r2) => r2.room.roomId === tombstone.getContent()['replacement_room'], + ); + return !hasReplacementRoom; + } + return true; + }); + + this.matcher.setObjects(matcherObjects); const matchedString = command[0]; completions = this.matcher.match(matchedString); completions = _sortBy(completions, [ diff --git a/src/components/structures/AutoHideScrollbar.js b/src/components/structures/AutoHideScrollbar.js index 47ae24ba0f..72d48a2084 100644 --- a/src/components/structures/AutoHideScrollbar.js +++ b/src/components/structures/AutoHideScrollbar.js @@ -20,6 +20,7 @@ import React from "react"; // 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'; @@ -101,10 +102,6 @@ export default class AutoHideScrollbar extends React.Component { installBodyClassesIfNeeded(); this._needsOverflowListener = document.body.classList.contains("mx_scrollbar_nooverlay"); - if (this._needsOverflowListener) { - this.containerRef.addEventListener("overflow", this.onOverflow); - this.containerRef.addEventListener("underflow", this.onUnderflow); - } this.checkOverflow(); } @@ -117,17 +114,16 @@ export default class AutoHideScrollbar extends React.Component { } } - componentWillUnmount() { - if (this._needsOverflowListener && this.containerRef) { - this.containerRef.removeEventListener("overflow", this.onOverflow); - this.containerRef.removeEventListener("underflow", this.onUnderflow); - } + getScrollTop() { + return this.containerRef.scrollTop; } render() { return (
{ this.props.children } diff --git a/src/components/structures/BottomLeftMenu.js b/src/components/structures/BottomLeftMenu.js index ed8b8a00b7..5f2b954300 100644 --- a/src/components/structures/BottomLeftMenu.js +++ b/src/components/structures/BottomLeftMenu.js @@ -19,8 +19,8 @@ import React from 'react'; import ReactDOM from 'react-dom'; import sdk from '../../index'; import dis from '../../dispatcher'; -import Velocity from 'velocity-vector'; -import 'velocity-vector/velocity.ui'; +import Velocity from 'velocity-animate'; +import 'velocity-animate/velocity.ui'; import SettingsStore from '../../settings/SettingsStore'; const CALLOUT_ANIM_DURATION = 1000; @@ -145,8 +145,8 @@ module.exports = React.createClass({ // Get the label/tooltip to show getLabel: function(label, show) { if (show) { - const RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); - return ; + const Tooltip = sdk.getComponent("elements.Tooltip"); + return ; } }, @@ -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..c6abba4eb3 100644 --- a/src/components/structures/CompatibilityPage.js +++ b/src/components/structures/CompatibilityPage.js @@ -41,26 +41,30 @@ 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, Firefox, ' + + 'or Safari for the best experience.', {}, { 'chromeLink': (sub) => {sub}, - 'firefoxLink': (sub) => {sub}, - }, - )} - { _t('Safari and Opera work too.', - {}, - { - 'safariLink': (sub) => {sub}, - 'operaLink': (sub) => {sub}, + 'firefoxLink': (sub) => {sub}, + 'safariLink': (sub) => {sub}, }, )}

- { _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!", + ) }