'use client'; import React from 'react'; import { CDNOptions } from '../types'; import NextImage, { ImageProps as NextImageProps } from 'next/image'; import { twMerge } from 'tailwind-merge'; import { ImageLoader } from '../utils/image-loader'; interface ImageProps extends NextImageProps { /** * Use fill to make the image responsive. * You also need to provide sizes and aspectRatio props. * * @default false */ fill?: boolean; /** * Crop option for CDN * * Available options: * - `center` * - `top` * - `bottom` * - `left` * - `right` * * @default 'center' */ crop?: CDNOptions['crop']; /** * It is used to calculate the height of the image when fill is true. * It prevents layout shift problems. */ aspectRatio?: number; /** * Sizes attribute for responsive images * * If it is not provided, large images will be downloaded for small screens and it will cause performance issues. * * @example * * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes */ sizes?: string; imageClassName?: string; /** * Swiper removed and we use react-multi-carousel at the moment. * We need to use this prop to make the image draggable or not. */ draggable?: boolean; } const DEFAULT_QUALITY = 70; /** * Image component for responsive images. * * It uses CDN options automatically if the image is hosted on Akinon CDN. You don't need to convert the src prop to CDN url. * * ## For responsive images * You need to provide `fill`, `sizes` and `aspectRatio` props. * If you are not sure about sizes, you can give `100vw` as a value. But it may cause performance issues. * * ## For non-responsive images * You need to provide `width` and `height` props. * This way, the browser will know the size of the image before downloading it and it will prevent layout shift problems. * * ## CDN options * You can use `crop` option to crop the image. * * Available options: * - `center` * - `top` * - `bottom` * - `left` * - `right` * * You can also use `quality` option to change the quality of the image. * Be careful about the file size when you change the quality. * * @default 70 */ export const Image = (props: ImageProps) => { const { src, width, fill, sizes, aspectRatio, quality = DEFAULT_QUALITY, crop = 'center', draggable, className, imageClassName, ...restImage } = props; const optimizeImageURL = ({ src, width }) => { return ImageLoader({ src, width, quality: parseInt(String(quality), DEFAULT_QUALITY), crop, fill, aspectRatio }); }; const hasGif = typeof src === 'string' && src.includes('.gif'); if (fill && !aspectRatio) { throw new Error('aspectRatio is required when fill is true'); } if (fill && !sizes) { throw new Error('sizes is required when fill is true'); } return (
optimizeImageURL({ src, width })} className={imageClassName} {...(hasGif && { unoptimized: true })} {...(draggable !== undefined && { draggable })} />
); };