mirror of
https://github.com/mastodon/mastodon.git
synced 2024-08-20 21:08:15 -07:00
Compare commits
6 commits
34e5932a22
...
6b85895fdf
Author | SHA1 | Date | |
---|---|---|---|
|
6b85895fdf | ||
|
a50c8e951f | ||
|
2c1e75727d | ||
|
9511daab05 | ||
|
770ad56494 | ||
|
22a78e24ca |
7 changed files with 51 additions and 50 deletions
|
@ -60,7 +60,7 @@ export interface BaseNotificationGroupJSON {
|
||||||
|
|
||||||
interface NotificationGroupWithStatusJSON extends BaseNotificationGroupJSON {
|
interface NotificationGroupWithStatusJSON extends BaseNotificationGroupJSON {
|
||||||
type: NotificationWithStatusType;
|
type: NotificationWithStatusType;
|
||||||
status: ApiStatusJSON;
|
status_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NotificationWithStatusJSON extends BaseNotificationJSON {
|
interface NotificationWithStatusJSON extends BaseNotificationJSON {
|
||||||
|
|
|
@ -49,22 +49,15 @@ export const FilteredNotificationsBanner: React.FC = () => {
|
||||||
<span>
|
<span>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='filtered_notifications_banner.pending_requests'
|
id='filtered_notifications_banner.pending_requests'
|
||||||
defaultMessage='Notifications from {count, plural, =0 {no one} one {one person} other {# people}} you may know'
|
defaultMessage='From {count, plural, =0 {no one} one {one person} other {# people}} you may know'
|
||||||
values={{ count: policy.summary.pending_requests_count }}
|
values={{ count: policy.summary.pending_requests_count }}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='filtered-notifications-banner__badge'>
|
<div className='filtered-notifications-banner__badge'>
|
||||||
<div className='filtered-notifications-banner__badge__badge'>
|
|
||||||
{toCappedNumber(policy.summary.pending_notifications_count)}
|
{toCappedNumber(policy.summary.pending_notifications_count)}
|
||||||
</div>
|
</div>
|
||||||
<FormattedMessage
|
|
||||||
id='filtered_notifications_banner.mentions'
|
|
||||||
defaultMessage='{count, plural, one {mention} other {mentions}}'
|
|
||||||
values={{ count: policy.summary.pending_notifications_count }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,11 +14,12 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import DescriptionIcon from '@/material-icons/400-24px/description-fill.svg?react';
|
import DescriptionIcon from '@/material-icons/400-24px/description-fill.svg?react';
|
||||||
import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react';
|
import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react';
|
||||||
import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react';
|
import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react';
|
||||||
|
import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react';
|
||||||
import { Blurhash } from 'mastodon/components/blurhash';
|
import { Blurhash } from 'mastodon/components/blurhash';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { MoreFromAuthor } from 'mastodon/components/more_from_author';
|
import { MoreFromAuthor } from 'mastodon/components/more_from_author';
|
||||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
||||||
import { useBlurhash } from 'mastodon/initial_state';
|
import { displayMedia, useBlurhash } from 'mastodon/initial_state';
|
||||||
|
|
||||||
const IDNA_PREFIX = 'xn--';
|
const IDNA_PREFIX = 'xn--';
|
||||||
|
|
||||||
|
@ -64,12 +65,14 @@ export default class Card extends PureComponent {
|
||||||
card: ImmutablePropTypes.map,
|
card: ImmutablePropTypes.map,
|
||||||
onOpenMedia: PropTypes.func.isRequired,
|
onOpenMedia: PropTypes.func.isRequired,
|
||||||
sensitive: PropTypes.bool,
|
sensitive: PropTypes.bool,
|
||||||
|
visible: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
previewLoaded: false,
|
previewLoaded: false,
|
||||||
embedded: false,
|
embedded: false,
|
||||||
revealed: !this.props.sensitive,
|
revealed: !this.props.sensitive,
|
||||||
|
visible: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
|
||||||
};
|
};
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps (nextProps) {
|
UNSAFE_componentWillReceiveProps (nextProps) {
|
||||||
|
@ -80,6 +83,12 @@ export default class Card extends PureComponent {
|
||||||
if (this.props.sensitive !== nextProps.sensitive) {
|
if (this.props.sensitive !== nextProps.sensitive) {
|
||||||
this.setState({ revealed: !nextProps.sensitive });
|
this.setState({ revealed: !nextProps.sensitive });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nextProps.visible === undefined) {
|
||||||
|
this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' });
|
||||||
|
} else if (!Immutable.is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
|
||||||
|
this.setState({ visible: nextProps.visible });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
|
@ -112,6 +121,12 @@ export default class Card extends PureComponent {
|
||||||
this.setState({ revealed: true });
|
this.setState({ revealed: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleOpen = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this.setState({ visible: !this.state.visible });
|
||||||
|
};
|
||||||
|
|
||||||
renderVideo () {
|
renderVideo () {
|
||||||
const { card } = this.props;
|
const { card } = this.props;
|
||||||
const content = { __html: addAutoPlay(card.get('html')) };
|
const content = { __html: addAutoPlay(card.get('html')) };
|
||||||
|
@ -128,7 +143,7 @@ export default class Card extends PureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { card } = this.props;
|
const { card } = this.props;
|
||||||
const { embedded, revealed } = this.state;
|
const { embedded, revealed, visible } = this.state;
|
||||||
|
|
||||||
if (card === null) {
|
if (card === null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -165,14 +180,14 @@ export default class Card extends PureComponent {
|
||||||
thumbnailStyle.aspectRatio = 1;
|
thumbnailStyle.aspectRatio = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let embed;
|
let embed, spoilerButton;
|
||||||
|
|
||||||
let canvas = (
|
let canvas = (
|
||||||
<Blurhash
|
<Blurhash
|
||||||
className={classNames('status-card__image-preview', {
|
|
||||||
'status-card__image-preview--hidden': revealed && this.state.previewLoaded,
|
|
||||||
})}
|
|
||||||
hash={card.get('blurhash')}
|
hash={card.get('blurhash')}
|
||||||
|
className={classNames('status-card__image-preview', {
|
||||||
|
'status-card__image-preview--hidden': visible && this.state.previewLoaded,
|
||||||
|
})}
|
||||||
dummy={!useBlurhash}
|
dummy={!useBlurhash}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -180,17 +195,24 @@ export default class Card extends PureComponent {
|
||||||
const thumbnailDescription = card.get('image_description');
|
const thumbnailDescription = card.get('image_description');
|
||||||
const thumbnail = <img src={card.get('image')} alt={thumbnailDescription} title={thumbnailDescription} lang={language} style={thumbnailStyle} onLoad={this.handleImageLoad} className='status-card__image-image' />;
|
const thumbnail = <img src={card.get('image')} alt={thumbnailDescription} title={thumbnailDescription} lang={language} style={thumbnailStyle} onLoad={this.handleImageLoad} className='status-card__image-image' />;
|
||||||
|
|
||||||
let spoilerButton = (
|
if (visible) {
|
||||||
<button type='button' onClick={this.handleReveal} className='spoiler-button__overlay'>
|
spoilerButton = (
|
||||||
|
<button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>
|
||||||
|
<Icon id='eye-slash' icon={VisibilityOffIcon} />
|
||||||
|
</button>);
|
||||||
|
} else {
|
||||||
|
spoilerButton = (
|
||||||
|
<button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>
|
||||||
<span className='spoiler-button__overlay__label'>
|
<span className='spoiler-button__overlay__label'>
|
||||||
<FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />
|
{revealed ? <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' /> : <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />}
|
||||||
<span className='spoiler-button__overlay__action'><FormattedMessage id='status.media.show' defaultMessage='Click to show' /></span>
|
<span className='spoiler-button__overlay__action'><FormattedMessage id='status.media.show' defaultMessage='Click to show' /></span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
spoilerButton = (
|
spoilerButton = (
|
||||||
<div className={classNames('spoiler-button', { 'spoiler-button--minified': revealed })}>
|
<div className={classNames('spoiler-button', { 'spoiler-button--minified': visible })}>
|
||||||
{spoilerButton}
|
{spoilerButton}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -204,11 +226,12 @@ export default class Card extends PureComponent {
|
||||||
{canvas}
|
{canvas}
|
||||||
{thumbnail}
|
{thumbnail}
|
||||||
|
|
||||||
{revealed ? (
|
{visible ? (
|
||||||
<div className='status-card__actions' onClick={this.handleEmbedClick} role='none'>
|
<div className='status-card__actions' onClick={this.handleEmbedClick} role='none'>
|
||||||
<div>
|
<div>
|
||||||
<button type='button' onClick={this.handleEmbedClick}><Icon id='play' icon={PlayArrowIcon} /></button>
|
<button type='button' onClick={this.handleEmbedClick}><Icon id='play' icon={PlayArrowIcon} /></button>
|
||||||
<a href={card.get('url')} onClick={this.handleExternalLinkClick} target='_blank' rel='noopener noreferrer'><Icon id='external-link' icon={OpenInNewIcon} /></a>
|
<a href={card.get('url')} onClick={this.handleExternalLinkClick} target='_blank' rel='noopener noreferrer'><Icon id='external-link' icon={OpenInNewIcon} /></a>
|
||||||
|
<button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'><Icon id='eye-slash' icon={VisibilityOffIcon} /></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : spoilerButton}
|
) : spoilerButton}
|
||||||
|
@ -226,6 +249,7 @@ export default class Card extends PureComponent {
|
||||||
embed = (
|
embed = (
|
||||||
<div className='status-card__image'>
|
<div className='status-card__image'>
|
||||||
{canvas}
|
{canvas}
|
||||||
|
{spoilerButton}
|
||||||
{thumbnail}
|
{thumbnail}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -209,7 +209,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (status.get('spoiler_text').length === 0) {
|
} else if (status.get('spoiler_text').length === 0) {
|
||||||
media = <Card sensitive={status.get('sensitive')} onOpenMedia={this.props.onOpenMedia} card={status.get('card', null)} />;
|
media = <Card visible={this.props.showMedia} sensitive={status.get('sensitive')} onOpenMedia={this.props.onOpenMedia} card={status.get('card', null)} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.get('application')) {
|
if (status.get('application')) {
|
||||||
|
|
|
@ -300,8 +300,7 @@
|
||||||
"filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
|
"filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
|
||||||
"filter_modal.select_filter.title": "Filter this post",
|
"filter_modal.select_filter.title": "Filter this post",
|
||||||
"filter_modal.title.status": "Filter a post",
|
"filter_modal.title.status": "Filter a post",
|
||||||
"filtered_notifications_banner.mentions": "{count, plural, one {mention} other {mentions}}",
|
"filtered_notifications_banner.pending_requests": "From {count, plural, =0 {no one} one {one person} other {# people}} you may know",
|
||||||
"filtered_notifications_banner.pending_requests": "Notifications from {count, plural, =0 {no one} one {one person} other {# people}} you may know",
|
|
||||||
"filtered_notifications_banner.title": "Filtered notifications",
|
"filtered_notifications_banner.title": "Filtered notifications",
|
||||||
"firehose.all": "All",
|
"firehose.all": "All",
|
||||||
"firehose.local": "This server",
|
"firehose.local": "This server",
|
||||||
|
|
|
@ -124,9 +124,9 @@ export function createNotificationGroupFromJSON(
|
||||||
case 'mention':
|
case 'mention':
|
||||||
case 'poll':
|
case 'poll':
|
||||||
case 'update': {
|
case 'update': {
|
||||||
const { status, ...groupWithoutStatus } = group;
|
const { status_id: statusId, ...groupWithoutStatus } = group;
|
||||||
return {
|
return {
|
||||||
statusId: status.id,
|
statusId,
|
||||||
sampleAccountIds,
|
sampleAccountIds,
|
||||||
...groupWithoutStatus,
|
...groupWithoutStatus,
|
||||||
};
|
};
|
||||||
|
|
|
@ -10170,27 +10170,12 @@ noscript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__badge {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 999px;
|
|
||||||
background: var(--background-border-color);
|
|
||||||
color: $darker-text-color;
|
|
||||||
padding: 4px;
|
|
||||||
padding-inline-end: 8px;
|
|
||||||
gap: 6px;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 11px;
|
|
||||||
line-height: 16px;
|
|
||||||
word-break: keep-all;
|
|
||||||
|
|
||||||
&__badge {
|
&__badge {
|
||||||
background: $ui-button-background-color;
|
background: $ui-button-background-color;
|
||||||
color: $white;
|
color: $white;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-request {
|
.notification-request {
|
||||||
|
|
Loading…
Reference in a new issue