product page: initial layout

This commit is contained in:
andr-ew
2023-09-16 16:48:34 -05:00
parent 0eac0c50cb
commit 55d289451b
42 changed files with 1415 additions and 1095 deletions

View File

@@ -2,9 +2,77 @@ import Image from 'next/image';
import xss from 'xss';
import { getProducts, getProduct } from 'lib/shopify';
import { getProducts, getProduct } from 'commerce/shopify';
import styles from './styles.module.scss';
import PurchaseInput from '/components/product/purchase-input.js';
import { getTags, listTags } from '/util';
//TODO: NumberInput
const ImageScroll = ({ images }) => (
<div className={styles.imageScroll}>
<div className={styles.horizScroll}>
{images?.length > 1 && (
<p className={styles.scrollMessage}>Scroll to right ( )</p>
)}
<div className={styles.imageContainer}>
{images?.map(image => (
<Image
key={image?.url}
src={image?.url}
alt={image?.altText}
width={image?.width}
height={image?.height}
/>
))}
<div>
<div className={styles.spacer} />
</div>
</div>
</div>
</div>
);
const ProductPane = async ({ product }) => {
const tags = await getTags({ product });
return (
<div className={styles.productPane}>
{product?.handle ? (
<div className={styles.topBottom}>
<div className={styles.description}>
<h1>{product?.title}</h1>
{tags && tags.length > 0 && (
<h2 className={styles.collections}>
{listTags({ tags })}
</h2>
)}
<div
dangerouslySetInnerHTML={{
__html: xss(product.descriptionHtml),
}}
/>
</div>
<PurchaseInput product={product} />
</div>
) : (
<p>Product not found</p>
)}
</div>
);
};
export default async function ProductPage({ params: { handle } }) {
const product = await getProduct(handle);
return (
<div className={styles.productPage}>
<ImageScroll images={product.images} />
<ProductPane {...{ product }} />
</div>
);
}
export async function generateStaticParams() {
const products = await getProducts({
@@ -15,37 +83,3 @@ export async function generateStaticParams() {
return products.map(product => ({ product: product.handle }));
}
//TODO: NumberInput
export default async function ProductPage({ params: { handle } }) {
const product = await getProduct(handle);
return (
<>
{product?.handle ? (
<>
<h1>{product?.title}</h1>
<div
dangerouslySetInnerHTML={{
__html: xss(product.descriptionHtml),
}}
/>
<PurchaseInput product={product} />
</>
) : (
<p>Product not found</p>
)}
<p>Scroll to right ( )</p>
{product?.images?.map(image => (
<Image
key={image?.url}
src={image?.url}
alt={image?.altText}
width={image?.width}
height={image?.height}
/>
))}
</>
);
}

View File

@@ -0,0 +1,93 @@
@use 'styles/_spacing';
@use 'styles/_typography';
$spacer-width: calc(100vw - 100vh);
.imageScroll {
position: relative;
left: 0;
top: 0;
right: 0;
bottom: 0;
height: 0;
overflow-y: visible;
.horizScroll {
height: 100vh;
overflow-x: scroll;
position: relative;
.scrollMessage {
@include typography.subheader;
position: absolute;
left: 30px;
bottom: spacing.$page-bottom-baseline;
z-index: 3;
}
.imageContainer {
display: flex;
flex-direction: row;
height: 100%;
> * {
height: 100%;
width: auto;
}
img {
z-index: 2;
}
.spacer {
padding-right: $spacer-width;
height: 0;
}
}
}
}
.productPane {
padding-left: calc(calc(100vw - $spacer-width) + spacing.$grid-column-gap);
padding-right: spacing.$page-margin-x;
padding-top: 59px;
padding-bottom: spacing.$page-bottom-baseline;
height: 100vh;
.topBottom {
* {
z-index: 1;
}
height: 100%;
display: flex;
flex-direction: column;
.description {
@include typography.body-content;
}
}
}
.productPage {
position: absolute;
height: 100vh;
width: 100vw;
overflow: hidden;
}
.productPage {
position: absolute;
height: 100vh;
width: 100vw;
overflow: hidden;
}