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.
This commit is contained in:
David Baker 2019-04-03 16:27:45 +01:00
parent ed03a92712
commit 7925e7169a
10 changed files with 60 additions and 35 deletions

View file

@ -118,7 +118,7 @@ textarea {
background-color: transparent; background-color: transparent;
color: $input-darker-fg-color; color: $input-darker-fg-color;
border-radius: 4px; border-radius: 4px;
border: 1px solid #c1c1c1; border: 1px solid $dialog-close-fg-color;
// these things should probably not be defined // these things should probably not be defined
// globally // globally
margin: 9px; margin: 9px;
@ -267,14 +267,18 @@ textarea {
font-weight: 300; font-weight: 300;
font-size: 15px; font-size: 15px;
position: relative; position: relative;
padding: 40px 58px 36px 58px; padding: 25px 30px 30px 30px;
width: 60%;
max-width: 704px; max-width: 704px;
box-shadow: 2px 15px 30px 0 $dialog-shadow-color;
max-height: 80%; max-height: 80%;
box-shadow: 2px 15px 30px 0 $dialog-shadow-color;
border-radius: 4px;
overflow-y: auto; overflow-y: auto;
} }
.mx_Dialog_fixedWidth {
min-width: 60vw;
}
.mx_Dialog_staticWrapper .mx_Dialog { .mx_Dialog_staticWrapper .mx_Dialog {
z-index: 4010; z-index: 4010;
} }
@ -317,13 +321,13 @@ textarea {
.mx_Dialog_header { .mx_Dialog_header {
position: relative; position: relative;
margin-bottom: 20px;
} }
.mx_Dialog_title { .mx_Dialog_title {
font-weight: bold;
font-size: 22px; font-size: 22px;
line-height: 36px; line-height: 36px;
color: $primary-fg-color; color: $dialog-title-fg-color;
} }
.mx_Dialog_header.mx_Dialog_headerWithButton > .mx_Dialog_title { .mx_Dialog_header.mx_Dialog_headerWithButton > .mx_Dialog_title {
@ -338,13 +342,14 @@ textarea {
mask: url('$(res)/img/feather-customised/cancel.svg'); mask: url('$(res)/img/feather-customised/cancel.svg');
mask-repeat: no-repeat; mask-repeat: no-repeat;
mask-position: center; mask-position: center;
width: 36px; mask-size: cover;
height: 36px; width: 14px;
background-color: $primary-fg-color; height: 14px;
background-color: $dialog-close-fg-color;
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
top: 20px; top: 4px;
right: 20px; right: 0px;
} }
.mx_Dialog_content { .mx_Dialog_content {
@ -355,6 +360,7 @@ textarea {
} }
.mx_Dialog_buttons { .mx_Dialog_buttons {
margin-top: 20px;
text-align: right; text-align: right;
} }
@ -370,6 +376,10 @@ textarea {
background-color: $button-secondary-bg-color; background-color: $button-secondary-bg-color;
} }
.mx_Dialog button:last-child {
margin-right: 0px;
}
.mx_Dialog button:hover, .mx_Dialog input[type="submit"]:hover { .mx_Dialog button:hover, .mx_Dialog input[type="submit"]:hover {
@mixin mx_DialogButton_hover; @mixin mx_DialogButton_hover;
} }
@ -381,6 +391,7 @@ textarea {
.mx_Dialog button.mx_Dialog_primary, .mx_Dialog input[type="submit"].mx_Dialog_primary { .mx_Dialog button.mx_Dialog_primary, .mx_Dialog input[type="submit"].mx_Dialog_primary {
color: $accent-fg-color; color: $accent-fg-color;
background-color: $accent-color; background-color: $accent-color;
min-width: 156px;
} }
.mx_Dialog button.danger, .mx_Dialog input[type="submit"].danger { .mx_Dialog button.danger, .mx_Dialog input[type="submit"].danger {

View file

@ -47,11 +47,11 @@
@import "./views/context_menus/_StatusMessageContextMenu.scss"; @import "./views/context_menus/_StatusMessageContextMenu.scss";
@import "./views/context_menus/_TagTileContextMenu.scss"; @import "./views/context_menus/_TagTileContextMenu.scss";
@import "./views/context_menus/_TopLeftMenu.scss"; @import "./views/context_menus/_TopLeftMenu.scss";
@import "./views/dialogs/_AddressPickerDialog.scss";
@import "./views/dialogs/_Analytics.scss"; @import "./views/dialogs/_Analytics.scss";
@import "./views/dialogs/_BugReportDialog.scss"; @import "./views/dialogs/_BugReportDialog.scss";
@import "./views/dialogs/_ChangelogDialog.scss"; @import "./views/dialogs/_ChangelogDialog.scss";
@import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss"; @import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss";
@import "./views/dialogs/_ChatInviteDialog.scss";
@import "./views/dialogs/_ConfirmUserActionDialog.scss"; @import "./views/dialogs/_ConfirmUserActionDialog.scss";
@import "./views/dialogs/_CreateGroupDialog.scss"; @import "./views/dialogs/_CreateGroupDialog.scss";
@import "./views/dialogs/_CreateRoomDialog.scss"; @import "./views/dialogs/_CreateRoomDialog.scss";

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2016 OpenMarket Ltd Copyright 2016 OpenMarket Ltd
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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 */ /* Using a textarea for this element, to circumvent autofill */
.mx_ChatInviteDialog_input, .mx_AddressPickerDialog_input,
.mx_ChatInviteDialog_input:focus .mx_AddressPickerDialog_input:focus
{ {
height: 26px; height: 26px;
font-size: 14px; font-size: 14px;
@ -34,11 +35,11 @@ limitations under the License.
word-wrap: nowrap; word-wrap: nowrap;
} }
.mx_ChatInviteDialog .mx_Dialog_content { .mx_AddressPickerDialog .mx_Dialog_content {
min-height: 50px min-height: 50px
} }
.mx_ChatInviteDialog_inputContainer { .mx_AddressPickerDialog_inputContainer {
border-radius: 3px; border-radius: 3px;
border: solid 1px $input-border-color; border: solid 1px $input-border-color;
line-height: 36px; line-height: 36px;
@ -51,19 +52,19 @@ limitations under the License.
overflow-y: auto; overflow-y: auto;
} }
.mx_ChatInviteDialog_error { .mx_AddressPickerDialog_error {
margin-top: 10px; margin-top: 10px;
color: $warning-color; color: $warning-color;
} }
.mx_ChatInviteDialog_cancel { .mx_AddressPickerDialog_cancel {
position: absolute; position: absolute;
right: 11px; right: 11px;
top: 13px; top: 13px;
cursor: pointer; cursor: pointer;
} }
.mx_ChatInviteDialog_cancel object { .mx_AddressPickerDialog_cancel object {
pointer-events: none; pointer-events: none;
} }

View file

@ -21,7 +21,7 @@ limitations under the License.
height: 80%; height: 80%;
border-radius: 4px; border-radius: 4px;
padding-top: 0; padding-top: 0;
padding-right: 0; padding-right: 30px;
padding-left: 0; padding-left: 0;
.mx_TabbedView { .mx_TabbedView {
@ -31,7 +31,7 @@ limitations under the License.
.mx_TabbedView .mx_SettingsTab { .mx_TabbedView .mx_SettingsTab {
box-sizing: border-box; box-sizing: border-box;
min-width: 580px; min-width: 580px;
padding-right: 130px; padding-right: 100px;
// Put some padding on the bottom to avoid the settings tab from // Put some padding on the bottom to avoid the settings tab from
// colliding harshly with the dialog when scrolled down. // colliding harshly with the dialog when scrolled down.

View file

@ -30,4 +30,6 @@ limitations under the License.
.mx_UploadConfirmDialog_imagePreview { .mx_UploadConfirmDialog_imagePreview {
max-height: 300px; max-height: 300px;
max-width: 100%; max-width: 100%;
border-radius: 4px;
border: 1px solid $dialog-close-fg-color;
} }

View file

@ -106,10 +106,10 @@ $avatar-bg-color: #ffffff;
$h3-color: #3d3b39; $h3-color: #3d3b39;
$dialog-title-fg-color: #2e2f32; $dialog-title-fg-color: #45474a;
$dialog-backdrop-color: rgba(46, 48, 51, 0.38); $dialog-backdrop-color: rgba(46, 48, 51, 0.38);
$dialog-shadow-color: rgba(0, 0, 0, 0.48); $dialog-shadow-color: rgba(0, 0, 0, 0.48);
$dialog-close-fg-color: #9fa9ba; $dialog-close-fg-color: #c1c1c1;
$dialog-background-bg-color: #e9e9e9; $dialog-background-bg-color: #e9e9e9;
$lightbox-background-bg-color: #000; $lightbox-background-bg-color: #000;

View file

@ -20,6 +20,7 @@ limitations under the License.
const React = require('react'); const React = require('react');
const ReactDOM = require('react-dom'); const ReactDOM = require('react-dom');
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames';
import Analytics from './Analytics'; import Analytics from './Analytics';
import sdk from './index'; import sdk from './index';
import dis from './dispatcher'; import dis from './dispatcher';
@ -158,7 +159,7 @@ class ModalManager {
} }
createDialog(Element, ...rest) { createDialog(Element, ...rest) {
return this.createDialogAsync(new Promise(resolve => resolve(Element)), ...rest); return this.createDialogAsync(Promise.resolve(Element), ...rest);
} }
createTrackedDialogAsync(analyticsAction, analyticsInfo, ...rest) { createTrackedDialogAsync(analyticsAction, analyticsInfo, ...rest) {

View file

@ -1,6 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd 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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -566,7 +566,7 @@ module.exports = React.createClass({
rows="1" rows="1"
id="textinput" id="textinput"
ref="textinput" ref="textinput"
className="mx_ChatInviteDialog_input" className="mx_AddressPickerDialog_input"
onChange={this.onQueryChanged} onChange={this.onQueryChanged}
placeholder={this.props.placeholder} placeholder={this.props.placeholder}
defaultValue={this.props.value} defaultValue={this.props.value}
@ -578,7 +578,7 @@ module.exports = React.createClass({
let addressSelector; let addressSelector;
if (this.state.error) { if (this.state.error) {
const validTypeDescriptions = this.props.validAddressTypes.map((t) => _t(addressTypeName[t])); const validTypeDescriptions = this.props.validAddressTypes.map((t) => _t(addressTypeName[t]));
error = <div className="mx_ChatInviteDialog_error"> error = <div className="mx_AddressPickerDialog_error">
{ _t("You have entered an invalid address.") } { _t("You have entered an invalid address.") }
<br /> <br />
{ _t("Try using one of the following valid address types: %(validTypesList)s.", { { _t("Try using one of the following valid address types: %(validTypesList)s.", {
@ -586,9 +586,9 @@ module.exports = React.createClass({
}) } }) }
</div>; </div>;
} else if (this.state.searchError) { } else if (this.state.searchError) {
error = <div className="mx_ChatInviteDialog_error">{ this.state.searchError }</div>; error = <div className="mx_AddressPickerDialog_error">{ this.state.searchError }</div>;
} else if (this.state.query.length > 0 && filteredSuggestedList.length === 0 && !this.state.busy) { } else if (this.state.query.length > 0 && filteredSuggestedList.length === 0 && !this.state.busy) {
error = <div className="mx_ChatInviteDialog_error">{ _t("No results") }</div>; error = <div className="mx_AddressPickerDialog_error">{ _t("No results") }</div>;
} else { } else {
addressSelector = ( addressSelector = (
<AddressSelector ref={(ref) => {this.addressSelector = ref;}} <AddressSelector ref={(ref) => {this.addressSelector = ref;}}
@ -601,13 +601,13 @@ module.exports = React.createClass({
} }
return ( return (
<BaseDialog className="mx_ChatInviteDialog" onKeyDown={this.onKeyDown} <BaseDialog className="mx_AddressPickerDialog" onKeyDown={this.onKeyDown}
onFinished={this.props.onFinished} title={this.props.title}> onFinished={this.props.onFinished} title={this.props.title}>
<div className="mx_ChatInviteDialog_label"> <div className="mx_AddressPickerDialog_label">
<label htmlFor="textinput">{ this.props.description }</label> <label htmlFor="textinput">{ this.props.description }</label>
</div> </div>
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
<div className="mx_ChatInviteDialog_inputContainer">{ query }</div> <div className="mx_AddressPickerDialog_inputContainer">{ query }</div>
{ error } { error }
{ addressSelector } { addressSelector }
{ this.props.extraNode } { this.props.extraNode }

View file

@ -1,6 +1,6 @@
/* /*
Copyright 2017 Vector Creations Ltd 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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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 // CSS class to apply to dialog div
className: PropTypes.string, 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 for the dialog.
title: PropTypes.node.isRequired, title: PropTypes.node.isRequired,
@ -72,6 +77,7 @@ export default React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
hasCancel: true, hasCancel: true,
fixedWidth: true,
}; };
}, },
@ -113,7 +119,10 @@ export default React.createClass({
return ( return (
<FocusTrap onKeyDown={this._onKeyDown} <FocusTrap onKeyDown={this._onKeyDown}
className={this.props.className} className={classNames({
[this.props.className]: true,
'mx_Dialog_fixedWidth': this.props.fixedWidth,
})}
role="dialog" role="dialog"
aria-labelledby='mx_BaseDialog_title' aria-labelledby='mx_BaseDialog_title'
// This should point to a node describing the dialog. // This should point to a node describing the dialog.
@ -131,8 +140,8 @@ export default React.createClass({
{ this.props.title } { this.props.title }
</div> </div>
{ this.props.headerButton } { this.props.headerButton }
{ cancelButton }
</div> </div>
{ cancelButton }
{ this.props.children } { this.props.children }
</FocusTrap> </FocusTrap>
); );

View file

@ -87,6 +87,7 @@ export default class UploadConfirmDialog extends React.Component {
return ( return (
<BaseDialog className='mx_UploadConfirmDialog' <BaseDialog className='mx_UploadConfirmDialog'
fixedWidth={false}
onFinished={this._onCancelClick} onFinished={this._onCancelClick}
title={title} title={title}
contentId='mx_Dialog_content' contentId='mx_Dialog_content'