Progress
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
import { length } from 'stringz';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import './character_counter.scss';
|
||||
|
||||
export default class CharacterCounter extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import classNames from 'classnames/bind'
|
||||
import Icon from '../../../components/icon'
|
||||
|
||||
export default class ComposeExtraButton extends PureComponent {
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
icon: PropTypes.string,
|
||||
}
|
||||
|
||||
state = {
|
||||
hovering: false,
|
||||
}
|
||||
|
||||
handleOnMouseEnter = () => {
|
||||
this.setState({ hovering: true })
|
||||
}
|
||||
|
||||
handleOnMouseLeave = () => {
|
||||
this.setState({ hovering: false })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title, disabled, onClick, icon, children } = this.props
|
||||
const { hovering } = this.state
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
const btnClasses = cx({
|
||||
default: 1,
|
||||
circle: 1,
|
||||
flexRow: 1,
|
||||
paddingVertical10PX: 1,
|
||||
paddingHorizontal10PX: 1,
|
||||
cursorPointer: 1,
|
||||
backgroundSubtle: !hovering,
|
||||
backgroundSubtle2: hovering,
|
||||
})
|
||||
|
||||
const titleClasses = cx({
|
||||
default: 1,
|
||||
marginLeft5PX: 1,
|
||||
text: 1,
|
||||
lineHeight15: 1,
|
||||
fontSize12PX: 1,
|
||||
fontWeight500: 1,
|
||||
colorSubtle: 1,
|
||||
displayNone: !hovering,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={[styles.default, styles.marginRight10PX].join(' ')}>
|
||||
<button
|
||||
className={btnClasses}
|
||||
title={title}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
>
|
||||
<Icon icon={icon} width='18px' height='18px' />
|
||||
<span className={titleClasses}>
|
||||
{title}
|
||||
</span>
|
||||
</button>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -7,22 +7,20 @@ import CharacterCounter from '../character_counter';
|
||||
import UploadForm from '../upload_form';
|
||||
import ReplyIndicatorContainer from '../../containers/reply_indicator_container';
|
||||
import AutosuggestTextbox from '../../../../components/autosuggest_textbox';
|
||||
import PollButtonContainer from '../../containers/poll_button_container';
|
||||
import UploadButtonContainer from '../../containers/upload_button_container';
|
||||
import SpoilerButtonContainer from '../../containers/spoiler_button_container';
|
||||
import PrivacyDropdownContainer from '../../containers/privacy_dropdown_container';
|
||||
import PollButton from '../../components/poll_button';
|
||||
import UploadButton from '../../components/upload_button';
|
||||
import SpoilerButton from '../../components/spoiler_button';
|
||||
import PrivacyDropdown from '../../components/privacy_dropdown';
|
||||
import EmojiPickerDropdown from '../../containers/emoji_picker_dropdown_container';
|
||||
import PollFormContainer from '../../containers/poll_form_container';
|
||||
import WarningContainer from '../../containers/warning_container';
|
||||
import SchedulePostDropdownContainer from '../../containers/schedule_post_dropdown_container';
|
||||
import SchedulePostDropdown from '../../components/schedule_post_dropdown';
|
||||
import QuotedStatusPreviewContainer from '../../containers/quoted_status_preview_container';
|
||||
import Icon from '../../../../components/icon';
|
||||
import Button from '../../../../components/button';
|
||||
import { isMobile } from '../../../../utils/is_mobile';
|
||||
import { countableText } from '../../util/counter';
|
||||
|
||||
import './compose_form.scss';
|
||||
|
||||
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
|
||||
const maxPostCharacterCount = 3000;
|
||||
|
||||
@@ -30,7 +28,7 @@ const messages = defineMessages({
|
||||
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
|
||||
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
|
||||
publish: { id: 'compose_form.publish', defaultMessage: 'Gab' },
|
||||
publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' },
|
||||
publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}' },
|
||||
schedulePost: { id: 'compose_form.schedule_post', defaultMessage: 'Schedule Post' }
|
||||
});
|
||||
|
||||
@@ -220,29 +218,22 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
const disabledButton = disabled || this.props.isUploading || this.props.isChangingUpload || length(text) > maxPostCharacterCount || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
|
||||
const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth)
|
||||
|
||||
let publishText = '';
|
||||
|
||||
if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
|
||||
publishText = <span className='compose-form__publish-private'><Icon id='lock' /> {intl.formatMessage(messages.publish)}</span>;
|
||||
} else {
|
||||
publishText = this.props.privacy !== 'unlisted' ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);
|
||||
}
|
||||
|
||||
if (scheduledAt) {
|
||||
publishText = intl.formatMessage(messages.schedulePost);
|
||||
}
|
||||
|
||||
const composeClassNames = classNames({
|
||||
'compose-form': true,
|
||||
'condensed': condensed,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={composeClassNames} ref={this.setForm} onClick={this.handleClick}>
|
||||
<WarningContainer />
|
||||
<div
|
||||
className={[styles.default, styles.flexGrow1].join(' ')}
|
||||
ref={this.setForm}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{ /* <WarningContainer /> */ }
|
||||
|
||||
{ !shouldCondense && <ReplyIndicatorContainer /> }
|
||||
{ /* !shouldCondense && <ReplyIndicatorContainer /> */ }
|
||||
|
||||
{ /*
|
||||
<div className={`spoiler-input ${this.props.spoiler ? 'spoiler-input--visible' : ''}`}>
|
||||
<AutosuggestTextbox
|
||||
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
|
||||
@@ -260,13 +251,14 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
className='spoiler-input__input'
|
||||
/>
|
||||
</div>
|
||||
*/ }
|
||||
|
||||
{ /*
|
||||
<div className='emoji-picker-wrapper'>
|
||||
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
|
||||
</div>
|
||||
</div> */ }
|
||||
|
||||
<AutosuggestTextbox
|
||||
textarea={true}
|
||||
ref={(isModalOpen && shouldCondense) ? null : this.setAutosuggestTextarea}
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
disabled={disabled}
|
||||
@@ -280,38 +272,37 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
onSuggestionSelected={this.onSuggestionSelected}
|
||||
onPaste={onPaste}
|
||||
autoFocus={shouldAutoFocus}
|
||||
textarea
|
||||
>
|
||||
{
|
||||
{ /*
|
||||
!condensed &&
|
||||
<div className='compose-form__modifiers'>
|
||||
<UploadForm />
|
||||
{!edit && <PollFormContainer />}
|
||||
</div>
|
||||
}
|
||||
*/ }
|
||||
</AutosuggestTextbox>
|
||||
|
||||
{quoteOfId && <QuotedStatusPreviewContainer id={quoteOfId} />}
|
||||
{ /* quoteOfId && <QuotedStatusPreviewContainer id={quoteOfId} /> */ }
|
||||
|
||||
{
|
||||
!condensed &&
|
||||
<div className='compose-form__buttons-wrapper'>
|
||||
<div className='compose-form__buttons'>
|
||||
<UploadButtonContainer />
|
||||
{!edit && <PollButtonContainer />}
|
||||
<PrivacyDropdownContainer />
|
||||
<SpoilerButtonContainer />
|
||||
<SchedulePostDropdownContainer
|
||||
position={isModalOpen ? 'top' : undefined}
|
||||
/>
|
||||
/* !condensed && */
|
||||
<div className={[styles.default, styles.flexRow, styles.marginTop10PX].join(' ')}>
|
||||
<div className={[styles.default, styles.flexRow, styles.marginRightAuto].join(' ')}>
|
||||
<UploadButton />
|
||||
{
|
||||
!edit && <PollButton />
|
||||
}
|
||||
<PrivacyDropdown />
|
||||
<SpoilerButton />
|
||||
<SchedulePostDropdown position={isModalOpen ? 'top' : undefined} />
|
||||
</div>
|
||||
<CharacterCounter max={maxPostCharacterCount} text={text} />
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
!condensed &&
|
||||
<div className='compose-form__publish'>
|
||||
<div className='compose-form__publish-button-wrapper'><Button text={publishText} onClick={this.handleSubmit} disabled={disabledButton} block /></div>
|
||||
<Button
|
||||
text={intl.formatMessage(scheduledAt ? messages.schedulePost : messages.publish)}
|
||||
onClick={this.handleSubmit}
|
||||
disabled={disabledButton}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ import Overlay from 'react-overlays/lib/Overlay';
|
||||
import { EmojiPicker as EmojiPickerAsync } from '../../../ui/util/async-components';
|
||||
import { buildCustomEmojis } from '../../../../components/emoji/emoji';
|
||||
|
||||
import './emoji_picker_dropdown.scss';
|
||||
|
||||
const messages = defineMessages({
|
||||
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
|
||||
emoji_search: { id: 'emoji_button.search', defaultMessage: 'Search...' },
|
||||
|
||||
@@ -7,8 +7,6 @@ import Permalink from '../../../../components/permalink';
|
||||
import IconButton from '../../../../components/icon_button';
|
||||
import { me } from '../../../../initial_state';
|
||||
|
||||
import './navigation_bar.scss';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
account: state.getIn(['accounts', me]),
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { addPoll, removePoll } from '../../../actions/compose';
|
||||
import ComposeExtraButton from './compose_extra_button'
|
||||
|
||||
const messages = defineMessages({
|
||||
add_poll: { id: 'poll_button.add_poll', defaultMessage: 'Add poll' },
|
||||
title: { id: 'poll_button.title', defaultMessage: 'Poll' },
|
||||
remove_poll: { id: 'poll_button.remove_poll', defaultMessage: 'Remove poll' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
unavailable: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 0),
|
||||
active: state.getIn(['compose', 'poll']) !== null,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onClick() {
|
||||
dispatch((_, getState) => {
|
||||
if (getState().getIn(['compose', 'poll'])) {
|
||||
dispatch(removePoll());
|
||||
} else {
|
||||
dispatch(addPoll());
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class PollButton extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
unavailable: PropTypes.bool,
|
||||
active: PropTypes.bool,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onClick();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, active, unavailable, disabled } = this.props;
|
||||
|
||||
if (unavailable) return null;
|
||||
|
||||
return (
|
||||
<ComposeExtraButton
|
||||
title={intl.formatMessage(active ? messages.remove_poll : messages.title)}
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
icon='tasks'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './poll_button';
|
||||
@@ -1,53 +0,0 @@
|
||||
import IconButton from '../../../../components/icon_button';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
const messages = defineMessages({
|
||||
add_poll: { id: 'poll_button.add_poll', defaultMessage: 'Add a poll' },
|
||||
remove_poll: { id: 'poll_button.remove_poll', defaultMessage: 'Remove poll' },
|
||||
});
|
||||
|
||||
const iconStyle = {
|
||||
height: null,
|
||||
lineHeight: '27px',
|
||||
};
|
||||
|
||||
export default
|
||||
@injectIntl
|
||||
class PollButton extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
unavailable: PropTypes.bool,
|
||||
active: PropTypes.bool,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onClick();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, active, unavailable, disabled } = this.props;
|
||||
|
||||
if (unavailable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
icon='tasks'
|
||||
title={intl.formatMessage(active ? messages.remove_poll : messages.add_poll)}
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
className={`${active ? 'active' : ''}`}
|
||||
size={18}
|
||||
inverted
|
||||
style={iconStyle}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,8 +6,6 @@ import IconButton from '../../../../components/icon_button';
|
||||
import Icon from '../../../../components/icon';
|
||||
import AutosuggestTextbox from '../../../../components/autosuggest_textbox';
|
||||
|
||||
import './poll_form.scss';
|
||||
|
||||
const messages = defineMessages({
|
||||
option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' },
|
||||
add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add a choice' },
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import detectPassiveEvents from 'detect-passive-events';
|
||||
import classNames from 'classnames';
|
||||
import Overlay from 'react-overlays/lib/Overlay';
|
||||
import IconButton from '../../../../components/icon_button';
|
||||
import Motion from '../../../ui/util/optional_motion';
|
||||
import Icon from '../../../../components/icon';
|
||||
|
||||
import './privacy_dropdown.scss';
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import spring from 'react-motion/lib/spring'
|
||||
import detectPassiveEvents from 'detect-passive-events'
|
||||
import classNames from 'classnames'
|
||||
import Overlay from 'react-overlays/lib/Overlay'
|
||||
import { changeComposeVisibility } from '../../../actions/compose'
|
||||
import { openModal, closeModal } from '../../../actions/modal'
|
||||
import { isUserTouching } from '../../../utils/is_mobile'
|
||||
import Motion from '../../ui/util/optional_motion'
|
||||
import Icon from '../../../components/icon'
|
||||
import ComposeExtraButton from './compose_extra_button'
|
||||
|
||||
const messages = defineMessages({
|
||||
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||
@@ -16,11 +17,11 @@ const messages = defineMessages({
|
||||
unlisted_long: { id: 'privacy.unlisted.long', defaultMessage: 'Do not show in public timelines' },
|
||||
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers-only' },
|
||||
private_long: { id: 'privacy.private.long', defaultMessage: 'Post to followers only' },
|
||||
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' },
|
||||
change_privacy: { id: 'privacy.change', defaultMessage: 'Adjust status privacy' },
|
||||
});
|
||||
visibility: { id: 'privacy.visibility', defaultMessage: 'Visibility' },
|
||||
})
|
||||
|
||||
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;
|
||||
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false
|
||||
|
||||
class PrivacyDropdownMenu extends PureComponent {
|
||||
|
||||
@@ -31,96 +32,96 @@ class PrivacyDropdownMenu extends PureComponent {
|
||||
placement: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
state = {
|
||||
mounted: false,
|
||||
};
|
||||
}
|
||||
|
||||
handleDocumentClick = e => {
|
||||
if (this.node && !this.node.contains(e.target)) {
|
||||
this.props.onClose();
|
||||
this.props.onClose()
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown = e => {
|
||||
const { items } = this.props;
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
const { items } = this.props
|
||||
const value = e.currentTarget.getAttribute('data-index')
|
||||
const index = items.findIndex(item => {
|
||||
return (item.value === value);
|
||||
});
|
||||
let element;
|
||||
return (item.value === value)
|
||||
})
|
||||
let element
|
||||
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
this.props.onClose();
|
||||
break;
|
||||
this.props.onClose()
|
||||
break
|
||||
case 'Enter':
|
||||
this.handleClick(e);
|
||||
break;
|
||||
this.handleClick(e)
|
||||
break
|
||||
case 'ArrowDown':
|
||||
element = this.node.childNodes[index + 1];
|
||||
element = this.node.childNodes[index + 1]
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.props.onChange(element.getAttribute('data-index'));
|
||||
element.focus()
|
||||
this.props.onChange(element.getAttribute('data-index'))
|
||||
}
|
||||
break;
|
||||
break
|
||||
case 'ArrowUp':
|
||||
element = this.node.childNodes[index - 1];
|
||||
element = this.node.childNodes[index - 1]
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.props.onChange(element.getAttribute('data-index'));
|
||||
element.focus()
|
||||
this.props.onChange(element.getAttribute('data-index'))
|
||||
}
|
||||
break;
|
||||
break
|
||||
case 'Home':
|
||||
element = this.node.firstChild;
|
||||
element = this.node.firstChild
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.props.onChange(element.getAttribute('data-index'));
|
||||
element.focus()
|
||||
this.props.onChange(element.getAttribute('data-index'))
|
||||
}
|
||||
break;
|
||||
break
|
||||
case 'End':
|
||||
element = this.node.lastChild;
|
||||
element = this.node.lastChild
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.props.onChange(element.getAttribute('data-index'));
|
||||
element.focus()
|
||||
this.props.onChange(element.getAttribute('data-index'))
|
||||
}
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
handleClick = e => {
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
const value = e.currentTarget.getAttribute('data-index')
|
||||
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
|
||||
this.props.onClose();
|
||||
this.props.onChange(value);
|
||||
this.props.onClose()
|
||||
this.props.onChange(value)
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
document.addEventListener('click', this.handleDocumentClick, false);
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
if (this.focusedItem) this.focusedItem.focus();
|
||||
this.setState({ mounted: true });
|
||||
document.addEventListener('click', this.handleDocumentClick, false)
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions)
|
||||
if (this.focusedItem) this.focusedItem.focus()
|
||||
this.setState({ mounted: true })
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
document.removeEventListener('click', this.handleDocumentClick, false);
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.removeEventListener('click', this.handleDocumentClick, false)
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions)
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
this.node = c
|
||||
}
|
||||
|
||||
setFocusRef = c => {
|
||||
this.focusedItem = c;
|
||||
this.focusedItem = c
|
||||
}
|
||||
|
||||
render () {
|
||||
const { mounted } = this.state;
|
||||
const { style, items, placement, value } = this.props;
|
||||
const { mounted } = this.state
|
||||
const { style, items, placement, value } = this.props
|
||||
|
||||
return (
|
||||
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
||||
@@ -144,12 +145,31 @@ class PrivacyDropdownMenu extends PureComponent {
|
||||
</div>
|
||||
)}
|
||||
</Motion>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default @injectIntl
|
||||
const mapStateToProps = state => ({
|
||||
isModalOpen: state.get('modal').modalType === 'ACTIONS',
|
||||
value: state.getIn(['compose', 'privacy']),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onChange (value) {
|
||||
dispatch(changeComposeVisibility(value))
|
||||
},
|
||||
|
||||
isUserTouching,
|
||||
onModalOpen: props => dispatch(openModal('ACTIONS', props)),
|
||||
onModalClose: () => dispatch(closeModal()),
|
||||
|
||||
})
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class PrivacyDropdown extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
@@ -160,84 +180,78 @@ class PrivacyDropdown extends PureComponent {
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
state = {
|
||||
open: false,
|
||||
placement: 'bottom',
|
||||
};
|
||||
}
|
||||
|
||||
handleToggle = ({ target }) => {
|
||||
if (this.props.isUserTouching()) {
|
||||
if (this.state.open) {
|
||||
this.props.onModalClose();
|
||||
this.props.onModalClose()
|
||||
} else {
|
||||
this.props.onModalOpen({
|
||||
actions: this.options.map(option => ({ ...option, active: option.value === this.props.value })),
|
||||
onClick: this.handleModalActionClick,
|
||||
});
|
||||
})
|
||||
}
|
||||
} else {
|
||||
const { top } = target.getBoundingClientRect();
|
||||
this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' });
|
||||
this.setState({ open: !this.state.open });
|
||||
const { top } = target.getBoundingClientRect()
|
||||
this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' })
|
||||
this.setState({ open: !this.state.open })
|
||||
}
|
||||
}
|
||||
|
||||
handleModalActionClick = (e) => {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
|
||||
const { value } = this.options[e.currentTarget.getAttribute('data-index')];
|
||||
const { value } = this.options[e.currentTarget.getAttribute('data-index')]
|
||||
|
||||
this.props.onModalClose();
|
||||
this.props.onChange(value);
|
||||
this.props.onModalClose()
|
||||
this.props.onChange(value)
|
||||
}
|
||||
|
||||
handleKeyDown = e => {
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
this.handleClose();
|
||||
break;
|
||||
this.handleClose()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ open: false });
|
||||
this.setState({ open: false })
|
||||
}
|
||||
|
||||
handleChange = value => {
|
||||
this.props.onChange(value);
|
||||
this.props.onChange(value)
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
const { intl: { formatMessage } } = this.props;
|
||||
const { intl: { formatMessage } } = this.props
|
||||
|
||||
this.options = [
|
||||
{ icon: 'globe', value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
|
||||
{ icon: 'unlock', value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
|
||||
{ icon: 'lock', value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
|
||||
];
|
||||
]
|
||||
}
|
||||
|
||||
render () {
|
||||
const { value, intl } = this.props;
|
||||
const { open, placement } = this.state;
|
||||
const { value, intl } = this.props
|
||||
const { open, placement } = this.state
|
||||
|
||||
const valueOption = this.options.find(item => item.value === value);
|
||||
const valueOption = this.options.find(item => item.value === value)
|
||||
|
||||
return (
|
||||
<div className={classNames('privacy-dropdown', placement, { active: open })} onKeyDown={this.handleKeyDown}>
|
||||
<div className={classNames('privacy-dropdown__value', { active: this.options.indexOf(valueOption) === 0 })}>
|
||||
<IconButton
|
||||
className='privacy-dropdown__value-icon'
|
||||
<ComposeExtraButton
|
||||
icon={valueOption.icon}
|
||||
title={intl.formatMessage(messages.change_privacy)}
|
||||
size={18}
|
||||
expanded={open}
|
||||
active={open}
|
||||
inverted
|
||||
title={intl.formatMessage(messages.visibility)}
|
||||
onClick={this.handleToggle}
|
||||
style={{ height: null, lineHeight: '27px' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -251,7 +265,7 @@ class PrivacyDropdown extends PureComponent {
|
||||
/>
|
||||
</Overlay>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './privacy_dropdown';
|
||||
@@ -1,101 +0,0 @@
|
||||
.privacy-dropdown {
|
||||
|
||||
&__dropdown {
|
||||
position: absolute;
|
||||
background: $simple-background-color;
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
border-radius: 4px;
|
||||
margin-left: 40px;
|
||||
overflow: hidden;
|
||||
z-index: 10000;
|
||||
|
||||
&.top {
|
||||
transform-origin: 50% 100%;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
transform-origin: 50% 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__option {
|
||||
color: $inverted-text-color;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
background: $ui-highlight-color;
|
||||
color: $primary-text-color;
|
||||
outline: 0;
|
||||
|
||||
.privacy-dropdown__option__content {
|
||||
color: $primary-text-color;
|
||||
|
||||
strong {
|
||||
color: $primary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active:hover {
|
||||
background: lighten($ui-highlight-color, 4%);
|
||||
}
|
||||
|
||||
&__icon {
|
||||
margin-right: 10px;
|
||||
|
||||
@include flex(center, center);
|
||||
}
|
||||
|
||||
&__content {
|
||||
flex: 1 1 auto;
|
||||
color: $lighter-text-color;
|
||||
|
||||
strong {
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
color: $inverted-text-color;
|
||||
|
||||
@each $lang in $cjk-langs {
|
||||
&:lang(#{$lang}) {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active & {
|
||||
&__dropdown {
|
||||
display: block;
|
||||
box-shadow: 2px 4px 6px rgba($base-shadow-color, 0.1);
|
||||
}
|
||||
|
||||
|
||||
&__value {
|
||||
background: $simple-background-color;
|
||||
border-radius: 4px 4px 0 0;
|
||||
box-shadow: 0 -4px 4px rgba($base-shadow-color, 0.1);
|
||||
|
||||
.icon-button {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: $ui-highlight-color;
|
||||
|
||||
.icon-button {
|
||||
color: $primary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active.top & {
|
||||
&__value {
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,6 @@ import IconButton from '../../../../components/icon_button';
|
||||
import DisplayName from '../../../../components/display_name';
|
||||
import { isRtl } from '../../../../utils/rtl';
|
||||
|
||||
import './reply_indicator.scss';
|
||||
|
||||
const messages = defineMessages({
|
||||
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
|
||||
});
|
||||
|
||||
@@ -1,32 +1,53 @@
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import DatePicker from 'react-datepicker';
|
||||
import IconButton from '../../../components/icon_button';
|
||||
import { isMobile } from '../../../utils/is_mobile';
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import DatePicker from 'react-datepicker'
|
||||
import IconButton from '../../../components/icon_button'
|
||||
import { changeScheduledAt } from '../../../actions/compose'
|
||||
import { openModal } from '../../../actions/modal'
|
||||
import { me } from '../../../initial_state'
|
||||
import { isMobile } from '../../../utils/is_mobile'
|
||||
import ComposeExtraButton from './compose_extra_button'
|
||||
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import 'react-datepicker/dist/react-datepicker.css'
|
||||
|
||||
const messages = defineMessages({
|
||||
schedule_status: { id: 'schedule_status.title', defaultMessage: 'Schedule Status' },
|
||||
});
|
||||
schedule_status: { id: 'schedule_status.title', defaultMessage: 'Schedule' },
|
||||
})
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
date: state.getIn(['compose', 'scheduled_at']),
|
||||
isPro: state.getIn(['accounts', me, 'is_pro']),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
setScheduledAt (date) {
|
||||
dispatch(changeScheduledAt(date))
|
||||
},
|
||||
|
||||
onOpenProUpgradeModal() {
|
||||
dispatch(openModal('PRO_UPGRADE'))
|
||||
},
|
||||
})
|
||||
|
||||
class DatePickerWrapper extends PureComponent {
|
||||
static propTypes = {
|
||||
value: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { value, onClick } = this.props;
|
||||
const { value, onClick } = this.props
|
||||
|
||||
return (
|
||||
<button className="schedule-post-dropdown-wrapper" onClick={onClick}>
|
||||
<button className='schedule-post-dropdown-wrapper' onClick={onClick}>
|
||||
{value}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default @injectIntl
|
||||
export default
|
||||
@injectIntl
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
class SchedulePostDropdown extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
@@ -36,43 +57,37 @@ class SchedulePostDropdown extends PureComponent {
|
||||
isPro: PropTypes.bool,
|
||||
onOpenProUpgradeModal: PropTypes.func.isRequired,
|
||||
position: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
handleToggle = () => {
|
||||
if (!this.props.isPro) {
|
||||
return this.props.onOpenProUpgradeModal();
|
||||
return this.props.onOpenProUpgradeModal()
|
||||
}
|
||||
|
||||
const { date } = this.props;
|
||||
const value = date ? null : new Date();
|
||||
this.handleSetDate(value);
|
||||
const { date } = this.props
|
||||
const value = date ? null : new Date()
|
||||
this.handleSetDate(value)
|
||||
}
|
||||
|
||||
handleSetDate = (date) => {
|
||||
this.props.setScheduledAt(date);
|
||||
this.props.setScheduledAt(date)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, date, isPro, position } = this.props;
|
||||
const { intl, date, isPro, position } = this.props
|
||||
|
||||
const open = !!date;
|
||||
const datePickerDisabled = !isPro;
|
||||
const withPortal = isMobile(window.innerWidth);
|
||||
const popperPlacement = position || undefined;
|
||||
const open = !!date
|
||||
const datePickerDisabled = !isPro
|
||||
const withPortal = isMobile(window.innerWidth)
|
||||
const popperPlacement = position || undefined
|
||||
|
||||
return (
|
||||
<div className='schedule-post-dropdown'>
|
||||
<div className='schedule-post-dropdown__container'>
|
||||
<IconButton
|
||||
inverted
|
||||
className='schedule-post-dropdown__icon'
|
||||
<div className={[].join(' ')}>
|
||||
<div className={[].join(' ')}>
|
||||
<ComposeExtraButton
|
||||
icon='calendar'
|
||||
title={intl.formatMessage(messages.schedule_status)}
|
||||
size={18}
|
||||
expanded={open}
|
||||
active={open}
|
||||
onClick={this.handleToggle}
|
||||
style={{ height: null, lineHeight: '27px' }}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
@@ -83,10 +98,10 @@ class SchedulePostDropdown extends PureComponent {
|
||||
minDate={new Date()}
|
||||
selected={date}
|
||||
onChange={date => this.handleSetDate(date)}
|
||||
timeFormat="p"
|
||||
timeFormat='p'
|
||||
timeIntervals={15}
|
||||
timeCaption="Time"
|
||||
dateFormat="MMM d, yyyy h:mm aa"
|
||||
timeCaption='Time'
|
||||
dateFormat='MMM d, yyyy h:mm aa'
|
||||
disabled={datePickerDisabled}
|
||||
showTimeSelect
|
||||
customInput={<DatePickerWrapper />}
|
||||
@@ -95,18 +110,18 @@ class SchedulePostDropdown extends PureComponent {
|
||||
popperModifiers={{
|
||||
offset: {
|
||||
enabled: true,
|
||||
offset: "0px, 5px"
|
||||
offset: '0px, 5px'
|
||||
},
|
||||
preventOverflow: {
|
||||
enabled: true,
|
||||
escapeWithReference: false,
|
||||
boundariesElement: "viewport"
|
||||
boundariesElement: 'viewport'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { injectIntl, defineMessages } from 'react-intl'
|
||||
import { changeComposeSpoilerness } from '../../../actions/compose'
|
||||
import ComposeExtraButton from './compose_extra_button'
|
||||
|
||||
const messages = defineMessages({
|
||||
marked: { id: 'compose_form.spoiler.marked', defaultMessage: 'Text is hidden behind warning' },
|
||||
unmarked: { id: 'compose_form.spoiler.unmarked', defaultMessage: 'Text is not hidden' },
|
||||
title: { id: 'compose_form.spoiler.title', defaultMessage: 'Warning' },
|
||||
})
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
active: state.getIn(['compose', 'spoiler']),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onClick () {
|
||||
dispatch(changeComposeSpoilerness())
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
export default
|
||||
@injectIntl
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
class SpoilerButton extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
active: PropTypes.bool,
|
||||
intl: PropTypes.map,
|
||||
}
|
||||
|
||||
handleClick = (e) => {
|
||||
e.preventDefault()
|
||||
this.props.onClick()
|
||||
}
|
||||
|
||||
render () {
|
||||
const { active, intl } = this.props
|
||||
|
||||
return (
|
||||
<ComposeExtraButton
|
||||
title={intl.formatMessage(messages.title)}
|
||||
icon='warning'
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './text_icon_button';
|
||||
@@ -1,33 +0,0 @@
|
||||
export default class TextIconButton extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
title: PropTypes.string,
|
||||
active: PropTypes.bool,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
ariaControls: PropTypes.string,
|
||||
};
|
||||
|
||||
handleClick = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.onClick();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { label, title, active, ariaControls } = this.props;
|
||||
|
||||
return (
|
||||
<button
|
||||
title={title}
|
||||
aria-label={title}
|
||||
className={`text-icon-button ${active ? 'text-icon-button--active' : ''}`}
|
||||
aria-expanded={active}
|
||||
onClick={this.handleClick}
|
||||
aria-controls={ariaControls}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
.text-icon-button {
|
||||
color: $gab-secondary-text;
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
padding: 0 3px;
|
||||
outline: 0;
|
||||
transition: color 100ms ease-in;
|
||||
|
||||
@include text-sizing(11px, 600, 27px);
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
color: darken($lighter-text-color, 7%);
|
||||
transition: color 200ms ease-out;
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: $highlight-text-color;
|
||||
}
|
||||
|
||||
&::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
&::-moz-focus-inner,
|
||||
&:focus,
|
||||
&:active {
|
||||
outline: 0 !important;
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,6 @@ import spring from 'react-motion/lib/spring';
|
||||
import Motion from '../../../ui/util/optional_motion';
|
||||
import IconButton from '../../../../components/icon_button';
|
||||
|
||||
import './upload.scss';
|
||||
|
||||
const messages = defineMessages({
|
||||
description: { id: 'upload_form.description', defaultMessage: 'Describe for the visually impaired' },
|
||||
delete: { id: 'upload_form.undo', defaultMessage: 'Delete' },
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import { uploadCompose } from '../../../actions/compose'
|
||||
import ComposeExtraButton from './compose_extra_button'
|
||||
|
||||
const messages = defineMessages({
|
||||
upload: { id: 'upload_button.label', defaultMessage: 'Add media (JPEG, PNG, GIF, WebM, MP4, MOV)' },
|
||||
title: { id: 'upload_button.title', defaultMessage: 'Photo/Video' },
|
||||
})
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const mapStateToProps = state => ({
|
||||
acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']),
|
||||
disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => m.get('type') === 'video')),
|
||||
unavailable: state.getIn(['compose', 'poll']) !== null,
|
||||
resetFileKey: state.getIn(['compose', 'resetFileKey']),
|
||||
})
|
||||
|
||||
return mapStateToProps
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onSelectFile(files) {
|
||||
dispatch(uploadCompose(files))
|
||||
},
|
||||
})
|
||||
|
||||
export default
|
||||
@connect(makeMapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class UploadButton extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
unavailable: PropTypes.bool,
|
||||
onSelectFile: PropTypes.func.isRequired,
|
||||
style: PropTypes.object,
|
||||
resetFileKey: PropTypes.number,
|
||||
acceptContentTypes: ImmutablePropTypes.listOf(PropTypes.string).isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
handleChange = (e) => {
|
||||
if (e.target.files.length > 0) {
|
||||
this.props.onSelectFile(e.target.files)
|
||||
}
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
this.fileElement.click()
|
||||
}
|
||||
|
||||
setRef = (c) => {
|
||||
this.fileElement = c
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, resetFileKey, unavailable, disabled, acceptContentTypes } = this.props
|
||||
|
||||
if (unavailable) return null
|
||||
|
||||
return (
|
||||
<ComposeExtraButton
|
||||
title={intl.formatMessage(messages.title)}
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
icon='upload'
|
||||
>
|
||||
<label>
|
||||
<span className={styles.displayNone}>{intl.formatMessage(messages.upload)}</span>
|
||||
<input
|
||||
key={resetFileKey}
|
||||
ref={this.setRef}
|
||||
type='file'
|
||||
accept={acceptContentTypes.toArray().join(',')}
|
||||
onChange={this.handleChange}
|
||||
disabled={disabled}
|
||||
className={styles.displayNone}
|
||||
multiple
|
||||
/>
|
||||
</label>
|
||||
</ComposeExtraButton>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './upload_button';
|
||||
@@ -1,89 +0,0 @@
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import IconButton from '../../../../components/icon_button';
|
||||
|
||||
import './upload_button.scss';
|
||||
|
||||
const messages = defineMessages({
|
||||
upload: { id: 'upload_button.label', defaultMessage: 'Add media (JPEG, PNG, GIF, WebM, MP4, MOV)' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const mapStateToProps = state => ({
|
||||
acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const iconStyle = {
|
||||
height: null,
|
||||
lineHeight: '27px',
|
||||
};
|
||||
|
||||
export default @connect(makeMapStateToProps)
|
||||
@injectIntl
|
||||
class UploadButton extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
unavailable: PropTypes.bool,
|
||||
onSelectFile: PropTypes.func.isRequired,
|
||||
style: PropTypes.object,
|
||||
resetFileKey: PropTypes.number,
|
||||
acceptContentTypes: ImmutablePropTypes.listOf(PropTypes.string).isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
handleChange = (e) => {
|
||||
if (e.target.files.length > 0) {
|
||||
this.props.onSelectFile(e.target.files);
|
||||
}
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
this.fileElement.click();
|
||||
}
|
||||
|
||||
setRef = (c) => {
|
||||
this.fileElement = c;
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, resetFileKey, unavailable, disabled, acceptContentTypes } = this.props;
|
||||
|
||||
if (unavailable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='compose-form-upload-button'>
|
||||
<IconButton
|
||||
inverted
|
||||
icon='camera'
|
||||
title={intl.formatMessage(messages.upload)}
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
className='compose-form-upload-button__icon'
|
||||
size={18}
|
||||
style={iconStyle}
|
||||
/>
|
||||
<label>
|
||||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.upload)}</span>
|
||||
<input
|
||||
key={resetFileKey}
|
||||
ref={this.setRef}
|
||||
type='file'
|
||||
multiple
|
||||
accept={acceptContentTypes.toArray().join(',')}
|
||||
onChange={this.handleChange}
|
||||
disabled={disabled}
|
||||
style={{ display: 'none' }}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
.compose-form-upload-button {
|
||||
&__icon {
|
||||
line-height: 27px;
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import UploadProgress from '../upload_progress';
|
||||
import UploadContainer from '../../containers/upload_container';
|
||||
import SensitiveButtonContainer from '../../containers/sensitive_button_container';
|
||||
|
||||
import './upload_form.scss';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
mediaIds: state.getIn(['compose', 'media_attachments']).map(item => item.get('id')),
|
||||
});
|
||||
|
||||
@@ -3,8 +3,6 @@ import spring from 'react-motion/lib/spring';
|
||||
import Motion from '../../../ui/util/optional_motion';
|
||||
import Icon from '../../../../components/icon';
|
||||
|
||||
import './upload_progress.scss'
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
active: state.getIn(['compose', 'is_uploading']),
|
||||
progress: state.getIn(['compose', 'progress']),
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import Motion from '../../../ui/util/optional_motion';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
|
||||
import './warning.scss';
|
||||
|
||||
export default class Warning extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
||||
Reference in New Issue
Block a user