117 lines
5.7 KiB
TypeScript
117 lines
5.7 KiB
TypeScript
import React from 'react';
|
|
import { useParams, Link } from 'react-router-dom';
|
|
import { motion } from 'framer-motion';
|
|
import { useStore } from '../src/context/StoreContext';
|
|
|
|
const ProductDetail: React.FC = () => {
|
|
const { slug } = useParams<{ slug: string }>();
|
|
const { products, addToCart } = useStore();
|
|
const product = products.find(item => item.slug === slug);
|
|
|
|
if (!product) {
|
|
return (
|
|
<div className="min-h-screen pt-32 flex flex-col items-center justify-center text-text-main dark:text-white">
|
|
<h2 className="text-4xl font-display mb-4">Product Not Found</h2>
|
|
<Link to="/collections" className="underline hover:text-stone-500">Return to Shop</Link>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="bg-white dark:bg-stone-950 min-h-screen pt-32 pb-24">
|
|
<div className="max-w-[1920px] mx-auto px-6 md:px-12">
|
|
{/* Breadcrumb */}
|
|
<div className="mb-12 text-sm uppercase tracking-widest text-stone-500">
|
|
<Link to="/collections" className="hover:text-text-main dark:hover:text-white transition-colors">Shop</Link>
|
|
<span className="mx-2">/</span>
|
|
<span className="text-text-main dark:text-white">{product.title}</span>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 xl:gap-24">
|
|
{/* Images Column */}
|
|
<div className="space-y-4">
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className="aspect-[4/5] w-full overflow-hidden bg-stone-100 rounded-sm"
|
|
>
|
|
<img
|
|
src={product.image}
|
|
alt={product.title}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</motion.div>
|
|
{/* Additional images grid */}
|
|
<div className="grid grid-cols-2 gap-4">
|
|
{product.images?.slice(1).map((img, idx) => (
|
|
<motion.div
|
|
key={idx}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ delay: 0.1 * (idx + 1) }}
|
|
className="aspect-square w-full overflow-hidden bg-stone-100 rounded-sm"
|
|
>
|
|
<img src={img} alt={`${product.title} detail ${idx + 1}`} className="w-full h-full object-cover" />
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Info Column */}
|
|
<div className="lg:sticky lg:top-32 h-fit">
|
|
<motion.h1
|
|
initial={{ opacity: 0, x: -20 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
className="font-display text-5xl md:text-7xl font-light text-text-main dark:text-white mb-6"
|
|
>
|
|
{product.title}
|
|
</motion.h1>
|
|
|
|
<motion.p
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
transition={{ delay: 0.1 }}
|
|
className="text-2xl font-light text-stone-600 dark:text-stone-300 mb-8"
|
|
>
|
|
${product.price}
|
|
</motion.p>
|
|
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
transition={{ delay: 0.2 }}
|
|
className="prose prose-stone dark:prose-invert max-w-none mb-12 font-light leading-relaxed text-lg"
|
|
>
|
|
<p>{product.description}</p>
|
|
<ul>
|
|
{product.details && product.details.map((detail, i) => (
|
|
<li key={i}>{detail}</li>
|
|
))}
|
|
<li>Made in Corpus Christi, TX</li>
|
|
</ul>
|
|
</motion.div>
|
|
|
|
<motion.button
|
|
initial={{ opacity: 0, y: 10 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ delay: 0.3 }}
|
|
onClick={() => addToCart(product)}
|
|
type="button"
|
|
className="w-full bg-text-main dark:bg-white text-white dark:text-text-main py-4 uppercase tracking-[0.2em] hover:bg-stone-800 dark:hover:bg-stone-200 transition-colors"
|
|
>
|
|
Add to Cart
|
|
</motion.button>
|
|
|
|
<div className="mt-12 pt-12 border-t border-stone-200 dark:border-stone-800 text-sm text-stone-500 font-light space-y-2">
|
|
<p>Free shipping on orders over $150</p>
|
|
<p>Ships within 3-5 business days</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ProductDetail;
|