180 lines
6.6 KiB
TypeScript
180 lines
6.6 KiB
TypeScript
import { FC } from 'react'
|
|
import { ImageType, ImageSize, HorizontalAlignment, VerticalAlignment, ElementType, PersonalityDataType } from '../types/Types'
|
|
import { usePersonalityStore } from '../store/Store'
|
|
|
|
interface ImageRendererProps {
|
|
images: ImageType[]
|
|
itemId: string
|
|
sectionKey: keyof PersonalityDataType
|
|
}
|
|
|
|
const ImageRenderer: FC<ImageRendererProps> = ({ images, itemId, sectionKey }) => {
|
|
const { selectedElement, setSelectedElement } = usePersonalityStore()
|
|
|
|
if (!images || images.length === 0) return null
|
|
|
|
const handleImageClick = (e: React.MouseEvent, imageId: string) => {
|
|
// جلوگیری از propagation به parent handlers
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
setSelectedElement({
|
|
type: ElementType.IMAGE,
|
|
elementId: imageId,
|
|
itemId,
|
|
sectionKey,
|
|
})
|
|
}
|
|
|
|
// تابعهای helper برای تبدیل enum به string
|
|
const getHorizontalAlign = (alignment?: HorizontalAlignment) => {
|
|
switch (alignment) {
|
|
case HorizontalAlignment.LEFT:
|
|
return 'left'
|
|
case HorizontalAlignment.RIGHT:
|
|
return 'right'
|
|
case HorizontalAlignment.CENTER:
|
|
default:
|
|
return 'center'
|
|
}
|
|
}
|
|
|
|
const getVerticalAlign = (verticalAlignment?: VerticalAlignment) => {
|
|
switch (verticalAlignment) {
|
|
case VerticalAlignment.TOP:
|
|
return 'top'
|
|
case VerticalAlignment.BOTTOM:
|
|
return 'bottom'
|
|
case VerticalAlignment.MIDDLE:
|
|
default:
|
|
return 'middle'
|
|
}
|
|
}
|
|
|
|
const getImageStyle = (image: ImageType) => {
|
|
return {
|
|
width: image.width || '100%',
|
|
height: image.height || 'auto',
|
|
border: '0',
|
|
pointerEvents: 'none' as const // Prevent double click handling
|
|
}
|
|
}
|
|
|
|
const shouldUseBackgroundImage = (imageSize: ImageSize) => {
|
|
return imageSize === ImageSize.REPEAT ||
|
|
imageSize === ImageSize.REPEAT_X ||
|
|
imageSize === ImageSize.REPEAT_Y
|
|
}
|
|
|
|
const getBackgroundStyle = (image: ImageType) => {
|
|
let backgroundRepeat = 'no-repeat'
|
|
|
|
switch (image.size) {
|
|
case ImageSize.REPEAT:
|
|
backgroundRepeat = 'repeat'
|
|
break
|
|
case ImageSize.REPEAT_X:
|
|
backgroundRepeat = 'repeat-x'
|
|
break
|
|
case ImageSize.REPEAT_Y:
|
|
backgroundRepeat = 'repeat-y'
|
|
break
|
|
default:
|
|
backgroundRepeat = 'no-repeat'
|
|
break
|
|
}
|
|
|
|
const horizontal = image.alignment === HorizontalAlignment.LEFT ? 'left' :
|
|
image.alignment === HorizontalAlignment.RIGHT ? 'right' : 'center'
|
|
const vertical = image.verticalAlignment === VerticalAlignment.TOP ? 'top' :
|
|
image.verticalAlignment === VerticalAlignment.BOTTOM ? 'bottom' : 'center'
|
|
|
|
return {
|
|
backgroundImage: `url(${image.src})`,
|
|
backgroundPosition: `${horizontal} ${vertical}`,
|
|
backgroundRepeat,
|
|
width: image.width || '100%',
|
|
height: image.height || '100px'
|
|
}
|
|
}
|
|
|
|
const renderImage = (image: ImageType) => {
|
|
const imageWrapper = (
|
|
<div
|
|
data-element-type="image"
|
|
onClick={(e) => handleImageClick(e, image.id)}
|
|
style={{
|
|
cursor: 'pointer',
|
|
outline: selectedElement?.elementId === image.id ? '2px dashed #0038FF' : 'none',
|
|
outlineOffset: '2px',
|
|
borderRadius: '4px',
|
|
padding: '2px',
|
|
display: 'inline-block',
|
|
minWidth: '20px',
|
|
minHeight: '20px'
|
|
}}
|
|
>
|
|
{shouldUseBackgroundImage(image.size) ? (
|
|
// برای pattern های repeat از background استفاده میکنیم
|
|
<div style={getBackgroundStyle(image)}>
|
|
|
|
</div>
|
|
) : (
|
|
// برای تصاویر عادی
|
|
image.size === ImageSize.CONTAIN ? (
|
|
// برای contain از table wrapper استفاده میکنیم تا نسبت حفظ شود
|
|
<table width={image.width || '100%'} cellPadding="0" cellSpacing="0" border={0}>
|
|
<tbody>
|
|
<tr>
|
|
<td align="center" valign="middle" style={{ textAlign: 'center' }}>
|
|
<img
|
|
src={image.src}
|
|
alt={image.alt || 'تصویر آپلود شده'}
|
|
width={image.width || '100%'}
|
|
height={image.height || 'auto'}
|
|
style={getImageStyle(image)}
|
|
/>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
) : (
|
|
// برای cover و auto
|
|
<img
|
|
src={image.src}
|
|
alt={image.alt || 'تصویر آپلود شده'}
|
|
width={image.width || '100%'}
|
|
height={image.height || 'auto'}
|
|
style={getImageStyle(image)}
|
|
/>
|
|
)
|
|
)}
|
|
</div>
|
|
)
|
|
|
|
return imageWrapper
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{images.map((image, imageIndex) => (
|
|
<table key={image.id} width="100%" cellPadding="0" cellSpacing="0" border={0}>
|
|
<tbody>
|
|
<tr>
|
|
<td
|
|
align={getHorizontalAlign(image.alignment)}
|
|
valign={getVerticalAlign(image.verticalAlignment)}
|
|
style={{
|
|
paddingBottom: imageIndex < images.length - 1 ? '4px' : '0'
|
|
}}
|
|
>
|
|
{renderImage(image)}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
))}
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default ImageRenderer
|