Merge version_1 into main #6
@@ -3,9 +3,10 @@
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered";
|
||||
import FooterCard from "@/components/sections/footer/FooterCard";
|
||||
import { Instagram, Twitter, Youtube, ShoppingCart, Heart } from "lucide-react";
|
||||
import { Instagram, Twitter, Youtube, Heart, Share2, ShoppingCart } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
@@ -20,11 +21,56 @@ const TikTok = (props: React.SVGProps<SVGSVGElement>) => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
interface PageProps {
|
||||
params: { id: string };
|
||||
}
|
||||
const products: Record<
|
||||
string,
|
||||
{
|
||||
id: string;
|
||||
name: string;
|
||||
price: number;
|
||||
imageSrc: string;
|
||||
imageAlt: string;
|
||||
description: string;
|
||||
sizes: string[];
|
||||
colors: string[];
|
||||
specs: { label: string; value: string }[];
|
||||
}
|
||||
> = {
|
||||
"1": {
|
||||
id: "1", name: "Classic Black Hoodie", price: 89.99,
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/medium-shot-man-posing-with-hoodie-indoors_23-2149359859.jpg", imageAlt: "Classic black oversized hoodie", description:
|
||||
"Premium comfort meets timeless style with our Classic Black Hoodie. Crafted from 100% organic cotton, this essential piece features a relaxed fit perfect for everyday wear. The durable construction ensures it'll be a staple in your wardrobe for years to come.", sizes: ["XS", "S", "M", "L", "XL", "XXL"],
|
||||
colors: ["Black", "Gray", "Navy"],
|
||||
specs: [
|
||||
{ label: "Material", value: "100% Organic Cotton" },
|
||||
{ label: "Weight", value: "280g" },
|
||||
{ label: "Care", value: "Machine wash cold" },
|
||||
{ label: "Fit", value: "Relaxed" },
|
||||
],
|
||||
},
|
||||
"2": {
|
||||
id: "2", name: "Vintage Denim Jacket", price: 129.99,
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/fashionable-woman-wearing-denim-jacket_23-2148859621.jpg", imageAlt: "Vintage style denim jacket", description:
|
||||
"Elevate your streetwear game with our Vintage Denim Jacket. Featuring authentic distressing and premium indigo denim, this jacket adds instant character to any outfit. Perfect for layering or wearing standalone.", sizes: ["XS", "S", "M", "L", "XL"],
|
||||
colors: ["Indigo", "Light Blue", "Black"],
|
||||
specs: [
|
||||
{ label: "Material", value: "100% Cotton Denim" },
|
||||
{ label: "Weight", value: "650g" },
|
||||
{ label: "Care", value: "Wash separately" },
|
||||
{ label: "Fit", value: "Classic" },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default function ProductPage() {
|
||||
const params = useParams();
|
||||
const productId = params.id as string;
|
||||
const product = products[productId];
|
||||
|
||||
const [selectedSize, setSelectedSize] = useState(product?.sizes[2] || "");
|
||||
const [selectedColor, setSelectedColor] = useState(product?.colors[0] || "");
|
||||
const [quantity, setQuantity] = useState(1);
|
||||
const [isFavorited, setIsFavorited] = useState(false);
|
||||
|
||||
export default function ProductDetailPage({ params }: PageProps) {
|
||||
const navItems = [
|
||||
{ name: "Shop", id: "products" },
|
||||
{ name: "Collections", id: "collections" },
|
||||
@@ -33,32 +79,6 @@ export default function ProductDetailPage({ params }: PageProps) {
|
||||
{ name: "Contact", id: "contact" },
|
||||
];
|
||||
|
||||
const [quantity, setQuantity] = useState(1);
|
||||
const [selectedSize, setSelectedSize] = useState("M");
|
||||
const [selectedColor, setSelectedColor] = useState("Black");
|
||||
const [isFavorited, setIsFavorited] = useState(false);
|
||||
|
||||
const productId = params.id;
|
||||
|
||||
const products: Record<string, any> = {
|
||||
"1": {
|
||||
id: "1", name: "Classic Black Hoodie", price: 89.99,
|
||||
description: "Experience ultimate comfort with our signature Classic Black Hoodie. Crafted from premium cotton blend, this versatile piece is perfect for any casual occasion. Features a spacious front pocket and adjustable drawstrings.", imageSrc: "http://img.b2bpic.net/free-photo/medium-shot-man-posing-with-hoodie-indoors_23-2149359859.jpg", sizes: ["XS", "S", "M", "L", "XL", "XXL"],
|
||||
colors: ["Black", "Navy", "Charcoal"],
|
||||
rating: 4.8,
|
||||
reviews: 156,
|
||||
},
|
||||
"2": {
|
||||
id: "2", name: "Vintage Denim Jacket", price: 129.99,
|
||||
description: "Make a statement with our Vintage Denim Jacket. This timeless piece features authentic fading and distressing for that perfect worn-in look. Premium quality denim with reinforced stitching ensures durability.", imageSrc: "http://img.b2bpic.net/free-photo/fashionable-woman-wearing-denim-jacket_23-2148859621.jpg", sizes: ["XS", "S", "M", "L", "XL"],
|
||||
colors: ["Indigo", "Light Blue", "Black"],
|
||||
rating: 4.9,
|
||||
reviews: 203,
|
||||
},
|
||||
};
|
||||
|
||||
const product = products[productId] || products["1"];
|
||||
|
||||
const socialLinks = [
|
||||
{ icon: Instagram, href: "https://instagram.com/umbra", ariaLabel: "Instagram" },
|
||||
{ icon: Twitter, href: "https://twitter.com/umbra", ariaLabel: "Twitter" },
|
||||
@@ -66,6 +86,48 @@ export default function ProductDetailPage({ params }: PageProps) {
|
||||
{ icon: Youtube, href: "https://youtube.com/@umbra", ariaLabel: "YouTube" },
|
||||
];
|
||||
|
||||
if (!product) {
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="shift-hover"
|
||||
defaultTextAnimation="reveal-blur"
|
||||
borderRadius="soft"
|
||||
contentWidth="smallMedium"
|
||||
sizing="medium"
|
||||
background="circleGradient"
|
||||
cardStyle="glass-elevated"
|
||||
primaryButtonStyle="gradient"
|
||||
secondaryButtonStyle="glass"
|
||||
headingFontWeight="normal"
|
||||
>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarStyleCentered
|
||||
navItems={navItems}
|
||||
button={{ text: "View Cart", href: "/cart" }}
|
||||
brandName="Umbra"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<h1 className="text-4xl font-bold text-foreground mb-4">Product Not Found</h1>
|
||||
<Link href="/shop" className="text-accent hover:text-background-accent">
|
||||
Return to Shop
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterCard
|
||||
logoText="Umbra"
|
||||
copyrightText="© 2025 | Umbra Streetwear. All rights reserved."
|
||||
socialLinks={socialLinks}
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="shift-hover"
|
||||
@@ -87,124 +149,114 @@ export default function ProductDetailPage({ params }: PageProps) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="product" data-section="product" 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">
|
||||
← Back to Shop
|
||||
</Link>
|
||||
<div id="product" data-section="product" className="min-h-screen px-4 py-20">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<Link href="/shop" className="text-accent hover:text-background-accent mb-8 inline-block">
|
||||
← Back to Shop
|
||||
</Link>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-12">
|
||||
{/* Product Image */}
|
||||
<div className="flex items-center justify-center bg-card/50 border border-accent/20 rounded-soft p-8 aspect-square">
|
||||
<img
|
||||
src={product.imageSrc}
|
||||
alt={product.name}
|
||||
className="w-full h-full object-cover rounded"
|
||||
/>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
|
||||
<div className="flex items-center justify-center bg-card/30 rounded-soft overflow-hidden">
|
||||
<img
|
||||
src={product.imageSrc}
|
||||
alt={product.imageAlt}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col justify-center">
|
||||
<h1 className="text-5xl font-light text-foreground mb-4">{product.name}</h1>
|
||||
<p className="text-3xl font-bold text-background-accent mb-6">
|
||||
${product.price.toFixed(2)}
|
||||
</p>
|
||||
<p className="text-foreground/70 text-lg mb-8">{product.description}</p>
|
||||
|
||||
<div className="mb-8">
|
||||
<label className="block text-foreground font-semibold mb-3">Size</label>
|
||||
<div className="flex gap-3 flex-wrap">
|
||||
{product.sizes.map((size) => (
|
||||
<button
|
||||
key={size}
|
||||
onClick={() => setSelectedSize(size)}
|
||||
className={`px-4 py-2 rounded-soft border-2 transition-colors ${
|
||||
selectedSize === size
|
||||
? "bg-background-accent text-primary-cta-text border-background-accent"
|
||||
: "border-accent/30 text-foreground hover:border-accent"
|
||||
}`}
|
||||
>
|
||||
{size}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Product Details */}
|
||||
<div className="flex flex-col justify-center">
|
||||
<div className="mb-4">
|
||||
<h1 className="text-4xl font-bold text-foreground mb-2">{product.name}</h1>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-background-accent font-semibold">{product.rating}★</span>
|
||||
<span className="text-foreground/70 text-sm">({product.reviews} reviews)</span>
|
||||
</div>
|
||||
<div className="mb-8">
|
||||
<label className="block text-foreground font-semibold mb-3">Color</label>
|
||||
<div className="flex gap-3 flex-wrap">
|
||||
{product.colors.map((color) => (
|
||||
<button
|
||||
key={color}
|
||||
onClick={() => setSelectedColor(color)}
|
||||
className={`px-4 py-2 rounded-soft border-2 transition-colors ${
|
||||
selectedColor === color
|
||||
? "bg-background-accent text-primary-cta-text border-background-accent"
|
||||
: "border-accent/30 text-foreground hover:border-accent"
|
||||
}`}
|
||||
>
|
||||
{color}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
<span className="text-3xl font-bold text-background-accent">${product.price.toFixed(2)}</span>
|
||||
</div>
|
||||
|
||||
<p className="text-foreground/80 mb-8 leading-relaxed">{product.description}</p>
|
||||
|
||||
{/* Size Selection */}
|
||||
<div className="mb-6">
|
||||
<label className="block text-foreground font-semibold mb-3">Size</label>
|
||||
<div className="flex gap-3 flex-wrap">
|
||||
{product.sizes.map((size: string) => (
|
||||
<button
|
||||
key={size}
|
||||
onClick={() => setSelectedSize(size)}
|
||||
className={`px-4 py-2 border rounded-soft transition-colors ${
|
||||
selectedSize === size
|
||||
? "bg-background-accent text-primary-cta-text border-background-accent"
|
||||
: "border-accent/50 text-foreground hover:border-accent"
|
||||
}`}
|
||||
>
|
||||
{size}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Color Selection */}
|
||||
<div className="mb-6">
|
||||
<label className="block text-foreground font-semibold mb-3">Color</label>
|
||||
<div className="flex gap-3 flex-wrap">
|
||||
{product.colors.map((color: string) => (
|
||||
<button
|
||||
key={color}
|
||||
onClick={() => setSelectedColor(color)}
|
||||
className={`px-4 py-2 border rounded-soft transition-colors ${
|
||||
selectedColor === color
|
||||
? "bg-background-accent text-primary-cta-text border-background-accent"
|
||||
: "border-accent/50 text-foreground hover:border-accent"
|
||||
}`}
|
||||
>
|
||||
{color}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quantity Selection */}
|
||||
<div className="mb-8">
|
||||
<label className="block text-foreground font-semibold mb-3">Quantity</label>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-3 bg-accent/10 rounded-soft p-2 w-fit">
|
||||
<button
|
||||
onClick={() => setQuantity(Math.max(1, quantity - 1))}
|
||||
className="p-1 hover:bg-accent/20 rounded transition-colors"
|
||||
>
|
||||
<span className="text-foreground">−</span>
|
||||
</button>
|
||||
<span className="w-8 text-center text-foreground font-semibold">{quantity}</span>
|
||||
<button
|
||||
onClick={() => setQuantity(quantity + 1)}
|
||||
className="p-1 hover:bg-accent/20 rounded transition-colors"
|
||||
>
|
||||
<span className="text-foreground">+</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex gap-4 mb-8">
|
||||
<button className="flex-1 px-6 py-3 bg-background-accent text-primary-cta-text font-semibold rounded-soft hover:bg-primary-cta hover:text-primary-cta-text transition-colors flex items-center justify-center gap-2">
|
||||
<ShoppingCart size={20} />
|
||||
Add to Cart
|
||||
</button>
|
||||
<div className="mb-8">
|
||||
<label className="block text-foreground font-semibold mb-3">Quantity</label>
|
||||
<div className="flex items-center gap-4 w-fit bg-accent/10 rounded-soft p-2">
|
||||
<button
|
||||
onClick={() => setIsFavorited(!isFavorited)}
|
||||
className={`px-6 py-3 border rounded-soft font-semibold transition-colors ${
|
||||
isFavorited
|
||||
? "bg-background-accent/10 border-background-accent text-background-accent"
|
||||
: "border-accent/50 text-foreground hover:border-accent"
|
||||
}`}
|
||||
onClick={() => setQuantity(Math.max(1, quantity - 1))}
|
||||
className="px-3 py-1 hover:bg-accent/20 rounded transition-colors"
|
||||
>
|
||||
<Heart size={20} fill={isFavorited ? "currentColor" : "none"} />
|
||||
−
|
||||
</button>
|
||||
<span className="w-8 text-center font-semibold text-foreground">{quantity}</span>
|
||||
<button
|
||||
onClick={() => setQuantity(quantity + 1)}
|
||||
className="px-3 py-1 hover:bg-accent/20 rounded transition-colors"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Product Info */}
|
||||
<div className="space-y-3 text-foreground/70 text-sm border-t border-accent/20 pt-6">
|
||||
<p>✓ Free shipping on orders over $150</p>
|
||||
<p>✓ 30-day return policy</p>
|
||||
<p>✓ Premium quality guaranteed</p>
|
||||
<div className="flex gap-4 mb-8">
|
||||
<button className="flex-1 px-8 py-4 bg-background-accent text-primary-cta-text font-semibold rounded-soft hover:bg-primary-cta hover:text-primary-cta-text transition-colors flex items-center justify-center gap-2">
|
||||
<ShoppingCart size={20} />
|
||||
Add to Cart
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIsFavorited(!isFavorited)}
|
||||
className={`px-6 py-4 rounded-soft border-2 transition-colors ${
|
||||
isFavorited
|
||||
? "bg-accent/20 border-accent text-background-accent"
|
||||
: "border-accent/30 text-foreground hover:border-accent"
|
||||
}`}
|
||||
>
|
||||
<Heart size={20} fill={isFavorited ? "currentColor" : "none"} />
|
||||
</button>
|
||||
<button className="px-6 py-4 rounded-soft border-2 border-accent/30 text-foreground hover:border-accent transition-colors">
|
||||
<Share2 size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="bg-card/30 border border-accent/20 rounded-soft p-6">
|
||||
<h3 className="text-lg font-semibold text-foreground mb-4">Product Details</h3>
|
||||
<div className="space-y-3">
|
||||
{product.specs.map((spec, idx) => (
|
||||
<div key={idx} className="flex justify-between text-foreground/70">
|
||||
<span>{spec.label}:</span>
|
||||
<span className="font-semibold text-foreground">{spec.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user