From edba87cb2d22fe0ca451171f9d39bee0c9f14a4c Mon Sep 17 00:00:00 2001 From: Shaik Sameer <109991523+vij-sameerb5@users.noreply.github.com> Date: Sun, 24 May 2026 23:59:21 +0530 Subject: [PATCH] feat: add clipped video tab component --- .../docs/components/clipped-video-tab.mdx | 15 + apps/www/public/llms-full.txt | 445 +++++++++++++++++- apps/www/public/llms.txt | 2 + apps/www/public/r/clipped-video-tab-demo.json | 17 + apps/www/public/r/clipped-video-tab.json | 17 + apps/www/public/r/registry.json | 30 ++ apps/www/public/r/tweet-card.json | 2 +- apps/www/public/registry.json | 30 ++ apps/www/registry.json | 30 ++ apps/www/registry/__index__.tsx | 34 ++ .../example/clipped-video-tab-demo.tsx | 5 + .../registry/magicui/clipped-video-tab.tsx | 380 +++++++++++++++ apps/www/registry/magicui/tweet-card.tsx | 46 +- apps/www/registry/registry-examples.ts | 13 + apps/www/registry/registry-ui.ts | 14 + package.json | 3 + pnpm-lock.yaml | 41 ++ 17 files changed, 1119 insertions(+), 5 deletions(-) create mode 100644 apps/www/content/docs/components/clipped-video-tab.mdx create mode 100644 apps/www/public/r/clipped-video-tab-demo.json create mode 100644 apps/www/public/r/clipped-video-tab.json create mode 100644 apps/www/registry/example/clipped-video-tab-demo.tsx create mode 100644 apps/www/registry/magicui/clipped-video-tab.tsx diff --git a/apps/www/content/docs/components/clipped-video-tab.mdx b/apps/www/content/docs/components/clipped-video-tab.mdx new file mode 100644 index 000000000..d77936eb7 --- /dev/null +++ b/apps/www/content/docs/components/clipped-video-tab.mdx @@ -0,0 +1,15 @@ +--- +title: Clipped Video Tab +date: 2026-05-24 +description: Cinematic clipped video section +author: sameer +published: true +--- + + + +## Installation + +```bash +npx shadcn@latest add @magicui/clipped-video-tab +``` diff --git a/apps/www/public/llms-full.txt b/apps/www/public/llms-full.txt index 6625eeef5..577ca6a7f 100644 --- a/apps/www/public/llms-full.txt +++ b/apps/www/public/llms-full.txt @@ -4740,6 +4740,405 @@ export default function TweetMetaPreview() { +===== COMPONENT: clipped-video-tab ===== +Title: Clipped Video Tab +Description: A full-width tabbed section with clipped video backgrounds and animated content cards. + +--- file: magicui/clipped-video-tab.tsx --- +"use client" + +import { useState } from "react" +import { AnimatePresence, motion } from "framer-motion" +import { + Bot, + Brain, + BrainCircuit, + CheckCircle2, + Circle, + Cpu, + Database, + Globe, + LoaderCircle, + Lock, + Mic, + Zap, +} from "lucide-react" + +const items = [ + { + icon: Zap, + label: "2D/3D Annotation", + title: "Data Annotation", + description: + "Multimodal workflows for image, video, and 3D annotation with high-accuracy quality control.", + + video: + "https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779622196/new107_qhrklf.mp4", + + card: { + heading: "Data Annotation", + badge: "Live", + goal: "Deploy multimodal AI data pipelines across multiple international regions.", + + tasks: [ + { + title: "Regional onboarding", + meta: "Completed in 4.2s", + status: "completed", + }, + { + title: "Deploy collection teams", + meta: "Completed in 8.1s", + status: "completed", + }, + { + title: "Scale infrastructure", + meta: "In progress... 18s", + status: "progress", + }, + { + title: "Validate datasets", + meta: "Pending", + status: "pending", + }, + ], + }, + }, + + { + icon: Lock, + label: "Data Collection", + title: "Data Collection", + description: + "High-speed multimodal data collection pipelines to capture and structure real-world datasets.", + + video: + "https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779621768/new105_meaomd.mp4", + + card: { + heading: "Data Collection", + badge: "Data-Ready", + goal: "Prepare large-scale datasets for training multimodal reasoning systems.", + + tasks: [ + { + title: "Process raw data", + meta: "Completed in 3.1s", + status: "completed", + }, + { + title: "Generate annotations", + meta: "Completed in 5.4s", + status: "completed", + }, + { + title: "Train reasoning model", + meta: "In progress... 24s", + status: "progress", + }, + { + title: "Run evaluation tests", + meta: "Pending", + status: "pending", + }, + ], + }, + }, + + { + icon: Mic, + label: "Audio and Speech", + title: "Audio and Speech", + description: + "Automation-first AI systems with human validation and scalable workflows.", + + video: + "https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779622220/new108_k1a47m.mp4", + + card: { + heading: "Audio Transcription", + badge: "Auto-generated", + goal: "Build a REST API endpoint for user authentication with JWT tokens.", + + tasks: [ + { + title: "Gather requirements", + meta: "Completed in 2.3s", + status: "completed", + }, + { + title: "Research solutions", + meta: "Completed in 5.1s", + status: "completed", + }, + { + title: "Implement solution", + meta: "In progress... 12s", + status: "progress", + }, + { + title: "Test and validate", + meta: "Pending", + status: "pending", + }, + ], + }, + }, + + { + icon: Database, + label: "Explainable AI", + title: "Data Engine", + description: + "Transparent AI models with interpretable predictions and decision-making insights.", + + video: + "https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779622271/02_u2efg7.mp4", + + card: { + heading: "Pipeline Engine", + badge: "Optimized", + goal: "Process and validate multimodal datasets for enterprise deployment.", + + tasks: [ + { + title: "Upload raw datasets", + meta: "Completed in 1.9s", + status: "completed", + }, + { + title: "Run QA workflows", + meta: "Completed in 6.7s", + status: "completed", + }, + { + title: "Generate metadata", + meta: "In progress... 16s", + status: "progress", + }, + { + title: "Export training package", + meta: "Pending", + status: "pending", + }, + ], + }, + }, +] + +function TabMenu({ + activeTab, + onSelect, + className, +}: { + activeTab: number + onSelect: (index: number) => void + className?: string +}) { + return ( +
+
+ {items.map((tab, index) => { + const Icon = tab.icon + + return ( + + ) + })} +
+
+ ) +} + +export default function ClippedImageSection() { + const [activeTab, setActiveTab] = useState(0) + + const activeItem = items[activeTab] + + return ( +
+
+ {/* TOP */} +
+
+ {/* LEFT */} +
+

+ Our Platforms +

+
+ + {/* RIGHT */} +
+

+ Crafted for magicUI. A cinematic interface for modern digital + products — designed and developed by Sameer. +

+
+
+
+ + {/* TABS — in flow on mobile */} +
+ +
+ + {/* MEDIA AREA */} +
+ {/* TABS — overlay on desktop */} +
+ +
+ + {/* VIDEO CONTAINER */} +
+ {/* VIDEO */} + + + + + {/* OVERLAY */} +
+ + {/* CENTER CARD */} +
+ + + {/* HEADER */} +
+

+ {activeItem.card.heading} +

+ + + {activeItem.card.badge} + +
+ + {/* GOAL */} +
+

Goal

+ +

+ {activeItem.card.goal} +

+
+ + {/* TASKS */} +
+ {activeItem.card.tasks.map((task, index) => ( +
+ {/* ICON */} +
+ {task.status === "completed" && ( + + )} + + {task.status === "progress" && ( + + )} + + {task.status === "pending" && ( + + )} +
+ + {/* CONTENT */} +
+

+ {task.title} +

+ +

{task.meta}

+
+
+ ))} +
+ + {/* FOOTER */} +
+ 2/5 tasks complete + + Est. 45s remaining +
+
+
+
+
+
+
+
+ ) +} + + +===== EXAMPLE: clipped-video-tab-demo ===== +Title: Clipped Video Tab Demo + +--- file: example/clipped-video-tab-demo.tsx --- +import Component from "@/registry/magicui/clipped-video-tab" + +export default function ClippedVideoTabDemo() { + return +} + + + ===== COMPONENT: code-comparison ===== Title: Code Comparison Description: A component which compares two code snippets. @@ -19088,7 +19487,12 @@ Description: A card that displays a tweet with the author's name, handle, and pr --- file: magicui/tweet-card.tsx --- import { Suspense } from "react" import { enrichTweet, type EnrichedTweet, type TweetProps } from "react-tweet" -import { getTweet, type Tweet } from "react-tweet/api" +import { + getTweet, + type QuotedTweet, + type Tweet, + type TweetEntities, +} from "react-tweet/api" import { cn } from "@/lib/utils" @@ -19317,6 +19721,43 @@ export const TweetMedia = ({ tweet }: { tweet: EnrichedTweet }) => { ) } +const EMPTY_TWEET_ENTITIES: TweetEntities = { + hashtags: [], + urls: [], + user_mentions: [], + symbols: [], +} + +/** Syndication API responses sometimes omit entity arrays; react-tweet expects iterables. */ +function normalizeTweetEntities(tweet: T): T { + const entities: TweetEntities = { + ...EMPTY_TWEET_ENTITIES, + ...tweet.entities, + hashtags: tweet.entities?.hashtags ?? [], + urls: tweet.entities?.urls ?? [], + user_mentions: tweet.entities?.user_mentions ?? [], + symbols: tweet.entities?.symbols ?? [], + ...(tweet.entities?.media ? { media: tweet.entities.media } : {}), + } + + const textLength = tweet.text?.length ?? 0 + + const normalized = { + ...tweet, + entities, + display_text_range: tweet.display_text_range ?? [0, textLength], + } + + if ("quoted_tweet" in tweet && tweet.quoted_tweet) { + return { + ...normalized, + quoted_tweet: normalizeTweetEntities(tweet.quoted_tweet), + } + } + + return normalized +} + export const MagicTweet = ({ tweet, className, @@ -19325,7 +19766,7 @@ export const MagicTweet = ({ tweet: Tweet className?: string }) => { - const enrichedTweet = enrichTweet(tweet) + const enrichedTweet = enrichTweet(normalizeTweetEntities(tweet)) return (
\n}\n", + "type": "registry:example" + } + ] +} \ No newline at end of file diff --git a/apps/www/public/r/clipped-video-tab.json b/apps/www/public/r/clipped-video-tab.json new file mode 100644 index 000000000..09fd3b928 --- /dev/null +++ b/apps/www/public/r/clipped-video-tab.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "clipped-video-tab", + "type": "registry:ui", + "title": "Clipped Video Tab", + "description": "A full-width tabbed section with clipped video backgrounds and animated content cards.", + "dependencies": [ + "framer-motion" + ], + "files": [ + { + "path": "registry/magicui/clipped-video-tab.tsx", + "content": "\"use client\"\n\nimport { useState } from \"react\"\nimport { AnimatePresence, motion } from \"framer-motion\"\nimport {\n Bot,\n Brain,\n BrainCircuit,\n CheckCircle2,\n Circle,\n Cpu,\n Database,\n Globe,\n LoaderCircle,\n Lock,\n Mic,\n Zap,\n} from \"lucide-react\"\n\nconst items = [\n {\n icon: Zap,\n label: \"2D/3D Annotation\",\n title: \"Data Annotation\",\n description:\n \"Multimodal workflows for image, video, and 3D annotation with high-accuracy quality control.\",\n\n video:\n \"https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779622196/new107_qhrklf.mp4\",\n\n card: {\n heading: \"Data Annotation\",\n badge: \"Live\",\n goal: \"Deploy multimodal AI data pipelines across multiple international regions.\",\n\n tasks: [\n {\n title: \"Regional onboarding\",\n meta: \"Completed in 4.2s\",\n status: \"completed\",\n },\n {\n title: \"Deploy collection teams\",\n meta: \"Completed in 8.1s\",\n status: \"completed\",\n },\n {\n title: \"Scale infrastructure\",\n meta: \"In progress... 18s\",\n status: \"progress\",\n },\n {\n title: \"Validate datasets\",\n meta: \"Pending\",\n status: \"pending\",\n },\n ],\n },\n },\n\n {\n icon: Lock,\n label: \"Data Collection\",\n title: \"Data Collection\",\n description:\n \"High-speed multimodal data collection pipelines to capture and structure real-world datasets.\",\n\n video:\n \"https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779621768/new105_meaomd.mp4\",\n\n card: {\n heading: \"Data Collection\",\n badge: \"Data-Ready\",\n goal: \"Prepare large-scale datasets for training multimodal reasoning systems.\",\n\n tasks: [\n {\n title: \"Process raw data\",\n meta: \"Completed in 3.1s\",\n status: \"completed\",\n },\n {\n title: \"Generate annotations\",\n meta: \"Completed in 5.4s\",\n status: \"completed\",\n },\n {\n title: \"Train reasoning model\",\n meta: \"In progress... 24s\",\n status: \"progress\",\n },\n {\n title: \"Run evaluation tests\",\n meta: \"Pending\",\n status: \"pending\",\n },\n ],\n },\n },\n\n {\n icon: Mic,\n label: \"Audio and Speech\",\n title: \"Audio and Speech\",\n description:\n \"Automation-first AI systems with human validation and scalable workflows.\",\n\n video:\n \"https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779622220/new108_k1a47m.mp4\",\n\n card: {\n heading: \"Audio Transcription\",\n badge: \"Auto-generated\",\n goal: \"Build a REST API endpoint for user authentication with JWT tokens.\",\n\n tasks: [\n {\n title: \"Gather requirements\",\n meta: \"Completed in 2.3s\",\n status: \"completed\",\n },\n {\n title: \"Research solutions\",\n meta: \"Completed in 5.1s\",\n status: \"completed\",\n },\n {\n title: \"Implement solution\",\n meta: \"In progress... 12s\",\n status: \"progress\",\n },\n {\n title: \"Test and validate\",\n meta: \"Pending\",\n status: \"pending\",\n },\n ],\n },\n },\n\n {\n icon: Database,\n label: \"Explainable AI\",\n title: \"Data Engine\",\n description:\n \"Transparent AI models with interpretable predictions and decision-making insights.\",\n\n video:\n \"https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779622271/02_u2efg7.mp4\",\n\n card: {\n heading: \"Pipeline Engine\",\n badge: \"Optimized\",\n goal: \"Process and validate multimodal datasets for enterprise deployment.\",\n\n tasks: [\n {\n title: \"Upload raw datasets\",\n meta: \"Completed in 1.9s\",\n status: \"completed\",\n },\n {\n title: \"Run QA workflows\",\n meta: \"Completed in 6.7s\",\n status: \"completed\",\n },\n {\n title: \"Generate metadata\",\n meta: \"In progress... 16s\",\n status: \"progress\",\n },\n {\n title: \"Export training package\",\n meta: \"Pending\",\n status: \"pending\",\n },\n ],\n },\n },\n]\n\nfunction TabMenu({\n activeTab,\n onSelect,\n className,\n}: {\n activeTab: number\n onSelect: (index: number) => void\n className?: string\n}) {\n return (\n \n
\n {items.map((tab, index) => {\n const Icon = tab.icon\n\n return (\n onSelect(index)}\n className={`group flex items-center gap-3 rounded-xl border px-4 py-3 text-left transition-all duration-300 ${\n activeTab === index\n ? \"border-[#266347] bg-[#f4fbf7]\"\n : \"border-transparent hover:border-[#266347] hover:bg-[#f8fffb]\"\n }`}\n >\n \n\n \n {tab.label}\n \n \n )\n })}\n
\n
\n )\n}\n\nexport default function ClippedImageSection() {\n const [activeTab, setActiveTab] = useState(0)\n\n const activeItem = items[activeTab]\n\n return (\n
\n
\n {/* TOP */}\n
\n
\n {/* LEFT */}\n
\n

\n Our Platforms\n

\n
\n\n {/* RIGHT */}\n
\n

\n Crafted for magicUI. A cinematic interface for modern digital\n products — designed and developed by Sameer.\n

\n
\n
\n
\n\n {/* TABS — in flow on mobile */}\n
\n \n
\n\n {/* MEDIA AREA */}\n
\n {/* TABS — overlay on desktop */}\n \n\n {/* VIDEO CONTAINER */}\n
\n {/* VIDEO */}\n \n \n \n\n {/* OVERLAY */}\n
\n\n {/* CENTER CARD */}\n
\n \n \n {/* HEADER */}\n
\n

\n {activeItem.card.heading}\n

\n\n \n {activeItem.card.badge}\n \n
\n\n {/* GOAL */}\n
\n

Goal

\n\n

\n {activeItem.card.goal}\n

\n
\n\n {/* TASKS */}\n
\n {activeItem.card.tasks.map((task, index) => (\n
\n {/* ICON */}\n
\n {task.status === \"completed\" && (\n \n )}\n\n {task.status === \"progress\" && (\n \n )}\n\n {task.status === \"pending\" && (\n \n )}\n
\n\n {/* CONTENT */}\n
\n \n {task.title}\n

\n\n

{task.meta}

\n
\n
\n ))}\n
\n\n {/* FOOTER */}\n
\n 2/5 tasks complete\n\n Est. 45s remaining\n
\n \n
\n
\n
\n
\n
\n
\n )\n}\n", + "type": "registry:ui" + } + ] +} \ No newline at end of file diff --git a/apps/www/public/r/registry.json b/apps/www/public/r/registry.json index ce7754ff6..54c1bd03c 100644 --- a/apps/www/public/r/registry.json +++ b/apps/www/public/r/registry.json @@ -523,6 +523,21 @@ } ] }, + { + "name": "clipped-video-tab", + "type": "registry:ui", + "title": "Clipped Video Tab", + "description": "A full-width tabbed section with clipped video backgrounds and animated content cards.", + "dependencies": [ + "framer-motion" + ], + "files": [ + { + "path": "registry/magicui/clipped-video-tab.tsx", + "type": "registry:ui" + } + ] + }, { "name": "bento-grid", "type": "registry:ui", @@ -1348,6 +1363,21 @@ } ] }, + { + "name": "clipped-video-tab-demo", + "type": "registry:example", + "title": "Clipped Video Tab Demo", + "description": "Clipped video tab demo", + "registryDependencies": [ + "@magicui/clipped-video-tab" + ], + "files": [ + { + "path": "registry/example/clipped-video-tab-demo.tsx", + "type": "registry:example" + } + ] + }, { "name": "magic-card-demo", "type": "registry:example", diff --git a/apps/www/public/r/tweet-card.json b/apps/www/public/r/tweet-card.json index d59c5c933..a3b1f98c2 100644 --- a/apps/www/public/r/tweet-card.json +++ b/apps/www/public/r/tweet-card.json @@ -10,7 +10,7 @@ "files": [ { "path": "registry/magicui/tweet-card.tsx", - "content": "import { 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 \n \n \n \n \n \n)\n\nconst Verified = ({ className, ...props }: TwitterIconProps) => (\n \n \n \n \n \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) => {\n return (\n
\n )\n}\n\nexport const TweetSkeleton = ({\n className,\n ...props\n}: {\n className?: string\n [key: string]: unknown\n}) => (\n \n
\n \n \n
\n \n
\n)\n\nexport const TweetNotFound = ({\n className,\n ...props\n}: {\n className?: string\n [key: string]: unknown\n}) => (\n \n

Tweet not found

\n \n)\n\nexport const TweetHeader = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\n
\n \n \n \n
\n \n {truncate(tweet.user.name, 20)}\n {tweet.user.verified ||\n (tweet.user.is_blue_verified && (\n \n ))}\n \n
\n \n @{truncate(tweet.user.screen_name, 16)}\n \n
\n
\n
\n \n Link to tweet\n \n \n
\n)\n\nexport const TweetBody = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\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 \n {entity.text}\n \n )\n case \"text\":\n return (\n \n )\n default:\n return null\n }\n })}\n
\n)\n\nexport const TweetMedia = ({ tweet }: { tweet: EnrichedTweet }) => {\n if (!tweet.video && !tweet.photos) return null\n return (\n
\n {tweet.video && (\n \n \n Your browser does not support the video tag.\n \n )}\n {tweet.photos && (\n
\n
\n {tweet.photos.map((photo) => (\n \n ))}\n
\n
\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 \n )}\n
\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 \n \n \n \n
\n )\n}\n\n/**\n * TweetCard (Server Side Only)\n */\nexport const TweetCard = async ({\n id,\n components,\n fallback = ,\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 \n }\n\n return (\n \n \n \n )\n}\n", + "content": "import { Suspense } from \"react\"\nimport { enrichTweet, type EnrichedTweet, type TweetProps } from \"react-tweet\"\nimport {\n getTweet,\n type QuotedTweet,\n type Tweet,\n type TweetEntities,\n} 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 \n \n \n \n \n \n)\n\nconst Verified = ({ className, ...props }: TwitterIconProps) => (\n \n \n \n \n \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) => {\n return (\n
\n )\n}\n\nexport const TweetSkeleton = ({\n className,\n ...props\n}: {\n className?: string\n [key: string]: unknown\n}) => (\n \n
\n \n \n
\n \n
\n)\n\nexport const TweetNotFound = ({\n className,\n ...props\n}: {\n className?: string\n [key: string]: unknown\n}) => (\n \n

Tweet not found

\n
\n)\n\nexport const TweetHeader = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\n
\n \n \n \n
\n \n {truncate(tweet.user.name, 20)}\n {tweet.user.verified ||\n (tweet.user.is_blue_verified && (\n \n ))}\n \n
\n \n @{truncate(tweet.user.screen_name, 16)}\n \n
\n
\n
\n \n Link to tweet\n \n \n
\n)\n\nexport const TweetBody = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\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 \n {entity.text}\n \n )\n case \"text\":\n return (\n \n )\n default:\n return null\n }\n })}\n
\n)\n\nexport const TweetMedia = ({ tweet }: { tweet: EnrichedTweet }) => {\n if (!tweet.video && !tweet.photos) return null\n return (\n
\n {tweet.video && (\n \n \n Your browser does not support the video tag.\n \n )}\n {tweet.photos && (\n
\n
\n {tweet.photos.map((photo) => (\n \n ))}\n
\n
\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 \n )}\n
\n )\n}\n\nconst EMPTY_TWEET_ENTITIES: TweetEntities = {\n hashtags: [],\n urls: [],\n user_mentions: [],\n symbols: [],\n}\n\n/** Syndication API responses sometimes omit entity arrays; react-tweet expects iterables. */\nfunction normalizeTweetEntities(tweet: T): T {\n const entities: TweetEntities = {\n ...EMPTY_TWEET_ENTITIES,\n ...tweet.entities,\n hashtags: tweet.entities?.hashtags ?? [],\n urls: tweet.entities?.urls ?? [],\n user_mentions: tweet.entities?.user_mentions ?? [],\n symbols: tweet.entities?.symbols ?? [],\n ...(tweet.entities?.media ? { media: tweet.entities.media } : {}),\n }\n\n const textLength = tweet.text?.length ?? 0\n\n const normalized = {\n ...tweet,\n entities,\n display_text_range: tweet.display_text_range ?? [0, textLength],\n }\n\n if (\"quoted_tweet\" in tweet && tweet.quoted_tweet) {\n return {\n ...normalized,\n quoted_tweet: normalizeTweetEntities(tweet.quoted_tweet),\n }\n }\n\n return normalized\n}\n\nexport const MagicTweet = ({\n tweet,\n className,\n ...props\n}: {\n tweet: Tweet\n className?: string\n}) => {\n const enrichedTweet = enrichTweet(normalizeTweetEntities(tweet))\n return (\n \n \n \n \n
\n )\n}\n\n/**\n * TweetCard (Server Side Only)\n */\nexport const TweetCard = async ({\n id,\n components,\n fallback = ,\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 \n }\n\n return (\n \n \n \n )\n}\n", "type": "registry:ui" } ] diff --git a/apps/www/public/registry.json b/apps/www/public/registry.json index ce7754ff6..54c1bd03c 100644 --- a/apps/www/public/registry.json +++ b/apps/www/public/registry.json @@ -523,6 +523,21 @@ } ] }, + { + "name": "clipped-video-tab", + "type": "registry:ui", + "title": "Clipped Video Tab", + "description": "A full-width tabbed section with clipped video backgrounds and animated content cards.", + "dependencies": [ + "framer-motion" + ], + "files": [ + { + "path": "registry/magicui/clipped-video-tab.tsx", + "type": "registry:ui" + } + ] + }, { "name": "bento-grid", "type": "registry:ui", @@ -1348,6 +1363,21 @@ } ] }, + { + "name": "clipped-video-tab-demo", + "type": "registry:example", + "title": "Clipped Video Tab Demo", + "description": "Clipped video tab demo", + "registryDependencies": [ + "@magicui/clipped-video-tab" + ], + "files": [ + { + "path": "registry/example/clipped-video-tab-demo.tsx", + "type": "registry:example" + } + ] + }, { "name": "magic-card-demo", "type": "registry:example", diff --git a/apps/www/registry.json b/apps/www/registry.json index ce7754ff6..54c1bd03c 100644 --- a/apps/www/registry.json +++ b/apps/www/registry.json @@ -523,6 +523,21 @@ } ] }, + { + "name": "clipped-video-tab", + "type": "registry:ui", + "title": "Clipped Video Tab", + "description": "A full-width tabbed section with clipped video backgrounds and animated content cards.", + "dependencies": [ + "framer-motion" + ], + "files": [ + { + "path": "registry/magicui/clipped-video-tab.tsx", + "type": "registry:ui" + } + ] + }, { "name": "bento-grid", "type": "registry:ui", @@ -1348,6 +1363,21 @@ } ] }, + { + "name": "clipped-video-tab-demo", + "type": "registry:example", + "title": "Clipped Video Tab Demo", + "description": "Clipped video tab demo", + "registryDependencies": [ + "@magicui/clipped-video-tab" + ], + "files": [ + { + "path": "registry/example/clipped-video-tab-demo.tsx", + "type": "registry:example" + } + ] + }, { "name": "magic-card-demo", "type": "registry:example", diff --git a/apps/www/registry/__index__.tsx b/apps/www/registry/__index__.tsx index c660e626b..9d9e8ad73 100644 --- a/apps/www/registry/__index__.tsx +++ b/apps/www/registry/__index__.tsx @@ -491,6 +491,23 @@ export const Index: Record = { }), meta: undefined, }, + "clipped-video-tab": { + name: "clipped-video-tab", + description: "A full-width tabbed section with clipped video backgrounds and animated content cards.", + type: "registry:ui", + registryDependencies: undefined, + files: [{ + path: "registry/magicui/clipped-video-tab.tsx", + type: "registry:ui", + target: "" + }], + component: React.lazy(async () => { + const mod = await import("@/registry/magicui/clipped-video-tab.tsx") + const exportName = Object.keys(mod).find(key => typeof mod[key] === 'function' || typeof mod[key] === 'object') ?? item.name + return { default: mod.default ?? mod[exportName] } + }), + meta: undefined, + }, "bento-grid": { name: "bento-grid", description: "Bento grid is a layout used to showcase the features of a product in a simple and elegant way.", @@ -1307,6 +1324,23 @@ export const Index: Record = { }), meta: undefined, }, + "clipped-video-tab-demo": { + name: "clipped-video-tab-demo", + description: "Clipped video tab demo", + type: "registry:example", + registryDependencies: ["@magicui/clipped-video-tab"], + files: [{ + path: "registry/example/clipped-video-tab-demo.tsx", + type: "registry:example", + target: "" + }], + component: React.lazy(async () => { + const mod = await import("@/registry/example/clipped-video-tab-demo.tsx") + const exportName = Object.keys(mod).find(key => typeof mod[key] === 'function' || typeof mod[key] === 'object') ?? item.name + return { default: mod.default ?? mod[exportName] } + }), + meta: undefined, + }, "magic-card-demo": { name: "magic-card-demo", description: "Example showing a spotlight effect that follows your mouse cursor and highlights borders on hover.", diff --git a/apps/www/registry/example/clipped-video-tab-demo.tsx b/apps/www/registry/example/clipped-video-tab-demo.tsx new file mode 100644 index 000000000..32364deeb --- /dev/null +++ b/apps/www/registry/example/clipped-video-tab-demo.tsx @@ -0,0 +1,5 @@ +import Component from "@/registry/magicui/clipped-video-tab" + +export default function ClippedVideoTabDemo() { + return +} diff --git a/apps/www/registry/magicui/clipped-video-tab.tsx b/apps/www/registry/magicui/clipped-video-tab.tsx new file mode 100644 index 000000000..47f0d5c2e --- /dev/null +++ b/apps/www/registry/magicui/clipped-video-tab.tsx @@ -0,0 +1,380 @@ +"use client" + +import { useState } from "react" +import { AnimatePresence, motion } from "framer-motion" +import { + Bot, + Brain, + BrainCircuit, + CheckCircle2, + Circle, + Cpu, + Database, + Globe, + LoaderCircle, + Lock, + Mic, + Zap, +} from "lucide-react" + +const items = [ + { + icon: Zap, + label: "2D/3D Annotation", + title: "Data Annotation", + description: + "Multimodal workflows for image, video, and 3D annotation with high-accuracy quality control.", + + video: + "https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779622196/new107_qhrklf.mp4", + + card: { + heading: "Data Annotation", + badge: "Live", + goal: "Deploy multimodal AI data pipelines across multiple international regions.", + + tasks: [ + { + title: "Regional onboarding", + meta: "Completed in 4.2s", + status: "completed", + }, + { + title: "Deploy collection teams", + meta: "Completed in 8.1s", + status: "completed", + }, + { + title: "Scale infrastructure", + meta: "In progress... 18s", + status: "progress", + }, + { + title: "Validate datasets", + meta: "Pending", + status: "pending", + }, + ], + }, + }, + + { + icon: Lock, + label: "Data Collection", + title: "Data Collection", + description: + "High-speed multimodal data collection pipelines to capture and structure real-world datasets.", + + video: + "https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779621768/new105_meaomd.mp4", + + card: { + heading: "Data Collection", + badge: "Data-Ready", + goal: "Prepare large-scale datasets for training multimodal reasoning systems.", + + tasks: [ + { + title: "Process raw data", + meta: "Completed in 3.1s", + status: "completed", + }, + { + title: "Generate annotations", + meta: "Completed in 5.4s", + status: "completed", + }, + { + title: "Train reasoning model", + meta: "In progress... 24s", + status: "progress", + }, + { + title: "Run evaluation tests", + meta: "Pending", + status: "pending", + }, + ], + }, + }, + + { + icon: Mic, + label: "Audio and Speech", + title: "Audio and Speech", + description: + "Automation-first AI systems with human validation and scalable workflows.", + + video: + "https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779622220/new108_k1a47m.mp4", + + card: { + heading: "Audio Transcription", + badge: "Auto-generated", + goal: "Build a REST API endpoint for user authentication with JWT tokens.", + + tasks: [ + { + title: "Gather requirements", + meta: "Completed in 2.3s", + status: "completed", + }, + { + title: "Research solutions", + meta: "Completed in 5.1s", + status: "completed", + }, + { + title: "Implement solution", + meta: "In progress... 12s", + status: "progress", + }, + { + title: "Test and validate", + meta: "Pending", + status: "pending", + }, + ], + }, + }, + + { + icon: Database, + label: "Explainable AI", + title: "Data Engine", + description: + "Transparent AI models with interpretable predictions and decision-making insights.", + + video: + "https://res.cloudinary.com/dy4bqxt8p/video/upload/v1779622271/02_u2efg7.mp4", + + card: { + heading: "Pipeline Engine", + badge: "Optimized", + goal: "Process and validate multimodal datasets for enterprise deployment.", + + tasks: [ + { + title: "Upload raw datasets", + meta: "Completed in 1.9s", + status: "completed", + }, + { + title: "Run QA workflows", + meta: "Completed in 6.7s", + status: "completed", + }, + { + title: "Generate metadata", + meta: "In progress... 16s", + status: "progress", + }, + { + title: "Export training package", + meta: "Pending", + status: "pending", + }, + ], + }, + }, +] + +function TabMenu({ + activeTab, + onSelect, + className, +}: { + activeTab: number + onSelect: (index: number) => void + className?: string +}) { + return ( +
+
+ {items.map((tab, index) => { + const Icon = tab.icon + + return ( + + ) + })} +
+
+ ) +} + +export default function ClippedImageSection() { + const [activeTab, setActiveTab] = useState(0) + + const activeItem = items[activeTab] + + return ( +
+
+ {/* TOP */} +
+
+ {/* LEFT */} +
+

+ Our Platforms +

+
+ + {/* RIGHT */} +
+

+ Crafted for magicUI. A cinematic interface for modern digital + products — designed and developed by Sameer. +

+
+
+
+ + {/* TABS — in flow on mobile */} +
+ +
+ + {/* MEDIA AREA */} +
+ {/* TABS — overlay on desktop */} +
+ +
+ + {/* VIDEO CONTAINER */} +
+ {/* VIDEO */} + + + + + {/* OVERLAY */} +
+ + {/* CENTER CARD */} +
+ + + {/* HEADER */} +
+

+ {activeItem.card.heading} +

+ + + {activeItem.card.badge} + +
+ + {/* GOAL */} +
+

Goal

+ +

+ {activeItem.card.goal} +

+
+ + {/* TASKS */} +
+ {activeItem.card.tasks.map((task, index) => ( +
+ {/* ICON */} +
+ {task.status === "completed" && ( + + )} + + {task.status === "progress" && ( + + )} + + {task.status === "pending" && ( + + )} +
+ + {/* CONTENT */} +
+

+ {task.title} +

+ +

{task.meta}

+
+
+ ))} +
+ + {/* FOOTER */} +
+ 2/5 tasks complete + + Est. 45s remaining +
+
+
+
+
+
+
+
+ ) +} diff --git a/apps/www/registry/magicui/tweet-card.tsx b/apps/www/registry/magicui/tweet-card.tsx index 899c5855a..c4c40cd51 100644 --- a/apps/www/registry/magicui/tweet-card.tsx +++ b/apps/www/registry/magicui/tweet-card.tsx @@ -1,6 +1,11 @@ import { Suspense } from "react" import { enrichTweet, type EnrichedTweet, type TweetProps } from "react-tweet" -import { getTweet, type Tweet } from "react-tweet/api" +import { + getTweet, + type QuotedTweet, + type Tweet, + type TweetEntities, +} from "react-tweet/api" import { cn } from "@/lib/utils" @@ -229,6 +234,43 @@ export const TweetMedia = ({ tweet }: { tweet: EnrichedTweet }) => { ) } +const EMPTY_TWEET_ENTITIES: TweetEntities = { + hashtags: [], + urls: [], + user_mentions: [], + symbols: [], +} + +/** Syndication API responses sometimes omit entity arrays; react-tweet expects iterables. */ +function normalizeTweetEntities(tweet: T): T { + const entities: TweetEntities = { + ...EMPTY_TWEET_ENTITIES, + ...tweet.entities, + hashtags: tweet.entities?.hashtags ?? [], + urls: tweet.entities?.urls ?? [], + user_mentions: tweet.entities?.user_mentions ?? [], + symbols: tweet.entities?.symbols ?? [], + ...(tweet.entities?.media ? { media: tweet.entities.media } : {}), + } + + const textLength = tweet.text?.length ?? 0 + + const normalized = { + ...tweet, + entities, + display_text_range: tweet.display_text_range ?? [0, textLength], + } + + if ("quoted_tweet" in tweet && tweet.quoted_tweet) { + return { + ...normalized, + quoted_tweet: normalizeTweetEntities(tweet.quoted_tweet), + } + } + + return normalized +} + export const MagicTweet = ({ tweet, className, @@ -237,7 +279,7 @@ export const MagicTweet = ({ tweet: Tweet className?: string }) => { - const enrichedTweet = enrichTweet(tweet) + const enrichedTweet = enrichTweet(normalizeTweetEntities(tweet)) return (
= 0.8'} @@ -3611,6 +3630,7 @@ packages: git-raw-commits@4.0.0: resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} engines: {node: '>=16'} + deprecated: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead. hasBin: true github-slugger@2.0.0: @@ -4537,9 +4557,15 @@ packages: motion-dom@12.23.23: resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==} + motion-dom@12.40.0: + resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==} + motion-utils@12.23.6: resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} + motion-utils@12.39.0: + resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==} + motion@12.23.26: resolution: {integrity: sha512-Ll8XhVxY8LXMVYTCfme27WH2GjBrCIzY4+ndr5QKxsK+YwCtOi2B/oBi5jcIbik5doXuWT/4KKDOVAZJkeY5VQ==} peerDependencies: @@ -9354,6 +9380,15 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) + framer-motion@12.40.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + motion-dom: 12.40.0 + motion-utils: 12.39.0 + tslib: 2.8.1 + optionalDependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + fresh@2.0.0: {} fs-extra@11.3.3: @@ -10694,8 +10729,14 @@ snapshots: dependencies: motion-utils: 12.23.6 + motion-dom@12.40.0: + dependencies: + motion-utils: 12.39.0 + motion-utils@12.23.6: {} + motion-utils@12.39.0: {} + motion@12.23.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: framer-motion: 12.23.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1)