|
|
|
|
@@ -3,11 +3,12 @@
|
|
|
|
|
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
|
|
|
|
import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered";
|
|
|
|
|
import FooterCard from "@/components/sections/footer/FooterCard";
|
|
|
|
|
import { Instagram, Twitter, Youtube } from "lucide-react";
|
|
|
|
|
import { Instagram, Twitter, Youtube, Heart, ShoppingCart, Minus, Plus } from "lucide-react";
|
|
|
|
|
import Link from "next/link";
|
|
|
|
|
import { useState } from "react";
|
|
|
|
|
import type { LucideIcon } from "lucide-react";
|
|
|
|
|
|
|
|
|
|
const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
|
|
|
|
|
const TikTok = (props: React.SVGProps<SVGSVGElement>): LucideIcon => (
|
|
|
|
|
<svg
|
|
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
width="24"
|
|
|
|
|
@@ -18,29 +19,9 @@ const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
|
|
|
|
|
>
|
|
|
|
|
<path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.68v13.67a2.4 2.4 0 1 1-2.4-2.4c.34 0 .67.03 1 .09V9.41a7.12 7.12 0 0 0-1-.08C5.89 9.33 2 13.46 2 18.13s3.88 8.81 8.74 8.81c4.65 0 8.6-3.36 8.6-7.53 0-.13 0-.26 0-.39a5.5 5.5 0 0 0-.56-1.78h.09c4.87 0 8.82-3.37 8.82-7.53 0-4.16-3.96-7.53-8.82-7.53z"/>
|
|
|
|
|
</svg>
|
|
|
|
|
) as unknown as LucideIcon;
|
|
|
|
|
|
|
|
|
|
const productDetails: { [key: string]: { name: string; price: number; image: string; description: string; sizes: string[]; colors: string[] } } = {
|
|
|
|
|
"1": {
|
|
|
|
|
name: "Classic Black Hoodie", price: 89.99,
|
|
|
|
|
image: "http://img.b2bpic.net/free-photo/medium-shot-man-posing-with-hoodie-indoors_23-2149359859.jpg", description: "Premium oversized hoodie crafted from 100% organic cotton. Perfect for layering or wearing solo. Features a kangaroo pocket and adjustable drawstrings. Comfortable, durable, and timeless.", sizes: ["XS", "S", "M", "L", "XL", "XXL"],
|
|
|
|
|
colors: ["Black", "Charcoal", "Navy", "White"],
|
|
|
|
|
},
|
|
|
|
|
"2": {
|
|
|
|
|
name: "Vintage Denim Jacket", price: 129.99,
|
|
|
|
|
image: "http://img.b2bpic.net/free-photo/fashionable-woman-wearing-denim-jacket_23-2148859621.jpg", description: "Authentic vintage-inspired denim jacket with a modern fit. Featuring button closure, multiple pockets, and classic denim construction. A versatile staple for any wardrobe.", sizes: ["XS", "S", "M", "L", "XL"],
|
|
|
|
|
colors: ["Indigo", "Light Blue", "Black"],
|
|
|
|
|
},
|
|
|
|
|
"3": {
|
|
|
|
|
name: "Cargo Pants - Khaki", price: 79.99,
|
|
|
|
|
image: "http://img.b2bpic.net/free-photo/young-woman-wearing-trucker-hat_23-2149432334.jpg", description: "Comfortable cargo pants with multiple pockets and adjustable straps. Perfect for everyday wear with a practical, streetwear aesthetic. Premium cotton blend fabric.", sizes: ["XS", "S", "M", "L", "XL", "XXL"],
|
|
|
|
|
colors: ["Khaki", "Black", "Olive"],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default function ProductPage({ params }: { params: { id: string } }) {
|
|
|
|
|
const product = productDetails[params.id as keyof typeof productDetails] || productDetails["1"];
|
|
|
|
|
) as any;
|
|
|
|
|
|
|
|
|
|
export default function ProductDetailPage() {
|
|
|
|
|
const navItems = [
|
|
|
|
|
{ name: "Shop", id: "products" },
|
|
|
|
|
{ name: "Collections", id: "collections" },
|
|
|
|
|
@@ -49,6 +30,28 @@ export default function ProductPage({ params }: { params: { id: string } }) {
|
|
|
|
|
{ name: "Contact", id: "contact" },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const [quantity, setQuantity] = useState(1);
|
|
|
|
|
const [isFavorite, setIsFavorite] = useState(false);
|
|
|
|
|
const [selectedSize, setSelectedSize] = useState("M");
|
|
|
|
|
const [selectedColor, setSelectedColor] = useState("Black");
|
|
|
|
|
|
|
|
|
|
const product = {
|
|
|
|
|
id: "1", name: "Classic Black Hoodie", price: 89.99,
|
|
|
|
|
originalPrice: 119.99,
|
|
|
|
|
rating: 4.8,
|
|
|
|
|
reviews: 128,
|
|
|
|
|
description: "Experience premium comfort with our Classic Black Hoodie. Crafted from high-quality materials, this versatile piece is perfect for any season. Features a spacious kangaroo pocket, drawstring hood, and relaxed fit that pairs well with any outfit.", images: [
|
|
|
|
|
"http://img.b2bpic.net/free-photo/medium-shot-man-posing-with-hoodie-indoors_23-2149359859.jpg", "http://img.b2bpic.net/free-photo/medium-shot-cool-man-with-electric-scooter_23-2149356776.jpg"],
|
|
|
|
|
sizes: ["XS", "S", "M", "L", "XL", "XXL"],
|
|
|
|
|
colors: ["Black", "Navy", "Gray", "Charcoal"],
|
|
|
|
|
specifications: [
|
|
|
|
|
{ label: "Material", value: "100% Premium Cotton" },
|
|
|
|
|
{ label: "Weight", value: "450 GSM" },
|
|
|
|
|
{ label: "Care", value: "Machine wash cold, tumble dry low" },
|
|
|
|
|
{ label: "Fit", value: "Relaxed fit" },
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const socialLinks: Array<{ icon: LucideIcon; href: string; ariaLabel: string }> = [
|
|
|
|
|
{ icon: Instagram, href: "https://instagram.com/umbra", ariaLabel: "Instagram" },
|
|
|
|
|
{ icon: Twitter, href: "https://twitter.com/umbra", ariaLabel: "Twitter" },
|
|
|
|
|
@@ -56,6 +59,14 @@ export default function ProductPage({ params }: { params: { id: string } }) {
|
|
|
|
|
{ icon: Youtube, href: "https://youtube.com/@umbra", ariaLabel: "YouTube" },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const handleAddToCart = () => {
|
|
|
|
|
console.log(`Added ${quantity} of ${product.name} (${selectedSize}, ${selectedColor}) to cart`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleToggleFavorite = () => {
|
|
|
|
|
setIsFavorite(!isFavorite);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<ThemeProvider
|
|
|
|
|
defaultButtonVariant="shift-hover"
|
|
|
|
|
@@ -77,7 +88,7 @@ export default function ProductPage({ params }: { params: { id: string } }) {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div id="product" data-section="product" className="mx-auto px-4 md:px-6">
|
|
|
|
|
<div id="product-detail" data-section="product-detail" className="mx-auto px-4 md:px-6">
|
|
|
|
|
<div className="py-20">
|
|
|
|
|
<div className="max-w-6xl mx-auto">
|
|
|
|
|
<Link href="/shop" className="text-accent hover:text-background-accent mb-8 inline-block">
|
|
|
|
|
@@ -85,37 +96,65 @@ export default function ProductPage({ params }: { params: { id: string } }) {
|
|
|
|
|
</Link>
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-12">
|
|
|
|
|
<div className="bg-card/30 rounded-soft overflow-hidden h-96 md:h-full">
|
|
|
|
|
<img src={product.image} alt={product.name} className="w-full h-full object-cover" />
|
|
|
|
|
{/* Product Images */}
|
|
|
|
|
<div>
|
|
|
|
|
<div className="bg-card border border-accent/20 rounded-soft p-4 mb-4">
|
|
|
|
|
<img
|
|
|
|
|
src={product.images[0]}
|
|
|
|
|
alt={product.name}
|
|
|
|
|
className="w-full h-auto rounded-soft object-cover"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="grid grid-cols-4 gap-4">
|
|
|
|
|
{product.images.map((img, idx) => (
|
|
|
|
|
<div
|
|
|
|
|
key={idx}
|
|
|
|
|
className="bg-card border border-accent/20 rounded-soft p-2 cursor-pointer hover:border-accent/50 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<img src={img} alt={`${product.name} ${idx + 1}`} className="w-full h-auto object-cover" />
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col justify-center">
|
|
|
|
|
{/* Product Details */}
|
|
|
|
|
<div>
|
|
|
|
|
<h1 className="text-4xl font-bold text-foreground mb-4">{product.name}</h1>
|
|
|
|
|
<p className="text-2xl font-semibold text-background-accent mb-6">${product.price.toFixed(2)}</p>
|
|
|
|
|
|
|
|
|
|
<p className="text-foreground/80 text-lg mb-8 leading-relaxed">{product.description}</p>
|
|
|
|
|
|
|
|
|
|
<div className="mb-8">
|
|
|
|
|
<h3 className="text-lg font-semibold text-foreground mb-4">Colors</h3>
|
|
|
|
|
<div className="flex gap-3">
|
|
|
|
|
{product.colors.map((color) => (
|
|
|
|
|
<button
|
|
|
|
|
key={color}
|
|
|
|
|
className="px-4 py-2 border border-accent/30 rounded-soft text-foreground hover:border-background-accent transition-colors"
|
|
|
|
|
>
|
|
|
|
|
{color}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center gap-4 mb-6">
|
|
|
|
|
<span className="text-3xl font-bold text-background-accent">${product.price}</span>
|
|
|
|
|
<span className="text-lg line-through text-foreground/50">${product.originalPrice}</span>
|
|
|
|
|
<span className="px-3 py-1 bg-background-accent/20 text-background-accent rounded-full text-sm font-semibold">
|
|
|
|
|
{Math.round(((product.originalPrice - product.price) / product.originalPrice) * 100)}% OFF
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="mb-8">
|
|
|
|
|
<h3 className="text-lg font-semibold text-foreground mb-4">Sizes</h3>
|
|
|
|
|
<div className="flex flex-wrap gap-3">
|
|
|
|
|
<div className="flex items-center gap-2 mb-8">
|
|
|
|
|
<div className="flex text-background-accent">
|
|
|
|
|
{[...Array(5)].map((_, i) => (
|
|
|
|
|
<span key={i}>★</span>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
<span className="text-foreground/70">
|
|
|
|
|
{product.rating} ({product.reviews} reviews)
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<p className="text-foreground/80 mb-8">{product.description}</p>
|
|
|
|
|
|
|
|
|
|
{/* Size Selection */}
|
|
|
|
|
<div className="mb-6">
|
|
|
|
|
<label className="block text-sm font-semibold text-foreground mb-3">Size</label>
|
|
|
|
|
<div className="grid grid-cols-6 gap-2">
|
|
|
|
|
{product.sizes.map((size) => (
|
|
|
|
|
<button
|
|
|
|
|
key={size}
|
|
|
|
|
className="px-4 py-2 border border-accent/30 rounded-soft text-foreground hover:border-background-accent transition-colors"
|
|
|
|
|
onClick={() => setSelectedSize(size)}
|
|
|
|
|
className={`py-2 rounded-soft font-semibold transition-colors ${
|
|
|
|
|
selectedSize === size
|
|
|
|
|
? "bg-background-accent text-primary-cta-text"
|
|
|
|
|
: "bg-card border border-accent/20 text-foreground hover:border-accent/50"
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
{size}
|
|
|
|
|
</button>
|
|
|
|
|
@@ -123,13 +162,76 @@ export default function ProductPage({ params }: { params: { id: string } }) {
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button className="px-8 py-4 bg-background-accent text-primary-cta-text font-semibold rounded-soft hover:bg-primary-cta transition-colors w-full mb-4">
|
|
|
|
|
Add to Cart
|
|
|
|
|
</button>
|
|
|
|
|
{/* Color Selection */}
|
|
|
|
|
<div className="mb-8">
|
|
|
|
|
<label className="block text-sm font-semibold text-foreground mb-3">Color</label>
|
|
|
|
|
<div className="flex gap-3">
|
|
|
|
|
{product.colors.map((color) => (
|
|
|
|
|
<button
|
|
|
|
|
key={color}
|
|
|
|
|
onClick={() => setSelectedColor(color)}
|
|
|
|
|
className={`px-4 py-2 rounded-soft font-semibold transition-colors ${
|
|
|
|
|
selectedColor === color
|
|
|
|
|
? "bg-background-accent text-primary-cta-text"
|
|
|
|
|
: "bg-card border border-accent/20 text-foreground hover:border-accent/50"
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
{color}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button className="px-8 py-4 border border-accent/50 text-foreground font-semibold rounded-soft hover:bg-accent/10 transition-colors w-full">
|
|
|
|
|
Save for Later
|
|
|
|
|
</button>
|
|
|
|
|
{/* Quantity & Buttons */}
|
|
|
|
|
<div className="flex gap-4 mb-8">
|
|
|
|
|
<div className="flex items-center gap-3 bg-card border border-accent/20 rounded-soft p-2">
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => setQuantity(Math.max(1, quantity - 1))}
|
|
|
|
|
className="p-2 hover:bg-accent/20 rounded transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<Minus size={18} className="text-foreground" />
|
|
|
|
|
</button>
|
|
|
|
|
<span className="w-8 text-center text-foreground font-semibold">{quantity}</span>
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => setQuantity(quantity + 1)}
|
|
|
|
|
className="p-2 hover:bg-accent/20 rounded transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<Plus size={18} className="text-foreground" />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleAddToCart}
|
|
|
|
|
className="flex-1 px-6 py-3 bg-background-accent text-primary-cta-text font-semibold rounded-soft hover:bg-primary-cta transition-colors flex items-center justify-center gap-2"
|
|
|
|
|
>
|
|
|
|
|
<ShoppingCart size={20} />
|
|
|
|
|
Add to Cart
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleToggleFavorite}
|
|
|
|
|
className={`px-6 py-3 rounded-soft font-semibold transition-colors ${
|
|
|
|
|
isFavorite
|
|
|
|
|
? "bg-background-accent/20 text-background-accent"
|
|
|
|
|
: "bg-card border border-accent/20 text-foreground hover:border-accent/50"
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
<Heart size={20} fill={isFavorite ? "currentColor" : "none"} />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Specifications */}
|
|
|
|
|
<div className="bg-card/50 border border-accent/20 rounded-soft p-6">
|
|
|
|
|
<h3 className="text-lg font-semibold text-foreground mb-4">Specifications</h3>
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
{product.specifications.map((spec, idx) => (
|
|
|
|
|
<div key={idx} className="flex justify-between">
|
|
|
|
|
<span className="text-foreground/70">{spec.label}</span>
|
|
|
|
|
<span className="font-semibold text-foreground">{spec.value}</span>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|