* PLT-6905 - Updating channel header design * Updating border-radius * Updating radius for wide icons * Updating trigger for overlay * Updating UI for channel header * Updating channel header sizing * Updating channel header css * Updating sidebar css * Updating status icons * Adjusting border * Updating comment * Removing type from status icon * Fixing UI issues for the channel header/sidebar * make "Add a channel description" open the channel header modal * Updating status and opacity * Updating stauts icon positioning * Updating description and heading size * Updating UI changes * Updating UI changes * add a focused class to the parent div .search__form and then remove when hover away * Fix active state for pinned posts icon * Updating UI changes * Update channel header text
477 строки
16 KiB
JavaScript
477 строки
16 KiB
JavaScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See License.txt for license information.
|
|
|
|
import 'bootstrap-colorpicker';
|
|
import $ from 'jquery';
|
|
import PropTypes from 'prop-types';
|
|
import React from 'react';
|
|
import {Popover, OverlayTrigger} from 'react-bootstrap';
|
|
import {defineMessages, FormattedMessage, intlShape, injectIntl} from 'react-intl';
|
|
|
|
import Constants from 'utils/constants.jsx';
|
|
import * as UserAgent from 'utils/user_agent.jsx';
|
|
import * as Utils from 'utils/utils.jsx';
|
|
|
|
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'
|
|
},
|
|
errorTextColor: {
|
|
id: 'user.settings.custom_theme.errorTextColor',
|
|
defaultMessage: 'Error Text Color'
|
|
},
|
|
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'
|
|
}
|
|
});
|
|
|
|
const HEX_CODE_LENGTH = 7;
|
|
|
|
class CustomThemeChooser extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.selectTheme = this.selectTheme.bind(this);
|
|
|
|
const copyTheme = Object.assign({}, this.props.theme);
|
|
delete copyTheme.type;
|
|
delete copyTheme.image;
|
|
|
|
this.state = {
|
|
copyTheme: JSON.stringify(copyTheme)
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
$('.color-picker').colorpicker({
|
|
format: 'hex'
|
|
});
|
|
$('.color-picker').on('changeColor', this.onPickerChange);
|
|
$('.group--code').on('change', this.onCodeThemeChange);
|
|
document.addEventListener('click', this.closeColorpicker);
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
$('.color-picker').off('changeColor', this.onPickerChange);
|
|
$('.group--code').off('change', this.onCodeThemeChange);
|
|
document.removeEventListener('click', this.closeColorpicker);
|
|
}
|
|
|
|
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');
|
|
}
|
|
});
|
|
}
|
|
|
|
closeColorpicker(e) {
|
|
if (!$(e.target).closest('.color-picker').length && Utils.isMobile()) {
|
|
$('.color-picker').colorpicker('hide');
|
|
}
|
|
}
|
|
|
|
onPickerChange = (e) => {
|
|
const inputBox = e.target.childNodes[0];
|
|
if (document.activeElement === inputBox && inputBox.value.length !== HEX_CODE_LENGTH) {
|
|
return;
|
|
}
|
|
|
|
const theme = this.props.theme;
|
|
if (theme[e.target.id] !== e.color.toHex()) {
|
|
theme[e.target.id] = e.color.toHex();
|
|
theme.type = 'custom';
|
|
this.props.updateTheme(theme);
|
|
}
|
|
}
|
|
|
|
pasteBoxChange = (e) => {
|
|
let text = '';
|
|
|
|
if (window.clipboardData && window.clipboardData.getData) { // IE
|
|
text = window.clipboardData.getData('Text');
|
|
} else {
|
|
text = e.clipboardData.getData('Text');//e.clipboardData.getData('text/plain');
|
|
}
|
|
|
|
if (text.length === 0) {
|
|
return;
|
|
}
|
|
|
|
let theme;
|
|
try {
|
|
theme = JSON.parse(text);
|
|
} catch (err) {
|
|
return;
|
|
}
|
|
|
|
this.setState({
|
|
copyTheme: JSON.stringify(theme)
|
|
});
|
|
|
|
theme.type = 'custom';
|
|
this.props.updateTheme(theme);
|
|
}
|
|
|
|
onChangeHandle = (e) => {
|
|
e.stopPropagation();
|
|
}
|
|
|
|
selectTheme() {
|
|
const textarea = this.refs.textarea;
|
|
textarea.focus();
|
|
textarea.setSelectionRange(0, this.state.copyTheme.length);
|
|
}
|
|
|
|
toggleSidebarStyles = (e) => {
|
|
e.preventDefault();
|
|
|
|
$(this.refs.sidebarStylesHeader).toggleClass('open');
|
|
this.toggleSection(this.refs.sidebarStyles);
|
|
}
|
|
|
|
toggleCenterChannelStyles = (e) => {
|
|
e.preventDefault();
|
|
|
|
$(this.refs.centerChannelStylesHeader).toggleClass('open');
|
|
this.toggleSection(this.refs.centerChannelStyles);
|
|
}
|
|
|
|
toggleLinkAndButtonStyles = (e) => {
|
|
e.preventDefault();
|
|
|
|
$(this.refs.linkAndButtonStylesHeader).toggleClass('open');
|
|
this.toggleSection(this.refs.linkAndButtonStyles);
|
|
}
|
|
|
|
toggleSection(node) {
|
|
if (UserAgent.isIos()) {
|
|
// iOS doesn't support jQuery animations
|
|
$(node).toggleClass('open');
|
|
} else {
|
|
$(node).slideToggle();
|
|
}
|
|
}
|
|
|
|
onCodeThemeChange = (e) => {
|
|
const theme = this.props.theme;
|
|
theme.codeTheme = e.target.value;
|
|
this.props.updateTheme(theme);
|
|
}
|
|
|
|
render() {
|
|
const {formatMessage} = this.props.intl;
|
|
const theme = this.props.theme;
|
|
|
|
const sidebarElements = [];
|
|
const centerChannelElements = [];
|
|
const linkAndButtonElements = [];
|
|
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'
|
|
defaultValue={theme[element.id]}
|
|
>
|
|
{codeThemeOptions}
|
|
</select>
|
|
<OverlayTrigger
|
|
trigger={['hover', 'focus']}
|
|
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'
|
|
defaultValue={theme[element.id]}
|
|
/>
|
|
<span className='input-group-addon'><i/></span>
|
|
</div>
|
|
</div>
|
|
);
|
|
} 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'
|
|
defaultValue={theme[element.id]}
|
|
/>
|
|
<span className='input-group-addon'><i/></span>
|
|
</div>
|
|
</div>
|
|
);
|
|
} 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'
|
|
defaultValue={theme[element.id]}
|
|
/>
|
|
<span className='input-group-addon'><i/></span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
|
|
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>
|
|
<textarea
|
|
ref='textarea'
|
|
className='form-control'
|
|
value={this.state.copyTheme}
|
|
onPaste={this.pasteBoxChange}
|
|
onChange={this.onChangeHandle}
|
|
onClick={this.selectTheme}
|
|
/>
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className='appearance-section padding-top'>
|
|
<div className='theme-elements row'>
|
|
<div
|
|
ref='sidebarStylesHeader'
|
|
className='theme-elements__header'
|
|
onClick={this.toggleSidebarStyles}
|
|
>
|
|
<FormattedMessage
|
|
id='user.settings.custom_theme.sidebarTitle'
|
|
defaultMessage='Sidebar Styles'
|
|
/>
|
|
<div className='header__icon'>
|
|
<i className='fa fa-plus'/>
|
|
<i className='fa fa-minus'/>
|
|
</div>
|
|
</div>
|
|
<div
|
|
ref='sidebarStyles'
|
|
className='theme-elements__body'
|
|
>
|
|
{sidebarElements}
|
|
</div>
|
|
</div>
|
|
<div className='theme-elements row'>
|
|
<div
|
|
ref='centerChannelStylesHeader'
|
|
className='theme-elements__header'
|
|
onClick={this.toggleCenterChannelStyles}
|
|
>
|
|
<FormattedMessage
|
|
id='user.settings.custom_theme.centerChannelTitle'
|
|
defaultMessage='Center Channel Styles'
|
|
/>
|
|
<div className='header__icon'>
|
|
<i className='fa fa-plus'/>
|
|
<i className='fa fa-minus'/>
|
|
</div>
|
|
</div>
|
|
<div
|
|
ref='centerChannelStyles'
|
|
className='theme-elements__body'
|
|
>
|
|
{centerChannelElements}
|
|
</div>
|
|
</div>
|
|
<div className='theme-elements row form-group'>
|
|
<div
|
|
ref='linkAndButtonStylesHeader'
|
|
className='theme-elements__header'
|
|
onClick={this.toggleLinkAndButtonStyles}
|
|
>
|
|
<FormattedMessage
|
|
id='user.settings.custom_theme.linkButtonTitle'
|
|
defaultMessage='Link and Button Styles'
|
|
/>
|
|
<div className='header__icon'>
|
|
<i className='fa fa-plus'/>
|
|
<i className='fa fa-minus'/>
|
|
</div>
|
|
</div>
|
|
<div
|
|
ref='linkAndButtonStyles'
|
|
className='theme-elements__body'
|
|
>
|
|
{linkAndButtonElements}
|
|
</div>
|
|
</div>
|
|
<div className='row'>
|
|
{pasteBox}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
CustomThemeChooser.propTypes = {
|
|
intl: intlShape.isRequired,
|
|
theme: PropTypes.object.isRequired,
|
|
updateTheme: PropTypes.func.isRequired
|
|
};
|
|
|
|
export default injectIntl(CustomThemeChooser);
|