Add circle visibility
This commit is contained in:
parent
44eb57183e
commit
3af223275f
20 changed files with 154 additions and 12 deletions
|
@ -0,0 +1,59 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
|
||||
import Select, { NonceProvider } from 'react-select';
|
||||
|
||||
class CircleSelect extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
unavailable: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
circles: ImmutablePropTypes.list,
|
||||
circleId: PropTypes.string,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleClick = value => {
|
||||
this.props.onChange(value.value);
|
||||
};
|
||||
|
||||
noOptionsMessage = () => '';
|
||||
|
||||
render () {
|
||||
const { unavailable, circles, circleId } = this.props;
|
||||
|
||||
if (unavailable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const listOptions = circles.toArray().filter((circle) => circle[1]).map((circle) => {
|
||||
return { value: circle[1].get('id'), label: circle[1].get('title') };
|
||||
});
|
||||
const listValue = listOptions.find((opt) => opt.value === circleId);
|
||||
|
||||
return (
|
||||
<div className='compose-form__circle-select'>
|
||||
<NonceProvider nonce={document.querySelector('meta[name=style-nonce]').content} cacheKey='circles'>
|
||||
<Select
|
||||
value={listValue}
|
||||
options={listOptions}
|
||||
noOptionsMessage={this.noOptionsMessage}
|
||||
onChange={this.handleClick}
|
||||
className='column-content-select__container'
|
||||
classNamePrefix='column-content-select'
|
||||
name='circles'
|
||||
defaultOptions
|
||||
/>
|
||||
</NonceProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(CircleSelect);
|
|
@ -14,6 +14,7 @@ import { Icon } from 'mastodon/components/icon';
|
|||
import AutosuggestInput from '../../../components/autosuggest_input';
|
||||
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
|
||||
import Button from '../../../components/button';
|
||||
import CircleSelectContainer from '../containers/circle_select_container';
|
||||
import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
|
||||
import ExpirationDropdownContainer from '../containers/expiration_dropdown_container';
|
||||
import LanguageDropdown from '../containers/language_dropdown_container';
|
||||
|
@ -76,6 +77,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
isInReply: PropTypes.bool,
|
||||
singleColumn: PropTypes.bool,
|
||||
lang: PropTypes.string,
|
||||
circleId: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -101,11 +103,11 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
};
|
||||
|
||||
canSubmit = () => {
|
||||
const { isSubmitting, isChangingUpload, isUploading, anyMedia } = this.props;
|
||||
const { isSubmitting, isChangingUpload, isUploading, anyMedia, privacy, circleId } = this.props;
|
||||
const fulltext = this.getFulltextForCharacterCounting();
|
||||
const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0;
|
||||
|
||||
return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia));
|
||||
return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia) || (privacy === 'circle' && !circleId));
|
||||
};
|
||||
|
||||
handleSubmit = (e) => {
|
||||
|
@ -317,6 +319,8 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<CircleSelectContainer />
|
||||
|
||||
<div className='compose-form__publish'>
|
||||
<div className='compose-form__publish-button-wrapper'>
|
||||
<Button
|
||||
|
|
|
@ -26,6 +26,8 @@ const messages = defineMessages({
|
|||
private_long: { id: 'privacy.private.long', defaultMessage: 'Visible for followers only' },
|
||||
mutual_short: { id: 'privacy.mutual.short', defaultMessage: 'Mutual' },
|
||||
mutual_long: { id: 'privacy.mutual.long', defaultMessage: 'Mutual follows only' },
|
||||
circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle' },
|
||||
circle_long: { id: 'privacy.circle.long', defaultMessage: 'Circle members only' },
|
||||
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
|
||||
direct_long: { id: 'privacy.direct.long', defaultMessage: 'Visible for mentioned users only' },
|
||||
change_privacy: { id: 'privacy.change', defaultMessage: 'Adjust status privacy' },
|
||||
|
@ -235,6 +237,7 @@ class PrivacyDropdown extends PureComponent {
|
|||
{ 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: 'exchange', value: 'mutual', text: formatMessage(messages.mutual_short), meta: formatMessage(messages.mutual_long) },
|
||||
{ icon: 'user-circle', value: 'circle', text: formatMessage(messages.circle_short), meta: formatMessage(messages.circle_long) },
|
||||
{ icon: 'at', value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
|
||||
];
|
||||
this.selectableOptions = [...this.options];
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { connect } from 'react-redux';
|
||||
|
||||
import { changeCircle } from '../../../actions/compose';
|
||||
import CircleSelect from '../components/circle_select';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
unavailable: state.getIn(['compose', 'privacy']) !== 'circle',
|
||||
circles: state.get('circles'),
|
||||
circleId: state.getIn(['compose', 'circle_id']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onChange (circleId) {
|
||||
dispatch(changeCircle(circleId));
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(CircleSelect);
|
|
@ -30,6 +30,7 @@ const mapStateToProps = state => ({
|
|||
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
|
||||
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
|
||||
lang: state.getIn(['compose', 'language']),
|
||||
circleId: state.getIn(['compose', 'circle_id']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
|
|
|
@ -11,10 +11,10 @@ import Warning from '../components/warning';
|
|||
|
||||
const mapStateToProps = state => ({
|
||||
needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),
|
||||
hashtagWarning: ['public', 'public_unlisted', 'login'].indexOf(state.getIn(['compose', 'privacy'])) < 0 && state.getIn(['compose', 'searchability']) !== 'public' && HASHTAG_PATTERN_REGEX.test(state.getIn(['compose', 'text'])),
|
||||
hashtagWarning: ['public', 'public_unlisted', 'login'].includes(state.getIn(['compose', 'privacy'])) && state.getIn(['compose', 'searchability']) !== 'public' && HASHTAG_PATTERN_REGEX.test(state.getIn(['compose', 'text'])),
|
||||
directMessageWarning: state.getIn(['compose', 'privacy']) === 'direct',
|
||||
searchabilityWarning: state.getIn(['compose', 'searchability']) === 'limited',
|
||||
limitedPostWarning: state.getIn(['compose', 'privacy']) === 'mutual',
|
||||
limitedPostWarning: ['mutual', 'circle'].includes(state.getIn(['compose', 'privacy'])),
|
||||
});
|
||||
|
||||
const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning, searchabilityWarning, limitedPostWarning }) => {
|
||||
|
|
|
@ -22,6 +22,7 @@ const messages = defineMessages({
|
|||
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
|
||||
limited_short: { id: 'privacy.limited.short', defaultMessage: 'Limited menbers only' },
|
||||
mutual_short: { id: 'privacy.mutual.short', defaultMessage: 'Mutual followers only' },
|
||||
circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle members only' },
|
||||
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
|
||||
});
|
||||
|
||||
|
@ -55,6 +56,7 @@ class StatusCheckBox extends PureComponent {
|
|||
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
|
||||
'limited': { icon: 'get-pocket', text: intl.formatMessage(messages.limited_short) },
|
||||
'mutual': { icon: 'exchange', text: intl.formatMessage(messages.mutual_short) },
|
||||
'circle': { icon: 'user-circle', text: intl.formatMessage(messages.circle_short) },
|
||||
'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ const messages = defineMessages({
|
|||
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
|
||||
limited_short: { id: 'privacy.limited.short', defaultMessage: 'Limited menbers only' },
|
||||
mutual_short: { id: 'privacy.mutual.short', defaultMessage: 'Mutual followers only' },
|
||||
circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle members only' },
|
||||
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
|
||||
searchability_public_short: { id: 'searchability.public.short', defaultMessage: 'Public' },
|
||||
searchability_private_short: { id: 'searchability.unlisted.short', defaultMessage: 'Followers' },
|
||||
|
@ -256,6 +257,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
|
||||
'limited': { icon: 'get-pocket', text: intl.formatMessage(messages.limited_short) },
|
||||
'mutual': { icon: 'exchange', text: intl.formatMessage(messages.mutual_short) },
|
||||
'circle': { icon: 'user-circle', text: intl.formatMessage(messages.circle_short) },
|
||||
'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ const messages = defineMessages({
|
|||
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
|
||||
limited_short: { id: 'privacy.limited.short', defaultMessage: 'Limited menbers only' },
|
||||
mutual_short: { id: 'privacy.mutual.short', defaultMessage: 'Mutual followers only' },
|
||||
circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle members only' },
|
||||
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
|
||||
});
|
||||
|
||||
|
@ -98,6 +99,7 @@ class BoostModal extends ImmutablePureComponent {
|
|||
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
|
||||
'limited': { icon: 'get-pocket', text: intl.formatMessage(messages.limited_short) },
|
||||
'mutual': { icon: 'exchange', text: intl.formatMessage(messages.mutual_short) },
|
||||
'circle': { icon: 'user-circle', text: intl.formatMessage(messages.circle_short) },
|
||||
'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue