+
-
+
{!!embeddedTweetIdentity && (
@@ -59,23 +93,27 @@ export function EmbeddedTweetPreview({
{showXLogo && (
)}
- {post.sharedPost?.titleHtml ? (
+ {tweetBodyHtml ? (
) : (
- {post.sharedPost?.title}
+ {tweetBody}
)}
+ {shouldShowMedia && !!mediaSrc && (
+
+
+
+ )}
);
}
diff --git a/packages/shared/src/components/cards/socialTwitter/SocialTwitterGrid.spec.tsx b/packages/shared/src/components/cards/socialTwitter/SocialTwitterGrid.spec.tsx
index d10d85bbc1..ffe88fe4b4 100644
--- a/packages/shared/src/components/cards/socialTwitter/SocialTwitterGrid.spec.tsx
+++ b/packages/shared/src/components/cards/socialTwitter/SocialTwitterGrid.spec.tsx
@@ -81,10 +81,10 @@ it('should render top action link using post comments permalink', async () => {
expect(link).toHaveAttribute('href', basePost.permalink);
});
-it('should render source name next to metadata date for regular tweets', async () => {
+it('should render "From x.com" next to metadata date for regular tweets', async () => {
renderComponent();
- expect(await screen.findByText(/Avengers/i)).toBeInTheDocument();
+ expect(await screen.findByText(/From x\.com/i)).toBeInTheDocument();
expect(screen.queryByText(/Avengers reposted/i)).not.toBeInTheDocument();
});
@@ -127,7 +127,7 @@ it('should render quote/repost detail from shared post', async () => {
},
});
- expect(await screen.findByText(/Avengers reposted/i)).toBeInTheDocument();
+ expect(await screen.findByText(/From x\.com/i)).toBeInTheDocument();
expect((await screen.findAllByText(/@devrelweekly/)).length).toBeGreaterThan(
0,
);
@@ -173,7 +173,7 @@ it('should use creatorTwitter when shared source is unknown', async () => {
expect(screen.queryByText('@unknown')).not.toBeInTheDocument();
});
-it('should prefer source name when source id is unknown', async () => {
+it('should use creator identity when source id is unknown', async () => {
renderComponent({
post: {
...basePost,
@@ -186,10 +186,7 @@ it('should prefer source name when source id is unknown', async () => {
},
});
- expect(
- await screen.findByText('Lee Hansel Solevilla Jr'),
- ).toBeInTheDocument();
- expect(screen.queryByText('@root_creator')).not.toBeInTheDocument();
+ expect(await screen.findByText('root_creator')).toBeInTheDocument();
expect(screen.queryByText('@unknown')).not.toBeInTheDocument();
});
@@ -221,7 +218,7 @@ it('should hide headline and tags for repost cards without repost text', async (
),
).not.toBeInTheDocument();
expect(screen.queryByTestId('post-tags')).not.toBeInTheDocument();
- expect(await screen.findByText(/Avengers reposted/i)).toBeInTheDocument();
+ expect(await screen.findByText(/From x\.com/i)).toBeInTheDocument();
expect(
await screen.findByText(/Y Combinator @ycombinator/i),
).toBeInTheDocument();
diff --git a/packages/shared/src/components/cards/socialTwitter/SocialTwitterGrid.tsx b/packages/shared/src/components/cards/socialTwitter/SocialTwitterGrid.tsx
index 6d20959c16..faca7132ee 100644
--- a/packages/shared/src/components/cards/socialTwitter/SocialTwitterGrid.tsx
+++ b/packages/shared/src/components/cards/socialTwitter/SocialTwitterGrid.tsx
@@ -9,7 +9,6 @@ import {
import FeedItemContainer from '../common/FeedItemContainer';
import {
CardHeader,
- CardImage,
CardTextContainer,
CardTitle,
getPostClassNames,
@@ -27,12 +26,13 @@ import { ButtonVariant } from '../../buttons/Button';
import { IconSize } from '../../Icon';
import { TwitterIcon } from '../../icons';
import { useFeedPreviewMode } from '../../../hooks';
-import { isSocialTwitterShareLike } from '../../../graphql/posts';
import { isSourceUserSource } from '../../../graphql/sources';
import { sanitizeMessage } from '../../../features/onboarding/shared';
import {
getSocialTwitterMetadata,
+ getSocialTextDirectionProps,
getSocialTwitterMetadataLabel,
+ stripRepostedOnXPrefix,
} from './socialTwitterHelpers';
import { EmbeddedTweetPreview } from './EmbeddedTweetPreview';
@@ -91,45 +91,43 @@ export const SocialTwitterGrid = forwardRef(function SocialTwitterGrid(
): ReactElement {
const isFeedPreview = useFeedPreviewMode();
const isUserSource = isSourceUserSource(post.source);
- const isQuoteLike = isSocialTwitterShareLike(post);
- const shouldHideMedia = post.subType === 'thread';
- const showQuoteDetail = isQuoteLike;
- const showMediaDetail = !isQuoteLike && !shouldHideMedia && !!post.image;
- const shouldHideRepostHeadlineAndTags =
- post.subType === 'repost' && !post.content?.trim();
- const quoteDetailsContainerClass = shouldHideRepostHeadlineAndTags
- ? 'mx-1 mb-1 mt-2 min-h-[13.5rem] flex-1'
- : 'mx-1 mb-1 mt-2 h-40';
- const quoteDetailsTextClampClass = shouldHideRepostHeadlineAndTags
- ? 'line-clamp-[10]'
- : 'line-clamp-5';
const rawTitle = post.title || post.sharedPost?.title;
+ const normalizedContent = (
+ post.content ||
+ (post.contentHtml ? sanitizeMessage(post.contentHtml, []) : '')
+ ).trim();
+ const titleWithoutRepostPrefix = stripRepostedOnXPrefix(rawTitle);
+ const sharedTitle = post.sharedPost?.title?.trim() ?? '';
+ const hasTitleCommentary =
+ post.subType !== 'repost' &&
+ !!titleWithoutRepostPrefix &&
+ !!sharedTitle &&
+ !sharedTitle.startsWith(titleWithoutRepostPrefix);
+ const isStandaloneTweet = post.subType === 'tweet' && !post.sharedPost;
+ const hasDailyDevMarkdown =
+ !isStandaloneTweet && (!!normalizedContent || hasTitleCommentary);
+ const quoteDetailsContainerClass = 'mx-1 mb-1 mt-2';
+ const quoteDetailsTextClampClass = hasDailyDevMarkdown
+ ? 'line-clamp-6'
+ : 'line-clamp-8';
const cardTags = post.tags?.length ? post.tags : post.sharedPost?.tags;
- const threadBody =
- post.subType === 'thread'
- ? normalizeThreadBody({
- title: rawTitle,
- content: post.content,
- contentHtml: post.contentHtml,
- })
- : undefined;
- const {
- repostedByName,
- metadataHandles,
- embeddedTweetIdentity,
- embeddedTweetAvatarUser,
- } = getSocialTwitterMetadata(post);
- const cardOverlayLabel =
- isQuoteLike && repostedByName
- ? `${repostedByName} reposted on X. ${
- rawTitle || post.title || ''
- }`.trim()
- : rawTitle;
- const metadataLabel = getSocialTwitterMetadataLabel({
- isRepostLike: isQuoteLike,
- repostedByName,
- metadataHandles,
- });
+ let commentaryBody: string | undefined;
+ if (hasDailyDevMarkdown) {
+ if (post.subType === 'thread') {
+ commentaryBody = normalizeThreadBody({
+ title: rawTitle,
+ content: post.content,
+ contentHtml: post.contentHtml,
+ });
+ } else {
+ commentaryBody = normalizedContent || undefined;
+ }
+ }
+ const { embeddedTweetIdentity, embeddedTweetAvatarUser } =
+ getSocialTwitterMetadata(post);
+ const socialTextDirectionProps = getSocialTextDirectionProps(post.language);
+ const cardOverlayLabel = rawTitle;
+ const metadataLabel = getSocialTwitterMetadataLabel();
const metadataContent = (
<>
{!!post.createdAt &&
}
@@ -147,7 +145,7 @@ export const SocialTwitterGrid = forwardRef(function SocialTwitterGrid(
className: getPostClassNames(
post,
domProps.className,
- 'min-h-card max-h-card',
+ 'min-h-card max-h-card overflow-hidden',
),
}}
ref={ref}
@@ -187,14 +185,17 @@ export const SocialTwitterGrid = forwardRef(function SocialTwitterGrid(