From 7925e7169ae3f32cefd0bcd7fd023a90389fbe36 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 3 Apr 2019 16:27:45 +0100 Subject: [PATCH 1/5] Design tweaks to dialogs Little bit of a mix of things in this one: * Support variable-width dialogs. Default is fixed-width as before, only UploadConformDialog is variable-width. Controlled by a prop to BaseDialog. * Fixes to the cancel 'x' - scale the mask image, tweak size & colour * Colour & boldness of dialog titles * Align the dialog title & cancel 'x' * Remove gap between dialog buttons & right hand side of dialog(!) * Round corners on dialogs * Add grey border on image preview in upload confirm dialog * and, squeezing in slightly randomly, finish the partially renamed ChatInviteDialog to AddressPickerDialog. --- res/css/_common.scss | 33 ++++++++++++------- res/css/_components.scss | 2 +- ...eDialog.scss => _AddressPickerDialog.scss} | 15 +++++---- res/css/views/dialogs/_SettingsDialog.scss | 4 +-- .../views/dialogs/_UploadConfirmDialog.scss | 2 ++ res/themes/light/css/_light.scss | 4 +-- src/Modal.js | 3 +- .../views/dialogs/AddressPickerDialog.js | 16 ++++----- src/components/views/dialogs/BaseDialog.js | 15 +++++++-- .../views/dialogs/UploadConfirmDialog.js | 1 + 10 files changed, 60 insertions(+), 35 deletions(-) rename res/css/views/dialogs/{_ChatInviteDialog.scss => _AddressPickerDialog.scss} (83%) diff --git a/res/css/_common.scss b/res/css/_common.scss index 1e388c4531..5537eb0fce 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -118,7 +118,7 @@ textarea { background-color: transparent; color: $input-darker-fg-color; border-radius: 4px; - border: 1px solid #c1c1c1; + border: 1px solid $dialog-close-fg-color; // these things should probably not be defined // globally margin: 9px; @@ -267,14 +267,18 @@ textarea { font-weight: 300; font-size: 15px; position: relative; - padding: 40px 58px 36px 58px; - width: 60%; + padding: 25px 30px 30px 30px; max-width: 704px; - box-shadow: 2px 15px 30px 0 $dialog-shadow-color; max-height: 80%; + box-shadow: 2px 15px 30px 0 $dialog-shadow-color; + border-radius: 4px; overflow-y: auto; } +.mx_Dialog_fixedWidth { + min-width: 60vw; +} + .mx_Dialog_staticWrapper .mx_Dialog { z-index: 4010; } @@ -317,13 +321,13 @@ textarea { .mx_Dialog_header { position: relative; + margin-bottom: 20px; } .mx_Dialog_title { - font-weight: bold; font-size: 22px; line-height: 36px; - color: $primary-fg-color; + color: $dialog-title-fg-color; } .mx_Dialog_header.mx_Dialog_headerWithButton > .mx_Dialog_title { @@ -338,13 +342,14 @@ textarea { mask: url('$(res)/img/feather-customised/cancel.svg'); mask-repeat: no-repeat; mask-position: center; - width: 36px; - height: 36px; - background-color: $primary-fg-color; + mask-size: cover; + width: 14px; + height: 14px; + background-color: $dialog-close-fg-color; cursor: pointer; position: absolute; - top: 20px; - right: 20px; + top: 4px; + right: 0px; } .mx_Dialog_content { @@ -355,6 +360,7 @@ textarea { } .mx_Dialog_buttons { + margin-top: 20px; text-align: right; } @@ -370,6 +376,10 @@ textarea { background-color: $button-secondary-bg-color; } +.mx_Dialog button:last-child { + margin-right: 0px; +} + .mx_Dialog button:hover, .mx_Dialog input[type="submit"]:hover { @mixin mx_DialogButton_hover; } @@ -381,6 +391,7 @@ textarea { .mx_Dialog button.mx_Dialog_primary, .mx_Dialog input[type="submit"].mx_Dialog_primary { color: $accent-fg-color; background-color: $accent-color; + min-width: 156px; } .mx_Dialog button.danger, .mx_Dialog input[type="submit"].danger { diff --git a/res/css/_components.scss b/res/css/_components.scss index b7d0c7a2a5..25022acd2e 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -47,11 +47,11 @@ @import "./views/context_menus/_StatusMessageContextMenu.scss"; @import "./views/context_menus/_TagTileContextMenu.scss"; @import "./views/context_menus/_TopLeftMenu.scss"; +@import "./views/dialogs/_AddressPickerDialog.scss"; @import "./views/dialogs/_Analytics.scss"; @import "./views/dialogs/_BugReportDialog.scss"; @import "./views/dialogs/_ChangelogDialog.scss"; @import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss"; -@import "./views/dialogs/_ChatInviteDialog.scss"; @import "./views/dialogs/_ConfirmUserActionDialog.scss"; @import "./views/dialogs/_CreateGroupDialog.scss"; @import "./views/dialogs/_CreateRoomDialog.scss"; diff --git a/res/css/views/dialogs/_ChatInviteDialog.scss b/res/css/views/dialogs/_AddressPickerDialog.scss similarity index 83% rename from res/css/views/dialogs/_ChatInviteDialog.scss rename to res/css/views/dialogs/_AddressPickerDialog.scss index dcc0f5921a..b4d4a74cb5 100644 --- a/res/css/views/dialogs/_ChatInviteDialog.scss +++ b/res/css/views/dialogs/_AddressPickerDialog.scss @@ -1,5 +1,6 @@ /* 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. @@ -15,8 +16,8 @@ limitations under the License. */ /* Using a textarea for this element, to circumvent autofill */ -.mx_ChatInviteDialog_input, -.mx_ChatInviteDialog_input:focus +.mx_AddressPickerDialog_input, +.mx_AddressPickerDialog_input:focus { height: 26px; font-size: 14px; @@ -34,11 +35,11 @@ limitations under the License. word-wrap: nowrap; } -.mx_ChatInviteDialog .mx_Dialog_content { +.mx_AddressPickerDialog .mx_Dialog_content { min-height: 50px } -.mx_ChatInviteDialog_inputContainer { +.mx_AddressPickerDialog_inputContainer { border-radius: 3px; border: solid 1px $input-border-color; line-height: 36px; @@ -51,19 +52,19 @@ limitations under the License. overflow-y: auto; } -.mx_ChatInviteDialog_error { +.mx_AddressPickerDialog_error { margin-top: 10px; color: $warning-color; } -.mx_ChatInviteDialog_cancel { +.mx_AddressPickerDialog_cancel { position: absolute; right: 11px; top: 13px; cursor: pointer; } -.mx_ChatInviteDialog_cancel object { +.mx_AddressPickerDialog_cancel object { pointer-events: none; } diff --git a/res/css/views/dialogs/_SettingsDialog.scss b/res/css/views/dialogs/_SettingsDialog.scss index abf0048cfd..77a447e8b9 100644 --- a/res/css/views/dialogs/_SettingsDialog.scss +++ b/res/css/views/dialogs/_SettingsDialog.scss @@ -21,7 +21,7 @@ limitations under the License. height: 80%; border-radius: 4px; padding-top: 0; - padding-right: 0; + padding-right: 30px; padding-left: 0; .mx_TabbedView { @@ -31,7 +31,7 @@ limitations under the License. .mx_TabbedView .mx_SettingsTab { box-sizing: border-box; min-width: 580px; - padding-right: 130px; + padding-right: 100px; // Put some padding on the bottom to avoid the settings tab from // colliding harshly with the dialog when scrolled down. diff --git a/res/css/views/dialogs/_UploadConfirmDialog.scss b/res/css/views/dialogs/_UploadConfirmDialog.scss index 116be798e3..cf9736ce81 100644 --- a/res/css/views/dialogs/_UploadConfirmDialog.scss +++ b/res/css/views/dialogs/_UploadConfirmDialog.scss @@ -30,4 +30,6 @@ limitations under the License. .mx_UploadConfirmDialog_imagePreview { max-height: 300px; max-width: 100%; + border-radius: 4px; + border: 1px solid $dialog-close-fg-color; } diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 879be67dda..ca2e4cf58d 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -106,10 +106,10 @@ $avatar-bg-color: #ffffff; $h3-color: #3d3b39; -$dialog-title-fg-color: #2e2f32; +$dialog-title-fg-color: #45474a; $dialog-backdrop-color: rgba(46, 48, 51, 0.38); $dialog-shadow-color: rgba(0, 0, 0, 0.48); -$dialog-close-fg-color: #9fa9ba; +$dialog-close-fg-color: #c1c1c1; $dialog-background-bg-color: #e9e9e9; $lightbox-background-bg-color: #000; diff --git a/src/Modal.js b/src/Modal.js index 96dbd49324..b956a09822 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -20,6 +20,7 @@ limitations under the License. const React = require('react'); const ReactDOM = require('react-dom'); import PropTypes from 'prop-types'; +import classNames from 'classnames'; import Analytics from './Analytics'; import sdk from './index'; import dis from './dispatcher'; @@ -158,7 +159,7 @@ class ModalManager { } createDialog(Element, ...rest) { - return this.createDialogAsync(new Promise(resolve => resolve(Element)), ...rest); + return this.createDialogAsync(Promise.resolve(Element), ...rest); } createTrackedDialogAsync(analyticsAction, analyticsInfo, ...rest) { diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js index 6276a45839..67fd197f8a 100644 --- a/src/components/views/dialogs/AddressPickerDialog.js +++ b/src/components/views/dialogs/AddressPickerDialog.js @@ -1,6 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017, 2018 New Vector Ltd +Copyright 2017, 2018, 2019 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -566,7 +566,7 @@ module.exports = React.createClass({ rows="1" id="textinput" ref="textinput" - className="mx_ChatInviteDialog_input" + className="mx_AddressPickerDialog_input" onChange={this.onQueryChanged} placeholder={this.props.placeholder} defaultValue={this.props.value} @@ -578,7 +578,7 @@ module.exports = React.createClass({ let addressSelector; if (this.state.error) { const validTypeDescriptions = this.props.validAddressTypes.map((t) => _t(addressTypeName[t])); - error =
+ error =
{ _t("You have entered an invalid address.") }
{ _t("Try using one of the following valid address types: %(validTypesList)s.", { @@ -586,9 +586,9 @@ module.exports = React.createClass({ }) }
; } else if (this.state.searchError) { - error =
{ this.state.searchError }
; + error =
{ this.state.searchError }
; } else if (this.state.query.length > 0 && filteredSuggestedList.length === 0 && !this.state.busy) { - error =
{ _t("No results") }
; + error =
{ _t("No results") }
; } else { addressSelector = ( {this.addressSelector = ref;}} @@ -601,13 +601,13 @@ module.exports = React.createClass({ } return ( - -
+
-
{ query }
+
{ query }
{ error } { addressSelector } { this.props.extraNode } diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index 34370d5b98..ee838b9825 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -1,6 +1,6 @@ /* Copyright 2017 Vector Creations Ltd -Copyright 2018 New Vector Ltd +Copyright 2018, 2019 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -55,6 +55,11 @@ export default React.createClass({ // CSS class to apply to dialog div className: PropTypes.string, + // if true, dialog container is 60% of the viewport width. Otherwise, + // the container will have no fixed size, allowing its contents to + // determine its size. Default: true. + fixedWidth: PropTypes.bool, + // Title for the dialog. title: PropTypes.node.isRequired, @@ -72,6 +77,7 @@ export default React.createClass({ getDefaultProps: function() { return { hasCancel: true, + fixedWidth: true, }; }, @@ -113,7 +119,10 @@ export default React.createClass({ return ( { this.props.headerButton } + { cancelButton }
- { cancelButton } { this.props.children } ); diff --git a/src/components/views/dialogs/UploadConfirmDialog.js b/src/components/views/dialogs/UploadConfirmDialog.js index f026454cea..e7b22950d6 100644 --- a/src/components/views/dialogs/UploadConfirmDialog.js +++ b/src/components/views/dialogs/UploadConfirmDialog.js @@ -87,6 +87,7 @@ export default class UploadConfirmDialog extends React.Component { return ( Date: Wed, 3 Apr 2019 16:48:11 +0100 Subject: [PATCH 2/5] Fix dialog title colour on dark theme --- res/themes/dark/css/_dark.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 3112644a73..daa0906aa3 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -72,7 +72,7 @@ $avatar-bg-color: $bg-color; $h3-color: $primary-fg-color; -$dialog-title-fg-color: #454545; +$dialog-title-fg-color: #edf3ff; $dialog-backdrop-color: #000; $dialog-shadow-color: rgba(0, 0, 0, 0.48); $dialog-close-fg-color: #9fa9ba; From 0a61d05ba28d3ae69eab373c24582ee95c5f5848 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 3 Apr 2019 17:53:38 +0100 Subject: [PATCH 3/5] Make fixed width dialogs actually fixed width again Settings overrode that to be larger, so do the corresponding override for the other part. --- res/css/_common.scss | 2 +- res/css/views/dialogs/_SettingsDialog.scss | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/res/css/_common.scss b/res/css/_common.scss index 5537eb0fce..8abd1c6ea7 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -276,7 +276,7 @@ textarea { } .mx_Dialog_fixedWidth { - min-width: 60vw; + width: 60vw; } .mx_Dialog_staticWrapper .mx_Dialog { diff --git a/res/css/views/dialogs/_SettingsDialog.scss b/res/css/views/dialogs/_SettingsDialog.scss index 77a447e8b9..840ddb0a09 100644 --- a/res/css/views/dialogs/_SettingsDialog.scss +++ b/res/css/views/dialogs/_SettingsDialog.scss @@ -43,5 +43,8 @@ limitations under the License. margin-top: 16px; margin-bottom: 24px; } + .mx_Dialog_fixedWidth { + width: 90vw; + } } } From 590535c569019a120da532072d28256ecb50f1ee Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 5 Apr 2019 10:06:35 +0100 Subject: [PATCH 4/5] Use value from unified palette Co-Authored-By: dbkr --- res/themes/dark/css/_dark.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index daa0906aa3..c433a028a3 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -72,7 +72,7 @@ $avatar-bg-color: $bg-color; $h3-color: $primary-fg-color; -$dialog-title-fg-color: #edf3ff; +$dialog-title-fg-color: $base-text-color; $dialog-backdrop-color: #000; $dialog-shadow-color: rgba(0, 0, 0, 0.48); $dialog-close-fg-color: #9fa9ba; From cd0dcc266826770dd381235229bef8ad9b0cad7f Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 5 Apr 2019 10:18:41 +0100 Subject: [PATCH 5/5] delint Modal.js --- .eslintignore.errorfiles | 1 - src/Modal.js | 29 +++++++++++++---------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 6d1874b872..2224ef67bc 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -59,7 +59,6 @@ src/languageHandler.js src/linkify-matrix.js src/Markdown.js src/MatrixClientPeg.js -src/Modal.js src/notifications/ContentRules.js src/notifications/PushRuleVectorState.js src/notifications/VectorPushRulesDefinitions.js diff --git a/src/Modal.js b/src/Modal.js index b956a09822..a114ad2d3c 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -20,7 +20,6 @@ limitations under the License. const React = require('react'); const ReactDOM = require('react-dom'); import PropTypes from 'prop-types'; -import classNames from 'classnames'; import Analytics from './Analytics'; import sdk from './index'; import dis from './dispatcher'; @@ -76,10 +75,9 @@ const AsyncWrapper = React.createClass({ }, render: function() { - const {loader, ...otherProps} = this.props; if (this.state.component) { const Component = this.state.component; - return ; + return ; } else if (this.state.error) { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); @@ -194,36 +192,35 @@ class ModalManager { * also be removed from the stack. This is not compatible * with being a priority modal. Only one modal can be * static at a time. + * @returns {object} Object with 'close' parameter being a function that will close the dialog */ createDialogAsync(prom, props, className, isPriorityModal, isStaticModal) { - const self = this; const modal = {}; // never call this from onFinished() otherwise it will loop // - // nb explicit function() rather than arrow function, to get `arguments` - const closeDialog = function() { - if (props && props.onFinished) props.onFinished.apply(null, arguments); - const i = self._modals.indexOf(modal); + const closeDialog = (...args) => { + if (props && props.onFinished) props.onFinished.apply(null, args); + const i = this._modals.indexOf(modal); if (i >= 0) { - self._modals.splice(i, 1); + this._modals.splice(i, 1); } - if (self._priorityModal === modal) { - self._priorityModal = null; + if (this._priorityModal === modal) { + this._priorityModal = null; // XXX: This is destructive - self._modals = []; + this._modals = []; } - if (self._staticModal === modal) { - self._staticModal = null; + if (this._staticModal === modal) { + this._staticModal = null; // XXX: This is destructive - self._modals = []; + this._modals = []; } - self._reRender(); + this._reRender(); }; // don't attempt to reuse the same AsyncWrapper for different dialogs,