mirror of
https://github.com/mastodon/mastodon.git
synced 2024-11-27 07:46:29 +00:00
Add dropdown for boost privacy in boost confirmation modal (#15704)
* Various dropdown code quality fixes * Prepare support for privacy selection in boost modal * Add dropdown for boost privacy in boost confirmation modal
This commit is contained in:
parent
8b8c6726ce
commit
07b46cb332
29
app/javascript/mastodon/actions/boosts.js
Normal file
29
app/javascript/mastodon/actions/boosts.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { openModal } from './modal';
|
||||||
|
|
||||||
|
export const BOOSTS_INIT_MODAL = 'BOOSTS_INIT_MODAL';
|
||||||
|
export const BOOSTS_CHANGE_PRIVACY = 'BOOSTS_CHANGE_PRIVACY';
|
||||||
|
|
||||||
|
export function initBoostModal(props) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const default_privacy = getState().getIn(['compose', 'default_privacy']);
|
||||||
|
|
||||||
|
const privacy = props.status.get('visibility') === 'private' ? 'private' : default_privacy;
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: BOOSTS_INIT_MODAL,
|
||||||
|
privacy
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(openModal('BOOST', props));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function changeBoostPrivacy(privacy) {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch({
|
||||||
|
type: BOOSTS_CHANGE_PRIVACY,
|
||||||
|
privacy,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
|
@ -41,11 +41,11 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST';
|
||||||
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
||||||
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
||||||
|
|
||||||
export function reblog(status) {
|
export function reblog(status, visibility) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
dispatch(reblogRequest(status));
|
dispatch(reblogRequest(status));
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then(function (response) {
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) {
|
||||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||||
dispatch(importFetchedStatus(response.data.reblog));
|
dispatch(importFetchedStatus(response.data.reblog));
|
||||||
|
|
|
@ -177,7 +177,6 @@ export default class Dropdown extends React.PureComponent {
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
status: ImmutablePropTypes.map,
|
status: ImmutablePropTypes.map,
|
||||||
isUserTouching: PropTypes.func,
|
isUserTouching: PropTypes.func,
|
||||||
isModalOpen: PropTypes.bool.isRequired,
|
|
||||||
onOpen: PropTypes.func.isRequired,
|
onOpen: PropTypes.func.isRequired,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
dropdownPlacement: PropTypes.string,
|
dropdownPlacement: PropTypes.string,
|
||||||
|
|
|
@ -6,7 +6,6 @@ import DropdownMenu from '../components/dropdown_menu';
|
||||||
import { isUserTouching } from '../is_mobile';
|
import { isUserTouching } from '../is_mobile';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
isModalOpen: state.get('modal').modalType === 'ACTIONS',
|
|
||||||
dropdownPlacement: state.getIn(['dropdown_menu', 'placement']),
|
dropdownPlacement: state.getIn(['dropdown_menu', 'placement']),
|
||||||
openDropdownId: state.getIn(['dropdown_menu', 'openId']),
|
openDropdownId: state.getIn(['dropdown_menu', 'openId']),
|
||||||
openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']),
|
openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']),
|
||||||
|
|
|
@ -35,6 +35,7 @@ import {
|
||||||
} from '../actions/domain_blocks';
|
} from '../actions/domain_blocks';
|
||||||
import { initMuteModal } from '../actions/mutes';
|
import { initMuteModal } from '../actions/mutes';
|
||||||
import { initBlockModal } from '../actions/blocks';
|
import { initBlockModal } from '../actions/blocks';
|
||||||
|
import { initBoostModal } from '../actions/boosts';
|
||||||
import { initReport } from '../actions/reports';
|
import { initReport } from '../actions/reports';
|
||||||
import { openModal } from '../actions/modal';
|
import { openModal } from '../actions/modal';
|
||||||
import { deployPictureInPicture } from '../actions/picture_in_picture';
|
import { deployPictureInPicture } from '../actions/picture_in_picture';
|
||||||
|
@ -82,11 +83,11 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onModalReblog (status) {
|
onModalReblog (status, privacy) {
|
||||||
if (status.get('reblogged')) {
|
if (status.get('reblogged')) {
|
||||||
dispatch(unreblog(status));
|
dispatch(unreblog(status));
|
||||||
} else {
|
} else {
|
||||||
dispatch(reblog(status));
|
dispatch(reblog(status, privacy));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
if ((e && e.shiftKey) || !boostModal) {
|
if ((e && e.shiftKey) || !boostModal) {
|
||||||
this.onModalReblog(status);
|
this.onModalReblog(status);
|
||||||
} else {
|
} else {
|
||||||
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
|
dispatch(initBoostModal({ status, onReblog: this.onModalReblog }));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ class PrivacyDropdownMenu extends React.PureComponent {
|
||||||
// It should not be transformed when mounting because the resulting
|
// It should not be transformed when mounting because the resulting
|
||||||
// size will be used to determine the coordinate of the menu by
|
// size will be used to determine the coordinate of the menu by
|
||||||
// react-overlays
|
// react-overlays
|
||||||
<div className={`privacy-dropdown__dropdown ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null, zIndex: 2 }} role='listbox' ref={this.setRef}>
|
<div className={`privacy-dropdown__dropdown ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} role='listbox' ref={this.setRef}>
|
||||||
{items.map(item => (
|
{items.map(item => (
|
||||||
<div role='option' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
|
<div role='option' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
|
||||||
<div className='privacy-dropdown__option__icon'>
|
<div className='privacy-dropdown__option__icon'>
|
||||||
|
@ -153,11 +153,12 @@ class PrivacyDropdown extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
isUserTouching: PropTypes.func,
|
isUserTouching: PropTypes.func,
|
||||||
isModalOpen: PropTypes.bool.isRequired,
|
|
||||||
onModalOpen: PropTypes.func,
|
onModalOpen: PropTypes.func,
|
||||||
onModalClose: PropTypes.func,
|
onModalClose: PropTypes.func,
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
|
noDirect: PropTpes.bool,
|
||||||
|
container: PropTypes.func,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -167,7 +168,7 @@ class PrivacyDropdown extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handleToggle = ({ target }) => {
|
handleToggle = ({ target }) => {
|
||||||
if (this.props.isUserTouching()) {
|
if (this.props.isUserTouching && this.props.isUserTouching()) {
|
||||||
if (this.state.open) {
|
if (this.state.open) {
|
||||||
this.props.onModalClose();
|
this.props.onModalClose();
|
||||||
} else {
|
} else {
|
||||||
|
@ -236,12 +237,17 @@ class PrivacyDropdown extends React.PureComponent {
|
||||||
{ icon: 'globe', value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
|
{ icon: 'globe', value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
|
||||||
{ icon: 'unlock', value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
|
{ icon: 'unlock', value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
|
||||||
{ icon: 'lock', value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
|
{ icon: 'lock', value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
|
||||||
{ icon: 'envelope', value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (!this.props.noDirect) {
|
||||||
|
this.options.push(
|
||||||
|
{ icon: 'envelope', value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { value, intl } = this.props;
|
const { value, container, intl } = this.props;
|
||||||
const { open, placement } = this.state;
|
const { open, placement } = this.state;
|
||||||
|
|
||||||
const valueOption = this.options.find(item => item.value === value);
|
const valueOption = this.options.find(item => item.value === value);
|
||||||
|
@ -264,7 +270,7 @@ class PrivacyDropdown extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Overlay show={open} placement={placement} target={this}>
|
<Overlay show={open} placement={placement} target={this} container={container}>
|
||||||
<PrivacyDropdownMenu
|
<PrivacyDropdownMenu
|
||||||
items={this.options}
|
items={this.options}
|
||||||
value={value}
|
value={value}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { openModal, closeModal } from '../../../actions/modal';
|
||||||
import { isUserTouching } from '../../../is_mobile';
|
import { isUserTouching } from '../../../is_mobile';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
isModalOpen: state.get('modal').modalType === 'ACTIONS',
|
|
||||||
value: state.getIn(['compose', 'privacy']),
|
value: state.getIn(['compose', 'privacy']),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeGetNotification, makeGetStatus } from '../../../selectors';
|
import { makeGetNotification, makeGetStatus } from '../../../selectors';
|
||||||
import Notification from '../components/notification';
|
import Notification from '../components/notification';
|
||||||
|
import { initBoostModal } from '../../../actions/boosts';
|
||||||
import { openModal } from '../../../actions/modal';
|
import { openModal } from '../../../actions/modal';
|
||||||
import { mentionCompose } from '../../../actions/compose';
|
import { mentionCompose } from '../../../actions/compose';
|
||||||
import {
|
import {
|
||||||
|
@ -35,8 +36,8 @@ const mapDispatchToProps = dispatch => ({
|
||||||
dispatch(mentionCompose(account, router));
|
dispatch(mentionCompose(account, router));
|
||||||
},
|
},
|
||||||
|
|
||||||
onModalReblog (status) {
|
onModalReblog (status, privacy) {
|
||||||
dispatch(reblog(status));
|
dispatch(reblog(status, privacy));
|
||||||
},
|
},
|
||||||
|
|
||||||
onReblog (status, e) {
|
onReblog (status, e) {
|
||||||
|
@ -46,7 +47,7 @@ const mapDispatchToProps = dispatch => ({
|
||||||
if (e.shiftKey || !boostModal) {
|
if (e.shiftKey || !boostModal) {
|
||||||
this.onModalReblog(status);
|
this.onModalReblog(status);
|
||||||
} else {
|
} else {
|
||||||
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
|
dispatch(initBoostModal({ status, onReblog: this.onModalReblog }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import { replyCompose } from 'mastodon/actions/compose';
|
import { replyCompose } from 'mastodon/actions/compose';
|
||||||
import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions';
|
import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions';
|
||||||
import { makeGetStatus } from 'mastodon/selectors';
|
import { makeGetStatus } from 'mastodon/selectors';
|
||||||
|
import { initBoostModal } from 'mastodon/actions/boosts';
|
||||||
import { openModal } from 'mastodon/actions/modal';
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -89,9 +90,9 @@ class Footer extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_performReblog = () => {
|
_performReblog = (status, privacy) => {
|
||||||
const { dispatch, status } = this.props;
|
const { dispatch } = this.props;
|
||||||
dispatch(reblog(status));
|
dispatch(reblog(status, privacy));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReblogClick = e => {
|
handleReblogClick = e => {
|
||||||
|
@ -100,9 +101,9 @@ class Footer extends ImmutablePureComponent {
|
||||||
if (status.get('reblogged')) {
|
if (status.get('reblogged')) {
|
||||||
dispatch(unreblog(status));
|
dispatch(unreblog(status));
|
||||||
} else if ((e && e.shiftKey) || !boostModal) {
|
} else if ((e && e.shiftKey) || !boostModal) {
|
||||||
this._performReblog();
|
this._performReblog(status);
|
||||||
} else {
|
} else {
|
||||||
dispatch(openModal('BOOST', { status, onReblog: this._performReblog }));
|
dispatch(initBoostModal({ status, onReblog: this._performReblog }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
} from '../../../actions/statuses';
|
} from '../../../actions/statuses';
|
||||||
import { initMuteModal } from '../../../actions/mutes';
|
import { initMuteModal } from '../../../actions/mutes';
|
||||||
import { initBlockModal } from '../../../actions/blocks';
|
import { initBlockModal } from '../../../actions/blocks';
|
||||||
|
import { initBoostModal } from '../../../actions/boosts';
|
||||||
import { initReport } from '../../../actions/reports';
|
import { initReport } from '../../../actions/reports';
|
||||||
import { openModal } from '../../../actions/modal';
|
import { openModal } from '../../../actions/modal';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
@ -68,8 +69,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onModalReblog (status) {
|
onModalReblog (status, privacy) {
|
||||||
dispatch(reblog(status));
|
dispatch(reblog(status, privacy));
|
||||||
},
|
},
|
||||||
|
|
||||||
onReblog (status, e) {
|
onReblog (status, e) {
|
||||||
|
@ -79,7 +80,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
if (e.shiftKey || !boostModal) {
|
if (e.shiftKey || !boostModal) {
|
||||||
this.onModalReblog(status);
|
this.onModalReblog(status);
|
||||||
} else {
|
} else {
|
||||||
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
|
dispatch(initBoostModal({ status, onReblog: this.onModalReblog }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -42,6 +42,7 @@ import {
|
||||||
} from '../../actions/domain_blocks';
|
} from '../../actions/domain_blocks';
|
||||||
import { initMuteModal } from '../../actions/mutes';
|
import { initMuteModal } from '../../actions/mutes';
|
||||||
import { initBlockModal } from '../../actions/blocks';
|
import { initBlockModal } from '../../actions/blocks';
|
||||||
|
import { initBoostModal } from '../../actions/boosts';
|
||||||
import { initReport } from '../../actions/reports';
|
import { initReport } from '../../actions/reports';
|
||||||
import { makeGetStatus, makeGetPictureInPicture } from '../../selectors';
|
import { makeGetStatus, makeGetPictureInPicture } from '../../selectors';
|
||||||
import { ScrollContainer } from 'react-router-scroll-4';
|
import { ScrollContainer } from 'react-router-scroll-4';
|
||||||
|
@ -234,8 +235,8 @@ class Status extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModalReblog = (status) => {
|
handleModalReblog = (status, privacy) => {
|
||||||
this.props.dispatch(reblog(status));
|
this.props.dispatch(reblog(status, privacy));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReblogClick = (status, e) => {
|
handleReblogClick = (status, e) => {
|
||||||
|
@ -245,7 +246,7 @@ class Status extends ImmutablePureComponent {
|
||||||
if ((e && e.shiftKey) || !boostModal) {
|
if ((e && e.shiftKey) || !boostModal) {
|
||||||
this.handleModalReblog(status);
|
this.handleModalReblog(status);
|
||||||
} else {
|
} else {
|
||||||
this.props.dispatch(openModal('BOOST', { status, onReblog: this.handleModalReblog }));
|
this.props.dispatch(initBoostModal({ status, onReblog: this.handleModalReblog }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
|
@ -10,7 +11,9 @@ import DisplayName from '../../../components/display_name';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import Icon from 'mastodon/components/icon';
|
import Icon from 'mastodon/components/icon';
|
||||||
import AttachmentList from 'mastodon/components/attachment_list';
|
import AttachmentList from 'mastodon/components/attachment_list';
|
||||||
|
import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdown';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { changeBoostPrivacy } from 'mastodon/actions/boosts';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
||||||
|
@ -21,7 +24,22 @@ const messages = defineMessages({
|
||||||
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' },
|
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' },
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @injectIntl
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
privacy: state.getIn(['boosts', 'new', 'privacy']),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onChangeBoostPrivacy(value) {
|
||||||
|
dispatch(changeBoostPrivacy(value));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default @connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
@injectIntl
|
||||||
class BoostModal extends ImmutablePureComponent {
|
class BoostModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
|
@ -32,6 +50,8 @@ class BoostModal extends ImmutablePureComponent {
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
onReblog: PropTypes.func.isRequired,
|
onReblog: PropTypes.func.isRequired,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
|
onChangeBoostPrivacy: PropTypes.func.isRequired,
|
||||||
|
privacy: PropTypes.string.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,7 +60,7 @@ class BoostModal extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReblog = () => {
|
handleReblog = () => {
|
||||||
this.props.onReblog(this.props.status);
|
this.props.onReblog(this.props.status, this.props.privacy);
|
||||||
this.props.onClose();
|
this.props.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +72,16 @@ class BoostModal extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_findContainer = () => {
|
||||||
|
return document.getElementsByClassName('modal-root__container')[0];
|
||||||
|
};
|
||||||
|
|
||||||
setRef = (c) => {
|
setRef = (c) => {
|
||||||
this.button = c;
|
this.button = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, intl } = this.props;
|
const { status, privacy, intl } = this.props;
|
||||||
const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
|
const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
|
||||||
|
|
||||||
const visibilityIconInfo = {
|
const visibilityIconInfo = {
|
||||||
|
@ -102,6 +126,14 @@ class BoostModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
<div className='boost-modal__action-bar'>
|
<div className='boost-modal__action-bar'>
|
||||||
<div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} /></div>
|
<div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} /></div>
|
||||||
|
{status.get('visibility') !== 'private' && !status.get('reblogged') && (
|
||||||
|
<PrivacyDropdown
|
||||||
|
noDirect
|
||||||
|
value={privacy}
|
||||||
|
container={this._findContainer}
|
||||||
|
onChange={this.props.onChangeBoostPrivacy}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} />
|
<Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
25
app/javascript/mastodon/reducers/boosts.js
Normal file
25
app/javascript/mastodon/reducers/boosts.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import Immutable from 'immutable';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BOOSTS_INIT_MODAL,
|
||||||
|
BOOSTS_CHANGE_PRIVACY,
|
||||||
|
} from 'mastodon/actions/boosts';
|
||||||
|
|
||||||
|
const initialState = Immutable.Map({
|
||||||
|
new: Immutable.Map({
|
||||||
|
privacy: 'public',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function mutes(state = initialState, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case BOOSTS_INIT_MODAL:
|
||||||
|
return state.withMutations((state) => {
|
||||||
|
state.setIn(['new', 'privacy'], action.privacy);
|
||||||
|
});
|
||||||
|
case BOOSTS_CHANGE_PRIVACY:
|
||||||
|
return state.setIn(['new', 'privacy'], action.privacy);
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import push_notifications from './push_notifications';
|
||||||
import status_lists from './status_lists';
|
import status_lists from './status_lists';
|
||||||
import mutes from './mutes';
|
import mutes from './mutes';
|
||||||
import blocks from './blocks';
|
import blocks from './blocks';
|
||||||
|
import boosts from './boosts';
|
||||||
import reports from './reports';
|
import reports from './reports';
|
||||||
import contexts from './contexts';
|
import contexts from './contexts';
|
||||||
import compose from './compose';
|
import compose from './compose';
|
||||||
|
@ -57,6 +58,7 @@ const reducers = {
|
||||||
push_notifications,
|
push_notifications,
|
||||||
mutes,
|
mutes,
|
||||||
blocks,
|
blocks,
|
||||||
|
boosts,
|
||||||
reports,
|
reports,
|
||||||
contexts,
|
contexts,
|
||||||
compose,
|
compose,
|
||||||
|
|
|
@ -4209,6 +4209,7 @@ a.status-card.compact:hover {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-left: 40px;
|
margin-left: 40px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
&.top {
|
&.top {
|
||||||
transform-origin: 50% 100%;
|
transform-origin: 50% 100%;
|
||||||
|
@ -4219,6 +4220,15 @@ a.status-card.compact:hover {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-root__container .privacy-dropdown {
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-root__container .privacy-dropdown__dropdown {
|
||||||
|
pointer-events: auto;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
.privacy-dropdown__option {
|
.privacy-dropdown__option {
|
||||||
color: $inverted-text-color;
|
color: $inverted-text-color;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
Loading…
Reference in a new issue