2022-11-18 11:54:06 +08:00
|
|
|
import React from 'react';
|
|
|
|
import classNames from 'classnames';
|
2022-12-24 18:11:43 +08:00
|
|
|
import { Image } from 'antd';
|
|
|
|
import toArray from 'rc-util/lib/Children/toArray';
|
|
|
|
|
|
|
|
interface ImagePreviewProps {
|
|
|
|
children: React.ReactNode[];
|
2023-07-18 18:22:47 +08:00
|
|
|
className?: string;
|
|
|
|
/** Do not show padding & background */
|
|
|
|
pure?: boolean;
|
2022-12-24 18:11:43 +08:00
|
|
|
}
|
2022-11-18 11:54:06 +08:00
|
|
|
|
2022-12-07 18:26:29 +08:00
|
|
|
function isGood(className: string): boolean {
|
2022-11-18 11:54:06 +08:00
|
|
|
return /\bgood\b/i.test(className);
|
|
|
|
}
|
|
|
|
|
2022-12-07 18:26:29 +08:00
|
|
|
function isBad(className: string): boolean {
|
2022-11-18 11:54:06 +08:00
|
|
|
return /\bbad\b/i.test(className);
|
|
|
|
}
|
|
|
|
|
2022-12-07 18:26:29 +08:00
|
|
|
function isInline(className: string): boolean {
|
2022-11-18 11:54:06 +08:00
|
|
|
return /\binline\b/i.test(className);
|
|
|
|
}
|
|
|
|
|
2022-12-07 18:26:29 +08:00
|
|
|
function isGoodBadImg(imgMeta: any): boolean {
|
|
|
|
return imgMeta.isGood || imgMeta.isBad;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isCompareImg(imgMeta: any): boolean {
|
|
|
|
return isGoodBadImg(imgMeta) || imgMeta.inline;
|
|
|
|
}
|
2022-12-24 18:11:43 +08:00
|
|
|
const ImagePreview: React.FC<ImagePreviewProps> = (props) => {
|
2023-07-18 18:22:47 +08:00
|
|
|
const { children, className: rootClassName, pure } = props;
|
2022-12-24 18:11:43 +08:00
|
|
|
const imgs = toArray(children).filter((ele) => ele.type === 'img');
|
|
|
|
|
|
|
|
const imgsMeta = imgs.map((img) => {
|
|
|
|
const { alt, description, src, className } = img.props;
|
|
|
|
return {
|
|
|
|
className,
|
|
|
|
alt,
|
|
|
|
description,
|
|
|
|
src,
|
|
|
|
isGood: isGood(className),
|
|
|
|
isBad: isBad(className),
|
|
|
|
inline: isInline(className),
|
2022-11-18 11:54:06 +08:00
|
|
|
};
|
2022-12-24 18:11:43 +08:00
|
|
|
});
|
2022-11-18 11:54:06 +08:00
|
|
|
|
2022-12-24 18:11:43 +08:00
|
|
|
const imagesList = imgsMeta.map<React.ReactNode>((meta, index) => {
|
|
|
|
const metaCopy = { ...meta };
|
|
|
|
delete metaCopy.description;
|
|
|
|
delete metaCopy.isGood;
|
|
|
|
delete metaCopy.isBad;
|
|
|
|
return (
|
|
|
|
<div key={index}>
|
|
|
|
<div className="image-modal-container">
|
|
|
|
<img {...metaCopy} src={meta.src} alt={meta.alt} />
|
2022-11-18 11:54:06 +08:00
|
|
|
</div>
|
2022-12-24 18:11:43 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
});
|
2022-11-18 11:54:06 +08:00
|
|
|
|
2022-12-24 18:11:43 +08:00
|
|
|
const comparable =
|
|
|
|
(imgs.length === 2 && imgsMeta.every(isCompareImg)) ||
|
|
|
|
(imgs.length >= 2 && imgsMeta.every(isGoodBadImg));
|
2022-11-18 11:54:06 +08:00
|
|
|
|
2022-12-24 18:11:43 +08:00
|
|
|
const style: React.CSSProperties = comparable
|
|
|
|
? { width: `${(100 / imgs.length).toFixed(3)}%` }
|
|
|
|
: {};
|
2022-11-18 11:54:06 +08:00
|
|
|
|
2022-12-24 18:11:43 +08:00
|
|
|
const hasCarousel = imgs.length > 1 && !comparable;
|
2023-07-23 10:12:05 +08:00
|
|
|
|
|
|
|
const previewClassName = classNames(rootClassName, 'clearfix', 'preview-image-boxes', {
|
2022-12-24 18:11:43 +08:00
|
|
|
'preview-image-boxes-compare': comparable,
|
|
|
|
'preview-image-boxes-with-carousel': hasCarousel,
|
|
|
|
});
|
|
|
|
|
2023-07-18 18:22:47 +08:00
|
|
|
// ===================== Render =====================
|
|
|
|
const imgWrapperCls = 'preview-image-wrapper';
|
|
|
|
|
2022-12-24 18:11:43 +08:00
|
|
|
return (
|
|
|
|
<div className={previewClassName}>
|
2023-07-18 18:22:47 +08:00
|
|
|
{!imgs.length && (
|
|
|
|
<div
|
|
|
|
className={imgWrapperCls}
|
|
|
|
style={pure ? { background: 'transparent', padding: 0 } : {}}
|
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
2022-12-24 18:11:43 +08:00
|
|
|
{imagesList.map((_, index) => {
|
|
|
|
if (!comparable && index !== 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const coverMeta = imgsMeta[index];
|
2023-07-18 18:22:47 +08:00
|
|
|
const imageWrapperClassName = classNames(imgWrapperCls, {
|
2022-12-24 18:11:43 +08:00
|
|
|
good: coverMeta.isGood,
|
|
|
|
bad: coverMeta.isBad,
|
|
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className="preview-image-box" style={style} key={index}>
|
|
|
|
<div className={imageWrapperClassName}>
|
|
|
|
<Image className={coverMeta.className} src={coverMeta.src} alt={coverMeta.alt} />
|
|
|
|
</div>
|
|
|
|
<div className="preview-image-title">{coverMeta.alt}</div>
|
|
|
|
<div
|
|
|
|
className="preview-image-description"
|
|
|
|
dangerouslySetInnerHTML={{ __html: coverMeta.description }}
|
2022-11-18 11:54:06 +08:00
|
|
|
/>
|
2022-12-24 18:11:43 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
2022-12-07 18:26:29 +08:00
|
|
|
|
|
|
|
export default ImagePreview;
|