summaryrefslogtreecommitdiffstats
path: root/webapp/components/user_settings/custom_theme_chooser.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/components/user_settings/custom_theme_chooser.jsx')
-rw-r--r--webapp/components/user_settings/custom_theme_chooser.jsx394
1 files changed, 394 insertions, 0 deletions
diff --git a/webapp/components/user_settings/custom_theme_chooser.jsx b/webapp/components/user_settings/custom_theme_chooser.jsx
new file mode 100644
index 000000000..9fbdd1251
--- /dev/null
+++ b/webapp/components/user_settings/custom_theme_chooser.jsx
@@ -0,0 +1,394 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import $ from 'jquery';
+import Constants from 'utils/constants.jsx';
+import 'bootstrap-colorpicker';
+
+import {Popover, OverlayTrigger} from 'react-bootstrap';
+
+import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl';
+
+const messages = defineMessages({
+ sidebarBg: {
+ id: 'user.settings.custom_theme.sidebarBg',
+ defaultMessage: 'Sidebar BG'
+ },
+ sidebarText: {
+ id: 'user.settings.custom_theme.sidebarText',
+ defaultMessage: 'Sidebar Text'
+ },
+ sidebarHeaderBg: {
+ id: 'user.settings.custom_theme.sidebarHeaderBg',
+ defaultMessage: 'Sidebar Header BG'
+ },
+ sidebarHeaderTextColor: {
+ id: 'user.settings.custom_theme.sidebarHeaderTextColor',
+ defaultMessage: 'Sidebar Header Text'
+ },
+ sidebarUnreadText: {
+ id: 'user.settings.custom_theme.sidebarUnreadText',
+ defaultMessage: 'Sidebar Unread Text'
+ },
+ sidebarTextHoverBg: {
+ id: 'user.settings.custom_theme.sidebarTextHoverBg',
+ defaultMessage: 'Sidebar Text Hover BG'
+ },
+ sidebarTextActiveBorder: {
+ id: 'user.settings.custom_theme.sidebarTextActiveBorder',
+ defaultMessage: 'Sidebar Text Active Border'
+ },
+ sidebarTextActiveColor: {
+ id: 'user.settings.custom_theme.sidebarTextActiveColor',
+ defaultMessage: 'Sidebar Text Active Color'
+ },
+ onlineIndicator: {
+ id: 'user.settings.custom_theme.onlineIndicator',
+ defaultMessage: 'Online Indicator'
+ },
+ awayIndicator: {
+ id: 'user.settings.custom_theme.awayIndicator',
+ defaultMessage: 'Away Indicator'
+ },
+ mentionBj: {
+ id: 'user.settings.custom_theme.mentionBj',
+ defaultMessage: 'Mention Jewel BG'
+ },
+ mentionColor: {
+ id: 'user.settings.custom_theme.mentionColor',
+ defaultMessage: 'Mention Jewel Text'
+ },
+ centerChannelBg: {
+ id: 'user.settings.custom_theme.centerChannelBg',
+ defaultMessage: 'Center Channel BG'
+ },
+ centerChannelColor: {
+ id: 'user.settings.custom_theme.centerChannelColor',
+ defaultMessage: 'Center Channel Text'
+ },
+ newMessageSeparator: {
+ id: 'user.settings.custom_theme.newMessageSeparator',
+ defaultMessage: 'New Message Separator'
+ },
+ linkColor: {
+ id: 'user.settings.custom_theme.linkColor',
+ defaultMessage: 'Link Color'
+ },
+ buttonBg: {
+ id: 'user.settings.custom_theme.buttonBg',
+ defaultMessage: 'Button BG'
+ },
+ buttonColor: {
+ id: 'user.settings.custom_theme.buttonColor',
+ defaultMessage: 'Button Text'
+ },
+ mentionHighlightBg: {
+ id: 'user.settings.custom_theme.mentionHighlightBg',
+ defaultMessage: 'Mention Highlight BG'
+ },
+ mentionHighlightLink: {
+ id: 'user.settings.custom_theme.mentionHighlightLink',
+ defaultMessage: 'Mention Highlight Link'
+ },
+ codeTheme: {
+ id: 'user.settings.custom_theme.codeTheme',
+ defaultMessage: 'Code Theme'
+ }
+});
+
+import React from 'react';
+
+class CustomThemeChooser extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onPickerChange = this.onPickerChange.bind(this);
+ this.onInputChange = this.onInputChange.bind(this);
+ this.pasteBoxChange = this.pasteBoxChange.bind(this);
+ this.toggleContent = this.toggleContent.bind(this);
+
+ this.state = {};
+ }
+ componentDidMount() {
+ $('.color-picker').colorpicker({
+ format: 'hex'
+ });
+ $('.color-picker').on('changeColor', this.onPickerChange);
+ }
+ componentDidUpdate() {
+ const theme = this.props.theme;
+ Constants.THEME_ELEMENTS.forEach((element) => {
+ if (theme.hasOwnProperty(element.id) && element.id !== 'codeTheme') {
+ $('#' + element.id).data('colorpicker').color.setColor(theme[element.id]);
+ $('#' + element.id).colorpicker('update');
+ }
+ });
+ }
+ onPickerChange(e) {
+ const theme = this.props.theme;
+ theme[e.target.id] = e.color.toHex();
+ theme.type = 'custom';
+ this.props.updateTheme(theme);
+ }
+ onInputChange(e) {
+ const theme = this.props.theme;
+ theme[e.target.parentNode.id] = e.target.value;
+ theme.type = 'custom';
+ this.props.updateTheme(theme);
+ }
+ pasteBoxChange(e) {
+ const text = e.target.value;
+
+ if (text.length === 0) {
+ return;
+ }
+
+ const colors = text.split(',');
+
+ const theme = {type: 'custom'};
+ let index = 0;
+ Constants.THEME_ELEMENTS.forEach((element) => {
+ if (index < colors.length - 1) {
+ theme[element.id] = colors[index];
+ }
+ index++;
+ });
+ theme.codeTheme = colors[colors.length - 1];
+
+ this.props.updateTheme(theme);
+ }
+ toggleContent(e) {
+ e.stopPropagation();
+ if ($(e.target).hasClass('theme-elements__header')) {
+ $(e.target).next().slideToggle();
+ $(e.target).toggleClass('open');
+ } else {
+ $(e.target).closest('.theme-elements__header').next().slideToggle();
+ $(e.target).closest('.theme-elements__header').toggleClass('open');
+ }
+ }
+ render() {
+ const {formatMessage} = this.props.intl;
+ const theme = this.props.theme;
+
+ const sidebarElements = [];
+ const centerChannelElements = [];
+ const linkAndButtonElements = [];
+ let colors = '';
+ Constants.THEME_ELEMENTS.forEach((element, index) => {
+ if (element.id === 'codeTheme') {
+ const codeThemeOptions = [];
+ let codeThemeURL = '';
+
+ element.themes.forEach((codeTheme, codeThemeIndex) => {
+ if (codeTheme.id === theme[element.id]) {
+ codeThemeURL = codeTheme.iconURL;
+ }
+ codeThemeOptions.push(
+ <option
+ key={'code-theme-key' + codeThemeIndex}
+ value={codeTheme.id}
+ >
+ {codeTheme.uiName}
+ </option>
+ );
+ });
+
+ var popoverContent = (
+ <Popover
+ bsStyle='info'
+ id='code-popover'
+ className='code-popover'
+ >
+ <img
+ width='200'
+ src={codeThemeURL}
+ />
+ </Popover>
+ );
+
+ centerChannelElements.push(
+ <div
+ className='col-sm-6 form-group'
+ key={'custom-theme-key' + index}
+ >
+ <label className='custom-label'>{formatMessage(messages[element.id])}</label>
+ <div
+ className='input-group theme-group group--code dropdown'
+ id={element.id}
+ >
+ <select
+ className='form-control'
+ type='text'
+ value={theme[element.id]}
+ onChange={this.onInputChange}
+ >
+ {codeThemeOptions}
+ </select>
+ <OverlayTrigger
+ placement='top'
+ overlay={popoverContent}
+ ref='headerOverlay'
+ >
+ <span className='input-group-addon'>
+ <img
+ src={codeThemeURL}
+ />
+ </span>
+ </OverlayTrigger>
+ </div>
+ </div>
+ );
+ } else if (element.group === 'centerChannelElements') {
+ centerChannelElements.push(
+ <div
+ className='col-sm-6 form-group element'
+ key={'custom-theme-key' + index}
+ >
+ <label className='custom-label'>{formatMessage(messages[element.id])}</label>
+ <div
+ className='input-group color-picker'
+ id={element.id}
+ >
+ <input
+ className='form-control'
+ type='text'
+ value={theme[element.id]}
+ onChange={this.onInputChange}
+ />
+ <span className='input-group-addon'><i></i></span>
+ </div>
+ </div>
+ );
+
+ colors += theme[element.id] + ',';
+ } else if (element.group === 'sidebarElements') {
+ sidebarElements.push(
+ <div
+ className='col-sm-6 form-group element'
+ key={'custom-theme-key' + index}
+ >
+ <label className='custom-label'>{formatMessage(messages[element.id])}</label>
+ <div
+ className='input-group color-picker'
+ id={element.id}
+ >
+ <input
+ className='form-control'
+ type='text'
+ value={theme[element.id]}
+ onChange={this.onInputChange}
+ />
+ <span className='input-group-addon'><i></i></span>
+ </div>
+ </div>
+ );
+
+ colors += theme[element.id] + ',';
+ } else {
+ linkAndButtonElements.push(
+ <div
+ className='col-sm-6 form-group element'
+ key={'custom-theme-key' + index}
+ >
+ <label className='custom-label'>{formatMessage(messages[element.id])}</label>
+ <div
+ className='input-group color-picker'
+ id={element.id}
+ >
+ <input
+ className='form-control'
+ type='text'
+ value={theme[element.id]}
+ onChange={this.onInputChange}
+ />
+ <span className='input-group-addon'><i></i></span>
+ </div>
+ </div>
+ );
+
+ colors += theme[element.id] + ',';
+ }
+ });
+
+ colors += theme.codeTheme;
+
+ const pasteBox = (
+ <div className='col-sm-12'>
+ <label className='custom-label'>
+ <FormattedMessage
+ id='user.settings.custom_theme.copyPaste'
+ defaultMessage='Copy and paste to share theme colors:'
+ />
+ </label>
+ <input
+ type='text'
+ className='form-control'
+ value={colors}
+ onChange={this.pasteBoxChange}
+ />
+ </div>
+ );
+
+ return (
+ <div className='appearance-section padding-top'>
+ <div className='theme-elements row'>
+ <div
+ className='theme-elements__header'
+ onClick={this.toggleContent}
+ >
+ {'Sidebar Styles'}
+ <div className='header__icon'>
+ <i className='fa fa-plus'></i>
+ <i className='fa fa-minus'></i>
+ </div>
+ </div>
+ <div className='theme-elements__body'>
+ {sidebarElements}
+ </div>
+ </div>
+ <div className='theme-elements row'>
+ <div
+ className='theme-elements__header'
+ onClick={this.toggleContent}
+ >
+ {'Center Channel Styles'}
+ <div className='header__icon'>
+ <i className='fa fa-plus'></i>
+ <i className='fa fa-minus'></i>
+ </div>
+ </div>
+ <div className='theme-elements__body'>
+ {centerChannelElements}
+ </div>
+ </div>
+ <div className='theme-elements row form-group'>
+ <div
+ className='theme-elements__header'
+ onClick={this.toggleContent}
+ >
+ {'Link and Button Styles'}
+ <div className='header__icon'>
+ <i className='fa fa-plus'></i>
+ <i className='fa fa-minus'></i>
+ </div>
+ </div>
+ <div className='theme-elements__body'>
+ {linkAndButtonElements}
+ </div>
+ </div>
+ <div className='row'>
+ {pasteBox}
+ </div>
+ </div>
+ );
+ }
+}
+
+CustomThemeChooser.propTypes = {
+ intl: intlShape.isRequired,
+ theme: React.PropTypes.object.isRequired,
+ updateTheme: React.PropTypes.func.isRequired
+};
+
+export default injectIntl(CustomThemeChooser);