This commit is contained in:
mgabdev
2020-02-28 10:20:47 -05:00
parent 0bd1eb2c77
commit 3ca4ffcc6b
77 changed files with 6110 additions and 1427 deletions

View File

@@ -1,6 +1,5 @@
import { defineMessages, injectIntl } from 'react-intl';
import { openModal } from '../../../../actions/modal';
import Dropdown from '../../../../components/dropdown_menu'
import { meUsername } from '../../../../initial_state';
const messages = defineMessages({

View File

@@ -5,27 +5,30 @@ export default class CharacterCounter extends PureComponent {
static propTypes = {
text: PropTypes.string.isRequired,
max: PropTypes.number.isRequired,
small: PropTypes.bool,
}
render () {
const radius = 12
const { text, max, small } = this.props
const actualRadius = small ? '10' : '16'
const radius = small ? 8 : 12
const circumference = 2 * Math.PI * radius
const diff = length(this.props.text) / this.props.max
const diff = length(text) / max
const dashoffset = circumference * (1 - diff)
return (
<div className={[_s.default, _s.marginRight10PX, _s.justifyContentCenter, _s.alignItemsCenter].join(' ')}>
<svg width="32" height="32" viewBox="0 0 32 32">
<circle fill='none' cx="16" cy="16" r="12" fill="none" stroke="#e6e6e6" strokeWidth="2" />
<svg width={actualRadius * 2} height={actualRadius * 2} viewBox={`0 0 ${actualRadius * 2} ${actualRadius * 2}`}>
<circle fill='none' cx={actualRadius} cy={actualRadius} r={radius} fill="none" stroke="#e6e6e6" strokeWidth="2" />
<circle style={{
// transform: 'rotate(-90deg)',
strokeDashoffset: dashoffset,
strokeDasharray: circumference,
}}
fill='none'
cx="16"
cy="16"
r="12"
cx={actualRadius}
cy={actualRadius}
r={radius}
strokeWidth="2"
strokeLinecap='round'
stroke='#21cf7a'

View File

@@ -9,6 +9,7 @@ export default class ComposeExtraButton extends PureComponent {
disabled: PropTypes.bool,
onClick: PropTypes.func,
icon: PropTypes.string,
small: PropTypes.bool,
}
state = {
@@ -24,18 +25,26 @@ export default class ComposeExtraButton extends PureComponent {
}
render() {
const { title, disabled, onClick, icon, children } = this.props
const { title, disabled, onClick, icon, children, small } = this.props
const { hovering } = this.state
const containerClasses = cx({
default: 1,
marginRight10PX: !small,
marginRight2PX: small,
})
const btnClasses = cx({
default: 1,
circle: 1,
flexRow: 1,
paddingVertical10PX: 1,
paddingHorizontal10PX: 1,
cursorPointer: 1,
backgroundSubtle: !hovering,
backgroundSubtle2: hovering,
paddingVertical10PX: !small,
paddingHorizontal10PX: !small,
paddingVertical5PX: small,
paddingHorizontal5PX: small,
})
const titleClasses = cx({
@@ -49,8 +58,10 @@ export default class ComposeExtraButton extends PureComponent {
displayNone: !hovering,
})
const iconSize = !!small ? '12px' : '18px'
return (
<div className={[_s.default, _s.marginRight10PX].join(' ')}>
<div className={containerClasses}>
<button
className={btnClasses}
title={title}
@@ -59,10 +70,13 @@ export default class ComposeExtraButton extends PureComponent {
onMouseEnter={() => this.handleOnMouseEnter()}
onMouseLeave={() => this.handleOnMouseLeave()}
>
<Icon id={icon} width='18px' height='18px' className={_s.fillcolorSecondary} />
<span className={titleClasses}>
{title}
</span>
<Icon id={icon} width={iconSize} height={iconSize} className={_s.fillcolorSecondary} />
{
!small &&
<span className={titleClasses}>
{title}
</span>
}
</button>
{children}
</div>

View File

@@ -2,7 +2,7 @@ import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { length } from 'stringz';
import ImmutablePropTypes from 'react-immutable-proptypes';
import classNames from 'classnames';
import classNames from 'classnames/bind'
import CharacterCounter from '../character_counter';
import UploadForm from '../upload_form';
import ReplyIndicatorContainer from '../../containers/reply_indicator_container';
@@ -18,6 +18,7 @@ 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 Avatar from '../../../../components/avatar'
import { isMobile } from '../../../../utils/is_mobile';
import { countableText } from '../../util/counter';
@@ -32,6 +33,8 @@ const messages = defineMessages({
schedulePost: { id: 'compose_form.schedule_post', defaultMessage: 'Schedule Post' }
});
const cx = classNames.bind(_s)
export default
@injectIntl
class ComposeForm extends ImmutablePureComponent {
@@ -49,6 +52,8 @@ class ComposeForm extends ImmutablePureComponent {
edit: PropTypes.bool.isRequired,
text: PropTypes.string.isRequired,
suggestions: ImmutablePropTypes.list,
account: ImmutablePropTypes.map.isRequired,
status: ImmutablePropTypes.map,
spoiler: PropTypes.bool,
privacy: PropTypes.string,
spoilerText: PropTypes.string,
@@ -164,7 +169,7 @@ class ComposeForm extends ImmutablePureComponent {
document.removeEventListener("click", this.handleClick, false);
}
componentDidUpdate (prevProps) {
componentDidUpdate(prevProps) {
if (!this.autosuggestTextarea) return;
// This statement does several things:
@@ -176,13 +181,13 @@ class ComposeForm extends ImmutablePureComponent {
let selectionEnd, selectionStart;
if (this.props.preselectDate !== prevProps.preselectDate) {
selectionEnd = this.props.text.length;
selectionEnd = this.props.text.length;
selectionStart = this.props.text.search(/\s/) + 1;
} else if (typeof this.props.caretPosition === 'number') {
selectionStart = this.props.caretPosition;
selectionEnd = this.props.caretPosition;
selectionEnd = this.props.caretPosition;
} else {
selectionEnd = this.props.text.length;
selectionEnd = this.props.text.length;
selectionStart = selectionEnd;
}
@@ -211,30 +216,65 @@ class ComposeForm extends ImmutablePureComponent {
this.props.onPickEmoji(position, data, needsSpace);
}
render () {
const { intl, onPaste, showSearch, anyMedia, shouldCondense, autoFocus, isModalOpen, quoteOfId, edit, scheduledAt } = this.props;
render() {
const {
intl,
account,
onPaste,
showSearch,
anyMedia,
shouldCondense,
autoFocus,
isModalOpen,
quoteOfId,
edit,
scheduledAt
} = this.props
const condensed = shouldCondense && !this.props.text && !this.state.composeFocused;
const disabled = this.props.isSubmitting;
const text = [this.props.spoilerText, countableText(this.props.text)].join('');
const text = [this.props.spoilerText, countableText(this.props.text)].join('');
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)
const composeClassNames = classNames({
'compose-form': true,
'condensed': condensed,
});
const containerClasses = cx({
default: 1,
flexGrow1: 1,
flexRow: shouldCondense,
radiusSmall: shouldCondense,
backgroundSubtle: shouldCondense,
paddingHorizontal5PX: shouldCondense,
})
const actionsContainerClasses = cx({
default: 1,
flexRow: 1,
alignItemsCenter: 1,
marginTop10PX: !shouldCondense,
})
const avatarContainerClasses = cx({
default: 1,
marginRight10PX: 1,
marginTop5PX: shouldCondense,
})
const avatarSize = shouldCondense ? 28 : 46
return (
<div
className={[_s.default, _s.flexGrow1].join(' ')}
ref={this.setForm}
onClick={this.handleClick}
>
{ /* <WarningContainer /> */ }
<div className={[_s.default, _s.flexRow, _s.width100PC].join(' ')}>
<div className={avatarContainerClasses}>
<Avatar account={account} size={avatarSize} />
</div>
<div
className={containerClasses}
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)}
@@ -254,63 +294,68 @@ class ComposeForm extends ImmutablePureComponent {
</div>
*/ }
{ /*
{ /*
<div className='emoji-picker-wrapper'>
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
</div> */ }
<AutosuggestTextbox
ref={(isModalOpen && shouldCondense) ? null : this.setAutosuggestTextarea}
placeholder={intl.formatMessage(messages.placeholder)}
disabled={disabled}
value={this.props.text}
onChange={this.handleChange}
suggestions={this.props.suggestions}
onKeyDown={this.handleKeyDown}
onFocus={this.handleComposeFocus}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
onSuggestionSelected={this.onSuggestionSelected}
onPaste={onPaste}
autoFocus={shouldAutoFocus}
textarea
>
{ /*
<AutosuggestTextbox
ref={(isModalOpen && shouldCondense) ? null : this.setAutosuggestTextarea}
placeholder={intl.formatMessage(messages.placeholder)}
disabled={disabled}
value={this.props.text}
onChange={this.handleChange}
suggestions={this.props.suggestions}
onKeyDown={this.handleKeyDown}
onFocus={this.handleComposeFocus}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
onSuggestionSelected={this.onSuggestionSelected}
onPaste={onPaste}
autoFocus={shouldAutoFocus}
small={shouldCondense}
textarea
>
{ /*
!condensed &&
<div className='compose-form__modifiers'>
<UploadForm />
{!edit && <PollFormContainer />}
</div>
*/ }
</AutosuggestTextbox>
</AutosuggestTextbox>
{ /* quoteOfId && <QuotedStatusPreviewContainer id={quoteOfId} /> */ }
{ /* quoteOfId && <QuotedStatusPreviewContainer id={quoteOfId} /> */}
{
/* !condensed && */
<div className={[_s.default, _s.flexRow, _s.marginTop10PX].join(' ')}>
<div className={actionsContainerClasses}>
<div className={[_s.default, _s.flexRow, _s.marginRightAuto].join(' ')}>
<UploadButton />
<UploadButton small={shouldCondense} />
{
!edit && <PollButton />
!edit && <PollButton small={shouldCondense} />
}
<PrivacyDropdown />
<SpoilerButton />
<SchedulePostDropdown position={isModalOpen ? 'top' : undefined} />
{
!shouldCondense &&
<PrivacyDropdown />
}
<SpoilerButton small={shouldCondense} />
<SchedulePostDropdown small={shouldCondense} position={isModalOpen ? 'top' : undefined} />
</div>
<CharacterCounter max={maxPostCharacterCount} text={text} />
<Button
className={[_s.fontSize15PX, _s.paddingHorizontal15PX].join(' ')}
onClick={this.handleSubmit}
disabled={disabledButton}
>
{intl.formatMessage(scheduledAt ? messages.schedulePost : messages.publish)}
</Button>
<CharacterCounter max={maxPostCharacterCount} text={text} small={shouldCondense} />
{
!shouldCondense &&
<Button
className={[_s.fontSize15PX, _s.paddingHorizontal15PX].join(' ')}
onClick={this.handleSubmit}
disabled={disabledButton}
>
{intl.formatMessage(scheduledAt ? messages.schedulePost : messages.publish)}
</Button>
}
</div>
}
</div>
</div>
);
)
}
}

View File

@@ -38,6 +38,7 @@ class PollButton extends PureComponent {
active: PropTypes.bool,
onClick: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
small: PropTypes.bool,
};
handleClick = () => {
@@ -45,7 +46,7 @@ class PollButton extends PureComponent {
}
render() {
const { intl, active, unavailable, disabled } = this.props;
const { intl, active, unavailable, disabled, small } = this.props;
if (unavailable) return null;
@@ -55,6 +56,7 @@ class PollButton extends PureComponent {
disabled={disabled}
onClick={this.handleClick}
icon='poll'
small={small}
/>
)
}

View File

@@ -56,6 +56,7 @@ class SchedulePostDropdown extends PureComponent {
isPro: PropTypes.bool,
onOpenProUpgradeModal: PropTypes.func.isRequired,
position: PropTypes.string,
small: PropTypes.bool,
}
handleToggle = () => {
@@ -73,7 +74,7 @@ class SchedulePostDropdown extends PureComponent {
}
render () {
const { intl, date, isPro, position } = this.props
const { intl, date, isPro, position, small } = this.props
const open = !!date
const datePickerDisabled = !isPro
@@ -87,6 +88,7 @@ class SchedulePostDropdown extends PureComponent {
icon='calendar'
title={intl.formatMessage(messages.schedule_status)}
onClick={this.handleToggle}
small={small}
/>
</div>
{

View File

@@ -28,6 +28,7 @@ class SpoilerButton extends PureComponent {
static propTypes = {
active: PropTypes.bool,
intl: PropTypes.map,
small: PropTypes.bool,
}
handleClick = (e) => {
@@ -36,13 +37,14 @@ class SpoilerButton extends PureComponent {
}
render () {
const { active, intl } = this.props
const { active, intl, small } = this.props
return (
<ComposeExtraButton
title={intl.formatMessage(messages.title)}
icon='warning'
onClick={this.handleClick}
small={small}
/>
)
}

View File

@@ -39,6 +39,7 @@ class UploadButton extends ImmutablePureComponent {
resetFileKey: PropTypes.number,
acceptContentTypes: ImmutablePropTypes.listOf(PropTypes.string).isRequired,
intl: PropTypes.object.isRequired,
small: PropTypes.bool,
}
handleChange = (e) => {
@@ -56,7 +57,7 @@ class UploadButton extends ImmutablePureComponent {
}
render() {
const { intl, resetFileKey, unavailable, disabled, acceptContentTypes } = this.props
const { intl, resetFileKey, unavailable, disabled, acceptContentTypes, small } = this.props
if (unavailable) return null
@@ -66,6 +67,7 @@ class UploadButton extends ImmutablePureComponent {
disabled={disabled}
onClick={this.handleClick}
icon='media'
small={small}
>
<label>
<span className={_s.displayNone}>{intl.formatMessage(messages.upload)}</span>