Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/www/public/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15036,7 +15036,7 @@ export const TweetNotFound = ({

export const TweetHeader = ({ tweet }: { tweet: EnrichedTweet }) => (
<div className="flex flex-row justify-between tracking-tight">
<div className="flex items-center space-x-2">
<div className="flex items-center space-x-2 shrink-0">
<a href={tweet.user.url} target="_blank" rel="noreferrer">
<img
title={`Profile picture of ${tweet.user.name}`}
Expand Down
2 changes: 1 addition & 1 deletion apps/www/public/r/tweet-card.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"files": [
{
"path": "registry/magicui/tweet-card.tsx",
"content": "/* eslint-disable @next/next/no-img-element */\nimport { Suspense } from \"react\"\nimport { enrichTweet, type EnrichedTweet, type TweetProps } from \"react-tweet\"\nimport { getTweet, type Tweet } from \"react-tweet/api\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface TwitterIconProps {\n className?: string\n [key: string]: unknown\n}\nconst Twitter = ({ className, ...props }: TwitterIconProps) => (\n <svg\n stroke=\"currentColor\"\n fill=\"currentColor\"\n strokeWidth=\"0\"\n viewBox=\"0 0 24 24\"\n height=\"1em\"\n width=\"1em\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n {...props}\n >\n <g>\n <path fill=\"none\" d=\"M0 0h24v24H0z\"></path>\n <path d=\"M22.162 5.656a8.384 8.384 0 0 1-2.402.658A4.196 4.196 0 0 0 21.6 4c-.82.488-1.719.83-2.656 1.015a4.182 4.182 0 0 0-7.126 3.814 11.874 11.874 0 0 1-8.62-4.37 4.168 4.168 0 0 0-.566 2.103c0 1.45.738 2.731 1.86 3.481a4.168 4.168 0 0 1-1.894-.523v.052a4.185 4.185 0 0 0 3.355 4.101 4.21 4.21 0 0 1-1.89.072A4.185 4.185 0 0 0 7.97 16.65a8.394 8.394 0 0 1-6.191 1.732 11.83 11.83 0 0 0 6.41 1.88c7.693 0 11.9-6.373 11.9-11.9 0-.18-.005-.362-.013-.54a8.496 8.496 0 0 0 2.087-2.165z\"></path>\n </g>\n </svg>\n)\n\nconst Verified = ({ className, ...props }: TwitterIconProps) => (\n <svg\n aria-label=\"Verified Account\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <g fill=\"currentColor\">\n <path d=\"M22.5 12.5c0-1.58-.875-2.95-2.148-3.6.154-.435.238-.905.238-1.4 0-2.21-1.71-3.998-3.818-3.998-.47 0-.92.084-1.336.25C14.818 2.415 13.51 1.5 12 1.5s-2.816.917-3.437 2.25c-.415-.165-.866-.25-1.336-.25-2.11 0-3.818 1.79-3.818 4 0 .494.083.964.237 1.4-1.272.65-2.147 2.018-2.147 3.6 0 1.495.782 2.798 1.942 3.486-.02.17-.032.34-.032.514 0 2.21 1.708 4 3.818 4 .47 0 .92-.086 1.335-.25.62 1.334 1.926 2.25 3.437 2.25 1.512 0 2.818-.916 3.437-2.25.415.163.865.248 1.336.248 2.11 0 3.818-1.79 3.818-4 0-.174-.012-.344-.033-.513 1.158-.687 1.943-1.99 1.943-3.484zm-6.616-3.334l-4.334 6.5c-.145.217-.382.334-.625.334-.143 0-.288-.04-.416-.126l-.115-.094-2.415-2.415c-.293-.293-.293-.768 0-1.06s.768-.294 1.06 0l1.77 1.767 3.825-5.74c.23-.345.696-.436 1.04-.207.346.23.44.696.21 1.04z\" />\n </g>\n </svg>\n)\n\nexport const truncate = (str: string | null, length: number) => {\n if (!str || str.length <= length) return str\n return `${str.slice(0, length - 3)}...`\n}\n\nconst Skeleton = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => {\n return (\n <div className={cn(\"bg-primary/10 rounded-md\", className)} {...props} />\n )\n}\n\nexport const TweetSkeleton = ({\n className,\n ...props\n}: {\n className?: string\n [key: string]: unknown\n}) => (\n <div\n className={cn(\n \"flex size-full max-h-max min-w-72 flex-col gap-2 rounded-lg border p-4\",\n className\n )}\n {...props}\n >\n <div className=\"flex flex-row gap-2\">\n <Skeleton className=\"size-10 shrink-0 rounded-full\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n <Skeleton className=\"h-20 w-full\" />\n </div>\n)\n\nexport const TweetNotFound = ({\n className,\n ...props\n}: {\n className?: string\n [key: string]: unknown\n}) => (\n <div\n className={cn(\n \"flex size-full flex-col items-center justify-center gap-2 rounded-lg border p-4\",\n className\n )}\n {...props}\n >\n <h3>Tweet not found</h3>\n </div>\n)\n\nexport const TweetHeader = ({ tweet }: { tweet: EnrichedTweet }) => (\n <div className=\"flex flex-row justify-between tracking-tight\">\n <div className=\"flex items-center space-x-2\">\n <a href={tweet.user.url} target=\"_blank\" rel=\"noreferrer\">\n <img\n title={`Profile picture of ${tweet.user.name}`}\n alt={tweet.user.screen_name}\n height={48}\n width={48}\n src={tweet.user.profile_image_url_https}\n className=\"overflow-hidden rounded-full border border-transparent\"\n />\n </a>\n <div>\n <a\n href={tweet.user.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"flex items-center font-semibold whitespace-nowrap\"\n >\n {truncate(tweet.user.name, 20)}\n {tweet.user.verified ||\n (tweet.user.is_blue_verified && (\n <Verified className=\"ml-1 inline size-4 text-blue-500\" />\n ))}\n </a>\n <div className=\"flex items-center space-x-1\">\n <a\n href={tweet.user.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-sm text-gray-500 transition-all duration-75\"\n >\n @{truncate(tweet.user.screen_name, 16)}\n </a>\n </div>\n </div>\n </div>\n <a href={tweet.url} target=\"_blank\" rel=\"noreferrer\">\n <span className=\"sr-only\">Link to tweet</span>\n <Twitter className=\"size-5 items-start text-[#3BA9EE] transition-all ease-in-out hover:scale-105\" />\n </a>\n </div>\n)\n\nexport const TweetBody = ({ tweet }: { tweet: EnrichedTweet }) => (\n <div className=\"leading-normal tracking-tighter break-words\">\n {tweet.entities.map((entity, idx) => {\n switch (entity.type) {\n case \"url\":\n case \"symbol\":\n case \"hashtag\":\n case \"mention\":\n return (\n <a\n key={idx}\n href={entity.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm font-normal text-gray-500\"\n >\n <span>{entity.text}</span>\n </a>\n )\n case \"text\":\n return (\n <span\n key={idx}\n className=\"text-sm font-normal\"\n dangerouslySetInnerHTML={{ __html: entity.text }}\n />\n )\n }\n })}\n </div>\n)\n\nexport const TweetMedia = ({ tweet }: { tweet: EnrichedTweet }) => {\n if (!tweet.video && !tweet.photos) return null\n return (\n <div className=\"flex flex-1 items-center justify-center\">\n {tweet.video && (\n <video\n poster={tweet.video.poster}\n autoPlay\n loop\n muted\n playsInline\n className=\"rounded-xl border shadow-sm\"\n >\n <source src={tweet.video.variants[0].src} type=\"video/mp4\" />\n Your browser does not support the video tag.\n </video>\n )}\n {tweet.photos && (\n <div className=\"relative flex transform-gpu snap-x snap-mandatory gap-4 overflow-x-auto\">\n <div className=\"shrink-0 snap-center sm:w-2\" />\n {tweet.photos.map((photo) => (\n <img\n key={photo.url}\n src={photo.url}\n width={photo.width}\n height={photo.height}\n title={\"Photo by \" + tweet.user.name}\n alt={tweet.text}\n className=\"h-64 w-5/6 shrink-0 snap-center snap-always rounded-xl border object-cover shadow-sm\"\n />\n ))}\n <div className=\"shrink-0 snap-center sm:w-2\" />\n </div>\n )}\n {!tweet.video &&\n !tweet.photos &&\n // @ts-expect-error package doesn't have type definitions\n tweet?.card?.binding_values?.thumbnail_image_large?.image_value.url && (\n <img\n src={\n // @ts-expect-error package doesn't have type definitions\n tweet.card.binding_values.thumbnail_image_large.image_value.url\n }\n className=\"h-64 rounded-xl border object-cover shadow-sm\"\n alt={tweet.text}\n />\n )}\n </div>\n )\n}\n\nexport const MagicTweet = ({\n tweet,\n className,\n ...props\n}: {\n tweet: Tweet\n className?: string\n}) => {\n const enrichedTweet = enrichTweet(tweet)\n return (\n <div\n className={cn(\n \"relative flex h-fit w-full max-w-lg flex-col gap-2 overflow-hidden rounded-lg border p-4 backdrop-blur-md\",\n className\n )}\n {...props}\n >\n <TweetHeader tweet={enrichedTweet} />\n <TweetBody tweet={enrichedTweet} />\n <TweetMedia tweet={enrichedTweet} />\n </div>\n )\n}\n\n/**\n * TweetCard (Server Side Only)\n */\nexport const TweetCard = async ({\n id,\n components,\n fallback = <TweetSkeleton />,\n onError,\n ...props\n}: TweetProps & {\n className?: string\n}) => {\n const tweet = id\n ? await getTweet(id).catch((err) => {\n if (onError) {\n onError(err)\n } else {\n console.error(err)\n }\n })\n : undefined\n\n if (!tweet) {\n const NotFound = components?.TweetNotFound || TweetNotFound\n return <NotFound {...props} />\n }\n\n return (\n <Suspense fallback={fallback}>\n <MagicTweet tweet={tweet} {...props} />\n </Suspense>\n )\n}\n",
"content": "/* eslint-disable @next/next/no-img-element */\nimport { Suspense } from \"react\"\nimport { enrichTweet, type EnrichedTweet, type TweetProps } from \"react-tweet\"\nimport { getTweet, type Tweet } from \"react-tweet/api\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface TwitterIconProps {\n className?: string\n [key: string]: unknown\n}\nconst Twitter = ({ className, ...props }: TwitterIconProps) => (\n <svg\n stroke=\"currentColor\"\n fill=\"currentColor\"\n strokeWidth=\"0\"\n viewBox=\"0 0 24 24\"\n height=\"1em\"\n width=\"1em\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n {...props}\n >\n <g>\n <path fill=\"none\" d=\"M0 0h24v24H0z\"></path>\n <path d=\"M22.162 5.656a8.384 8.384 0 0 1-2.402.658A4.196 4.196 0 0 0 21.6 4c-.82.488-1.719.83-2.656 1.015a4.182 4.182 0 0 0-7.126 3.814 11.874 11.874 0 0 1-8.62-4.37 4.168 4.168 0 0 0-.566 2.103c0 1.45.738 2.731 1.86 3.481a4.168 4.168 0 0 1-1.894-.523v.052a4.185 4.185 0 0 0 3.355 4.101 4.21 4.21 0 0 1-1.89.072A4.185 4.185 0 0 0 7.97 16.65a8.394 8.394 0 0 1-6.191 1.732 11.83 11.83 0 0 0 6.41 1.88c7.693 0 11.9-6.373 11.9-11.9 0-.18-.005-.362-.013-.54a8.496 8.496 0 0 0 2.087-2.165z\"></path>\n </g>\n </svg>\n)\n\nconst Verified = ({ className, ...props }: TwitterIconProps) => (\n <svg\n aria-label=\"Verified Account\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <g fill=\"currentColor\">\n <path d=\"M22.5 12.5c0-1.58-.875-2.95-2.148-3.6.154-.435.238-.905.238-1.4 0-2.21-1.71-3.998-3.818-3.998-.47 0-.92.084-1.336.25C14.818 2.415 13.51 1.5 12 1.5s-2.816.917-3.437 2.25c-.415-.165-.866-.25-1.336-.25-2.11 0-3.818 1.79-3.818 4 0 .494.083.964.237 1.4-1.272.65-2.147 2.018-2.147 3.6 0 1.495.782 2.798 1.942 3.486-.02.17-.032.34-.032.514 0 2.21 1.708 4 3.818 4 .47 0 .92-.086 1.335-.25.62 1.334 1.926 2.25 3.437 2.25 1.512 0 2.818-.916 3.437-2.25.415.163.865.248 1.336.248 2.11 0 3.818-1.79 3.818-4 0-.174-.012-.344-.033-.513 1.158-.687 1.943-1.99 1.943-3.484zm-6.616-3.334l-4.334 6.5c-.145.217-.382.334-.625.334-.143 0-.288-.04-.416-.126l-.115-.094-2.415-2.415c-.293-.293-.293-.768 0-1.06s.768-.294 1.06 0l1.77 1.767 3.825-5.74c.23-.345.696-.436 1.04-.207.346.23.44.696.21 1.04z\" />\n </g>\n </svg>\n)\n\nexport const truncate = (str: string | null, length: number) => {\n if (!str || str.length <= length) return str\n return `${str.slice(0, length - 3)}...`\n}\n\nconst Skeleton = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => {\n return (\n <div className={cn(\"bg-primary/10 rounded-md\", className)} {...props} />\n )\n}\n\nexport const TweetSkeleton = ({\n className,\n ...props\n}: {\n className?: string\n [key: string]: unknown\n}) => (\n <div\n className={cn(\n \"flex size-full max-h-max min-w-72 flex-col gap-2 rounded-lg border p-4\",\n className\n )}\n {...props}\n >\n <div className=\"flex flex-row gap-2\">\n <Skeleton className=\"size-10 shrink-0 rounded-full\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n <Skeleton className=\"h-20 w-full\" />\n </div>\n)\n\nexport const TweetNotFound = ({\n className,\n ...props\n}: {\n className?: string\n [key: string]: unknown\n}) => (\n <div\n className={cn(\n \"flex size-full flex-col items-center justify-center gap-2 rounded-lg border p-4\",\n className\n )}\n {...props}\n >\n <h3>Tweet not found</h3>\n </div>\n)\n\nexport const TweetHeader = ({ tweet }: { tweet: EnrichedTweet }) => (\n <div className=\"flex flex-row justify-between tracking-tight\">\n <div className=\"flex items-center space-x-2 shrink-0\">\n <a href={tweet.user.url} target=\"_blank\" rel=\"noreferrer\">\n <img\n title={`Profile picture of ${tweet.user.name}`}\n alt={tweet.user.screen_name}\n height={48}\n width={48}\n src={tweet.user.profile_image_url_https}\n className=\"overflow-hidden rounded-full border border-transparent\"\n />\n </a>\n <div>\n <a\n href={tweet.user.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"flex items-center font-semibold whitespace-nowrap\"\n >\n {truncate(tweet.user.name, 20)}\n {tweet.user.verified ||\n (tweet.user.is_blue_verified && (\n <Verified className=\"ml-1 inline size-4 text-blue-500\" />\n ))}\n </a>\n <div className=\"flex items-center space-x-1\">\n <a\n href={tweet.user.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-sm text-gray-500 transition-all duration-75\"\n >\n @{truncate(tweet.user.screen_name, 16)}\n </a>\n </div>\n </div>\n </div>\n <a href={tweet.url} target=\"_blank\" rel=\"noreferrer\">\n <span className=\"sr-only\">Link to tweet</span>\n <Twitter className=\"size-5 items-start text-[#3BA9EE] transition-all ease-in-out hover:scale-105\" />\n </a>\n </div>\n)\n\nexport const TweetBody = ({ tweet }: { tweet: EnrichedTweet }) => (\n <div className=\"leading-normal tracking-tighter break-words\">\n {tweet.entities.map((entity, idx) => {\n switch (entity.type) {\n case \"url\":\n case \"symbol\":\n case \"hashtag\":\n case \"mention\":\n return (\n <a\n key={idx}\n href={entity.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm font-normal text-gray-500\"\n >\n <span>{entity.text}</span>\n </a>\n )\n case \"text\":\n return (\n <span\n key={idx}\n className=\"text-sm font-normal\"\n dangerouslySetInnerHTML={{ __html: entity.text }}\n />\n )\n }\n })}\n </div>\n)\n\nexport const TweetMedia = ({ tweet }: { tweet: EnrichedTweet }) => {\n if (!tweet.video && !tweet.photos) return null\n return (\n <div className=\"flex flex-1 items-center justify-center\">\n {tweet.video && (\n <video\n poster={tweet.video.poster}\n autoPlay\n loop\n muted\n playsInline\n className=\"rounded-xl border shadow-sm\"\n >\n <source src={tweet.video.variants[0].src} type=\"video/mp4\" />\n Your browser does not support the video tag.\n </video>\n )}\n {tweet.photos && (\n <div className=\"relative flex transform-gpu snap-x snap-mandatory gap-4 overflow-x-auto\">\n <div className=\"shrink-0 snap-center sm:w-2\" />\n {tweet.photos.map((photo) => (\n <img\n key={photo.url}\n src={photo.url}\n width={photo.width}\n height={photo.height}\n title={\"Photo by \" + tweet.user.name}\n alt={tweet.text}\n className=\"h-64 w-5/6 shrink-0 snap-center snap-always rounded-xl border object-cover shadow-sm\"\n />\n ))}\n <div className=\"shrink-0 snap-center sm:w-2\" />\n </div>\n )}\n {!tweet.video &&\n !tweet.photos &&\n // @ts-expect-error package doesn't have type definitions\n tweet?.card?.binding_values?.thumbnail_image_large?.image_value.url && (\n <img\n src={\n // @ts-expect-error package doesn't have type definitions\n tweet.card.binding_values.thumbnail_image_large.image_value.url\n }\n className=\"h-64 rounded-xl border object-cover shadow-sm\"\n alt={tweet.text}\n />\n )}\n </div>\n )\n}\n\nexport const MagicTweet = ({\n tweet,\n className,\n ...props\n}: {\n tweet: Tweet\n className?: string\n}) => {\n const enrichedTweet = enrichTweet(tweet)\n return (\n <div\n className={cn(\n \"relative flex h-fit w-full max-w-lg flex-col gap-2 overflow-hidden rounded-lg border p-4 backdrop-blur-md\",\n className\n )}\n {...props}\n >\n <TweetHeader tweet={enrichedTweet} />\n <TweetBody tweet={enrichedTweet} />\n <TweetMedia tweet={enrichedTweet} />\n </div>\n )\n}\n\n/**\n * TweetCard (Server Side Only)\n */\nexport const TweetCard = async ({\n id,\n components,\n fallback = <TweetSkeleton />,\n onError,\n ...props\n}: TweetProps & {\n className?: string\n}) => {\n const tweet = id\n ? await getTweet(id).catch((err) => {\n if (onError) {\n onError(err)\n } else {\n console.error(err)\n }\n })\n : undefined\n\n if (!tweet) {\n const NotFound = components?.TweetNotFound || TweetNotFound\n return <NotFound {...props} />\n }\n\n return (\n <Suspense fallback={fallback}>\n <MagicTweet tweet={tweet} {...props} />\n </Suspense>\n )\n}\n",
"type": "registry:ui"
}
]
Expand Down
2 changes: 1 addition & 1 deletion apps/www/registry/magicui/tweet-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const TweetNotFound = ({

export const TweetHeader = ({ tweet }: { tweet: EnrichedTweet }) => (
<div className="flex flex-row justify-between tracking-tight">
<div className="flex items-center space-x-2">
<div className="flex shrink-0 items-center space-x-2">
<a href={tweet.user.url} target="_blank" rel="noreferrer">
<img
title={`Profile picture of ${tweet.user.name}`}
Expand Down