sforkowany z mirror/soapbox
Merge remote-tracking branch 'origin/develop' into just-messing-around
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>strip-front-mentions
commit
11107c6df9
|
@ -148,8 +148,16 @@ export function fetchAccountByUsername(username) {
|
|||
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
const me = state.get('me');
|
||||
|
||||
if (features.accountByUsername) {
|
||||
if (!me && features.accountLookup) {
|
||||
dispatch(accountLookup(username)).then(account => {
|
||||
dispatch(fetchAccountSuccess(account));
|
||||
}).catch(error => {
|
||||
dispatch(fetchAccountFail(null, error));
|
||||
dispatch(importErrorWhileFetchingAccountByUsername(username));
|
||||
});
|
||||
} else if (features.accountByUsername) {
|
||||
api(getState).get(`/api/v1/accounts/${username}`).then(response => {
|
||||
dispatch(fetchRelationships([response.data.id]));
|
||||
dispatch(importFetchedAccount(response.data));
|
||||
|
|
|
@ -48,6 +48,10 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST';
|
|||
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
||||
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
||||
|
||||
export const REMOTE_INTERACTION_REQUEST = 'REMOTE_INTERACTION_REQUEST';
|
||||
export const REMOTE_INTERACTION_SUCCESS = 'REMOTE_INTERACTION_SUCCESS';
|
||||
export const REMOTE_INTERACTION_FAIL = 'REMOTE_INTERACTION_FAIL';
|
||||
|
||||
const messages = defineMessages({
|
||||
bookmarkAdded: { id: 'status.bookmarked', defaultMessage: 'Bookmark added.' },
|
||||
bookmarkRemoved: { id: 'status.unbookmarked', defaultMessage: 'Bookmark removed.' },
|
||||
|
@ -475,3 +479,46 @@ export function unpinFail(status, error) {
|
|||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function remoteInteraction(ap_id, profile) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(remoteInteractionRequest(ap_id, profile));
|
||||
|
||||
return api(getState).post('/api/v1/pleroma/remote_interaction', { ap_id, profile }).then(({ data }) => {
|
||||
if (data.error) throw new Error(data.error);
|
||||
|
||||
dispatch(remoteInteractionSuccess(ap_id, profile, data.url));
|
||||
|
||||
return data.url;
|
||||
}).catch(error => {
|
||||
dispatch(remoteInteractionFail(ap_id, profile, error));
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function remoteInteractionRequest(ap_id, profile) {
|
||||
return {
|
||||
type: REMOTE_INTERACTION_REQUEST,
|
||||
ap_id,
|
||||
profile,
|
||||
};
|
||||
}
|
||||
|
||||
export function remoteInteractionSuccess(ap_id, profile, url) {
|
||||
return {
|
||||
type: REMOTE_INTERACTION_SUCCESS,
|
||||
ap_id,
|
||||
profile,
|
||||
url,
|
||||
};
|
||||
}
|
||||
|
||||
export function remoteInteractionFail(ap_id, profile, error) {
|
||||
return {
|
||||
type: REMOTE_INTERACTION_FAIL,
|
||||
ap_id,
|
||||
profile,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ class Poll extends ImmutablePureComponent {
|
|||
dispatch: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
me: SoapboxPropTypes.me,
|
||||
status: PropTypes.string,
|
||||
};
|
||||
|
||||
state = {
|
||||
|
@ -81,7 +82,11 @@ class Poll extends ImmutablePureComponent {
|
|||
};
|
||||
|
||||
openUnauthorizedModal = () => {
|
||||
this.props.dispatch(openModal('UNAUTHORIZED'));
|
||||
const { dispatch, status } = this.props;
|
||||
dispatch(openModal('UNAUTHORIZED', {
|
||||
action: 'POLL_VOTE',
|
||||
ap_id: status,
|
||||
}));
|
||||
}
|
||||
|
||||
handleRefresh = () => {
|
||||
|
|
|
@ -52,6 +52,7 @@ export const ProfileHoverCard = ({ visible }) => {
|
|||
|
||||
const [popperElement, setPopperElement] = useState(null);
|
||||
|
||||
const me = useSelector(state => state.get('me'));
|
||||
const accountId = useSelector(state => state.getIn(['profile_hover_card', 'accountId']));
|
||||
const account = useSelector(state => accountId && getAccount(state, accountId));
|
||||
const targetRef = useSelector(state => state.getIn(['profile_hover_card', 'ref', 'current']));
|
||||
|
@ -65,7 +66,7 @@ export const ProfileHoverCard = ({ visible }) => {
|
|||
|
||||
if (!account) return null;
|
||||
const accountBio = { __html: account.get('note_emojified') };
|
||||
const followedBy = account.getIn(['relationship', 'followed_by']);
|
||||
const followedBy = me !== account.get('id') && account.getIn(['relationship', 'followed_by']);
|
||||
|
||||
return (
|
||||
<div className={classNames('profile-hover-card', { 'profile-hover-card--visible': visible })} ref={setPopperElement} style={styles.popper} {...attributes.popper} onMouseEnter={handleMouseEnter(dispatch)} onMouseLeave={handleMouseLeave(dispatch)}>
|
||||
|
|
|
@ -117,11 +117,11 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
]
|
||||
|
||||
handleReplyClick = () => {
|
||||
const { me } = this.props;
|
||||
const { me, onReply, onOpenUnauthorizedModal, status } = this.props;
|
||||
if (me) {
|
||||
this.props.onReply(this.props.status, this.context.router.history);
|
||||
onReply(status, this.context.router.history);
|
||||
} else {
|
||||
this.props.onOpenUnauthorizedModal();
|
||||
onOpenUnauthorizedModal('REPLY');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,22 +167,22 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
|
||||
handleReactClick = emoji => {
|
||||
return e => {
|
||||
const { me, status } = this.props;
|
||||
const { me, dispatch, onOpenUnauthorizedModal, status } = this.props;
|
||||
if (me) {
|
||||
this.props.dispatch(simpleEmojiReact(status, emoji));
|
||||
dispatch(simpleEmojiReact(status, emoji));
|
||||
} else {
|
||||
this.props.onOpenUnauthorizedModal();
|
||||
onOpenUnauthorizedModal('FAVOURITE');
|
||||
}
|
||||
this.setState({ emojiSelectorVisible: false });
|
||||
};
|
||||
}
|
||||
|
||||
handleFavouriteClick = () => {
|
||||
const { me } = this.props;
|
||||
const { me, onFavourite, onOpenUnauthorizedModal, status } = this.props;
|
||||
if (me) {
|
||||
this.props.onFavourite(this.props.status);
|
||||
onFavourite(status);
|
||||
} else {
|
||||
this.props.onOpenUnauthorizedModal();
|
||||
onOpenUnauthorizedModal('FAVOURITE');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,11 +191,11 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
handleReblogClick = e => {
|
||||
const { me } = this.props;
|
||||
const { me, onReblog, onOpenUnauthorizedModal, status } = this.props;
|
||||
if (me) {
|
||||
this.props.onReblog(this.props.status, e);
|
||||
onReblog(status, e);
|
||||
} else {
|
||||
this.props.onOpenUnauthorizedModal();
|
||||
onOpenUnauthorizedModal('REBLOG');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -599,10 +599,13 @@ const mapStateToProps = state => {
|
|||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
const mapDispatchToProps = (dispatch, { status }) => ({
|
||||
dispatch,
|
||||
onOpenUnauthorizedModal() {
|
||||
dispatch(openModal('UNAUTHORIZED'));
|
||||
onOpenUnauthorizedModal(action) {
|
||||
dispatch(openModal('UNAUTHORIZED', {
|
||||
action,
|
||||
ap_id: status.get('url'),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -242,7 +242,7 @@ class StatusContent extends React.PureComponent {
|
|||
|
||||
<div tabIndex={!hidden ? 0 : null} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''}`} style={directionStyle} dangerouslySetInnerHTML={content} lang={status.get('language')} />
|
||||
|
||||
{!hidden && !!status.get('poll') && <PollContainer pollId={status.get('poll')} />}
|
||||
{!hidden && !!status.get('poll') && <PollContainer pollId={status.get('poll')} status={status.get('url')} />}
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.onClick) {
|
||||
|
@ -265,7 +265,7 @@ class StatusContent extends React.PureComponent {
|
|||
}
|
||||
|
||||
if (status.get('poll')) {
|
||||
output.push(<PollContainer pollId={status.get('poll')} key='poll' />);
|
||||
output.push(<PollContainer pollId={status.get('poll')} key='poll' status={status.get('url')} />);
|
||||
}
|
||||
|
||||
return output;
|
||||
|
@ -285,7 +285,7 @@ class StatusContent extends React.PureComponent {
|
|||
];
|
||||
|
||||
if (status.get('poll')) {
|
||||
output.push(<PollContainer pollId={status.get('poll')} key='poll' />);
|
||||
output.push(<PollContainer pollId={status.get('poll')} key='poll' status={status.get('url')} />);
|
||||
}
|
||||
|
||||
return output;
|
||||
|
|
|
@ -6,4 +6,5 @@ const mapStateToProps = (state, { pollId }) => ({
|
|||
me: state.get('me'),
|
||||
});
|
||||
|
||||
|
||||
export default connect(mapStateToProps)(Poll);
|
||||
|
|
|
@ -44,10 +44,10 @@ const messages = defineMessages({
|
|||
deleteHeading: { id: 'confirmations.delete.heading', defaultMessage: 'Delete' },
|
||||
deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this post?' },
|
||||
redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
|
||||
redraftHeading: { id: 'confirmations.redraft.heading', defaultMessage: 'Delete & redraft' },
|
||||
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this post and re-draft it? Favorites and reposts will be lost, and replies to the original post will be orphaned.' },
|
||||
blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
|
||||
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
|
||||
redraftHeading: { id: 'confirmations.redraft.heading', defaultMessage: 'Delete & redraft' },
|
||||
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
||||
blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
|
||||
});
|
||||
|
@ -68,178 +68,180 @@ const makeMapStateToProps = () => {
|
|||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
onReply(status, router) {
|
||||
dispatch((_, getState) => {
|
||||
const state = getState();
|
||||
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: intl.formatMessage(messages.replyMessage),
|
||||
confirm: intl.formatMessage(messages.replyConfirm),
|
||||
onConfirm: () => dispatch(replyCompose(status, router)),
|
||||
}));
|
||||
} else {
|
||||
dispatch(replyCompose(status, router));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onModalReblog(status) {
|
||||
const mapDispatchToProps = (dispatch, { intl }) => {
|
||||
function onModalReblog(status) {
|
||||
if (status.get('reblogged')) {
|
||||
dispatch(unreblog(status));
|
||||
} else {
|
||||
dispatch(reblog(status));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onReblog(status, e) {
|
||||
dispatch((_, getState) => {
|
||||
const boostModal = getSettings(getState()).get('boostModal');
|
||||
if (e.shiftKey || !boostModal) {
|
||||
this.onModalReblog(status);
|
||||
return {
|
||||
onReply(status, router) {
|
||||
dispatch((_, getState) => {
|
||||
const state = getState();
|
||||
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: intl.formatMessage(messages.replyMessage),
|
||||
confirm: intl.formatMessage(messages.replyConfirm),
|
||||
onConfirm: () => dispatch(replyCompose(status, router)),
|
||||
}));
|
||||
} else {
|
||||
dispatch(replyCompose(status, router));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onModalReblog,
|
||||
|
||||
onReblog(status, e) {
|
||||
dispatch((_, getState) => {
|
||||
const boostModal = getSettings(getState()).get('boostModal');
|
||||
if (e.shiftKey || !boostModal) {
|
||||
this.onModalReblog(status);
|
||||
} else {
|
||||
dispatch(openModal('BOOST', { status, onReblog: onModalReblog }));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onFavourite(status) {
|
||||
if (status.get('favourited')) {
|
||||
dispatch(unfavourite(status));
|
||||
} else {
|
||||
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
|
||||
dispatch(favourite(status));
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
onFavourite(status) {
|
||||
if (status.get('favourited')) {
|
||||
dispatch(unfavourite(status));
|
||||
} else {
|
||||
dispatch(favourite(status));
|
||||
}
|
||||
},
|
||||
|
||||
onBookmark(status) {
|
||||
if (status.get('bookmarked')) {
|
||||
dispatch(unbookmark(intl, status));
|
||||
} else {
|
||||
dispatch(bookmark(intl, status));
|
||||
}
|
||||
},
|
||||
|
||||
onPin(status) {
|
||||
if (status.get('pinned')) {
|
||||
dispatch(unpin(status));
|
||||
} else {
|
||||
dispatch(pin(status));
|
||||
}
|
||||
},
|
||||
|
||||
onEmbed(status) {
|
||||
dispatch(openModal('EMBED', {
|
||||
url: status.get('url'),
|
||||
onError: error => dispatch(showAlertForError(error)),
|
||||
}));
|
||||
},
|
||||
|
||||
onDelete(status, history, withRedraft = false) {
|
||||
dispatch((_, getState) => {
|
||||
const deleteModal = getSettings(getState()).get('deleteModal');
|
||||
if (!deleteModal) {
|
||||
dispatch(deleteStatus(status.get('id'), history, withRedraft));
|
||||
onBookmark(status) {
|
||||
if (status.get('bookmarked')) {
|
||||
dispatch(unbookmark(intl, status));
|
||||
} else {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: withRedraft ? require('@tabler/icons/icons/edit.svg') : require('@tabler/icons/icons/trash.svg'),
|
||||
heading: intl.formatMessage(withRedraft ? messages.redraftHeading : messages.deleteHeading),
|
||||
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
|
||||
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
|
||||
onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),
|
||||
}));
|
||||
dispatch(bookmark(intl, status));
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
onDirect(account, router) {
|
||||
dispatch(directCompose(account, router));
|
||||
},
|
||||
onPin(status) {
|
||||
if (status.get('pinned')) {
|
||||
dispatch(unpin(status));
|
||||
} else {
|
||||
dispatch(pin(status));
|
||||
}
|
||||
},
|
||||
|
||||
onChat(account, router) {
|
||||
dispatch(launchChat(account.get('id'), router));
|
||||
},
|
||||
onEmbed(status) {
|
||||
dispatch(openModal('EMBED', {
|
||||
url: status.get('url'),
|
||||
onError: error => dispatch(showAlertForError(error)),
|
||||
}));
|
||||
},
|
||||
|
||||
onMention(account, router) {
|
||||
dispatch(mentionCompose(account, router));
|
||||
},
|
||||
onDelete(status, history, withRedraft = false) {
|
||||
dispatch((_, getState) => {
|
||||
const deleteModal = getSettings(getState()).get('deleteModal');
|
||||
if (!deleteModal) {
|
||||
dispatch(deleteStatus(status.get('id'), history, withRedraft));
|
||||
} else {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: withRedraft ? require('@tabler/icons/icons/edit.svg') : require('@tabler/icons/icons/trash.svg'),
|
||||
heading: intl.formatMessage(withRedraft ? messages.redraftHeading : messages.deleteHeading),
|
||||
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
|
||||
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
|
||||
onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)),
|
||||
}));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onOpenMedia(media, index) {
|
||||
dispatch(openModal('MEDIA', { media, index }));
|
||||
},
|
||||
onDirect(account, router) {
|
||||
dispatch(directCompose(account, router));
|
||||
},
|
||||
|
||||
onOpenVideo(media, time) {
|
||||
dispatch(openModal('VIDEO', { media, time }));
|
||||
},
|
||||
onChat(account, router) {
|
||||
dispatch(launchChat(account.get('id'), router));
|
||||
},
|
||||
|
||||
onOpenAudio(media, time) {
|
||||
dispatch(openModal('AUDIO', { media, time }));
|
||||
},
|
||||
onMention(account, router) {
|
||||
dispatch(mentionCompose(account, router));
|
||||
},
|
||||
|
||||
onBlock(status) {
|
||||
const account = status.get('account');
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: require('@tabler/icons/icons/ban.svg'),
|
||||
heading: <FormattedMessage id='confirmations.block.heading' defaultMessage='Block @{name}' values={{ name: account.get('acct') }} />,
|
||||
message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
onConfirm: () => dispatch(blockAccount(account.get('id'))),
|
||||
secondary: intl.formatMessage(messages.blockAndReport),
|
||||
onSecondary: () => {
|
||||
dispatch(blockAccount(account.get('id')));
|
||||
dispatch(initReport(account, status));
|
||||
},
|
||||
}));
|
||||
},
|
||||
onOpenMedia(media, index) {
|
||||
dispatch(openModal('MEDIA', { media, index }));
|
||||
},
|
||||
|
||||
onReport(status) {
|
||||
dispatch(initReport(status.get('account'), status));
|
||||
},
|
||||
onOpenVideo(media, time) {
|
||||
dispatch(openModal('VIDEO', { media, time }));
|
||||
},
|
||||
|
||||
onMute(account) {
|
||||
dispatch(initMuteModal(account));
|
||||
},
|
||||
onOpenAudio(media, time) {
|
||||
dispatch(openModal('AUDIO', { media, time }));
|
||||
},
|
||||
|
||||
onMuteConversation(status) {
|
||||
if (status.get('muted')) {
|
||||
dispatch(unmuteStatus(status.get('id')));
|
||||
} else {
|
||||
dispatch(muteStatus(status.get('id')));
|
||||
}
|
||||
},
|
||||
onBlock(status) {
|
||||
const account = status.get('account');
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: require('@tabler/icons/icons/ban.svg'),
|
||||
heading: <FormattedMessage id='confirmations.block.heading' defaultMessage='Block @{name}' values={{ name: account.get('acct') }} />,
|
||||
message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
onConfirm: () => dispatch(blockAccount(account.get('id'))),
|
||||
secondary: intl.formatMessage(messages.blockAndReport),
|
||||
onSecondary: () => {
|
||||
dispatch(blockAccount(account.get('id')));
|
||||
dispatch(initReport(account, status));
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
onToggleHidden(status) {
|
||||
if (status.get('hidden')) {
|
||||
dispatch(revealStatus(status.get('id')));
|
||||
} else {
|
||||
dispatch(hideStatus(status.get('id')));
|
||||
}
|
||||
},
|
||||
onReport(status) {
|
||||
dispatch(initReport(status.get('account'), status));
|
||||
},
|
||||
|
||||
onGroupRemoveAccount(groupId, accountId) {
|
||||
dispatch(createRemovedAccount(groupId, accountId));
|
||||
},
|
||||
onMute(account) {
|
||||
dispatch(initMuteModal(account));
|
||||
},
|
||||
|
||||
onGroupRemoveStatus(groupId, statusId) {
|
||||
dispatch(groupRemoveStatus(groupId, statusId));
|
||||
},
|
||||
onMuteConversation(status) {
|
||||
if (status.get('muted')) {
|
||||
dispatch(unmuteStatus(status.get('id')));
|
||||
} else {
|
||||
dispatch(muteStatus(status.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onDeactivateUser(status) {
|
||||
dispatch(deactivateUserModal(intl, status.getIn(['account', 'id'])));
|
||||
},
|
||||
onToggleHidden(status) {
|
||||
if (status.get('hidden')) {
|
||||
dispatch(revealStatus(status.get('id')));
|
||||
} else {
|
||||
dispatch(hideStatus(status.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onDeleteUser(status) {
|
||||
dispatch(deleteUserModal(intl, status.getIn(['account', 'id'])));
|
||||
},
|
||||
onGroupRemoveAccount(groupId, accountId) {
|
||||
dispatch(createRemovedAccount(groupId, accountId));
|
||||
},
|
||||
|
||||
onDeleteStatus(status) {
|
||||
dispatch(deleteStatusModal(intl, status.get('id')));
|
||||
},
|
||||
onGroupRemoveStatus(groupId, statusId) {
|
||||
dispatch(groupRemoveStatus(groupId, statusId));
|
||||
},
|
||||
|
||||
onToggleStatusSensitivity(status) {
|
||||
dispatch(toggleStatusSensitivityModal(intl, status.get('id'), status.get('sensitive')));
|
||||
},
|
||||
onDeactivateUser(status) {
|
||||
dispatch(deactivateUserModal(intl, status.getIn(['account', 'id'])));
|
||||
},
|
||||
|
||||
});
|
||||
onDeleteUser(status) {
|
||||
dispatch(deleteUserModal(intl, status.getIn(['account', 'id'])));
|
||||
},
|
||||
|
||||
onDeleteStatus(status) {
|
||||
dispatch(deleteStatusModal(intl, status.get('id')));
|
||||
},
|
||||
|
||||
onToggleStatusSensitivity(status) {
|
||||
dispatch(toggleStatusSensitivityModal(intl, status.get('id'), status.get('sensitive')));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status));
|
||||
|
|
|
@ -356,7 +356,7 @@ class Header extends ImmutablePureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
if (account.get('id') !== me && isLocal(account)) {
|
||||
if (account.get('id') !== me && isLocal(account) && isAdmin(meAccount)) {
|
||||
if (isAdmin(account)) {
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.demoteToModerator, { name: account.get('username') }),
|
||||
|
@ -407,7 +407,7 @@ class Header extends ImmutablePureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
if (features.suggestionsV2) {
|
||||
if (features.suggestionsV2 && isAdmin(meAccount)) {
|
||||
if (account.getIn(['pleroma', 'is_suggested'])) {
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.unsuggestUser, { name: account.get('username') }),
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from 'soapbox/actions/accounts';
|
||||
import { expandAccountMediaTimeline } from '../../actions/timelines';
|
||||
import LoadingIndicator from 'soapbox/components/loading_indicator';
|
||||
import Column from '../ui/components/column';
|
||||
import Column from 'soapbox/components/column';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { getAccountGallery, findAccountByUsername } from 'soapbox/selectors';
|
||||
import MediaItem from './components/media_item';
|
||||
|
@ -17,6 +17,7 @@ import MissingIndicator from 'soapbox/components/missing_indicator';
|
|||
import { openModal } from 'soapbox/actions/modal';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import SubNavigation from 'soapbox/components/sub_navigation';
|
||||
|
||||
const mapStateToProps = (state, { params, withReplies = false }) => {
|
||||
const username = params.username || '';
|
||||
|
@ -186,6 +187,7 @@ class AccountGallery extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<Column>
|
||||
<SubNavigation message={`@${accountUsername}`} />
|
||||
<div className='slist slist--flex' onScroll={this.handleScroll}>
|
||||
<div className='account__section-headline'>
|
||||
<div style={{ width: '100%', display: 'flex' }}>
|
||||
|
|
|
@ -12,6 +12,7 @@ import { SimpleForm, TextInput } from 'soapbox/features/forms';
|
|||
import { Set as ImmutableSet, OrderedSet as ImmutableOrderedSet, is } from 'immutable';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.admin.users', defaultMessage: 'Users' },
|
||||
empty: { id: 'admin.user_index.empty', defaultMessage: 'No users found.' },
|
||||
searchPlaceholder: { id: 'admin.user_index.search_input_placeholder', defaultMessage: 'Who are you looking for?' },
|
||||
});
|
||||
|
@ -100,7 +101,7 @@ class UserIndex extends ImmutablePureComponent {
|
|||
const showLoading = isLoading && accountIds.isEmpty();
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Column heading={intl.formatMessage(messages.heading)}>
|
||||
<SimpleForm style={{ paddingBottom: 0 }}>
|
||||
<TextInput
|
||||
onChange={this.handleQueryChange}
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import SoapboxPropTypes from 'soapbox/utils/soapbox_prop_types';
|
||||
import { connect } from 'react-redux';
|
||||
import classNames from 'classnames';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
@ -18,6 +19,7 @@ const makeMapStateToProps = () => {
|
|||
const getAccount = makeGetAccount();
|
||||
|
||||
const mapStateToProps = (state, { id }) => ({
|
||||
me: state.get('me'),
|
||||
account: getAccount(state, id),
|
||||
autoPlayGif: getSettings(state).get('autoPlayGif'),
|
||||
});
|
||||
|
@ -30,15 +32,24 @@ export default @injectIntl
|
|||
class AccountCard extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
me: SoapboxPropTypes.me,
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
autoPlayGif: PropTypes.bool,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { account, autoPlayGif } = this.props;
|
||||
const { account, autoPlayGif, me } = this.props;
|
||||
|
||||
const followedBy = me !== account.get('id') && account.getIn(['relationship', 'followed_by']);
|
||||
|
||||
return (
|
||||
<div className='directory__card'>
|
||||
{followedBy &&
|
||||
<div className='directory__card__info'>
|
||||
<span className='relationship-tag'>
|
||||
<FormattedMessage id='account.follows_you' defaultMessage='Follows you' />
|
||||
</span>
|
||||
</div>}
|
||||
<div className='directory__card__action-button'>
|
||||
<ActionButton account={account} small />
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import { fetchFavouritedStatuses, expandFavouritedStatuses, fetchAccountFavouritedStatuses, expandAccountFavouritedStatuses } from '../../actions/favourites';
|
||||
import Column from '../ui/components/column';
|
||||
import StatusList from '../../components/status_list';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { debounce } from 'lodash';
|
||||
import MissingIndicator from 'soapbox/components/missing_indicator';
|
||||
|
@ -13,6 +13,10 @@ import { fetchAccount, fetchAccountByUsername } from '../../actions/accounts';
|
|||
import LoadingIndicator from '../../components/loading_indicator';
|
||||
import { findAccountByUsername } from 'soapbox/selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.favourited_statuses', defaultMessage: 'Liked posts' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { params }) => {
|
||||
const username = params.username || '';
|
||||
const me = state.get('me');
|
||||
|
@ -102,7 +106,7 @@ class Favourites extends ImmutablePureComponent {
|
|||
}, 300, { leading: true })
|
||||
|
||||
render() {
|
||||
const { statusIds, isLoading, hasMore, isMyAccount, isAccount, accountId, unavailable } = this.props;
|
||||
const { intl, statusIds, isLoading, hasMore, isMyAccount, isAccount, accountId, unavailable } = this.props;
|
||||
|
||||
if (!isMyAccount && !isAccount && accountId !== -1) {
|
||||
return (
|
||||
|
@ -135,7 +139,7 @@ class Favourites extends ImmutablePureComponent {
|
|||
: <FormattedMessage id='empty_column.account_favourited_statuses' defaultMessage="This user doesn't have any liked posts yet." />;
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Column heading={intl.formatMessage(messages.heading)}>
|
||||
<StatusList
|
||||
statusIds={statusIds}
|
||||
scrollKey='favourited_statuses'
|
||||
|
|
|
@ -215,54 +215,50 @@ class Filters extends ImmutablePureComponent {
|
|||
|
||||
<Button className='button button-primary setup' text={intl.formatMessage(messages.add_new)} onClick={this.handleAddNew} />
|
||||
|
||||
<ColumnSubheading text={intl.formatMessage(messages.subheading_filters)} />
|
||||
|
||||
<ScrollableList
|
||||
scrollKey='filters'
|
||||
emptyMessage={emptyMessage}
|
||||
>
|
||||
{filters.map((filter, i) => (
|
||||
<div key={i} className='filter__container'>
|
||||
<div className='filter__details'>
|
||||
<div className='filter__phrase'>
|
||||
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_phrase_label' defaultMessage='Keyword or phrase:' /></span>
|
||||
<span className='filter__list-value'>{filter.get('phrase')}</span>
|
||||
</div>
|
||||
<div className='filter__contexts'>
|
||||
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_context_label' defaultMessage='Filter contexts:' /></span>
|
||||
<span className='filter__list-value'>
|
||||
{filter.get('context').map((context, i) => (
|
||||
<span key={i} className='context'>{context}</span>
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
<div className='filter__details'>
|
||||
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_details_label' defaultMessage='Filter settings:' /></span>
|
||||
<span className='filter__list-value'>
|
||||
{filter.get('irreversible') ?
|
||||
<span><FormattedMessage id='filters.filters_list_drop' defaultMessage='Drop' /></span> :
|
||||
<span><FormattedMessage id='filters.filters_list_hide' defaultMessage='Hide' /></span>
|
||||
}
|
||||
{filter.get('whole_word') &&
|
||||
<span><FormattedMessage id='filters.filters_list_whole-word' defaultMessage='Whole word' /></span>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='filter__delete' role='button' tabIndex='0' onClick={this.handleFilterDelete} data-value={filter.get('id')} aria-label={intl.formatMessage(messages.delete)}>
|
||||
<Icon className='filter__delete-icon' id='times' size={40} />
|
||||
<span className='filter__delete-label'><FormattedMessage id='filters.filters_list_delete' defaultMessage='Delete' /></span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</ScrollableList>
|
||||
|
||||
</div>
|
||||
</SimpleForm>
|
||||
|
||||
<ColumnSubheading text={intl.formatMessage(messages.subheading_filters)} />
|
||||
|
||||
|
||||
|
||||
<ScrollableList
|
||||
scrollKey='filters'
|
||||
emptyMessage={emptyMessage}
|
||||
>
|
||||
{filters.map((filter, i) => (
|
||||
<div key={i} className='filter__container'>
|
||||
<div className='filter__details'>
|
||||
<div className='filter__phrase'>
|
||||
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_phrase_label' defaultMessage='Keyword or phrase:' /></span>
|
||||
<span className='filter__list-value'>{filter.get('phrase')}</span>
|
||||
</div>
|
||||
<div className='filter__contexts'>
|
||||
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_context_label' defaultMessage='Filter contexts:' /></span>
|
||||
<span className='filter__list-value'>
|
||||
{filter.get('context').map((context, i) => (
|
||||
<span key={i} className='context'>{context}</span>
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
<div className='filter__details'>
|
||||
<span className='filter__list-label'><FormattedMessage id='filters.filters_list_details_label' defaultMessage='Filter settings:' /></span>
|
||||
<span className='filter__list-value'>
|
||||
{filter.get('irreversible') ?
|
||||
<span><FormattedMessage id='filters.filters_list_drop' defaultMessage='Drop' /></span> :
|
||||
<span><FormattedMessage id='filters.filters_list_hide' defaultMessage='Hide' /></span>
|
||||
}
|
||||
{filter.get('whole_word') &&
|
||||
<span><FormattedMessage id='filters.filters_list_whole-word' defaultMessage='Whole word' /></span>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='filter__delete' role='button' tabIndex='0' onClick={this.handleFilterDelete} data-value={filter.get('id')} aria-label={intl.formatMessage(messages.delete)}>
|
||||
<Icon className='filter__delete-icon' id='times' size={40} />
|
||||
<span className='filter__delete-label'><FormattedMessage id='filters.filters_list_delete' defaultMessage='Delete' /></span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
expandFollowers,
|
||||
fetchAccountByUsername,
|
||||
} from '../../actions/accounts';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import AccountContainer from '../../containers/account_container';
|
||||
import Column from '../ui/components/column';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
|
@ -19,6 +19,10 @@ import MissingIndicator from 'soapbox/components/missing_indicator';
|
|||
import { getFollowDifference } from 'soapbox/utils/accounts';
|
||||
import { findAccountByUsername } from 'soapbox/selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.followers', defaultMessage: 'Followers' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { params, withReplies = false }) => {
|
||||
const username = params.username || '';
|
||||
const me = state.get('me');
|
||||
|
@ -47,9 +51,11 @@ const mapStateToProps = (state, { params, withReplies = false }) => {
|
|||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class Followers extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
accountIds: ImmutablePropTypes.orderedSet,
|
||||
|
@ -85,7 +91,7 @@ class Followers extends ImmutablePureComponent {
|
|||
}, 300, { leading: true });
|
||||
|
||||
render() {
|
||||
const { accountIds, hasMore, diffCount, isAccount, accountId, unavailable } = this.props;
|
||||
const { intl, accountIds, hasMore, diffCount, isAccount, accountId, unavailable } = this.props;
|
||||
|
||||
if (!isAccount && accountId !== -1) {
|
||||
return (
|
||||
|
@ -114,7 +120,7 @@ class Followers extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Column heading={intl.formatMessage(messages.heading)}>
|
||||
<ScrollableList
|
||||
scrollKey='followers'
|
||||
hasMore={hasMore}
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
expandFollowing,
|
||||
fetchAccountByUsername,
|
||||
} from '../../actions/accounts';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import AccountContainer from '../../containers/account_container';
|
||||
import Column from '../ui/components/column';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
|
@ -19,6 +19,10 @@ import MissingIndicator from 'soapbox/components/missing_indicator';
|
|||
import { getFollowDifference } from 'soapbox/utils/accounts';
|
||||
import { findAccountByUsername } from 'soapbox/selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.following', defaultMessage: 'Following' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { params, withReplies = false }) => {
|
||||
const username = params.username || '';
|
||||
const me = state.get('me');
|
||||
|
@ -47,9 +51,11 @@ const mapStateToProps = (state, { params, withReplies = false }) => {
|
|||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class Following extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
accountIds: ImmutablePropTypes.orderedSet,
|
||||
|
@ -85,7 +91,7 @@ class Following extends ImmutablePureComponent {
|
|||
}, 300, { leading: true });
|
||||
|
||||
render() {
|
||||
const { accountIds, hasMore, isAccount, diffCount, accountId, unavailable } = this.props;
|
||||
const { intl, accountIds, hasMore, isAccount, diffCount, accountId, unavailable } = this.props;
|
||||
|
||||
if (!isAccount && accountId !== -1) {
|
||||
return (
|
||||
|
@ -114,7 +120,7 @@ class Following extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Column heading={intl.formatMessage(messages.heading)}>
|
||||
<ScrollableList
|
||||
scrollKey='following'
|
||||
hasMore={hasMore}
|
||||
|
|
|
@ -69,7 +69,7 @@ class ListAdder extends ImmutablePureComponent {
|
|||
const { accountId, listIds, intl } = this.props;
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal compose-modal'>
|
||||
<div className='modal-root__modal compose-modal list-editor__content'>
|
||||
<div className='compose-modal__header'>
|
||||
<h3 className='compose-modal__header__title'>
|
||||
<FormattedMessage id='list_adder.header_title' defaultMessage='Add or Remove from Lists' />
|
||||
|
|
|
@ -70,7 +70,7 @@ class ListEditor extends ImmutablePureComponent {
|
|||
</h3>
|
||||
<IconButton className='compose-modal__close' title={intl.formatMessage(messages.close)} src={require('@tabler/icons/icons/x.svg')} onClick={this.onClickClose} />
|
||||
</div>
|
||||
<div className='compose-modal__content'>
|
||||
<div className='compose-modal__content list-editor__content'>
|
||||
<div className='list-editor'>
|
||||
<ColumnSubheading text={intl.formatMessage(messages.changeTitle)} />
|
||||
<EditListForm />
|
||||
|
|
|
@ -5,10 +5,14 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import { fetchPinnedStatuses } from '../../actions/pin_statuses';
|
||||
import Column from '../ui/components/column';
|
||||
import StatusList from '../../components/status_list';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import MissingIndicator from 'soapbox/components/missing_indicator';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.pins', defaultMessage: 'Pinned posts' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { params }) => {
|
||||
const username = params.username || '';
|
||||
const me = state.get('me');
|
||||
|
@ -37,7 +41,7 @@ class PinnedStatuses extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { statusIds, hasMore, isMyAccount } = this.props;
|
||||
const { intl, statusIds, hasMore, isMyAccount } = this.props;
|
||||
|
||||
if (!isMyAccount) {
|
||||
return (
|
||||
|
@ -48,7 +52,7 @@ class PinnedStatuses extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Column heading={intl.formatMessage(messages.heading)}>
|
||||
<StatusList
|
||||
statusIds={statusIds}
|
||||
scrollKey='pinned_statuses'
|
||||
|
|
|
@ -4,16 +4,20 @@ import { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import LoadingIndicator from '../../components/loading_indicator';
|
||||
import MissingIndicator from '../../components/missing_indicator';
|
||||
import { fetchFavourites, fetchReactions } from '../../actions/interactions';
|
||||
import { fetchStatus } from '../../actions/statuses';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import AccountContainer from '../../containers/account_container';
|
||||
import Column from '../ui/components/column';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import { makeGetStatus } from '../../selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.reactions', defaultMessage: 'Reactions' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const getStatus = makeGetStatus();
|
||||
const status = getStatus(state, {
|
||||
|
@ -35,6 +39,7 @@ const mapStateToProps = (state, props) => {
|
|||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class Reactions extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
|
@ -78,14 +83,11 @@ class Reactions extends ImmutablePureComponent {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { params, reactions, accounts, status } = this.props;
|
||||
const { username, statusId } = params;
|
||||
|
||||
const back = `/@${username}/posts/${statusId}`;
|
||||
const { intl, params, reactions, accounts, status } = this.props;
|
||||
|
||||
if (!accounts) {
|
||||
return (
|
||||
<Column back={back}>
|
||||
<Column>
|
||||
<LoadingIndicator />
|
||||
</Column>
|
||||
);
|
||||
|
@ -93,7 +95,7 @@ class Reactions extends ImmutablePureComponent {
|
|||
|
||||
if (!status) {
|
||||
return (
|
||||
<Column back={back}>
|
||||
<Column>
|
||||
<MissingIndicator />
|
||||
</Column>
|
||||
);
|
||||
|
@ -102,7 +104,7 @@ class Reactions extends ImmutablePureComponent {
|
|||
const emptyMessage = <FormattedMessage id='status.reactions.empty' defaultMessage='No one has reacted to this post yet. When someone does, they will show up here.' />;
|
||||
|
||||
return (
|
||||
<Column back={back}>
|
||||
<Column heading={intl.formatMessage(messages.heading)}>
|
||||
{
|
||||
reactions.size > 0 && (
|
||||
<div className='reaction__filter-bar'>
|
||||
|
|
|
@ -66,9 +66,12 @@ const mapStateToProps = state => {
|
|||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onOpenUnauthorizedModal() {
|
||||
dispatch(openModal('UNAUTHORIZED'));
|
||||
const mapDispatchToProps = (dispatch, { status }) => ({
|
||||
onOpenUnauthorizedModal(action) {
|
||||
dispatch(openModal('UNAUTHORIZED', {
|
||||
action,
|
||||
ap_id: status.get('url'),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -121,20 +124,20 @@ class ActionBar extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleReplyClick = () => {
|
||||
const { me } = this.props;
|
||||
const { me, onReply, onOpenUnauthorizedModal } = this.props;
|
||||
if (me) {
|
||||
this.props.onReply(this.props.status);
|
||||
onReply(this.props.status);
|
||||
} else {
|
||||
this.props.onOpenUnauthorizedModal();
|
||||
onOpenUnauthorizedModal('REPLY');
|
||||
}
|
||||
}
|
||||
|
||||
handleReblogClick = (e) => {
|
||||
const { me } = this.props;
|
||||
const { me, onReblog, onOpenUnauthorizedModal, status } = this.props;
|
||||
if (me) {
|
||||
this.props.onReblog(this.props.status, e);
|
||||
onReblog(status, e);
|
||||
} else {
|
||||
this.props.onOpenUnauthorizedModal();
|
||||
onOpenUnauthorizedModal('REBLOG');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,11 +146,11 @@ class ActionBar extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleFavouriteClick = () => {
|
||||
const { me } = this.props;
|
||||
const { me, onFavourite, onOpenUnauthorizedModal } = this.props;
|
||||
if (me) {
|
||||
this.props.onFavourite(this.props.status);
|
||||
onFavourite(status);
|
||||
} else {
|
||||
this.props.onOpenUnauthorizedModal();
|
||||
onOpenUnauthorizedModal('FAVOURITE');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,11 +187,11 @@ class ActionBar extends React.PureComponent {
|
|||
|
||||
handleReactClick = emoji => {
|
||||
return e => {
|
||||
const { me } = this.props;
|
||||
const { me, onEmojiReact, onOpenUnauthorizedModal, status } = this.props;
|
||||
if (me) {
|
||||
this.props.onEmojiReact(this.props.status, emoji);
|
||||
onEmojiReact(status, emoji);
|
||||
} else {
|
||||
this.props.onOpenUnauthorizedModal();
|
||||
onOpenUnauthorizedModal('FAVOURITE');
|
||||
}
|
||||
this.setState({ emojiSelectorVisible: false, emojiSelectorFocused: false });
|
||||
};
|
||||
|
|
|
@ -13,6 +13,8 @@ import {
|
|||
blockAccount,
|
||||
unblockAccount,
|
||||
} from 'soapbox/actions/accounts';
|
||||
import { openModal } from 'soapbox/actions/modal';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
const messages = defineMessages({
|
||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||
|
@ -26,8 +28,11 @@ const messages = defineMessages({
|
|||
|
||||
const mapStateToProps = state => {
|
||||
const me = state.get('me');
|
||||
const instance = state.get('instance');
|
||||
|
||||
return {
|
||||
me,
|
||||
features: getFeatures(instance),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -47,6 +52,14 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
dispatch(blockAccount(account.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onOpenUnauthorizedModal(account) {
|
||||
dispatch(openModal('UNAUTHORIZED', {
|
||||
action: 'FOLLOW',
|
||||
account: account.get('id'),
|
||||
ap_id: account.get('url'),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps, mapDispatchToProps)
|
||||
|
@ -57,8 +70,10 @@ class ActionButton extends ImmutablePureComponent {
|
|||
account: ImmutablePropTypes.map.isRequired,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onOpenUnauthorizedModal: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
small: PropTypes.bool,
|
||||
features: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -81,12 +96,26 @@ class ActionButton extends ImmutablePureComponent {
|
|||
this.props.onBlock(this.props.account);
|
||||
}
|
||||
|
||||
handleRemoteFollow = () => {
|
||||
this.props.onOpenUnauthorizedModal(this.props.account);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { account, intl, me, small } = this.props;
|
||||
const { account, intl, me, small, features } = this.props;
|
||||
const empty = <></>;
|
||||
|
||||
if (!me) {
|
||||
// Remote follow
|
||||
if (features.remoteInteractionsAPI) {
|
||||
return (<Button
|
||||
className='button--follow'
|
||||
onClick={this.handleRemoteFollow}
|
||||
>
|
||||
{intl.formatMessage(messages.follow)}
|
||||
<Icon src={require('@tabler/icons/icons/plus.svg')} />
|
||||
</Button>);
|
||||
}
|
||||
|
||||
return (<form method='POST' action='/main/ostatus'>
|
||||
<input type='hidden' name='nickname' value={account.get('acct')} />
|
||||
<input type='hidden' name='profile' value='' />
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import Column from './column';
|
||||
import ColumnHeader from './column_header';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column_forbidden.title', defaultMessage: 'Forbidden' },
|
||||
body: { id: 'column_forbidden.body', defaultMessage: 'You do not have permission to access this page.' },
|
||||
});
|
||||
|
||||
class ColumnForbidden extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl: { formatMessage } } = this.props;
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<ColumnHeader icon='exclamation-circle' type={formatMessage(messages.title)} />
|
||||
<div className='error-column'>
|
||||
{formatMessage(messages.body)}
|
||||
</div>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(ColumnForbidden);
|
|
@ -5,32 +5,150 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|||
import { Link } from 'react-router-dom';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import IconButton from 'soapbox/components/icon_button';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { remoteInteraction } from 'soapbox/actions/interactions';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
accountPlaceholder: { id: 'remote_interaction.account_placeholder', defaultMessage: 'Enter your username@domain you want to act from' },
|
||||
userNotFoundError: { id: 'remote_interaction.user_not_found_error', defaultMessage: 'Couldn\'t find given user' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const me = state.get('me');
|
||||
const mapStateToProps = (state, props) => {
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
|
||||
if (props.action !== 'FOLLOW') {
|
||||
return {
|
||||
features,
|
||||
siteTitle: state.getIn(['instance', 'title']),
|
||||
remoteInteractionsAPI: features.remoteInteractionsAPI,
|
||||
};
|
||||
}
|
||||
|
||||
const userName = state.getIn(['accounts', props.account, 'display_name']);
|
||||
|
||||
return {
|
||||
account: state.getIn(['accounts', me]),
|
||||
features,
|
||||
siteTitle: state.getIn(['instance', 'title']),
|
||||
userName,
|
||||
remoteInteractionsAPI: features.remoteInteractionsAPI,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
dispatch,
|
||||
onRemoteInteraction(ap_id, account) {
|
||||
return dispatch(remoteInteraction(ap_id, account));
|
||||
},
|
||||
});
|
||||
|
||||
class UnauthorizedModal extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
features: PropTypes.object.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onRemoteInteraction: PropTypes.func.isRequired,
|
||||
userName: PropTypes.string,
|
||||
};
|
||||
|
||||
state = {
|
||||
account: '',
|
||||
};
|
||||
|
||||
onAccountChange = e => {
|
||||
this.setState({ account: e.target.value });
|
||||
}
|
||||
|
||||
onClickClose = () => {
|
||||
this.props.onClose('UNAUTHORIZED');
|
||||
};
|
||||
|
||||
onClickProceed = e => {
|
||||
e.preventDefault();
|
||||
|
||||
const { intl, ap_id, dispatch, onClose, onRemoteInteraction } = this.props;
|
||||
const { account } = this.state;
|
||||
|
||||
onRemoteInteraction(ap_id, account)
|
||||
.then(url => {
|
||||
window.open(url, '_new', 'noopener,noreferrer');
|
||||
onClose('UNAUTHORIZED');
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.message === 'Couldn\'t find user') {
|
||||
dispatch(snackbar.error(intl.formatMessage(messages.userNotFoundError)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
renderRemoteInteractions() {
|
||||
const { intl, siteTitle, userName, action } = this.props;
|
||||
const { account } = this.state;
|
||||
|
||||
let header;
|
||||
let button;
|
||||
|
||||
if (action === 'FOLLOW') {
|
||||
header = <FormattedMessage id='remote_interaction.follow_title' defaultMessage='Follow {user} remotely' values={{ user: userName }} />;
|
||||
button = <FormattedMessage id='remote_interaction.follow' defaultMessage='Proceed to follow' />;
|
||||
} else if (action === 'REPLY') {
|
||||
header = <FormattedMessage id='remote_interaction.reply_title' defaultMessage='Reply to a post remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.reply' defaultMessage='Proceed to reply' />;
|
||||
} else if (action === 'REBLOG') {
|
||||
header = <FormattedMessage id='remote_interaction.reblog_title' defaultMessage='Reblog a post remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.reblog' defaultMessage='Proceed to repost' />;
|
||||
} else if (action === 'FAVOURITE') {
|
||||
header = <FormattedMessage id='remote_interaction.favourite_title' defaultMessage='Like a post remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.favourite' defaultMessage='Proceed to like' />;
|
||||
} else if (action === 'POLL_VOTE') {
|
||||
header = <FormattedMessage id='remote_interaction.poll_vote_title' defaultMessage='Vote in a poll remotely' />;
|
||||
button = <FormattedMessage id='remote_interaction.poll_vote' defaultMessage='Proceed to vote' />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal compose-modal unauthorized-modal remote-interaction-modal'>
|
||||
<div className='compose-modal__header'>
|
||||
<h3 className='compose-modal__header__title'>{header}</h3>
|
||||
<IconButton className='compose-modal__close' title={intl.formatMessage(messages.close)} src={require('@tabler/icons/icons/x.svg')} onClick={this.onClickClose} />
|
||||
</div>
|
||||
<div className='remote-interaction-modal__content'>
|
||||
<form className='simple_form remote-interaction-modal__fields'>
|
||||
<input
|
||||
type='text'
|
||||
placeholder={intl.formatMessage(messages.accountPlaceholder)}
|
||||
name='remote_follow[acct]'
|
||||
value={account}
|
||||
autoCorrect='off'
|
||||
autoCapitalize='off'
|
||||
onChange={this.onAccountChange}
|
||||
required
|
||||
/>
|
||||
<button className='button' onClick={this.onClickProceed}>{button}</button>
|
||||
</form>
|
||||
<div className='remote-interaction-modal__divider'>
|
||||
<span>
|
||||
<FormattedMessage id='remote_interaction.divider' defaultMessage='or' />
|
||||
</span>
|
||||
</div>
|
||||
<h3 className='compose-modal__header__title'><FormattedMessage id='unauthorized_modal.title' defaultMessage='Sign up for {site_title}' values={{ site_title: siteTitle }} /></h3>
|
||||
<Link to='/' className='unauthorized-modal-content__button button' onClick={this.onClickClose}>
|
||||
<FormattedMessage id='account.register' defaultMessage='Sign up' />
|
||||
</Link>
|
||||
<Link to='/auth/sign_in' className='unauthorized-modal-content__button button button-secondary' onClick={this.onClickClose}>
|
||||
<FormattedMessage id='account.login' defaultMessage='Log in' />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, siteTitle } = this.props;
|
||||
const { intl, features, siteTitle } = this.props;
|
||||
|
||||
if (features.remoteInteractionsAPI && features.federating) return this.renderRemoteInteractions();
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal compose-modal unauthorized-modal'>
|
||||
|
@ -61,4 +179,4 @@ class UnauthorizedModal extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default injectIntl(connect(mapStateToProps)(UnauthorizedModal));
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(UnauthorizedModal));
|
||||
|
|
|
@ -317,14 +317,14 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||
<WrappedRoute path='/settings/import' page={DefaultPage} component={ImportData} content={children} />
|
||||
<WrappedRoute path='/settings/aliases' page={DefaultPage} component={Aliases} content={children} />
|
||||
<WrappedRoute path='/backups' page={DefaultPage} component={Backups} content={children} />
|
||||
<WrappedRoute path='/soapbox/config' page={DefaultPage} component={SoapboxConfig} content={children} />
|
||||
<WrappedRoute path='/soapbox/config' adminOnly page={DefaultPage} component={SoapboxConfig} content={children} />
|
||||
|
||||
<Redirect from='/admin/dashboard' to='/admin' exact />
|
||||
<WrappedRoute path='/admin' page={AdminPage} component={Dashboard} content={children} exact />
|
||||
<WrappedRoute path='/admin/approval' page={AdminPage} component={AwaitingApproval} content={children} exact />
|
||||
<WrappedRoute path='/admin/reports' page={AdminPage} component={Reports} content={children} exact />
|
||||
<WrappedRoute path='/admin/log' page={AdminPage} component={ModerationLog} content={children} exact />
|
||||
<WrappedRoute path='/admin/users' page={AdminPage} component={UserIndex} content={children} exact />
|
||||
<WrappedRoute path='/admin' staffOnly page={AdminPage} component={Dashboard} content={children} exact />
|
||||
<WrappedRoute path='/admin/approval' staffOnly page={AdminPage} component={AwaitingApproval} content={children} exact />
|
||||
<WrappedRoute path='/admin/reports' staffOnly page={AdminPage} component={Reports} content={children} exact />
|
||||
<WrappedRoute path='/admin/log' staffOnly page={AdminPage} component={ModerationLog} content={children} exact />
|
||||
<WrappedRoute path='/admin/users' staffOnly page={AdminPage} component={UserIndex} content={children} exact />
|
||||
<WrappedRoute path='/info' page={EmptyPage} component={ServerInfo} content={children} />
|
||||
|
||||
<WrappedRoute path='/developers/apps/create' page={DefaultPage} component={CreateApp} content={children} />
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import SoapboxPropTypes from 'soapbox/utils/soapbox_prop_types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { Redirect, Route } from 'react-router-dom';
|
||||
import ColumnsAreaContainer from '../containers/columns_area_container';
|
||||
import ColumnLoading from '../components/column_loading';
|
||||
import ColumnForbidden from '../components/column_forbidden';
|
||||
import BundleColumnError from '../components/bundle_column_error';
|
||||
import BundleContainer from '../containers/bundle_container';
|
||||
import { isStaff, isAdmin } from 'soapbox/utils/accounts';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const me = state.get('me');
|
||||
|
||||
return {
|
||||
me: state.get('me'),
|
||||
account: state.getIn(['accounts', me]),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -22,8 +26,10 @@ class WrappedRoute extends React.Component {
|
|||
content: PropTypes.node,
|
||||
componentParams: PropTypes.object,
|
||||
layout: PropTypes.object,
|
||||
account: ImmutablePropTypes.map,
|
||||
publicRoute: PropTypes.bool,
|
||||
me: SoapboxPropTypes.me,
|
||||
staffOnly: PropTypes.bool,
|
||||
adminOnly: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -72,6 +78,14 @@ class WrappedRoute extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
renderForbidden = () => {
|
||||
return (
|
||||
<ColumnsAreaContainer layout={this.props.layout}>
|
||||
<ColumnForbidden />
|
||||
</ColumnsAreaContainer>
|
||||
);
|
||||
}
|
||||
|
||||
renderError = (props) => {
|
||||
return (
|
||||
<ColumnsAreaContainer layout={this.props.layout}>
|
||||
|
@ -80,16 +94,26 @@ class WrappedRoute extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { component: Component, content, publicRoute, me, ...rest } = this.props;
|
||||
loginRedirect = () => {
|
||||
const actualUrl = encodeURIComponent(`${this.props.computedMatch.url}${this.props.location.search}`); // eslint-disable-line react/prop-types
|
||||
return <Redirect to={`/auth/sign_in?redirect_uri=${actualUrl}`} />;
|
||||
}
|
||||
|
||||
if (!publicRoute && me === false) {
|
||||
const actualUrl = encodeURIComponent(`${this.props.computedMatch.url}${this.props.location.search}`); // eslint-disable-line react/prop-types
|
||||
return <Redirect to={`/auth/sign_in?redirect_uri=${actualUrl}`} />;
|
||||
// return <Route path={this.props.path} component={() => {
|
||||
// window.location.href = `/auth/sign_in?redirect_uri=${actualUrl}`;
|
||||
// return null;
|
||||
// }}/>
|
||||
render() {
|
||||
const { component: Component, content, account, publicRoute, staffOnly, adminOnly, ...rest } = this.props;
|
||||
|
||||
const authorized = [
|
||||
account || publicRoute,
|
||||
staffOnly ? account && isStaff(account) : true,
|
||||
adminOnly ? account && isAdmin(account) : true,
|
||||
].every(c => c);
|
||||
|
||||
if (!authorized) {
|
||||
if (!account) {
|
||||
return this.loginRedirect();
|
||||
} else {
|
||||
return this.renderForbidden();
|
||||
}
|
||||
}
|
||||
|
||||
return <Route {...rest} render={this.renderComponent} />;
|
||||
|
|
|
@ -740,6 +740,18 @@
|
|||
"remote_instance.federation_panel.some_restrictions_message": "{siteTitle} nakłada pewne ograniczenia na {host}.",
|
||||
"remote_instance.pin_host": "Przypnij {instance}",
|
||||
"remote_instance.unpin_host": "Odepnij {instance}",
|
||||
"remote_interaction.account_placeholder": "Wprowadź nazwę@domenę użytkownika, z którego chcesz wykonać działanie",
|
||||
"remote_interaction.favourite": "Przejdź do polubienia",
|
||||
"remote_interaction.favourite_title": "Polub wpis zdalnie",
|
||||
"remote_interaction.follow": "Przejdź do obserwacji",
|
||||
"remote_interaction.follow_title": "Obserwuj {user} zdalnie",
|
||||
"remote_interaction.poll_vote": "Przejdź do ankiety",
|
||||
"remote_interaction.poll_vote_title": "Zagłosuj w ankiecie zdalnie",
|
||||
"remote_interaction.reblog": "Przejdź do wpisu",
|
||||
"remote_interaction.reblog_title": "Udostępnij wpis zdalnie",
|
||||
"remote_interaction.reply": "Przejdź do odpowiedzi",
|
||||
"remote_interaction.reply_title": "Odpowiedz na wpis zdalnie",
|
||||
"remote_interaction.user_not_found_error": "Nie można odnaleźć podanego użytkownika",
|
||||
"remote_timeline.filter_message": "Przeglądasz oś czasu {instance}",
|
||||
"reply_indicator.cancel": "Anuluj",
|
||||
"report.block": "Zablokuj {target}",
|
||||
|
|
|
@ -74,6 +74,7 @@ export const getFeatures = createSelector([
|
|||
v.software === MASTODON && gte(v.compatVersion, '3.4.0'),
|
||||
v.software === PLEROMA && gte(v.version, '2.4.50'),
|
||||
]),
|
||||
remoteInteractionsAPI: v.software === PLEROMA && gte(v.version, '2.4.50'),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -956,7 +956,7 @@
|
|||
// ScrollableList
|
||||
.slist .item-list > article:first-child,
|
||||
// ScrollableList placeholders
|
||||
.slist .item-list .slist__placeholder > .material-status:first-child,
|
||||
.slist .item-list .slist__placeholder:first-child > .material-status:first-child,
|
||||
.slist.slist--flex .item-list > .material-status:first-child,
|
||||
// Thread
|
||||
.material-status:not(.material-status + .material-status) {
|
||||
|
|
|
@ -185,17 +185,29 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__descendants .thread__status:first-child {
|
||||
&__descendants &__status:first-child {
|
||||
margin-top: 10px;
|
||||
|
||||
.status__wrapper--filtered {
|
||||
margin-top: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__status--focused:first-child,
|
||||
&__ancestors &__status:first-child {
|
||||
margin-top: 10px;
|
||||
|
||||
.status__wrapper--filtered {
|
||||
margin-top: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__descendants &__status:last-child {
|
||||
margin-bottom: 10px;
|
||||
|
||||
.status__wrapper--filtered {
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__connector {
|
||||
|
|
|
@ -39,6 +39,13 @@
|
|||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&__info {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
&__action-button {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__accounts {
|
||||
background: var(--background-color);
|
||||
overflow-y: auto;
|
||||
|
@ -33,7 +37,7 @@
|
|||
.search {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 10px 0;
|
||||
margin: 10px;
|
||||
|
||||
> label {
|
||||
flex: 1 1;
|
||||
|
|
|
@ -702,6 +702,12 @@
|
|||
right: 15px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
|
||||
.svg-icon {
|
||||
color: var(--primary-text-color);
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -854,6 +860,59 @@
|
|||
}
|
||||
}
|
||||
|
||||
.remote-interaction-modal {
|
||||
&__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// align-items: center;
|
||||
row-gap: 10px;
|
||||
padding: 10px;
|
||||
|
||||
.unauthorized-modal-content__button {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
|
||||
.button {
|
||||
width: auto;
|
||||
margin: 0;
|
||||
text-transform: none;
|
||||
overflow: unset;
|
||||
}
|
||||
}
|
||||
|
||||
&__divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin: 0 -10px;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: "";
|
||||
flex: 1;
|
||||
border-bottom: 1px solid hsla(var(--primary-text-color_hsl), 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 895px) {
|
||||
margin: 0;
|
||||
border-radius: 6px;
|
||||
height: unset !important;
|
||||
width: 440px !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
width: 330px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.focal-point-modal {
|
||||
max-width: 80vw;
|
||||
max-height: 80vh;
|
||||
|
|
|
@ -127,7 +127,7 @@
|
|||
}
|
||||
|
||||
.status__wrapper--filtered {
|
||||
color: var(--primary-text-color);
|
||||
color: var(--primary-text-color--faint);
|
||||
border: 0;
|
||||
font-size: inherit;
|
||||
text-align: center;
|
||||
|
@ -137,7 +137,6 @@
|
|||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
clear: both;
|
||||
border-bottom: 1px solid var(--brand-color--med);
|
||||
}
|
||||
|
||||
.status__prepend-icon-wrapper {
|
||||
|
|
|
@ -169,7 +169,7 @@
|
|||
}
|
||||
|
||||
&:hover::before {
|
||||
z-index: 0;
|
||||
z-index: -1;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
|
@ -496,7 +496,7 @@ code {
|
|||
&::after {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
|
@ -504,6 +504,7 @@ code {
|
|||
padding-left: 12px;
|
||||
pointer-events: none;
|
||||
margin-top: 8px;
|
||||
font-weight: 900;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -246,6 +246,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
article:last-child > .domain {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.domain__wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
"detect-passive-events": "^2.0.0",
|
||||
"dotenv": "^8.0.0",
|
||||
"emoji-datasource": "5.0.0",
|
||||
"emoji-mart": "^3.0.1",
|
||||
"emoji-mart": "npm:emoji-mart-lazyload",
|
||||
"entities": "^3.0.1",
|
||||
"es6-symbol": "^3.1.1",
|
||||
"escape-html": "^1.0.3",
|
||||
|
@ -90,7 +90,7 @@
|
|||
"http-link-header": "^1.0.2",
|
||||
"immutable": "^4.0.0-rc.14",
|
||||
"imports-loader": "^1.0.0",
|
||||
"intersection-observer": "^0.11.0",
|
||||
"intersection-observer": "^0.12.0",
|
||||
"intl": "^1.2.5",
|
||||
"intl-messageformat": "^9.0.0",
|
||||
"intl-messageformat-parser": "^6.0.0",
|
||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -3598,12 +3598,13 @@ emoji-datasource@5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/emoji-datasource/-/emoji-datasource-5.0.0.tgz#1522fdba3c52223a1cf5a1c1fc282935400eaa06"
|
||||
integrity sha512-LuvLWFnxznTH++GytEzpzOPUo1SB+6CUFqIlVETJJ3x9fpyMCKFfyqberbhMLOpT1qcNe+km+zoyBeUSC3u5Rw==
|
||||
|
||||
emoji-mart@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-3.0.1.tgz#9ce86706e02aea0506345f98464814a662ca54c6"
|
||||
integrity sha512-sxpmMKxqLvcscu6mFn9ITHeZNkGzIvD0BSNFE/LJESPbCA8s1jM6bCDPjWbV31xHq7JXaxgpHxLB54RCbBZSlg==
|
||||
"emoji-mart@npm:emoji-mart-lazyload":
|
||||
version "3.0.1-j"
|
||||
resolved "https://registry.yarnpkg.com/emoji-mart-lazyload/-/emoji-mart-lazyload-3.0.1-j.tgz#87a90d30b79d9145ece078d53e3e683c1a10ce9c"
|
||||
integrity sha512-0wKF7MR0/iAeCIoiBLY+JjXCugycTgYRC2SL0y9/bjNSQlbeMdzILmPQJAufU/mgLFDUitOvjxLDhOZ9yxZ48g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0"
|
||||
intersection-observer "^0.12.0"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
|
@ -4951,10 +4952,10 @@ interpret@^2.2.0:
|
|||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
|
||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||
|
||||
intersection-observer@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.11.0.tgz#f4ea067070326f68393ee161cc0a2ca4c0040c6f"
|
||||
integrity sha512-KZArj2QVnmdud9zTpKf279m2bbGfG+4/kn16UU0NL3pTVl52ZHiJ9IRNSsnn6jaHrL9EGLFM5eWjTx2fz/+zoQ==
|
||||
intersection-observer@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.0.tgz#6c84628f67ce8698e5f9ccf857d97718745837aa"
|
||||
integrity sha512-2Vkz8z46Dv401zTWudDGwO7KiGHNDkMv417T5ItcNYfmvHR/1qCTVBO9vwH8zZmQ0WkA/1ARwpysR9bsnop4NQ==
|
||||
|
||||
intl-messageformat-parser@6.1.2:
|
||||
version "6.1.2"
|
||||
|
|
Ładowanie…
Reference in New Issue