Status redesign: Link cards (#40436)

This commit is contained in:
Echo
2026-09-09 11:39:14 +00:00
committed by GitHub
parent 28b3695b6b
commit 4447410702
3 changed files with 78 additions and 11 deletions

View File

@@ -107,15 +107,17 @@ type CardBodyProps<As extends React.ElementType> = PolymorphicProps<
{
children: React.ReactNode;
className?: string;
isDescription?: boolean;
noClamp?: boolean;
},
As
>;
export const CardBody = <As extends React.ElementType>({
export const CardBody = <As extends React.ElementType = 'div'>({
as: asComp,
children,
className,
isDescription,
noClamp,
...props
}: CardBodyProps<As>) => {
@@ -123,7 +125,12 @@ export const CardBody = <As extends React.ElementType>({
return (
<Comp
{...props}
className={classNames(className, classes.body, !noClamp && classes.clamp)}
className={classNames(
className,
classes.body,
!noClamp && classes.clamp,
isDescription && classes.description,
)}
>
{children}
</Comp>

View File

@@ -21,6 +21,9 @@
// Handle cases where the root is a link
a.root {
color: inherit;
text-decoration: none;
&:hover {
text-decoration: none;
}
@@ -60,7 +63,7 @@ a.root {
}
.body {
@include mixins.type-body-compact;
@include mixins.type-label-lg;
overflow-wrap: break-word;
flex-grow: 1;
@@ -84,12 +87,18 @@ a.root {
a.body {
padding-inline: var(--space-sm);
margin-inline: calc(-1 * var(--space-sm));
color: inherit;
text-decoration: none;
.root:has(&:hover) {
background-color: var(--color-bg-highlight);
}
}
.description {
@include mixins.type-body-compact;
}
.image {
contain: size;
grid-column: 2;

View File

@@ -4,11 +4,13 @@ import { openModal } from '@/mastodon/actions/modal';
import type { DeployPictureInPictureCallback } from '@/mastodon/actions/picture_in_picture';
import { deployPictureInPicture } from '@/mastodon/actions/picture_in_picture';
import { CollectionPreviewCard } from '@/mastodon/features/collections/components/collection_preview_card';
import Card from '@/mastodon/features/status/components/card';
import MediaCard from '@/mastodon/features/status/components/card';
import { useExpandedStatus } from '@/mastodon/hooks/useStatus';
import { useToggle } from '@/mastodon/hooks/useToggle';
import { displayMedia } from '@/mastodon/initial_state';
import type {
CardShape,
ExpandedStatusShape,
MediaAttachment,
MediaAttachmentShape,
} from '@/mastodon/models/status';
@@ -18,7 +20,9 @@ import { selectPictureInPicture } from '@/mastodon/selectors/statuses';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { compareUrls } from '@/mastodon/utils/compare_urls';
import { Card, CardBody, CardTitle } from '../card';
import { PictureInPicturePlaceholder } from '../picture_in_picture_placeholder';
import { RelativeTimestamp } from '../relative_timestamp';
import { StatusQuote } from './quote';
@@ -58,13 +62,7 @@ export const StatusAttachments: React.FC<{
? status.tagged_collections.find(({ url }) => compareUrls(url, card.url))
: status.tagged_collections[0];
if (card && !collection) {
return (
<Card
key={`${status.id}-${status.edited_at}`}
card={card}
sensitive={status.sensitive}
/>
);
return <LinkCard card={card} status={status} />;
}
if (collection) {
@@ -276,3 +274,56 @@ const MediaAttachments: React.FC<{
</Suspense>
);
};
const LinkCard: React.FC<{ card: CardShape; status: ExpandedStatusShape }> = ({
card,
status,
}) => {
// Use the old card if we have authors as the new design doesn't have attribution yet.
if (card.type === 'video' || card.authors.length > 0) {
return (
<div>
<MediaCard
key={`${status.id}-${status.edited_at}`}
card={card}
sensitive={status.sensitive}
/>
</div>
);
}
const providerUrl = new URL(card.provider_url || card.url);
const cardLinkProps = {
as: 'a',
href: card.url,
target: '_blank',
rel: 'noopener',
} as const;
return (
<Card>
<CardTitle
afterContent={
card.published_at && (
<RelativeTimestamp timestamp={card.published_at} />
)
}
>
<a
href={`${providerUrl.protocol}//${providerUrl.host}`}
target='_blank'
rel='noopener'
>
{card.author_name || card.provider_name || providerUrl.host}
</a>
</CardTitle>
<CardBody {...cardLinkProps}>{card.title}</CardBody>
{card.description && (
<CardBody {...cardLinkProps} isDescription>
{card.description}
</CardBody>
)}
</Card>
);
};