Skip to content

Commit

Permalink
Finish basic layout of product page
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminsehl committed May 22, 2024
1 parent ddd20d0 commit fbff023
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 75 deletions.
5 changes: 4 additions & 1 deletion app/components/hydrogen/Price.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Money} from '@shopify/hydrogen';
import {cx} from './new/cva.config';

export function Price({variant, ...props}) {
return <Money data={variant.price} {...props} />;
Expand All @@ -13,7 +14,9 @@ export function isDiscounted(price, compareAtPrice) {

export function PriceCompareAt({variant, ...props}) {
return isDiscounted(variant.price, variant.compareAtPrice) ? (
<Money data={variant.compareAtPrice} {...props} />
<span className={cx('strike', props.className)}>
<Money data={variant.compareAtPrice} {...props} />
</span>
) : null;
}

Expand Down
65 changes: 32 additions & 33 deletions app/components/hydrogen/ProductCard.jsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,45 @@
import clsx from 'clsx';
import {flattenConnection, Image, Money} from '@shopify/hydrogen';
import {flattenConnection, Image} from '@shopify/hydrogen';

import {Text} from '@h2/Text';
import Link from '@h2/Link';
import {Button, AddToCartButton} from '@h2/Button';
import {isDiscounted, isNewArrival} from '~/lib/utils';
import {Price, PriceCompareAt} from './Price';

export function ProductCard({
product,
label,
className,
loading,
onClick,
quickAdd,
}) {
let cardLabel;
export function ProductCard({product, className, loading, onClick, quickAdd}) {
product = {
handle: 'builders-tote',
title: 'Builders Tote',
variants: {
nodes: [
{
availableForSale: true,
price: {
amount: '38.00',
currencyCode: 'CAD',
},
compareAtPrice: {
amount: '42.00',
currencyCode: 'CAD',
},
image: {
id: 'gid://Shopify/placeholder/1234',
altText: 'Placeholder',
height: '600',
width: '400',
url: 'https://cdn.shopify.com/s/files/1/0657/3811/3197/files/builders-tote.png',
},
},
],
},
};

if (!product?.variants?.nodes?.length) return null;

const firstVariant = flattenConnection(product.variants)[0];

if (!firstVariant) return null;
const {image, price, compareAtPrice} = firstVariant;

if (label) {
cardLabel = label;
} else if (isDiscounted(price, compareAtPrice)) {
cardLabel = 'Sale';
} else if (isNewArrival(product.publishedAt)) {
cardLabel = 'New';
}
const {image} = firstVariant;

return (
<div className="flex flex-col gap-2">
Expand All @@ -50,13 +60,6 @@ export function ProductCard({
loading={loading}
/>
)}
<Text
as="label"
size="fine"
className="absolute top-0 right-0 m-4 text-right text-notice"
>
{cardLabel}
</Text>
</div>
<div className="grid gap-1">
<Text
Expand All @@ -67,12 +70,8 @@ export function ProductCard({
</Text>
<div className="flex gap-4">
<Text className="flex gap-4">
<Money withoutTrailingZeros data={price} />
{isDiscounted(price, compareAtPrice) && (
<span className="strike">
<Money className={'opacity-50'} data={compareAtPrice} />
</span>
)}
<Price variant={firstVariant} />
<PriceCompareAt className="opacity-80" variant={firstVariant} />
</Text>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/routes/products.$handle/route.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ export default function Product() {
<HighlightDetails />
<HighlightSolution />
<Reviews />
<Spotlight />
<Recommended />
<Spotlight />
</div>
);
}
Expand Down
36 changes: 24 additions & 12 deletions app/routes/products.$handle/sections/highlight-details.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,35 @@ import {Heading} from '~/components/hydrogen/Text';
export default function HighlightDetails() {
return (
<Section className="bg-darkGray items-center text-white min-h-[40vw]">
<Container>
<Container resizeY="fill">
<Grid resizeY="fill">
<Flex resizeY="fill" justify="center" direction="down" gap={8}>
<Flex direction="down" gap={4}>
<Flex resizeY="fill" justify="center" direction="down" gap={9}>
<Flex direction="down" gap={5}>
<Heading>Materials and care</Heading>
<ul>
<li>Recycled cotton tote.</li>
<li>Machine wash cold. Hang dry.</li>
</ul>
<Flex as="ul" gap={2} direction="down">
<Flex gap={4} as="li" className="flex items-center">
<span className="bg-accent inline-block w-10 h-[2px]" />
Recycled cotton tote.
</Flex>
<Flex gap={4} as="li" className="flex items-center">
<span className="bg-accent inline-block w-10 h-[2px]" />
Machine wash cold. Hang dry.
</Flex>
</Flex>
</Flex>

<Flex direction="down" gap={4}>
<Flex direction="down" gap={5}>
<Heading>Size</Heading>
<ul>
<li>16&quot; W x 15.5&quot; H x 3&quot; bottom gusst. </li>
<li>10&quot; handle drop length.</li>
</ul>
<Flex as="ul" gap={2} direction="down">
<Flex gap={4} as="li" className="flex items-center">
<span className="bg-accent inline-block w-10 h-[2px]" />
16&quot; W x 15.5&quot; H x 3&quot; bottom gusst.{' '}
</Flex>
<Flex gap={4} as="li" className="flex items-center">
<span className="bg-accent inline-block w-10 h-[2px]" />
10&quot; handle drop length.
</Flex>
</Flex>
</Flex>
</Flex>
</Grid>
Expand Down
36 changes: 25 additions & 11 deletions app/routes/products.$handle/sections/highlight-solution.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,26 @@ export default function HighlightSolution() {
} = useLoaderData();
return (
<Section className="aspect-[2/1]">
<Background className="bg-offWhite">
<div className="rotate-12 max-w-screen-md">
<Image className="pointer-events-none" data={selectedVariant.image} />
</div>
</Background>
<Flex
className="z-10 relative"
className="relative z-10 h-full"
direction="right"
justify="center"
align="center"
>
<Container>
<Grid columns={2} justify="center">
<Container className="h-full">
<Grid columns={2} className="h-full">
<div></div>
<Flex direction="down" align="start" gap={4}>
<Flex
className="h-full"
direction="down"
align="start"
justify="center"
gap={9}
>
<Heading className="uppercase">
Your{' '}
<span className="rounded-full p-2 mx-2 bg-accent">ideal</span>
<span className="rounded-full px-4 py-2 mx-2 bg-accent">
<span className="p-2 mx-2 rounded-full bg-accent">ideal</span>
<span className="px-4 py-2 mx-2 rounded-full bg-accent">
&nbsp;
</span>{' '}
travel companion
Expand All @@ -45,6 +46,19 @@ export default function HighlightSolution() {
</Grid>
</Container>
</Flex>
<Background className="bg-offWhite">
<Image
className="h-full max-w-screen-md scale-110 -translate-y-32 pointer-events-none mix-blend-darken rotate-12"
data={selectedVariant.image}
/>
</Background>
<div className="absolute bottom-0 right-0 flex justify-around w-1/2 translate-y-7">
<span className="-translate-x-4 translate-y-2 aspect-square w-14 bg-offWhite"></span>
<span className="translate-x-3 aspect-square w-14 bg-offWhite"></span>
<span className="translate-y-14 aspect-square w-14 bg-offWhite"></span>
<span className="-translate-x-4 translate-y-4 aspect-square w-14 bg-offWhite"></span>
<span className="bg-white aspect-square w-14 -translate-y-7"></span>
</div>
</Section>
);
}
8 changes: 4 additions & 4 deletions app/routes/products.$handle/sections/marquee.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ export default function Banner() {
const slogan = Array(10)
.fill(null)
.map((_, index) => (
<div key={index} className="flex items-center gap-4 p-4 pr-0">
<span className="font-accent">For Builders</span>
<div key={index} className="flex items-center gap-8 p-8 pr-0">
<span className="text-5xl font-accent">For Builders</span>
<Star />
<span className="font-sans">By Builders</span>
<span className="font-sans text-5xl">By Builders</span>
<Star />
</div>
));

return <Marquee className="bg-black uppercase text-white">{slogan}</Marquee>;
return <Marquee className="text-white uppercase bg-black">{slogan}</Marquee>;
}

const Star = () => {
Expand Down
18 changes: 10 additions & 8 deletions app/routes/products.$handle/sections/recommended.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ProductCard} from '@h2/ProductCard';
import {Heading} from '@h2/Text';
import {Section} from '@h2/new/Layout';
import {Container, Section} from '@h2/new/Layout';

const mockProducts = {
nodes: new Array(12).fill(''),
Expand All @@ -13,13 +13,15 @@ export default function Recommended({
...props
}) {
return (
<Section {...props}>
<Heading>
You may
<br />
also like
</Heading>
<div className="swimlane hiddenScroll md:pb-8 md:scroll-px-8 lg:scroll-px-12 md:px-8 lg:px-12">
<Section padded className="w-screen" {...props}>
<Container className="pb-16">
<Heading>
You may
<br />
also like
</Heading>
</Container>
<div className="swimlane">
{products.nodes.map((product) => (
<ProductCard
product={product}
Expand Down
10 changes: 5 additions & 5 deletions app/routes/products.$handle/sections/reviews.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ const reviews = [
export default function Reviews({data = reviews}) {
return (
<Section>
<Container>
<div>
<Container as="header" className="py-16 -mb-64">
<Flex direction="down" gap={8}>
<Heading>Don’t take our word for it</Heading>
<div>
<Flex direction="down" gap={6}>
<Text>4.8 — 385 Reviews</Text>
<Button>View all reviews</Button>
</div>
</div>
</Flex>
</Flex>
</Container>
<Container>
<div className="max-w-3xl ml-auto">
Expand Down
42 changes: 42 additions & 0 deletions app/styles/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,49 @@
}
}

@layer components {
.swimlane {
/* @apply mx-auto px-4 md:px-8 lg:px-10 relative z-10 max-w-7xl w-auto h-auto py-16 */
display: grid;
width: 100%;
scroll-snap-type: x mandatory;
grid-auto-flow: column;
justify-content: flex-start;
gap: 1rem;
overflow-x: scroll;
padding-bottom: 1rem;
padding-left: max(1rem, calc((100vw - 80rem + 2rem) / 2));
padding-right: max(1rem, calc((100vw - 80rem + 2rem) / 2));
scroll-padding-left: max(1rem, calc((100vw - 80rem + 2rem) / 2));
scroll-padding-right: max(1rem, calc((100vw - 80rem + 2rem) / 2));
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
@media (min-width: 48em) {
padding-bottom: 2rem;
padding-left: max(2rem, calc((100vw - 80rem + 4rem) / 2));
padding-right: max(2rem, calc((100vw - 80rem + 4rem) / 2));
scroll-padding-left: max(2rem, calc((100vw - 80rem + 4rem) / 2));
scroll-padding-right: max(2rem, calc((100vw - 80rem + 4rem) / 2));
}
@media (min-width: 64em) {
padding-left: calc((100vw - 80rem + 5rem) / 2);
padding-right: calc((100vw - 80rem + 5rem) / 2);
scroll-padding-left: calc((100vw - 80rem + 5rem) / 2);
scroll-padding-right: calc((100vw - 80rem + 5rem) / 2);
}
}
}

@layer utilities {
.hiddenScroll {
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}

.strike {
position: relative;
&::before {
Expand Down

0 comments on commit fbff023

Please sign in to comment.