import type { PooledTweet } from "@xtap-pool/shared"; import { avatarColor, displayName, formatCount, formatTweetDate, isArticleTweet, isRetweet, photoMedia, quotedTweetUrl, tweetMetrics, tweetTextHtml, } from "../lib/format.js"; export type TweetCardProps = { tweet: PooledTweet; contributors: readonly string[]; now: Date; }; /** * Tweet text rendered to escaped HTML (URLs/mentions/hashtags linkified). */ function TweetText({ text }: { text: string }): React.JSX.Element { return (
); } function TweetMedia({ tweet }: { tweet: PooledTweet }): React.JSX.Element | null { const photos = photoMedia(tweet); if (photos.length === 0) return null; return (
{photos.map((photo) => ( {photo.alt} ))}
); } function Metrics({ tweet }: { tweet: PooledTweet }): React.JSX.Element { const metrics = tweetMetrics(tweet); const entries: [string, number][] = [ ["replies", metrics.replies], ["reposts", metrics.retweets], ["likes", metrics.likes], ["views", metrics.views], ]; return (
{entries.map(([label, value]) => ( {formatCount(value)} {label} ))}
); } /** One tweet, rendered in the solmaz.io X-card style. */ export function TweetCard({ tweet, contributors, now }: TweetCardProps): React.JSX.Element { const name = displayName(tweet); const quoted = quotedTweetUrl(tweet); return (
{name.slice(0, 1).toUpperCase()}
{name} @{tweet.author.username} · View on X
{isRetweet(tweet) ?
reposted
: null} {quoted === undefined ? null : ( View quoted post on X )}
{isArticleTweet(tweet) ? article : null} {contributors.map((contributor) => ( ⛏ {contributor} ))}
); }