{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chat-interface-testimonial",
  "dependencies": [
    "motion"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "../../packages/blocks/src/testimonial-section/chat-interface.tsx",
      "content": "'use client'\r\n\r\nimport { cn } from '@/lib/utils'\r\nimport React, { useState, useEffect } from 'react'\r\nimport { motion, AnimatePresence } from 'motion/react'\r\n\r\ninterface Message {\r\n  id: number\r\n  sender: string\r\n  avatar: string\r\n  text: string\r\n  side: 'left' | 'right'\r\n  time: string\r\n  reactions: string[]\r\n}\r\n\r\nconst messages: Message[] = [\r\n  {\r\n    id: 1,\r\n    sender: 'Emily Chen',\r\n    avatar:\r\n      'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop',\r\n    text: 'Just integrated the new grid system. Incredible work!',\r\n    side: 'left',\r\n    time: '2:34 PM',\r\n    reactions: ['👏', '🔥'],\r\n  },\r\n  {\r\n    id: 2,\r\n    sender: 'Team Lab',\r\n    avatar: 'TL',\r\n    text: 'So glad you like it Emily! Let us know if you need any help.',\r\n    side: 'right',\r\n    time: '2:35 PM',\r\n    reactions: ['❤️'],\r\n  },\r\n  {\r\n    id: 3,\r\n    sender: 'Markus T.',\r\n    avatar:\r\n      'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop',\r\n    text: 'The documentation is actually readable for once. Thank you.',\r\n    side: 'left',\r\n    time: '2:37 PM',\r\n    reactions: ['😄', '💯'],\r\n  },\r\n  {\r\n    id: 4,\r\n    sender: 'Emily Chen',\r\n    avatar:\r\n      'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop',\r\n    text: 'Btw, the dark mode tokens are perfect.',\r\n    side: 'left',\r\n    time: '2:38 PM',\r\n    reactions: ['✨'],\r\n  },\r\n  {\r\n    id: 5,\r\n    sender: 'Sarah K.',\r\n    avatar:\r\n      'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop',\r\n    text: 'Migration took 10 minutes. Best decision we made this quarter!',\r\n    side: 'left',\r\n    time: '2:40 PM',\r\n    reactions: ['🚀', '💪'],\r\n  },\r\n]\r\n\r\nconst TypingIndicator = () => (\r\n  <div className=\"flex gap-1 px-4 py-3\">\r\n    {[0, 1, 2].map((i) => (\r\n      <motion.div\r\n        key={i}\r\n        className=\"size-2 bg-zinc-400 rounded-full\"\r\n        animate={{ scale: [1, 1.2, 1], opacity: [0.5, 1, 0.5] }}\r\n        transition={{\r\n          duration: 1,\r\n          repeat: Infinity,\r\n          delay: i * 0.2,\r\n          ease: 'easeInOut',\r\n        }}\r\n      />\r\n    ))}\r\n  </div>\r\n)\r\n\r\nexport const ChatTestimonials: React.FC = () => {\r\n  const [visibleMessages, setVisibleMessages] = useState<number[]>([])\r\n  const [showTyping, setShowTyping] = useState(false)\r\n  const [activeReactions, setActiveReactions] = useState<Set<number>>(new Set())\r\n\r\n  useEffect(() => {\r\n    const showMessages = async () => {\r\n      for (let i = 0; i < messages.length; i++) {\r\n        // Show typing indicator\r\n        setShowTyping(true)\r\n        await new Promise((resolve) => setTimeout(resolve, 800))\r\n\r\n        // Hide typing and show message\r\n        setShowTyping(false)\r\n        setVisibleMessages((prev) => [...prev, i])\r\n\r\n        // Wait before next message\r\n        await new Promise((resolve) => setTimeout(resolve, 1200))\r\n      }\r\n    }\r\n\r\n    showMessages()\r\n  }, [])\r\n\r\n  const toggleReaction = (messageId: number) => {\r\n    setActiveReactions((prev) => {\r\n      const newSet = new Set(prev)\r\n      if (newSet.has(messageId)) {\r\n        newSet.delete(messageId)\r\n      } else {\r\n        newSet.add(messageId)\r\n      }\r\n      return newSet\r\n    })\r\n  }\r\n\r\n  return (\r\n    <section className=\"bg-zinc-100 min-h-screen px-4 font-manrope relative\">\r\n      <div className=\"max-w-7xl mx-auto py-16 relative z-10\">\r\n        {/* Header */}\r\n        <div className=\"text-center mb-16\">\r\n          <h2 className=\"text-5xl font-bold tracking-tight text-zinc-900 mb-4\">\r\n            Live Support Conversations\r\n          </h2>\r\n          <p className=\"text-lg text-zinc-600 max-w-3xl mx-auto\">\r\n            See real-time interactions between our support team and customers.\r\n            Experience the responsive, helpful communication that sets us apart.\r\n          </p>\r\n        </div>\r\n\r\n        {/* Two-column layout */}\r\n        <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-12 items-start\">\r\n          {/* Left Content */}\r\n          <div className=\"space-y-8\">\r\n            <motion.div\r\n              initial={{ opacity: 0, x: -20 }}\r\n              animate={{ opacity: 1, x: 0 }}\r\n              transition={{ duration: 0.6 }}\r\n              className=\"bg-white rounded-2xl p-8 border border-zinc-200 \"\r\n            >\r\n              <h3 className=\"text-2xl font-bold text-zinc-900 mb-4\">\r\n                Real Customer Experiences\r\n              </h3>\r\n              <p className=\"text-zinc-600 mb-6 leading-relaxed\">\r\n                Our support team is dedicated to providing exceptional\r\n                assistance. Watch as customers share their genuine experiences\r\n                and receive immediate, helpful responses.\r\n              </p>\r\n\r\n              <div className=\"space-y-4\">\r\n                <div className=\"flex items-center gap-3\">\r\n                  <div className=\"size-12 bg-green-100 rounded-full flex items-center justify-center\">\r\n                    <svg\r\n                      className=\"w-6 h-6 text-green-600\"\r\n                      fill=\"none\"\r\n                      stroke=\"currentColor\"\r\n                      viewBox=\"0 0 24 24\"\r\n                    >\r\n                      <path\r\n                        strokeLinecap=\"round\"\r\n                        strokeLinejoin=\"round\"\r\n                        strokeWidth={2}\r\n                        d=\"M13 10V3L4 14h7v7l9-11h-7z\"\r\n                      />\r\n                    </svg>\r\n                  </div>\r\n                  <div>\r\n                    <p className=\"font-semibold text-zinc-900\">\r\n                      Lightning Fast Response\r\n                    </p>\r\n                    <p className=\"text-sm text-zinc-600\">\r\n                      Average response time under 2 minutes\r\n                    </p>\r\n                  </div>\r\n                </div>\r\n\r\n                <div className=\"flex items-center gap-3\">\r\n                  <div className=\"size-12 bg-blue-100 rounded-full flex items-center justify-center\">\r\n                    <svg\r\n                      className=\"w-6 h-6 text-blue-600\"\r\n                      fill=\"none\"\r\n                      stroke=\"currentColor\"\r\n                      viewBox=\"0 0 24 24\"\r\n                    >\r\n                      <path\r\n                        strokeLinecap=\"round\"\r\n                        strokeLinejoin=\"round\"\r\n                        strokeWidth={2}\r\n                        d=\"M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z\"\r\n                      />\r\n                    </svg>\r\n                  </div>\r\n                  <div>\r\n                    <p className=\"font-semibold text-zinc-900\">\r\n                      24/7 Availability\r\n                    </p>\r\n                    <p className=\"text-sm text-zinc-600\">\r\n                      Always here when you need us\r\n                    </p>\r\n                  </div>\r\n                </div>\r\n\r\n                <div className=\"flex items-center gap-3\">\r\n                  <div className=\"size-12 bg-purple-100 rounded-full flex items-center justify-center\">\r\n                    <svg\r\n                      className=\"w-6 h-6 text-purple-600\"\r\n                      fill=\"none\"\r\n                      stroke=\"currentColor\"\r\n                      viewBox=\"0 0 24 24\"\r\n                    >\r\n                      <path\r\n                        strokeLinecap=\"round\"\r\n                        strokeLinejoin=\"round\"\r\n                        strokeWidth={2}\r\n                        d=\"M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z\"\r\n                      />\r\n                    </svg>\r\n                  </div>\r\n                  <div>\r\n                    <p className=\"font-semibold text-zinc-900\">\r\n                      Customer Satisfaction\r\n                    </p>\r\n                    <p className=\"text-sm text-zinc-600\">\r\n                      98% positive feedback rate\r\n                    </p>\r\n                  </div>\r\n                </div>\r\n              </div>\r\n            </motion.div>\r\n\r\n            <motion.div\r\n              initial={{ opacity: 0, x: -20 }}\r\n              animate={{ opacity: 1, x: 0 }}\r\n              transition={{ duration: 0.6, delay: 0.2 }}\r\n              className=\"grid grid-cols-3 gap-4\"\r\n            >\r\n              {[\r\n                { label: 'Response Rate', value: '98%' },\r\n                { label: 'Avg. Rating', value: '4.9★' },\r\n                { label: 'Active Users', value: '2.4k' },\r\n              ].map((stat, idx) => (\r\n                <motion.div\r\n                  key={idx}\r\n                  initial={{ opacity: 0, y: 10 }}\r\n                  animate={{ opacity: 1, y: 0 }}\r\n                  transition={{ delay: 0.3 + idx * 0.1 }}\r\n                  className=\"bg-white border border-zinc-200 rounded-xl p-4 text-center\"\r\n                >\r\n                  <p className=\"text-xl font-bold text-zinc-900\">\r\n                    {stat.value}\r\n                  </p>\r\n                  <p className=\"text-xs text-zinc-500 uppercase tracking-wider\">\r\n                    {stat.label}\r\n                  </p>\r\n                </motion.div>\r\n              ))}\r\n            </motion.div>\r\n          </div>\r\n\r\n          {/* Right - Chat Interface */}\r\n          <div className=\"lg:sticky lg:top-8\">\r\n            <div className=\"bg-white rounded-2xl border border-zinc-200  overflow-hidden\">\r\n              {/* Chat Header */}\r\n              <div className=\"bg-zinc-50 px-6 py-4 border-b border-zinc-200\">\r\n                <div className=\"flex items-center justify-between\">\r\n                  <div className=\"flex items-center gap-3\">\r\n                    <div className=\"relative\">\r\n                      <div className=\"size-3 bg-green-500 rounded-full animate-pulse\" />\r\n                      <div className=\"absolute inset-0 size-3 bg-green-500 rounded-full animate-ping opacity-75\" />\r\n                    </div>\r\n                    <div>\r\n                      <p className=\"font-semibold text-zinc-900\">\r\n                        Support Chat\r\n                      </p>\r\n                      <p className=\"text-xs text-zinc-500\">\r\n                        42 customers online\r\n                      </p>\r\n                    </div>\r\n                  </div>\r\n                  <div className=\"flex items-center gap-1\">\r\n                    {[1, 2, 3].map((i) => (\r\n                      <div\r\n                        key={i}\r\n                        className=\"size-1.5 bg-zinc-300 rounded-full\"\r\n                      />\r\n                    ))}\r\n                  </div>\r\n                </div>\r\n              </div>\r\n\r\n              {/* Messages */}\r\n              <div className=\"h-96 overflow-y-auto p-5 space-y-3\">\r\n                <AnimatePresence>\r\n                  {visibleMessages.map((index) => {\r\n                    const msg = messages[index]\r\n                    const showReactions = activeReactions.has(msg?.id || 0)\r\n\r\n                    return (\r\n                      <motion.div\r\n                        key={msg?.id}\r\n                        initial={{ opacity: 0, y: 20, scale: 0.95 }}\r\n                        animate={{ opacity: 1, y: 0, scale: 1 }}\r\n                        transition={{ duration: 0.4, ease: [0.32, 0.72, 0, 1] }}\r\n                        className={cn(\r\n                          'flex gap-2 max-w-[85%]',\r\n                          msg?.side === 'right'\r\n                            ? 'ml-auto flex-row-reverse'\r\n                            : 'mr-auto'\r\n                        )}\r\n                      >\r\n                        {/* Avatar */}\r\n                        <motion.div\r\n                          initial={{ scale: 0 }}\r\n                          animate={{ scale: 1 }}\r\n                          transition={{\r\n                            delay: 0.2,\r\n                            type: 'spring',\r\n                            stiffness: 500,\r\n                            damping: 25,\r\n                          }}\r\n                          className={cn(\r\n                            'size-8 rounded-full flex items-center justify-center text-xs font-bold shrink-0 overflow-hidden',\r\n                            msg?.side === 'right'\r\n                              ? 'bg-zinc-900 text-white'\r\n                              : 'bg-zinc-200'\r\n                          )}\r\n                        >\r\n                          {msg?.avatar.startsWith('http') ? (\r\n                            <img\r\n                              src={msg.avatar}\r\n                              alt={msg.sender}\r\n                              className=\"size-full object-cover\"\r\n                            />\r\n                          ) : (\r\n                            <span\r\n                              className={\r\n                                msg?.side === 'right'\r\n                                  ? 'text-white'\r\n                                  : 'text-zinc-900'\r\n                              }\r\n                            >\r\n                              {msg?.avatar}\r\n                            </span>\r\n                          )}\r\n                        </motion.div>\r\n\r\n                        {/* Message Content */}\r\n                        <div\r\n                          className={cn(\r\n                            'flex flex-col gap-1',\r\n                            msg?.side === 'right' ? 'items-end' : 'items-start'\r\n                          )}\r\n                        >\r\n                          {/* Sender Name */}\r\n                          <span className=\"text-xs text-zinc-500 font-medium px-1\">\r\n                            {msg?.sender}\r\n                          </span>\r\n\r\n                          {/* Message Bubble */}\r\n                          <div className=\"relative group\">\r\n                            <motion.div\r\n                              whileHover={{ scale: 1.02 }}\r\n                              className={cn(\r\n                                'px-4 py-2.5 rounded-2xl text-sm cursor-pointer transition-all',\r\n                                msg?.side === 'right'\r\n                                  ? 'bg-zinc-900 text-white rounded-tr-sm'\r\n                                  : 'bg-zinc-50 border border-zinc-200 text-zinc-900 rounded-tl-sm hover:border-zinc-300'\r\n                              )}\r\n                              onClick={() => toggleReaction(msg?.id || 0)}\r\n                            >\r\n                              {msg?.text}\r\n                            </motion.div>\r\n\r\n                            {/* Reactions */}\r\n                            <AnimatePresence>\r\n                              {showReactions && (\r\n                                <motion.div\r\n                                  initial={{ opacity: 0, scale: 0.8, y: 5 }}\r\n                                  animate={{ opacity: 1, scale: 1, y: 0 }}\r\n                                  exit={{ opacity: 0, scale: 0.8, y: 5 }}\r\n                                  transition={{ duration: 0.2 }}\r\n                                  className={cn(\r\n                                    'absolute -bottom-3 flex gap-0.5 bg-white border border-zinc-200 rounded-full px-2 py-0.5 ',\r\n                                    msg?.side === 'right' ? 'right-0' : 'left-0'\r\n                                  )}\r\n                                >\r\n                                  {msg?.reactions.map((reaction, idx) => (\r\n                                    <motion.span\r\n                                      key={idx}\r\n                                      initial={{ scale: 0 }}\r\n                                      animate={{ scale: 1 }}\r\n                                      transition={{\r\n                                        delay: idx * 0.05,\r\n                                        type: 'spring',\r\n                                        stiffness: 500,\r\n                                      }}\r\n                                      className=\"text-xs\"\r\n                                    >\r\n                                      {reaction}\r\n                                    </motion.span>\r\n                                  ))}\r\n                                </motion.div>\r\n                              )}\r\n                            </AnimatePresence>\r\n                          </div>\r\n\r\n                          {/* Timestamp */}\r\n                          <span className=\"text-[9px] text-zinc-400 font-medium px-1\">\r\n                            {msg?.time}\r\n                          </span>\r\n                        </div>\r\n                      </motion.div>\r\n                    )\r\n                  })}\r\n                </AnimatePresence>\r\n\r\n                {/* Typing Indicator */}\r\n                <AnimatePresence>\r\n                  {showTyping && (\r\n                    <motion.div\r\n                      initial={{ opacity: 0, y: 20 }}\r\n                      animate={{ opacity: 1, y: 0 }}\r\n                      exit={{ opacity: 0, y: -10 }}\r\n                      transition={{ duration: 0.3 }}\r\n                      className=\"flex gap-2 max-w-[85%] mr-auto\"\r\n                    >\r\n                      <div className=\"size-8 rounded-full overflow-hidden shrink-0\">\r\n                        <img\r\n                          src=\"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop\"\r\n                          alt=\"User typing\"\r\n                          className=\"size-full object-cover\"\r\n                        />\r\n                      </div>\r\n                      <div className=\"bg-zinc-50 border border-zinc-200 rounded-2xl rounded-tl-sm \">\r\n                        <TypingIndicator />\r\n                      </div>\r\n                    </motion.div>\r\n                  )}\r\n                </AnimatePresence>\r\n              </div>\r\n\r\n              {/* Chat Footer */}\r\n              <div className=\"bg-zinc-50 px-4 py-2 border-t border-zinc-200\">\r\n                <div className=\"flex items-center gap-3\">\r\n                  <input\r\n                    type=\"text\"\r\n                    placeholder=\"Type a message...\"\r\n                    className=\"flex-1 px-4 py-3 bg-white border border-zinc-200 rounded-full text-sm focus:outline-none focus:border-zinc-300\"\r\n                  />\r\n                  <button className=\"size-10 bg-zinc-900 text-white rounded-full flex items-center justify-center hover:bg-zinc-800 transition-colors\">\r\n                    <svg\r\n                      className=\"w-5 h-5\"\r\n                      fill=\"none\"\r\n                      stroke=\"currentColor\"\r\n                      viewBox=\"0 0 24 24\"\r\n                    >\r\n                      <path\r\n                        strokeLinecap=\"round\"\r\n                        strokeLinejoin=\"round\"\r\n                        strokeWidth={2}\r\n                        d=\"M12 19l9 2-9-18-9 18 9-2zm0 0v-8\"\r\n                      />\r\n                    </svg>\r\n                  </button>\r\n                </div>\r\n              </div>\r\n            </div>\r\n          </div>\r\n        </div>\r\n      </div>\r\n      <div className=\"absolute bottom-0 left-0 right-0 top-0 bg-[linear-gradient(to_right,#efefef_1px,transparent_1px),linear-gradient(to_bottom,#efefef_1px,transparent_1px)] bg-size-[6rem_4rem] mask-[radial-gradient(ellipse_80%_50%_at_50%_0%,#000_70%,transparent_110%)]\"></div>\r\n      <div className=\"absolute bottom-0 left-0 right-0 top-0 bg-[radial-gradient(125%_125%_at_50%_10%,rgba(255,255,255,0)_40%,rgba(237,218,50,1)_100%)]\"></div>\r\n    </section>\r\n  )\r\n}\r\n",
      "type": "registry:block"
    },
    {
      "path": "./components/ui/timeline-animation.tsx",
      "content": "import type { Variants } from 'motion/react';\nimport { type HTMLMotionProps, motion, useInView } from 'motion/react';\nimport type React from 'react';\n\ntype TimelineContentProps<T extends keyof HTMLElementTagNameMap> = {\n  children?: React.ReactNode;\n  animationNum: number;\n  className?: string;\n  timelineRef: React.RefObject<HTMLElement | null>;\n  as?: T;\n  customVariants?: Variants;\n  once?: boolean;\n} & HTMLMotionProps<T>;\n\nexport const TimelineAnimation = <T extends keyof HTMLElementTagNameMap = 'div'>({\n  children,\n  animationNum,\n  timelineRef,\n  className,\n  as,\n  customVariants,\n  once = true,\n  ...props\n}: TimelineContentProps<T>) => {\n  const defaultSequenceVariants = {\n    visible: (i: number) => ({\n      filter: 'blur(0px)',\n      y: 0,\n      opacity: 1,\n      transition: {\n        delay: i * 0.5,\n        duration: 0.5,\n      },\n    }),\n    hidden: {\n      filter: 'blur(20px)',\n      y: 0,\n      opacity: 0,\n    },\n  };\n\n  const sequenceVariants = customVariants || defaultSequenceVariants;\n\n  const isInView = useInView(timelineRef, {\n    once,\n  });\n\n  const MotionComponent = motion[as || 'div'] as React.ElementType;\n\n  return (\n    <MotionComponent\n      initial='hidden'\n      animate={isInView ? 'visible' : 'hidden'}\n      custom={animationNum}\n      variants={sequenceVariants}\n      className={className}\n      {...props}\n    >\n      {children}\n    </MotionComponent>\n  );\n};\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}