From c90e224349eb6105ef1d3ecf20c519238ba5e018 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 5 Feb 2016 11:29:03 -0500 Subject: Remove appearance settings tab and move theme management to display settings tab --- .../user_settings/custom_theme_chooser.jsx | 8 +- .../user_settings/premade_theme_chooser.jsx | 2 +- .../components/user_settings/user_settings.jsx | 18 +- .../user_settings/user_settings_appearance.jsx | 295 -------------------- .../user_settings/user_settings_display.jsx | 24 +- .../user_settings/user_settings_modal.jsx | 19 +- .../user_settings/user_settings_theme.jsx | 301 +++++++++++++++++++++ 7 files changed, 337 insertions(+), 330 deletions(-) delete mode 100644 web/react/components/user_settings/user_settings_appearance.jsx create mode 100644 web/react/components/user_settings/user_settings_theme.jsx (limited to 'web/react/components/user_settings') diff --git a/web/react/components/user_settings/custom_theme_chooser.jsx b/web/react/components/user_settings/custom_theme_chooser.jsx index 9116dd938..2d88a3650 100644 --- a/web/react/components/user_settings/custom_theme_chooser.jsx +++ b/web/react/components/user_settings/custom_theme_chooser.jsx @@ -222,7 +222,7 @@ class CustomThemeChooser extends React.Component { } else { elements.push(
@@ -265,8 +265,8 @@ class CustomThemeChooser extends React.Component { ); return ( -
-
+
+
{elements}
@@ -283,4 +283,4 @@ CustomThemeChooser.propTypes = { updateTheme: React.PropTypes.func.isRequired }; -export default injectIntl(CustomThemeChooser); \ No newline at end of file +export default injectIntl(CustomThemeChooser); diff --git a/web/react/components/user_settings/premade_theme_chooser.jsx b/web/react/components/user_settings/premade_theme_chooser.jsx index 9889bff5c..80ff8c4de 100644 --- a/web/react/components/user_settings/premade_theme_chooser.jsx +++ b/web/react/components/user_settings/premade_theme_chooser.jsx @@ -45,7 +45,7 @@ export default class PremadeThemeChooser extends React.Component { } return ( -
+
{premadeThemes}
); diff --git a/web/react/components/user_settings/user_settings.jsx b/web/react/components/user_settings/user_settings.jsx index 54d98bbde..4da51fa5f 100644 --- a/web/react/components/user_settings/user_settings.jsx +++ b/web/react/components/user_settings/user_settings.jsx @@ -6,7 +6,6 @@ import * as utils from '../../utils/utils.jsx'; import NotificationsTab from './user_settings_notifications.jsx'; import SecurityTab from './user_settings_security.jsx'; import GeneralTab from './user_settings_general.jsx'; -import AppearanceTab from './user_settings_appearance.jsx'; import DeveloperTab from './user_settings_developer.jsx'; import IntegrationsTab from './user_settings_integrations.jsx'; import DisplayTab from './user_settings_display.jsx'; @@ -85,21 +84,6 @@ export default class UserSettings extends React.Component { />
); - } else if (this.props.activeTab === 'appearance') { - return ( -
- -
- ); } else if (this.props.activeTab === 'developer') { return (
@@ -137,6 +121,8 @@ export default class UserSettings extends React.Component { updateTab={this.props.updateTab} closeModal={this.props.closeModal} collapseModal={this.props.collapseModal} + setEnforceFocus={this.props.setEnforceFocus} + setRequireConfirm={this.props.setRequireConfirm} />
); diff --git a/web/react/components/user_settings/user_settings_appearance.jsx b/web/react/components/user_settings/user_settings_appearance.jsx deleted file mode 100644 index fb11dc81b..000000000 --- a/web/react/components/user_settings/user_settings_appearance.jsx +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import CustomThemeChooser from './custom_theme_chooser.jsx'; -import PremadeThemeChooser from './premade_theme_chooser.jsx'; - -import UserStore from '../../stores/user_store.jsx'; - -import AppDispatcher from '../../dispatcher/app_dispatcher.jsx'; -import * as Client from '../../utils/client.jsx'; -import * as Utils from '../../utils/utils.jsx'; - -import Constants from '../../utils/constants.jsx'; - -import {FormattedMessage} from 'mm-intl'; - -const ActionTypes = Constants.ActionTypes; - -export default class UserSettingsAppearance extends React.Component { - constructor(props) { - super(props); - - this.onChange = this.onChange.bind(this); - this.submitTheme = this.submitTheme.bind(this); - this.updateTheme = this.updateTheme.bind(this); - this.deactivate = this.deactivate.bind(this); - this.resetFields = this.resetFields.bind(this); - this.handleImportModal = this.handleImportModal.bind(this); - - this.state = this.getStateFromStores(); - - this.originalTheme = Object.assign({}, this.state.theme); - } - componentDidMount() { - UserStore.addChangeListener(this.onChange); - - if (this.props.activeSection === 'theme') { - $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border'); - } - } - componentDidUpdate() { - if (this.props.activeSection === 'theme') { - $('.color-btn').removeClass('active-border'); - $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border'); - } - } - componentWillUnmount() { - UserStore.removeChangeListener(this.onChange); - } - getStateFromStores() { - const user = UserStore.getCurrentUser(); - let theme = null; - - if ($.isPlainObject(user.theme_props) && !$.isEmptyObject(user.theme_props)) { - theme = Object.assign({}, user.theme_props); - } else { - theme = $.extend(true, {}, Constants.THEMES.default); - } - - let type = 'premade'; - if (theme.type === 'custom') { - type = 'custom'; - } - - if (!theme.codeTheme) { - theme.codeTheme = Constants.DEFAULT_CODE_THEME; - } - - return {theme, type}; - } - onChange() { - const newState = this.getStateFromStores(); - - if (!Utils.areObjectsEqual(this.state, newState)) { - this.setState(newState); - } - - this.props.setEnforceFocus(true); - } - scrollToTop() { - $('.ps-container.modal-body').scrollTop(0); - $('.ps-container.modal-body').perfectScrollbar('update'); - } - submitTheme(e) { - e.preventDefault(); - var user = UserStore.getCurrentUser(); - user.theme_props = this.state.theme; - - Client.updateUser(user, - (data) => { - AppDispatcher.handleServerAction({ - type: ActionTypes.RECIEVED_ME, - me: data - }); - - this.props.setRequireConfirm(false); - this.originalTheme = Object.assign({}, this.state.theme); - this.scrollToTop(); - }, - (err) => { - var state = this.getStateFromStores(); - state.serverError = err; - this.setState(state); - } - ); - } - updateTheme(theme) { - let themeChanged = this.state.theme.length === theme.length; - if (!themeChanged) { - for (const field in theme) { - if (theme.hasOwnProperty(field)) { - if (this.state.theme[field] !== theme[field]) { - themeChanged = true; - break; - } - } - } - } - - this.props.setRequireConfirm(themeChanged); - - this.setState({theme}); - Utils.applyTheme(theme); - } - updateType(type) { - this.setState({type}); - } - deactivate() { - const state = this.getStateFromStores(); - - Utils.applyTheme(state.theme); - } - resetFields() { - const state = this.getStateFromStores(); - state.serverError = null; - this.setState(state); - this.scrollToTop(); - - Utils.applyTheme(state.theme); - - this.props.setRequireConfirm(false); - } - handleImportModal() { - AppDispatcher.handleViewAction({ - type: ActionTypes.TOGGLE_IMPORT_THEME_MODAL, - value: true - }); - - this.props.setEnforceFocus(false); - } - render() { - var serverError; - if (this.state.serverError) { - serverError = this.state.serverError; - } - - const displayCustom = this.state.type === 'custom'; - - let custom; - let premade; - if (displayCustom) { - custom = ( - - ); - } else { - premade = ( - - ); - } - - const themeUI = ( -
-
-
- -
-
- {premade} -
- -
-
- {custom} -
- {serverError} - - - - - - -
-
- ); - - return ( -
-
- -

- - -

-
-
-

- -

-
- {themeUI} -
-
- - - -
-
- ); - } -} - -UserSettingsAppearance.defaultProps = { - activeSection: '' -}; -UserSettingsAppearance.propTypes = { - activeSection: React.PropTypes.string, - updateTab: React.PropTypes.func, - closeModal: React.PropTypes.func.isRequired, - collapseModal: React.PropTypes.func.isRequired, - setRequireConfirm: React.PropTypes.func.isRequired, - setEnforceFocus: React.PropTypes.func.isRequired -}; diff --git a/web/react/components/user_settings/user_settings_display.jsx b/web/react/components/user_settings/user_settings_display.jsx index 776bde442..4b11c06fb 100644 --- a/web/react/components/user_settings/user_settings_display.jsx +++ b/web/react/components/user_settings/user_settings_display.jsx @@ -1,15 +1,18 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import {savePreferences} from '../../utils/client.jsx'; import SettingItemMin from '../setting_item_min.jsx'; import SettingItemMax from '../setting_item_max.jsx'; -import Constants from '../../utils/constants.jsx'; -const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES; -import PreferenceStore from '../../stores/preference_store.jsx'; import ManageLanguages from './manage_languages.jsx'; +import ThemeSetting from './user_settings_theme.jsx'; + +import PreferenceStore from '../../stores/preference_store.jsx'; import * as Utils from '../../utils/utils.jsx'; +import Constants from '../../utils/constants.jsx'; +const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES; + +import {savePreferences} from '../../utils/client.jsx'; import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl'; const holders = defineMessages({ @@ -452,6 +455,13 @@ class UserSettingsDisplay extends React.Component { />
+ +
{fontSection}
{clockSection} @@ -472,7 +482,9 @@ UserSettingsDisplay.propTypes = { updateTab: React.PropTypes.func, activeSection: React.PropTypes.string, closeModal: React.PropTypes.func.isRequired, - collapseModal: React.PropTypes.func.isRequired + collapseModal: React.PropTypes.func.isRequired, + setRequireConfirm: React.PropTypes.func.isRequired, + setEnforceFocus: React.PropTypes.func.isRequired }; -export default injectIntl(UserSettingsDisplay); \ No newline at end of file +export default injectIntl(UserSettingsDisplay); diff --git a/web/react/components/user_settings/user_settings_modal.jsx b/web/react/components/user_settings/user_settings_modal.jsx index 2a0a90cf5..57796d559 100644 --- a/web/react/components/user_settings/user_settings_modal.jsx +++ b/web/react/components/user_settings/user_settings_modal.jsx @@ -2,9 +2,13 @@ // See License.txt for license information. import ConfirmModal from '../confirm_modal.jsx'; -const Modal = ReactBootstrap.Modal; -import SettingsSidebar from '../settings_sidebar.jsx'; import UserSettings from './user_settings.jsx'; +import SettingsSidebar from '../settings_sidebar.jsx'; + +import UserStore from '../../stores/user_store.jsx'; +import * as Utils from '../../utils/utils.jsx'; + +const Modal = ReactBootstrap.Modal; import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl'; @@ -21,10 +25,6 @@ const holders = defineMessages({ id: 'user.settings.modal.notifications', defaultMessage: 'Notifications' }, - appearance: { - id: 'user.settings.modal.appearance', - defaultMessage: 'Appearance' - }, developer: { id: 'user.settings.modal.developer', defaultMessage: 'Developer' @@ -214,6 +214,10 @@ class UserSettingsModal extends React.Component { if (!skipConfirm && this.requireConfirm) { this.showConfirmModal(() => this.updateSection(section, true)); } else { + if (this.state.active_section === 'theme' && section !== 'theme') { + const user = UserStore.getCurrentUser(); + Utils.applyTheme(user.theme_props); + } this.setState({active_section: section}); } } @@ -224,7 +228,6 @@ class UserSettingsModal extends React.Component { tabs.push({name: 'general', uiName: formatMessage(holders.general), icon: 'glyphicon glyphicon-cog'}); tabs.push({name: 'security', uiName: formatMessage(holders.security), icon: 'glyphicon glyphicon-lock'}); tabs.push({name: 'notifications', uiName: formatMessage(holders.notifications), icon: 'glyphicon glyphicon-exclamation-sign'}); - tabs.push({name: 'appearance', uiName: formatMessage(holders.appearance), icon: 'glyphicon glyphicon-wrench'}); if (global.window.mm_config.EnableOAuthServiceProvider === 'true') { tabs.push({name: 'developer', uiName: formatMessage(holders.developer), icon: 'glyphicon glyphicon-th'}); } @@ -294,4 +297,4 @@ UserSettingsModal.propTypes = { onModalDismissed: React.PropTypes.func.isRequired }; -export default injectIntl(UserSettingsModal); \ No newline at end of file +export default injectIntl(UserSettingsModal); diff --git a/web/react/components/user_settings/user_settings_theme.jsx b/web/react/components/user_settings/user_settings_theme.jsx new file mode 100644 index 000000000..a0656feaa --- /dev/null +++ b/web/react/components/user_settings/user_settings_theme.jsx @@ -0,0 +1,301 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import CustomThemeChooser from './custom_theme_chooser.jsx'; +import PremadeThemeChooser from './premade_theme_chooser.jsx'; +import SettingItemMin from '../setting_item_min.jsx'; +import SettingItemMax from '../setting_item_max.jsx'; + +import UserStore from '../../stores/user_store.jsx'; + +import AppDispatcher from '../../dispatcher/app_dispatcher.jsx'; +import * as Client from '../../utils/client.jsx'; +import * as Utils from '../../utils/utils.jsx'; + +import Constants from '../../utils/constants.jsx'; + +import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl'; + +const ActionTypes = Constants.ActionTypes; + +const holders = defineMessages({ + themeTitle: { + id: 'user.settings.display.theme.title', + defaultMessage: 'Theme' + }, + themeDescribe: { + id: 'user.settings.display.theme.describe', + defaultMessage: 'Open to manage your theme' + } +}); + +export default class ThemeSetting extends React.Component { + constructor(props) { + super(props); + + this.onChange = this.onChange.bind(this); + this.submitTheme = this.submitTheme.bind(this); + this.updateTheme = this.updateTheme.bind(this); + this.deactivate = this.deactivate.bind(this); + this.resetFields = this.resetFields.bind(this); + this.handleImportModal = this.handleImportModal.bind(this); + + this.state = this.getStateFromStores(); + + this.originalTheme = Object.assign({}, this.state.theme); + } + componentDidMount() { + UserStore.addChangeListener(this.onChange); + + if (this.props.selected) { + $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border'); + } + } + componentDidUpdate() { + if (this.props.selected) { + $('.color-btn').removeClass('active-border'); + $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border'); + } + } + componentWillReceiveProps(nextProps) { + if (!this.props.selected && nextProps.selected) { + this.resetFields(); + } + } + componentWillUnmount() { + UserStore.removeChangeListener(this.onChange); + } + getStateFromStores() { + const user = UserStore.getCurrentUser(); + let theme = null; + + if ($.isPlainObject(user.theme_props) && !$.isEmptyObject(user.theme_props)) { + theme = Object.assign({}, user.theme_props); + } else { + theme = $.extend(true, {}, Constants.THEMES.default); + } + + let type = 'premade'; + if (theme.type === 'custom') { + type = 'custom'; + } + + if (!theme.codeTheme) { + theme.codeTheme = Constants.DEFAULT_CODE_THEME; + } + + return {theme, type}; + } + onChange() { + const newState = this.getStateFromStores(); + + if (!Utils.areObjectsEqual(this.state, newState)) { + this.setState(newState); + } + + this.props.setEnforceFocus(true); + } + scrollToTop() { + $('.ps-container.modal-body').scrollTop(0); + $('.ps-container.modal-body').perfectScrollbar('update'); + } + submitTheme(e) { + e.preventDefault(); + var user = UserStore.getCurrentUser(); + user.theme_props = this.state.theme; + + Client.updateUser(user, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECIEVED_ME, + me: data + }); + + this.props.setRequireConfirm(false); + this.originalTheme = Object.assign({}, this.state.theme); + this.scrollToTop(); + this.props.updateSection(''); + }, + (err) => { + var state = this.getStateFromStores(); + state.serverError = err; + this.setState(state); + } + ); + } + updateTheme(theme) { + let themeChanged = this.state.theme.length === theme.length; + if (!themeChanged) { + for (const field in theme) { + if (theme.hasOwnProperty(field)) { + if (this.state.theme[field] !== theme[field]) { + themeChanged = true; + break; + } + } + } + } + + this.props.setRequireConfirm(themeChanged); + + this.setState({theme}); + Utils.applyTheme(theme); + } + updateType(type) { + this.setState({type}); + } + deactivate() { + const state = this.getStateFromStores(); + + Utils.applyTheme(state.theme); + } + resetFields() { + const state = this.getStateFromStores(); + state.serverError = null; + this.setState(state); + this.scrollToTop(); + + Utils.applyTheme(state.theme); + + this.props.setRequireConfirm(false); + } + handleImportModal() { + AppDispatcher.handleViewAction({ + type: ActionTypes.TOGGLE_IMPORT_THEME_MODAL, + value: true + }); + + this.props.setEnforceFocus(false); + } + render() { + const {formatMessage} = this.props.intl; + + var serverError; + if (this.state.serverError) { + serverError = this.state.serverError; + } + + const displayCustom = this.state.type === 'custom'; + + let custom; + let premade; + if (displayCustom) { + custom = ( +
+
+ +
+ ); + } else { + premade = ( +
+
+ +
+ ); + } + + let themeUI; + if (this.props.selected) { + let inputs = []; + + inputs.push( +
+ +
+
+ ); + + inputs.push(premade); + + inputs.push( +
+ +
+
+ ); + + inputs.push(custom); + + inputs.push( +
+
+ + + +
+ ); + + themeUI = ( + { + this.props.updateSection(''); + e.preventDefault(); + }} + /> + ); + } else { + themeUI = ( + { + this.props.updateSection('theme'); + }} + /> + ); + } + + return themeUI; + } +} + +ThemeSetting.propTypes = { + intl: intlShape.isRequired, + selected: React.PropTypes.bool.isRequired, + updateSection: React.PropTypes.func.isRequired, + setRequireConfirm: React.PropTypes.func.isRequired, + setEnforceFocus: React.PropTypes.func.isRequired +}; + +export default injectIntl(ThemeSetting); -- cgit v1.2.3-1-g7c22 From 39b35b7b394cdc2391beaff8b96cd733400ebcb8 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 8 Feb 2016 07:28:04 -0500 Subject: Fix cancel bug --- web/react/components/user_settings/user_settings_modal.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'web/react/components/user_settings') diff --git a/web/react/components/user_settings/user_settings_modal.jsx b/web/react/components/user_settings/user_settings_modal.jsx index 57796d559..e0b72157b 100644 --- a/web/react/components/user_settings/user_settings_modal.jsx +++ b/web/react/components/user_settings/user_settings_modal.jsx @@ -216,7 +216,9 @@ class UserSettingsModal extends React.Component { } else { if (this.state.active_section === 'theme' && section !== 'theme') { const user = UserStore.getCurrentUser(); - Utils.applyTheme(user.theme_props); + if (user.theme_props != null) { + Utils.applyTheme(user.theme_props); + } } this.setState({active_section: section}); } -- cgit v1.2.3-1-g7c22