Progress
This commit is contained in:
parent
4dfb7c9fd6
commit
c1131db577
@ -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) => {
|
||||||
|
24
app/javascript/gabsocial/assets/block_icon.js
Normal file
24
app/javascript/gabsocial/assets/block_icon.js
Normal 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
|
26
app/javascript/gabsocial/assets/trash_icon.js
Normal file
26
app/javascript/gabsocial/assets/trash_icon.js
Normal 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
|
@ -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>
|
||||||
|
@ -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'>
|
||||||
|
@ -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}
|
||||||
|
@ -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'
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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'
|
||||||
|
@ -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: (
|
||||||
|
@ -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(' ')}
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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}
|
||||||
|
@ -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'
|
||||||
|
@ -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}
|
||||||
|
@ -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>
|
||||||
|
@ -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 (
|
||||||
|
@ -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
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
@ -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}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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(' ')}>
|
||||||
|
@ -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))
|
||||||
},
|
},
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -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)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user