Skip to content

Commit

Permalink
implement NextImage component
Browse files Browse the repository at this point in the history
- now we don't use srcset solution for which was our Image component prepared
- it was replaced with the solution provided by Next.js which is NextImage component
- this component allows us many more possibilities.
  • Loading branch information
tvikito authored and vitek-rostislav committed Dec 7, 2023
1 parent 1c53d06 commit 0311a43
Show file tree
Hide file tree
Showing 37 changed files with 229 additions and 178 deletions.
5 changes: 3 additions & 2 deletions storefront/components/Basic/Icon/IconImage.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { Image } from 'components/Basic/Image/Image';
import { HTMLAttributes } from 'react';
import { ExtractNativePropsFromDefault } from 'types/ExtractNativePropsFromDefault';

type NativeProps = ExtractNativePropsFromDefault<HTMLAttributes<HTMLElement>, never, 'onClick' | 'title'>;

type IconImageProps = NativeProps & {
icon: string;
alt: string | undefined;
alt: string;
width?: number;
height?: number;
};

export const IconImage: FC<IconImageProps> = ({ icon, height, width, ...props }) => {
return (
<img
<Image
height={height !== undefined ? height : '24'}
src={`/icons/${icon}.png`}
width={width !== undefined ? width : '24'}
Expand Down
63 changes: 13 additions & 50 deletions storefront/components/Basic/Image/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,21 @@
import { ImageFragmentApi } from 'graphql/generated';
import { twMergeCustom } from 'helpers/twMerge';
import { ImgHTMLAttributes } from 'react';
import NextImage, { ImageProps as NextImageProps } from 'next/image';
import { useState } from 'react';

type ImageProps = {
image: ImageFragmentApi | null | undefined;
alt: string | null | undefined;
loading?: ImgHTMLAttributes<HTMLImageElement>['loading'];
width?: string | number;
height?: string | number;
wrapperClassName?: string;
};

const getDataTestId = (dataTestId?: string) => dataTestId ?? 'basic-image';

export const Image: FC<ImageProps> = ({
image,
alt,
loading,
dataTestId,
width,
height,
className,
wrapperClassName,
}) => {
const imageTwClass = twMergeCustom(
'object-contain [image-rendering:-webkit-optimize-contrast] max-w-full max-h-full mx-auto',
className,
);
src: NextImageProps['src'] | undefined | null;
} & Omit<NextImageProps, 'src'>;

if (!image) {
return (
<div className={wrapperClassName}>
<img
alt={alt || ''}
className={twMergeCustom('h-auto w-full', imageTwClass)}
data-testid={getDataTestId(dataTestId) + '-empty'}
height={height || 160}
src="/images/optimized-noimage.webp"
width={width || 160}
/>
</div>
);
}
export const Image: FC<ImageProps> = ({ src, className, ...props }) => {
const [imageUrl, setImageUrl] = useState(src ?? '/images/optimized-noimage.webp');

return (
<picture className={wrapperClassName}>
<img
alt={image.name || alt || ''}
className={imageTwClass}
height={height}
loading={loading}
src={image.url}
width={width}
/>
</picture>
<NextImage
className={twMergeCustom('[image-rendering:-webkit-optimize-contrast]', className)}
loader={({ src, width }) => `${src}?width=${width || '0'}`}
src={imageUrl}
onError={() => setImageUrl('/images/optimized-noimage.webp')}
{...props}
/>
);
};
22 changes: 15 additions & 7 deletions storefront/components/Blocks/Adverts/Adverts.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ExtendedNextLink } from 'components/Basic/ExtendedNextLink/ExtendedNextLink';
import { Image } from 'components/Basic/Image/Image';
import { Webline } from 'components/Layout/Webline/Webline';
import { AdvertsFragmentApi, CategoryDetailFragmentApi, useAdvertsQueryApi } from 'graphql/generated';
import { Fragment } from 'react';
Expand Down Expand Up @@ -50,15 +51,22 @@ export const Adverts: FC<AdvertsProps> = ({
const mainImageMobile = advert.mainImageMobile;

const ImageComponent = (
<picture>
{/* use min-width equal to Tailwind "lg" breakpoint */}
<source media="(min-width: 48.0625em)" srcSet={mainImage?.url} />
<img
alt={advert.mainImage?.name || advert.mainImageMobile?.name || advert.name}
className="w-full"
<>
<Image
alt={mainImage?.name || advert.name}
className="hidden lg:block"
height={400}
src={mainImage?.url}
width={1280}
/>
<Image
alt={mainImageMobile?.name || advert.name}
className="lg:hidden"
height={300}
src={mainImageMobile?.url}
width={770}
/>
</picture>
</>
);

return (
Expand Down
14 changes: 10 additions & 4 deletions storefront/components/Blocks/Banners/BannersSliderItem.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Image } from 'components/Basic/Image/Image';
import { SliderItemFragmentApi } from 'graphql/generated';

type BannersSliderItemProps = {
Expand All @@ -16,14 +17,19 @@ export const BannersSliderItem: FC<BannersSliderItemProps> = ({
{!image ? (
<BannerImage alt="no image" src="images/optimized-noimage.webp" />
) : (
<picture>
<BannerImage alt={image.name || name} src={image.url} />
</picture>
<BannerImage alt={image.name || name} src={image.url} />
)}
</a>
);
};

const BannerImage: FC<{ src: string; alt: string }> = ({ src, alt }) => (
<img alt={alt} className="block h-full w-full object-cover" src={src} />
<Image
alt={alt}
className="block h-full w-full object-cover"
height={300}
sizes="(max-width: 1024px) 100vw, 80vw"
src={src}
width={1025}
/>
);
7 changes: 5 additions & 2 deletions storefront/components/Blocks/BlogPreview/BlogPreviewMain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ export const BlogPreviewMain: FC<MainProps> = ({ articles }) => (
>
<Image
alt={article.mainImage?.name || article.name}
className="rounded"
image={article.mainImage}
className="mx-auto rounded"
height={220}
sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 35vw"
src={article.mainImage?.url}
width={700}
/>
</ArticleLink>

Expand Down
5 changes: 4 additions & 1 deletion storefront/components/Blocks/BlogPreview/BlogPreviewSide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ export const BlogPreviewSide: FC<SideProps> = ({ articles }) => (
<Image
alt={article.mainImage?.name || article.name}
className="rounded"
image={article.mainImage}
height={250}
sizes="(max-width: 600px) 90vw, (max-width: 1024px) 40vw, 10vw"
src={article.mainImage?.url}
width={768}
/>
</ArticleLink>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sentCartImage from '/public/images/sent-cart.svg';
import { Image } from 'components/Basic/Image/Image';
import { SkeletonPageConfirmation } from 'components/Blocks/Skeleton/SkeletonPageConfirmation';
import { ReactElement } from 'react';

Expand All @@ -21,7 +23,7 @@ export const ConfirmationPageContent: FC<ConfirmationPageContentProps> = ({
return (
<div className="mt-16 mb-10 flex flex-col items-center justify-center lg:mt-16 lg:mb-24 lg:flex-row">
<div className="mb-0 w-40 lg:mr-32">
<img alt={heading} src="/public/frontend/images/sent-cart.svg" />
<Image alt={heading} src={sentCartImage} />
</div>
<div>
<div className="h1 mb-3">{heading}</div>
Expand Down
14 changes: 9 additions & 5 deletions storefront/components/Blocks/OrderSummary/SingleProduct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ export const SingleProduct: FC<SingleProductProps> = ({ item }) => {

return (
<li className="flex items-center border-b border-creamWhite py-3">
<Image
alt={item.product.mainImage?.name || item.product.fullName}
className="mr-4 h-14 w-14"
image={item.product.mainImage}
/>
<div className="mr-4 flex w-14 items-center justify-center">
<Image
alt={item.product.mainImage?.name || item.product.fullName}
className="max-h-14 w-auto"
height={56}
src={item.product.mainImage?.url}
width={56}
/>
</div>

<div className="flex flex-1 items-center">
<span className="flex-1 pr-3 text-sm">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ export const TransportAndPayment: FC<TransportAndPaymentProps> = ({ payment, tra
<OrderSummaryRow>
<OrderSummaryTextAndImage dataTestId={TEST_IDENTIFIER + '-transport-name'}>
{transport.name}
<span className="inline-block align-bottom">
<Image alt={transport.name} className="h-8 w-8" image={transport.mainImage} />
</span>
<div className="flex h-8 w-8 items-center">
<Image alt={transport.name} height={32} src={transport.mainImage?.url} width={32} />
</div>
</OrderSummaryTextAndImage>
<OrderSummaryPrice dataTestId={TEST_IDENTIFIER + '-transport-price'}>
<strong>{formatPrice(transport.price.priceWithVat)}</strong>
Expand All @@ -45,9 +45,9 @@ export const TransportAndPayment: FC<TransportAndPaymentProps> = ({ payment, tra
<OrderSummaryRow>
<OrderSummaryTextAndImage dataTestId={TEST_IDENTIFIER + '-payment-name'}>
{payment.name}
<span className="inline-block align-bottom">
<Image alt={payment.name} className="h-8 w-8" image={payment.mainImage} />
</span>
<div className="flex h-8 w-8 items-center">
<Image alt={payment.name} height={32} src={payment.mainImage?.url} width={32} />
</div>
</OrderSummaryTextAndImage>
<OrderSummaryPrice dataTestId={TEST_IDENTIFIER + '-payment-price'}>
<strong>{formatPrice(payment.price.priceWithVat)}</strong>
Expand Down
8 changes: 7 additions & 1 deletion storefront/components/Blocks/Product/AddToCartPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ export const AddToCartPopup: FC<AddToCartPopupProps> = ({ onCloseCallback, added
>
{!!product.mainImage && (
<div className="mb-4 flex w-24 items-center justify-center md:mb-0">
<Image alt={product.mainImage.name || product.fullName} image={product.mainImage} />
<Image
alt={product.mainImage.name || product.fullName}
className="max-h-20 w-auto"
height={48}
src={product.mainImage.url}
width={72}
/>
</div>
)}
<div className="w-full md:pl-4 lg:flex lg:items-center lg:justify-between">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ export const ProductListItem = forwardRef<HTMLLIElement, ProductItemProps>(
<div className="relative">
<Image
alt={product.mainImage?.name || product.fullName}
className="h-40 justify-center lg:hover:mix-blend-multiply"
image={product.mainImage}
className="mx-auto h-40 w-auto"
height={160}
src={product.mainImage?.url}
width={320}
/>
{!!product.flags.length && (
<div className="absolute top-3 left-4 flex flex-col">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,19 @@ export const SimpleNavigationListItem: FC<SimpleNavigationListItemProps> = ({
)}
>
{itemImage && (
<Image
alt={itemImage.name || listedItem.name}
className="h-12 min-w-[64px] mix-blend-multiply"
image={itemImage}
width={64}
/>
<div className="h-12 w-16 shrink-0">
<Image
alt={itemImage.name || listedItem.name}
className="mx-auto max-h-full w-auto mix-blend-multiply"
height={48}
src={itemImage.url}
width={64}
/>
</div>
)}

<div className={twJoin('max-w-full text-center ', itemImage && 'lg:text-left')}>
<span className="block max-w-full text-sm text-dark">{listedItem.name}</span>
<div className={twJoin('text-center ', itemImage && 'lg:text-left')}>
<div className="text-sm text-dark">{listedItem.name}</div>
{'totalCount' in listedItem && listedItem.totalCount !== undefined && (
<span className="ml-2 whitespace-nowrap text-sm text-greyLight">({listedItem.totalCount})</span>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { TextInput } from './TextInput';
import eyeIcon from '/public/svg/eye.svg';
import { Image } from 'components/Basic/Image/Image';
import { FormLineError } from 'components/Forms/Lib/FormLineError';
import { InputHTMLAttributes, ReactElement, useCallback, useState } from 'react';
import { Control, useController } from 'react-hook-form';
Expand Down Expand Up @@ -56,9 +58,9 @@ export const PasswordInputControlled: FC<PasswordInputControlledProps> = ({
onBlur={field.onBlur}
onChange={field.onChange}
>
<img
<Image
alt="eye icon"
src="/svg/eye.svg"
src={eyeIcon}
className={twJoin(
'absolute top-1/2 right-4 w-6 -translate-y-1/2 cursor-pointer',
inputType === 'text' && 'opacity-50',
Expand Down
15 changes: 7 additions & 8 deletions storefront/components/Layout/Footer/FooterBoxInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import needAdviceImage from '/public/images/need_advice.webp';
import { ExtendedNextLink } from 'components/Basic/ExtendedNextLink/ExtendedNextLink';
import { PhoneIcon } from 'components/Basic/Icon/IconsSvg';
import { Image } from 'components/Basic/Image/Image';
import { Button } from 'components/Forms/Button/Button';
import { getInternationalizedStaticUrls } from 'helpers/getInternationalizedStaticUrls';
import { useDomainConfig } from 'hooks/useDomainConfig';
Expand All @@ -20,14 +22,11 @@ export const FooterBoxInfo: FC = () => {

return (
<div className="relative mb-11 flex items-center lg:mb-24" data-testid={TEST_IDENTIFIER}>
<picture>
<source srcSet="/images/need_advice2x.webp 2x, /images/need_advice2x.webp 1x" />
<img
alt={t('Need advice?')}
className="absolute left-0 bottom-0 block h-12 w-12 translate-y-1/2 lg:h-16 lg:w-16"
src="/images/need_advice.webp"
/>
</picture>
<Image
alt={t('Need advice?')}
className="absolute left-0 bottom-0 block h-12 w-12 translate-y-1/2 lg:h-16 lg:w-16"
src={needAdviceImage}
/>
<div className="relative ml-16 flex flex-1 flex-col items-start rounded bg-primary p-4 before:absolute before:-left-1 before:-bottom-1 before:h-6 before:w-4 before:rounded-bl before:bg-primary before:content-[''] before:[transform:rotate(0deg)skewX(-41deg)scale(1.414,0.707)] lg:ml-24 lg:flex-row lg:items-center lg:justify-between lg:py-5 lg:pr-5 lg:pl-8">
<div className="mb-3 text-lg font-bold text-white lg:mr-3 lg:mb-0 lg:flex-1 lg:text-2xl vl:flex-none">
{t('Need advice?')}
Expand Down
5 changes: 3 additions & 2 deletions storefront/components/Layout/Footer/FooterCopyright.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import imageLogo from '/public/images/logo.svg';
import { Image } from 'components/Basic/Image/Image';
import useTranslation from 'next-translate/useTranslation';
import Image from 'next/image';

const TEST_IDENTIFIER = 'layout-footer-footercopyright';

Expand All @@ -14,7 +15,7 @@ export const FooterCopyright: FC = () => {
<div className="flex items-center text-sm text-greyLight">
{t('Customized E-shop by')}
<a className="ml-2 flex w-20" href="https://www.shopsys.com" rel="noreferrer" target="_blank">
<Image alt="footer logo" height={18} src="/images/logo.svg" width={77} />
<Image alt="footer logo" src={imageLogo} />
</a>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ type AutocompleteProps = {

const TEST_IDENTIFIER = 'layout-header-search-autocomplete-popup';

const imageTwClass = 'lg:w-full';

export const AutocompleteSearchPopup: FC<AutocompleteProps> = ({
autocompleteSearchQueryValue,
autocompleteSearchResults: { articlesSearch, brandSearch, categoriesSearch, productsSearch },
Expand Down Expand Up @@ -120,9 +118,10 @@ export const AutocompleteSearchPopup: FC<AutocompleteProps> = ({
>
<Image
alt={product.mainImage?.name || product.fullName}
className="flex h-16 w-20 items-center justify-center"
image={product.mainImage}
wrapperClassName={imageTwClass}
className="mx-auto flex items-center justify-center"
height={64}
src={product.mainImage?.url}
width={80}
/>

<span className="flex-1">{product.fullName}</span>
Expand Down
Loading

0 comments on commit 0311a43

Please sign in to comment.