mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-25 18:55:19 +02:00
embed tweets
This commit is contained in:
parent
8737605666
commit
e3d2a0988b
7 changed files with 87 additions and 63 deletions
|
|
@ -49,6 +49,7 @@
|
|||
"radix-ui": "^1.4.3",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-tweet": "^3.2.2",
|
||||
"recharts": "^3.8.0",
|
||||
"remark-breaks": "^4.0.0",
|
||||
"sonner": "^2.0.7",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { mergeAttributes, Node } from '@tiptap/react'
|
||||
import { ReactNodeViewRenderer, NodeViewWrapper } from '@tiptap/react'
|
||||
import { X, ExternalLink } from 'lucide-react'
|
||||
import { Tweet } from 'react-tweet'
|
||||
import { blocks } from '@x/shared'
|
||||
|
||||
function getEmbedUrl(provider: string, url: string): string | null {
|
||||
|
|
@ -24,6 +25,28 @@ function getEmbedUrl(provider: string, url: string): string | null {
|
|||
return null
|
||||
}
|
||||
|
||||
function extractTweetId(url: string): string | null {
|
||||
try {
|
||||
const parsed = new URL(url)
|
||||
const hostname = parsed.hostname
|
||||
.toLowerCase()
|
||||
.replace(/^www\./, '')
|
||||
.replace(/^mobile\./, '')
|
||||
if (hostname !== 'twitter.com' && hostname !== 'x.com') return null
|
||||
|
||||
const segments = parsed.pathname.split('/').filter(Boolean)
|
||||
for (let i = 0; i < segments.length - 1; i += 1) {
|
||||
if ((segments[i] === 'status' || segments[i] === 'statuses') && /^\d+$/.test(segments[i + 1])) {
|
||||
return segments[i + 1]
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function EmbedBlockView({ node, deleteNode }: { node: { attrs: Record<string, unknown> }; deleteNode: () => void }) {
|
||||
const raw = node.attrs.data as string
|
||||
let config: blocks.EmbedBlock | null = null
|
||||
|
|
@ -45,6 +68,7 @@ function EmbedBlockView({ node, deleteNode }: { node: { attrs: Record<string, un
|
|||
)
|
||||
}
|
||||
|
||||
const tweetId = extractTweetId(config.url)
|
||||
const embedUrl = getEmbedUrl(config.provider, config.url)
|
||||
|
||||
return (
|
||||
|
|
@ -57,7 +81,14 @@ function EmbedBlockView({ node, deleteNode }: { node: { attrs: Record<string, un
|
|||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
{embedUrl ? (
|
||||
{config.provider === 'tweet' && tweetId ? (
|
||||
<div
|
||||
className="embed-block-tweet-shell"
|
||||
onMouseDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<Tweet id={tweetId} />
|
||||
</div>
|
||||
) : embedUrl ? (
|
||||
<div className="embed-block-iframe-container">
|
||||
<iframe
|
||||
src={embedUrl}
|
||||
|
|
|
|||
|
|
@ -867,6 +867,16 @@
|
|||
border: none;
|
||||
}
|
||||
|
||||
.tiptap-editor .ProseMirror .embed-block-tweet-shell {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tiptap-editor .ProseMirror .embed-block-tweet-shell .react-tweet-theme {
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.tiptap-editor .ProseMirror .embed-block-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue