mirror of
https://github.com/mastodon/mastodon.git
synced 2025-05-11 20:21:10 +00:00
Add rendering of quote posts in web UI
This commit is contained in:
parent
dee744c793
commit
6472f78690
|
@ -70,6 +70,10 @@ export function importFetchedStatuses(statuses) {
|
||||||
processStatus(status.reblog);
|
processStatus(status.reblog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status.quote?.quoted_status) {
|
||||||
|
processStatus(status.quote.quoted_status);
|
||||||
|
}
|
||||||
|
|
||||||
if (status.poll?.id) {
|
if (status.poll?.id) {
|
||||||
pushUnique(polls, createPollFromServerJSON(status.poll, getState().polls[status.poll.id]));
|
pushUnique(polls, createPollFromServerJSON(status.poll, getState().polls[status.poll.id]));
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,17 @@ export function normalizeFilterResult(result) {
|
||||||
|
|
||||||
export function normalizeStatus(status, normalOldStatus) {
|
export function normalizeStatus(status, normalOldStatus) {
|
||||||
const normalStatus = { ...status };
|
const normalStatus = { ...status };
|
||||||
|
|
||||||
normalStatus.account = status.account.id;
|
normalStatus.account = status.account.id;
|
||||||
|
|
||||||
if (status.reblog && status.reblog.id) {
|
if (status.reblog && status.reblog.id) {
|
||||||
normalStatus.reblog = status.reblog.id;
|
normalStatus.reblog = status.reblog.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status.quote?.quoted_status) {
|
||||||
|
normalStatus.quote = { ...status.quote, quoted_status: status.quote.quoted_status.id };
|
||||||
|
}
|
||||||
|
|
||||||
if (status.poll && status.poll.id) {
|
if (status.poll && status.poll.id) {
|
||||||
normalStatus.poll = status.poll.id;
|
normalStatus.poll = status.poll.id;
|
||||||
}
|
}
|
||||||
|
|
73
app/javascript/mastodon/components/quote.tsx
Normal file
73
app/javascript/mastodon/components/quote.tsx
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
|
import { useAppSelector } from 'mastodon/store';
|
||||||
|
import { EmbeddedStatus } from 'mastodon/features/notifications_v2/components/embedded_status';
|
||||||
|
|
||||||
|
type QuoteMap = ImmutableMap<'state' | 'quoted_status', string | null>;
|
||||||
|
|
||||||
|
export const Quote: React.FC<{ quote: QuoteMap }> = ({ quote }) => {
|
||||||
|
const quotedStatusId = quote.get('quoted_status');
|
||||||
|
const state = quote.get('state');
|
||||||
|
const status = useAppSelector((state) =>
|
||||||
|
quotedStatusId ? state.statuses.get(quotedStatusId) : undefined,
|
||||||
|
);
|
||||||
|
const accountId = status?.get('account') as string | undefined;
|
||||||
|
const account = useAppSelector((state) =>
|
||||||
|
accountId ? state.accounts.get(accountId) : undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!status || !quotedStatusId) {
|
||||||
|
return (
|
||||||
|
<div className='status__quote'>
|
||||||
|
<FormattedMessage
|
||||||
|
id=''
|
||||||
|
defaultMessage='This post cannot be displayed.'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (state === 'deleted') {
|
||||||
|
return (
|
||||||
|
<div className='status__quote'>
|
||||||
|
<FormattedMessage
|
||||||
|
id=''
|
||||||
|
defaultMessage='This post was removed by its author.'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (state === 'unauthorized') {
|
||||||
|
return (
|
||||||
|
<div className='status__quote'>
|
||||||
|
<FormattedMessage
|
||||||
|
id=''
|
||||||
|
defaultMessage='This post cannot be displayed as you are not authorized to view it.'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (state === 'pending') {
|
||||||
|
return (
|
||||||
|
<div className='status__quote'>
|
||||||
|
<FormattedMessage
|
||||||
|
id=''
|
||||||
|
defaultMessage='This post is pending approval from the original author.'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (state === 'rejected' || state === 'revoked') {
|
||||||
|
return (
|
||||||
|
<div className='status__quote'>
|
||||||
|
<FormattedMessage
|
||||||
|
id=''
|
||||||
|
defaultMessage='This post cannot be displayed as the original author does not allow it to be quoted.'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='status__quote'>
|
||||||
|
<EmbeddedStatus statusId={quotedStatusId} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -37,6 +37,7 @@ import StatusActionBar from './status_action_bar';
|
||||||
import StatusContent from './status_content';
|
import StatusContent from './status_content';
|
||||||
import { StatusThreadLabel } from './status_thread_label';
|
import { StatusThreadLabel } from './status_thread_label';
|
||||||
import { VisibilityIcon } from './visibility_icon';
|
import { VisibilityIcon } from './visibility_icon';
|
||||||
|
import { Quote } from './quote';
|
||||||
|
|
||||||
const domParser = new DOMParser();
|
const domParser = new DOMParser();
|
||||||
|
|
||||||
|
@ -578,6 +579,8 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
{expanded && (
|
{expanded && (
|
||||||
<>
|
<>
|
||||||
|
{status.get('quote') && <Quote quote={status.get('quote')} />}
|
||||||
|
|
||||||
<StatusContent
|
<StatusContent
|
||||||
status={status}
|
status={status}
|
||||||
onClick={this.handleClick}
|
onClick={this.handleClick}
|
||||||
|
|
|
@ -24,13 +24,13 @@ import { IconLogo } from 'mastodon/components/logo';
|
||||||
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
|
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
|
||||||
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
|
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
|
||||||
import { Video } from 'mastodon/features/video';
|
import { Video } from 'mastodon/features/video';
|
||||||
|
import { Avatar } from 'mastodon/components/avatar';
|
||||||
import { Avatar } from '../../../components/avatar';
|
import { DisplayName } from 'mastodon/components/display_name';
|
||||||
import { DisplayName } from '../../../components/display_name';
|
import MediaGallery from 'mastodon/components/media_gallery';
|
||||||
import MediaGallery from '../../../components/media_gallery';
|
import StatusContent from 'mastodon/components/status_content';
|
||||||
import StatusContent from '../../../components/status_content';
|
import Audio from 'mastodon/features/audio';
|
||||||
import Audio from '../../audio';
|
import scheduleIdleTask from 'mastodon/features/ui/util/schedule_idle_task';
|
||||||
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
|
import { Quote } from 'mastodon/components/quote';
|
||||||
|
|
||||||
import Card from './card';
|
import Card from './card';
|
||||||
|
|
||||||
|
@ -367,6 +367,8 @@ export const DetailedStatus: React.FC<{
|
||||||
|
|
||||||
{expanded && (
|
{expanded && (
|
||||||
<>
|
<>
|
||||||
|
{status.get('quote') && <Quote quote={status.get('quote')} />}
|
||||||
|
|
||||||
<StatusContent
|
<StatusContent
|
||||||
status={status}
|
status={status}
|
||||||
onTranslate={handleTranslate}
|
onTranslate={handleTranslate}
|
||||||
|
|
|
@ -1491,34 +1491,34 @@ body > [data-popper-placement] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$thread-margin: 46px + 8px;
|
||||||
|
|
||||||
&--in-thread {
|
&--in-thread {
|
||||||
$thread-margin: 46px + 10px;
|
|
||||||
|
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.status__content,
|
.status__content,
|
||||||
.status__action-bar,
|
.status__action-bar,
|
||||||
.media-gallery,
|
.media-gallery,
|
||||||
.video-player,
|
.video-player,
|
||||||
.audio-player,
|
.audio-player,
|
||||||
.attachment-list,
|
.attachment-list,
|
||||||
.picture-in-picture-placeholder,
|
.picture-in-picture-placeholder,
|
||||||
.more-from-author,
|
.more-from-author,
|
||||||
.status-card,
|
.status-card,
|
||||||
.hashtag-bar,
|
.hashtag-bar,
|
||||||
.content-warning,
|
.content-warning,
|
||||||
.filter-warning {
|
.filter-warning {
|
||||||
margin-inline-start: $thread-margin;
|
margin-inline-start: $thread-margin;
|
||||||
width: calc(100% - $thread-margin);
|
width: calc(100% - $thread-margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
.more-from-author {
|
.more-from-author {
|
||||||
width: calc(100% - $thread-margin + 2px);
|
width: calc(100% - $thread-margin + 2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status__content__read-more-button {
|
.status__content__read-more-button {
|
||||||
margin-inline-start: $thread-margin;
|
margin-inline-start: $thread-margin;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__action-bar__button-wrapper {
|
&__action-bar__button-wrapper {
|
||||||
|
@ -1571,8 +1571,6 @@ body > [data-popper-placement] {
|
||||||
|
|
||||||
.status__relative-time {
|
.status__relative-time {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 15px;
|
|
||||||
line-height: 22px;
|
|
||||||
height: 40px;
|
height: 40px;
|
||||||
order: 2;
|
order: 2;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
@ -1603,10 +1601,8 @@ body > [data-popper-placement] {
|
||||||
.status__info .status__display-name {
|
.status__info .status__display-name {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 15px;
|
|
||||||
line-height: 22px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.display-name {
|
.display-name {
|
||||||
|
@ -1630,7 +1626,7 @@ body > [data-popper-placement] {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 10px;
|
gap: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1674,7 +1670,7 @@ body > [data-popper-placement] {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 12px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
@ -1685,6 +1681,7 @@ body > [data-popper-placement] {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
margin-inline-start: 30px;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
|
@ -10402,6 +10399,7 @@ noscript {
|
||||||
|
|
||||||
.account__avatar {
|
.account__avatar {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
--avatar-border-radius: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10835,3 +10833,43 @@ noscript {
|
||||||
.lists-scrollable {
|
.lists-scrollable {
|
||||||
min-height: 50vh;
|
min-height: 50vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status__quote {
|
||||||
|
padding-inline-start: 46px + 8px;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
background: var(--rich-text-container-color);
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--rich-text-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-group__embedded-status__account bdi,
|
||||||
|
.notification-group__embedded-status__content,
|
||||||
|
.notification-group__embedded-status__content a {
|
||||||
|
color: var(--rich-text-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-group__embedded-status__account .display-name__account {
|
||||||
|
color: var(--rich-text-text-color);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-group__embedded-status__account {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
display: block;
|
||||||
|
content: '';
|
||||||
|
width: 24px;
|
||||||
|
height: 20px;
|
||||||
|
mask-image: url('../images/quote.svg');
|
||||||
|
background-color: var(--rich-text-decorations-color);
|
||||||
|
position: absolute;
|
||||||
|
inset-inline-start: 20px;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user