From 5187938dc656020dfe1289ea1e5ec6274d4e9fe7 Mon Sep 17 00:00:00 2001 From: Tommaso Casaburi Date: Fri, 8 May 2026 16:51:18 +0700 Subject: [PATCH] fix(embed): restore x status embeds --- src/components/embed/__tests__/embed.test.tsx | 8 +++-- src/components/embed/embed.tsx | 35 +++++++++++++++---- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/components/embed/__tests__/embed.test.tsx b/src/components/embed/__tests__/embed.test.tsx index bad65953..d52c77c2 100644 --- a/src/components/embed/__tests__/embed.test.tsx +++ b/src/components/embed/__tests__/embed.test.tsx @@ -39,10 +39,12 @@ describe('Embed', () => { expect(container.querySelector('iframe')?.getAttribute('src')).toContain(`parent=${window.location.hostname}`); }); - it('renders x and reddit embeds through iframe markup and leaves unsupported urls empty', async () => { + it('renders x as a direct tweet iframe, renders reddit through iframe markup, and leaves unsupported urls empty', async () => { await renderEmbed('https://x.com/test/status/123'); - expect(container.querySelector('iframe')?.getAttribute('srcdoc')).toContain('twitter-tweet'); + expect(container.querySelector('iframe')?.getAttribute('src')).toBe( + 'https://platform.twitter.com/embed/Tweet.html?id=123&theme=dark&dnt=false&hideThread=false&hideCard=false&lang=en', + ); await renderEmbed('https://www.reddit.com/r/test/comments/abc123/example/'); @@ -56,6 +58,8 @@ describe('Embed', () => { it('reports embeddable hosts through canEmbed and rejects unsupported reddit pages', () => { expect(canEmbed(new URL('https://www.youtube.com/watch?v=abc123'))).toBe(true); expect(canEmbed(new URL('https://yt.example/watch?v=abc123'))).toBe(true); + expect(canEmbed(new URL('https://x.com/test/status/123'))).toBe(true); + expect(canEmbed(new URL('https://x.com/test'))).toBe(false); expect(canEmbed(new URL('https://www.reddit.com/r/test/comments/abc123/example/'))).toBe(true); expect(canEmbed(new URL('https://www.reddit.com/r/test/'))).toBe(false); expect(canEmbed(new URL('https://example.com/plain-link'))).toBe(false); diff --git a/src/components/embed/embed.tsx b/src/components/embed/embed.tsx index d337124e..8b73ccba 100644 --- a/src/components/embed/embed.tsx +++ b/src/components/embed/embed.tsx @@ -110,7 +110,29 @@ const YoutubeEmbed = ({ parsedUrl }: EmbedComponentProps) => { const xHosts = new Set(['twitter.com', 'www.twitter.com', 'x.com', 'www.x.com']); +const getXTweetId = (parsedUrl: URL): string | undefined => { + const pathParts = parsedUrl.pathname.split('/').filter(Boolean); + const statusIndex = pathParts.findIndex((part) => part === 'status' || part === 'statuses'); + const statusId = statusIndex === -1 ? undefined : pathParts[statusIndex + 1]; + + return statusId && /^\d+$/.test(statusId) ? statusId : undefined; +}; + const XEmbed = ({ parsedUrl }: EmbedComponentProps) => { + const tweetId = getXTweetId(parsedUrl); + if (!tweetId) { + return null; + } + + const searchParams = new URLSearchParams({ + id: tweetId, + theme: 'dark', + dnt: 'false', + hideThread: 'false', + hideCard: 'false', + lang: 'en', + }); + return (