SoapboxConfig: break extraneous components out into their own files

api-accept
Alex Gleason 2022-05-05 13:08:45 -05:00
rodzic 37b0b972e0
commit 1bd81a2f0f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
6 zmienionych plików z 152 dodań i 125 usunięć

Wyświetl plik

@ -0,0 +1,49 @@
import { supportsPassiveEvents } from 'detect-passive-events';
import React, { useEffect, useRef } from 'react';
import { SketchPicker, ColorChangeHandler } from 'react-color';
import { isMobile } from 'soapbox/is_mobile';
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
interface IColorPicker {
style?: React.CSSProperties,
value: string,
onChange: ColorChangeHandler,
onClose: () => void,
}
const ColorPicker: React.FC<IColorPicker> = ({ style, value, onClose, onChange }) => {
const node = useRef<HTMLDivElement>(null);
const handleDocumentClick = (e: MouseEvent | TouchEvent) => {
if (node.current && !node.current.contains(e.target as HTMLElement)) {
onClose();
}
};
useEffect(() => {
document.addEventListener('click', handleDocumentClick, false);
document.addEventListener('touchend', handleDocumentClick, listenerOptions);
return () => {
document.removeEventListener('click', handleDocumentClick, false);
document.removeEventListener('touchend', handleDocumentClick);
};
});
const pickerStyle: React.CSSProperties = {
...style,
marginLeft: isMobile(window.innerWidth) ? '20px' : '12px',
position: 'absolute',
zIndex: 1000,
};
return (
<div id='SketchPickerContainer' ref={node} style={pickerStyle}>
<SketchPicker color={value} disableAlpha onChange={onChange} />
</div>
);
};
export default ColorPicker;

Wyświetl plik

@ -0,0 +1,61 @@
import React, { useState, useRef } from 'react';
// @ts-ignore: TODO: upgrade react-overlays. v3.1 and above have TS definitions
import Overlay from 'react-overlays/lib/Overlay';
import { isMobile } from 'soapbox/is_mobile';
import ColorPicker from './color-picker';
import type { ColorChangeHandler } from 'react-color';
interface IColorWithPicker {
buttonId: string,
label: React.ReactNode,
value: string,
onChange: ColorChangeHandler,
}
const ColorWithPicker: React.FC<IColorWithPicker> = ({ buttonId, label, value, onChange }) => {
const node = useRef<HTMLDivElement>(null);
const [active, setActive] = useState(false);
const [placement, setPlacement] = useState<string | null>(null);
const hidePicker = () => {
setActive(false);
};
const showPicker = () => {
setActive(true);
setPlacement(isMobile(window.innerWidth) ? 'bottom' : 'right');
};
const onToggle: React.MouseEventHandler = () => {
if (active) {
hidePicker();
} else {
showPicker();
}
};
return (
<div className='label_input__color'>
<label>{label}</label>
<div
ref={node}
id={buttonId}
className='color-swatch'
role='presentation'
style={{ background: value }}
title={value}
onClick={onToggle}
/>
<Overlay show={active} placement={placement} target={node.current}>
<ColorPicker value={value} onChange={onChange} onClose={hidePicker} />
</Overlay>
</div>
);
};
export default ColorWithPicker;

Wyświetl plik

@ -0,0 +1,24 @@
import React from 'react';
import IconPickerDropdown from './icon_picker_dropdown';
interface IIconPicker {
label: React.ReactNode,
value: string,
onChange: React.ChangeEventHandler,
}
const IconPicker: React.FC<IIconPicker> = ({ onChange, value, label }) => {
return (
<div className='input with_label font_icon_picker'>
<div className='label_input__font_icon_picker'>
{label && (<label>{label}</label>)}
<div className='label_input_wrapper'>
<IconPickerDropdown value={value} onPickEmoji={onChange} />
</div>
</div>
</div>
);
};
export default IconPicker;

Wyświetl plik

