feat(poc): changes for new design

This commit is contained in:
Björn Meyer 2023-07-27 17:14:18 +02:00
parent 82c0fb8813
commit 5ad4654c55
13 changed files with 106 additions and 124 deletions

View File

@ -8,7 +8,7 @@ import { Gallery } from 'components/product/gallery';
import { ProductDescription } from 'components/product/product-description';
import { HIDDEN_PRODUCT_TAG } from 'lib/constants';
import { getProduct, getProductRecommendations } from 'lib/shopware';
import { Image } from 'lib/shopify/types';
import { Image } from 'lib/shopware/types';
import Link from 'next/link';
export const runtime = 'edge';
@ -132,8 +132,8 @@ async function RelatedProducts({ id }: { id: string }) {
currencyCode: product.priceRange.maxVariantPrice.currencyCode
}}
src={product.featuredImage?.url}
width={600}
height={600}
width={500}
height={500}
/>
</Link>
);

View File

@ -58,13 +58,18 @@ export default async function CategoryPage({
<Grid className="grid-cols-2 lg:grid-cols-3">
<ProductGridItems products={products} />
</Grid>
<nav aria-label="Collection pagination" className="block items-center sm:flex">
<Pagination
itemsPerPage={limit}
itemsTotal={total}
currentPage={page ? parseInt(page) - 1 : 0}
/>
</nav>
{total > limit ? (
<nav
aria-label="Collection pagination"
className="mb-2 mt-4 block items-center sm:flex"
>
<Pagination
itemsPerPage={limit}
itemsTotal={total}
currentPage={page ? parseInt(page) - 1 : 0}
/>
</nav>
) : null}
</div>
<div className="order-none flex-none md:order-last md:w-[125px]">
<FilterList list={sorting} title="Sort by" />

View File

@ -25,7 +25,7 @@ export default async function SearchPage({
return (
<>
{searchValue && products.length === 0 ? (
<div className="mx-auto flex max-w-7xl flex-col bg-white py-6 text-black dark:bg-black dark:text-white md:flex-row">
<div className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-4 pb-4 text-black dark:text-white md:flex-row">
<p>
{'There are no products that match '}
<span className="font-bold">&quot;{searchValue}&quot;</span>
@ -33,20 +33,22 @@ export default async function SearchPage({
</div>
) : null}
{products.length > 0 ? (
<div className="mx-auto flex max-w-7xl flex-col bg-white py-6 text-black dark:bg-black dark:text-white md:flex-row">
<div className="order-first flex-none md:w-1/6">
<div className="mx-auto flex max-w-screen-2xl flex-col gap-8 px-4 pb-4 text-black dark:text-white md:flex-row">
<div className="order-first w-full flex-none md:max-w-[125px]">
{searchValue ? (
<p>
<p className="text-sm text-neutral-500">
{`Showing ${products.length} ${resultsText} for `}
<span className="font-bold">&quot;{searchValue}&quot;</span>
</p>
) : null}
<p className="pt-4">Good place to add other suggest search terms ;)</p>
<p className="pt-4 text-xs text-neutral-500">
Good place to add other suggested search terms ;)
</p>
</div>
<Grid className="grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
<Grid className="grid-cols-2 lg:grid-cols-3">
<ProductGridItems products={products} />
</Grid>
<div className="order-none md:order-last md:w-1/6 md:flex-none">
<div className="order-none flex-none md:order-last md:w-[125px]">
<FilterList list={sorting} title="Sort by" />
</div>
</div>

View File

@ -1,6 +1,8 @@
'use client';
import ReactPaginate from 'react-paginate';
import { ArrowLeftIcon } from '@heroicons/react/24/outline';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import { createUrl } from 'lib/utils';
import { usePathname, useSearchParams, useRouter } from 'next/navigation';
@ -52,18 +54,18 @@ export default function Pagination({
initialPage={currentPage}
pageCount={pageCount}
breakLabel="..."
nextLabel=">>"
previousLabel="<<"
nextLabel=<ArrowRightIcon className="h-5" />
previousLabel=<ArrowLeftIcon className="h-5" />
renderOnZeroPageCount={null}
containerClassName="inline sm:flex text-base h-10 mx-auto"
activeClassName="active"
pageClassName="m-2 sm:m-0 sm:mx-2 text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white [&.active]:bg-gray-100"
pageClassName="m-2 sm:m-0 sm:mx-2 text-gray-500 bg-white border rounded-lg border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white [&.active]:bg-gray-100"
pageLinkClassName="flex items-center justify-center px-4 h-10 ml-0 leading-tight"
previousClassName="m-2 sm:m-0 sm:mx-2 text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white [&.disabled]:hidden"
previousClassName="m-2 sm:m-0 sm:mx-2 text-gray-500 bg-white border rounded-lg border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white [&.disabled]:hidden"
previousLinkClassName="flex items-center justify-center px-4 h-10 ml-0 leading-tight"
nextClassName="m-2 sm:m-0 sm:mx-2 text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white [&.disabled]:hidden"
nextClassName="m-2 sm:m-0 sm:mx-2 text-gray-500 bg-white border rounded-lg border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white [&.disabled]:hidden"
nextLinkClassName="flex items-center justify-center px-4 h-10 ml-0 leading-tight"
breakClassName="m-2 sm:m-0 sm:mx-2 text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
breakClassName="m-2 sm:m-0 sm:mx-2 text-gray-500 bg-white border rounded-lg border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
breakLinkClassName="flex items-center justify-center px-4 h-10 ml-0 leading-tight"
/>
</>

View File

@ -33,7 +33,8 @@ export function GridTileImage({
<Image
className={clsx('relative h-full w-full object-contain', {
'transition duration-300 ease-in-out hover:scale-105': isInteractive,
'm-4 max-h-[8rem] min-h-[8rem]': props.width === 200 && props.height === 200 // this styling is for the thumbnails below gallery on product detail page
'max-h-[4rem] min-h-[4rem]': props.width === 200 && props.height === 200, // this styling is for the thumbnails below gallery on product detail page
'max-h-[20rem] min-h-[20rem]': props.width === 500 && props.height === 500 // this styling is for the gallery in recommendations on product detail page
})}
{...props}
/>

View File

@ -1,16 +1,18 @@
import clsx from 'clsx';
import Image from 'next/image';
export default function LogoIcon(props: React.ComponentProps<'svg'>) {
export type ImageProps = {
width?: number | string;
height?: number | string;
className?: string;
};
export default function LogoIcon(props: ImageProps) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
aria-label={`${process.env.SITE_NAME} logo`}
viewBox="0 0 32 28"
{...props}
className={clsx('h-4 w-4 fill-black dark:fill-white', props.className)}
>
<path d="M21.5758 9.75769L16 0L0 28H11.6255L21.5758 9.75769Z" />
<path d="M26.2381 17.9167L20.7382 28H32L26.2381 17.9167Z" />
</svg>
<Image
src="https://www.shopware.com/media/pages/solutions/shopware-frontends/shopware-frontends-intro-graphic-base.svg"
alt="Shopware Composable Frontends Logo"
width={Number(props.width)}
height={Number(props.height)}
></Image>
);
}

View File

@ -1,7 +1,7 @@
'use client';
import clsx from 'clsx';
import { Menu } from 'lib/shopify/types';
import { Menu } from 'lib/shopware/types';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { useEffect, useState } from 'react';
@ -15,7 +15,7 @@ const FooterMenuItem = ({ item }: { item: Menu }) => {
}, [pathname, item.path]);
return (
<li className="mt-2 first:mt-1">
<li key={item.title} className="mt-2 first:mt-1">
<Link
href={item.path}
className={clsx(
@ -34,13 +34,25 @@ const FooterMenuItem = ({ item }: { item: Menu }) => {
export default function FooterMenu({ menu }: { menu: Menu[] }) {
if (!menu.length) return null;
return (
<nav>
<ul>
{menu.map((item: Menu) => {
return <FooterMenuItem key={item.title} item={item} />;
})}
</ul>
return menu.map((item: Menu) => (
<nav className="col-span-1 lg:col-span-3" key={item.title + item.type}>
{item.type === 'headline' ? <span className="font-bold">{item.title}</span> : null}
{item.children.length > 0 ? (
<ul className="py-3 md:py-0 md:pt-4" key={item.title}>
{item.children.map((item: Menu) => (
<FooterMenuItem key={item.title} item={item} />
))}
</ul>
) : (
// if there are no children, at least display a link
<Link
key={item.title}
href={item.path}
className="text-gray-800 transition duration-150 ease-in-out hover:text-gray-300 dark:text-gray-100"
>
{item.title}
</Link>
)}
</nav>
);
));
}

View File

@ -5,7 +5,6 @@ import GitHubIcon from 'components/icons/github';
import FooterMenu from 'components/layout/footer-menu';
import LogoSquare from 'components/logo-square';
import { getMenu } from 'lib/shopware';
import { Menu } from 'lib/shopware/types';
import { Suspense } from 'react';
const { COMPANY_NAME, SITE_NAME } = process.env;
@ -18,44 +17,30 @@ export default async function Footer() {
const copyrightName = COMPANY_NAME || SITE_NAME || '';
return (
<footer className="border-t border-gray-700 bg-white text-black dark:bg-black dark:text-white">
<div className="mx-auto w-full max-w-7xl px-6">
<div className="grid grid-cols-1 gap-8 border-b border-gray-700 py-12 transition-colors duration-150 lg:grid-cols-12">
<div className="col-span-1 lg:col-span-4">
<footer className="text-sm text-neutral-400 dark:text-neutral-600">
<div className="mx-auto flex w-full max-w-7xl flex-col gap-6 border-t border-neutral-200 px-6 py-12 text-sm dark:border-neutral-700 md:flex-row md:gap-12 md:px-4 xl:px-0">
<div className="grid grid-cols-1 gap-8 transition-colors duration-150 lg:grid-cols-12">
<div className="col-span-1 lg:col-span-3">
<Link className="flex items-center gap-2 text-black dark:text-white" href="/">
<LogoSquare size="sm" />
<span className="uppercase">{SITE_NAME}</span>
</Link>
</div>
{menu.map((item: Menu) => (
<nav className="col-span-1 lg:col-span-3" key={item.title + item.type}>
{item.type === 'headline' ? <span className="font-bold">{item.title}</span> : null}
{item.children.length > 0 ? (
<ul className="py-3 md:py-0 md:pt-4" key={item.title}>
{item.children.map((item: Menu) => (
<li key={item.title} className="py-3 md:py-0 md:pb-4">
<Link
href={item.path}
className="text-gray-800 transition duration-150 ease-in-out hover:text-gray-300 dark:text-gray-100"
>
{item.title}
</Link>
</li>
))}
</ul>
) : (
// if there are no children, at least display a link
<Link
key={item.title}
href={item.path}
className="text-gray-800 transition duration-150 ease-in-out hover:text-gray-300 dark:text-gray-100"
>
{item.title}
</Link>
)}
</nav>
))}
<div className="col-span-1 inline-grid justify-items-end text-black dark:text-white lg:col-span-2">
<Suspense
fallback={
<div className="flex h-[188px] w-[200px] flex-col gap-2">
<div className={skeleton} />
<div className={skeleton} />
<div className={skeleton} />
<div className={skeleton} />
<div className={skeleton} />
<div className={skeleton} />
</div>
}
>
<FooterMenu menu={menu} />
</Suspense>
<div className="md:ml-auto">
<a
aria-label="Github Repository"
href="https://github.com/shopware/frontends"
@ -66,30 +51,6 @@ export default async function Footer() {
</a>
</div>
</div>
<Suspense
fallback={
<div className="flex h-[188px] w-[200px] flex-col gap-2">
<div className={skeleton} />
<div className={skeleton} />
<div className={skeleton} />
<div className={skeleton} />
<div className={skeleton} />
<div className={skeleton} />
</div>
}
>
<FooterMenu menu={menu} />
</Suspense>
<div className="md:ml-auto">
<a
className="flex items-center gap-2 hover:text-black dark:hover:text-neutral-300"
aria-label="Github Repository"
href="https://github.com/vercel/commerce"
>
<GitHubIcon className="h-6" />
<p>Source</p>
</a>
</div>
</div>
<div className="border-t border-neutral-200 py-6 text-sm dark:border-neutral-700">
<div className="mx-auto flex w-full max-w-7xl flex-col items-center gap-1 md:flex-row md:gap-0">
@ -97,10 +58,9 @@ export default async function Footer() {
&copy; {copyrightDate} {copyrightName}
{copyrightName.length && !copyrightName.endsWith('.') ? '.' : ''} All rights reserved.
</p>
<div className="flex items-center text-sm text-white dark:text-black">
<span className="text-black dark:text-white">
Created by Shopware Composable Frontends
</span>
<hr className="mx-4 hidden h-4 w-[1px] border-l border-neutral-400 md:inline-block" />
<p>Created by Shopware Composable Frontends</p>
<div className="md:ml-auto">
<a
rel="noopener noreferrer"
href="https://frontends.shopware.com/"

View File

@ -7,7 +7,6 @@ import Link from 'next/link';
import { Suspense } from 'react';
import MobileMenu from './mobile-menu';
import Search from './search';
const { SITE_NAME } = process.env;
export default async function Navbar() {
const menu = await getMenu({ type: 'main-navigation' });
@ -18,16 +17,13 @@ export default async function Navbar() {
<MobileMenu menu={menu} />
</div>
<div className="flex w-full items-center">
<div className="flex w-full md:w-1/3">
<div className="flex w-full md:w-4/6">
<Link
href="/"
aria-label="Go back home"
className="mr-2 flex w-full items-center justify-center md:w-auto lg:mr-6"
>
<LogoSquare />
<div className="ml-2 flex-none text-sm font-medium uppercase md:hidden lg:block">
{SITE_NAME}
</div>
</Link>
{menu.length ? (
<ul className="hidden text-sm md:flex md:items-center">
@ -44,10 +40,10 @@ export default async function Navbar() {
</ul>
) : null}
</div>
<div className="hidden justify-center md:flex md:w-1/3">
<div className="hidden justify-center md:flex md:w-1/6">
<Search />
</div>
<div className="flex justify-end md:w-1/3">
<div className="flex justify-end md:w-1/6">
<Suspense fallback={<OpenCart />}>
<Cart />
</Suspense>

View File

@ -13,6 +13,8 @@ export default function LogoSquare({ size }: { size?: 'sm' | undefined }) {
)}
>
<LogoIcon
width={20}
height={20}
className={clsx({
'h-[16px] w-[16px]': !size,
'h-[10px] w-[10px]': size === 'sm'

View File

@ -17,7 +17,7 @@ export default async function OpengraphImage(props?: Props): Promise<ImageRespon
(
<div tw="flex h-full w-full flex-col items-center justify-center bg-black">
<div tw="flex flex-none items-center justify-center border border-neutral-700 h-[160px] w-[160px] rounded-3xl">
<LogoIcon width="64" height="58" fill="white" />
<LogoIcon width="64" height="58" />
</div>
<p tw="mt-12 text-6xl font-bold text-white">{title}</p>
</div>

View File

@ -21,7 +21,7 @@ export function Gallery({ images }: { images: { src: string; altText: string }[]
return (
<div className="mr-8 h-full">
<div className="relative mb-12 h-full max-h-[550px] overflow-hidden">
<div className="relative mb-12 h-full max-h-[550px] min-h-[550px] overflow-hidden">
{images[currentImageIndex] && (
<Image
className="relative h-full w-full object-contain"

View File

@ -18,18 +18,18 @@ export function ProductDescription({ product }: { product: Product }) {
</div>
<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
product={product}
variants={product.variants}
availableForSale={product.availableForSale}
/>
{product.descriptionHtml ? (
<Prose
className="m-6 max-h-96 overflow-y-auto text-sm leading-tight dark:text-white/[60%]"
html={product.descriptionHtml}
/>
) : null}
</>
);
}