Rework custom status context menu
This updates the custom status context menu to match the latest comps. A single button is used for setting / clearing, depending on what is appropriate. The state logic is also changed to depend on events and storage from js-sdk for the committed status message. This makes it easy to distinguish the value being edited from what's currently committed.
This commit is contained in:
parent
fc3055f541
commit
5b88b64950
6 changed files with 103 additions and 77 deletions
|
@ -14,42 +14,43 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_StatusMessageContextMenu_message {
|
.mx_StatusMessageContextMenu {
|
||||||
display: inline-block;
|
padding: 10px;
|
||||||
border-radius: 3px 0 0 3px;
|
}
|
||||||
|
|
||||||
|
.mx_StatusMessageContextMenu_form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.mx_StatusMessageContextMenu_message {
|
||||||
|
border-radius: 4px;
|
||||||
border: 1px solid $input-border-color;
|
border: 1px solid $input-border-color;
|
||||||
font-size: 13px;
|
padding: 6.5px 11px;
|
||||||
padding: 7px 7px 7px 9px;
|
background-color: $primary-bg-color;
|
||||||
width: 135px;
|
font-weight: normal;
|
||||||
background-color: $primary-bg-color !important;
|
margin: 0 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_StatusMessageContextMenu_submit {
|
.mx_StatusMessageContextMenu_message::placeholder {
|
||||||
display: inline-block;
|
color: $memberstatus-placeholder-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_StatusMessageContextMenu_submitFaded {
|
.mx_StatusMessageContextMenu_submit,
|
||||||
opacity: 0.5;
|
.mx_StatusMessageContextMenu_clear {
|
||||||
|
@mixin mx_DialogButton;
|
||||||
|
align-self: start;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 6px 1em;
|
||||||
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_StatusMessageContextMenu_submit img {
|
.mx_StatusMessageContextMenu_submit[disabled] {
|
||||||
vertical-align: middle;
|
opacity: 0.49;
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_StatusMessageContextMenu hr {
|
|
||||||
border: 0.5px solid $menu-border-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_StatusMessageContextMenu_clearIcon {
|
|
||||||
margin: 5px 15px 5px 5px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_StatusMessageContextMenu_clear {
|
.mx_StatusMessageContextMenu_clear {
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_StatusMessageContextMenu_hasStatus .mx_StatusMessageContextMenu_clear {
|
|
||||||
color: $warning-color;
|
color: $warning-color;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid $warning-color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
||||||
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
|
|
||||||
<title>Tick</title>
|
|
||||||
<desc>Created with Sketch.</desc>
|
|
||||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
||||||
<g id="Custom-Status-Copy" transform="translate(-529.000000, -917.000000)" fill-rule="nonzero">
|
|
||||||
<g id="Tick" transform="translate(530.000000, 918.000000)">
|
|
||||||
<circle id="Oval" stroke="#6AAC8C" fill="#75CFA6" cx="9" cy="9" r="9"></circle>
|
|
||||||
<g id="Glyph" transform="translate(8.949747, 7.949747) rotate(-45.000000) translate(-8.949747, -7.949747) translate(4.449747, 5.449747)" fill="#FFFFFF">
|
|
||||||
<rect id="Rectangle" x="0" y="0" width="2" height="5"></rect>
|
|
||||||
<rect id="Rectangle" x="0" y="3" width="9" height="2"></rect>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -68,7 +68,7 @@ $event-selected-color: #f7f7f7;
|
||||||
$primary-hairline-color: #e5e5e5;
|
$primary-hairline-color: #e5e5e5;
|
||||||
|
|
||||||
// used for the border of input text fields
|
// 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-bg-color: rgba(193, 201, 214, 0.29);
|
||||||
$input-darker-fg-color: #9fa9ba;
|
$input-darker-fg-color: #9fa9ba;
|
||||||
$input-lighter-bg-color: #f2f5f8;
|
$input-lighter-bg-color: #f2f5f8;
|
||||||
|
@ -192,6 +192,8 @@ $progressbar-color: #000;
|
||||||
|
|
||||||
$room-warning-bg-color: #fff8e3;
|
$room-warning-bg-color: #fff8e3;
|
||||||
|
|
||||||
|
$memberstatus-placeholder-color: $roomtile-name-color;
|
||||||
|
|
||||||
/*** form elements ***/
|
/*** form elements ***/
|
||||||
|
|
||||||
// .mx_textinput is a container for a text input
|
// .mx_textinput is a container for a text input
|
||||||
|
|
|
@ -188,6 +188,8 @@ $progressbar-color: #000;
|
||||||
|
|
||||||
$room-warning-bg-color: #fff8e3;
|
$room-warning-bg-color: #fff8e3;
|
||||||
|
|
||||||
|
$memberstatus-placeholder-color: $roomtile-name-color;
|
||||||
|
|
||||||
// ***** Mixins! *****
|
// ***** Mixins! *****
|
||||||
|
|
||||||
@define-mixin mx_DialogButton {
|
@define-mixin mx_DialogButton {
|
||||||
|
|
|
@ -19,7 +19,6 @@ import PropTypes from 'prop-types';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
export default class StatusMessageContextMenu extends React.Component {
|
export default class StatusMessageContextMenu extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -31,13 +30,42 @@ export default class StatusMessageContextMenu extends React.Component {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
message: props.user ? props.user._unstable_statusMessage : "",
|
message: this.comittedStatusMessage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
const { user } = this.props;
|
||||||
|
if (!user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUmount() {
|
||||||
|
const { user } = this.props;
|
||||||
|
if (!user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
user.removeListener(
|
||||||
|
"User._unstable_statusMessage",
|
||||||
|
this._onStatusMessageCommitted,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get comittedStatusMessage() {
|
||||||
|
return this.props.user ? this.props.user._unstable_statusMessage : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
_onStatusMessageCommitted = () => {
|
||||||
|
// The `User` object has observed a status message change.
|
||||||
|
this.setState({
|
||||||
|
message: this.comittedStatusMessage,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
_onClearClick = async (e) => {
|
_onClearClick = async (e) => {
|
||||||
await MatrixClientPeg.get()._unstable_setStatusMessage("");
|
await MatrixClientPeg.get()._unstable_setStatusMessage("");
|
||||||
this.setState({message: ""});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_onSubmit = (e) => {
|
_onSubmit = (e) => {
|
||||||
|
@ -46,41 +74,49 @@ export default class StatusMessageContextMenu extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
_onStatusChange = (e) => {
|
_onStatusChange = (e) => {
|
||||||
this.setState({message: e.target.value});
|
// The input field's value was changed.
|
||||||
|
this.setState({
|
||||||
|
message: e.target.value,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const formSubmitClasses = classNames({
|
let actionButton;
|
||||||
"mx_StatusMessageContextMenu_submit": true,
|
if (this.comittedStatusMessage) {
|
||||||
"mx_StatusMessageContextMenu_submitFaded": !this.state.message, // no message == faded
|
if (this.state.message === this.comittedStatusMessage) {
|
||||||
});
|
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_clear"
|
||||||
|
onClick={this._onClearClick}
|
||||||
|
>
|
||||||
|
<span>{_t("Clear status")}</span>
|
||||||
|
</AccessibleButton>;
|
||||||
|
} else {
|
||||||
|
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
|
||||||
|
onClick={this._onSubmit}
|
||||||
|
>
|
||||||
|
<span>{_t("Update status")}</span>
|
||||||
|
</AccessibleButton>;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
|
||||||
|
disabled={!this.state.message} onClick={this._onSubmit}
|
||||||
|
>
|
||||||
|
<span>{_t("Set status")}</span>
|
||||||
|
</AccessibleButton>;
|
||||||
|
}
|
||||||
|
|
||||||
const form = <form className="mx_StatusMessageContextMenu_form" onSubmit={this._onSubmit} autoComplete="off">
|
const form = <form className="mx_StatusMessageContextMenu_form"
|
||||||
<input type="text" key="message" placeholder={_t("Set a new status...")} autoFocus={true}
|
autoComplete="off" onSubmit={this._onSubmit}
|
||||||
className="mx_StatusMessageContextMenu_message"
|
>
|
||||||
value={this.state.message} onChange={this._onStatusChange} maxLength="60" />
|
<input type="text" className="mx_StatusMessageContextMenu_message"
|
||||||
<AccessibleButton onClick={this._onSubmit} element="div" className={formSubmitClasses}>
|
key="message" placeholder={_t("Set a new status...")}
|
||||||
<img src="img/icons-checkmark.svg" width="22" height="22" />
|
autoFocus={true} maxLength="60" value={this.state.message}
|
||||||
</AccessibleButton>
|
onChange={this._onStatusChange}
|
||||||
|
/>
|
||||||
|
{actionButton}
|
||||||
</form>;
|
</form>;
|
||||||
|
|
||||||
const clearIcon = this.state.message ? "img/cancel-red.svg" : "img/cancel.svg";
|
return <div className="mx_StatusMessageContextMenu">
|
||||||
const clearButton = <AccessibleButton onClick={this._onClearClick} disabled={!this.state.message}
|
|
||||||
className="mx_StatusMessageContextMenu_clear">
|
|
||||||
<img src={clearIcon} alt={_t('Clear status')} width="12" height="12"
|
|
||||||
className="mx_filterFlipColor mx_StatusMessageContextMenu_clearIcon" />
|
|
||||||
<span>{_t("Clear status")}</span>
|
|
||||||
</AccessibleButton>;
|
|
||||||
|
|
||||||
const menuClasses = classNames({
|
|
||||||
"mx_StatusMessageContextMenu": true,
|
|
||||||
"mx_StatusMessageContextMenu_hasStatus": this.state.message,
|
|
||||||
});
|
|
||||||
|
|
||||||
return <div className={menuClasses}>
|
|
||||||
{ form }
|
{ form }
|
||||||
<hr />
|
|
||||||
{ clearButton }
|
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1087,8 +1087,10 @@
|
||||||
"Forget": "Forget",
|
"Forget": "Forget",
|
||||||
"Low Priority": "Low Priority",
|
"Low Priority": "Low Priority",
|
||||||
"Direct Chat": "Direct Chat",
|
"Direct Chat": "Direct Chat",
|
||||||
"Set a new status...": "Set a new status...",
|
|
||||||
"Clear status": "Clear status",
|
"Clear status": "Clear status",
|
||||||
|
"Update status": "Update status",
|
||||||
|
"Set status": "Set status",
|
||||||
|
"Set a new status...": "Set a new status...",
|
||||||
"View as Grid": "View as Grid",
|
"View as Grid": "View as Grid",
|
||||||
"View Community": "View Community",
|
"View Community": "View Community",
|
||||||
"Sorry, your browser is <b>not</b> able to run Riot.": "Sorry, your browser is <b>not</b> able to run Riot.",
|
"Sorry, your browser is <b>not</b> able to run Riot.": "Sorry, your browser is <b>not</b> able to run Riot.",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue