mirror of
https://github.com/vercel/commerce.git
synced 2025-05-20 08:26:59 +00:00
Update home page UI (#1068)
* home page updated UI design * prettier * remove unused bg color prop * change label margin on carousol labels * move label ui into own component * change space-x from 6 to 4 in carousel --------- Co-authored-by: Michael Novotny <manovotny@gmail.com>
This commit is contained in:
parent
7bad98965a
commit
65bd26b090
@ -1,6 +1,7 @@
|
|||||||
import { getCollectionProducts } from 'lib/shopify';
|
import { getCollectionProducts } from 'lib/shopify';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import Label from './label';
|
||||||
|
|
||||||
export async function Carousel() {
|
export async function Carousel() {
|
||||||
// Collections that start with `hidden-*` are hidden from the search page.
|
// Collections that start with `hidden-*` are hidden from the search page.
|
||||||
@ -9,13 +10,13 @@ export async function Carousel() {
|
|||||||
if (!products?.length) return null;
|
if (!products?.length) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full overflow-hidden bg-black dark:bg-white">
|
<div className="relative w-full overflow-hidden pb-6">
|
||||||
<div className="flex animate-carousel">
|
<div className="flex animate-carousel space-x-4">
|
||||||
{[...products, ...products].map((product, i) => (
|
{[...products, ...products].map((product, i) => (
|
||||||
<Link
|
<Link
|
||||||
key={`${product.handle}${i}`}
|
key={`${product.handle}${i}`}
|
||||||
href={`/product/${product.handle}`}
|
href={`/product/${product.handle}`}
|
||||||
className="relative h-[30vh] w-1/2 flex-none md:w-1/3"
|
className="relative h-[30vh] w-2/3 flex-none rounded-lg border border-gray-200 bg-white dark:border-gray-800 dark:bg-black md:w-1/3"
|
||||||
>
|
>
|
||||||
{product.featuredImage ? (
|
{product.featuredImage ? (
|
||||||
<Image
|
<Image
|
||||||
@ -26,11 +27,11 @@ export async function Carousel() {
|
|||||||
src={product.featuredImage.url}
|
src={product.featuredImage.url}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="absolute inset-y-0 right-0 flex items-center justify-center">
|
<Label
|
||||||
<div className="inline-flex bg-white p-4 text-xl font-semibold text-black dark:bg-black dark:text-white">
|
title={product.title}
|
||||||
{product.title}
|
amount={product.priceRange.maxVariantPrice.amount}
|
||||||
</div>
|
currencyCode={product.priceRange.maxVariantPrice.currencyCode}
|
||||||
</div>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@ import clsx from 'clsx';
|
|||||||
|
|
||||||
function Grid(props: React.ComponentProps<'ul'>) {
|
function Grid(props: React.ComponentProps<'ul'>) {
|
||||||
return (
|
return (
|
||||||
<ul {...props} className={clsx('grid grid-flow-row gap-4 py-5', props.className)}>
|
<ul {...props} className={clsx('grid grid-flow-row gap-4 py-5', props.className)}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
|
@ -3,26 +3,18 @@ import { getCollectionProducts } from 'lib/shopify';
|
|||||||
import type { Product } from 'lib/shopify/types';
|
import type { Product } from 'lib/shopify/types';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
function ThreeItemGridItem({
|
function ThreeItemGridItem({ item, size }: { item: Product; size: 'full' | 'half' }) {
|
||||||
item,
|
|
||||||
size,
|
|
||||||
background
|
|
||||||
}: {
|
|
||||||
item: Product;
|
|
||||||
size: 'full' | 'half';
|
|
||||||
background: 'white' | 'pink' | 'purple' | 'black';
|
|
||||||
}) {
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={size === 'full' ? 'lg:col-span-4 lg:row-span-2' : 'lg:col-span-2 lg:row-span-1'}
|
className={size === 'full' ? 'lg:col-span-4 lg:row-span-2' : 'lg:col-span-2 lg:row-span-1'}
|
||||||
>
|
>
|
||||||
<Link className="block h-full" href={`/product/${item.handle}`}>
|
<Link className="block h-full p-2" href={`/product/${item.handle}`}>
|
||||||
<GridTileImage
|
<GridTileImage
|
||||||
src={item.featuredImage.url}
|
src={item.featuredImage.url}
|
||||||
width={size === 'full' ? 1080 : 540}
|
width={size === 'full' ? 1080 : 540}
|
||||||
height={size === 'full' ? 1080 : 540}
|
height={size === 'full' ? 1080 : 540}
|
||||||
|
labelPosition={size === 'full' ? 'center' : 'bottom'}
|
||||||
priority={true}
|
priority={true}
|
||||||
background={background}
|
|
||||||
alt={item.title}
|
alt={item.title}
|
||||||
labels={{
|
labels={{
|
||||||
title: item.title as string,
|
title: item.title as string,
|
||||||
@ -46,10 +38,10 @@ export async function ThreeItemGrid() {
|
|||||||
const [firstProduct, secondProduct, thirdProduct] = homepageItems;
|
const [firstProduct, secondProduct, thirdProduct] = homepageItems;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="lg:grid lg:grid-cols-6 lg:grid-rows-2" data-testid="homepage-products">
|
<section className="p-2 lg:grid lg:grid-cols-6 lg:grid-rows-2" data-testid="homepage-products">
|
||||||
<ThreeItemGridItem size="full" item={firstProduct} background="purple" />
|
<ThreeItemGridItem size="full" item={firstProduct} />
|
||||||
<ThreeItemGridItem size="half" item={secondProduct} background="black" />
|
<ThreeItemGridItem size="half" item={secondProduct} />
|
||||||
<ThreeItemGridItem size="half" item={thirdProduct} background="pink" />
|
<ThreeItemGridItem size="half" item={thirdProduct} />
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import Label from '../label';
|
||||||
import Price from 'components/price';
|
|
||||||
|
|
||||||
export function GridTileImage({
|
export function GridTileImage({
|
||||||
isInteractive = true,
|
isInteractive = true,
|
||||||
background,
|
|
||||||
active,
|
active,
|
||||||
|
labelPosition,
|
||||||
labels,
|
labels,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
isInteractive?: boolean;
|
isInteractive?: boolean;
|
||||||
background?: 'white' | 'pink' | 'purple' | 'black' | 'purple-dark' | 'blue' | 'cyan' | 'gray';
|
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
|
labelPosition?: 'bottom' | 'center';
|
||||||
labels?: {
|
labels?: {
|
||||||
title: string;
|
title: string;
|
||||||
amount: string;
|
amount: string;
|
||||||
@ -22,18 +21,12 @@ export function GridTileImage({
|
|||||||
} & React.ComponentProps<typeof Image>) {
|
} & React.ComponentProps<typeof Image>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx('relative flex h-full w-full items-center justify-center overflow-hidden', {
|
className={clsx(
|
||||||
'bg-white dark:bg-white': background === 'white',
|
'relative flex h-full w-full items-center justify-center overflow-hidden rounded-lg border border-gray-200 bg-white dark:border-gray-800 dark:bg-black',
|
||||||
'bg-[#ff0080] dark:bg-[#ff0080]': background === 'pink',
|
{
|
||||||
'bg-[#7928ca] dark:bg-[#7928ca]': background === 'purple',
|
relative: labels
|
||||||
'bg-gray-900 dark:bg-gray-900': background === 'black',
|
}
|
||||||
'bg-violetDark dark:bg-violetDark': background === 'purple-dark',
|
)}
|
||||||
'bg-blue-500 dark:bg-blue-500': background === 'blue',
|
|
||||||
'bg-cyan-500 dark:bg-cyan-500': background === 'cyan',
|
|
||||||
'bg-gray-100 dark:bg-gray-100': background === 'gray',
|
|
||||||
'bg-gray-100 dark:bg-gray-900': !background,
|
|
||||||
relative: labels
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
{active !== undefined && active ? (
|
{active !== undefined && active ? (
|
||||||
<span className="absolute h-full w-full bg-white opacity-25"></span>
|
<span className="absolute h-full w-full bg-white opacity-25"></span>
|
||||||
@ -48,22 +41,13 @@ export function GridTileImage({
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{labels ? (
|
{labels ? (
|
||||||
<div className="absolute left-0 top-0 w-3/4 text-black dark:text-white">
|
<Label
|
||||||
<h3
|
title={labels.title}
|
||||||
data-testid="product-name"
|
amount={labels.amount}
|
||||||
className={clsx(
|
currencyCode={labels.currencyCode}
|
||||||
'inline bg-white box-decoration-clone py-3 pl-5 font-semibold leading-loose shadow-[1.25rem_0_0] shadow-white dark:bg-black dark:shadow-black',
|
size="large"
|
||||||
!labels.isSmall ? 'text-3xl' : 'text-lg'
|
position={labelPosition}
|
||||||
)}
|
/>
|
||||||
>
|
|
||||||
{labels.title}
|
|
||||||
</h3>
|
|
||||||
<Price
|
|
||||||
className="w-fit bg-white px-5 py-3 text-sm font-semibold dark:bg-black dark:text-white"
|
|
||||||
amount={labels.amount}
|
|
||||||
currencyCode={labels.currencyCode}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
41
components/label.tsx
Normal file
41
components/label.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import clsx from 'clsx';
|
||||||
|
import Price from './price';
|
||||||
|
|
||||||
|
const Label = ({
|
||||||
|
title,
|
||||||
|
amount,
|
||||||
|
currencyCode,
|
||||||
|
position,
|
||||||
|
size
|
||||||
|
}: {
|
||||||
|
title: string;
|
||||||
|
amount: string;
|
||||||
|
currencyCode: string;
|
||||||
|
position?: 'bottom' | 'center';
|
||||||
|
size?: 'large' | 'small';
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'absolute bottom-0 left-0 flex items-center rounded-full border bg-white/80 p-1 text-black backdrop-blur-md dark:border-gray-800 dark:bg-black/80 dark:text-white',
|
||||||
|
size === 'large' ? 'text-sm' : 'text-xs',
|
||||||
|
position === 'center'
|
||||||
|
? 'mb-4 ml-4 md:mb-8 md:ml-8 lg:mb-[35%] lg:ml-20'
|
||||||
|
: size === 'large'
|
||||||
|
? 'mb-4 ml-4 md:mb-8 md:ml-8'
|
||||||
|
: 'mb-4 ml-4'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<h3 data-testid="product-name" className="mr-6 inline pl-2 font-semibold">
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
<Price
|
||||||
|
className="flex-none rounded-full bg-blue-600 p-2 font-semibold text-white"
|
||||||
|
amount={amount}
|
||||||
|
currencyCode={currencyCode}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Label;
|
@ -41,7 +41,6 @@ export function Gallery({
|
|||||||
height={600}
|
height={600}
|
||||||
isInteractive={false}
|
isInteractive={false}
|
||||||
priority={true}
|
priority={true}
|
||||||
background="purple"
|
|
||||||
labels={{
|
labels={{
|
||||||
title,
|
title,
|
||||||
amount,
|
amount,
|
||||||
@ -86,7 +85,6 @@ export function Gallery({
|
|||||||
src={image.src}
|
src={image.src}
|
||||||
width={600}
|
width={600}
|
||||||
height={600}
|
height={600}
|
||||||
background="purple-dark"
|
|
||||||
active={isActive}
|
active={isActive}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user