Seed: ecommerce template (24 files)

This commit is contained in:
2026-07-23 22:55:37 +00:00
parent f8ca687390
commit ea9e3cb144
+10 -10
View File
@@ -54,7 +54,7 @@ export default function ProductDetailPage() {
const renderStars = (count: number) => const renderStars = (count: number) =>
Array.from({ length: 5 }, (_, i) => ( Array.from({ length: 5 }, (_, i) => (
<Star key={i} className={`h-4 w-4 \${i < count ? "fill-amber-400 text-amber-400" : "text-stone-300"}`} /> <Star key={i} className={`h-4 w-4 ${i < count ? "fill-amber-400 text-amber-400" : "text-stone-300"}`} />
)); ));
const handleAddToCart = () => { const handleAddToCart = () => {
@@ -90,7 +90,7 @@ export default function ProductDetailPage() {
<div className="space-y-4"> <div className="space-y-4">
<Dialog> <Dialog>
<DialogTrigger asChild> <DialogTrigger asChild>
<div className={`aspect-square rounded-2xl bg-gradient-to-br \${thumbnails[selectedImage]} flex items-center justify-center text-stone-400 relative overflow-hidden animate-scale-in cursor-zoom-in group/zoom`}> <div className={`aspect-square rounded-2xl bg-gradient-to-br ${thumbnails[selectedImage]} flex items-center justify-center text-stone-400 relative overflow-hidden animate-scale-in cursor-zoom-in group/zoom`}>
<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 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-12 h-32 w-32 rounded-full bg-white/30 blur-2xl" /> <div className="absolute top-1/4 -left-12 h-32 w-32 rounded-full bg-white/30 blur-2xl" />
<div className="absolute bottom-1/4 -right-12 h-28 w-28 rounded-full bg-white/20 blur-2xl" /> <div className="absolute bottom-1/4 -right-12 h-28 w-28 rounded-full bg-white/20 blur-2xl" />
@@ -101,7 +101,7 @@ export default function ProductDetailPage() {
</div> </div>
</DialogTrigger> </DialogTrigger>
<DialogContent className="max-w-4xl p-0 border-0 overflow-hidden"> <DialogContent className="max-w-4xl p-0 border-0 overflow-hidden">
<div className={`w-full aspect-square bg-gradient-to-br \${thumbnails[selectedImage]} flex items-center justify-center text-stone-400 relative overflow-hidden`}> <div className={`w-full aspect-square bg-gradient-to-br ${thumbnails[selectedImage]} flex items-center justify-center text-stone-400 relative overflow-hidden`}>
<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 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-12 h-32 w-32 rounded-full bg-white/30 blur-2xl" /> <div className="absolute top-1/4 -left-12 h-32 w-32 rounded-full bg-white/30 blur-2xl" />
<div className="absolute bottom-1/4 -right-12 h-28 w-28 rounded-full bg-white/20 blur-2xl" /> <div className="absolute bottom-1/4 -right-12 h-28 w-28 rounded-full bg-white/20 blur-2xl" />
@@ -114,7 +114,7 @@ export default function ProductDetailPage() {
<button <button
key={i} key={i}
onClick={() => setSelectedImage(i)} onClick={() => setSelectedImage(i)}
className={`aspect-square rounded-lg bg-gradient-to-br \${grad} \${selectedImage === i ? "ring-2 ring-stone-900 ring-offset-2" : "opacity-60 hover:opacity-100"} transition-all`} className={`aspect-square rounded-lg bg-gradient-to-br ${grad} ${selectedImage === i ? "ring-2 ring-stone-900 ring-offset-2" : "opacity-60 hover:opacity-100"} transition-all`}
/> />
))} ))}
</div> </div>
@@ -149,7 +149,7 @@ export default function ProductDetailPage() {
<button <button
key={c.name} key={c.name}
onClick={() => setSelectedColor(c.name)} onClick={() => setSelectedColor(c.name)}
className={`h-9 w-9 rounded-full \${c.class} \${selectedColor === c.name ? "ring-2 ring-offset-2 ring-stone-900" : ""} transition-all`} className={`h-9 w-9 rounded-full ${c.class} ${selectedColor === c.name ? "ring-2 ring-offset-2 ring-stone-900" : ""} transition-all`}
title={c.name} title={c.name}
/> />
))} ))}
@@ -168,7 +168,7 @@ export default function ProductDetailPage() {
key={s} key={s}
variant={selectedSize === s ? "default" : "outline"} variant={selectedSize === s ? "default" : "outline"}
size="sm" size="sm"
className={`min-w-[3rem] \${selectedSize === s ? "bg-stone-900" : ""}`} className={`min-w-[3rem] ${selectedSize === s ? "bg-stone-900" : ""}`}
onClick={() => setSelectedSize(s)} onClick={() => setSelectedSize(s)}
> >
{s} {s}
@@ -194,8 +194,8 @@ export default function ProductDetailPage() {
<Button size="lg" className="flex-1 bg-stone-900 hover:bg-stone-800 rounded-full active:scale-[0.98] transition-all" onClick={handleAddToCart}> <Button size="lg" className="flex-1 bg-stone-900 hover:bg-stone-800 rounded-full active:scale-[0.98] transition-all" onClick={handleAddToCart}>
<ShoppingBag className="mr-2 h-4 w-4" /> Add to Cart <ShoppingBag className="mr-2 h-4 w-4" /> Add to Cart
</Button> </Button>
<Button variant="outline" size="icon" className={`h-11 w-11 rounded-full hover:scale-125 active:scale-90 transition-transform \${wishlisted ? "border-rose-300 bg-rose-50" : ""}`} onClick={() => { if (!wishlisted) toast.success("Added to wishlist!"); setWishlisted(!wishlisted); }}> <Button variant="outline" size="icon" className={`h-11 w-11 rounded-full hover:scale-125 active:scale-90 transition-transform ${wishlisted ? "border-rose-300 bg-rose-50" : ""}`} onClick={() => { if (!wishlisted) toast.success("Added to wishlist!"); setWishlisted(!wishlisted); }}>
<Heart className={`h-4 w-4 \${wishlisted ? "fill-rose-500 text-rose-500" : ""}`} /> <Heart className={`h-4 w-4 ${wishlisted ? "fill-rose-500 text-rose-500" : ""}`} />
</Button> </Button>
</div> </div>
@@ -283,7 +283,7 @@ export default function ProductDetailPage() {
{relatedProducts.map((product) => ( {relatedProducts.map((product) => (
<Link to="/product" key={product.id} className="group snap-start min-w-[250px]"> <Link to="/product" key={product.id} className="group snap-start min-w-[250px]">
<Card className="overflow-hidden border-0 shadow-sm hover:shadow-xl hover:-translate-y-1 transition-all duration-300"> <Card className="overflow-hidden border-0 shadow-sm hover:shadow-xl hover:-translate-y-1 transition-all duration-300">
<div className={`aspect-[3/4] bg-gradient-to-br \${product.gradient} flex items-center justify-center text-stone-400 text-xs relative overflow-hidden animate-scale-in`}> <div className={`aspect-[3/4] bg-gradient-to-br ${product.gradient} flex items-center justify-center text-stone-400 text-xs relative overflow-hidden animate-scale-in`}>
<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 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-24 w-24 rounded-full bg-white/30 blur-2xl" /> <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 bottom-1/4 -right-8 h-20 w-20 rounded-full bg-white/20 blur-2xl" />
@@ -292,7 +292,7 @@ export default function ProductDetailPage() {
<CardContent className="p-4"> <CardContent className="p-4">
<h3 className="font-medium text-sm group-hover:text-rose-600 transition-colors">{product.name}</h3> <h3 className="font-medium text-sm group-hover:text-rose-600 transition-colors">{product.name}</h3>
<div className="flex items-center gap-0.5 mt-1">{renderStars(product.rating)}</div> <div className="flex items-center gap-0.5 mt-1">{renderStars(product.rating)}</div>
<p className="mt-1.5 font-semibold">\${product.price}</p> <p className="mt-1.5 font-semibold">${product.price}</p>
</CardContent> </CardContent>
</Card> </Card>
</Link> </Link>