x
This commit is contained in:
1 parent
ef26b107ca
commit
07f04e2065
2 files changed
+86
-15
No files matched your search
@@ -7,6 +7,7 @@ import ReactMarkdown from 'react-markdown'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { getCategoryImage, type Product } from '@homaroma/types'
|
||||
import AddToCartSection from '@/components/AddToCartSection'
|
||||
import ProductGallery from '@/components/ProductGallery'
|
||||
import DynamicPageRenderer from '@/components/dynamic/DynamicPageRenderer'
|
||||
import ProductCard from '@/components/ProductCard'
|
||||
import { getCategoriesResult, getCmsPageResult, getProduct, getProductResult, getProductsResult } from '@/lib/cms'
|
||||
@@ -154,7 +155,7 @@ export default async function ProductDetailPage({ params }: { params: Promise<{
|
||||
{announcementSections.length > 0 && (
|
||||
<DynamicPageRenderer sections={announcementSections} categories={categories} lang={lang} />
|
||||
)}
|
||||
<div className="mx-auto max-w-7xl space-y-16 px-6 pt-32 pb-14 md:pt-40 md:pb-20">
|
||||
<div className="mx-auto max-w-7xl space-y-8 px-6 pt-28 pb-14 md:pt-32 md:pb-20">
|
||||
<nav className="flex flex-wrap items-center gap-2 text-xs font-semibold uppercase tracking-widest text-muted-text/70">
|
||||
<Link href="/" className="transition hover:text-brand-primary">Home</Link>
|
||||
<span>/</span>
|
||||
@@ -168,20 +169,11 @@ export default async function ProductDetailPage({ params }: { params: Promise<{
|
||||
</nav>
|
||||
|
||||
<section className="grid gap-10 md:grid-cols-2 md:gap-16">
|
||||
<div className="relative aspect-square overflow-hidden rounded-3xl bg-surface-card shadow-card">
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt={productName}
|
||||
fill
|
||||
priority={true}
|
||||
className="object-cover"
|
||||
/>
|
||||
{categoryName && (
|
||||
<div className="absolute left-5 top-5 rounded-full bg-surface-card/90 px-4 py-2 text-xs font-bold uppercase tracking-widest text-text-main shadow-sm">
|
||||
{categoryName}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ProductGallery
|
||||
images={product.images?.map(img => img.url) || [imageUrl]}
|
||||
productName={productName}
|
||||
categoryName={categoryName}
|
||||
/>
|
||||
|
||||
<AddToCartSection product={product} />
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import Image from 'next/image'
|
||||
|
||||
interface Props {
|
||||
productName: string
|
||||
categoryName?: string
|
||||
images: string[]
|
||||
}
|
||||
|
||||
export default function ProductGallery({ productName, categoryName, images }: Props) {
|
||||
const [activeIndex, setActiveIndex] = useState(0)
|
||||
|
||||
if (images.length === 0) return null
|
||||
|
||||
// If there's only one image, don't show thumbnails
|
||||
if (images.length === 1) {
|
||||
return (
|
||||
<div className="relative aspect-square w-full overflow-hidden rounded-3xl bg-surface-card shadow-card">
|
||||
<Image
|
||||
src={images[0]}
|
||||
alt={productName}
|
||||
fill
|
||||
priority={true}
|
||||
className="object-cover"
|
||||
/>
|
||||
{categoryName && (
|
||||
<div className="absolute left-5 top-5 rounded-full bg-surface-card/90 px-4 py-2 text-xs font-bold uppercase tracking-widest text-text-main shadow-sm pointer-events-none">
|
||||
{categoryName}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col-reverse md:flex-row items-start gap-4 w-full">
|
||||
{/* Thumbnails */}
|
||||
<div className="flex flex-row md:flex-col gap-3 overflow-x-auto md:overflow-y-auto w-full md:w-20 lg:w-24 flex-none hide-scrollbar snap-x md:snap-y snap-mandatory pb-2 md:pb-0 md:pr-2">
|
||||
{images.map((img, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
type="button"
|
||||
onClick={() => setActiveIndex(idx)}
|
||||
className={`relative aspect-square w-20 md:w-full flex-none overflow-hidden rounded-2xl border-2 transition-all snap-center ${
|
||||
activeIndex === idx ? 'border-brand-primary opacity-100' : 'border-transparent opacity-60 hover:opacity-100'
|
||||
}`}
|
||||
>
|
||||
<Image
|
||||
src={img}
|
||||
alt={`${productName} thumbnail ${idx + 1}`}
|
||||
fill
|
||||
unoptimized
|
||||
className="object-cover"
|
||||
/>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Main Image */}
|
||||
<div className="relative aspect-square w-full flex-1 overflow-hidden rounded-3xl bg-surface-card shadow-card">
|
||||
<Image
|
||||
key={activeIndex}
|
||||
src={images[activeIndex]}
|
||||
alt={productName}
|
||||
fill
|
||||
priority={true}
|
||||
className="object-cover animate-fade-in"
|
||||
/>
|
||||
{categoryName && (
|
||||
<div className="absolute left-5 top-5 rounded-full bg-surface-card/90 px-4 py-2 text-xs font-bold uppercase tracking-widest text-text-main shadow-sm pointer-events-none z-10">
|
||||
{categoryName}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user