From f4f617f8d2441e251590d06003e3e2a4309d5392 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 14 Mar 2026 16:15:09 +0330 Subject: [PATCH] add components for modal --- src/components/DefaulModal.tsx | 62 ++++++++++++++++++++++++++ src/components/HeaderModal.tsx | 25 +++++++++++ src/components/ModalConfrim.tsx | 69 +++++++++++++++++++++++++++++ src/components/Textarea.tsx | 39 ++++++++++++++++ src/components/TrashWithConfrim.tsx | 30 +++++++++++++ 5 files changed, 225 insertions(+) create mode 100644 src/components/DefaulModal.tsx create mode 100644 src/components/HeaderModal.tsx create mode 100644 src/components/ModalConfrim.tsx create mode 100644 src/components/Textarea.tsx create mode 100644 src/components/TrashWithConfrim.tsx diff --git a/src/components/DefaulModal.tsx b/src/components/DefaulModal.tsx new file mode 100644 index 0000000..abb9a68 --- /dev/null +++ b/src/components/DefaulModal.tsx @@ -0,0 +1,62 @@ +import { type FC, Fragment, type ReactNode, useEffect } from 'react' +import { createPortal } from 'react-dom' +import HeaderModal from './HeaderModal' + +interface Props { + open: boolean, + close: () => void, + children: ReactNode, + isHeader?: boolean, + title_header?: string, + width?: number +} + +const DefaulModal: FC = (props: Props) => { + + useEffect(() => { + if (props.open) { + document.body.style.overflow = 'hidden' + } else { + document.body.style.overflow = 'auto' + } + }, [props.open]) + + + const modalContent = props.open ? ( + +
+
+
e.stopPropagation()} + > +
+ + + { + props.isHeader && props.title_header && +
+
+ +
+ } + + {props.children} + + +
+
+
+ + ) : null + + return createPortal(modalContent, document.body) +} + +export default DefaulModal \ No newline at end of file diff --git a/src/components/HeaderModal.tsx b/src/components/HeaderModal.tsx new file mode 100644 index 0000000..5943cdf --- /dev/null +++ b/src/components/HeaderModal.tsx @@ -0,0 +1,25 @@ +import { CloseCircle } from 'iconsax-react' +import { type FC } from 'react' + + +type Props = { + label: string, + close: () => void, +} + +const HeaderModal: FC = (props: Props) => { + return ( +
+
{props.label}
+
+ +
+
+ ) +} + +export default HeaderModal \ No newline at end of file diff --git a/src/components/ModalConfrim.tsx b/src/components/ModalConfrim.tsx new file mode 100644 index 0000000..3ad0ab7 --- /dev/null +++ b/src/components/ModalConfrim.tsx @@ -0,0 +1,69 @@ +import { type FC, useState } from 'react' +import DefaulModal from './DefaulModal' +import { useTranslation } from 'react-i18next' +import Button from './Button' +import Textarea from './Textarea' + +type Props = { + isloading?: boolean, + close: () => void, + isOpen: boolean, + onConfrim: (text?: string) => void, + label?: string, + isHasDescription?: boolean +} + +const ModalConfrim: FC = (props: Props) => { + + const { t } = useTranslation('global') + const [description, setDescription] = useState('') + + return ( + +
+
+ { + props.label ? + props.label + : + t('confrim.content') + } + + { + props.isHasDescription && +
+ + + { + props.error_text && + + } + +
+ ) +} + +export default Textarea \ No newline at end of file diff --git a/src/components/TrashWithConfrim.tsx b/src/components/TrashWithConfrim.tsx new file mode 100644 index 0000000..1a712e9 --- /dev/null +++ b/src/components/TrashWithConfrim.tsx @@ -0,0 +1,30 @@ +import { Trash } from 'iconsax-react' +import { type FC, useState } from 'react' +import ModalConfrim from './ModalConfrim' + +interface Props { + onDelete: () => void, + isloading?: boolean +} + +const TrashWithConfrim: FC = ({ onDelete, isloading = false }) => { + const [isConfirm, setIsConfirm] = useState(false) + return ( +
+ setIsConfirm(true)} + className='size-5' + color='#888' + /> + + setIsConfirm(false)} + onConfrim={() => onDelete()} + isloading={isloading} + /> +
+ ) +} + +export default TrashWithConfrim \ No newline at end of file