Progress
This commit is contained in:
@@ -8,6 +8,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import {
|
||||
favorite,
|
||||
unfavorite,
|
||||
repost,
|
||||
unrepost,
|
||||
} from '../actions/interactions'
|
||||
import { replyCompose } from '../actions/compose'
|
||||
import { openModal } from '../actions/modal'
|
||||
@@ -15,8 +17,9 @@ import { openPopover } from '../actions/popover'
|
||||
import { makeGetStatus } from '../selectors'
|
||||
import {
|
||||
CX,
|
||||
MODAL_BOOST,
|
||||
} from '../constants'
|
||||
import { me } from '../initial_state'
|
||||
import { me, boostModal } from '../initial_state'
|
||||
import Avatar from './avatar'
|
||||
import Button from './button'
|
||||
import CommentHeader from './comment_header'
|
||||
@@ -49,6 +52,10 @@ class Comment extends ImmutablePureComponent {
|
||||
this.props.onFavorite(this.props.status)
|
||||
}
|
||||
|
||||
handleOnRepost = () => {
|
||||
this.props.onRepost(this.props.status)
|
||||
}
|
||||
|
||||
handleOnOpenStatusOptions = () => {
|
||||
this.props.onOpenStatusOptions(this.moreNode, this.props.status)
|
||||
}
|
||||
@@ -57,6 +64,26 @@ class Comment extends ImmutablePureComponent {
|
||||
this.setState({ showMedia: !this.state.showMedia })
|
||||
}
|
||||
|
||||
handleOnThreadMouseEnter = (event) => {
|
||||
if (event.target) {
|
||||
const threadKey = event.target.getAttribute('data-threader-indent')
|
||||
const elems = document.querySelectorAll(`[data-threader-indent="${threadKey}"]`)
|
||||
elems.forEach((elem) => elem.classList.add('thread-hovering'))
|
||||
}
|
||||
}
|
||||
|
||||
handleOnThreadMouseLeave = (event) => {
|
||||
if (event.target) {
|
||||
const threadKey = event.target.getAttribute('data-threader-indent')
|
||||
const elems = document.querySelectorAll(`[data-threader-indent="${threadKey}"]`)
|
||||
elems.forEach((elem) => elem.classList.remove('thread-hovering'))
|
||||
}
|
||||
}
|
||||
|
||||
handleOnThreadClick = (event) => {
|
||||
// : todo :
|
||||
}
|
||||
|
||||
setMoreNode = (c) => {
|
||||
this.moreNode = c
|
||||
}
|
||||
@@ -81,7 +108,7 @@ class Comment extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
const style = {
|
||||
paddingLeft: `${indent * 42}px`,
|
||||
paddingLeft: `${indent * 38}px`,
|
||||
}
|
||||
|
||||
const contentClasses = CX({
|
||||
@@ -95,8 +122,28 @@ class Comment extends ImmutablePureComponent {
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.px15, _s.mb10, _s.py5].join(' ')} data-comment={status.get('id')}>
|
||||
<div className={_s.d} style={style}>
|
||||
<div className={[_s.d, _s.px15, _s.py5].join(' ')} data-comment={status.get('id')}>
|
||||
{
|
||||
indent > 0 &&
|
||||
<div className={[_s.d, _s.z3, _s.flexRow, _s.posAbs, _s.topNeg20PX, _s.left0, _s.bottom20PX, _s.aiCenter, _s.jcCenter].join(' ')}>
|
||||
{Array.apply(null, {
|
||||
length: indent
|
||||
}).map((_, i) => (
|
||||
<button
|
||||
key={`thread-${status.get('id')}-${i}`}
|
||||
data-threader
|
||||
data-threader-indent={i}
|
||||
onMouseEnter={this.handleOnThreadMouseEnter}
|
||||
onMouseLeave={this.handleOnThreadMouseLeave}
|
||||
onClick={this.handleOnThreadClick}
|
||||
className={[_s.d, _s.w14PX, _s.h100PC, _s.outlineNone, _s.bgTransparent, _s.ml20, _s.cursorPointer].join(' ')}
|
||||
>
|
||||
<span className={[_s.d, _s.w2PX, _s.h100PC, _s.mlAuto, _s.mr2, _s.bgSubtle].join(' ')} />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
<div className={[_s.d, _s.mb10].join(' ')} style={style}>
|
||||
|
||||
<div className={[_s.d, _s.flexRow].join(' ')}>
|
||||
<NavLink
|
||||
@@ -104,7 +151,7 @@ class Comment extends ImmutablePureComponent {
|
||||
title={status.getIn(['account', 'acct'])}
|
||||
className={[_s.d, _s.mr10, _s.pt5].join(' ')}
|
||||
>
|
||||
<Avatar account={status.get('account')} size={32} />
|
||||
<Avatar account={status.get('account')} size={30} />
|
||||
</NavLink>
|
||||
|
||||
<div className={[_s.d, _s.flexShrink1, _s.maxW100PC42PX].join(' ')}>
|
||||
@@ -145,6 +192,10 @@ class Comment extends ImmutablePureComponent {
|
||||
title={intl.formatMessage(messages.reply)}
|
||||
onClick={this.handleOnReply}
|
||||
/>
|
||||
<CommentButton
|
||||
title={intl.formatMessage(status.get('reblogged') ? messages.unrepost : messages.repost)}
|
||||
onClick={this.handleOnRepost}
|
||||
/>
|
||||
<div ref={this.setMoreNode}>
|
||||
<CommentButton
|
||||
title='···'
|
||||
@@ -193,6 +244,8 @@ CommentButton.propTypes = {
|
||||
|
||||
const messages = defineMessages({
|
||||
reply: { id: 'status.reply', defaultMessage: 'Reply' },
|
||||
repost: { id: 'status.repost', defaultMessage: 'Repost' },
|
||||
unrepost: { id: 'status.unrepost', defaultMessage: 'Unrepost' },
|
||||
like: { id: 'status.like', defaultMessage: 'Like' },
|
||||
unlike: { id: 'status.unlike', defaultMessage: 'Unlike' },
|
||||
})
|
||||
@@ -227,6 +280,24 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
dispatch(favorite(status))
|
||||
}
|
||||
},
|
||||
onRepost(status) {
|
||||
if (!me) return dispatch(openModal('UNAUTHORIZED'))
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
},
|
||||
onOpenStatusOptions(targetRef, status) {
|
||||
dispatch(openPopover('STATUS_OPTIONS', {
|
||||
targetRef,
|
||||
@@ -260,6 +331,7 @@ Comment.propTypes = {
|
||||
isHighlighted: PropTypes.bool,
|
||||
onReply: PropTypes.func.isRequired,
|
||||
onFavorite: PropTypes.func.isRequired,
|
||||
onRepost: PropTypes.func.isRequired,
|
||||
onOpenStatusOptions: PropTypes.func.isRequired,
|
||||
onOpenLikes: PropTypes.func.isRequired,
|
||||
onOpenReposts: PropTypes.func.isRequired,
|
||||
|
||||
@@ -5,8 +5,11 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { openModal } from '../../actions/modal'
|
||||
import { cancelReplyCompose } from '../../actions/compose'
|
||||
import ModalLayout from './modal_layout'
|
||||
import TimelineComposeBlock from '../timeline_compose_block'
|
||||
import Block from '../block'
|
||||
import Heading from '../heading'
|
||||
import Text from '../text'
|
||||
import Button from '../button'
|
||||
|
||||
class ComposeModal extends ImmutablePureComponent {
|
||||
|
||||
@@ -32,6 +35,10 @@ class ComposeModal extends ImmutablePureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
onHandleSubmit = () => {
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
intl,
|
||||
@@ -42,13 +49,35 @@ class ComposeModal extends ImmutablePureComponent {
|
||||
const title = isEditing ? messages.edit : isComment ? messages.comment : messages.title
|
||||
|
||||
return (
|
||||
<ModalLayout
|
||||
noPadding
|
||||
title={intl.formatMessage(title)}
|
||||
onClose={this.onClickClose}
|
||||
>
|
||||
<TimelineComposeBlock modal />
|
||||
</ModalLayout>
|
||||
<div style={{width: '512px'}} className={[_s.d, _s.modal].join(' ')}>
|
||||
<Block>
|
||||
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.jcCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.h53PX, _s.px15].join(' ')}>
|
||||
<Button
|
||||
backgroundColor='none'
|
||||
title={intl.formatMessage(messages.close)}
|
||||
onClick={this.onClickClose}
|
||||
color='secondary'
|
||||
icon='close'
|
||||
iconSize='10px'
|
||||
/>
|
||||
<Heading size='h2'>
|
||||
{intl.formatMessage(title)}
|
||||
</Heading>
|
||||
<Button
|
||||
backgroundColor='none'
|
||||
title={intl.formatMessage(messages.close)}
|
||||
className={_s.mlAuto}
|
||||
onClick={this.onHandleSubmit}
|
||||
color='secondary'
|
||||
>
|
||||
<Text>Post</Text>
|
||||
</Button>
|
||||
</div>
|
||||
<div className={[_s.d].join(' ')}>
|
||||
<TimelineComposeBlock isModal />
|
||||
</div>
|
||||
</Block>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -58,6 +87,7 @@ const messages = defineMessages({
|
||||
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' },
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
})
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
|
||||
@@ -99,7 +99,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
GroupsPanel.propTypes = {
|
||||
groupIds: ImmutablePropTypes.list,
|
||||
isLazy: PropTypes.bool,
|
||||
onFetchGroups: PropTypes.func.isRequired,
|
||||
onFetchGroupsByTab: PropTypes.func.isRequired,
|
||||
shouldLoad: PropTypes.bool,
|
||||
groupType: PropTypes.string,
|
||||
}
|
||||
|
||||
@@ -160,12 +160,6 @@ class StatusOptionsPopover extends ImmutablePureComponent {
|
||||
|
||||
if (me) {
|
||||
if (isReply) {
|
||||
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,
|
||||
|
||||
@@ -35,7 +35,7 @@ class SidebarPanelGroup extends React.PureComponent {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{
|
||||
layout.map((panel) => {
|
||||
layout.map((panel, i) => {
|
||||
if (!panel) return null
|
||||
|
||||
if (typeof panel !== 'function' || panel.key === 'status-promotion-panel') {
|
||||
@@ -44,6 +44,7 @@ class SidebarPanelGroup extends React.PureComponent {
|
||||
|
||||
return (
|
||||
<Bundle
|
||||
key={`sidebar-panel-group-item-${i}`}
|
||||
fetchComponent={panel}
|
||||
loading={this.renderLoading}
|
||||
error={this.renderError}
|
||||
|
||||
@@ -403,7 +403,6 @@ StatusList.propTypes = {
|
||||
timelineId: PropTypes.string,
|
||||
queuedItemSize: PropTypes.number,
|
||||
onDequeueTimeline: PropTypes.func.isRequired,
|
||||
onClearTimeline: PropTypes.func.isRequired,
|
||||
onScrollToTop: PropTypes.func.isRequired,
|
||||
onScroll: PropTypes.func.isRequired,
|
||||
onFetchContext: PropTypes.func.isRequired,
|
||||
|
||||
@@ -19,15 +19,15 @@ class TimelineComposeBlock extends ImmutablePureComponent {
|
||||
account,
|
||||
size,
|
||||
intl,
|
||||
modal,
|
||||
isModal,
|
||||
...rest
|
||||
} = this.props
|
||||
|
||||
if (modal) {
|
||||
if (isModal) {
|
||||
return (
|
||||
<section className={_s.d}>
|
||||
<div className={[_s.d, _s.flexRow].join(' ')}>
|
||||
<ComposeFormContainer {...rest} modal={modal} />
|
||||
<ComposeFormContainer {...rest} isModal={isModal} />
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
@@ -69,7 +69,7 @@ TimelineComposeBlock.propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
size: PropTypes.number,
|
||||
modal: PropTypes.bool,
|
||||
isModal: PropTypes.bool,
|
||||
}
|
||||
|
||||
TimelineComposeBlock.defaultProps = {
|
||||
|
||||
@@ -71,7 +71,7 @@ UserStat.propTypes = {
|
||||
PropTypes.number,
|
||||
PropTypes.object,
|
||||
]).isRequired,
|
||||
isCentered: PropTypes.bool.isRequired,
|
||||
isCentered: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default UserStat
|
||||
Reference in New Issue
Block a user