UX polish for custom themes

This commit is contained in:
Travis Ralston 2020-03-06 17:43:10 -07:00
parent 65d7bb2ef9
commit 6aeca7b853
3 changed files with 46 additions and 21 deletions

View file

@ -42,10 +42,15 @@ pre, code {
font-size: 100% !important; font-size: 100% !important;
} }
.error, .warning { .error, .warning,
.text-error, .text-warning {
color: $warning-color; color: $warning-color;
} }
.text-success {
color: $accent-color;
}
b { b {
// On Firefox, the default weight for `<b>` is `bolder` which results in no bold // On Firefox, the default weight for `<b>` is `bolder` which results in no bold
// effect since we only have specific weights of our fonts available. // effect since we only have specific weights of our fonts available.

View file

@ -62,7 +62,7 @@ export default class GeneralUserSettingsTab extends React.Component {
msisdns: [], msisdns: [],
...this._calculateThemeState(), ...this._calculateThemeState(),
customThemeUrl: "", customThemeUrl: "",
customThemeError: "", customThemeMessage: {isError: false, text: ""},
}; };
this.dispatcherRef = dis.register(this._onAction); this.dispatcherRef = dis.register(this._onAction);
@ -281,22 +281,30 @@ export default class GeneralUserSettingsTab extends React.Component {
if (!currentThemes) currentThemes = []; if (!currentThemes) currentThemes = [];
currentThemes = currentThemes.map(c => c); // cheap clone currentThemes = currentThemes.map(c => c); // cheap clone
if (this._themeTimer) {
clearTimeout(this._themeTimer);
}
try { try {
const r = await fetch(this.state.customThemeUrl); const r = await fetch(this.state.customThemeUrl);
const themeInfo = await r.json(); const themeInfo = await r.json();
if (!themeInfo || typeof(themeInfo['name']) !== 'string' || typeof(themeInfo['colors']) !== 'object') { if (!themeInfo || typeof(themeInfo['name']) !== 'string' || typeof(themeInfo['colors']) !== 'object') {
console.log(themeInfo); this.setState({customThemeMessage: {text: _t("Invalid theme schema."), isError: true}});
this.setState({customThemeError: _t("Invalid theme schema.")});
return; return;
} }
currentThemes.push(themeInfo); currentThemes.push(themeInfo);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
this.setState({customThemeError: _t("Error downloading theme information.")}); this.setState({customThemeMessage: {text: _t("Error downloading theme information."), isError: true}});
return; // Don't continue on error
} }
await SettingsStore.setValue("custom_themes", null, SettingLevel.ACCOUNT, currentThemes); await SettingsStore.setValue("custom_themes", null, SettingLevel.ACCOUNT, currentThemes);
this.setState({customThemeUrl: "", customThemeError: ""}); this.setState({customThemeUrl: "", customThemeMessage: {text: _t("Theme added!"), isError: false}});
this._themeTimer = setTimeout(() => {
this.setState({customThemeMessage: {text: "", isError: false}});
}, 3000);
}; };
_onCustomThemeChange = (e) => { _onCustomThemeChange = (e) => {
@ -400,22 +408,33 @@ export default class GeneralUserSettingsTab extends React.Component {
let customThemeForm; let customThemeForm;
if (SettingsStore.isFeatureEnabled("feature_custom_themes")) { if (SettingsStore.isFeatureEnabled("feature_custom_themes")) {
let messageElement = null;
if (this.state.customThemeMessage.text) {
if (this.state.customThemeMessage.isError) {
messageElement = <div className='text-error'>{this.state.customThemeMessage.text}</div>;
} else {
messageElement = <div className='text-success'>{this.state.customThemeMessage.text}</div>;
}
}
customThemeForm = ( customThemeForm = (
<form onSubmit={this._onAddCustomTheme}> <div className='mx_SettingsTab_section'>
<Field <form onSubmit={this._onAddCustomTheme}>
label={_t("Custom theme URL")} <Field
type='text' label={_t("Custom theme URL")}
id='mx_GeneralUserSettingsTab_customThemeInput' type='text'
autoComplete="off" id='mx_GeneralUserSettingsTab_customThemeInput'
onChange={this._onCustomThemeChange} autoComplete="off"
value={this.state.customThemeUrl} onChange={this._onCustomThemeChange}
/> value={this.state.customThemeUrl}
<div className='error'>{this.state.customThemeError}</div> />
<AccessibleButton <AccessibleButton
onClick={this._onAddCustomTheme} onClick={this._onAddCustomTheme}
type="submit" kind="primary_sm" type="submit" kind="primary_sm"
>{_t("Add theme")}</AccessibleButton> disabled={!this.state.customThemeUrl.trim()}
</form> >{_t("Add theme")}</AccessibleButton>
{messageElement}
</form>
</div>
); );
} }

View file

@ -706,6 +706,7 @@
"Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them", "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them",
"Invalid theme schema.": "Invalid theme schema.", "Invalid theme schema.": "Invalid theme schema.",
"Error downloading theme information.": "Error downloading theme information.", "Error downloading theme information.": "Error downloading theme information.",
"Theme added!": "Theme added!",
"Profile": "Profile", "Profile": "Profile",
"Email addresses": "Email addresses", "Email addresses": "Email addresses",
"Phone numbers": "Phone numbers", "Phone numbers": "Phone numbers",