Color picker for admin config

This commit is contained in:
Sean King 2020-08-02 14:41:26 -06:00
parent ba18c3a643
commit f398dde5cb
5 changed files with 160 additions and 5 deletions

View File

@ -11,6 +11,7 @@ import {
TextInput,
Checkbox,
FileChooser,
ColorWithPicker,
} from 'soapbox/features/forms';
import StillImage from 'soapbox/components/still_image';
import {
@ -177,7 +178,7 @@ class ConfigSoapbox extends ImmutablePureComponent {
}
handleBrandColorChange = e => {
this.setState({ brandColor: e.target.value });
this.setState({ brandColor: e.hex });
}
handleTextChange = e => {
@ -284,10 +285,13 @@ class ConfigSoapbox extends ImmutablePureComponent {
</div>
</FieldsGroup>
<FieldsGroup>
<div>
<label htmlFor='brand_color'><FormattedMessage id='soapbox_settings.fields.brand_color_label' defaultMessage='Brand color' /></label><br /><br />
<input type='color' id='brand_color' name='brand_color' value={this.state.brandColor || '#0482d8'} onChange={this.handleBrandColorChange} /><br /><br />
<label>{ this.state.brandColor }</label>
<div className='fields-row__column fields-group'>
<ColorWithPicker
buttonId='brand_color'
label={<FormattedMessage id='soapbox_settings.fields.brand_color_label' defaultMessage='Brand color' />}
value={this.state.brandColor || '#0482d8'}
onChange={this.handleBrandColorChange}
/>
</div>
</FieldsGroup>
<FieldsGroup>

View File

@ -3,6 +3,10 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { v4 as uuidv4 } from 'uuid';
import { SketchPicker } from 'react-color';
import Overlay from 'react-overlays/lib/Overlay';
import { isMobile } from '../../is_mobile';
import detectPassiveEvents from 'detect-passive-events';
const FormPropTypes = {
label: PropTypes.oneOfType([
@ -12,6 +16,8 @@ const FormPropTypes = {
]),
};
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;
export const InputContainer = (props) => {
const containerClass = classNames('input', {
'with_label': props.label,
@ -153,6 +159,98 @@ export class RadioGroup extends ImmutablePureComponent {
}
export class ColorPicker extends React.PureComponent {
static propTypes = {
style: PropTypes.object,
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
onClose: PropTypes.func,
}
handleDocumentClick = e => {
if (this.node && !this.node.contains(e.target)) {
this.props.onClose();
}
}
componentDidMount() {
document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleDocumentClick, false);
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
}
setRef = c => {
this.node = c;
}
render() {
const { style, value, onChange } = this.props;
let margin_left_picker = isMobile(window.innerWidth) ? '20px' : '12px';
return (
<div id='SketchPickerContainer' ref={this.setRef} style={{ ...style, marginLeft: margin_left_picker, position: 'absolute', zIndex: 1000 }}>
<SketchPicker color={value} disableAlpha onChange={onChange} />
</div>
);
}
}
export class ColorWithPicker extends ImmutablePureComponent {
static propTypes = {
buttonId: PropTypes.string.isRequired,
label: FormPropTypes.label,
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
}
onToggle = (e) => {
if (!e.key || e.key === 'Enter') {
if (this.state.active) {
this.onHidePicker();
} else {
this.onShowPicker(e);
}
}
}
state = {
active: false,
placement: null,
}
onHidePicker = () => {
this.setState({ active: false });
}
onShowPicker = ({ target }) => {
this.setState({ active: true });
this.setState({ placement: isMobile(window.innerWidth) ? 'bottom' : 'right' });
}
render() {
const { buttonId, label, value, onChange } = this.props;
const { active, placement } = this.state;
return (
<div className='label_input__color'>
<label>{label}</label>
<button id={buttonId} className='color-swatch' style={{ background: value }} value={value} onClick={this.onToggle} />
<Overlay show={active} placement={placement} target={this}>
<ColorPicker value={value} onChange={onChange} onClose={this.onHidePicker} />
</Overlay>
</div>
);
}
}
export class RadioItem extends ImmutablePureComponent {
static propTypes = {

View File

@ -444,6 +444,19 @@ code {
}
.label_input {
&__color {
display: inline-flex;
font-size: 14px;
.color-swatch {
width: 32px;
height: 16px;
margin-left: 12px;
display: inline-block;
}
}
&__wrapper {
position: relative;
}

View File

@ -102,6 +102,7 @@
"punycode": "^2.1.0",
"rails-ujs": "^5.2.3",
"react": "^16.13.1",
"react-color": "^2.18.1",
"react-dom": "^16.13.1",
"react-helmet": "^6.0.0",
"react-hotkeys": "^1.1.4",

View File

@ -1229,6 +1229,11 @@
dependencies:
emojis-list "^3.0.0"
"@icons/material@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@ -7411,6 +7416,11 @@ lodash@^4.0.0, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.1
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
lodash@^4.0.1:
version "4.17.19"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.5, lodash@^4.7.11:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
@ -7510,6 +7520,11 @@ marky@^1.2.1:
resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.1.tgz#a3fcf82ffd357756b8b8affec9fdbf3a30dc1b02"
integrity sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ==
material-colors@^1.2.1:
version "1.2.6"
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@ -9423,6 +9438,18 @@ rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
react-color@^2.18.1:
version "2.18.1"
resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.18.1.tgz#2cda8cc8e06a9e2c52ad391a30ddad31972472f4"
integrity sha512-X5XpyJS6ncplZs74ak0JJoqPi+33Nzpv5RYWWxn17bslih+X7OlgmfpmGC1fNvdkK7/SGWYf1JJdn7D2n5gSuQ==
dependencies:
"@icons/material" "^0.2.4"
lodash "^4.17.11"
material-colors "^1.2.1"
prop-types "^15.5.10"
reactcss "^1.2.0"
tinycolor2 "^1.4.1"
react-dom@^16.13.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
@ -9738,6 +9765,13 @@ react@^16.13.1:
object-assign "^4.1.1"
prop-types "^15.6.2"
reactcss@^1.2.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==
dependencies:
lodash "^4.0.1"
read-pkg-up@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
@ -11330,6 +11364,11 @@ tiny-warning@^1.0.0:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tinycolor2@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"