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 {