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;
+ }
+ }
+ }
}
}