Improve the profile section a bit and add a highlight to the temp tab

pull/21833/head
Travis Ralston 2019-01-21 17:27:43 -07:00
parent c3692aa9ae
commit 15a56fa90b
9 changed files with 186 additions and 55 deletions

View File

@ -45,6 +45,11 @@ limitations under the License.
color: $tab-label-active-fg-color; color: $tab-label-active-fg-color;
} }
// TODO: Remove temporary hack alongside "visit old settings" tab
.mx_TabbedView_tabLabel_TEMP_HACK {
background-color: orange;
}
.mx_TabbedView_tabLabel_icon { .mx_TabbedView_tabLabel_icon {
width: 14px; width: 14px;
height: 14px; height: 14px;
@ -89,4 +94,5 @@ limitations under the License.
.mx_TabbedView_tabPanelContent { .mx_TabbedView_tabPanelContent {
flex-grow: 1; flex-grow: 1;
min-width: 560px;
} }

View File

@ -21,3 +21,24 @@ limitations under the License.
.mx_AccessibleButton { .mx_AccessibleButton {
cursor: pointer; cursor: pointer;
} }
.mx_AccessibleButton_disabled {
cursor: default;
}
.mx_AccessibleButton_hasKind {
padding: 10px 25px;
text-align: center;
border-radius: 4px;
display: inline-block;
}
.mx_AccessibleButton_kind_primary {
color: $button-primary-fg-color;
background-color: $button-primary-bg-color;
}
.mx_AccessibleButton_kind_primary.mx_AccessibleButton_disabled {
color: $button-primary-disabled-fg-color;
background-color: $button-primary-disabled-bg-color;
}

View File

@ -1,6 +1,25 @@
.mx_GeneralSettingsTab_profile input { .mx_GeneralSettingsTab_profile {
display: block; display: flex;
font-size: 14px; }
padding: 5px;
border-radius: 4px; .mx_GeneralSettingsTab_profileControls {
flex-grow: 1;
}
.mx_GeneralSettingsTab_profileControls .mx_Field #profileDisplayName {
width: calc(100% - 20px); // subtract 10px padding on left and right
}
.mx_GeneralSettingsTab_profileAvatar {
width: 88px;
height: 88px;
margin-left: 13px;
}
.mx_GeneralSettingsTab_profileAvatar div {
display: block;
width: 88px;
height: 88px;
border-radius: 4px;
background-color: #ccc;
} }

View File

@ -200,6 +200,12 @@ $tab-label-active-bg-color: #7ac9a1;
$tab-label-icon-bg-color: #454545; $tab-label-icon-bg-color: #454545;
$tab-label-active-icon-bg-color: #ffffff; $tab-label-active-icon-bg-color: #ffffff;
// Buttons
$button-primary-fg-color: #ffffff;
$button-primary-bg-color: #7ac9a1;
$button-primary-disabled-fg-color: #ffffff;
$button-primary-disabled-bg-color: #bce4d0;
// unused? // unused?
$progressbar-color: #000; $progressbar-color: #000;

View File

@ -196,6 +196,12 @@ $tab-label-active-bg-color: #7ac9a1;
$tab-label-icon-bg-color: #454545; $tab-label-icon-bg-color: #454545;
$tab-label-active-icon-bg-color: #ffffff; $tab-label-active-icon-bg-color: #ffffff;
// Buttons
$button-primary-fg-color: #ffffff;
$button-primary-bg-color: #7ac9a1;
$button-primary-disabled-fg-color: #ffffff;
$button-primary-disabled-bg-color: #bce4d0;
// unused? // unused?
$progressbar-color: #000; $progressbar-color: #000;

View File

@ -39,7 +39,7 @@ export class Tab {
export class TabbedView extends React.Component { export class TabbedView extends React.Component {
static propTypes = { static propTypes = {
// The tabs to show // The tabs to show
tabs: PropTypes.arrayOf(Tab).isRequired, tabs: PropTypes.arrayOf(PropTypes.instanceOf(Tab)).isRequired,
}; };
constructor() { constructor() {
@ -74,6 +74,7 @@ export class TabbedView extends React.Component {
const idx = this.props.tabs.indexOf(tab); const idx = this.props.tabs.indexOf(tab);
if (idx === this._getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active"; if (idx === this._getActiveTabIndex()) classes += "mx_TabbedView_tabLabel_active";
if (tab.label === "Visit old settings") classes += "mx_TabbedView_tabLabel_TEMP_HACK";
let tabIcon = null; let tabIcon = null;
if (tab.icon) { if (tab.icon) {

View File

@ -28,7 +28,9 @@ import { KeyCode } from '../../../Keyboard';
* @returns {Object} rendered react * @returns {Object} rendered react
*/ */
export default function AccessibleButton(props) { export default function AccessibleButton(props) {
const {element, onClick, children, ...restProps} = props; const {element, onClick, children, kind, disabled, ...restProps} = props;
if (!disabled) {
restProps.onClick = onClick; restProps.onClick = onClick;
// We need to consume enter onKeyDown and space onKeyUp // We need to consume enter onKeyDown and space onKeyUp
// otherwise we are risking also activating other keyboard focusable elements // otherwise we are risking also activating other keyboard focusable elements
@ -37,7 +39,7 @@ export default function AccessibleButton(props) {
// And divs which we report as role button to assistive technologies. // And divs which we report as role button to assistive technologies.
// Browsers handle space and enter keypresses differently and we are only adjusting to the // Browsers handle space and enter keypresses differently and we are only adjusting to the
// inconsistencies here // inconsistencies here
restProps.onKeyDown = function(e) { restProps.onKeyDown = function (e) {
if (e.keyCode === KeyCode.ENTER) { if (e.keyCode === KeyCode.ENTER) {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
@ -48,7 +50,7 @@ export default function AccessibleButton(props) {
e.preventDefault(); e.preventDefault();
} }
}; };
restProps.onKeyUp = function(e) { restProps.onKeyUp = function (e) {
if (e.keyCode === KeyCode.SPACE) { if (e.keyCode === KeyCode.SPACE) {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
@ -59,10 +61,23 @@ export default function AccessibleButton(props) {
e.preventDefault(); e.preventDefault();
} }
}; };
}
restProps.tabIndex = restProps.tabIndex || "0"; restProps.tabIndex = restProps.tabIndex || "0";
restProps.role = "button"; restProps.role = "button";
restProps.className = (restProps.className ? restProps.className + " " : "") + restProps.className = (restProps.className ? restProps.className + " " : "") +
"mx_AccessibleButton"; "mx_AccessibleButton";
if (kind) {
// We apply a hasKind class to maintain backwards compatibility with
// buttons which might not know about kind and break
restProps.className += " mx_AccessibleButton_hasKind mx_AccessibleButton_kind_" + kind;
}
if (disabled) {
restProps.className += " mx_AccessibleButton_disabled";
}
return React.createElement(element, restProps, children); return React.createElement(element, restProps, children);
} }
@ -76,6 +91,12 @@ AccessibleButton.propTypes = {
children: PropTypes.node, children: PropTypes.node,
element: PropTypes.string, element: PropTypes.string,
onClick: PropTypes.func.isRequired, onClick: PropTypes.func.isRequired,
// The kind of button, similar to how Bootstrap works.
// See available classes for AccessibleButton for options.
kind: PropTypes.string,
disabled: PropTypes.bool,
}; };
AccessibleButton.defaultProps = { AccessibleButton.defaultProps = {

View File

@ -16,32 +16,82 @@ limitations under the License.
import React from 'react'; import React from 'react';
import {_t} from "../../../../languageHandler"; import {_t} from "../../../../languageHandler";
import MatrixClientPeg from "../../../../MatrixClientPeg";
import Field from "../../elements/Field";
import AccessibleButton from "../../elements/AccessibleButton";
export default class GeneralSettingsTab extends React.Component { export default class GeneralSettingsTab extends React.Component {
constructor() {
super();
const client = MatrixClientPeg.get();
this.state = {
userId: client.getUserId(),
displayName: client.getUser(client.getUserId()).displayName,
enableProfileSave: false,
};
}
_saveProfile = async (e) => {
e.stopPropagation();
e.preventDefault();
if (!this.state.enableProfileSave) return;
this.setState({enableProfileSave: false});
// TODO: What do we do about errors?
await MatrixClientPeg.get().setDisplayName(this.state.displayName);
// TODO: Support avatars
this.setState({enableProfileSave: true});
};
_onDisplayNameChanged = (e) => {
this.setState({
displayName: e.target.value,
enableProfileSave: true,
});
};
_renderProfileSection() {
const form = (
<form onSubmit={this._saveProfile} autoComplete={false} noValidate={true}>
<div className="mx_GeneralSettingsTab_profile">
<div className="mx_GeneralSettingsTab_profileControls">
<p className="mx_GeneralSettingsTab_profileUsername">{this.state.userId}</p>
<Field id="profileDisplayName" label={_t("Display Name")}
type="text" value={this.state.displayName} autocomplete="off"
onChange={this._onDisplayNameChanged}
/>
</div>
<div className="mx_GeneralSettingsTab_profileAvatar">
{/*TODO: Ditch avatar placeholder and use the real thing*/}
<div/>
</div>
</div>
<AccessibleButton onClick={this._saveProfile} kind="primary"
disabled={!this.state.enableProfileSave}
>
{_t("Save")}
</AccessibleButton>
</form>
);
return (
<div className="mx_SettingsTab_section">
<span className="mx_SettingsTab_subheading">{_t("Profile")}</span>
{form}
</div>
);
}
render() { render() {
return ( return (
<div className="mx_SettingsTab"> <div className="mx_SettingsTab">
<div className="mx_SettingsTab_heading">{_t("General")}</div> <div className="mx_SettingsTab_heading">{_t("General")}</div>
<div className="mx_GeneralSettingsTab_profile mx_SettingsTab_section"> {this._renderProfileSection()}
<span className="mx_SettingsTab_subheading">{_t("Profile")}</span>
<input type="text" value="travis"/>
<input type="text" value="TravisR"/>
</div>
<div className="mx_GeneralSettingsTab_profile mx_SettingsTab_section">
<span className="mx_SettingsTab_subheading">{_t("Profile")}</span>
<input type="text" value="travis"/>
<input type="text" value="TravisR"/>
</div>
<div className="mx_GeneralSettingsTab_profile mx_SettingsTab_section">
<span className="mx_SettingsTab_subheading">{_t("Profile")}</span>
<input type="text" value="travis"/>
<input type="text" value="TravisR"/>
</div>
<div className="mx_GeneralSettingsTab_profile mx_SettingsTab_section">
<span className="mx_SettingsTab_subheading">{_t("Profile")}</span>
<input type="text" value="travis"/>
<input type="text" value="TravisR"/>
</div>
</div> </div>
); );
} }

View File

@ -403,6 +403,7 @@
"Noisy": "Noisy", "Noisy": "Noisy",
"General": "General", "General": "General",
"Profile": "Profile", "Profile": "Profile",
"Display Name": "Display Name",
"Cannot add any more widgets": "Cannot add any more widgets", "Cannot add any more widgets": "Cannot add any more widgets",
"The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.", "The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.",
"Add a widget": "Add a widget", "Add a widget": "Add a widget",