项目文件夹

文件
Alexandru Paduraru b59da7127f registry build checks
2026-01-08 17:47:30 +02:00

26 行
10 KiB
JSON

{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "ecommerce-sections-02",
"description": "Luxury product detail page with image gallery",
"registryDependencies": [
"badge",
"button"
],
"files": [
{
"path": "creative-tim/blocks/ecommerce-sections-02/page.tsx",
"content": "\"use client\"\n\nimport { useState } from \"react\"\nimport {\n ChevronDown,\n MapPin,\n Package,\n Ruler,\n ShoppingBag,\n Star,\n} from \"lucide-react\"\n\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\n\nexport default function EcommerceSections02() {\n const [selectedImage, setSelectedImage] = useState(0)\n const [selectedColor, setSelectedColor] = useState(1)\n const [isInfoOpen, setIsInfoOpen] = useState(false)\n\n const thumbnails = [\n `${process.env.NEXT_PUBLIC_ASSET_PREFIX}/placeholder.svg?height=80&width=80&text=Bag+1`,\n `${process.env.NEXT_PUBLIC_ASSET_PREFIX}/placeholder.svg?height=80&width=80&text=Bag+2`,\n `${process.env.NEXT_PUBLIC_ASSET_PREFIX}/placeholder.svg?height=80&width=80&text=Detail`,\n `${process.env.NEXT_PUBLIC_ASSET_PREFIX}/placeholder.svg?height=80&width=80&text=Inside`,\n `${process.env.NEXT_PUBLIC_ASSET_PREFIX}/placeholder.svg?height=80&width=80&text=Model`,\n `${process.env.NEXT_PUBLIC_ASSET_PREFIX}/placeholder.svg?height=80&width=80&text=Lifestyle`,\n ]\n\n const colors = [\n { name: \"Black\", hex: \"#1a1a1a\" },\n { name: \"Cream\", hex: \"#f5f0e8\" },\n { name: \"Forest Green\", hex: \"#7d9488\" },\n { name: \"Gray\", hex: \"#9ca3af\" },\n { name: \"Navy Blue\", hex: \"#0f172a\" },\n { name: \"Brown\", hex: \"#a0522d\" },\n ]\n\n const features = [\n { icon: ShoppingBag, text: \"Crossbody style\" },\n { icon: Package, text: \"Premium leather\" },\n { icon: Ruler, text: \"Adjustable strap\" },\n { icon: MapPin, text: \"Crafted in France\" },\n ]\n\n return (\n <div className=\"min-h-screen bg-neutral-50 p-4 sm:p-8\">\n <div className=\"mx-auto max-w-7xl\">\n <div className=\"grid gap-8 lg:grid-cols-[auto_1fr_1fr] lg:gap-12\">\n <div className=\"hidden lg:flex lg:flex-col lg:gap-3\">\n {thumbnails.map((thumb, index) => (\n <button\n key={index}\n onClick={() => setSelectedImage(index)}\n className={`h-20 w-20 overflow-hidden rounded-lg border-2 transition-all ${\n selectedImage === index\n ? \"border-neutral-900\"\n : \"border-neutral-200 hover:border-neutral-400\"\n }`}\n >\n <img\n src={thumb}\n alt={`Product view ${index + 1}`}\n className=\"h-full w-full object-cover\"\n />\n </button>\n ))}\n </div>\n\n <div className=\"flex items-start justify-center\">\n <div className=\"w-full max-w-lg\">\n <div className=\"aspect-square overflow-hidden rounded-2xl bg-white\">\n <img\n src={thumbnails[selectedImage]}\n alt=\"Product main view\"\n className=\"h-full w-full object-cover\"\n />\n </div>\n <div className=\"mt-4 flex gap-2 lg:hidden\">\n {thumbnails.slice(0, 4).map((thumb, index) => (\n <button\n key={index}\n onClick={() => setSelectedImage(index)}\n className={`h-16 w-16 overflow-hidden rounded-lg border-2 ${\n selectedImage === index\n ? \"border-neutral-900\"\n : \"border-neutral-200\"\n }`}\n >\n <img\n src={thumb}\n alt={`Thumbnail ${index + 1}`}\n className=\"h-full w-full object-cover\"\n />\n </button>\n ))}\n </div>\n </div>\n </div>\n\n <div className=\"flex flex-col\">\n <Badge\n variant=\"outline\"\n className=\"mb-4 w-fit border-neutral-300 text-xs font-medium text-neutral-600\"\n >\n Trending Now\n </Badge>\n\n <h1 className=\"mb-2 text-3xl font-light tracking-tight text-neutral-900 sm:text-4xl\">\n Artisan Leather Crossbody\n </h1>\n\n <div className=\"mb-6 flex items-center gap-4\">\n <span className=\"text-2xl font-normal text-neutral-900\">\n $385.00\n </span>\n <div className=\"flex items-center gap-1\">\n <div className=\"flex\">\n {[...Array(5)].map((_, i) => (\n <Star\n key={i}\n className={`h-4 w-4 ${\n i < 4\n ? \"fill-neutral-900 text-neutral-900\"\n : \"fill-neutral-900 text-neutral-900\"\n }`}\n />\n ))}\n </div>\n <span className=\"text-sm text-neutral-500\">(4.7)</span>\n </div>\n </div>\n\n <div className=\"mb-6\">\n <p className=\"mb-3 text-sm font-medium text-neutral-900\">\n Color:{\" \"}\n <span className=\"font-normal\">\n {colors[selectedColor].name}\n </span>\n </p>\n <div className=\"flex gap-2\">\n {colors.map((color, index) => (\n <button\n key={index}\n onClick={() => setSelectedColor(index)}\n className={`h-10 w-10 rounded-md border-2 transition-all ${\n selectedColor === index\n ? \"border-neutral-900 ring-2 ring-neutral-900 ring-offset-2\"\n : \"border-neutral-200 hover:border-neutral-400\"\n }`}\n style={{ backgroundColor: color.hex }}\n title={color.name}\n />\n ))}\n </div>\n </div>\n\n <p className=\"mb-4 text-sm leading-relaxed text-neutral-600\">\n Elegant crossbody bag crafted from premium vegetable-tanned\n leather with a minimalist silhouette. Features a secure magnetic\n clasp closure, interior zip compartment, and an adjustable\n shoulder strap for versatile wear.\n </p>\n\n <p className=\"mb-6 text-sm text-neutral-600\">\n This is a demo store. To buy this product, visit{\" \"}\n <a\n href=\"#\"\n className=\"font-medium text-neutral-900 underline underline-offset-2 hover:text-neutral-700\"\n >\n Maison Atelier\n </a>{\" \"}\n official store.\n </p>\n\n <div className=\"mb-6 flex flex-col gap-3 sm:flex-row\">\n <Button\n variant=\"outline\"\n size=\"lg\"\n className=\"flex-1 border-neutral-900 text-neutral-900 hover:bg-neutral-900 hover:text-white\"\n >\n Add to Cart\n </Button>\n <Button\n size=\"lg\"\n className=\"flex-1 bg-neutral-900 text-white hover:bg-neutral-800\"\n >\n Buy it Now\n </Button>\n </div>\n\n <div className=\"mb-6 grid grid-cols-2 gap-3\">\n {features.map((feature, index) => (\n <div\n key={index}\n className=\"flex items-center gap-2 text-sm text-neutral-600\"\n >\n <feature.icon className=\"h-4 w-4\" />\n <span>{feature.text}</span>\n </div>\n ))}\n </div>\n\n <div className=\"border-t border-neutral-200\">\n <button\n onClick={() => setIsInfoOpen(!isInfoOpen)}\n className=\"flex w-full items-center justify-between py-4 text-sm font-medium text-neutral-900 hover:text-neutral-600\"\n >\n More Information\n <ChevronDown\n className={`h-4 w-4 transition-transform ${\n isInfoOpen ? \"rotate-180\" : \"\"\n }`}\n />\n </button>\n {isInfoOpen && (\n <div className=\"pb-4 text-sm leading-relaxed text-neutral-600\">\n <p className=\"mb-3\">\n <strong>Materials & Care:</strong> This bag is made from\n 100% full-grain vegetable-tanned leather that develops a\n beautiful patina over time. Clean with a soft, dry cloth and\n condition regularly with leather cream.\n </p>\n <p className=\"mb-3\">\n <strong>Dimensions:</strong> 9.5\" W x 7\" H x 3\" D. Strap\n drop adjustable from 20\" to 24\". Weight: 1.2 lbs.\n </p>\n <p>\n <strong>Shipping & Returns:</strong> Free standard shipping\n on orders over $200. 30-day return policy with original\n receipt and tags attached.\n </p>\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\n )\n}\n",
"type": "registry:page",
"target": "app/ecommerce-sections/page.tsx"
}
],
"meta": {
"iframeHeight": "900px",
"container": "w-full bg-surface min-h-svh flex px-4 py-12 items-center md:py-20 justify-center min-w-0",
"mobile": "component"
},
"categories": [
"ecommerce"
],
"type": "registry:block"
}