Add phrase confirmation to domain block dialog
This commit is contained in:
parent
c297bf5471
commit
695f9a7d08
18 changed files with 137 additions and 29 deletions
|
@ -96,6 +96,7 @@ class Settings::PreferencesController < Settings::BaseController
|
||||||
:setting_default_search_searchability,
|
:setting_default_search_searchability,
|
||||||
:setting_show_reload_button,
|
:setting_show_reload_button,
|
||||||
:setting_default_column_width,
|
:setting_default_column_width,
|
||||||
|
:setting_confirm_domain_block,
|
||||||
notification_emails: %i(follow follow_request reblog favourite emoji_reaction status_reference mention digest report pending_account trending_tag),
|
notification_emails: %i(follow follow_request reblog favourite emoji_reaction status_reference mention digest report pending_account trending_tag),
|
||||||
interactions: %i(must_be_follower must_be_following must_be_following_dm must_be_dm_to_send_email must_be_following_reference)
|
interactions: %i(must_be_follower must_be_following must_be_following_dm must_be_dm_to_send_email must_be_following_reference)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { blockDomain, unblockDomain } from '../actions/domain_blocks';
|
import { unblockDomain } from '../actions/domain_blocks';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
||||||
import Domain from '../components/domain';
|
import Domain from '../components/domain';
|
||||||
import { openModal } from '../actions/modal';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Block entire domain' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
const mapStateToProps = () => ({});
|
const mapStateToProps = () => ({});
|
||||||
|
@ -15,18 +8,10 @@ const makeMapStateToProps = () => {
|
||||||
return mapStateToProps;
|
return mapStateToProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
onBlockDomain (domain) {
|
|
||||||
dispatch(openModal('CONFIRM', {
|
|
||||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.' values={{ domain: <strong>{domain}</strong> }} />,
|
|
||||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
|
||||||
onConfirm: () => dispatch(blockDomain(domain)),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
onUnblockDomain (domain) {
|
onUnblockDomain (domain) {
|
||||||
dispatch(unblockDomain(domain));
|
dispatch(unblockDomain(domain));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Domain));
|
export default connect(makeMapStateToProps, mapDispatchToProps)(Domain);
|
||||||
|
|
|
@ -52,7 +52,7 @@ 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';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import { boostModal, deleteModal, unfollowModal, unsubscribeModal } from '../initial_state';
|
import { boostModal, deleteModal, unfollowModal, unsubscribeModal, confirmDomainBlock } from '../initial_state';
|
||||||
import { showAlertForError } from '../actions/alerts';
|
import { showAlertForError } from '../actions/alerts';
|
||||||
|
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
@ -68,6 +68,7 @@ const messages = defineMessages({
|
||||||
quoteConfirm: { id: 'confirmations.quote.confirm', defaultMessage: 'Quote' },
|
quoteConfirm: { id: 'confirmations.quote.confirm', defaultMessage: 'Quote' },
|
||||||
quoteMessage: { id: 'confirmations.quote.message', defaultMessage: 'Quoting now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
quoteMessage: { id: 'confirmations.quote.message', defaultMessage: 'Quoting now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
||||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||||
|
blockDomainPassphrase: { id: 'confirmations.domain_block.passphrase', defaultMessage: 'block' },
|
||||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||||
unsubscribeConfirm: { id: 'confirmations.unsubscribe.confirm', defaultMessage: 'Unsubscribe' },
|
unsubscribeConfirm: { id: 'confirmations.unsubscribe.confirm', defaultMessage: 'Unsubscribe' },
|
||||||
});
|
});
|
||||||
|
@ -254,6 +255,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||||
onConfirm: () => dispatch(blockDomain(domain)),
|
onConfirm: () => dispatch(blockDomain(domain)),
|
||||||
|
passphrase: confirmDomainBlock && intl.formatMessage(messages.blockDomainPassphrase),
|
||||||
|
destructive: true,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,14 @@ import { initReport } from '../../../actions/reports';
|
||||||
import { openModal } from '../../../actions/modal';
|
import { openModal } from '../../../actions/modal';
|
||||||
import { blockDomain, unblockDomain } from '../../../actions/domain_blocks';
|
import { blockDomain, unblockDomain } from '../../../actions/domain_blocks';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import { unfollowModal, unsubscribeModal } from '../../../initial_state';
|
import { unfollowModal, unsubscribeModal, confirmDomainBlock } from '../../../initial_state';
|
||||||
import { List as ImmutableList } from 'immutable';
|
import { List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||||
unsubscribeConfirm: { id: 'confirmations.unsubscribe.confirm', defaultMessage: 'Unsubscribe' },
|
unsubscribeConfirm: { id: 'confirmations.unsubscribe.confirm', defaultMessage: 'Unsubscribe' },
|
||||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||||
|
blockDomainPassphrase: { id: 'confirmations.domain_block.passphrase', defaultMessage: 'block' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
|
@ -146,6 +147,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||||
onConfirm: () => dispatch(blockDomain(domain)),
|
onConfirm: () => dispatch(blockDomain(domain)),
|
||||||
|
passphrase: confirmDomainBlock && intl.formatMessage(messages.blockDomainPassphrase),
|
||||||
|
destructive: true,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ import { openModal } from '../../actions/modal';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { HotKeys } from 'react-hotkeys';
|
import { HotKeys } from 'react-hotkeys';
|
||||||
import { boostModal, deleteModal, enableStatusReference } from '../../initial_state';
|
import { boostModal, deleteModal, confirmDomainBlock, enableStatusReference } from '../../initial_state';
|
||||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
|
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
|
||||||
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
|
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
|
||||||
import Icon from 'mastodon/components/icon';
|
import Icon from 'mastodon/components/icon';
|
||||||
|
@ -82,6 +82,7 @@ const messages = defineMessages({
|
||||||
quoteConfirm: { id: 'confirmations.quote.confirm', defaultMessage: 'Quote' },
|
quoteConfirm: { id: 'confirmations.quote.confirm', defaultMessage: 'Quote' },
|
||||||
quoteMessage: { id: 'confirmations.quote.message', defaultMessage: 'Quoting now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
quoteMessage: { id: 'confirmations.quote.message', defaultMessage: 'Quoting now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
||||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||||
|
blockDomainPassphrase: { id: 'confirmations.domain_block.passphrase', defaultMessage: 'block' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
|
@ -430,6 +431,8 @@ class Status extends ImmutablePureComponent {
|
||||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||||
confirm: this.props.intl.formatMessage(messages.blockDomainConfirm),
|
confirm: this.props.intl.formatMessage(messages.blockDomainConfirm),
|
||||||
onConfirm: () => this.props.dispatch(blockDomain(domain)),
|
onConfirm: () => this.props.dispatch(blockDomain(domain)),
|
||||||
|
passphrase: confirmDomainBlock && this.props.intl.formatMessage(messages.blockDomainPassphrase),
|
||||||
|
destructive: true,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import Button from '../../../components/button';
|
import Button from '../../../components/button';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
export default @injectIntl
|
export default @injectIntl
|
||||||
class ConfirmationModal extends React.PureComponent {
|
class ConfirmationModal extends React.PureComponent {
|
||||||
|
@ -14,6 +15,8 @@ class ConfirmationModal extends React.PureComponent {
|
||||||
secondary: PropTypes.string,
|
secondary: PropTypes.string,
|
||||||
onSecondary: PropTypes.func,
|
onSecondary: PropTypes.func,
|
||||||
closeWhenConfirm: PropTypes.bool,
|
closeWhenConfirm: PropTypes.bool,
|
||||||
|
destructive: PropTypes.bool,
|
||||||
|
passphrase: PropTypes.string,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,15 +24,30 @@ class ConfirmationModal extends React.PureComponent {
|
||||||
closeWhenConfirm: true,
|
closeWhenConfirm: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
passphrase: '',
|
||||||
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
if (this.props.passphrase) {
|
||||||
|
this.passphraseInput.focus();
|
||||||
|
} else {
|
||||||
this.button.focus();
|
this.button.focus();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleClick = () => {
|
handleClick = () => {
|
||||||
if (this.props.closeWhenConfirm) {
|
const { passphrase, closeWhenConfirm, onClose, onConfirm } = this.props;
|
||||||
this.props.onClose();
|
|
||||||
|
if (passphrase && this.state.passphrase !== passphrase) {
|
||||||
|
this.passphraseInput.focus();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this.props.onConfirm();
|
|
||||||
|
if (closeWhenConfirm) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
onConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSecondary = () => {
|
handleSecondary = () => {
|
||||||
|
@ -41,12 +59,20 @@ class ConfirmationModal extends React.PureComponent {
|
||||||
this.props.onClose();
|
this.props.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleChange = (e) => {
|
||||||
|
this.setState({ passphrase: e.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
setRef = (c) => {
|
setRef = (c) => {
|
||||||
this.button = c;
|
this.button = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPassphraseRef = (c) => {
|
||||||
|
this.passphraseInput = c;
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { message, confirm, secondary } = this.props;
|
const { message, confirm, secondary, destructive, passphrase } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='modal-root__modal confirmation-modal'>
|
<div className='modal-root__modal confirmation-modal'>
|
||||||
|
@ -54,6 +80,15 @@ class ConfirmationModal extends React.PureComponent {
|
||||||
{message}
|
{message}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{passphrase && (
|
||||||
|
<div className='confirmation-modal__passphrase'>
|
||||||
|
<div className='passphrase__label'>
|
||||||
|
<FormattedMessage id='confirmations.passphrase' defaultMessage='Please type "{passphrase}" to confirm' values={{ passphrase: <strong>{passphrase}</strong> }} />,
|
||||||
|
</div>
|
||||||
|
<input type='text' className={classNames('passphrase__input', { invalid: this.state.passphrase !== passphrase })} onChange={this.handleChange} ref={this.setPassphraseRef} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className='confirmation-modal__action-bar'>
|
<div className='confirmation-modal__action-bar'>
|
||||||
<Button onClick={this.handleCancel} className='confirmation-modal__cancel-button'>
|
<Button onClick={this.handleCancel} className='confirmation-modal__cancel-button'>
|
||||||
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
|
<FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
|
||||||
|
@ -61,7 +96,7 @@ class ConfirmationModal extends React.PureComponent {
|
||||||
{secondary !== undefined && (
|
{secondary !== undefined && (
|
||||||
<Button text={secondary} onClick={this.handleSecondary} className='confirmation-modal__secondary-button' />
|
<Button text={secondary} onClick={this.handleSecondary} className='confirmation-modal__secondary-button' />
|
||||||
)}
|
)}
|
||||||
<Button text={confirm} onClick={this.handleClick} ref={this.setRef} />
|
<Button text={confirm} className={classNames({ 'always-destructive': destructive })} onClick={this.handleClick} disabled={passphrase && this.state.passphrase !== passphrase} ref={this.setRef} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -31,6 +31,7 @@ export const showTrends = getMeta('trends');
|
||||||
export const title = getMeta('title');
|
export const title = getMeta('title');
|
||||||
export const cropImages = getMeta('crop_images');
|
export const cropImages = getMeta('crop_images');
|
||||||
export const disableSwiping = getMeta('disable_swiping');
|
export const disableSwiping = getMeta('disable_swiping');
|
||||||
|
export const confirmDomainBlock = getMeta('confirm_domain_block');
|
||||||
export const show_follow_button_on_timeline = getMeta('show_follow_button_on_timeline');
|
export const show_follow_button_on_timeline = getMeta('show_follow_button_on_timeline');
|
||||||
export const show_subscribe_button_on_timeline = getMeta('show_subscribe_button_on_timeline');
|
export const show_subscribe_button_on_timeline = getMeta('show_subscribe_button_on_timeline');
|
||||||
export const show_followed_by = getMeta('show_followed_by');
|
export const show_followed_by = getMeta('show_followed_by');
|
||||||
|
|
|
@ -185,11 +185,13 @@
|
||||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||||
"confirmations.domain_block.confirm": "Block entire domain",
|
"confirmations.domain_block.confirm": "Block entire domain",
|
||||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
||||||
|
"confirmations.domain_block.passphrase": "block",
|
||||||
"confirmations.logout.confirm": "Log out",
|
"confirmations.logout.confirm": "Log out",
|
||||||
"confirmations.logout.message": "Are you sure you want to log out?",
|
"confirmations.logout.message": "Are you sure you want to log out?",
|
||||||
"confirmations.mute.confirm": "Mute",
|
"confirmations.mute.confirm": "Mute",
|
||||||
"confirmations.mute.explanation": "This will hide posts from them and posts mentioning them, but it will still allow them to see your posts and follow you.",
|
"confirmations.mute.explanation": "This will hide posts from them and posts mentioning them, but it will still allow them to see your posts and follow you.",
|
||||||
"confirmations.mute.message": "Are you sure you want to mute {name}?",
|
"confirmations.mute.message": "Are you sure you want to mute {name}?",
|
||||||
|
"confirmations.passphrase": "Please type \"{passphrase}\" to confirm",
|
||||||
"confirmations.post_reference.confirm": "Post",
|
"confirmations.post_reference.confirm": "Post",
|
||||||
"confirmations.post_reference.message": "It contains references, do you want to post it?",
|
"confirmations.post_reference.message": "It contains references, do you want to post it?",
|
||||||
"confirmations.quote.confirm": "Quote",
|
"confirmations.quote.confirm": "Quote",
|
||||||
|
|
|
@ -185,11 +185,13 @@
|
||||||
"confirmations.delete_list.message": "本当にこのリストを完全に削除しますか?",
|
"confirmations.delete_list.message": "本当にこのリストを完全に削除しますか?",
|
||||||
"confirmations.domain_block.confirm": "ドメイン全体をブロック",
|
"confirmations.domain_block.confirm": "ドメイン全体をブロック",
|
||||||
"confirmations.domain_block.message": "本当に{domain}全体を非表示にしますか? 多くの場合は個別にブロックやミュートするだけで充分であり、また好ましいです。公開タイムラインにそのドメインのコンテンツが表示されなくなり、通知も届かなくなります。そのドメインのフォロワーはアンフォローされます。",
|
"confirmations.domain_block.message": "本当に{domain}全体を非表示にしますか? 多くの場合は個別にブロックやミュートするだけで充分であり、また好ましいです。公開タイムラインにそのドメインのコンテンツが表示されなくなり、通知も届かなくなります。そのドメインのフォロワーはアンフォローされます。",
|
||||||
|
"confirmations.domain_block.passphrase": "ブロック",
|
||||||
"confirmations.logout.confirm": "ログアウト",
|
"confirmations.logout.confirm": "ログアウト",
|
||||||
"confirmations.logout.message": "本当にログアウトしますか?",
|
"confirmations.logout.message": "本当にログアウトしますか?",
|
||||||
"confirmations.mute.confirm": "ミュート",
|
"confirmations.mute.confirm": "ミュート",
|
||||||
"confirmations.mute.explanation": "これにより相手の投稿と返信は見えなくなりますが、相手はあなたをフォローし続け投稿を見ることができます。",
|
"confirmations.mute.explanation": "これにより相手の投稿と返信は見えなくなりますが、相手はあなたをフォローし続け投稿を見ることができます。",
|
||||||
"confirmations.mute.message": "本当に{name}さんをミュートしますか?",
|
"confirmations.mute.message": "本当に{name}さんをミュートしますか?",
|
||||||
|
"confirmations.passphrase": "確認のため \"{passphrase}\" と入力してください",
|
||||||
"confirmations.post_reference.confirm": "投稿",
|
"confirmations.post_reference.confirm": "投稿",
|
||||||
"confirmations.post_reference.message": "参照を含んでいますが、投稿しますか?",
|
"confirmations.post_reference.message": "参照を含んでいますが、投稿しますか?",
|
||||||
"confirmations.quote.confirm": "引用",
|
"confirmations.quote.confirm": "引用",
|
||||||
|
|
|
@ -382,6 +382,14 @@ html {
|
||||||
border: 1px solid lighten($ui-base-color, 8%);
|
border: 1px solid lighten($ui-base-color, 8%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.confirmation-modal__passphrase .passphrase__input {
|
||||||
|
border: 1px solid lighten($ui-base-color, 8%);
|
||||||
|
|
||||||
|
&.invalid {
|
||||||
|
background-color: darken($error-value-color, 35%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.reactions-bar__item {
|
.reactions-bar__item {
|
||||||
&:hover:enabled,
|
&:hover:enabled,
|
||||||
&:focus:enabled,
|
&:focus:enabled,
|
||||||
|
|
|
@ -84,6 +84,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.always-destructive {
|
||||||
|
background-color: $error-red;
|
||||||
|
|
||||||
|
&:disabled,
|
||||||
|
&.disabled {
|
||||||
|
background-color: $ui-primary-color;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:disabled,
|
&:disabled,
|
||||||
&.disabled {
|
&.disabled {
|
||||||
background-color: $ui-primary-color;
|
background-color: $ui-primary-color;
|
||||||
|
@ -5747,6 +5757,51 @@ a.status-card.compact:hover {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.confirmation-modal__passphrase {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 30px 30px;
|
||||||
|
font-size: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.passphrase__label {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
@each $lang in $cjk-langs {
|
||||||
|
&:lang(#{$lang}) {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.passphrase__input {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 50%;
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0;
|
||||||
|
color: $inverted-text-color;
|
||||||
|
background: $simple-background-color;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 16px;
|
||||||
|
resize: vertical;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&.invalid {
|
||||||
|
background-color: lighten($error-value-color, 35%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.block-modal,
|
.block-modal,
|
||||||
.mute-modal {
|
.mute-modal {
|
||||||
&__explanation {
|
&__explanation {
|
||||||
|
|
|
@ -57,6 +57,7 @@ class UserSettingsDecorator
|
||||||
user.settings['use_pending_items'] = use_pending_items_preference if change?('setting_use_pending_items')
|
user.settings['use_pending_items'] = use_pending_items_preference if change?('setting_use_pending_items')
|
||||||
user.settings['trends'] = trends_preference if change?('setting_trends')
|
user.settings['trends'] = trends_preference if change?('setting_trends')
|
||||||
user.settings['crop_images'] = crop_images_preference if change?('setting_crop_images')
|
user.settings['crop_images'] = crop_images_preference if change?('setting_crop_images')
|
||||||
|
user.settings['confirm_domain_block'] = confirm_domain_block_preference if change?('setting_confirm_domain_block')
|
||||||
user.settings['show_follow_button_on_timeline'] = show_follow_button_on_timeline_preference if change?('setting_show_follow_button_on_timeline')
|
user.settings['show_follow_button_on_timeline'] = show_follow_button_on_timeline_preference if change?('setting_show_follow_button_on_timeline')
|
||||||
user.settings['show_subscribe_button_on_timeline'] = show_subscribe_button_on_timeline_preference if change?('setting_show_subscribe_button_on_timeline')
|
user.settings['show_subscribe_button_on_timeline'] = show_subscribe_button_on_timeline_preference if change?('setting_show_subscribe_button_on_timeline')
|
||||||
user.settings['show_followed_by'] = show_followed_by_preference if change?('setting_show_followed_by')
|
user.settings['show_followed_by'] = show_followed_by_preference if change?('setting_show_followed_by')
|
||||||
|
@ -90,7 +91,7 @@ class UserSettingsDecorator
|
||||||
user.settings['default_search_searchability'] = default_search_searchability_preference if change?('setting_default_search_searchability')
|
user.settings['default_search_searchability'] = default_search_searchability_preference if change?('setting_default_search_searchability')
|
||||||
user.settings['show_reload_button'] = show_reload_button_preference if change?('setting_show_reload_button')
|
user.settings['show_reload_button'] = show_reload_button_preference if change?('setting_show_reload_button')
|
||||||
user.settings['default_column_width'] = default_column_width_preference if change?('setting_default_column_width')
|
user.settings['default_column_width'] = default_column_width_preference if change?('setting_default_column_width')
|
||||||
end
|
end
|
||||||
|
|
||||||
def merged_notification_emails
|
def merged_notification_emails
|
||||||
user.settings['notification_emails'].merge coerced_settings('notification_emails').to_h
|
user.settings['notification_emails'].merge coerced_settings('notification_emails').to_h
|
||||||
|
@ -204,6 +205,10 @@ end
|
||||||
boolean_cast_setting 'setting_crop_images'
|
boolean_cast_setting 'setting_crop_images'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def confirm_domain_block_preference
|
||||||
|
boolean_cast_setting 'setting_confirm_domain_block'
|
||||||
|
end
|
||||||
|
|
||||||
def show_follow_button_on_timeline_preference
|
def show_follow_button_on_timeline_preference
|
||||||
boolean_cast_setting 'setting_show_follow_button_on_timeline'
|
boolean_cast_setting 'setting_show_follow_button_on_timeline'
|
||||||
end
|
end
|
||||||
|
|
|
@ -125,7 +125,7 @@ class User < ApplicationRecord
|
||||||
:reduce_motion, :system_font_ui, :noindex, :theme, :display_media, :hide_network,
|
:reduce_motion, :system_font_ui, :noindex, :theme, :display_media, :hide_network,
|
||||||
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
|
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
|
||||||
:advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
|
:advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
|
||||||
:disable_swiping,
|
:disable_swiping, :confirm_domain_block,
|
||||||
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_target,
|
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_target,
|
||||||
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_followed_by, :show_target,
|
:show_follow_button_on_timeline, :show_subscribe_button_on_timeline, :show_followed_by, :show_target,
|
||||||
:follow_button_to_list_adder, :show_navigation_panel, :show_quote_button, :show_bookmark_button,
|
:follow_button_to_list_adder, :show_navigation_panel, :show_quote_button, :show_bookmark_button,
|
||||||
|
|
|
@ -42,6 +42,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
||||||
store[:is_staff] = object.current_account.user.staff?
|
store[:is_staff] = object.current_account.user.staff?
|
||||||
store[:trends] = Setting.trends && object.current_account.user.setting_trends
|
store[:trends] = Setting.trends && object.current_account.user.setting_trends
|
||||||
store[:crop_images] = object.current_account.user.setting_crop_images
|
store[:crop_images] = object.current_account.user.setting_crop_images
|
||||||
|
store[:confirm_domain_block] = object.current_account.user.setting_confirm_domain_block
|
||||||
store[:show_follow_button_on_timeline] = object.current_account.user.setting_show_follow_button_on_timeline
|
store[:show_follow_button_on_timeline] = object.current_account.user.setting_show_follow_button_on_timeline
|
||||||
store[:show_subscribe_button_on_timeline] = object.current_account.user.setting_show_subscribe_button_on_timeline
|
store[:show_subscribe_button_on_timeline] = object.current_account.user.setting_show_subscribe_button_on_timeline
|
||||||
store[:show_followed_by] = object.current_account.user.setting_show_followed_by
|
store[:show_followed_by] = object.current_account.user.setting_show_followed_by
|
||||||
|
|
|
@ -98,6 +98,7 @@
|
||||||
= f.input :setting_unsubscribe_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
= f.input :setting_unsubscribe_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||||
= f.input :setting_boost_modal, as: :boolean, wrapper: :with_label
|
= f.input :setting_boost_modal, as: :boolean, wrapper: :with_label
|
||||||
= f.input :setting_delete_modal, as: :boolean, wrapper: :with_label
|
= f.input :setting_delete_modal, as: :boolean, wrapper: :with_label
|
||||||
|
= f.input :setting_confirm_domain_block, as: :boolean, wrapper: :with_label
|
||||||
= f.input :setting_post_reference_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
= f.input :setting_post_reference_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||||
= f.input :setting_add_reference_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
= f.input :setting_add_reference_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||||
= f.input :setting_unselect_reference_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
= f.input :setting_unselect_reference_modal, as: :boolean, wrapper: :with_label, fedibird_features: true
|
||||||
|
|
|
@ -220,6 +220,7 @@ en:
|
||||||
setting_auto_play_gif: Auto-play animated GIFs
|
setting_auto_play_gif: Auto-play animated GIFs
|
||||||
setting_boost_modal: Show confirmation dialog before boosting
|
setting_boost_modal: Show confirmation dialog before boosting
|
||||||
setting_compact_reaction: Compact display of reaction
|
setting_compact_reaction: Compact display of reaction
|
||||||
|
setting_confirm_domain_block: Require domain input for domain block
|
||||||
setting_confirm_follow_from_bot: Require follow requests from bot
|
setting_confirm_follow_from_bot: Require follow requests from bot
|
||||||
setting_content_emoji_reaction_size: Emoji reaction size
|
setting_content_emoji_reaction_size: Emoji reaction size
|
||||||
setting_content_font_size: Content font size
|
setting_content_font_size: Content font size
|
||||||
|
|
|
@ -220,6 +220,7 @@ ja:
|
||||||
setting_auto_play_gif: アニメーションGIFを自動再生する
|
setting_auto_play_gif: アニメーションGIFを自動再生する
|
||||||
setting_boost_modal: ブーストする前に確認ダイアログを表示する
|
setting_boost_modal: ブーストする前に確認ダイアログを表示する
|
||||||
setting_compact_reaction: リアクションをコンパクトに表示
|
setting_compact_reaction: リアクションをコンパクトに表示
|
||||||
|
setting_confirm_domain_block: ドメインブロックにドメイン入力を要求する
|
||||||
setting_confirm_follow_from_bot: Bot承認制アカウントにする
|
setting_confirm_follow_from_bot: Bot承認制アカウントにする
|
||||||
setting_content_emoji_reaction_size: 投稿の絵文字リアクションのサイズ
|
setting_content_emoji_reaction_size: 投稿の絵文字リアクションのサイズ
|
||||||
setting_content_font_size: 投稿のフォントサイズ
|
setting_content_font_size: 投稿のフォントサイズ
|
||||||
|
|
|
@ -42,6 +42,7 @@ defaults: &defaults
|
||||||
trends: true
|
trends: true
|
||||||
trendable_by_default: false
|
trendable_by_default: false
|
||||||
crop_images: true
|
crop_images: true
|
||||||
|
confirm_domain_block: true
|
||||||
show_follow_button_on_timeline: false
|
show_follow_button_on_timeline: false
|
||||||
show_subscribe_button_on_timeline: false
|
show_subscribe_button_on_timeline: false
|
||||||
show_followed_by: false
|
show_followed_by: false
|
||||||
|
|
Loading…
Reference in a new issue