This commit is contained in:
mgabdev 2020-05-06 19:40:54 -04:00
parent 4dfb7c9fd6
commit c1131db577
30 changed files with 811 additions and 452 deletions

View File

@ -1,4 +1,5 @@
import api from '../api'; import api from '../api';
import { FormattedMessage } from 'react-intl'
import { CancelToken, isCancel } from 'axios'; import { CancelToken, isCancel } from 'axios';
import throttle from 'lodash.throttle' import throttle from 'lodash.throttle'
import moment from 'moment-mini' import moment from 'moment-mini'
@ -13,6 +14,7 @@ import { updateTimeline, dequeueTimeline } from './timelines';
import { defineMessages } from 'react-intl'; import { defineMessages } from 'react-intl';
import { openModal, closeModal } from './modal'; import { openModal, closeModal } from './modal';
import { me } from '../initial_state'; import { me } from '../initial_state';
import { makeGetStatus } from '../selectors'
let cancelFetchComposeSuggestionsAccounts; let cancelFetchComposeSuggestionsAccounts;
@ -79,14 +81,88 @@ export const ensureComposeIsVisible = (getState, routerHistory) => {
}; };
export function changeCompose(text, markdown, replyId) { export function changeCompose(text, markdown, replyId) {
console.log("changeCompose:", text) return function (dispatch, getState) {
return { const reduxReplyToId = getState().getIn(['compose', 'in_reply_to'])
type: COMPOSE_CHANGE, const existingText = getState().getIn(['compose', 'text']).trim()
text: text, const isModalOpen = getState().getIn(['modal', 'modalType']) === 'COMPOSE'
markdown: markdown,
replyId: replyId, let status
}; if (!!replyId) {
}; status = getState().getIn(['statuses', replyId])
status = makeGetStatus()(getState(), {
id: status.get('id')
})
}
if (!!replyId && replyId !== reduxReplyToId && !isModalOpen) {
if (existingText.length === 0 && text.trim().length > 0) {
dispatch({
type: COMPOSE_REPLY,
status: status,
})
dispatch({
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
})
} else if (existingText.length > 0 && text.trim().length > 0) {
dispatch(openModal('CONFIRM', {
message: <FormattedMessage id='confirmations.reply.message' defaultMessage='Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' />,
confirm: <FormattedMessage id='confirmations.reply.confirm' defaultMessage='Reply' />,
onConfirm: () => {
dispatch({
type: COMPOSE_REPLY,
status: status,
})
dispatch({
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
})
}
}))
} else {
dispatch({
type: COMPOSE_REPLY_CANCEL,
})
}
} else if (!replyId && !!reduxReplyToId && !isModalOpen) {
if (existingText.length === 0 && text.trim().length > 0) {
dispatch({
type: COMPOSE_REPLY_CANCEL,
})
dispatch({
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
})
} else if (existingText.length > 0 && text.trim().length > 0) {
dispatch(openModal('CONFIRM', {
message: <FormattedMessage id='confirmations.new_compose.message' defaultMessage='Composing now will overwrite the reply you are currently writing. Are you sure you want to proceed?' />,
confirm: <FormattedMessage id='confirmations.new_compose.confirm' defaultMessage='Yes' />,
onConfirm: () => {
dispatch({
type: COMPOSE_REPLY_CANCEL,
})
dispatch({
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
})
},
}))
} else {
//
}
} else {
dispatch({
type: COMPOSE_CHANGE,
text: text,
markdown: markdown,
})
}
}
}
export function replyCompose(status, router, showModal) { export function replyCompose(status, router, showModal) {
return (dispatch) => { return (dispatch) => {

View File

@ -0,0 +1,24 @@
const BlockIcon = ({
className = '',
size = '16px',
title = '',
}) => (
<svg
className={className}
version='1.1'
xmlns='http://www.w3.org/2000/svg'
x='0px'
y='0px'
width={size}
height={size}
viewBox='0 0 48 48'
xmlSpace='preserve'
aria-label={title}
>
<g>
<path d='M 24 0 C 10.800781 0 0 10.800781 0 24 C 0 37.199219 10.800781 48 24 48 C 37.199219 48 48 37.199219 48 24 C 48 10.800781 37.199219 0 24 0 Z M 4.800781 24 C 4.800781 13.441406 13.441406 4.800781 24 4.800781 C 28.320312 4.800781 32.398438 6.238281 35.761719 8.878906 L 8.878906 35.761719 C 6.238281 32.398438 4.800781 28.320312 4.800781 24 Z M 24 43.199219 C 19.679688 43.199219 15.601562 41.761719 12.238281 39.121094 L 39.121094 12.238281 C 41.761719 15.601562 43.199219 19.679688 43.199219 24 C 43.199219 34.558594 34.558594 43.199219 24 43.199219 Z M 24 43.199219' />
</g>
</svg>
)
export default BlockIcon

View File

@ -0,0 +1,26 @@
const TrashIcon = ({
className = '',
size = '32px',
title = 'Trash',
}) => (
<svg
className={className}
version='1.1'
xmlns='http://www.w3.org/2000/svg'
x='0px'
y='0px'
width={size}
height={size}
viewBox='0 0 48 48'
xmlSpace='preserve'
aria-label={title}
>
<g>
<path d='M 16.171875 4.363281 C 16.171875 2.929688 17.289062 1.886719 18.71875 1.886719 L 29.1875 1.886719 C 30.617188 1.886719 31.734375 2.929688 31.734375 4.363281 L 31.734375 7.074219 L 33.617188 7.074219 L 33.617188 4.363281 C 33.617188 1.890625 31.65625 0 29.1875 0 L 18.71875 0 C 16.25 0 14.285156 1.890625 14.285156 4.363281 L 14.285156 7.074219 L 16.171875 7.074219 Z M 16.171875 4.363281' />
<path d='M 12.800781 47.976562 L 35.105469 47.976562 C 37.253906 47.976562 38.921875 46.085938 38.921875 43.734375 L 38.921875 14.617188 L 8.980469 14.617188 L 8.980469 43.734375 C 8.980469 46.085938 10.652344 47.976562 12.800781 47.976562 Z M 29.964844 19.121094 C 29.964844 18.597656 30.386719 18.175781 30.90625 18.175781 C 31.429688 18.175781 31.851562 18.597656 31.851562 19.121094 L 31.851562 41.398438 C 31.851562 41.917969 31.429688 42.339844 30.90625 42.339844 C 30.386719 42.339844 29.964844 41.917969 29.964844 41.398438 Z M 23.007812 19.121094 C 23.007812 18.597656 23.433594 18.175781 23.953125 18.175781 C 24.472656 18.175781 24.894531 18.597656 24.894531 19.121094 L 24.894531 41.398438 C 24.894531 41.917969 24.472656 42.339844 23.953125 42.339844 C 23.433594 42.339844 23.007812 41.917969 23.007812 41.398438 Z M 16.054688 19.121094 C 16.054688 18.597656 16.476562 18.175781 16.996094 18.175781 C 17.519531 18.175781 17.941406 18.597656 17.941406 19.121094 L 17.941406 41.398438 C 17.941406 41.917969 17.519531 42.339844 16.996094 42.339844 C 16.476562 42.339844 16.054688 41.917969 16.054688 41.398438 Z M 16.054688 19.121094' />
<path d='M 8.015625 12.730469 L 39.890625 12.730469 C 41.191406 12.730469 42.246094 11.675781 42.246094 10.375 C 42.246094 9.070312 41.191406 8.015625 39.890625 8.015625 L 8.015625 8.015625 C 6.714844 8.015625 5.65625 9.070312 5.65625 10.375 C 5.65625 11.675781 6.714844 12.730469 8.015625 12.730469 Z M 8.015625 12.730469' />
</g>
</svg>
)
export default TrashIcon

View File

@ -58,8 +58,12 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(favorite(status)) dispatch(favorite(status))
} }
}, },
onOpenStatusOptions(status) { onOpenStatusOptions(targetRef, status) {
dispatch(openPopover('STATUS_OPTOINS', { status })) dispatch(openPopover('STATUS_OPTIONS', {
targetRef,
status,
position: 'top',
}))
}, },
onOpenLikes(status) { onOpenLikes(status) {
dispatch(openModal('STATUS_LIKES', { status })) dispatch(openModal('STATUS_LIKES', { status }))
@ -67,6 +71,11 @@ const mapDispatchToProps = (dispatch) => ({
onOpenReposts(status) { onOpenReposts(status) {
dispatch(openModal('STATUS_REPOSTS', { status })) dispatch(openModal('STATUS_REPOSTS', { status }))
}, },
onOpenStatusRevisionsPopover(status) {
dispatch(openModal('STATUS_REVISIONS', {
status,
}))
},
}) })
export default export default
@ -87,6 +96,7 @@ class Comment extends ImmutablePureComponent {
onOpenStatusOptions: PropTypes.func.isRequired, onOpenStatusOptions: PropTypes.func.isRequired,
onOpenLikes: PropTypes.func.isRequired, onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired, onOpenReposts: PropTypes.func.isRequired,
onOpenStatusRevisionsPopover: PropTypes.func.isRequired,
} }
updateOnProps = [ updateOnProps = [
@ -103,6 +113,10 @@ class Comment extends ImmutablePureComponent {
height: undefined, height: undefined,
} }
handleClick = () => {
//
}
handleOnReply = () => { handleOnReply = () => {
this.props.onReply(this.props.status) this.props.onReply(this.props.status)
} }
@ -112,7 +126,11 @@ class Comment extends ImmutablePureComponent {
} }
handleOnOpenStatusOptions = () => { handleOnOpenStatusOptions = () => {
this.props.onOpenStatusOptions(this.props.status) this.props.onOpenStatusOptions(this.moreNode, this.props.status)
}
setMoreNode = (c) => {
this.moreNode = c
} }
render() { render() {
@ -150,7 +168,7 @@ class Comment extends ImmutablePureComponent {
return ( return (
<div className={[_s.default, _s.px15, _s.mb10, _s.py5].join(' ')} data-comment={status.get('id')}> <div className={[_s.default, _s.px15, _s.mb10, _s.py5].join(' ')} data-comment={status.get('id')}>
<div className={[_s.default].join(' ')} style={style}> <div className={_s.default} style={style}>
<div className={[_s.default, _s.flexRow].join(' ')}> <div className={[_s.default, _s.flexRow].join(' ')}>
<NavLink <NavLink
@ -166,6 +184,7 @@ class Comment extends ImmutablePureComponent {
<CommentHeader <CommentHeader
ancestorAccountId={ancestorAccountId} ancestorAccountId={ancestorAccountId}
status={status} status={status}
onOpenRevisions={this.props.onOpenStatusRevisionsPopover}
onOpenLikes={this.props.onOpenLikes} onOpenLikes={this.props.onOpenLikes}
onOpenReposts={this.props.onOpenReposts} onOpenReposts={this.props.onOpenReposts}
/> />
@ -199,10 +218,12 @@ class Comment extends ImmutablePureComponent {
title={intl.formatMessage(messages.reply)} title={intl.formatMessage(messages.reply)}
onClick={this.handleOnReply} onClick={this.handleOnReply}
/> />
<CommentButton <div ref={this.setMoreNode}>
title='···' <CommentButton
onClick={this.handleOnOpenStatusOptions} title='···'
/> onClick={this.handleOnOpenStatusOptions}
/>
</div>
</div> </div>
</div> </div>

View File

@ -14,6 +14,7 @@ const messages = defineMessages({
edited: { id: 'status.edited', defaultMessage: 'Edited' }, edited: { id: 'status.edited', defaultMessage: 'Edited' },
likesLabel: { id: 'likes.label', defaultMessage: '{number, plural, one {# like} other {# likes}}' }, likesLabel: { id: 'likes.label', defaultMessage: '{number, plural, one {# like} other {# likes}}' },
repostsLabel: { id: 'reposts.label', defaultMessage: '{number, plural, one {# repost} other {# reposts}}' }, repostsLabel: { id: 'reposts.label', defaultMessage: '{number, plural, one {# repost} other {# reposts}}' },
original: { id: 'original_gabber', defaultMessage: 'Original Gabber' },
}) })
export default export default
@ -24,8 +25,9 @@ class CommentHeader extends ImmutablePureComponent {
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
ancestorAccountId: PropTypes.string.isRequired, ancestorAccountId: PropTypes.string.isRequired,
status: ImmutablePropTypes.map.isRequired, status: ImmutablePropTypes.map.isRequired,
openLikesList: PropTypes.func.isRequired, onOpenLikes: PropTypes.func.isRequired,
openRepostsList: PropTypes.func.isRequired, onOpenReposts: PropTypes.func.isRequired,
onOpenRevisions: PropTypes.func.isRequired,
} }
openLikesList = () => { openLikesList = () => {
@ -36,6 +38,10 @@ class CommentHeader extends ImmutablePureComponent {
this.props.onOpenReposts(this.props.status) this.props.onOpenReposts(this.props.status)
} }
openRevisions = () => {
this.props.onOpenRevisions(this.props.status)
}
render() { render() {
const { const {
intl, intl,
@ -52,27 +58,50 @@ class CommentHeader extends ImmutablePureComponent {
const isOwner = ancestorAccountId === status.getIn(['account', 'id']) const isOwner = ancestorAccountId === status.getIn(['account', 'id'])
return ( return (
<div className={[_s.default, _s.alignItemsStart, _s.py2, _s.flexGrow1].join(' ')}> <div className={[_s.default, _s.alignItemsStart, _s.py2, _s.maxWidth100PC, _s.flexGrow1].join(' ')}>
<div className={[_s.default, _s.flexRow, _s.width100PC, _s.alignItemsCenter].join(' ')}> <div className={[_s.default, _s.flexRow, _s.overflowHidden, _s.width100PC, _s.maxWidth100PC, _s.alignItemsCenter].join(' ')}>
<NavLink <NavLink
className={[_s.default, _s.flexRow, _s.alignItemsStart, _s.noUnderline].join(' ')} className={[_s.default, _s.flexRow, _s.alignItemsStart, _s.noUnderline].join(' ')}
to={`/${status.getIn(['account', 'acct'])}`} to={`/${status.getIn(['account', 'acct'])}`}
title={status.getIn(['account', 'acct'])} title={status.getIn(['account', 'acct'])}
> >
<DisplayName account={status.get('account')} isSmall /> <DisplayName
account={status.get('account')}
isSmall
isComment
/>
</NavLink> </NavLink>
{ {
isOwner && isOwner &&
<div className={[_s.default, _s.alignItemsCenter, _s.ml5].join(' ')}> <div className={[_s.default, _s.alignItemsCenter, _s.ml5].join(' ')}>
<span className={_s.visiblyHidden}> <span className={_s.visiblyHidden}>
Original Gabber {intl.formatMessage(messages.original)}
</span> </span>
<Icon id='mic' size='10px' className={_s.fillBrand} /> <Icon id='mic' size='10px' className={_s.fillBrand} />
</div> </div>
} }
{
!!status.get('group') &&
<Fragment>
<DotTextSeperator />
<Button
isText
underlineOnHover
backgroundColor='none'
color='tertiary'
to={`/groups/${status.getIn(['group', 'id'])}`}
className={_s.ml5}
>
<Text size='extraSmall' color='inherit'>
{status.getIn(['group', 'title'])}
</Text>
</Button>
</Fragment>
}
{ {
status.get('revised_at') !== null && status.get('revised_at') !== null &&
<Fragment> <Fragment>
@ -82,7 +111,7 @@ class CommentHeader extends ImmutablePureComponent {
underlineOnHover underlineOnHover
backgroundColor='none' backgroundColor='none'
color='tertiary' color='tertiary'
onClick={this.handleOpenStatusEdits} onClick={this.openRevisions}
className={_s.ml5} className={_s.ml5}
> >
<Text size='extraSmall' color='inherit'> <Text size='extraSmall' color='inherit'>

View File

@ -32,6 +32,7 @@ class DisplayName extends ImmutablePureComponent {
noHover: PropTypes.bool, noHover: PropTypes.bool,
noRelationship: PropTypes.bool, noRelationship: PropTypes.bool,
noUsername: PropTypes.bool, noUsername: PropTypes.bool,
isComment: PropTypes.bool,
} }
updateOnProps = [ updateOnProps = [
@ -42,6 +43,7 @@ class DisplayName extends ImmutablePureComponent {
'noHover', 'noHover',
'noRelationship', 'noRelationship',
'noUsername', 'noUsername',
'isComment',
] ]
mouseOverTimeout = null mouseOverTimeout = null
@ -77,7 +79,8 @@ class DisplayName extends ImmutablePureComponent {
noHover, noHover,
noUsername, noUsername,
noRelationship, noRelationship,
isSmall isSmall,
isComment,
} = this.props } = this.props
if (!account) return null if (!account) return null
@ -122,6 +125,7 @@ class DisplayName extends ImmutablePureComponent {
const iconSize = const iconSize =
!!isLarge ? '19px' : !!isLarge ? '19px' :
!!isComment ? '12px' :
!!isSmall ? '14px' : '15px' !!isSmall ? '14px' : '15px'
const domain = account.get('acct').split('@')[1] const domain = account.get('acct').split('@')[1]
@ -153,7 +157,7 @@ class DisplayName extends ImmutablePureComponent {
onMouseLeave={noHover ? undefined : this.handleMouseLeave} onMouseLeave={noHover ? undefined : this.handleMouseLeave}
ref={this.setRef} ref={this.setRef}
> >
<span className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}> <span className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.maxWidth180PX, _s.maxWidth100PC].join(' ')}>
<bdi className={[_s.text, _s.whiteSpaceNoWrap, _s.textOverflowEllipsis].join(' ')}> <bdi className={[_s.text, _s.whiteSpaceNoWrap, _s.textOverflowEllipsis].join(' ')}>
<strong <strong
className={displayNameClasses} className={displayNameClasses}

View File

@ -31,10 +31,11 @@ class FloatingActionButton extends PureComponent {
return ( return (
<Button <Button
onClick={onOpenCompose} onClick={onOpenCompose}
className={[_s.posFixed, _s.z4, _s.py15, _s.mb15, _s.mr15, _s.bottom50PX, _s.right0].join(' ')} className={[_s.posFixed, _s.z4, _s.py15, _s.mb15, _s.mr15, _s.bottom50PX, _s.height60PX, _s.width60PX, _s.right0, _s.justifyContentCenter, _s.alignItemsCenter].join(' ')}
title={message} title={message}
aria-label={message} aria-label={message}
icon='pencil' icon='pencil'
iconSize='20px'
/> />
) )
} }

View File

@ -6,6 +6,7 @@ import ArrowRightIcon from '../assets/arrow_right_icon'
import AudioIcon from '../assets/audio_icon' import AudioIcon from '../assets/audio_icon'
import AudioMuteIcon from '../assets/audio_mute_icon' import AudioMuteIcon from '../assets/audio_mute_icon'
import BackIcon from '../assets/back_icon' import BackIcon from '../assets/back_icon'
import BlockIcon from '../assets/block_icon'
import BlockquoteIcon from '../assets/blockquote_icon' import BlockquoteIcon from '../assets/blockquote_icon'
import BoldIcon from '../assets/bold_icon' import BoldIcon from '../assets/bold_icon'
import CalendarIcon from '../assets/calendar_icon' import CalendarIcon from '../assets/calendar_icon'
@ -61,6 +62,7 @@ import ShopIcon from '../assets/shop_icon'
import StrikethroughIcon from '../assets/strikethrough_icon' import StrikethroughIcon from '../assets/strikethrough_icon'
import SubtractIcon from '../assets/subtract_icon' import SubtractIcon from '../assets/subtract_icon'
import TextSizeIcon from '../assets/text_size_icon' import TextSizeIcon from '../assets/text_size_icon'
import TrashIcon from '../assets/trash_icon'
import TrendsIcon from '../assets/trends_icon' import TrendsIcon from '../assets/trends_icon'
import ULListIcon from '../assets/ul_list_icon' import ULListIcon from '../assets/ul_list_icon'
import UnderlineIcon from '../assets/underline_icon' import UnderlineIcon from '../assets/underline_icon'
@ -78,6 +80,7 @@ const ICONS = {
'audio': AudioIcon, 'audio': AudioIcon,
'audio-mute': AudioMuteIcon, 'audio-mute': AudioMuteIcon,
'back': BackIcon, 'back': BackIcon,
'block': BlockIcon,
'blockquote': BlockquoteIcon, 'blockquote': BlockquoteIcon,
'bold': BoldIcon, 'bold': BoldIcon,
'calendar': CalendarIcon, 'calendar': CalendarIcon,
@ -132,6 +135,7 @@ const ICONS = {
'strikethrough': StrikethroughIcon, 'strikethrough': StrikethroughIcon,
'subtract': SubtractIcon, 'subtract': SubtractIcon,
'text-size': TextSizeIcon, 'text-size': TextSizeIcon,
'trash': TrashIcon,
'trends': TrendsIcon, 'trends': TrendsIcon,
'ul-list': ULListIcon, 'ul-list': ULListIcon,
'underline': UnderlineIcon, 'underline': UnderlineIcon,

View File

@ -8,11 +8,19 @@ import TimelineComposeBlock from '../timeline_compose_block'
const messages = defineMessages({ const messages = defineMessages({
confirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, confirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
title: { id: 'navigation_bar.compose', defaultMessage: 'Compose new gab' }, title: { id: 'navigation_bar.compose', defaultMessage: 'Compose new gab' },
comment: { id: 'navigation_bar.compose_comment', defaultMessage: 'Compose new comment' },
edit: { id: 'navigation_bar.edit_gab', defaultMessage: 'Edit' },
}) })
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => {
composeText: state.getIn(['compose', 'text']), const status = state.getIn(['statuses', state.getIn(['compose', 'id'])])
})
return {
composeText: state.getIn(['compose', 'text']),
isEditing: !!status,
isComment: !!state.getIn(['compose', 'in_reply_to']),
}
}
export default export default
@connect(mapStateToProps) @connect(mapStateToProps)
@ -24,10 +32,17 @@ class ComposeModal extends ImmutablePureComponent {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
composeText: PropTypes.string, composeText: PropTypes.string,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
}; isEditing: PropTypes.bool,
isComment: PropTypes.bool,
}
onClickClose = () => { onClickClose = () => {
const { composeText, dispatch, onClose, intl } = this.props; const {
composeText,
dispatch,
onClose,
intl,
} = this.props
if (composeText) { if (composeText) {
dispatch(openModal('CONFIRM', { dispatch(openModal('CONFIRM', {
@ -36,24 +51,30 @@ class ComposeModal extends ImmutablePureComponent {
confirm: intl.formatMessage(messages.confirm), confirm: intl.formatMessage(messages.confirm),
onConfirm: () => dispatch(cancelReplyCompose()), onConfirm: () => dispatch(cancelReplyCompose()),
onCancel: () => dispatch(openModal('COMPOSE')), onCancel: () => dispatch(openModal('COMPOSE')),
})); }))
} }
else { else {
onClose('COMPOSE'); onClose('COMPOSE')
} }
}; }
render() { render() {
const { intl } = this.props const {
intl,
isEditing,
isComment,
} = this.props
const title = isEditing ? messages.edit : isComment ? messages.comment : messages.title
return ( return (
<ModalLayout <ModalLayout
noPadding noPadding
title={intl.formatMessage(messages.title)} title={intl.formatMessage(title)}
onClose={this.onClickClose} onClose={this.onClickClose}
> >
<TimelineComposeBlock modal /> <TimelineComposeBlock modal />
</ModalLayout> </ModalLayout>
); )
} }
} }

View File

@ -61,29 +61,33 @@ class HomeTimelineSettingsModal extends ImmutablePureComponent {
> >
<div className={[_s.default, _s.pb10].join(' ')}> <div className={[_s.default, _s.pb10].join(' ')}>
<SettingSwitch {
prefix='home_timeline' /*
settings={settings} <SettingSwitch
settingPath={['shows', 'polls']} prefix='home_timeline'
onChange={onChange} settings={settings}
label={intl.formatMessage(messages.showPolls)} settingPath={['shows', 'polls']}
/> onChange={onChange}
label={intl.formatMessage(messages.showPolls)}
/>
<SettingSwitch <SettingSwitch
prefix='home_timeline' prefix='home_timeline'
settings={settings} settings={settings}
settingPath={['shows', 'photos']} settingPath={['shows', 'photos']}
onChange={onChange} onChange={onChange}
label={intl.formatMessage(messages.showPhotos)} label={intl.formatMessage(messages.showPhotos)}
/> />
<SettingSwitch <SettingSwitch
prefix='home_timeline' prefix='home_timeline'
settings={settings} settings={settings}
settingPath={['shows', 'videos']} settingPath={['shows', 'videos']}
onChange={onChange} onChange={onChange}
label={intl.formatMessage(messages.showVideos)} label={intl.formatMessage(messages.showVideos)}
/> />
*/
}
<SettingSwitch <SettingSwitch
prefix='home_timeline' prefix='home_timeline'

View File

@ -23,23 +23,24 @@ class UnauthorizedModal extends ImmutablePureComponent {
} }
render() { render() {
const { intl } = this.props const { intl, onClose } = this.props
return ( return (
<ModalLayout <ModalLayout
title={intl.formatMessage(messages.signup)} title={intl.formatMessage(messages.signup)}
onClose={onClose} onClose={onClose}
width={400}
> >
<div className={[_s.default, _s.px10, _s.py10].join(' ')}> <div className={[_s.default, _s.px10, _s.py10].join(' ')}>
<Text className={_s.mb15}> <Text className={_s.mb15} align='center'>
{intl.formatMessage(messages.text)} {intl.formatMessage(messages.text)}
</Text> </Text>
<Button href='/auth/sign_up' className={[_s.width240PX, _s.mlAuto, _s.mlAuto].join(' ')}> <Button isBlock href='/auth/sign_up' className={[_s.mr15, _s.ml15, _s.mlAuto, _s.mrAuto].join(' ')}>
{intl.formatMessage(messages.register)} {intl.formatMessage(messages.register)}
</Button> </Button>
</div> </div>
<div className={[_s.default, _s.px10, _s.py10].join(' ')}> <div className={[_s.default, _s.px10, _s.py5].join(' ')}>
<Text color='secondary'> <Text color='secondary' size='small' align='center'>
{ {
intl.formatMessage(messages.login, { intl.formatMessage(messages.login, {
login: ( login: (

View File

@ -128,7 +128,7 @@ class NavigationBar extends ImmutablePureComponent {
noClasses noClasses
color='primary' color='primary'
backgroundColor='none' backgroundColor='none'
className={[_s.alignItemsCenter, _s.height53PX, _s.bgTransparent, _s.mr5, _s.cursorPointer, _s.outlineNone, _s.default, _s.justifyContentCenter].join(' ')} className={[_s.height53PX, _s.bgTransparent, _s.mr5, _s.cursorPointer, _s.outlineNone, _s.default, _s.justifyContentCenter].join(' ')}
icon='arrow-left' icon='arrow-left'
iconSize='32px' iconSize='32px'
iconClassName={[_s.mr5, _s.fillPrimary].join(' ')} iconClassName={[_s.mr5, _s.fillPrimary].join(' ')}

View File

@ -1,3 +1,4 @@
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component'
import PillItem from './pill_item' import PillItem from './pill_item'
/** /**
@ -14,7 +15,10 @@ export default class Pills extends PureComponent {
const { pills } = this.props const { pills } = this.props
return ( return (
<div className={[_s.default, _s.flexWrap, _s.px5, _s.flexRow].join(' ')}> <ResponsiveClassesComponent
classNames={[_s.default, _s.flexWrap, _s.px5, _s.flexRow].join(' ')}
classNamesXS={[_s.default, _s.overflowYHidden, _s.overflowXScroll, _s.noScrollbar, _s.pl10, _s.pr15, _s.flexRow].join(' ')}
>
{ {
!!pills && !!pills &&
pills.map((tab, i) => ( pills.map((tab, i) => (
@ -27,7 +31,7 @@ export default class Pills extends PureComponent {
/> />
)) ))
} }
</div> </ResponsiveClassesComponent>
) )
} }

View File

@ -145,7 +145,7 @@ class PopoverBase extends ImmutablePureComponent {
referenceElement={targetRef} referenceElement={targetRef}
> >
{({ ref, style, placement, arrowProps }) => ( {({ ref, style, placement, arrowProps }) => (
<div ref={ref} style={style} data-placement={placement} className={[_s.mt5, _s.mb5, _s.boxShadowPopover].join(' ')}> <div ref={ref} style={style} data-placement={placement} className={[_s.z4, _s.mt5, _s.mb5, _s.boxShadowPopover].join(' ')}>
<div ref={arrowProps.ref} style={arrowProps.style} /> <div ref={arrowProps.ref} style={arrowProps.style} />
<div ref={this.setRef} data-popover='true' onKeyDown={this.handleKeyDown} className={containerClasses}> <div ref={this.setRef} data-popover='true' onKeyDown={this.handleKeyDown} className={containerClasses}>
{children} {children}

View File

@ -1,7 +1,28 @@
import ImmutablePropTypes from 'react-immutable-proptypes' import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component' import ImmutablePureComponent from 'react-immutable-pure-component'
import { defineMessages, injectIntl } from 'react-intl' import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'
import { me, isStaff } from '../../initial_state' import { me, isStaff, boostModal, deleteModal } from '../../initial_state'
import {
repost,
unrepost,
pin,
unpin,
} from '../../actions/interactions';
import {
muteStatus,
unmuteStatus,
deleteStatus,
editStatus,
} from '../../actions/statuses';
import {
fetchGroupRelationships,
createRemovedAccount,
groupRemoveStatus,
} from '../../actions/groups'
import { initMuteModal } from '../../actions/mutes'
import { initReport } from '../../actions/reports'
import { openModal } from '../../actions/modal'
import { closePopover } from '../../actions/popover'
import PopoverLayout from './popover_layout' import PopoverLayout from './popover_layout'
import List from '../list' import List from '../list'
@ -16,7 +37,7 @@ const messages = defineMessages({
replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' }, replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' },
repost: { id: 'repost', defaultMessage: 'Repost' }, repost: { id: 'repost', defaultMessage: 'Repost' },
quote: { id: 'status.quote', defaultMessage: 'Quote' }, quote: { id: 'status.quote', defaultMessage: 'Quote' },
repost_private: { id: 'status.repost_private', defaultMessage: 'Repost to original audience' }, repost_private: { id: 'status.repost', defaultMessage: 'Repost' },
cancel_repost_private: { id: 'status.cancel_repost_private', defaultMessage: 'Remove Repost' }, cancel_repost_private: { id: 'status.cancel_repost_private', defaultMessage: 'Remove Repost' },
cannot_repost: { id: 'status.cannot_repost', defaultMessage: 'This post cannot be reposted' }, cannot_repost: { id: 'status.cannot_repost', defaultMessage: 'This post cannot be reposted' },
cannot_quote: { id: 'status.cannot_quote', defaultMessage: 'This post cannot be quoted' }, cannot_quote: { id: 'status.cannot_quote', defaultMessage: 'This post cannot be quoted' },
@ -30,14 +51,128 @@ const messages = defineMessages({
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' }, admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },
group_remove_account: { id: 'status.remove_account_from_group', defaultMessage: 'Remove account from group' }, group_remove_account: { id: 'status.remove_account_from_group', defaultMessage: 'Remove account from group' },
group_remove_post: { id: 'status.remove_post_from_group', defaultMessage: 'Remove status from group' }, group_remove_post: { id: 'status.remove_post_from_group', defaultMessage: 'Remove status from group' },
repostWithComment: { id: 'repost_with_comment', defaultMessage: 'Repost with comment' },
}) })
const mapStateToProps = (state) => ({ const mapStateToProps = (state, { status }) => {
if (!me) return null
}) const groupId = status ? status.getIn(['group', 'id']) : undefined
const groupRelationships = state.getIn(['group_relationships', groupId])
return {
groupId,
groupRelationships,
}
}
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
onMuteConversation(status) {
dispatch(closePopover())
if (status.get('muted')) {
dispatch(unmuteStatus(status.get('id')))
} else {
dispatch(muteStatus(status.get('id')))
}
},
onPin(status) {
dispatch(closePopover())
if (status.get('pinned')) {
dispatch(unpin(status))
} else {
dispatch(pin(status))
}
},
onQuote(status, router) {
dispatch(closePopover())
dispatch((_, getState) => {
const state = getState()
if (state.getIn(['compose', 'text']).trim().length !== 0) {
dispatch(openModal(MODAL_CONFIRM, {
message: intl.formatMessage(messages.quoteMessage),
confirm: intl.formatMessage(messages.quoteConfirm),
onConfirm: () => dispatch(quoteCompose(status, router)),
}))
} else {
dispatch(quoteCompose(status, router))
}
})
},
onRepost(status) {
dispatch(closePopover())
const alreadyReposted = status.get('reblogged')
if (boostModal && !alreadyReposted) {
dispatch(openModal(MODAL_BOOST, {
status,
onRepost: () => dispatch(repost(status)),
}))
} else {
if (alreadyReposted) {
dispatch(unrepost(status))
} else {
dispatch(repost(status))
}
}
},
onDelete(status, history) {
dispatch(closePopover())
if (!deleteModal) {
dispatch(deleteStatus(status.get('id'), history))
} else {
dispatch(openModal('CONFIRM', {
message: <FormattedMessage id='confirmations.delete.message' defaultMessage='Are you sure you want to delete this status?' />,
confirm: <FormattedMessage id='confirmations.delete.confirm' defaultMessage='Delete' />,
onConfirm: () => dispatch(deleteStatus(status.get('id'), history)),
}))
}
},
onEdit(status) {
dispatch(closePopover())
dispatch(editStatus(status))
},
onMute(account) {
dispatch(closePopover())
dispatch(initMuteModal(account))
},
onBlock(status) {
dispatch(closePopover())
const account = status.get('account')
dispatch(openModal('BLOCK_ACCOUNT', {
accountId: account.get('id'),
}))
},
onReport(status) {
dispatch(closePopover())
dispatch(initReport(status.get('account'), status))
},
onGroupRemoveAccount(groupId, accountId) {
dispatch(closePopover())
dispatch(createRemovedAccount(groupId, accountId))
},
onGroupRemoveStatus(groupId, statusId) {
dispatch(closePopover())
dispatch(groupRemoveStatus(groupId, statusId))
},
onFetchGroupRelationships(groupId) {
dispatch(fetchGroupRelationships([groupId]))
}
}) })
export default export default
@ -47,184 +182,187 @@ class StatusOptionsPopover extends ImmutablePureComponent {
static propTypes = { static propTypes = {
status: ImmutablePropTypes.map.isRequired, status: ImmutablePropTypes.map.isRequired,
account: ImmutablePropTypes.map.isRequired, groupRelationships: ImmutablePropTypes.map,
onOpenUnauthorizedModal: PropTypes.func.isRequired, groupId: PropTypes.string,
onOpenStatusSharePopover: PropTypes.func.isRequired, onQuote: PropTypes.func.isRequired,
onReply: PropTypes.func, onRepost: PropTypes.func.isRequired,
onQuote: PropTypes.func, onDelete: PropTypes.func.isRequired,
onFavorite: PropTypes.func, onMute: PropTypes.func.isRequired,
onRepost: PropTypes.func, onBlock: PropTypes.func.isRequired,
onDelete: PropTypes.func, onReport: PropTypes.func.isRequired,
onMention: PropTypes.func, onMuteConversation: PropTypes.func.isRequired,
onMute: PropTypes.func, onPin: PropTypes.func.isRequired,
onBlock: PropTypes.func,
onReport: PropTypes.func,
onMuteConversation: PropTypes.func,
onPin: PropTypes.func,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
onFetchGroupRelationships: PropTypes.func.isRequired,
} }
updateOnProps = [ updateOnProps = [
'status', 'status',
'account', 'groupRelationships',
] ]
handleConversationMuteClick = () => { componentDidMount() {
this.props.onMuteConversation(this.props.status); if (!this.props.groupRelationships && this.props.groupId) {
this.props.onFetchGroupRelationships(this.props.groupId)
}
} }
handleGroupRemoveAccount = () => {
const { status } = this.props;
this.props.onGroupRemoveAccount(status.getIn(['group', 'id']), status.getIn(['account', 'id'])); handleConversationMuteClick = () => {
this.props.onMuteConversation(this.props.status)
}
handleGroupRemoveAccount = () => {
const { status } = this.props
this.props.onGroupRemoveAccount(status.getIn(['group', 'id']), status.getIn(['account', 'id']))
} }
handleGroupRemovePost = () => { handleGroupRemovePost = () => {
const { status } = this.props; const { status } = this.props
this.props.onGroupRemoveStatus(status.getIn(['group', 'id']), status.get('id')); this.props.onGroupRemoveStatus(status.getIn(['group', 'id']), status.get('id'))
} }
handleReport = () => { handleReport = () => {
this.props.onReport(this.props.status); this.props.onReport(this.props.status)
} }
handleBlockClick = () => { handleBlockClick = () => {
this.props.onBlock(this.props.status); this.props.onBlock(this.props.status)
} }
handleMuteClick = () => { handleMuteClick = () => {
this.props.onMute(this.props.status.get('account')); this.props.onMute(this.props.status.get('account'))
}
handleMentionClick = () => {
this.props.onMention(this.props.status.get('account'), this.context.router.history);
} }
handlePinClick = () => { handlePinClick = () => {
this.props.onPin(this.props.status); this.props.onPin(this.props.status)
} }
handleDeleteClick = () => { handleDeleteClick = () => {
this.props.onDelete(this.props.status, this.context.router.history); this.props.onDelete(this.props.status)
} }
handleEditClick = () => { handleEditClick = () => {
this.props.onEdit(this.props.status); this.props.onEdit(this.props.status)
} }
handleRepostClick = (e) => { handleRepostClick = (e) => {
if (me) { this.props.onRepost(this.props.status, e)
// this.props.onRepost(this.props.status, e)
this.props.onQuote(this.props.status, this.context.router.history)
} else {
this.props.onOpenUnauthorizedModal()
}
} }
render() { render() {
const { const {
status, status,
intl, intl,
account, groupRelationships,
} = this.props } = this.props
const mutingConversation = status.get('muted') const mutingConversation = status.get('muted')
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')) const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'))
const isReply = !!status.get('in_reply_to_id')
const withGroupAdmin = !!groupRelationships ? groupRelationships.get('admin') : false
console.log("withGroupAdmin:", withGroupAdmin, groupRelationships ? groupRelationships.get('admin') : '')
let menu = []; let menu = []
if (me) { if (me) {
// if (status.getIn(['account', 'id']) === me) { if (status.getIn(['account', 'id']) === me) {
menu.push({ menu.push({
icon: 'audio-mute', icon: 'audio-mute',
hideArrow: true, hideArrow: true,
title: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), title: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation),
onClick: this.handleConversationMuteClick, onClick: this.handleConversationMuteClick,
}) })
// } }
// if (status.getIn(['account', 'id']) === me) { if (isReply) {
// if (publicStatus) { menu.push({
icon: 'repost',
hideArrow: true,
title: intl.formatMessage(status.get('reblogged') ? messages.cancel_repost_private : messages.repost_private),
onClick: this.handleRepostClick,
})
menu.push({
icon: 'pencil',
hideArrow: true,
title: intl.formatMessage(messages.repostWithComment),
onClick: this.handleRepostClick,
})
}
if (status.getIn(['account', 'id']) === me) {
if (publicStatus) {
menu.push({ menu.push({
icon: 'pin', icon: 'pin',
hideArrow: true, hideArrow: true,
title: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), title: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin),
onClick: this.handlePinClick, onClick: this.handlePinClick,
}) })
// } else { }
// if (status.get('visibility') === 'private') {
menu.push({
icon: 'repost',
hideArrow: true,
title: intl.formatMessage(status.get('reblogged') ? messages.cancel_repost_private : messages.repost_private),
onClick: this.handleRepostClick
})
// }
// }
menu.push({ menu.push({
icon: 'trash', icon: 'trash',
hideArrow: true, hideArrow: true,
title: intl.formatMessage(messages.delete), title: intl.formatMessage(messages.delete),
action: this.handleDeleteClick onClick: this.handleDeleteClick,
}); })
menu.push({ menu.push({
icon: 'pencil', icon: 'pencil',
hideArrow: true, hideArrow: true,
title: intl.formatMessage(messages.edit), action: title: intl.formatMessage(messages.edit),
this.handleEditClick onClick: this.handleEditClick,
}); })
// } else { } else {
menu.push({ menu.push({
icon: 'audio-mute', icon: 'audio-mute',
hideArrow: true, hideArrow: true,
title: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), title: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }),
action: this.handleMuteClick onClick: this.handleMuteClick,
}); })
menu.push({ menu.push({
icon: 'circle', icon: 'block',
hideArrow: true, hideArrow: true,
title: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), title: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }),
action: this.handleBlockClick onClick: this.handleBlockClick,
}); })
menu.push({ menu.push({
icon: 'circle', icon: 'warning',
hideArrow: true, hideArrow: true,
title: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), title: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }),
action: this.handleReport onClick: this.handleReport,
}); })
// : todo : if (withGroupAdmin) {
// if (withGroupAdmin) {
menu.push({ menu.push({
icon: 'circle', icon: 'trash',
hideArrow: true, hideArrow: true,
title: intl.formatMessage(messages.group_remove_account), title: intl.formatMessage(messages.group_remove_account),
action: this.handleGroupRemoveAccount onClick: this.handleGroupRemoveAccount,
}); })
menu.push({ menu.push({
icon: 'circle', icon: 'trash',
hideArrow: true, hideArrow: true,
title: intl.formatMessage(messages.group_remove_post), title: intl.formatMessage(messages.group_remove_post),
action: this.handleGroupRemovePost onClick: this.handleGroupRemovePost,
}); })
// } }
// if (isStaff) { if (isStaff) {
menu.push({ menu.push({
title: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), title: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }),
href: `/admin/accounts/${status.getIn(['account', 'id'])}` href: `/admin/accounts/${status.getIn(['account', 'id'])}`
}); })
menu.push({ menu.push({
title: intl.formatMessage(messages.admin_status), title: intl.formatMessage(messages.admin_status),
href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}`
}); })
// } }
// } }
} }
return ( return (
<PopoverLayout className={_s.width240PX}> <PopoverLayout>
<List <List
size='large' size='large'
scrollKey='profile_options' scrollKey='profile_options'

View File

@ -95,6 +95,7 @@ class Status extends ImmutablePureComponent {
commentsLimited: PropTypes.bool, commentsLimited: PropTypes.bool,
onOpenLikes: PropTypes.func.isRequired, onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired, onOpenReposts: PropTypes.func.isRequired,
isComposeModalOpen: PropTypes.bool,
} }
// Avoid checking props that are functions (and whose equality will always // Avoid checking props that are functions (and whose equality will always
@ -136,14 +137,12 @@ class Status extends ImmutablePureComponent {
if (nextProps.isChild) return null if (nextProps.isChild) return null
if (!nextProps.isHidden && (nextProps.isIntersecting || !nextProps.commentsLimited) && !prevState.loadedComments) { if (!nextProps.isHidden && (nextProps.isIntersecting || !nextProps.commentsLimited) && !prevState.loadedComments) {
console.log("111111111111111111111111111111111111", nextProps.isHidden, nextProps.isIntersecting)
return { return {
loadedComments: true loadedComments: true
} }
} }
if (nextProps.status && nextProps.status.get('id') !== prevState.statusId) { if (nextProps.status && nextProps.status.get('id') !== prevState.statusId) {
console.log("2222222222222222222222222222222222222")
return { return {
loadedComments: false, //reset loadedComments: false, //reset
showMedia: defaultMediaVisibility(nextProps.status), showMedia: defaultMediaVisibility(nextProps.status),
@ -369,6 +368,7 @@ class Status extends ImmutablePureComponent {
ancestorStatus, ancestorStatus,
isComment, isComment,
contextType, contextType,
isComposeModalOpen,
} = this.props } = this.props
// const { height } = this.state // const { height } = this.state
@ -423,10 +423,12 @@ class Status extends ImmutablePureComponent {
}) })
const containerClassesXS = cx({ const containerClassesXS = cx({
default: 1,
bgPrimary: !isChild, bgPrimary: !isChild,
boxShadowBlock: !isChild && !compactMode, boxShadowBlock: !isChild && !compactMode,
borderTop1PX: !isChild,
borderBottom1PX: !isChild && compactMode, borderBottom1PX: !isChild && compactMode,
borderColorSecondary: !isChild && compactMode, borderColorSecondary: !isChild,
}) })
const innerContainerClasses = cx({ const innerContainerClasses = cx({
@ -482,7 +484,10 @@ class Status extends ImmutablePureComponent {
isComment={isComment && !isChild} isComment={isComment && !isChild}
/> />
<StatusHeader status={status} reduced={isChild} /> <StatusHeader
status={status}
reduced={isChild}
/>
<div className={_s.default}> <div className={_s.default}>
<StatusContent <StatusContent
@ -497,6 +502,7 @@ class Status extends ImmutablePureComponent {
<StatusMedia <StatusMedia
isChild={isChild} isChild={isChild}
isComposeModalOpen={isComposeModalOpen}
status={status} status={status}
onOpenMedia={this.props.onOpenMedia} onOpenMedia={this.props.onOpenMedia}
cacheWidth={this.props.cacheMediaWidth} cacheWidth={this.props.cacheMediaWidth}

View File

@ -54,13 +54,14 @@ const addAutoPlay = html => {
return html return html
} }
export default class Card extends ImmutablePureComponent { export default class StatusCard extends ImmutablePureComponent {
static propTypes = { static propTypes = {
card: ImmutablePropTypes.map, card: ImmutablePropTypes.map,
onOpenMedia: PropTypes.func.isRequired, onOpenMedia: PropTypes.func.isRequired,
defaultWidth: PropTypes.number, defaultWidth: PropTypes.number,
cacheWidth: PropTypes.func, cacheWidth: PropTypes.func,
isReduced: PropTypes.bool,
} }
state = { state = {
@ -129,7 +130,7 @@ export default class Card extends ImmutablePureComponent {
} }
render() { render() {
const { card } = this.props const { card, isReduced } = this.props
const { width, embedded } = this.state const { width, embedded } = this.state
if (card === null) return null if (card === null) return null
@ -199,22 +200,25 @@ export default class Card extends ImmutablePureComponent {
return ( return (
<div className={[_s.default, _s.width100PC, _s.px10].join(' ')}> <div className={[_s.default, _s.width100PC, _s.px10].join(' ')}>
<div className={[_s.default, _s.overflowHidden, _s.width100PC, _s.borderColorSecondary, _s.border1PX, _s.radiusSmall].join(' ')}> <div className={[_s.default, _s.overflowHidden, _s.width100PC, _s.borderColorSecondary, _s.border1PX, _s.radiusSmall].join(' ')}>
<div className={[_s.default, _s.width100PC].join(' ')}> {
<div className={[_s.default, _s.width100PC, _s.pt5625PC].join(' ')}> !isReduced &&
{!!embed && embed} <div className={[_s.default, _s.width100PC].join(' ')}>
{!embed && thumbnail} <div className={[_s.default, _s.width100PC, _s.pt5625PC].join(' ')}>
{!embed && {!!embed && embed}
<div className={[_s.default, _s.posAbs, _s.top0, _s.right0, _s.left0, _s.bottom0, _s.alignItemsCenter, _s.justifyContentCenter].join(' ')}> {!embed && thumbnail}
<button {!embed &&
className={[_s.default, _s.cursorPointer, _s.bgBlackOpaque, _s.radiusSmall, _s.py15, _s.px15].join(' ')} <div className={[_s.default, _s.posAbs, _s.top0, _s.right0, _s.left0, _s.bottom0, _s.alignItemsCenter, _s.justifyContentCenter].join(' ')}>
onClick={this.handleEmbedClick} <button
> className={[_s.default, _s.cursorPointer, _s.bgBlackOpaque, _s.radiusSmall, _s.py15, _s.px15].join(' ')}
<Icon id={iconVariant} size='22px' className={[_s.fillWhite].join(' ')} /> onClick={this.handleEmbedClick}
</button> >
</div> <Icon id={iconVariant} size='22px' className={[_s.fillWhite].join(' ')} />
} </button>
</div>
}
</div>
</div> </div>
</div> }
{description} {description}
</div> </div>
</div> </div>
@ -245,7 +249,7 @@ export default class Card extends ImmutablePureComponent {
classNames={[_s.default, _s.flexRow, _s.width100PC].join(' ')} classNames={[_s.default, _s.flexRow, _s.width100PC].join(' ')}
classNamesSmall={!cardImg ? undefined : [_s.default, _s.width100PC].join(' ')} classNamesSmall={!cardImg ? undefined : [_s.default, _s.width100PC].join(' ')}
> >
{embed} {!isReduced && embed}
{description} {description}
</ResponsiveClassesComponent> </ResponsiveClassesComponent>
</a> </a>

View File

@ -230,6 +230,7 @@ class StatusContent extends ImmutablePureComponent {
statusContent: 1, statusContent: 1,
px15: !isComment, px15: !isComment,
outlineNone: 1, outlineNone: 1,
mt5: isComment,
}) })
return ( return (
@ -290,8 +291,10 @@ class StatusContent extends ImmutablePureComponent {
const statusContentClasses = cx({ const statusContentClasses = cx({
statusContent: 1, statusContent: 1,
height215PX: collapsed, height215PX: collapsed & !isComment,
height122PX: collapsed && isComment,
overflowHidden: collapsed, overflowHidden: collapsed,
mt5: isComment,
}) })
return ( return (

View File

@ -25,6 +25,8 @@ const makeGetStatusIds = () => createSelector([
const statusForId = statuses.get(id); const statusForId = statuses.get(id);
let showStatus = true; let showStatus = true;
console.log("columnSettings:", columnSettings)
if (columnSettings.getIn(['shows', 'reblog']) === false) { if (columnSettings.getIn(['shows', 'reblog']) === false) {
showStatus = showStatus && statusForId.get('reblog') === null; showStatus = showStatus && statusForId.get('reblog') === null;
} }
@ -91,7 +93,6 @@ class StatusList extends ImmutablePureComponent {
queuedItemSize: PropTypes.number, queuedItemSize: PropTypes.number,
onDequeueTimeline: PropTypes.func, onDequeueTimeline: PropTypes.func,
group: ImmutablePropTypes.map, group: ImmutablePropTypes.map,
withGroupAdmin: PropTypes.bool,
onScrollToTop: PropTypes.func, onScrollToTop: PropTypes.func,
onScroll: PropTypes.func, onScroll: PropTypes.func,
promotion: PropTypes.object, // : todo : promotion: PropTypes.object, // : todo :
@ -164,7 +165,19 @@ class StatusList extends ImmutablePureComponent {
} }
render () { render () {
const { statusIds, featuredStatusIds, onLoadMore, timelineId, totalQueuedItemsCount, isLoading, isPartial, withGroupAdmin, group, promotion, promotedStatus, ...other } = this.props; const {
statusIds,
featuredStatusIds,
onLoadMore,
timelineId,
totalQueuedItemsCount,
isLoading,
isPartial,
group,
promotion,
promotedStatus,
...other
} = this.props
if (isPartial) { if (isPartial) {
return <ColumnIndicator type='loading' /> return <ColumnIndicator type='loading' />
@ -185,9 +198,6 @@ class StatusList extends ImmutablePureComponent {
onMoveUp={this.handleMoveUp} onMoveUp={this.handleMoveUp}
onMoveDown={this.handleMoveDown} onMoveDown={this.handleMoveDown}
contextType={timelineId} contextType={timelineId}
// : todo :
// group={group}
// withGroupAdmin={withGroupAdmin}
commentsLimited commentsLimited
/> />
)) ))

View File

@ -22,6 +22,7 @@ export default class StatusMedia extends ImmutablePureComponent {
visible: PropTypes.bool, visible: PropTypes.bool,
defaultWidth: PropTypes.number, defaultWidth: PropTypes.number,
cacheWidth: PropTypes.number, cacheWidth: PropTypes.number,
isComposeModalOpen: PropTypes.bool,
} }
// Avoid checking props that are functions (and whose equality will always // Avoid checking props that are functions (and whose equality will always
@ -34,6 +35,7 @@ export default class StatusMedia extends ImmutablePureComponent {
'defaultWidth', 'defaultWidth',
'visible', 'visible',
'width', 'width',
'isComposeModalOpen',
] ]
renderLoadingMedia() { renderLoadingMedia() {
@ -52,6 +54,7 @@ export default class StatusMedia extends ImmutablePureComponent {
visible, visible,
defaultWidth, defaultWidth,
cacheWidth, cacheWidth,
isComposeModalOpen,
} = this.props } = this.props
if (!status) return null if (!status) return null
@ -113,6 +116,7 @@ export default class StatusMedia extends ImmutablePureComponent {
cacheWidth={cacheWidth} cacheWidth={cacheWidth}
defaultWidth={defaultWidth} defaultWidth={defaultWidth}
isComment={isComment} isComment={isComment}
isReduced={isComposeModalOpen}
/> />
) )
} }

View File

@ -42,6 +42,7 @@ class TimelineComposeBlock extends ImmutablePureComponent {
} = this.props } = this.props
if (modal) { if (modal) {
console.log("modal timeline composer: ", this.props)
return ( return (
<section className={_s.default}> <section className={_s.default}>
<div className={[_s.default, _s.flexRow].join(' ')}> <div className={[_s.default, _s.flexRow].join(' ')}>

View File

@ -9,29 +9,17 @@ import {
favorite, favorite,
unrepost, unrepost,
unfavorite, unfavorite,
pin,
unpin,
} from '../actions/interactions'; } from '../actions/interactions';
import { import {
muteStatus,
unmuteStatus,
deleteStatus,
editStatus,
hideStatus, hideStatus,
revealStatus, revealStatus,
fetchComments, fetchComments,
fetchContext, fetchContext,
} from '../actions/statuses'; } from '../actions/statuses';
import { initMuteModal } from '../actions/mutes';
import { initReport } from '../actions/reports';
import { openModal } from '../actions/modal'; import { openModal } from '../actions/modal';
import { openPopover } from '../actions/popover'; import { openPopover } from '../actions/popover';
import { me, deleteModal } from '../initial_state'; import { me } from '../initial_state';
import { import { makeGetStatus } from '../selectors'
createRemovedAccount,
groupRemoveStatus,
} from '../actions/groups';
import { makeGetStatus } from '../selectors';
import Status from '../components/status'; import Status from '../components/status';
const getDescendants = (state, status, highlightStatusId) => { const getDescendants = (state, status, highlightStatusId) => {
@ -123,6 +111,7 @@ const makeMapStateToProps = () => {
ancestorStatus, ancestorStatus,
descendantsIds, descendantsIds,
isComment, isComment,
isComposeModalOpen: state.getIn(['modal', 'modalType']) === 'COMPOSE',
} }
} }
@ -195,36 +184,6 @@ const mapDispatchToProps = (dispatch) => ({
} }
}, },
onPin (status) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
if (status.get('pinned')) {
dispatch(unpin(status));
} else {
dispatch(pin(status));
}
},
onDelete (status, history) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
if (!deleteModal) {
dispatch(deleteStatus(status.get('id'), history));
} else {
dispatch(openModal('CONFIRM', {
message: <FormattedMessage id='confirmations.delete.message' defaultMessage='Are you sure you want to delete this status?' />,
confirm: <FormattedMessage id='confirmations.delete.confirm' defaultMessage='Delete' />,
onConfirm: () => dispatch(deleteStatus(status.get('id'), history)),
}));
}
},
onEdit (status) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
dispatch(editStatus(status));
},
onMention (account, router) { onMention (account, router) {
if (!me) return dispatch(openModal('UNAUTHORIZED')) if (!me) return dispatch(openModal('UNAUTHORIZED'))
@ -239,35 +198,6 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(openModal('VIDEO', { media, time })); dispatch(openModal('VIDEO', { media, time }));
}, },
onBlock (status) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
const account = status.get('account')
dispatch(openModal('BLOCK_ACCOUNT', {
accountId: account.get('id'),
}))
},
onReport (status) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
dispatch(initReport(status.get('account'), status));
},
onMute (account) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
dispatch(initMuteModal(account));
},
onMuteConversation (status) {
if (status.get('muted')) {
dispatch(unmuteStatus(status.get('id')));
} else {
dispatch(muteStatus(status.get('id')));
}
},
onToggleHidden (status) { onToggleHidden (status) {
if (!me) return dispatch(openModal('UNAUTHORIZED')) if (!me) return dispatch(openModal('UNAUTHORIZED'))
@ -278,18 +208,6 @@ const mapDispatchToProps = (dispatch) => ({
} }
}, },
onGroupRemoveAccount(groupId, accountId) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
dispatch(createRemovedAccount(groupId, accountId));
},
onGroupRemoveStatus(groupId, statusId) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
dispatch(groupRemoveStatus(groupId, statusId));
},
onFetchComments(statusId) { onFetchComments(statusId) {
dispatch(fetchComments(statusId)) dispatch(fetchComments(statusId))
}, },

View File

@ -14,27 +14,25 @@ import Avatar from '../../../components/avatar'
import Button from '../../../components/button' import Button from '../../../components/button'
import CharacterCounter from '../../../components/character_counter' import CharacterCounter from '../../../components/character_counter'
import EmojiPickerButton from './emoji_picker_button' import EmojiPickerButton from './emoji_picker_button'
import GifSelectorButton from './gif_selector_button'
import PollButton from './poll_button' import PollButton from './poll_button'
import PollForm from './poll_form' import PollForm from './poll_form'
import RichTextEditorButton from './rich_text_editor_button'
import SchedulePostButton from './schedule_post_button' import SchedulePostButton from './schedule_post_button'
import SpoilerButton from './spoiler_button' import SpoilerButton from './spoiler_button'
import StatusContainer from '../../../containers/status_container' import StatusContainer from '../../../containers/status_container'
import StatusVisibilityButton from './status_visibility_button' import StatusVisibilityButton from './status_visibility_button'
import UploadButton from './media_upload_button' import UploadButton from './media_upload_button'
import UploadForm from './upload_form' import UploadForm from './upload_form'
import GifForm from './gif_form'
import Input from '../../../components/input' import Input from '../../../components/input'
const messages = defineMessages({ const messages = defineMessages({
placeholder: { id: 'compose_form.placeholder', defaultMessage: "What's on your mind?" }, placeholder: { id: 'compose_form.placeholder', defaultMessage: "What's on your mind?" },
commentPlaceholder: { id: 'compose_form.comment_placeholder', defaultMessage: "Write a comment..." }, commentPlaceholder: { id: 'compose_form.comment_placeholder', defaultMessage: "Write a comment..." },
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' }, spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
publish: { id: 'compose_form.publish', defaultMessage: 'Gab' }, publish: { id: 'compose_form.publish', defaultMessage: 'Publish' },
publishEdit: { id: 'compose_form.publish_edit', defaultMessage: 'Publish Edit' },
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' }, schedulePost: { id: 'compose_form.schedule_post', defaultMessage: 'Schedule Post' },
}); })
export default export default
@injectIntl @injectIntl
@ -194,7 +192,7 @@ class ComposeForm extends ImmutablePureComponent {
} }
// this.autosuggestTextarea.textbox.setSelectionRange(selectionStart, selectionEnd); // this.autosuggestTextarea.textbox.setSelectionRange(selectionStart, selectionEnd);
// this.autosuggestTextarea.textbox.focus(); // this.autosuggestTextarea.textbox.focus();
} }
} }
@ -241,7 +239,7 @@ class ComposeForm extends ImmutablePureComponent {
const text = [this.props.spoilerText, countableText(this.props.text)].join(''); const text = [this.props.spoilerText, countableText(this.props.text)].join('');
const disabledButton = disabled || isUploading || isChangingUpload || length(text) > MAX_POST_CHARACTER_COUNT || (length(text) !== 0 && length(text.trim()) === 0 && !anyMedia); const disabledButton = disabled || isUploading || isChangingUpload || length(text) > MAX_POST_CHARACTER_COUNT || (length(text) !== 0 && length(text.trim()) === 0 && !anyMedia);
const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth) const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth)
const parentContainerClasses = CX({ const parentContainerClasses = CX({
default: 1, default: 1,
width100PC: 1, width100PC: 1,
@ -278,160 +276,212 @@ class ComposeForm extends ImmutablePureComponent {
}) })
return ( return (
<div className={parentContainerClasses}> <div className={[_s.default, _s.width100PC].join(' ')}>
<div className={[_s.default, _s.flexRow, _s.width100PC].join(' ')}> {
{ shouldCondense &&
shouldCondense && <div className={parentContainerClasses}>
<div className={[_s.default, _s.mr10, _s.mt5].join(' ')}> <div className={[_s.default, _s.width100PC].join(' ')}>
<Avatar account={account} size={28} noHover />
<div className={[_s.default, _s.flexRow, _s.width100PC].join(' ')}>
<div className={[_s.default, _s.mr10, _s.mt5].join(' ')}>
<Avatar account={account} size={28} noHover />
</div>
<div
className={childContainerClasses}
ref={this.setForm}
onClick={this.handleClick}
>
<AutosuggestTextbox
ref={(isModalOpen && shouldCondense) ? null : this.setAutosuggestTextarea}
placeholder={intl.formatMessage(messages.commentPlaceholder)}
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
/>
<div className={actionsContainerClasses}>
<div className={[_s.default, _s.flexRow, _s.mrAuto].join(' ')}>
<EmojiPickerButton small={shouldCondense} isMatch={isMatch} />
<UploadButton small={shouldCondense} />
<div className={commentPublishBtnClasses}>
<Button
isNarrow
onClick={this.handleSubmit}
isDisabled={disabledButton}
className={_s.px10}
>
{intl.formatMessage(scheduledAt ? messages.schedulePost : messages.publish)}
</Button>
</div>
</div>
</div>
</div>
</div>
{
(isUploading || anyMedia) &&
<div className={[_s.default, _s.width100PC, _s.pl35, _s.mt5].join(' ')}>
<UploadForm
replyToId={replyToId}
isModalOpen={isModalOpen}
/>
</div>
}
</div> </div>
} </div>
}
<div {
className={childContainerClasses} !shouldCondense &&
ref={this.setForm} <div className={parentContainerClasses}>
onClick={this.handleClick} <div className={[_s.default, _s.flexRow, _s.width100PC].join(' ')}>
> <div
className={childContainerClasses}
{ ref={this.setForm}
!!reduxReplyToId && isModalOpen && !shouldCondense && onClick={this.handleClick}
<div className={[_s.default, _s.px15, _s.py10, _s.mt5].join(' ')}> >
<StatusContainer
contextType='compose'
id={reduxReplyToId}
isChild
/>
</div>
}
{
!!spoiler &&
<div className={[_s.default, _s.px15, _s.py10, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
<Input
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
value={this.props.spoilerText}
onChange={this.handleChangeSpoilerText}
disabled={!this.props.spoiler}
prependIcon='warning'
maxLength={256}
id='cw-spoiler-input'
/>
</div>
}
<AutosuggestTextbox
ref={(isModalOpen && shouldCondense) ? null : this.setAutosuggestTextarea}
placeholder={intl.formatMessage((shouldCondense || !!reduxReplyToId) ? messages.commentPlaceholder : 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
/>
{
(isUploading || anyMedia) &&
<div className={[_s.default, _s.px15, _s.mt5].join(' ')}>
<UploadForm replyToId={replyToId} />
</div>
}
{
/* : todo :
!!selectedGifSrc && !anyMedia &&
<div className={[_s.default, _s.px15].join(' ')}>
<GifForm
replyToId={replyToId}
small={shouldCondense}
selectedGifSrc={selectedGifSrc}
/>
</div>
*/
}
{
!edit && hasPoll &&
<div className={[_s.default, _s.px15, _s.mt5].join(' ')}>
<PollForm replyToId={replyToId} />
</div>
}
{
!!quoteOfId && isModalOpen &&
<div className={[_s.default, _s.px15, _s.py10, _s.mt5].join(' ')}>
<StatusContainer
contextType='compose'
id={quoteOfId}
isChild
/>
</div>
}
<div className={actionsContainerClasses}>
<div className={[_s.default, _s.flexRow, _s.mrAuto].join(' ')}>
<EmojiPickerButton small={shouldCondense} isMatch={isMatch} />
<UploadButton small={shouldCondense} />
{ /* <GifSelectorButton small={shouldCondense} /> */ }
{
!edit && !shouldCondense &&
<PollButton />
}
{ !shouldCondense && <StatusVisibilityButton /> }
{ !shouldCondense && <SpoilerButton /> }
{ !shouldCondense && <SchedulePostButton /> }
{ /* !shouldCondense && <RichTextEditorButton /> */ }
{ {
shouldCondense && !!reduxReplyToId && isModalOpen &&
<div className={commentPublishBtnClasses}> <div className={[_s.default, _s.px15, _s.py10, _s.mt5].join(' ')}>
<Button <StatusContainer
isNarrow contextType='compose'
onClick={this.handleSubmit} id={reduxReplyToId}
isDisabled={disabledButton} isChild
className={_s.px10} />
>
{intl.formatMessage(scheduledAt ? messages.schedulePost : messages.publish)}
</Button>
</div> </div>
} }
{
!!spoiler &&
<div className={[_s.default, _s.px15, _s.py10, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
<Input
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
value={this.props.spoilerText}
onChange={this.handleChangeSpoilerText}
disabled={!this.props.spoiler}
prependIcon='warning'
maxLength={256}
id='cw-spoiler-input'
/>
</div>
}
<AutosuggestTextbox
ref={(isModalOpen && shouldCondense) ? null : this.setAutosuggestTextarea}
placeholder={intl.formatMessage((shouldCondense || !!reduxReplyToId) && isMatch ? messages.commentPlaceholder : 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
/>
{
(isUploading || anyMedia) &&
<div className={[_s.default, _s.px15, _s.mt5].join(' ')}>
<UploadForm
replyToId={replyToId}
isModalOpen={isModalOpen}
/>
</div>
}
{
/* : todo :
!!selectedGifSrc && !anyMedia &&
<div className={[_s.default, _s.px15].join(' ')}>
<GifForm
replyToId={replyToId}
small={shouldCondense}
selectedGifSrc={selectedGifSrc}
/>
</div>
*/
}
{
!edit && hasPoll &&
<div className={[_s.default, _s.px15, _s.mt5].join(' ')}>
<PollForm replyToId={replyToId} />
</div>
}
{
!!quoteOfId && isModalOpen &&
<div className={[_s.default, _s.px15, _s.py10, _s.mt5].join(' ')}>
<StatusContainer
contextType='compose'
id={quoteOfId}
isChild
/>
</div>
}
<div className={actionsContainerClasses}>
<div className={[_s.default, _s.flexRow, _s.mrAuto].join(' ')}>
<EmojiPickerButton small={shouldCondense} isMatch={isMatch} />
<UploadButton small={shouldCondense} />
{ /* <GifSelectorButton small={shouldCondense} /> */}
{
!edit &&
<PollButton />
}
<StatusVisibilityButton />
<SpoilerButton />
<SchedulePostButton />
{ /* !shouldCondense && <RichTextEditorButton /> */}
</div>
<CharacterCounter max={MAX_POST_CHARACTER_COUNT} text={text} />
<Button
isOutline
isDisabled={disabledButton}
backgroundColor='none'
color='brand'
className={[_s.fs15PX, _s.px15].join(' ')}
onClick={this.handleSubmit}
>
{intl.formatMessage(scheduledAt ? messages.schedulePost : edit ? messages.publishEdit : messages.publish)}
</Button>
</div>
</div> </div>
{
!shouldCondense &&
<CharacterCounter max={MAX_POST_CHARACTER_COUNT} text={text} />
}
{
!shouldCondense &&
<Button
isOutline
isDisabled={disabledButton}
backgroundColor='none'
color='brand'
className={[_s.fs15PX, _s.px15].join(' ')}
onClick={this.handleSubmit}
>
{intl.formatMessage(scheduledAt ? messages.schedulePost : messages.publish)}
</Button>
}
</div> </div>
</div> </div>
</div> }
</div> </div>
) )
} }
} }

View File

@ -15,8 +15,9 @@ export default
class UploadForm extends ImmutablePureComponent { class UploadForm extends ImmutablePureComponent {
static propTypes = { static propTypes = {
mediaIds: ImmutablePropTypes.list.isRequired, isModalOpen: PropTypes.bool,
isUploading: PropTypes.bool, isUploading: PropTypes.bool,
mediaIds: ImmutablePropTypes.list.isRequired,
uploadProgress: PropTypes.number, uploadProgress: PropTypes.number,
}; };

View File

@ -15,12 +15,24 @@ import { me } from '../../../initial_state'
const mapStateToProps = (state, { replyToId }) => { const mapStateToProps = (state, { replyToId }) => {
const reduxReplyToId = state.getIn(['compose', 'in_reply_to']) const reduxReplyToId = state.getIn(['compose', 'in_reply_to'])
let isMatch = !!reduxReplyToId const isModalOpen = state.getIn(['modal', 'modalType']) === 'COMPOSE'
if (!isMatch) isMatch = replyToId ? reduxReplyToId === replyToId : true let isMatch;
if (!!reduxReplyToId && !!replyToId && replyToId === reduxReplyToId) {
isMatch = true
} else if (!reduxReplyToId && !replyToId) {
isMatch = true
} else {
isMatch = false
}
if (isModalOpen) isMatch = true
if (!isMatch) { if (!isMatch) {
return { return {
isMatch, isMatch,
isModalOpen,
reduxReplyToId,
edit: null, edit: null,
text: '', text: '',
suggestions: ImmutableList(), suggestions: ImmutableList(),
@ -35,20 +47,22 @@ const mapStateToProps = (state, { replyToId }) => {
isUploading: false, isUploading: false,
showSearch: false, showSearch: false,
anyMedia: false, anyMedia: false,
isModalOpen: false,
quoteOfId: null, quoteOfId: null,
scheduledAt: null, scheduledAt: null,
account: state.getIn(['accounts', me]), account: state.getIn(['accounts', me]),
hasPoll: false, hasPoll: false,
selectedGifSrc: null, selectedGifSrc: null,
reduxReplyToId
} }
} }
// console.log("isMatch:", isMatch, reduxReplyToId, replyToId, state.getIn(['compose', 'text'])) // console.log("isMatch:", isMatch, reduxReplyToId, replyToId, state.getIn(['compose', 'text']))
// console.log("reduxReplyToId:", reduxReplyToId, isModalOpen)
return { return {
isMatch, isMatch,
isModalOpen,
reduxReplyToId,
edit: state.getIn(['compose', 'id']) !== null, edit: state.getIn(['compose', 'id']) !== null,
text: state.getIn(['compose', 'text']), text: state.getIn(['compose', 'text']),
suggestions: state.getIn(['compose', 'suggestions']), suggestions: state.getIn(['compose', 'suggestions']),
@ -63,21 +77,17 @@ const mapStateToProps = (state, { replyToId }) => {
isUploading: state.getIn(['compose', 'is_uploading']), isUploading: state.getIn(['compose', 'is_uploading']),
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']), showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0, anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
isModalOpen: state.getIn(['modal', 'modalType']) === 'COMPOSE',
quoteOfId: state.getIn(['compose', 'quote_of_id']), quoteOfId: state.getIn(['compose', 'quote_of_id']),
scheduledAt: state.getIn(['compose', 'scheduled_at']), scheduledAt: state.getIn(['compose', 'scheduled_at']),
account: state.getIn(['accounts', me]), account: state.getIn(['accounts', me]),
hasPoll: state.getIn(['compose', 'poll']), hasPoll: state.getIn(['compose', 'poll']),
selectedGifSrc: state.getIn(['tenor', 'selectedGif', 'src']), selectedGifSrc: state.getIn(['tenor', 'selectedGif', 'src']),
reduxReplyToId,
} }
} }
const mapDispatchToProps = (dispatch, { reduxReplyToId, replyToId }) => ({ const mapDispatchToProps = (dispatch, { reduxReplyToId, replyToId }) => ({
onChange(text, markdown, newReplyToId) { onChange(text, markdown, newReplyToId) {
// : todo :
console.log("text:", text, newReplyToId, replyToId, reduxReplyToId)
dispatch(changeCompose(text, markdown, newReplyToId)) dispatch(changeCompose(text, markdown, newReplyToId))
}, },

View File

@ -91,7 +91,6 @@ class GroupTimeline extends ImmutablePureComponent {
timelineId={`group:${id}`} timelineId={`group:${id}`}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
group={group} group={group}
withGroupAdmin={relationships && relationships.get('admin')}
emptyMessage={intl.formatMessage(messages.empty)} emptyMessage={intl.formatMessage(messages.empty)}
/> />
) )

View File

@ -78,7 +78,7 @@ export default class Layout extends PureComponent {
{ {
!!tabs && !!tabs &&
<Responsive max={BREAKPOINT_EXTRA_SMALL}> <Responsive max={BREAKPOINT_EXTRA_SMALL}>
<div className={[_s.default, _s.mt10, _s.pb15].join(' ')}> <div className={[_s.default, _s.pb15].join(' ')}>
<Pills pills={tabs} /> <Pills pills={tabs} />
</div> </div>
</Responsive> </Responsive>

View File

@ -72,11 +72,10 @@ class HomePage extends PureComponent {
<DefaultLayout <DefaultLayout
title={intl.formatMessage(messages.home)} title={intl.formatMessage(messages.home)}
actions={[ actions={[
// : todo : {
// { icon: 'ellipsis',
// icon: 'ellipsis', onClick: onOpenHomePageSettingsModal,
// onClick: onOpenHomePageSettingsModal, },
// },
]} ]}
layout={( layout={(
<Fragment> <Fragment>

View File

@ -269,14 +269,8 @@ export default function compose(state = initialState, action) {
map.set('caretPosition', null); map.set('caretPosition', null);
map.set('preselectDate', new Date()); map.set('preselectDate', new Date());
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
map.set('spoiler', false);
if (action.status.get('spoiler_text').length > 0) { map.set('spoiler_text', '');
map.set('spoiler', true);
map.set('spoiler_text', action.status.get('spoiler_text'));
} else {
map.set('spoiler', false);
map.set('spoiler_text', '');
}
}); });
case COMPOSE_QUOTE: case COMPOSE_QUOTE:
return state.withMutations(map => { return state.withMutations(map => {
@ -287,14 +281,8 @@ export default function compose(state = initialState, action) {
map.set('caretPosition', null); map.set('caretPosition', null);
map.set('preselectDate', new Date()); map.set('preselectDate', new Date());
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
map.set('spoiler', false);
if (action.status.get('spoiler_text').length > 0) { map.set('spoiler_text', '');
map.set('spoiler', true);
map.set('spoiler_text', action.status.get('spoiler_text'));
} else {
map.set('spoiler', false);
map.set('spoiler_text', '');
}
}); });
case COMPOSE_REPLY_CANCEL: case COMPOSE_REPLY_CANCEL:
case COMPOSE_RESET: case COMPOSE_RESET:

View File

@ -238,6 +238,7 @@ body {
} }
.overflowYHidden { overflow-y: hidden; } .overflowYHidden { overflow-y: hidden; }
.overflowXScroll { overflow-x: scroll; }
.textOverflowEllipsis { .textOverflowEllipsis {
max-width: 100%; max-width: 100%;
@ -439,6 +440,7 @@ body {
.height158PX { height: 158px; } .height158PX { height: 158px; }
.height122PX { height: 122px; } .height122PX { height: 122px; }
.height72PX { height: 72px; } .height72PX { height: 72px; }
.height60PX { height: 60px; }
.height53PX { height: 53px; } .height53PX { height: 53px; }
.height40PX { height: 40px; } .height40PX { height: 40px; }
.height24PX { height: 24px; } .height24PX { height: 24px; }
@ -451,6 +453,7 @@ body {
.maxWidth100PC { max-width: 100%; } .maxWidth100PC { max-width: 100%; }
.maxWidth640PX { max-width: 640px; } .maxWidth640PX { max-width: 640px; }
.maxWidth180PX { max-width: 180px; }
.maxWidth100PC42PX { max-width: calc(100% - 42px); } .maxWidth100PC42PX { max-width: calc(100% - 42px); }
.width100PC { width: 100%; } .width100PC { width: 100%; }
@ -466,6 +469,7 @@ body {
.width160PX { width: 160px; } .width160PX { width: 160px; }
.width84PX { width: 84px; } .width84PX { width: 84px; }
.width72PX { width: 72px; } .width72PX { width: 72px; }
.width60PX { width: 60px; }
.width50PX { width: 50px; } .width50PX { width: 50px; }
.width20PX { width: 20px; } .width20PX { width: 20px; }
.width10PX { width: 10px; } .width10PX { width: 10px; }
@ -659,6 +663,7 @@ body {
.pb10 { padding-bottom: 10px; } .pb10 { padding-bottom: 10px; }
.pb5 { padding-bottom: 5px; } .pb5 { padding-bottom: 5px; }
.pl35 { padding-left: 35px; }
.pl25 { padding-left: 25px; } .pl25 { padding-left: 25px; }
.pl15 { padding-left: 15px; } .pl15 { padding-left: 15px; }
.pl10 { padding-left: 10px; } .pl10 { padding-left: 10px; }
@ -830,6 +835,14 @@ body {
color: rgba(255,255,255,0.65); color: rgba(255,255,255,0.65);
} }
.noScrollbar::-webkit-scrollbar {
display: none;
}
.noScrollbar {
-ms-overflow-style: none;
}
/** /**
* Rich Text Editor * Rich Text Editor
*/ */