diff --git a/app/soapbox/components/dropdown_menu.js b/app/soapbox/components/dropdown_menu.js index fa0d1ffd5..453f24d71 100644 --- a/app/soapbox/components/dropdown_menu.js +++ b/app/soapbox/components/dropdown_menu.js @@ -207,6 +207,8 @@ export default class Dropdown extends React.PureComponent { src: PropTypes.string, items: PropTypes.array.isRequired, size: PropTypes.number, + active: PropTypes.bool, + pressed: PropTypes.bool, title: PropTypes.string, disabled: PropTypes.bool, status: ImmutablePropTypes.map, @@ -217,6 +219,7 @@ export default class Dropdown extends React.PureComponent { dropdownPlacement: PropTypes.string, openDropdownId: PropTypes.number, openedViaKeyboard: PropTypes.bool, + text: PropTypes.string, }; static defaultProps = { @@ -302,7 +305,7 @@ export default class Dropdown extends React.PureComponent { } render() { - const { icon, src, items, size, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard } = this.props; + const { icon, src, items, size, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard, active, pressed, text } = this.props; const open = this.state.id === openDropdownId; return ( @@ -311,9 +314,11 @@ export default class Dropdown extends React.PureComponent { icon={icon} src={src} title={title} - active={open} + active={open || active} + pressed={pressed} disabled={disabled} size={size} + text={text} ref={this.setTargetRef} onClick={this.handleClick} onMouseDown={this.handleMouseDown} diff --git a/app/soapbox/components/status.js b/app/soapbox/components/status.js index 06285a8f4..6bfb2be18 100644 --- a/app/soapbox/components/status.js +++ b/app/soapbox/components/status.js @@ -458,7 +458,7 @@ class Status extends ImmutablePureComponent { ); } - } else if (status.get('spoiler_text').length === 0 && status.get('card')) { + } else if (status.get('spoiler_text').length === 0 && !status.getIn(['pleroma', 'quote']) && status.get('card')) { media = ( + ); + } else { + reblogButton = ( + + ); + } + const menu = this._makeMenu(publicStatus); let reblogIcon = require('feather-icons/dist/icons/repeat.svg'); let replyTitle; @@ -563,13 +605,10 @@ class StatusActionBar extends ImmutablePureComponent { {replyCount !== 0 && {replyCount}} -
- +
+ {reblogButton} {reblogCount !== 0 && {reblogCount}}
-
- -
{ @@ -87,6 +88,7 @@ class ActionBar extends React.PureComponent { status: ImmutablePropTypes.map.isRequired, onReply: PropTypes.func.isRequired, onReblog: PropTypes.func.isRequired, + onQuote: PropTypes.func.isRequired, onFavourite: PropTypes.func.isRequired, onEmojiReact: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired, @@ -143,6 +145,15 @@ class ActionBar extends React.PureComponent { } } + handleQuoteClick = () => { + const { me, onQuote, onOpenUnauthorizedModal, status } = this.props; + if (me) { + onQuote(status, this.context.router.history); + } else { + onOpenUnauthorizedModal('REBLOG'); + } + } + handleBookmarkClick = () => { this.props.onBookmark(this.props.status); } @@ -319,6 +330,47 @@ class ActionBar extends React.PureComponent { '😩': messages.reactionWeary, }[meEmojiReact] || messages.favourite); + let reblogButton; + + if (me && features.quotePosts) { + const reblogMenu = [ + { + text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog), + action: this.handleReblogClick, + icon: require('@tabler/icons/icons/repeat.svg'), + }, + { + text: intl.formatMessage(messages.quotePost), + action: this.handleQuoteClick, + icon: require('@tabler/icons/icons/quote.svg'), + }, + ]; + + reblogButton = ( + + ); + } else { + reblogButton = ( + + ); + } + const menu = []; if (publicStatus) { @@ -497,14 +549,7 @@ class ActionBar extends React.PureComponent { />
- + {reblogButton}
); } - } else if (status.get('spoiler_text').length === 0) { + } else if (status.get('spoiler_text').length === 0 && !status.getIn(['pleroma', 'quote'])) { media = ; } diff --git a/app/soapbox/features/status/components/quoted_status.js b/app/soapbox/features/status/components/quoted_status.js index f7878adcf..0825052c5 100644 --- a/app/soapbox/features/status/components/quoted_status.js +++ b/app/soapbox/features/status/components/quoted_status.js @@ -29,6 +29,8 @@ class QuotedStatus extends ImmutablePureComponent { } this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/posts/${this.props.status.get('id')}`); + + e.preventDefault(); } } diff --git a/app/soapbox/utils/features.js b/app/soapbox/utils/features.js index 36aba0d6b..fc3dc68ab 100644 --- a/app/soapbox/utils/features.js +++ b/app/soapbox/utils/features.js @@ -78,6 +78,7 @@ export const getFeatures = createSelector([ remoteInteractionsAPI: v.software === PLEROMA && gte(v.version, '2.4.50'), explicitAddressing: v.software === PLEROMA && gte(v.version, '1.0.0'), accountEndorsements: v.software === PLEROMA && gte(v.version, '2.4.50'), + quotePosts: v.software === PLEROMA && gte(v.version, '2.4.50'), }; }); diff --git a/app/styles/components/status.scss b/app/styles/components/status.scss index b3c982554..274252d24 100644 --- a/app/styles/components/status.scss +++ b/app/styles/components/status.scss @@ -338,6 +338,16 @@ font-weight: 500; color: var(--brand-color); } + + &--reblog { + > div { + display: flex; + + > .icon-button { + margin-right: 8px; + } + } + } } }