Merge commit '651e51a82eba542c4d8c3fec5edd16420ea1ff3e' into glitch-soc/merge-upstream
Conflicts: - `yarn.lock`: Upstream updated a dependency textually adjacent to a glitch-soc-specific one. Updated the dependency as upstream did.
This commit is contained in:
commit
4d9150735a
86 files changed
+2659
-1164
No files matched your search
@@ -73,6 +73,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
singleColumn: PropTypes.bool,
|
||||
lang: PropTypes.string,
|
||||
maxChars: PropTypes.number,
|
||||
redirectOnSuccess: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
@@ -255,62 +256,60 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
<Warning />
|
||||
|
||||
<div className={classNames('compose-form__highlightable', { active: highlighted })} ref={this.setRef}>
|
||||
<div className='compose-form__scrollable'>
|
||||
<EditIndicator />
|
||||
<EditIndicator />
|
||||
|
||||
{this.props.spoiler && (
|
||||
<div className='spoiler-input'>
|
||||
<div className='spoiler-input__border' />
|
||||
{this.props.spoiler && (
|
||||
<div className='spoiler-input'>
|
||||
<div className='spoiler-input__border' />
|
||||
|
||||
<AutosuggestInput
|
||||
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
|
||||
value={this.props.spoilerText}
|
||||
disabled={isSubmitting}
|
||||
onChange={this.handleChangeSpoilerText}
|
||||
onKeyDown={this.handleKeyDownSpoiler}
|
||||
ref={this.setSpoilerText}
|
||||
suggestions={this.props.suggestions}
|
||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||
onSuggestionSelected={this.onSpoilerSuggestionSelected}
|
||||
searchTokens={[':']}
|
||||
id='cw-spoiler-input'
|
||||
className='spoiler-input__input'
|
||||
lang={this.props.lang}
|
||||
spellCheck
|
||||
/>
|
||||
<AutosuggestInput
|
||||
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
|
||||
value={this.props.spoilerText}
|
||||
disabled={isSubmitting}
|
||||
onChange={this.handleChangeSpoilerText}
|
||||
onKeyDown={this.handleKeyDownSpoiler}
|
||||
ref={this.setSpoilerText}
|
||||
suggestions={this.props.suggestions}
|
||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||
onSuggestionSelected={this.onSpoilerSuggestionSelected}
|
||||
searchTokens={[':']}
|
||||
id='cw-spoiler-input'
|
||||
className='spoiler-input__input'
|
||||
lang={this.props.lang}
|
||||
spellCheck
|
||||
/>
|
||||
|
||||
<div className='spoiler-input__border' />
|
||||
</div>
|
||||
)}
|
||||
<div className='spoiler-input__border' />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<AutosuggestTextarea
|
||||
ref={this.textareaRef}
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
disabled={isSubmitting}
|
||||
value={this.props.text}
|
||||
onChange={this.handleChange}
|
||||
suggestions={this.props.suggestions}
|
||||
onFocus={this.handleFocus}
|
||||
onKeyDown={this.handleKeyDownPost}
|
||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||
onSuggestionSelected={this.onSuggestionSelected}
|
||||
onPaste={onPaste}
|
||||
autoFocus={autoFocus}
|
||||
lang={this.props.lang}
|
||||
/>
|
||||
<div className='compose-form__dropdowns'>
|
||||
<PrivacyDropdownContainer disabled={this.props.isEditing} />
|
||||
<LanguageDropdown />
|
||||
</div>
|
||||
|
||||
<AutosuggestTextarea
|
||||
ref={this.textareaRef}
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
disabled={isSubmitting}
|
||||
value={this.props.text}
|
||||
onChange={this.handleChange}
|
||||
suggestions={this.props.suggestions}
|
||||
onFocus={this.handleFocus}
|
||||
onKeyDown={this.handleKeyDownPost}
|
||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||
onSuggestionSelected={this.onSuggestionSelected}
|
||||
onPaste={onPaste}
|
||||
autoFocus={autoFocus}
|
||||
lang={this.props.lang}
|
||||
/>
|
||||
|
||||
<UploadForm />
|
||||
<PollForm />
|
||||
|
||||
<div className='compose-form__footer'>
|
||||
<div className='compose-form__dropdowns'>
|
||||
<PrivacyDropdownContainer disabled={this.props.isEditing} />
|
||||
<LanguageDropdown />
|
||||
</div>
|
||||
|
||||
<div className='compose-form__actions'>
|
||||
<div className='compose-form__buttons'>
|
||||
<UploadButtonContainer />
|
||||
@@ -329,7 +328,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
>
|
||||
{intl.formatMessage(
|
||||
this.props.isEditing ?
|
||||
messages.saveChanges :
|
||||
messages.saveChanges :
|
||||
(this.props.isInReply ? messages.reply : messages.publish)
|
||||
)}
|
||||
</Button>
|
||||
|
||||
@@ -396,7 +396,7 @@ export const LanguageDropdown: React.FC = () => {
|
||||
warning: guess !== '' && guess !== value,
|
||||
})}
|
||||
>
|
||||
<Icon id='' icon={TranslateIcon} />
|
||||
<Icon id='translate' icon={TranslateIcon} />
|
||||
<span className='dropdown-button__label'>{current[2] ?? value}</span>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
|
||||
import { DropdownSelector } from 'mastodon/components/dropdown_selector';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
export const messages = defineMessages({
|
||||
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||
public_long: { id: 'privacy.public.long', defaultMessage: 'Anyone on and off Mastodon' },
|
||||
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Quiet public' },
|
||||
|
||||
@@ -25,7 +25,7 @@ export const ReplyIndicator = () => {
|
||||
<div className='reply-indicator__line' />
|
||||
|
||||
<Link to={`/@${account.get('acct')}`} className='detailed-status__display-avatar'>
|
||||
<Avatar account={account} size={46} />
|
||||
<Avatar key={`avatar-${account.get('id')}`} account={account} size={46} />
|
||||
</Link>
|
||||
|
||||
<div className='reply-indicator__main'>
|
||||
|
||||
@@ -34,7 +34,7 @@ const mapStateToProps = state => ({
|
||||
maxChars: state.getIn(['server', 'server', 'configuration', 'statuses', 'max_characters'], 500),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
const mapDispatchToProps = (dispatch, props) => ({
|
||||
|
||||
onChange (text) {
|
||||
dispatch(changeCompose(text));
|
||||
@@ -47,7 +47,11 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
modalProps: {},
|
||||
}));
|
||||
} else {
|
||||
dispatch(submitCompose());
|
||||
dispatch(submitCompose((status) => {
|
||||
if (props.redirectOnSuccess) {
|
||||
window.location.assign(status.url);
|
||||
}
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -38,11 +38,7 @@ export const EmojiHTML = <Element extends ElementType>(
|
||||
if (isModernEmojiEnabled()) {
|
||||
return <ModernEmojiHTML {...props} />;
|
||||
}
|
||||
const Wrapper = props.as ?? 'div';
|
||||
return (
|
||||
<Wrapper
|
||||
{...props}
|
||||
dangerouslySetInnerHTML={{ __html: props.htmlString }}
|
||||
/>
|
||||
);
|
||||
const { as: asElement, htmlString, extraEmojis, ...rest } = props;
|
||||
const Wrapper = asElement ?? 'div';
|
||||
return <Wrapper {...rest} dangerouslySetInnerHTML={{ __html: htmlString }} />;
|
||||
};
|
||||
@@ -5,7 +5,7 @@ import ModalContainer from 'mastodon/features/ui/containers/modal_container';
|
||||
|
||||
const Compose = () => (
|
||||
<>
|
||||
<ComposeFormContainer autoFocus withoutNavigation />
|
||||
<ComposeFormContainer autoFocus withoutNavigation redirectOnSuccess />
|
||||
<AlertsController />
|
||||
<ModalContainer />
|
||||
<LoadingBarContainer className='loading-bar' />
|
||||
|
||||
@@ -26,6 +26,7 @@ import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/
|
||||
import { IconButton } from '../../../components/icon_button';
|
||||
import { Dropdown } from 'mastodon/components/dropdown_menu';
|
||||
import { me } from '../../../initial_state';
|
||||
import { isFeatureEnabled } from '@/mastodon/utils/environment';
|
||||
|
||||
const messages = defineMessages({
|
||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
||||
@@ -62,6 +63,7 @@ const messages = defineMessages({
|
||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||
openOriginalPage: { id: 'account.open_original_page', defaultMessage: 'Open original page' },
|
||||
revokeQuote: { id: 'status.revoke_quote', defaultMessage: 'Remove my post from @{name}’s post' },
|
||||
quotePolicyChange: { id: 'status.quote_policy_change', defaultMessage: 'Change who can quote' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { status }) => {
|
||||
@@ -84,6 +86,7 @@ class ActionBar extends PureComponent {
|
||||
onBookmark: PropTypes.func.isRequired,
|
||||
onDelete: PropTypes.func.isRequired,
|
||||
onRevokeQuote: PropTypes.func,
|
||||
onQuotePolicyChange: PropTypes.func,
|
||||
onEdit: PropTypes.func.isRequired,
|
||||
onDirect: PropTypes.func.isRequired,
|
||||
onMention: PropTypes.func.isRequired,
|
||||
@@ -122,7 +125,11 @@ class ActionBar extends PureComponent {
|
||||
|
||||
handleRevokeQuoteClick = () => {
|
||||
this.props.onRevokeQuote(this.props.status);
|
||||
}
|
||||
};
|
||||
|
||||
handleQuotePolicyChange = () => {
|
||||
this.props.onQuotePolicyChange(this.props.status);
|
||||
};
|
||||
|
||||
handleRedraftClick = () => {
|
||||
this.props.onDelete(this.props.status, true);
|
||||
@@ -240,6 +247,9 @@ class ActionBar extends PureComponent {
|
||||
}
|
||||
|
||||
menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
|
||||
if (isFeatureEnabled('outgoing_quotes') && !['private', 'direct'].includes(status.get('visibility'))) {
|
||||
menu.push({ text: intl.formatMessage(messages.quotePolicyChange), action: this.handleQuotePolicyChange });
|
||||
}
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick });
|
||||
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick, dangerous: true });
|
||||
|
||||
@@ -265,6 +265,11 @@ class Status extends ImmutablePureComponent {
|
||||
dispatch(openModal({ modalType: 'CONFIRM_REVOKE_QUOTE', modalProps: { statusId: status.get('id'), quotedStatusId: status.getIn(['quote', 'quoted_status']) }}));
|
||||
};
|
||||
|
||||
handleQuotePolicyChange = (status) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(openModal({ modalType: 'COMPOSE_PRIVACY', modalProps: { statusId: status.get('id') } }));
|
||||
};
|
||||
|
||||
handleEditClick = (status) => {
|
||||
const { dispatch, askReplyConfirmation } = this.props;
|
||||
|
||||
@@ -642,6 +647,7 @@ class Status extends ImmutablePureComponent {
|
||||
onBookmark={this.handleBookmarkClick}
|
||||
onDelete={this.handleDeleteClick}
|
||||
onRevokeQuote={this.handleRevokeQuoteClick}
|
||||
onQuotePolicyChange={this.handleQuotePolicyChange}
|
||||
onEdit={this.handleEditClick}
|
||||
onDirect={this.handleDirectClick}
|
||||
onMention={this.handleMentionClick}
|
||||
|
||||
@@ -43,6 +43,7 @@ import { ImageModal } from './image_modal';
|
||||
import MediaModal from './media_modal';
|
||||
import { ModalPlaceholder } from './modal_placeholder';
|
||||
import VideoModal from './video_modal';
|
||||
import { VisibilityModal } from './visibility_modal';
|
||||
|
||||
export const MODAL_COMPONENTS = {
|
||||
'MEDIA': () => Promise.resolve({ default: MediaModal }),
|
||||
@@ -76,6 +77,7 @@ export const MODAL_COMPONENTS = {
|
||||
'CLOSED_REGISTRATIONS': ClosedRegistrationsModal,
|
||||
'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal,
|
||||
'ANNUAL_REPORT': AnnualReportModal,
|
||||
'COMPOSE_PRIVACY': () => Promise.resolve({ default: VisibilityModal }),
|
||||
};
|
||||
|
||||
export default class ModalRoot extends PureComponent {
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
import { forwardRef, useCallback, useId, useMemo } from 'react';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { changeComposeVisibility } from '@/mastodon/actions/compose';
|
||||
import { setStatusQuotePolicy } from '@/mastodon/actions/statuses_typed';
|
||||
import type { ApiQuotePolicy } from '@/mastodon/api_types/quotes';
|
||||
import { isQuotePolicy } from '@/mastodon/api_types/quotes';
|
||||
import type { StatusVisibility } from '@/mastodon/api_types/statuses';
|
||||
import { Dropdown } from '@/mastodon/components/dropdown';
|
||||
import type { SelectItem } from '@/mastodon/components/dropdown_selector';
|
||||
import { IconButton } from '@/mastodon/components/icon_button';
|
||||
import { messages as privacyMessages } from '@/mastodon/features/compose/components/privacy_dropdown';
|
||||
import {
|
||||
createAppSelector,
|
||||
useAppDispatch,
|
||||
useAppSelector,
|
||||
} from '@/mastodon/store';
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
|
||||
import type { BaseConfirmationModalProps } from './confirmation_modals/confirmation_modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
buttonTitle: {
|
||||
id: 'visibility_modal.button_title',
|
||||
defaultMessage: 'Set visibility',
|
||||
},
|
||||
quotePublic: {
|
||||
id: 'visibility_modal.quote_public',
|
||||
defaultMessage: 'Anyone',
|
||||
},
|
||||
quoteFollowers: {
|
||||
id: 'visibility_modal.quote_followers',
|
||||
defaultMessage: 'Followers only',
|
||||
},
|
||||
quoteNobody: {
|
||||
id: 'visibility_modal.quote_nobody',
|
||||
defaultMessage: 'No one',
|
||||
},
|
||||
});
|
||||
|
||||
interface VisibilityModalProps extends BaseConfirmationModalProps {
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
const selectStatusPolicy = createAppSelector(
|
||||
[(state) => state.statuses, (_state, statusId: string) => statusId],
|
||||
(statuses, statusId) => {
|
||||
const status = statuses.get(statusId);
|
||||
if (!status) {
|
||||
return 'public';
|
||||
}
|
||||
const policy =
|
||||
(status.getIn(['quote_approval', 'automatic', 0]) as string) || 'nobody';
|
||||
const visibility = status.get('visibility') as StatusVisibility;
|
||||
|
||||
// If the status is private or direct, it cannot be quoted by anyone.
|
||||
if (visibility === 'private' || visibility === 'direct') {
|
||||
return 'nobody';
|
||||
}
|
||||
|
||||
// If the status has a specific quote policy, return it.
|
||||
if (isQuotePolicy(policy)) {
|
||||
return policy;
|
||||
}
|
||||
|
||||
// Otherwise, return the default based on visibility.
|
||||
if (visibility === 'unlisted') {
|
||||
return 'followers';
|
||||
}
|
||||
return 'public';
|
||||
},
|
||||
);
|
||||
|
||||
export const VisibilityModal: FC<VisibilityModalProps> = forwardRef(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
({ onClose, statusId }, ref) => {
|
||||
const intl = useIntl();
|
||||
const currentVisibility = useAppSelector(
|
||||
(state) =>
|
||||
(state.statuses.getIn([statusId, 'visibility'], 'public') as
|
||||
| StatusVisibility
|
||||
| undefined) ?? 'public',
|
||||
);
|
||||
const currentQuotePolicy = useAppSelector((state) =>
|
||||
selectStatusPolicy(state, statusId),
|
||||
);
|
||||
const disableQuotePolicy =
|
||||
currentVisibility === 'private' || currentVisibility === 'direct';
|
||||
const isSaving = useAppSelector(
|
||||
(state) =>
|
||||
state.statuses.getIn([statusId, 'isSavingQuotePolicy']) === true,
|
||||
);
|
||||
|
||||
const visibilityItems = useMemo<SelectItem<StatusVisibility>[]>(
|
||||
() => [
|
||||
{
|
||||
value: 'public',
|
||||
text: intl.formatMessage(privacyMessages.public_short),
|
||||
meta: intl.formatMessage(privacyMessages.public_long),
|
||||
},
|
||||
{
|
||||
value: 'unlisted',
|
||||
text: intl.formatMessage(privacyMessages.unlisted_short),
|
||||
meta: intl.formatMessage(privacyMessages.unlisted_long),
|
||||
},
|
||||
{
|
||||
value: 'private',
|
||||
text: intl.formatMessage(privacyMessages.private_short),
|
||||
meta: intl.formatMessage(privacyMessages.private_long),
|
||||
},
|
||||
{
|
||||
value: 'direct',
|
||||
text: intl.formatMessage(privacyMessages.direct_short),
|
||||
meta: intl.formatMessage(privacyMessages.direct_long),
|
||||
},
|
||||
],
|
||||
[intl],
|
||||
);
|
||||
const quoteItems = useMemo<SelectItem<ApiQuotePolicy>[]>(
|
||||
() => [
|
||||
{ value: 'public', text: intl.formatMessage(messages.quotePublic) },
|
||||
{
|
||||
value: 'followers',
|
||||
text: intl.formatMessage(messages.quoteFollowers),
|
||||
},
|
||||
{ value: 'nobody', text: intl.formatMessage(messages.quoteNobody) },
|
||||
],
|
||||
[intl],
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const handleVisibilityChange = useCallback(
|
||||
(value: string) => {
|
||||
// Published statuses cannot change visibility.
|
||||
if (statusId) {
|
||||
return;
|
||||
}
|
||||
dispatch(changeComposeVisibility(value));
|
||||
},
|
||||
[dispatch, statusId],
|
||||
);
|
||||
const handleQuotePolicyChange = useCallback(
|
||||
(value: string) => {
|
||||
if (isQuotePolicy(value) && !disableQuotePolicy) {
|
||||
void dispatch(setStatusQuotePolicy({ policy: value, statusId }));
|
||||
}
|
||||
},
|
||||
[disableQuotePolicy, dispatch, statusId],
|
||||
);
|
||||
|
||||
const privacyDropdownId = useId();
|
||||
const quoteDropdownId = useId();
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal dialog-modal visibility-modal'>
|
||||
<div className='dialog-modal__header'>
|
||||
<IconButton
|
||||
className='dialog-modal__header__close'
|
||||
title={intl.formatMessage(messages.close)}
|
||||
icon='times'
|
||||
iconComponent={CloseIcon}
|
||||
onClick={onClose}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='visibility_modal.header'
|
||||
defaultMessage='Visibility and interaction'
|
||||
>
|
||||
{(chunks) => (
|
||||
<span className='dialog-modal__header__title'>{chunks}</span>
|
||||
)}
|
||||
</FormattedMessage>
|
||||
</div>
|
||||
<div className='dialog-modal__content'>
|
||||
<div className='dialog-modal__content__description'>
|
||||
<FormattedMessage
|
||||
id='visibility_modal.instructions'
|
||||
defaultMessage='Control who can interact with this post. Global settings can be found under <link>Preferences > Other</link>.'
|
||||
values={{
|
||||
link: (chunks) => (
|
||||
<a href='/settings/preferences/other'>{chunks}</a>
|
||||
),
|
||||
}}
|
||||
tagName='p'
|
||||
/>
|
||||
</div>
|
||||
<div className='dialog-modal__content__form'>
|
||||
<label
|
||||
htmlFor={privacyDropdownId}
|
||||
className={classNames('visibility-dropdown__label', {
|
||||
disabled: isSaving || !!statusId,
|
||||
})}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='visibility_modal.privacy_label'
|
||||
defaultMessage='Privacy'
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
items={visibilityItems}
|
||||
classPrefix='visibility-dropdown'
|
||||
current={currentVisibility}
|
||||
onChange={handleVisibilityChange}
|
||||
title={intl.formatMessage(privacyMessages.change_privacy)}
|
||||
disabled={isSaving || !!statusId}
|
||||
id={privacyDropdownId}
|
||||
/>
|
||||
{!!statusId && (
|
||||
<p className='visibility-dropdown__helper'>
|
||||
<FormattedMessage
|
||||
id='visibility_modal.helper.privacy_editing'
|
||||
defaultMessage="Visibility can't be changed after a post is published."
|
||||
/>
|
||||
</p>
|
||||
)}
|
||||
</label>
|
||||
|
||||
<label
|
||||
htmlFor={quoteDropdownId}
|
||||
className={classNames('visibility-dropdown__label', {
|
||||
disabled: disableQuotePolicy || isSaving,
|
||||
})}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='visibility_modal.quote_label'
|
||||
defaultMessage='Change who can quote'
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
items={quoteItems}
|
||||
onChange={handleQuotePolicyChange}
|
||||
classPrefix='visibility-dropdown'
|
||||
current={currentQuotePolicy}
|
||||
title={intl.formatMessage(messages.buttonTitle)}
|
||||
disabled={disableQuotePolicy || isSaving}
|
||||
id={quoteDropdownId}
|
||||
/>
|
||||
<QuotePolicyHelper
|
||||
policy={currentQuotePolicy}
|
||||
visibility={currentVisibility}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
VisibilityModal.displayName = 'VisibilityModal';
|
||||
|
||||
const QuotePolicyHelper: FC<{
|
||||
policy: ApiQuotePolicy;
|
||||
visibility: StatusVisibility;
|
||||
}> = ({ policy, visibility }) => {
|
||||
if (visibility === 'unlisted' && policy !== 'nobody') {
|
||||
return (
|
||||
<p className='visibility-dropdown__helper'>
|
||||
<FormattedMessage
|
||||
id='visibility_modal.helper.unlisted_quoting'
|
||||
defaultMessage='When people quote you, their post will also be hidden from trending timelines.'
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
if (visibility === 'private') {
|
||||
return (
|
||||
<p className='visibility-dropdown__helper'>
|
||||
<FormattedMessage
|
||||
id='visibility_modal.helper.private_quoting'
|
||||
defaultMessage="Follower-only posts can't be quoted."
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
if (visibility === 'direct') {
|
||||
return (
|
||||
<p className='visibility-dropdown__helper'>
|
||||
<FormattedMessage
|
||||
id='visibility_modal.helper.direct_quoting'
|
||||
defaultMessage="Private mentions can't be quoted."
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
Reference in new issue
Block a user