@ -1,12 +1,9 @@
import { supportsPassiveEvents } from 'detect-passive-events';
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
import PropTypes from 'prop-types';
import React from 'react';
import { SketchPicker } from 'react-color';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import Overlay from 'react-overlays/lib/Overlay';
import { connect } from 'react-redux';
import { updateConfig } from 'soapbox/actions/admin';
@ -24,12 +21,12 @@ import {
Checkbox,
} from 'soapbox/features/forms';
import ThemeToggle from 'soapbox/features/ui/components/theme-toggle';
import { isMobile } from 'soapbox/is_mobile';
import { normalizeSoapboxConfig } from 'soapbox/normalizers';
import Accordion from '../ui/components/accordion';
import IconPickerDropdown from './components/icon_picker_dropdown';
import ColorWithPicker from './components/color-with-picker';
import IconPicker from './components/icon-picker';
import SitePreview from './components/site_preview';
const messages = defineMessages({
@ -60,8 +57,6 @@ const messages = defineMessages({
singleUserModeProfileHint: { id: 'soapbox_config.single_user_mode_profile_hint', defaultMessage: '@handle' },
});
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
const templates = {
promoPanelItem: ImmutableMap({ icon: '', text: '', url: '' }),
footerItem: ImmutableMap({ title: '', url: '' }),
@ -461,121 +456,3 @@ class SoapboxConfig extends ImmutablePureComponent {
}
}
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;
const 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>
);
}
}
class ColorWithPicker extends ImmutablePureComponent {
static propTypes = {
buttonId: PropTypes.string.isRequired,
label: PropTypes.node,
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>
<div id={buttonId} className='color-swatch' role='presentation' style={{ background: value }} title={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 IconPicker extends ImmutablePureComponent {
static propTypes = {
icons: PropTypes.object,
label: PropTypes.node,
value: PropTypes.string,
onChange: PropTypes.func.isRequired,
}
render() {
const { onChange, value, label } = this.props;
return (
<div className='input with_label font_icon_picker'>
<div className='label_input__font_icon_picker'>
{label && (<label>{label}</label>)}
<div className='label_input_wrapper'>
<IconPickerDropdown value={value} onPickEmoji={onChange} />
</div>
</div>
</div>
);
}
}

Wyświetl plik

@ -77,6 +77,7 @@
"@types/object-assign": "^4.0.30",
"@types/object-fit-images": "^3.2.3",
"@types/qrcode.react": "^1.0.2",
"@types/react-color": "^3.0.6",
"@types/react-datepicker": "^4.4.0",
"@types/react-helmet": "^6.1.5",
"@types/react-motion": "^0.0.32",

Wyświetl plik

@ -2184,6 +2184,14 @@
dependencies:
"@types/react" "*"
"@types/react-color@^3.0.6":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@types/react-color/-/react-color-3.0.6.tgz#602fed023802b2424e7cd6ff3594ccd3d5055f9a"
integrity sha512-OzPIO5AyRmLA7PlOyISlgabpYUa3En74LP8mTMa0veCA719SvYQov4WLMsHvCgXP+L+KI9yGhYnqZafVGG0P4w==
dependencies:
"@types/react" "*"
"@types/reactcss" "*"
"@types/react-datepicker@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.4.0.tgz#0072e18536ad305fd57786f9b6f9e499eed2b475"
@ -2272,6 +2280,13 @@
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/reactcss@*":
version "1.2.6"
resolved "https://registry.yarnpkg.com/@types/reactcss/-/reactcss-1.2.6.tgz#133c1e7e896f2726370d1d5a26bf06a30a038bcc"
integrity sha512-qaIzpCuXNWomGR1Xq8SCFTtF4v8V27Y6f+b9+bzHiv087MylI/nTCqqdChNeWS7tslgROmYB7yeiruWX7WnqNg==
dependencies:
"@types/react" "*"
"@types/redux-mock-store@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@types/redux-mock-store/-/redux-mock-store-1.0.3.tgz#895de4a364bc4836661570aec82f2eef5989d1fb"