mirror of
https://github.com/vercel/commerce.git
synced 2025-05-19 07:56:59 +00:00
dynamic product description comonents
This commit is contained in:
parent
9db73341f5
commit
890d91eec7
@ -83,7 +83,7 @@ export default async function ProductPage({ params }: { params: { handle: string
|
|||||||
/>
|
/>
|
||||||
<div className="mx-auto max-w-screen-2xl px-4">
|
<div className="mx-auto max-w-screen-2xl px-4">
|
||||||
<div className="rounded-lg border border-neutral-200 bg-white p-8 px-4 dark:border-neutral-800 dark:bg-black md:p-12 lg:grid lg:grid-cols-6">
|
<div className="rounded-lg border border-neutral-200 bg-white p-8 px-4 dark:border-neutral-800 dark:bg-black md:p-12 lg:grid lg:grid-cols-6">
|
||||||
<div className="lg:col-span-4">
|
<div className="lg:col-span-3">
|
||||||
<Gallery
|
<Gallery
|
||||||
images={product.images.map((image: Image) => ({
|
images={product.images.map((image: Image) => ({
|
||||||
src: image.url,
|
src: image.url,
|
||||||
@ -92,10 +92,12 @@ export default async function ProductPage({ params }: { params: { handle: string
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-6 pr-8 md:pr-12 lg:col-span-2">
|
<div className="lg:col-span-3 lg:grid lg:grid-cols-6">
|
||||||
|
<div className="py-6 lg:col-span-4 lg:col-start-2">
|
||||||
<ProductDescription product={product} />
|
<ProductDescription product={product} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<RelatedProducts id={product.id} />
|
<RelatedProducts id={product.id} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
@ -38,8 +38,8 @@ export async function ThreeItemGrid() {
|
|||||||
const [firstProduct, secondProduct, thirdProduct] = homepageItems;
|
const [firstProduct, secondProduct, thirdProduct] = homepageItems;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="mx-auto grid max-w-screen-2xl gap-4 px-4 pb-4 lg:grid-cols-6 lg:grid-rows-2">
|
<section className="mx-auto grid max-w-screen-2xl gap-4 px-4 pb-4 lg:grid-cols-6 lg:grid-rows-6">
|
||||||
{firstProduct && <ThreeItemGridItem size="full" item={firstProduct} />}
|
{firstProduct && <ThreeItemGridItem size="half" item={firstProduct} />}
|
||||||
{secondProduct && <ThreeItemGridItem size="half" item={secondProduct} />}
|
{secondProduct && <ThreeItemGridItem size="half" item={secondProduct} />}
|
||||||
{thirdProduct && <ThreeItemGridItem size="half" item={thirdProduct} />}
|
{thirdProduct && <ThreeItemGridItem size="half" item={thirdProduct} />}
|
||||||
</section>
|
</section>
|
||||||
|
52
components/product/description-content.tsx
Normal file
52
components/product/description-content.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { SCAPE } from 'constants/brand';
|
||||||
|
import { productTypes } from 'constants/item-details';
|
||||||
|
import { credentials, credentialsKeys } from 'constants/sustainability';
|
||||||
|
import { Product } from 'lib/shopify/types';
|
||||||
|
|
||||||
|
export function DescriptionContent({ product }: { product: Product }) {
|
||||||
|
const productTypeKeys = Object.keys(productTypes);
|
||||||
|
const checkProductType = () => {
|
||||||
|
return product.tags.find(tag => productTypeKeys.includes(tag));
|
||||||
|
}
|
||||||
|
const productType = checkProductType() as keyof typeof productTypes & string;
|
||||||
|
|
||||||
|
const getCertificationId = (toFind: string) => credentialsKeys.find(key => key === toFind);
|
||||||
|
|
||||||
|
if (!productType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemDetails = productTypes[productType];
|
||||||
|
|
||||||
|
if (!itemDetails) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const certificationLink = (credType: keyof typeof credentials) => {
|
||||||
|
return <a className='text-underline' href={`#${getCertificationId(credType)}`}> {credentials[credType].title} certified</a>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="mt-6">
|
||||||
|
<h4 className='text-lg'>{product.title}, an exclusive artwork by {SCAPE}</h4>
|
||||||
|
<div>
|
||||||
|
<p className='font-bold mt-6'>Details:</p>
|
||||||
|
<ul className='list-disc list-inside'>
|
||||||
|
<li className='mt-2'>
|
||||||
|
{itemDetails.content},
|
||||||
|
{certificationLink('gots')}
|
||||||
|
</li>
|
||||||
|
<li className='mt-1'>
|
||||||
|
{itemDetails.print},
|
||||||
|
{certificationLink('oekoEco')}
|
||||||
|
</li>
|
||||||
|
<li className='mt-1'>{itemDetails.weight.feel} weight, {itemDetails.weight.gsm} GSM</li>
|
||||||
|
<li className='mt-1'>{itemDetails.fit} fit</li>
|
||||||
|
<li className='mt-1'>{itemDetails.style}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
};
|
@ -1,15 +1,16 @@
|
|||||||
import { AddToCart } from 'components/cart/add-to-cart';
|
import { AddToCart } from 'components/cart/add-to-cart';
|
||||||
import Price from 'components/price';
|
import Price from 'components/price';
|
||||||
import Prose from 'components/prose';
|
|
||||||
import { Product } from 'lib/shopify/types';
|
import { Product } from 'lib/shopify/types';
|
||||||
|
import { DescriptionContent } from './description-content';
|
||||||
|
import { SustainabilityInfo } from './sustainability-info';
|
||||||
import { VariantSelector } from './variant-selector';
|
import { VariantSelector } from './variant-selector';
|
||||||
|
|
||||||
export function ProductDescription({ product }: { product: Product }) {
|
export function ProductDescription({ product }: { product: Product }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mb-6 flex flex-col border-b pb-6 dark:border-neutral-700">
|
<div className="mb-6 flex flex-col border-b pb-6 dark:border-neutral-700">
|
||||||
<h1 className="mb-2 text-5xl font-medium">{product.title}</h1>
|
<h1 className="mb-2 text-4xl md:text-3xl font-medium">{product.title}</h1>
|
||||||
<div className="mr-auto w-auto rounded-full bg-blue-600 p-2 text-sm text-white">
|
<div className="place-self-end mr-auto w-auto rounded-full bg-blue-600 p-2 text-sm text-white">
|
||||||
<Price
|
<Price
|
||||||
amount={product.priceRange.maxVariantPrice.amount}
|
amount={product.priceRange.maxVariantPrice.amount}
|
||||||
currencyCode={product.priceRange.maxVariantPrice.currencyCode}
|
currencyCode={product.priceRange.maxVariantPrice.currencyCode}
|
||||||
@ -17,15 +18,10 @@ export function ProductDescription({ product }: { product: Product }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<VariantSelector options={product.options} variants={product.variants} />
|
<VariantSelector options={product.options} variants={product.variants} />
|
||||||
|
|
||||||
{product.descriptionHtml ? (
|
|
||||||
<Prose
|
|
||||||
className="mb-6 text-sm leading-tight dark:text-white/[60%]"
|
|
||||||
html={product.descriptionHtml}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<AddToCart variants={product.variants} availableForSale={product.availableForSale} />
|
<AddToCart variants={product.variants} availableForSale={product.availableForSale} />
|
||||||
|
|
||||||
|
<DescriptionContent product={product} />
|
||||||
|
<SustainabilityInfo />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
21
components/product/sustainability-info.tsx
Normal file
21
components/product/sustainability-info.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { credentials, credentialsKeys } from "constants/sustainability";
|
||||||
|
|
||||||
|
export function SustainabilityInfo() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<p className='font-bold mt-6'>Credentials:</p>
|
||||||
|
<ul className='mt-2'>
|
||||||
|
{credentialsKeys.map(credential => (
|
||||||
|
<li
|
||||||
|
key={credential}
|
||||||
|
id={credential}
|
||||||
|
>
|
||||||
|
{credentials[credential as keyof typeof credentials].title}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user