From 7638e07e396012b2bb77fc03b51ab0abb109ce2d Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Tue, 1 Jul 2025 14:36:27 +0330 Subject: [PATCH] add renderer components --- src/components/UploadBoxDraggble.tsx | 10 +- .../personality/components/ButtonRenderer.tsx | 94 +++++++++++ .../personality/components/ButtonSidebar.tsx | 104 +++++++++--- .../personality/components/ContentSection.tsx | 132 ++++++++++++--- .../personality/components/FooterSection.tsx | 134 ++++++++++++--- .../personality/components/HeaderSection.tsx | 134 ++++++++++++--- .../personality/components/ImageRenderer.tsx | 94 +++++++++++ .../personality/components/ImageSideBar.tsx | 159 ++++++++++++++++-- .../personality/components/SettingSideBar.tsx | 148 +++++++++------- .../personality/components/TextRenderer.tsx | 33 ++++ .../personality/components/TextSidebar.tsx | 78 ++++++++- src/pages/setting/personality/store/Store.ts | 88 +++++++++- src/pages/setting/personality/types/Types.ts | 86 +++++++++- 13 files changed, 1102 insertions(+), 192 deletions(-) create mode 100644 src/pages/setting/personality/components/ButtonRenderer.tsx create mode 100644 src/pages/setting/personality/components/ImageRenderer.tsx create mode 100644 src/pages/setting/personality/components/TextRenderer.tsx diff --git a/src/components/UploadBoxDraggble.tsx b/src/components/UploadBoxDraggble.tsx index 9add931..b674fa7 100644 --- a/src/components/UploadBoxDraggble.tsx +++ b/src/components/UploadBoxDraggble.tsx @@ -12,7 +12,8 @@ type Props = { preview?: string[], onChangePreview?: (preview: string[]) => void, getCover?: (url: string) => void, - coverUrl?: string + coverUrl?: string, + isReset?: boolean } const UploadBoxDraggble: FC = (props: Props) => { @@ -67,6 +68,13 @@ const UploadBoxDraggble: FC = (props: Props) => { setCover(props.coverUrl ? props.coverUrl : '') }, [props.coverUrl]) + useEffect(() => { + if (props.isReset) { + setFiles([]) + setPerviews([]) + } + }, [props.isReset]) + return (
diff --git a/src/pages/setting/personality/components/ButtonRenderer.tsx b/src/pages/setting/personality/components/ButtonRenderer.tsx new file mode 100644 index 0000000..b68f3e2 --- /dev/null +++ b/src/pages/setting/personality/components/ButtonRenderer.tsx @@ -0,0 +1,94 @@ +import { FC } from 'react' +import { ButtonType, ButtonSize, HorizontalAlignment, VerticalAlignment } from '../types/Types' + +interface ButtonRendererProps { + buttons: ButtonType[] +} + +const ButtonRenderer: FC = ({ buttons }) => { + if (!buttons || buttons.length === 0) return null + + // تبدیل enum به string برای HTML attributes + 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' + } + } + + return ( + + + + + + +
+ + + + {buttons.slice(0, 2).map((button, buttonIndex) => ( + + ))} + + +
1 ? '4px' : '0' }}> + + + + + + +
+ + {button.text} + +
+
+
+ ) +} + +export default ButtonRenderer \ No newline at end of file diff --git a/src/pages/setting/personality/components/ButtonSidebar.tsx b/src/pages/setting/personality/components/ButtonSidebar.tsx index 14cefd1..0e785fb 100644 --- a/src/pages/setting/personality/components/ButtonSidebar.tsx +++ b/src/pages/setting/personality/components/ButtonSidebar.tsx @@ -7,26 +7,55 @@ import { AlignRight, AlignBottom, AlignHorizontally, AlignLeft, AlignTop, AlignV import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' import { usePersonalityStore } from '../store/Store' +import { ButtonSize, HorizontalAlignment, VerticalAlignment } from '../types/Types' const ButtonSidebar: FC = () => { const { t } = useTranslation() const { addButtonToActiveItem } = usePersonalityStore() + + const [buttonText, setButtonText] = useState('') + const [buttonLink, setButtonLink] = useState('') + const [buttonSize, setButtonSize] = useState(ButtonSize.MEDIUM) const [isBorder, setIsBorder] = useState(false) + const [borderSize, setBorderSize] = useState(1) + const [textColor, setTextColor] = useState('#000') + const [backgroundColor, setBackgroundColor] = useState('#000') + const [borderColor, setBorderColor] = useState('#000') + const [horizontalAlignment, setHorizontalAlignment] = useState(HorizontalAlignment.CENTER) + const [verticalAlignment, setVerticalAlignment] = useState(VerticalAlignment.MIDDLE) + + const sizeOptions = [ + { label: 'کوچک', value: ButtonSize.SMALL }, + { label: 'متوسط', value: ButtonSize.MEDIUM }, + { label: 'بزرگ', value: ButtonSize.LARGE } + ] const handleAddButton = () => { addButtonToActiveItem({ - text: 'دکمه جدید', - link: '#', - size: 'medium', - isBorder: true, - borderSize: 1, - textColor: '#ffffff', - backgroundColor: '#0038FF', - borderColor: '#0038FF', - alignment: 'center', - verticalAlignment: 'middle', + text: buttonText, + link: buttonLink, + size: buttonSize, + isBorder, + borderSize, + textColor, + backgroundColor, + borderColor, + alignment: horizontalAlignment, + verticalAlignment, }) + + // Reset form after adding + setButtonText('') + setButtonLink('') + setButtonSize(ButtonSize.MEDIUM) + setIsBorder(false) + setBorderSize(1) + setTextColor('#000') + setBackgroundColor('#000') + setBorderColor('#000') + setHorizontalAlignment(HorizontalAlignment.CENTER) + setVerticalAlignment(VerticalAlignment.MIDDLE) } return ( @@ -36,12 +65,16 @@ const ButtonSidebar: FC = () => {
setButtonText(e.target.value)} />
setButtonLink(e.target.value)} endIcon={} />
@@ -49,7 +82,9 @@ const ButtonSidebar: FC = () => {
setBorderSize(Number(e.target.value))} />
} @@ -75,21 +112,24 @@ const ButtonSidebar: FC = () => {
null} + defaultColor={textColor} + changeColor={setTextColor} />
null} + defaultColor={backgroundColor} + changeColor={setBackgroundColor} />
null} + defaultColor={borderColor} + changeColor={setBorderColor} />
@@ -99,9 +139,21 @@ const ButtonSidebar: FC = () => { {t('setting.horizontal_position')}
- - - +
setHorizontalAlignment(HorizontalAlignment.RIGHT)} + > + +
+
setHorizontalAlignment(HorizontalAlignment.CENTER)} + > + +
+
setHorizontalAlignment(HorizontalAlignment.LEFT)} + > + +
@@ -110,9 +162,21 @@ const ButtonSidebar: FC = () => { {t('setting.vertical_position')}
- - - +
setVerticalAlignment(VerticalAlignment.TOP)} + > + +
+
setVerticalAlignment(VerticalAlignment.MIDDLE)} + > + +
+
setVerticalAlignment(VerticalAlignment.BOTTOM)} + > + +
diff --git a/src/pages/setting/personality/components/ContentSection.tsx b/src/pages/setting/personality/components/ContentSection.tsx index 32302f0..6ecb060 100644 --- a/src/pages/setting/personality/components/ContentSection.tsx +++ b/src/pages/setting/personality/components/ContentSection.tsx @@ -2,13 +2,17 @@ import { FC } from 'react' import { usePersonalityStore } from '../store/Store' import { useTranslation } from 'react-i18next' import { AddCircle } from 'iconsax-react' +import TextRenderer from './TextRenderer' +import ButtonRenderer from './ButtonRenderer' +import ImageRenderer from './ImageRenderer' +import { SectionName, VerticalAlignment, HorizontalAlignment } from '../types/Types' const ContentSection: FC = () => { const { t } = useTranslation() const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore() - const handleSectionClick = (section: "header" | "content" | "footer") => { + const handleSectionClick = (section: SectionName) => { setActiveSection(section) } @@ -16,8 +20,35 @@ const ContentSection: FC = () => { setActiveItemIndex(index) } + // تابع‌های helper برای تعیین alignment دکمه‌ها + const getButtonHorizontalAlign = (button?: { alignment?: HorizontalAlignment }) => { + if (!button || !button.alignment) return 'center' + switch (button.alignment) { + case HorizontalAlignment.LEFT: + return 'left' + case HorizontalAlignment.RIGHT: + return 'right' + case HorizontalAlignment.CENTER: + default: + return 'center' + } + } + + const getButtonVerticalAlign = (button?: { verticalAlignment?: VerticalAlignment }) => { + if (!button || !button.verticalAlignment) return 'middle' + switch (button.verticalAlignment) { + case VerticalAlignment.TOP: + return 'top' + case VerticalAlignment.BOTTOM: + return 'bottom' + case VerticalAlignment.MIDDLE: + default: + return 'middle' + } + } + return ( - handleSectionClick("content")}> + handleSectionClick(SectionName.CONTENT)}> { data.content.columnsCount > 0 ? @@ -26,16 +57,16 @@ const ContentSection: FC = () => { - +
{ Array.from({ length: data.content.columnsCount }, (_, index) => { const item = data.content.items[index]; - const isActive = activeSection === "content" && activeItemIndex === index; + const isActive = activeSection === SectionName.CONTENT && activeItemIndex === index; return ( <> @@ -46,32 +77,81 @@ const ContentSection: FC = () => { }} key={index} style={{ + width: `${100 / data.content.columnsCount}%`, height: '246px', border: isActive ? '1px dashed #0038FF' : '1px dashed #EAECF4', backgroundColor: item?.backgroundColor || '#ffffff', backgroundImage: item?.backgroundImage ? `url(${item.backgroundImage})` : 'none', - backgroundSize: 'cover', - backgroundPosition: 'center', - cursor: 'pointer' + backgroundSize: item?.style?.backgroundSize || 'cover', + backgroundRepeat: item?.style?.backgroundRepeat || 'no-repeat', + backgroundPosition: item?.style?.backgroundPosition || 'center', + cursor: 'pointer', + padding: '0', + verticalAlign: 'top', + borderRadius: '8px', + position: 'relative' }} > - {/* محتوای آیتم */} - {item?.texts?.map(text => ( -
- {text.text} -
- ))} - {item?.buttons?.map(button => ( - - ))} +
+ + {/* اگر فقط دکمه داریم و متن نداریم */} + {(!item?.texts || item.texts.length === 0) && item?.buttons && item.buttons.length > 0 ? ( + + + + ) : ( + <> + {/* ردیف اصلی برای متن */} + + + + {/* ردیف دکمه‌ها */} + {item?.buttons && item.buttons.length > 0 && ( + + + + )} + + )} + +
+ +
0 ? "203" : "230"} + align={item?.texts?.[0]?.alignment || 'center'} + valign={item?.texts?.[0]?.verticalAlignment === VerticalAlignment.TOP ? 'top' : + item?.texts?.[0]?.verticalAlignment === VerticalAlignment.BOTTOM ? 'bottom' : 'middle'} + style={{ + padding: '8px', + fontSize: '14px', + lineHeight: '1.4' + }} + > + + +
+ +
{index < data.content.columnsCount - 1 && ( @@ -93,7 +173,7 @@ const ContentSection: FC = () => { { const { t } = useTranslation() const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore() - const handleSectionClick = (section: "header" | "content" | "footer") => { + const handleSectionClick = (section: SectionName) => { setActiveSection(section) } @@ -16,8 +20,35 @@ const FooterSection: FC = () => { setActiveItemIndex(index) } + // تابع‌های helper برای تعیین alignment دکمه‌ها + const getButtonHorizontalAlign = (button?: { alignment?: HorizontalAlignment }) => { + if (!button || !button.alignment) return 'center' + switch (button.alignment) { + case HorizontalAlignment.LEFT: + return 'left' + case HorizontalAlignment.RIGHT: + return 'right' + case HorizontalAlignment.CENTER: + default: + return 'center' + } + } + + const getButtonVerticalAlign = (button?: { verticalAlignment?: VerticalAlignment }) => { + if (!button || !button.verticalAlignment) return 'middle' + switch (button.verticalAlignment) { + case VerticalAlignment.TOP: + return 'top' + case VerticalAlignment.BOTTOM: + return 'bottom' + case VerticalAlignment.MIDDLE: + default: + return 'middle' + } + } + return ( - handleSectionClick("footer")}> + handleSectionClick(SectionName.FOOTER)}> { data.footer.columnsCount > 0 ? @@ -26,16 +57,16 @@ const FooterSection: FC = () => { - +
{ Array.from({ length: data.footer.columnsCount }, (_, index) => { const item = data.footer.items[index]; - const isActive = activeSection === "footer" && activeItemIndex === index; + const isActive = activeSection === SectionName.FOOTER && activeItemIndex === index; return ( <> @@ -46,32 +77,81 @@ const FooterSection: FC = () => { }} key={index} style={{ - height: '83px', + width: `${100 / data.footer.columnsCount}%`, + height: '123px', border: isActive ? '1px dashed #0038FF' : '1px dashed #EAECF4', backgroundColor: item?.backgroundColor || '#ffffff', backgroundImage: item?.backgroundImage ? `url(${item.backgroundImage})` : 'none', - backgroundSize: 'cover', - backgroundPosition: 'center', - cursor: 'pointer' + backgroundSize: item?.style?.backgroundSize || 'cover', + backgroundRepeat: item?.style?.backgroundRepeat || 'no-repeat', + backgroundPosition: item?.style?.backgroundPosition || 'center', + cursor: 'pointer', + padding: '0', + verticalAlign: 'top', + borderRadius: '8px', + position: 'relative' }} > - {/* محتوای آیتم */} - {item?.texts?.map(text => ( -
- {text.text} -
- ))} - {item?.buttons?.map(button => ( - - ))} +
+ + {/* اگر فقط دکمه داریم و متن نداریم */} + {(!item?.texts || item.texts.length === 0) && item?.buttons && item.buttons.length > 0 ? ( + + + + ) : ( + <> + {/* ردیف اصلی برای متن */} + + + + {/* ردیف دکمه‌ها */} + {item?.buttons && item.buttons.length > 0 && ( + + + + )} + + )} + +
+ +
0 ? "40" : "67"} + align={item?.texts?.[0]?.alignment || 'center'} + valign={item?.texts?.[0]?.verticalAlignment === VerticalAlignment.TOP ? 'top' : + item?.texts?.[0]?.verticalAlignment === VerticalAlignment.BOTTOM ? 'bottom' : 'middle'} + style={{ + padding: '8px', + fontSize: '14px', + lineHeight: '1.4' + }} + > + + +
+ +
{index < data.footer.columnsCount - 1 && ( @@ -93,7 +173,7 @@ const FooterSection: FC = () => { { const { t } = useTranslation() const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore() - const handleSectionClick = (section: "header" | "content" | "footer") => { + const handleSectionClick = (section: SectionName) => { setActiveSection(section) } @@ -16,22 +20,49 @@ const HeaderSection: FC = () => { setActiveItemIndex(index) } + // تابع‌های helper برای تعیین alignment دکمه‌ها + const getButtonHorizontalAlign = (button?: { alignment?: HorizontalAlignment }) => { + if (!button || !button.alignment) return 'center' + switch (button.alignment) { + case HorizontalAlignment.LEFT: + return 'left' + case HorizontalAlignment.RIGHT: + return 'right' + case HorizontalAlignment.CENTER: + default: + return 'center' + } + } + + const getButtonVerticalAlign = (button?: { verticalAlignment?: VerticalAlignment }) => { + if (!button || !button.verticalAlignment) return 'middle' + switch (button.verticalAlignment) { + case VerticalAlignment.TOP: + return 'top' + case VerticalAlignment.BOTTOM: + return 'bottom' + case VerticalAlignment.MIDDLE: + default: + return 'middle' + } + } + return ( - handleSectionClick("header")}> + handleSectionClick(SectionName.HEADER)}> { data.header.columnsCount > 0 ? - +
{ Array.from({ length: data.header.columnsCount }, (_, index) => { const item = data.header.items[index]; - const isActive = activeSection === "header" && activeItemIndex === index; + const isActive = activeSection === SectionName.HEADER && activeItemIndex === index; return ( <> @@ -42,32 +73,81 @@ const HeaderSection: FC = () => { }} key={index} style={{ - height: '103px', + width: `${100 / data.header.columnsCount}%`, + height: '123px', border: isActive ? '1px dashed #0038FF' : '1px dashed #EAECF4', backgroundColor: item?.backgroundColor || '#ffffff', backgroundImage: item?.backgroundImage ? `url(${item.backgroundImage})` : 'none', - backgroundSize: 'cover', - backgroundPosition: 'center', - cursor: 'pointer' + backgroundSize: item?.style?.backgroundSize || 'cover', + backgroundRepeat: item?.style?.backgroundRepeat || 'no-repeat', + backgroundPosition: item?.style?.backgroundPosition || 'center', + cursor: 'pointer', + padding: '0', + verticalAlign: 'top', + borderRadius: '8px', + position: 'relative' }} > - {/* محتوای آیتم */} - {item?.texts?.map(text => ( -
- {text.text} -
- ))} - {item?.buttons?.map(button => ( - - ))} +
+ + {/* اگر فقط دکمه داریم و متن نداریم */} + {(!item?.texts || item.texts.length === 0) && item?.buttons && item.buttons.length > 0 ? ( + + + + ) : ( + <> + {/* ردیف اصلی برای متن */} + + + + {/* ردیف دکمه‌ها */} + {item?.buttons && item.buttons.length > 0 && ( + + + + )} + + )} + +
+ +
0 ? "60" : "87"} + align={item?.texts?.[0]?.alignment || 'center'} + valign={item?.texts?.[0]?.verticalAlignment === VerticalAlignment.TOP ? 'top' : + item?.texts?.[0]?.verticalAlignment === VerticalAlignment.BOTTOM ? 'bottom' : 'middle'} + style={{ + padding: '8px', + fontSize: '14px', + lineHeight: '1.4' + }} + > + + +
+ +
{index < data.header.columnsCount - 1 && ( @@ -83,7 +163,7 @@ const HeaderSection: FC = () => { : = ({ images }) => { + if (!images || images.length === 0) return null + + const getBackgroundStyle = (image: ImageType) => { + let backgroundSize = 'cover' + let backgroundRepeat = 'no-repeat' + + switch (image.size) { + case ImageSize.COVER: + backgroundSize = 'cover' + backgroundRepeat = 'no-repeat' + break + case ImageSize.CONTAIN: + backgroundSize = 'contain' + backgroundRepeat = 'no-repeat' + break + case ImageSize.REPEAT: + backgroundSize = 'auto' + backgroundRepeat = 'repeat' + break + case ImageSize.REPEAT_X: + backgroundSize = 'auto' + backgroundRepeat = 'repeat-x' + break + case ImageSize.REPEAT_Y: + backgroundSize = 'auto' + backgroundRepeat = 'repeat-y' + break + case ImageSize.NO_REPEAT: + backgroundSize = 'auto' + backgroundRepeat = 'no-repeat' + break + case ImageSize.AUTO: + default: + backgroundSize = 'auto' + backgroundRepeat = 'no-repeat' + break + } + + let backgroundPosition = 'center center' + + // تنظیم موقعیت بر اساس alignment + 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' + + backgroundPosition = `${horizontal} ${vertical}` + + return { + backgroundImage: `url(${image.src})`, + backgroundSize, + backgroundRepeat, + backgroundPosition, + width: image.width || '100%', + height: image.height || '60px', + display: 'block' + } + } + + return ( + <> + {images.map((image, imageIndex) => ( + + + + + + +
+
+ {/* محتوا درون div با background image */} +   +
+
+ ))} + + ) +} + +export default ImageRenderer \ No newline at end of file diff --git a/src/pages/setting/personality/components/ImageSideBar.tsx b/src/pages/setting/personality/components/ImageSideBar.tsx index 20c8565..a9cf89b 100644 --- a/src/pages/setting/personality/components/ImageSideBar.tsx +++ b/src/pages/setting/personality/components/ImageSideBar.tsx @@ -1,12 +1,108 @@ import Button from '@/components/Button' +import Select from '@/components/Select' import UploadBoxDraggble from '@/components/UploadBoxDraggble' import { Add, AlignBottom, AlignHorizontally, AlignLeft, AlignRight, AlignTop, AlignVertically } from 'iconsax-react' -import { FC } from 'react' +import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' +import { usePersonalityStore } from '../store/Store' +import { ImageSize, HorizontalAlignment, VerticalAlignment } from '../types/Types' const ImageSideBar: FC = () => { const { t } = useTranslation() + const { addImageToActiveItem, activeSection, activeItemIndex, data } = usePersonalityStore() + + const [imageSrc, setImageSrc] = useState('') + const [imageSize, setImageSize] = useState(ImageSize.COVER) + const [horizontalAlignment, setHorizontalAlignment] = useState(HorizontalAlignment.CENTER) + const [verticalAlignment, setVerticalAlignment] = useState(VerticalAlignment.MIDDLE) + const [isLoading, setIsLoading] = useState(false) + const [isReset, setIsReset] = useState(false) + + const sizeOptions = [ + { label: 'کاور - تمام فضا را پوشش دهد (Cover)', value: ImageSize.COVER }, + { label: 'در مقیاس - در فضا جا شود (Contain)', value: ImageSize.CONTAIN }, + { label: 'تکرار - عکس تکرار شود (Repeat)', value: ImageSize.REPEAT }, + { label: 'تکرار افقی (Repeat-X)', value: ImageSize.REPEAT_X }, + { label: 'تکرار عمودی (Repeat-Y)', value: ImageSize.REPEAT_Y }, + { label: 'بدون تکرار (No-Repeat)', value: ImageSize.NO_REPEAT }, + { label: 'اندازه اصلی (Auto)', value: ImageSize.AUTO } + ] + + const handleImageUpload = (files: File[]) => { + if (files.length === 0) return + + const file = files[0] // فقط اولین فایل را در نظر می‌گیریم + // در اینجا باید فایل آپلود شود و URL برگردانده شود + // فعلاً از FileReader استفاده می‌کنم برای تست + const reader = new FileReader() + reader.onload = (e) => { + const result = e.target?.result as string + setImageSrc(result) + } + reader.readAsDataURL(file) + } + + const handleAddImage = () => { + if (!imageSrc) return + + console.log('Store state before adding image:', { + activeSection, + activeItemIndex, + hasActiveItem: activeSection && data[activeSection as keyof typeof data]?.items[activeItemIndex], + }) + + // Validation + if (!activeSection) { + console.error('No active section selected') + return + } + + const sectionData = data[activeSection as keyof typeof data] + if (!sectionData?.items || activeItemIndex >= sectionData.items.length) { + console.error('No active item found or invalid index', { + activeItemIndex, + itemsLength: sectionData?.items?.length + }) + return + } + + console.log('Adding image with data:', { + src: imageSrc, + alt: 'عکس آپلود شده', + size: imageSize, + alignment: horizontalAlignment, + verticalAlignment, + }) + + setIsLoading(true) + + try { + addImageToActiveItem({ + src: imageSrc, + alt: 'عکس آپلود شده', + size: imageSize, + alignment: horizontalAlignment, + verticalAlignment, + }) + + console.log('Image added successfully') + + // Reset form after adding + setImageSrc('') + setImageSize(ImageSize.COVER) + setHorizontalAlignment(HorizontalAlignment.CENTER) + setVerticalAlignment(VerticalAlignment.MIDDLE) + setIsReset(true) + setTimeout(() => { + setIsReset(false) + }, 1000) + } catch (error) { + console.error('Error adding image:', error) + } finally { + setIsLoading(false) + } + } return (
@@ -15,7 +111,18 @@ const ImageSideBar: FC = () => {
null} + onChange={handleImageUpload} + isReset={isReset} + /> +
+ +
+ { + const newSize = e.target.value as BackgroundSize + setBackgroundSize(newSize) + + const currentItem = activeSection ? data[activeSection as keyof typeof data]?.items[activeItemIndex] : null + updateActiveItem({ + style: { + ...currentItem?.style, + backgroundSize: getBackgroundSize(newSize), + backgroundRepeat: getBackgroundRepeat(newSize), + backgroundPosition: 'center center' + } + }) + }} placeholder={t('setting.size')} />
- -
-
-
- {t('setting.horizontal_position')} -
-
- updateActiveItem({ alignment: 'right' })} - /> - updateActiveItem({ alignment: 'center' })} - /> - updateActiveItem({ alignment: 'left' })} - /> -
-
- -
-
- {t('setting.vertical_position')} -
-
- updateActiveItem({ verticalAlignment: 'bottom' })} - /> - updateActiveItem({ verticalAlignment: 'middle' })} - /> - updateActiveItem({ verticalAlignment: 'top' })} - /> -
-
-
) } diff --git a/src/pages/setting/personality/components/TextRenderer.tsx b/src/pages/setting/personality/components/TextRenderer.tsx new file mode 100644 index 0000000..ea0355f --- /dev/null +++ b/src/pages/setting/personality/components/TextRenderer.tsx @@ -0,0 +1,33 @@ +import { FC } from 'react' +import { TextType } from '../types/Types' + +interface TextRendererProps { + texts: TextType[] +} + +const TextRenderer: FC = ({ texts }) => { + return ( + <> + {texts?.map((textItem, textIndex) => ( + + + + + +
+
+ ))} + + ) +} + +export default TextRenderer \ No newline at end of file diff --git a/src/pages/setting/personality/components/TextSidebar.tsx b/src/pages/setting/personality/components/TextSidebar.tsx index 299ee68..bf7867b 100644 --- a/src/pages/setting/personality/components/TextSidebar.tsx +++ b/src/pages/setting/personality/components/TextSidebar.tsx @@ -3,11 +3,39 @@ import { Add, AlignBottom, AlignHorizontally, AlignLeft, AlignRight, AlignTop, A import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' import ReactQuill from 'react-quill-new'; +import { usePersonalityStore } from '../store/Store'; +import ColorPicker from '@/components/ColorPicker'; +import { HorizontalAlignment, VerticalAlignment } from '../types/Types'; const TextSidebar: FC = () => { const { t } = useTranslation() const [value, setValue] = useState(''); + const [color, setColor] = useState('#000'); + const [horizontalPosition, setHorizontalPosition] = useState(HorizontalAlignment.CENTER); + const [verticalPosition, setVerticalPosition] = useState(VerticalAlignment.MIDDLE); + const { addTextToActiveItem } = usePersonalityStore(); + + const handleChange = (value: string) => { + setValue(value); + } + + const handleAddText = () => { + if (value.trim()) { + addTextToActiveItem({ + text: value, + color: color, + verticalAlignment: verticalPosition, + alignment: horizontalPosition, + }); + + // خالی کردن فیلدها بعد از ذخیره + setValue(''); + setColor('#000'); + setHorizontalPosition(HorizontalAlignment.CENTER); + setVerticalPosition(VerticalAlignment.MIDDLE); + } + } return (
@@ -27,39 +55,71 @@ const TextSidebar: FC = () => { }} theme="snow" value={value} - onChange={setValue} + onChange={handleChange} style={{ minHeight: '120px' }} className='text-sm' />
+
+ +
+
{t('setting.horizontal_position')}
- - - +
setHorizontalPosition(HorizontalAlignment.RIGHT)} + > + +
+
setHorizontalPosition(HorizontalAlignment.CENTER)} + > + +
+
setHorizontalPosition(HorizontalAlignment.LEFT)} + > + +
- {t('setting.horizontal_position')} + {t('setting.vertical_position')}
- - - +
setVerticalPosition(VerticalAlignment.TOP)} + > + +
+
setVerticalPosition(VerticalAlignment.MIDDLE)} + > + +
+
setVerticalPosition(VerticalAlignment.BOTTOM)} + > + +