{
  "name": "carousel-cards",
  "type": "registry:component",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "card",
    "badge",
    "button"
  ],
  "files": [
    {
      "type": "registry:component",
      "content": "\"use client\";\n\n/**\n * @author: @dorianbaffier\n * @description: Carousel Cards\n * @version: 1.0.0\n * @date: 2025-06-26\n * @license: MIT\n * @website: https://kokonutui.com\n * @github: https://github.com/kokonut-labs/kokonutui\n */\n\nimport { ChevronLeft, ChevronRight, Heart, Star } from \"lucide-react\";\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport React from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardFooter } from \"@/components/ui/card\";\n\ninterface ExperienceItem {\n  id: string;\n  title: string;\n  image: string;\n  location: string;\n  price: number;\n  currency?: string;\n  rating?: number;\n  reviewCount?: number;\n  badge?: string;\n  date?: string;\n}\n\ninterface ExperienceGridProps {\n  title: string;\n  items: ExperienceItem[];\n  viewAllHref?: string;\n}\n\nconst sampleExperiences: ExperienceItem[] = [\n  {\n    id: \"1\",\n    title: \"Become an Otaku Hottie with Megan Thee Stallion\",\n    image: \"https://images.unsplash.com/photo-1615571022219-eb45cf7faa9d\",\n    location: \"Los Angeles, United States\",\n    price: 120,\n    currency: \"€\",\n    rating: 4.97,\n    reviewCount: 128,\n    badge: \"Original\",\n    date: \"Closes May 21\",\n  },\n  {\n    id: \"2\",\n    title: \"Spend a Sunday Funday with Patrick Mahomes\",\n    image: \"https://images.unsplash.com/photo-1622127922040-13cab637ee78\",\n    location: \"Kansas City, United States\",\n    price: 150,\n    currency: \"€\",\n    rating: 4.92,\n    reviewCount: 86,\n    badge: \"Original\",\n    date: \"Closes Today\",\n  },\n  {\n    id: \"3\",\n    title: \"Celebrate with SEVENTEEN on their 10th anniversary\",\n    image: \"https://images.unsplash.com/photo-1534430480872-3498386e7856\",\n    location: \"Seoul, South Korea\",\n    price: 200,\n    currency: \"€\",\n    rating: 4.98,\n    reviewCount: 254,\n    badge: \"Original\",\n    date: \"Closed May 17\",\n  },\n  {\n    id: \"4\",\n    title: \"Learn the secrets of French pastry with nonnas\",\n    image: \"https://images.unsplash.com/photo-1604999333679-b86d54738315\",\n    location: \"Paris, France\",\n    price: 70,\n    currency: \"€\",\n    rating: 4.97,\n    reviewCount: 112,\n    badge: \"Original\",\n  },\n  {\n    id: \"5\",\n    title: \"Uncover the world of cabaret with a burlesque show\",\n    image: \"https://images.unsplash.com/photo-1552733407-5d5c46c3bb3b\",\n    location: \"Paris, France\",\n    price: 92,\n    currency: \"€\",\n    rating: 4.9,\n    reviewCount: 78,\n    badge: \"Original\",\n  },\n  {\n    id: \"6\",\n    title: \"The Super Powers of Art-family Game at the Louvre\",\n    image: \"https://images.unsplash.com/photo-1530789253388-582c481c54b0\",\n    location: \"Paris, France\",\n    price: 90,\n    currency: \"€\",\n    rating: 4.98,\n    reviewCount: 146,\n    badge: \"Original\",\n  },\n  {\n    id: \"7\",\n    title: \"Savor tasty vegan pastries with a plant-based pro\",\n    image: \"https://images.unsplash.com/photo-1608830597604-619220679440\",\n    location: \"Paris, France\",\n    price: 75,\n    currency: \"€\",\n    rating: 4.95,\n    reviewCount: 92,\n    badge: \"Original\",\n  },\n];\n\nconst popularExperiences: ExperienceItem[] = [\n  {\n    id: \"p1\",\n    title: \"Learn to bake the French Croissant\",\n    image: \"https://images.unsplash.com/photo-1555507036-ab1f4038808a\",\n    location: \"Paris, France\",\n    price: 95,\n    currency: \"€\",\n    rating: 4.95,\n    reviewCount: 218,\n    badge: \"Popular\",\n  },\n  {\n    id: \"p2\",\n    title: \"Seek out hidden speakeasy bars in the city\",\n    image: \"https://images.unsplash.com/photo-1470337458703-46ad1756a187\",\n    location: \"Paris, France\",\n    price: 74,\n    currency: \"€\",\n    rating: 4.9,\n    reviewCount: 165,\n    badge: \"Popular\",\n  },\n  {\n    id: \"p3\",\n    title: \"Versailles Food and Palace Bike Tour\",\n    image: \"https://images.unsplash.com/photo-1555507036-ab1f4038808a\",\n    location: \"Versailles, France\",\n    price: 122,\n    currency: \"€\",\n    rating: 4.97,\n    reviewCount: 89,\n    badge: \"Popular\",\n  },\n  {\n    id: \"p4\",\n    title: \"Haunted Paris Tour - Ghosts, Legends, True Crime\",\n    image: \"https://images.unsplash.com/photo-1549144511-f099e773c147\",\n    location: \"Paris, France\",\n    price: 25,\n    currency: \"€\",\n    rating: 4.98,\n    reviewCount: 345,\n    badge: \"Popular\",\n  },\n  {\n    id: \"p5\",\n    title: \"Learn to make the French macarons with a chef\",\n    image: \"https://images.unsplash.com/photo-1558326567-98ae2405596b\",\n    location: \"Paris, France\",\n    price: 110,\n    currency: \"€\",\n    rating: 4.95,\n    reviewCount: 203,\n    badge: \"Popular\",\n  },\n  {\n    id: \"p6\",\n    title: \"No Diet Club - Best food tour in Le Marais\",\n    image: \"https://images.unsplash.com/photo-1414235077428-338989a2e8c0\",\n    location: \"Paris, France\",\n    price: 65,\n    currency: \"€\",\n    rating: 4.92,\n    reviewCount: 178,\n    badge: \"5 spots left\",\n  },\n  {\n    id: \"p7\",\n    title: \"Soak up the nightlife of Paris\",\n    image: \"https://images.unsplash.com/photo-1546636889-ba9fdd63583e\",\n    location: \"Paris, France\",\n    price: 20,\n    currency: \"€\",\n    rating: 4.94,\n    reviewCount: 112,\n    badge: \"Popular\",\n  },\n];\n\nconst ExperienceCard = ({ experience }: { experience: ExperienceItem }) => (\n  <Card className=\"group relative flex h-[320px] w-full flex-col overflow-hidden rounded-xl border-0 shadow-sm transition-shadow duration-300 hover:shadow-md\">\n    <div className=\"relative aspect-[4/3] w-full overflow-hidden rounded-t-xl\">\n      <Image\n        alt={experience.title}\n        className=\"object-cover transition-transform duration-300 group-hover:scale-105\"\n        fill\n        src={experience.image}\n      />\n      <Button\n        className=\"absolute top-2 right-2 z-10 rounded-full bg-white/80 text-neutral-700 backdrop-blur-sm hover:bg-white/90 hover:text-black\"\n        size=\"icon\"\n        variant=\"ghost\"\n      >\n        <Heart className=\"h-4 w-4 stroke-[2px]\" />\n        <span className=\"sr-only\">Add to favorites</span>\n      </Button>\n      {experience.badge && (\n        <Badge className=\"absolute top-2 left-2 rounded-md bg-white/90 px-1.5 py-0.5 font-medium text-black text-xs\">\n          {experience.badge}\n        </Badge>\n      )}\n    </div>\n\n    <div className=\"flex flex-1 flex-col justify-between\">\n      <CardContent className=\"p-2 pt-3 pb-0\">\n        <h3 className=\"font-medium text-sm tracking-tight\">\n          {experience.title}\n        </h3>\n        <p className=\"text-muted-foreground text-xs tracking-tight\">\n          {experience.location}\n        </p>\n        {experience.date && (\n          <p className=\"text-muted-foreground text-xs tracking-tight\">\n            {experience.date}\n          </p>\n        )}\n      </CardContent>\n\n      <CardFooter className=\"mt-auto flex items-center gap-0.5 p-2 pt-0 text-xs\">\n        {experience.rating && (\n          <span className=\"flex items-center gap-0.5\">\n            <Star className=\"h-3 w-3 fill-current\" />\n            {experience.rating}\n          </span>\n        )}\n        {experience.reviewCount && (\n          <span className=\"text-muted-foreground text-xs tracking-tight\">\n            {experience.rating && \"·\"}\n            {experience.reviewCount > 0 ? ` (${experience.reviewCount})` : \"\"}\n          </span>\n        )}\n        <span className=\"ml-auto text-xs tracking-tight\">\n          {experience.currency || \"€\"} {experience.price} / guest\n        </span>\n      </CardFooter>\n    </div>\n  </Card>\n);\n\nconst ExperienceSection = ({\n  title,\n  items,\n  viewAllHref = \"#\",\n}: ExperienceGridProps) => {\n  const scrollContainer = React.useRef<HTMLDivElement>(null);\n\n  const handleScrollLeft = () => {\n    if (scrollContainer.current) {\n      scrollContainer.current.scrollBy({\n        left: -320,\n        behavior: \"smooth\",\n      });\n    }\n  };\n\n  const handleScrollRight = () => {\n    if (scrollContainer.current) {\n      scrollContainer.current.scrollBy({ left: 320, behavior: \"smooth\" });\n    }\n  };\n\n  return (\n    <div className=\"w-full py-4\">\n      <div className=\"mx-auto max-w-[1760px] px-4\">\n        <div className=\"mb-2 flex items-center justify-between\">\n          <h2 className=\"font-medium text-lg tracking-tight md:text-xl\">\n            {title}\n          </h2>\n          <div className=\"flex items-center gap-1\">\n            <Button\n              className=\"h-7 w-7 rounded-full border-neutral-200 hover:bg-neutral-100 dark:border-neutral-800 dark:hover:bg-neutral-900\"\n              onClick={handleScrollLeft}\n              size=\"icon\"\n              variant=\"outline\"\n            >\n              <ChevronLeft className=\"h-4 w-4\" />\n              <span className=\"sr-only\">Scroll left</span>\n            </Button>\n            <Button\n              className=\"h-7 w-7 rounded-full border-neutral-200 hover:bg-neutral-100 dark:border-neutral-800 dark:hover:bg-neutral-900\"\n              onClick={handleScrollRight}\n              size=\"icon\"\n              variant=\"outline\"\n            >\n              <ChevronRight className=\"h-4 w-4\" />\n              <span className=\"sr-only\">Scroll right</span>\n            </Button>\n            <Link\n              className=\"ml-1 hidden font-medium text-xs hover:underline md:block\"\n              href=\"#\"\n            >\n              Show all\n            </Link>\n          </div>\n        </div>\n\n        <div\n          className=\"scrollbar-hide -mx-1 flex snap-x snap-mandatory gap-3 overflow-x-auto px-1 pb-2\"\n          ref={scrollContainer}\n          style={{\n            scrollbarWidth: \"none\",\n            msOverflowStyle: \"none\",\n          }}\n        >\n          {items.map((item) => (\n            <div\n              className=\"w-[240px] flex-none snap-start md:w-[260px]\"\n              key={item.id}\n            >\n              <Link\n                className=\"block rounded-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2\"\n                href=\"#\"\n              >\n                <ExperienceCard experience={item} />\n              </Link>\n            </div>\n          ))}\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default function CarouselCards() {\n  return (\n    <div className=\"mt-4 w-full space-y-4\">\n      <ExperienceSection\n        items={sampleExperiences}\n        title=\"Airbnb Originals ›\"\n        viewAllHref=\"#\"\n      />\n      <ExperienceSection\n        items={popularExperiences}\n        title=\"Popular experiences in Paris\"\n        viewAllHref=\"#\"\n      />\n    </div>\n  );\n}\n",
      "path": "/components/kokonutui/carousel-cards.tsx",
      "target": "components/kokonutui/carousel-cards.tsx"
    }
  ]
}