mirror of
https://github.com/mastodon/mastodon.git
synced 2025-09-06 01:41:08 +00:00
Add quote notifications to WebUI (#35653)
Some checks failed
Check i18n / check-i18n (push) Waiting to run
Chromatic / Run Chromatic (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (ruby) (push) Waiting to run
Crowdin / Upload translations / upload-translations (push) Waiting to run
Check formatting / lint (push) Waiting to run
Haml Linting / lint (push) Waiting to run
JavaScript Linting / lint (push) Waiting to run
Ruby Linting / lint (push) Waiting to run
JavaScript Testing / test (push) Waiting to run
Historical data migration test / test (14-alpine) (push) Waiting to run
Historical data migration test / test (15-alpine) (push) Waiting to run
Historical data migration test / test (16-alpine) (push) Waiting to run
Historical data migration test / test (17-alpine) (push) Waiting to run
Ruby Testing / build (production) (push) Waiting to run
Ruby Testing / build (test) (push) Waiting to run
Ruby Testing / test (.ruby-version) (push) Blocked by required conditions
Ruby Testing / test (3.2) (push) Blocked by required conditions
Ruby Testing / test (3.3) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (.ruby-version) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.2) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.3) (push) Blocked by required conditions
Ruby Testing / End to End testing (.ruby-version) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.2) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.3) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.10.2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.2, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
CSS Linting / lint (push) Has been cancelled
Some checks failed
Check i18n / check-i18n (push) Waiting to run
Chromatic / Run Chromatic (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (ruby) (push) Waiting to run
Crowdin / Upload translations / upload-translations (push) Waiting to run
Check formatting / lint (push) Waiting to run
Haml Linting / lint (push) Waiting to run
JavaScript Linting / lint (push) Waiting to run
Ruby Linting / lint (push) Waiting to run
JavaScript Testing / test (push) Waiting to run
Historical data migration test / test (14-alpine) (push) Waiting to run
Historical data migration test / test (15-alpine) (push) Waiting to run
Historical data migration test / test (16-alpine) (push) Waiting to run
Historical data migration test / test (17-alpine) (push) Waiting to run
Ruby Testing / build (production) (push) Waiting to run
Ruby Testing / build (test) (push) Waiting to run
Ruby Testing / test (.ruby-version) (push) Blocked by required conditions
Ruby Testing / test (3.2) (push) Blocked by required conditions
Ruby Testing / test (3.3) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (.ruby-version) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.2) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.3) (push) Blocked by required conditions
Ruby Testing / End to End testing (.ruby-version) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.2) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.3) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.10.2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.2, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
CSS Linting / lint (push) Has been cancelled
This commit is contained in:
parent
570c9d16be
commit
081d38679f
|
@ -13,6 +13,7 @@ export const allNotificationTypes = [
|
||||||
'favourite',
|
'favourite',
|
||||||
'reblog',
|
'reblog',
|
||||||
'mention',
|
'mention',
|
||||||
|
'quote',
|
||||||
'poll',
|
'poll',
|
||||||
'status',
|
'status',
|
||||||
'update',
|
'update',
|
||||||
|
@ -28,6 +29,7 @@ export type NotificationWithStatusType =
|
||||||
| 'reblog'
|
| 'reblog'
|
||||||
| 'status'
|
| 'status'
|
||||||
| 'mention'
|
| 'mention'
|
||||||
|
| 'quote'
|
||||||
| 'poll'
|
| 'poll'
|
||||||
| 'update';
|
| 'update';
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,9 @@ import { Link, withRouter } from 'react-router-dom';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
|
|
||||||
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
||||||
import FlagIcon from '@/material-icons/400-24px/flag-fill.svg?react';
|
import FlagIcon from '@/material-icons/400-24px/flag-fill.svg?react';
|
||||||
|
import FormatQuoteIcon from '@/material-icons/400-24px/format_quote.svg?react';
|
||||||
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
||||||
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
|
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
|
||||||
import PersonIcon from '@/material-icons/400-24px/person-fill.svg?react';
|
import PersonIcon from '@/material-icons/400-24px/person-fill.svg?react';
|
||||||
|
@ -42,6 +42,7 @@ const messages = defineMessages({
|
||||||
adminReport: { id: 'notification.admin.report', defaultMessage: '{name} reported {target}' },
|
adminReport: { id: 'notification.admin.report', defaultMessage: '{name} reported {target}' },
|
||||||
relationshipsSevered: { id: 'notification.relationships_severance_event', defaultMessage: 'Lost connections with {name}' },
|
relationshipsSevered: { id: 'notification.relationships_severance_event', defaultMessage: 'Lost connections with {name}' },
|
||||||
moderationWarning: { id: 'notification.moderation_warning', defaultMessage: 'You have received a moderation warning' },
|
moderationWarning: { id: 'notification.moderation_warning', defaultMessage: 'You have received a moderation warning' },
|
||||||
|
quote: { id: 'notification.label.quote', defaultMessage: '{name} quoted your post'}
|
||||||
});
|
});
|
||||||
|
|
||||||
const notificationForScreenReader = (intl, message, timestamp) => {
|
const notificationForScreenReader = (intl, message, timestamp) => {
|
||||||
|
@ -251,6 +252,36 @@ class Notification extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderQuote (notification, link) {
|
||||||
|
const { intl, unread } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
|
<div className={classNames('notification notification-quote focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.quote, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
||||||
|
<div className='notification__message'>
|
||||||
|
<Icon id='quote' icon={FormatQuoteIcon} />
|
||||||
|
|
||||||
|
<span title={notification.get('created_at')}>
|
||||||
|
<FormattedMessage id='notification.label.quote' defaultMessage='{name} quoted your post' values={{ name: link }} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<StatusQuoteManager
|
||||||
|
id={notification.get('status')}
|
||||||
|
account={notification.get('account')}
|
||||||
|
muted
|
||||||
|
withDismiss
|
||||||
|
hidden={this.props.hidden}
|
||||||
|
getScrollPosition={this.props.getScrollPosition}
|
||||||
|
updateScrollBottom={this.props.updateScrollBottom}
|
||||||
|
cachedMediaWidth={this.props.cachedMediaWidth}
|
||||||
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Hotkeys>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
renderStatus (notification, link) {
|
renderStatus (notification, link) {
|
||||||
const { intl, unread, status } = this.props;
|
const { intl, unread, status } = this.props;
|
||||||
|
|
||||||
|
@ -467,6 +498,8 @@ class Notification extends ImmutablePureComponent {
|
||||||
return this.renderFollowRequest(notification, account, link);
|
return this.renderFollowRequest(notification, account, link);
|
||||||
case 'mention':
|
case 'mention':
|
||||||
return this.renderMention(notification);
|
return this.renderMention(notification);
|
||||||
|
case 'quote':
|
||||||
|
return this.renderQuote(notification);
|
||||||
case 'favourite':
|
case 'favourite':
|
||||||
return this.renderFavourite(notification, link);
|
return this.renderFavourite(notification, link);
|
||||||
case 'reblog':
|
case 'reblog':
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { NotificationFollowRequest } from './notification_follow_request';
|
||||||
import { NotificationMention } from './notification_mention';
|
import { NotificationMention } from './notification_mention';
|
||||||
import { NotificationModerationWarning } from './notification_moderation_warning';
|
import { NotificationModerationWarning } from './notification_moderation_warning';
|
||||||
import { NotificationPoll } from './notification_poll';
|
import { NotificationPoll } from './notification_poll';
|
||||||
|
import { NotificationQuote } from './notification_quote';
|
||||||
import { NotificationReblog } from './notification_reblog';
|
import { NotificationReblog } from './notification_reblog';
|
||||||
import { NotificationSeveredRelationships } from './notification_severed_relationships';
|
import { NotificationSeveredRelationships } from './notification_severed_relationships';
|
||||||
import { NotificationStatus } from './notification_status';
|
import { NotificationStatus } from './notification_status';
|
||||||
|
@ -91,6 +92,11 @@ export const NotificationGroup: React.FC<{
|
||||||
<NotificationMention unread={unread} notification={notificationGroup} />
|
<NotificationMention unread={unread} notification={notificationGroup} />
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'quote':
|
||||||
|
content = (
|
||||||
|
<NotificationQuote unread={unread} notification={notificationGroup} />
|
||||||
|
);
|
||||||
|
break;
|
||||||
case 'follow':
|
case 'follow':
|
||||||
content = (
|
content = (
|
||||||
<NotificationFollow unread={unread} notification={notificationGroup} />
|
<NotificationFollow unread={unread} notification={notificationGroup} />
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import FormatQuoteIcon from '@/material-icons/400-24px/format_quote.svg?react';
|
||||||
|
import type { NotificationGroupQuote } from 'mastodon/models/notification_group';
|
||||||
|
|
||||||
|
import type { LabelRenderer } from './notification_group_with_status';
|
||||||
|
import { NotificationWithStatus } from './notification_with_status';
|
||||||
|
|
||||||
|
const quoteLabelRenderer: LabelRenderer = (displayName) => (
|
||||||
|
<FormattedMessage
|
||||||
|
id='notification.label.quote'
|
||||||
|
defaultMessage='{name} quoted your post'
|
||||||
|
values={{ name: displayName }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const NotificationQuote: React.FC<{
|
||||||
|
notification: NotificationGroupQuote;
|
||||||
|
unread: boolean;
|
||||||
|
}> = ({ notification, unread }) => {
|
||||||
|
return (
|
||||||
|
<NotificationWithStatus
|
||||||
|
type='quote'
|
||||||
|
icon={FormatQuoteIcon}
|
||||||
|
iconId='quote'
|
||||||
|
accountIds={notification.sampleAccountIds}
|
||||||
|
count={notification.notifications_count}
|
||||||
|
statusId={notification.statusId}
|
||||||
|
labelRenderer={quoteLabelRenderer}
|
||||||
|
unread={unread}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
|
@ -600,6 +600,7 @@
|
||||||
"notification.label.mention": "Mention",
|
"notification.label.mention": "Mention",
|
||||||
"notification.label.private_mention": "Private mention",
|
"notification.label.private_mention": "Private mention",
|
||||||
"notification.label.private_reply": "Private reply",
|
"notification.label.private_reply": "Private reply",
|
||||||
|
"notification.label.quote": "{name} quoted your post",
|
||||||
"notification.label.reply": "Reply",
|
"notification.label.reply": "Reply",
|
||||||
"notification.mention": "Mention",
|
"notification.mention": "Mention",
|
||||||
"notification.mentioned_you": "{name} mentioned you",
|
"notification.mentioned_you": "{name} mentioned you",
|
||||||
|
|
|
@ -36,6 +36,7 @@ export type NotificationGroupFavourite =
|
||||||
export type NotificationGroupReblog = BaseNotificationWithStatus<'reblog'>;
|
export type NotificationGroupReblog = BaseNotificationWithStatus<'reblog'>;
|
||||||
export type NotificationGroupStatus = BaseNotificationWithStatus<'status'>;
|
export type NotificationGroupStatus = BaseNotificationWithStatus<'status'>;
|
||||||
export type NotificationGroupMention = BaseNotificationWithStatus<'mention'>;
|
export type NotificationGroupMention = BaseNotificationWithStatus<'mention'>;
|
||||||
|
export type NotificationGroupQuote = BaseNotificationWithStatus<'quote'>;
|
||||||
export type NotificationGroupPoll = BaseNotificationWithStatus<'poll'>;
|
export type NotificationGroupPoll = BaseNotificationWithStatus<'poll'>;
|
||||||
export type NotificationGroupUpdate = BaseNotificationWithStatus<'update'>;
|
export type NotificationGroupUpdate = BaseNotificationWithStatus<'update'>;
|
||||||
export type NotificationGroupFollow = BaseNotification<'follow'>;
|
export type NotificationGroupFollow = BaseNotification<'follow'>;
|
||||||
|
@ -87,6 +88,7 @@ export type NotificationGroup =
|
||||||
| NotificationGroupReblog
|
| NotificationGroupReblog
|
||||||
| NotificationGroupStatus
|
| NotificationGroupStatus
|
||||||
| NotificationGroupMention
|
| NotificationGroupMention
|
||||||
|
| NotificationGroupQuote
|
||||||
| NotificationGroupPoll
|
| NotificationGroupPoll
|
||||||
| NotificationGroupUpdate
|
| NotificationGroupUpdate
|
||||||
| NotificationGroupFollow
|
| NotificationGroupFollow
|
||||||
|
@ -137,6 +139,7 @@ export function createNotificationGroupFromJSON(
|
||||||
case 'reblog':
|
case 'reblog':
|
||||||
case 'status':
|
case 'status':
|
||||||
case 'mention':
|
case 'mention':
|
||||||
|
case 'quote':
|
||||||
case 'poll':
|
case 'poll':
|
||||||
case 'update': {
|
case 'update': {
|
||||||
const { status_id: statusId, ...groupWithoutStatus } = group;
|
const { status_id: statusId, ...groupWithoutStatus } = group;
|
||||||
|
@ -209,6 +212,7 @@ export function createNotificationGroupFromNotificationJSON(
|
||||||
case 'reblog':
|
case 'reblog':
|
||||||
case 'status':
|
case 'status':
|
||||||
case 'mention':
|
case 'mention':
|
||||||
|
case 'quote':
|
||||||
case 'poll':
|
case 'poll':
|
||||||
case 'update':
|
case 'update':
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m228-240 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T458-480L320-240h-92Zm360 0 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T818-480L680-240h-92Z"/></svg>
|
After Width: | Height: | Size: 322 B |
1
app/javascript/material-icons/400-24px/format_quote.svg
Normal file
1
app/javascript/material-icons/400-24px/format_quote.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m228-240 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T458-480L320-240h-92Zm360 0 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T818-480L680-240h-92ZM320-500q25 0 42.5-17.5T380-560q0-25-17.5-42.5T320-620q-25 0-42.5 17.5T260-560q0 25 17.5 42.5T320-500Zm360 0q25 0 42.5-17.5T740-560q0-25-17.5-42.5T680-620q-25 0-42.5 17.5T620-560q0 25 17.5 42.5T680-500Zm0-60Zm-360 0Z"/></svg>
|
After Width: | Height: | Size: 538 B |
Loading…
Reference in New Issue
Block a user