diff --git a/app/javascript/flavours/glitch/components/status_quoted.tsx b/app/javascript/flavours/glitch/components/status_quoted.tsx
index 3663bef616..a2111816ae 100644
--- a/app/javascript/flavours/glitch/components/status_quoted.tsx
+++ b/app/javascript/flavours/glitch/components/status_quoted.tsx
@@ -1,17 +1,23 @@
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
+import { Link } from 'react-router-dom';
import type { Map as ImmutableMap } from 'immutable';
import QuoteIcon from '@/images/quote.svg?react';
+import ArticleIcon from '@/material-icons/400-24px/article.svg?react';
+import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import { Icon } from 'flavours/glitch/components/icon';
import StatusContainer from 'flavours/glitch/containers/status_container';
+import type { Status } from 'flavours/glitch/models/status';
import { useAppSelector } from 'flavours/glitch/store';
+const MAX_QUOTE_POSTS_NESTING_LEVEL = 1;
+
const QuoteWrapper: React.FC<{
isError?: boolean;
- children: React.ReactNode;
+ children: React.ReactElement;
}> = ({ isError, children }) => {
return (
= ({ status }) => {
+ const accountId = status.get('account') as string;
+ const account = useAppSelector((state) =>
+ accountId ? state.accounts.get(accountId) : undefined,
+ );
+
+ const quoteAuthorName = account?.display_name_html;
+
+ if (!quoteAuthorName) {
+ return null;
+ }
+
+ const quoteAuthorElement = (
+
+ );
+ const quoteUrl = `/@${account.get('acct')}/${status.get('id') as string}`;
+
+ return (
+
+
+
+
+
+ );
+};
+
type QuoteMap = ImmutableMap<'state' | 'quoted_status', string | null>;
-export const QuotedStatus: React.FC<{ quote: QuoteMap }> = ({ quote }) => {
+export const QuotedStatus: React.FC<{
+ quote: QuoteMap;
+ variant?: 'full' | 'link';
+ nestingLevel?: number;
+}> = ({ quote, nestingLevel = 1, variant = 'full' }) => {
const quotedStatusId = quote.get('quoted_status');
const state = quote.get('state');
const status = useAppSelector((state) =>
quotedStatusId ? state.statuses.get(quotedStatusId) : undefined,
);
- let quoteError: React.ReactNode | null = null;
+ let quoteError: React.ReactNode = null;
if (state === 'deleted') {
quoteError = (
@@ -77,14 +119,28 @@ export const QuotedStatus: React.FC<{ quote: QuoteMap }> = ({ quote }) => {
return {quoteError};
}
+ if (variant === 'link' && status) {
+ return ;
+ }
+
+ const childQuote = status?.get('quote') as QuoteMap | undefined;
+ const canRenderChildQuote =
+ childQuote && nestingLevel <= MAX_QUOTE_POSTS_NESTING_LEVEL;
+
return (
-
+ {/* @ts-expect-error Status is not yet typed */}
+
+ {canRenderChildQuote && (
+
+ )}
+
);
};
diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss
index f99ee10a77..612bdbc709 100644
--- a/app/javascript/flavours/glitch/styles/components.scss
+++ b/app/javascript/flavours/glitch/styles/components.scss
@@ -1946,11 +1946,15 @@ body > [data-popper-placement] {
.status__quote {
position: relative;
margin-block-start: 16px;
- margin-inline-start: 56px;
+ margin-inline-start: 36px;
border-radius: 8px;
color: var(--nested-card-text);
background: var(--nested-card-background);
border: var(--nested-card-border);
+
+ @media screen and (min-width: $mobile-breakpoint) {
+ margin-inline-start: 56px;
+ }
}
.status__quote--error {
@@ -1961,10 +1965,42 @@ body > [data-popper-placement] {
font-size: 15px;
}
+.status__quote-author-button {
+ position: relative;
+ overflow: hidden;
+ display: inline-flex;
+ width: auto;
+ margin-block-start: 10px;
+ padding: 5px 12px;
+ align-items: center;
+ gap: 6px;
+ font-family: inherit;
+ font-size: 14px;
+ font-weight: 700;
+ line-height: normal;
+ letter-spacing: 0;
+ text-decoration: none;
+ color: $highlight-text-color;
+ background: var(--nested-card-background);
+ border: var(--nested-card-border);
+ border-radius: 4px;
+
+ &:active,
+ &:focus,
+ &:hover {
+ border-color: lighten($highlight-text-color, 4%);
+ color: lighten($highlight-text-color, 4%);
+ }
+
+ &:focus-visible {
+ outline: $ui-button-icon-focus-outline;
+ }
+}
+
.status__quote-icon {
position: absolute;
inset-block-start: 18px;
- inset-inline-start: -50px;
+ inset-inline-start: -40px;
display: block;
width: 26px;
height: 26px;
@@ -1976,6 +2012,10 @@ body > [data-popper-placement] {
inset-block-start: 50%;
transform: translateY(-50%);
}
+
+ @media screen and (min-width: $mobile-breakpoint) {
+ inset-inline-start: -50px;
+ }
}
.detailed-status__link {