image sidebar

This commit is contained in:
hamid zarghami
2025-07-01 16:11:32 +03:30
parent 7638e07e39
commit cdff4355d3
4 changed files with 98 additions and 49 deletions
@@ -19,9 +19,9 @@ const ButtonSidebar: FC = () => {
const [buttonSize, setButtonSize] = useState<ButtonSize>(ButtonSize.MEDIUM) const [buttonSize, setButtonSize] = useState<ButtonSize>(ButtonSize.MEDIUM)
const [isBorder, setIsBorder] = useState<boolean>(false) const [isBorder, setIsBorder] = useState<boolean>(false)
const [borderSize, setBorderSize] = useState<number>(1) const [borderSize, setBorderSize] = useState<number>(1)
const [textColor, setTextColor] = useState<string>('#000') const [textColor, setTextColor] = useState<string>('#fff')
const [backgroundColor, setBackgroundColor] = useState<string>('#000') const [backgroundColor, setBackgroundColor] = useState<string>('#000')
const [borderColor, setBorderColor] = useState<string>('#000') const [borderColor, setBorderColor] = useState<string>('#fff')
const [horizontalAlignment, setHorizontalAlignment] = useState<HorizontalAlignment>(HorizontalAlignment.CENTER) const [horizontalAlignment, setHorizontalAlignment] = useState<HorizontalAlignment>(HorizontalAlignment.CENTER)
const [verticalAlignment, setVerticalAlignment] = useState<VerticalAlignment>(VerticalAlignment.MIDDLE) const [verticalAlignment, setVerticalAlignment] = useState<VerticalAlignment>(VerticalAlignment.MIDDLE)
@@ -51,9 +51,9 @@ const ButtonSidebar: FC = () => {
setButtonSize(ButtonSize.MEDIUM) setButtonSize(ButtonSize.MEDIUM)
setIsBorder(false) setIsBorder(false)
setBorderSize(1) setBorderSize(1)
setTextColor('#000') setTextColor('#fff')
setBackgroundColor('#000') setBackgroundColor('#000')
setBorderColor('#000') setBorderColor('#fff')
setHorizontalAlignment(HorizontalAlignment.CENTER) setHorizontalAlignment(HorizontalAlignment.CENTER)
setVerticalAlignment(VerticalAlignment.MIDDLE) setVerticalAlignment(VerticalAlignment.MIDDLE)
} }
@@ -8,80 +8,135 @@ interface ImageRendererProps {
const ImageRenderer: FC<ImageRendererProps> = ({ images }) => { const ImageRenderer: FC<ImageRendererProps> = ({ images }) => {
if (!images || images.length === 0) return null if (!images || images.length === 0) return null
// تابع‌های 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'
}
}
const shouldUseBackgroundImage = (imageSize: ImageSize) => {
return imageSize === ImageSize.REPEAT ||
imageSize === ImageSize.REPEAT_X ||
imageSize === ImageSize.REPEAT_Y
}
const getBackgroundStyle = (image: ImageType) => { const getBackgroundStyle = (image: ImageType) => {
let backgroundSize = 'cover'
let backgroundRepeat = 'no-repeat' let backgroundRepeat = 'no-repeat'
switch (image.size) { switch (image.size) {
case ImageSize.COVER:
backgroundSize = 'cover'
backgroundRepeat = 'no-repeat'
break
case ImageSize.CONTAIN:
backgroundSize = 'contain'
backgroundRepeat = 'no-repeat'
break
case ImageSize.REPEAT: case ImageSize.REPEAT:
backgroundSize = 'auto'
backgroundRepeat = 'repeat' backgroundRepeat = 'repeat'
break break
case ImageSize.REPEAT_X: case ImageSize.REPEAT_X:
backgroundSize = 'auto'
backgroundRepeat = 'repeat-x' backgroundRepeat = 'repeat-x'
break break
case ImageSize.REPEAT_Y: case ImageSize.REPEAT_Y:
backgroundSize = 'auto'
backgroundRepeat = 'repeat-y' backgroundRepeat = 'repeat-y'
break break
case ImageSize.NO_REPEAT:
backgroundSize = 'auto'
backgroundRepeat = 'no-repeat'
break
case ImageSize.AUTO:
default: default:
backgroundSize = 'auto'
backgroundRepeat = 'no-repeat' backgroundRepeat = 'no-repeat'
break break
} }
let backgroundPosition = 'center center'
// تنظیم موقعیت بر اساس alignment
const horizontal = image.alignment === HorizontalAlignment.LEFT ? 'left' : const horizontal = image.alignment === HorizontalAlignment.LEFT ? 'left' :
image.alignment === HorizontalAlignment.RIGHT ? 'right' : 'center' image.alignment === HorizontalAlignment.RIGHT ? 'right' : 'center'
const vertical = image.verticalAlignment === VerticalAlignment.TOP ? 'top' : const vertical = image.verticalAlignment === VerticalAlignment.TOP ? 'top' :
image.verticalAlignment === VerticalAlignment.BOTTOM ? 'bottom' : 'center' image.verticalAlignment === VerticalAlignment.BOTTOM ? 'bottom' : 'center'
backgroundPosition = `${horizontal} ${vertical}`
return { return {
backgroundImage: `url(${image.src})`, backgroundImage: `url(${image.src})`,
backgroundSize, backgroundPosition: `${horizontal} ${vertical}`,
backgroundRepeat, backgroundRepeat,
backgroundPosition,
width: image.width || '100%', width: image.width || '100%',
height: image.height || '60px', height: image.height || '100px'
display: 'block'
} }
} }
const renderImage = (image: ImageType) => {
if (shouldUseBackgroundImage(image.size)) {
// برای pattern های repeat از background استفاده می‌کنیم
return (
<div style={getBackgroundStyle(image)}>
&nbsp;
</div>
)
}
// برای تصاویر عادی
if (image.size === ImageSize.CONTAIN) {
// برای contain از table wrapper استفاده می‌کنیم تا نسبت حفظ شود
return (
<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={{ border: '0' }}
/>
</td>
</tr>
</tbody>
</table>
)
}
// برای cover و auto
return (
<img
src={image.src}
alt={image.alt || 'تصویر آپلود شده'}
width={image.width || '100%'}
height={image.height || 'auto'}
style={getImageStyle(image)}
/>
)
}
return ( return (
<> <>
{images.map((image, imageIndex) => ( {images.map((image, imageIndex) => (
<table key={image.id} width="100%" cellPadding="0" cellSpacing="0" border={0} style={{ borderCollapse: 'collapse' }}> <table key={image.id} width="100%" cellPadding="0" cellSpacing="0" border={0}>
<tbody> <tbody>
<tr> <tr>
<td <td
align={image.alignment || 'center'} align={getHorizontalAlign(image.alignment)}
valign={image.verticalAlignment || 'middle'} valign={getVerticalAlign(image.verticalAlignment)}
style={{ style={{
paddingBottom: imageIndex < images.length - 1 ? '4px' : '0' paddingBottom: imageIndex < images.length - 1 ? '4px' : '0'
}} }}
> >
<div style={getBackgroundStyle(image)}> {renderImage(image)}
{/* محتوا درون div با background image */}
&nbsp;
</div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@@ -133,19 +133,16 @@ const ImageSideBar: FC = () => {
</div> </div>
<div className='mt-3 flex gap-4'> <div className='mt-3 flex gap-4'>
<div <div
className={`cursor-pointer p-1 rounded ${horizontalAlignment === HorizontalAlignment.RIGHT ? 'bg-blue-100' : ''}`}
onClick={() => setHorizontalAlignment(HorizontalAlignment.RIGHT)} onClick={() => setHorizontalAlignment(HorizontalAlignment.RIGHT)}
> >
<AlignRight size={20} color={horizontalAlignment === HorizontalAlignment.RIGHT ? '#0038FF' : '#000'} /> <AlignRight size={20} color={horizontalAlignment === HorizontalAlignment.RIGHT ? '#0038FF' : '#000'} />
</div> </div>
<div <div
className={`cursor-pointer p-1 rounded ${horizontalAlignment === HorizontalAlignment.CENTER ? 'bg-blue-100' : ''}`}
onClick={() => setHorizontalAlignment(HorizontalAlignment.CENTER)} onClick={() => setHorizontalAlignment(HorizontalAlignment.CENTER)}
> >
<AlignVertically size={20} color={horizontalAlignment === HorizontalAlignment.CENTER ? '#0038FF' : '#000'} /> <AlignVertically size={20} color={horizontalAlignment === HorizontalAlignment.CENTER ? '#0038FF' : '#000'} />
</div> </div>
<div <div
className={`cursor-pointer p-1 rounded ${horizontalAlignment === HorizontalAlignment.LEFT ? 'bg-blue-100' : ''}`}
onClick={() => setHorizontalAlignment(HorizontalAlignment.LEFT)} onClick={() => setHorizontalAlignment(HorizontalAlignment.LEFT)}
> >
<AlignLeft size={20} color={horizontalAlignment === HorizontalAlignment.LEFT ? '#0038FF' : '#000'} /> <AlignLeft size={20} color={horizontalAlignment === HorizontalAlignment.LEFT ? '#0038FF' : '#000'} />
@@ -159,19 +156,16 @@ const ImageSideBar: FC = () => {
</div> </div>
<div className='mt-3 flex gap-4'> <div className='mt-3 flex gap-4'>
<div <div
className={`cursor-pointer p-1 rounded ${verticalAlignment === VerticalAlignment.BOTTOM ? 'bg-blue-100' : ''}`}
onClick={() => setVerticalAlignment(VerticalAlignment.BOTTOM)} onClick={() => setVerticalAlignment(VerticalAlignment.BOTTOM)}
> >
<AlignBottom size={20} color={verticalAlignment === VerticalAlignment.BOTTOM ? '#0038FF' : '#000'} /> <AlignBottom size={20} color={verticalAlignment === VerticalAlignment.BOTTOM ? '#0038FF' : '#000'} />
</div> </div>
<div <div
className={`cursor-pointer p-1 rounded ${verticalAlignment === VerticalAlignment.MIDDLE ? 'bg-blue-100' : ''}`}
onClick={() => setVerticalAlignment(VerticalAlignment.MIDDLE)} onClick={() => setVerticalAlignment(VerticalAlignment.MIDDLE)}
> >
<AlignHorizontally size={20} color={verticalAlignment === VerticalAlignment.MIDDLE ? '#0038FF' : '#000'} /> <AlignHorizontally size={20} color={verticalAlignment === VerticalAlignment.MIDDLE ? '#0038FF' : '#000'} />
</div> </div>
<div <div
className={`cursor-pointer p-1 rounded ${verticalAlignment === VerticalAlignment.TOP ? 'bg-blue-100' : ''}`}
onClick={() => setVerticalAlignment(VerticalAlignment.TOP)} onClick={() => setVerticalAlignment(VerticalAlignment.TOP)}
> >
<AlignTop size={20} color={verticalAlignment === VerticalAlignment.TOP ? '#0038FF' : '#000'} /> <AlignTop size={20} color={verticalAlignment === VerticalAlignment.TOP ? '#0038FF' : '#000'} />
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import UploadBoxDraggble from '@/components/UploadBoxDraggble'; import UploadBoxDraggble from '@/components/UploadBoxDraggble';
import ColorPicker from '@/components/ColorPicker'; import ColorPicker from '@/components/ColorPicker';
import { usePersonalityStore } from '../store/Store'; import { usePersonalityStore } from '../store/Store';
import { SectionItemType, BackgroundSize } from '../types/Types'; import { SectionItemType, BackgroundSize, SectionName } from '../types/Types';
import Select from '@/components/Select'; import Select from '@/components/Select';
const SettingSideBar: FC = () => { const SettingSideBar: FC = () => {
@@ -19,10 +19,10 @@ const SettingSideBar: FC = () => {
const bgSize = style.backgroundSize const bgSize = style.backgroundSize
const bgRepeat = style.backgroundRepeat const bgRepeat = style.backgroundRepeat
if (bgSize === BackgroundSize.COVER) return BackgroundSize.COVER if (bgSize === 'cover') return BackgroundSize.COVER
if (bgSize === BackgroundSize.CONTAIN) return BackgroundSize.CONTAIN if (bgSize === 'contain') return BackgroundSize.CONTAIN
if (bgSize === 'auto' || !bgSize) { if (bgSize === 'auto' || !bgSize) {
if (bgRepeat === BackgroundSize.ROUND) return BackgroundSize.ROUND if (bgRepeat === 'round') return BackgroundSize.ROUND
} }
return BackgroundSize.COVER return BackgroundSize.COVER
} }
@@ -40,7 +40,7 @@ const SettingSideBar: FC = () => {
const handleColumnClick = (columns: number) => { const handleColumnClick = (columns: number) => {
if (activeSection) { if (activeSection) {
setColumnsCount(activeSection as "header" | "content" | "footer", columns); setColumnsCount(activeSection as SectionName, columns);
} }
} }