Seed: ecommerce template (24 files)

This commit is contained in:
2026-07-23 22:55:35 +00:00
parent 2d41d7ce06
commit f8ca687390
+16 -16
View File
@@ -80,7 +80,7 @@ export default function ProductsPage() {
const renderStars = (count: number) =>
Array.from({ length: 5 }, (_, i) => (
<Star key={i} className={`h-3 w-3 \${i < count ? "fill-amber-400 text-amber-400" : "text-stone-300"}`} />
<Star key={i} className={`h-3 w-3 ${i < count ? "fill-amber-400 text-amber-400" : "text-stone-300"}`} />
));
const Sidebar = () => (
@@ -113,7 +113,7 @@ export default function ProductsPage() {
<button
key={c.value}
onClick={() => toggleColor(c.value)}
className={`h-7 w-7 rounded-full \${c.class} \${selectedColors.includes(c.value) ? "ring-2 ring-offset-2 ring-rose-500" : ""} transition-all`}
className={`h-7 w-7 rounded-full ${c.class} ${selectedColors.includes(c.value) ? "ring-2 ring-offset-2 ring-rose-500" : ""} transition-all`}
title={c.name}
/>
))}
@@ -174,7 +174,7 @@ export default function ProductsPage() {
<div className="flex gap-8">
{/* Sidebar */}
<aside className={`w-56 shrink-0 \${showFilters ? "block" : "hidden"} lg:block`}>
<aside className={`w-56 shrink-0 ${showFilters ? "block" : "hidden"} lg:block`}>
<Sidebar />
</aside>
@@ -186,21 +186,21 @@ export default function ProductsPage() {
<DialogTrigger asChild>
<button className="group text-left w-full">
<Card className="overflow-hidden border-0 shadow-sm hover:shadow-xl hover:-translate-y-1 transition-all duration-300">
<div className={`relative aspect-[3/4] bg-gradient-to-br \${product.gradient} overflow-hidden`}>
<div className={`relative aspect-[3/4] bg-gradient-to-br ${product.gradient} overflow-hidden`}>
<div className="absolute inset-0 transition-transform duration-300 group-hover:scale-110 group-hover:brightness-110" style={{ backgroundImage: "radial-gradient(circle, rgba(0,0,0,0.06) 1px, transparent 1px)", backgroundSize: "16px 16px" }} />
<div className="absolute top-1/4 -left-8 h-24 w-24 rounded-full bg-white/30 blur-2xl" />
<div className="absolute bottom-1/4 -right-8 h-20 w-20 rounded-full bg-white/20 blur-2xl" />
<div className="absolute inset-0 flex items-center justify-center text-stone-400 text-xs transition-transform duration-300 group-hover:scale-110 group-hover:brightness-110">Image</div>
{product.badge && (
<Badge className={`absolute top-2 left-2 border-0 text-white text-xs \${product.badge === "Sale" ? "bg-rose-500" : "bg-stone-900"}`}>
<Badge className={`absolute top-2 left-2 border-0 text-white text-xs ${product.badge === "Sale" ? "bg-rose-500" : "bg-stone-900"}`}>
{product.badge}
</Badge>
)}
<span
onClick={(e) => { e.stopPropagation(); toggleWishlist(product.id); }}
className={`absolute top-2 right-2 h-7 w-7 rounded-full bg-white/80 backdrop-blur-sm flex items-center justify-center opacity-0 group-hover:opacity-100 transition-all hover:scale-125 active:scale-90 \${wishlist.includes(product.id) ? "!opacity-100" : ""}`}
className={`absolute top-2 right-2 h-7 w-7 rounded-full bg-white/80 backdrop-blur-sm flex items-center justify-center opacity-0 group-hover:opacity-100 transition-all hover:scale-125 active:scale-90 ${wishlist.includes(product.id) ? "!opacity-100" : ""}`}
>
<Heart className={`h-3.5 w-3.5 \${wishlist.includes(product.id) ? "fill-rose-500 text-rose-500" : "text-stone-600"}`} />
<Heart className={`h-3.5 w-3.5 ${wishlist.includes(product.id) ? "fill-rose-500 text-rose-500" : "text-stone-600"}`} />
</span>
<div className="absolute bottom-0 left-0 right-0 translate-y-full group-hover:translate-y-0 transition-transform duration-300 p-3"><Button className="w-full" size="sm">Quick Add</Button></div>
</div>
@@ -209,9 +209,9 @@ export default function ProductsPage() {
<div className="flex gap-1 mt-1 opacity-0 group-hover:opacity-100 transition-opacity"><span className="w-3 h-3 rounded-full bg-stone-900" /><span className="w-3 h-3 rounded-full bg-rose-400" /><span className="w-3 h-3 rounded-full bg-amber-200" /></div>
<div className="flex items-center gap-0.5 mt-1">{renderStars(product.rating)}</div>
<div className="mt-1.5 flex items-center gap-2">
<span className="font-semibold text-sm">\${product.price}</span>
<span className="font-semibold text-sm">${product.price}</span>
{product.originalPrice && (
<span className="text-xs text-stone-400 line-through">\${product.originalPrice}</span>
<span className="text-xs text-stone-400 line-through">${product.originalPrice}</span>
)}
</div>
<div className="flex items-center gap-1 mt-1"><div className="flex">{[...Array(5)].map((_, j) => <Star key={j} className="h-3 w-3 fill-amber-400 text-amber-400" />)}</div><span className="text-xs text-muted-foreground">(128)</span></div>
@@ -223,13 +223,13 @@ export default function ProductsPage() {
<DialogContent className="max-w-2xl p-0 overflow-hidden backdrop-blur-xl bg-white/80 dark:bg-slate-900/80 border-white/20">
<div className="grid md:grid-cols-2 gap-0">
{/* Product Image */}
<div className={`aspect-square bg-gradient-to-br \${product.gradient} relative`}>
<div className={`aspect-square bg-gradient-to-br ${product.gradient} relative`}>
<div className="absolute inset-0" style={{ backgroundImage: "radial-gradient(circle, rgba(0,0,0,0.06) 1px, transparent 1px)", backgroundSize: "16px 16px" }} />
<div className="absolute top-1/4 -left-8 h-32 w-32 rounded-full bg-white/30 blur-2xl" />
<div className="absolute bottom-1/4 -right-8 h-28 w-28 rounded-full bg-white/20 blur-2xl" />
<div className="absolute inset-0 flex items-center justify-center text-stone-400 text-sm">Product Image</div>
{product.badge && (
<Badge className={`absolute top-4 left-4 border-0 text-white \${product.badge === "Sale" ? "bg-rose-500" : "bg-stone-900"}`}>
<Badge className={`absolute top-4 left-4 border-0 text-white ${product.badge === "Sale" ? "bg-rose-500" : "bg-stone-900"}`}>
{product.badge}
</Badge>
)}
@@ -240,9 +240,9 @@ export default function ProductsPage() {
<h2 className="text-xl font-bold text-stone-900">{product.name}</h2>
<div className="flex items-center gap-0.5 mt-2">{renderStars(product.rating)}</div>
<div className="mt-3 flex items-center gap-3">
<span className="text-2xl font-bold">\${product.price}</span>
<span className="text-2xl font-bold">${product.price}</span>
{product.originalPrice && (
<span className="text-base text-stone-400 line-through">\${product.originalPrice}</span>
<span className="text-base text-stone-400 line-through">${product.originalPrice}</span>
)}
</div>
<p className="mt-3 text-sm text-stone-500 leading-relaxed">Premium quality crafted with the finest materials. Designed for comfort and style that lasts.</p>
@@ -254,7 +254,7 @@ export default function ProductsPage() {
<button
key={s}
onClick={() => setSelectedSize(s)}
className={`h-9 min-w-[2.5rem] px-3 rounded-md border text-sm font-medium transition-all \${selectedSize === s ? "border-stone-900 bg-stone-900 text-white" : "border-stone-200 hover:border-stone-400"}`}
className={`h-9 min-w-[2.5rem] px-3 rounded-md border text-sm font-medium transition-all ${selectedSize === s ? "border-stone-900 bg-stone-900 text-white" : "border-stone-200 hover:border-stone-400"}`}
>
{s}
</button>
@@ -264,7 +264,7 @@ export default function ProductsPage() {
<div className="mt-auto pt-4 space-y-2">
<Button
className="w-full bg-stone-900 hover:bg-stone-800 text-white rounded-full active:scale-[0.98] transition-all"
onClick={() => { if (!selectedSize) { toast.error("Please select a size"); return; } toast.success(`Added \${product.name} (size \${selectedSize}) to cart`); setQuickView(null); setSelectedSize(""); }}
onClick={() => { if (!selectedSize) { toast.error("Please select a size"); return; } toast.success(`Added ${product.name} (size ${selectedSize}) to cart`); setQuickView(null); setSelectedSize(""); }}
>
<ShoppingBag className="mr-2 h-4 w-4" /> Add to Cart
</Button>
@@ -285,7 +285,7 @@ export default function ProductsPage() {
<ChevronLeft className="h-4 w-4" />
</Button>
{[1, 2, 3].map((p) => (
<Button key={p} variant={page === p ? "default" : "outline"} size="icon" className={`h-9 w-9 \${page === p ? "bg-stone-900" : ""}`} onClick={() => setPage(p)}>
<Button key={p} variant={page === p ? "default" : "outline"} size="icon" className={`h-9 w-9 ${page === p ? "bg-stone-900" : ""}`} onClick={() => setPage(p)}>
{p}
</Button>
))}