{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"ecommerce-ecommerce-cross-sells-with-ratings","type":"registry:block","title":"With Ratings","files":[{"path":"components/blocks/ecommerce/ecommerce-cross-sells/with-ratings.tsx","content":"import { Star } from 'lucide-react';\nimport { Card, CardContent } from '@/components/ui/card';\n\ninterface Product {\n  id: string;\n  name: string;\n  price: number;\n  rating: number;\n  image: string;\n}\n\ninterface StarRatingProps {\n  rating: number;\n  maxStars?: number;\n}\n\nfunction StarRating({ rating, maxStars = 5 }: StarRatingProps) {\n  return (\n    <div className=\"flex items-center gap-0.5\">\n      {Array.from({ length: maxStars }, (_, index) => {\n        const starValue = index + 1;\n        const isFilled = starValue <= rating;\n        const isHalfFilled = starValue - 0.5 <= rating && starValue > rating;\n\n        return (\n          <Star\n            key={index}\n            className={`h-4 w-4 ${\n              isFilled\n                ? 'fill-yellow-400 text-yellow-400'\n                : isHalfFilled\n                  ? 'fill-yellow-400/50 text-yellow-400'\n                  : 'fill-muted text-muted-foreground'\n            }`}\n          />\n        );\n      })}\n    </div>\n  );\n}\n\ninterface ProductCardProps {\n  product: Product;\n}\n\nfunction ProductCard({ product }: ProductCardProps) {\n  return (\n    <Card className=\"group cursor-pointer p-0 transition-all duration-200 hover:shadow-md\">\n      <CardContent className=\"p-4\">\n        <div className=\"bg-muted relative mb-3 aspect-square overflow-hidden rounded-lg\">\n          <img\n            src={product.image || '/placeholder.svg'}\n            alt={product.name}\n            className=\"object-cover transition-transform duration-200 group-hover:scale-105\"\n          />\n        </div>\n        <div className=\"space-y-2\">\n          <h3 className=\"line-clamp-2 text-sm leading-tight font-medium\">\n            {product.name}\n          </h3>\n          <div className=\"flex items-center justify-between\">\n            <StarRating rating={product.rating} />\n            <span className=\"text-muted-foreground text-sm\">\n              ({product.rating})\n            </span>\n          </div>\n          <p className=\"text-lg font-semibold\">${product.price.toFixed(2)}</p>\n        </div>\n      </CardContent>\n    </Card>\n  );\n}\n\nconst sampleProducts: Product[] = [\n  {\n    id: '1',\n    name: 'Wireless Bluetooth Headphones',\n    price: 79.99,\n    rating: 4.5,\n    image: '/placeholder.svg?height=300&width=300',\n  },\n  {\n    id: '2',\n    name: 'Portable Phone Charger Power Bank',\n    price: 29.99,\n    rating: 4.2,\n    image: '/placeholder.svg?height=300&width=300',\n  },\n  {\n    id: '3',\n    name: 'USB-C Cable Fast Charging',\n    price: 12.99,\n    rating: 4.8,\n    image: '/placeholder.svg?height=300&width=300',\n  },\n];\n\nexport default function CrossSellWithRatings() {\n  return (\n    <div className=\"px-4 py-8 md:py-12\">\n      <div className=\"mx-auto max-w-6xl\">\n        <h2 className=\"text-muted-foreground mb-8 text-center text-xl font-semibold\">\n          You May Also Like\n        </h2>\n        <div className=\"grid grid-cols-2 gap-4 md:grid-cols-3 md:gap-6\">\n          {sampleProducts.map((product) => (\n            <ProductCard key={product.id} product={product} />\n          ))}\n        </div>\n      </div>\n    </div>\n  );\n}\n","type":"registry:component","target":"components/blocks/ecommerce/ecommerce-cross-sells/with-ratings.tsx"},{"path":"components/ui/card.tsx","content":"import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({\n  className,\n  size = \"default\",\n  ...props\n}: React.ComponentProps<\"div\"> & { size?: \"default\" | \"sm\" }) {\n  return (\n    <div\n      data-slot=\"card\"\n      data-size={size}\n      className={cn(\n        \"group/card flex flex-col gap-6 overflow-hidden rounded-xl bg-card py-6 text-sm text-card-foreground shadow-xs ring-1 ring-foreground/10 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-header\"\n      className={cn(\n        \"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-6 group-data-[size=sm]/card:px-4 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-6 group-data-[size=sm]/card:[.border-b]:pb-4\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-title\"\n      className={cn(\n        \"font-heading text-base leading-normal font-medium group-data-[size=sm]/card:text-sm\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-description\"\n      className={cn(\"text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-action\"\n      className={cn(\n        \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-content\"\n      className={cn(\"px-6 group-data-[size=sm]/card:px-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-footer\"\n      className={cn(\n        \"flex items-center rounded-b-xl px-6 group-data-[size=sm]/card:px-4 [.border-t]:pt-6 group-data-[size=sm]/card:[.border-t]:pt-4\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Card,\n  CardHeader,\n  CardFooter,\n  CardTitle,\n  CardAction,\n  CardDescription,\n  CardContent,\n}\n","type":"registry:ui","target":"components/ui/card.tsx"}],"description":"Recommended products shown with star ratings and review counts beside each price. Uses social proof to push complementary items into the cart.","dependencies":["lucide-react"]}