Merge remote-tracking branch 'parent/main' into kb-upstream-20231026
This commit is contained in:
commit
5448bcf276
313 changed files with 3717 additions and 4735 deletions
|
@ -9,6 +9,16 @@ import { withRouter } from 'react-router-dom';
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
|
||||
import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
|
||||
import { ReactComponent as EmojiReactionIcon } from '@material-symbols/svg-600/outlined/mood.svg';
|
||||
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
|
||||
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
|
||||
import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
|
||||
import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
|
||||
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
|
||||
import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
|
||||
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
|
@ -99,7 +109,7 @@ class ActionBar extends PureComponent {
|
|||
};
|
||||
|
||||
handleOpenMentions = () => {
|
||||
this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}/mentioned_users`);
|
||||
this.props.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}/mentioned_users`);
|
||||
};
|
||||
|
||||
handleReplyClick = () => {
|
||||
|
@ -326,10 +336,13 @@ class ActionBar extends PureComponent {
|
|||
}
|
||||
|
||||
let replyIcon;
|
||||
let replyIconComponent;
|
||||
if (status.get('in_reply_to_id', null) === null) {
|
||||
replyIcon = 'reply';
|
||||
replyIconComponent = ReplyIcon;
|
||||
} else {
|
||||
replyIcon = 'reply-all';
|
||||
replyIconComponent = ReplyAllIcon;
|
||||
}
|
||||
|
||||
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility_ex') === 'private';
|
||||
|
@ -352,7 +365,7 @@ class ActionBar extends PureComponent {
|
|||
const outside = emojiReactionPolicy !== 'outside_only' || (relationship && (relationship.get('following') || relationship.get('followed_by')));
|
||||
const denyFromAll = emojiReactionPolicy !== 'block' && emojiReactionPolicy !== 'block';
|
||||
const emojiPickerButton = (
|
||||
<IconButton icon='smile-o' onClick={this.handleEmojiPickInnerButton} title={intl.formatMessage(messages.pickEmoji)} />
|
||||
<IconButton icon='smile-o' iconComponent={EmojiReactionIcon} onClick={this.handleEmojiPickInnerButton} title={intl.formatMessage(messages.pickEmoji)} />
|
||||
);
|
||||
const emojiPickerDropdown = enableEmojiReaction && denyFromAll && (writtenByMe || (following && followed && mutual && outside)) && (
|
||||
<div className='detailed-status__button'><EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={emojiPickerButton} /></div>
|
||||
|
@ -360,14 +373,14 @@ class ActionBar extends PureComponent {
|
|||
|
||||
return (
|
||||
<div className='detailed-status__action-bar'>
|
||||
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /></div>
|
||||
{emojiPickerDropdown}
|
||||
|
||||
<div className='detailed-status__action-bar-dropdown'>
|
||||
<DropdownMenuContainer size={18} icon='ellipsis-h' status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} />
|
||||
<DropdownMenuContainer icon='ellipsis-h' iconComponent={MoreHorizIcon} status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -10,6 +10,10 @@ import classNames from 'classnames';
|
|||
import Immutable from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import { ReactComponent as DescriptionIcon } from '@material-symbols/svg-600/outlined/description.svg';
|
||||
import { ReactComponent as OpenInNewIcon } from '@material-symbols/svg-600/outlined/open_in_new.svg';
|
||||
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow.svg';
|
||||
|
||||
import { Blurhash } from 'mastodon/components/blurhash';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
||||
|
@ -197,8 +201,8 @@ export default class Card extends PureComponent {
|
|||
{revealed ? (
|
||||
<div className='status-card__actions' onClick={this.handleEmbedClick} role='none'>
|
||||
<div>
|
||||
<button type='button' onClick={this.handleEmbedClick}><Icon id='play' /></button>
|
||||
<a href={card.get('url')} target='_blank' rel='noopener noreferrer'><Icon id='external-link' /></a>
|
||||
<button type='button' onClick={this.handleEmbedClick}><Icon id='play' icon={PlayArrowIcon} /></button>
|
||||
<a href={card.get('url')} target='_blank' rel='noopener noreferrer'><Icon id='external-link' icon={OpenInNewIcon} /></a>
|
||||
</div>
|
||||
</div>
|
||||
) : spoilerButton}
|
||||
|
@ -222,7 +226,7 @@ export default class Card extends PureComponent {
|
|||
} else {
|
||||
embed = (
|
||||
<div className='status-card__image'>
|
||||
<Icon id='file-text' />
|
||||
<Icon id='file-text' icon={DescriptionIcon} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
import { injectIntl, defineMessages, FormattedDate, FormattedMessage } from 'react-intl';
|
||||
import { FormattedDate, FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Link, withRouter } from 'react-router-dom';
|
||||
|
@ -8,11 +8,19 @@ import { Link, withRouter } from 'react-router-dom';
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
|
||||
import { ReactComponent as ReferenceIcon } from '@material-symbols/svg-600/outlined/link.svg';
|
||||
import { ReactComponent as EmojiReactionIcon } from '@material-symbols/svg-600/outlined/mood.svg';
|
||||
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
|
||||
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
|
||||
|
||||
import { AnimatedNumber } from 'mastodon/components/animated_number';
|
||||
import EditedTimestamp from 'mastodon/components/edited_timestamp';
|
||||
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
|
||||
import { SearchabilityIcon } from 'mastodon/components/searchability_icon';
|
||||
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
|
||||
import { enableEmojiReaction } from 'mastodon/initial_state';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
|
@ -27,24 +35,6 @@ import Video from '../../video';
|
|||
|
||||
import Card from './card';
|
||||
|
||||
const messages = defineMessages({
|
||||
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
|
||||
public_unlisted_short: { id: 'privacy.public_unlisted.short', defaultMessage: 'Public unlisted' },
|
||||
login_short: { id: 'privacy.login.short', defaultMessage: 'Login only' },
|
||||
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
|
||||
limited_short: { id: 'privacy.limited.short', defaultMessage: 'Limited menbers only' },
|
||||
mutual_short: { id: 'privacy.mutual.short', defaultMessage: 'Mutual followers only' },
|
||||
circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle members only' },
|
||||
personal_short: { id: 'privacy.personal.short', defaultMessage: 'Yourself only' },
|
||||
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
|
||||
searchability_public_short: { id: 'searchability.public.short', defaultMessage: 'Public' },
|
||||
searchability_public_unlisted_short: { id: 'searchability.public_unlisted.short', defaultMessage: 'Public unlisted' },
|
||||
searchability_private_short: { id: 'searchability.unlisted.short', defaultMessage: 'Followers' },
|
||||
searchability_direct_short: { id: 'searchability.private.short', defaultMessage: 'Reactionners' },
|
||||
searchability_limited_short: { id: 'searchability.direct.short', defaultMessage: 'Self only' },
|
||||
});
|
||||
|
||||
class DetailedStatus extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
@ -152,7 +142,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
render () {
|
||||
const status = this._properStatus();
|
||||
const outerStyle = { boxSizing: 'border-box' };
|
||||
const { intl, compact, pictureInPicture } = this.props;
|
||||
const { compact, pictureInPicture } = this.props;
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
|
@ -162,7 +152,8 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
let isCardMediaWithSensitive = false;
|
||||
let applicationLink = '';
|
||||
let reblogLink = '';
|
||||
let reblogIcon = 'retweet';
|
||||
const reblogIcon = 'retweet';
|
||||
const reblogIconComponent = RepeatIcon;
|
||||
let favouriteLink = '';
|
||||
let emojiReactionsLink = '';
|
||||
let statusReferencesLink = '';
|
||||
|
@ -251,32 +242,8 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
applicationLink = <> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></>;
|
||||
}
|
||||
|
||||
const visibilityIconInfo = {
|
||||
'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
|
||||
'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
|
||||
'public_unlisted': { icon: 'cloud', text: intl.formatMessage(messages.public_unlisted_short) },
|
||||
'login': { icon: 'key', text: intl.formatMessage(messages.login_short) },
|
||||
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
|
||||
'limited': { icon: 'get-pocket', text: intl.formatMessage(messages.limited_short) },
|
||||
'mutual': { icon: 'exchange', text: intl.formatMessage(messages.mutual_short) },
|
||||
'circle': { icon: 'user-circle', text: intl.formatMessage(messages.circle_short) },
|
||||
'personal': { icon: 'sticky-note-o', text: intl.formatMessage(messages.personal_short) },
|
||||
'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
|
||||
};
|
||||
|
||||
const visibilityIcon = visibilityIconInfo[status.get('limited_scope') || status.get('visibility_ex')];
|
||||
const visibilityLink = <> · <Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></>;
|
||||
|
||||
const searchabilityIconInfo = {
|
||||
'public': { icon: 'globe', text: intl.formatMessage(messages.searchability_public_short) },
|
||||
'public_unlisted': { icon: 'cloud', text: intl.formatMessage(messages.searchability_public_unlisted_short) },
|
||||
'private': { icon: 'unlock', text: intl.formatMessage(messages.searchability_private_short) },
|
||||
'direct': { icon: 'lock', text: intl.formatMessage(messages.searchability_direct_short) },
|
||||
'limited': { icon: 'at', text: intl.formatMessage(messages.searchability_limited_short) },
|
||||
};
|
||||
|
||||
const searchabilityIcon = searchabilityIconInfo[status.get('searchability')];
|
||||
const searchabilityLink = <> · <Icon id={searchabilityIcon.icon} title={searchabilityIcon.text} /></>;
|
||||
const visibilityLink = <> · <VisibilityIcon visibility={status.get('limited_scope') || status.get('visibility_ex')} /></>;
|
||||
const searchabilityLink = <> · <SearchabilityIcon searchability={status.get('searchability')} /></>;
|
||||
|
||||
if (['private', 'direct'].includes(status.get('visibility_ex'))) {
|
||||
reblogLink = '';
|
||||
|
@ -285,7 +252,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
<>
|
||||
{' · '}
|
||||
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`} className='detailed-status__link'>
|
||||
<Icon id={reblogIcon} />
|
||||
<Icon id={reblogIcon} icon={reblogIconComponent} />
|
||||
<span className='detailed-status__reblogs'>
|
||||
<AnimatedNumber value={status.get('reblogs_count')} />
|
||||
</span>
|
||||
|
@ -297,7 +264,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
<>
|
||||
{' · '}
|
||||
<a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
|
||||
<Icon id={reblogIcon} />
|
||||
<Icon id={reblogIcon} icon={reblogIconComponent} />
|
||||
<span className='detailed-status__reblogs'>
|
||||
<AnimatedNumber value={status.get('reblogs_count')} />
|
||||
</span>
|
||||
|
@ -309,7 +276,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
if (this.props.history) {
|
||||
favouriteLink = (
|
||||
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/favourites`} className='detailed-status__link'>
|
||||
<Icon id='star' />
|
||||
<Icon id='star' icon={StarIcon} />
|
||||
<span className='detailed-status__favorites'>
|
||||
<AnimatedNumber value={status.get('favourites_count')} />
|
||||
</span>
|
||||
|
@ -318,7 +285,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
} else {
|
||||
favouriteLink = (
|
||||
<a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
|
||||
<Icon id='star' />
|
||||
<Icon id='star' icon={StarIcon} />
|
||||
<span className='detailed-status__favorites'>
|
||||
<AnimatedNumber value={status.get('favourites_count')} />
|
||||
</span>
|
||||
|
@ -329,7 +296,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
if (this.context.router) {
|
||||
emojiReactionsLink = (
|
||||
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/emoji_reactions`} className='detailed-status__link'>
|
||||
<Icon id='smile-o' />
|
||||
<Icon id='smile-o' icon={EmojiReactionIcon} />
|
||||
<span className='detailed-status__favorites'>
|
||||
<AnimatedNumber value={status.get('emoji_reactions_count')} />
|
||||
</span>
|
||||
|
@ -338,7 +305,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
} else {
|
||||
emojiReactionsLink = (
|
||||
<a href={`/interact/${status.get('id')}?type=emoji_reactions`} className='detailed-status__link' onClick={this.handleModalLink}>
|
||||
<Icon id='smile-o' />
|
||||
<Icon id='smile-o' icon={EmojiReactionIcon} />
|
||||
<span className='detailed-status__favorites'>
|
||||
<AnimatedNumber value={status.get('emoji_reactions_count')} />
|
||||
</span>
|
||||
|
@ -349,7 +316,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
if (this.context.router) {
|
||||
statusReferencesLink = (
|
||||
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/references`} className='detailed-status__link'>
|
||||
<Icon id='link' />
|
||||
<Icon id='link' icon={ReferenceIcon} />
|
||||
<span className='detailed-status__favorites'>
|
||||
<AnimatedNumber value={status.get('status_referred_by_count')} />
|
||||
</span>
|
||||
|
@ -358,7 +325,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
} else {
|
||||
statusReferencesLink = (
|
||||
<a href={`/interact/${status.get('id')}?type=references`} className='detailed-status__link' onClick={this.handleModalLink}>
|
||||
<Icon id='link' />
|
||||
<Icon id='link' icon={ReferenceIcon} />
|
||||
<span className='detailed-status__favorites'>
|
||||
<AnimatedNumber value={status.get('status_referred_by_count')} />
|
||||
</span>
|
||||
|
@ -383,7 +350,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
<div ref={this.setRef} className={classNames('detailed-status', { compact })}>
|
||||
{status.get('visibility_ex') === 'direct' && (
|
||||
<div className='status__prepend'>
|
||||
<div className='status__prepend-icon-wrapper'><Icon id='at' className='status__prepend-icon' fixedWidth /></div>
|
||||
<div className='status__prepend-icon-wrapper'><Icon id='at' icon={AlternateEmailIcon} className='status__prepend-icon' /></div>
|
||||
<FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
|
||||
</div>
|
||||
)}
|
||||
|
@ -418,4 +385,4 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default withRouter(injectIntl(DetailedStatus));
|
||||
export default withRouter(DetailedStatus);
|
||||
|
|
|
@ -12,6 +12,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
|||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg';
|
||||
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
|
||||
import { HotKeys } from 'react-hotkeys';
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
@ -748,7 +750,7 @@ class Status extends ImmutablePureComponent {
|
|||
showBackButton
|
||||
multiColumn={multiColumn}
|
||||
extraButton={(
|
||||
<button type='button' className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button>
|
||||
<button type='button' className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} icon={status.get('hidden') ? VisibilityOffIcon : VisibilityIcon} /></button>
|
||||
)}
|
||||
/>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue