From 2e16ecc88c2b0fab331efcf6bdaf6951996e4ab6 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 28 Jun 2025 16:26:01 +0330 Subject: [PATCH] table like gmail and openn and close new messsage with animation +... --- src/components/Table.tsx | 122 +++++++++++++++++++++++ src/components/newMessage/NewMessage.tsx | 43 ++++++-- src/shared/SideBar.tsx | 6 +- 3 files changed, 162 insertions(+), 9 deletions(-) diff --git a/src/components/Table.tsx b/src/components/Table.tsx index bb0da07..dac4838 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -68,6 +68,81 @@ const Table = ({ return selectedRows.some((row) => row.id === item.id); }; + // Gmail-style layout برای وقتی header نمایش داده نمی‌شود + const renderGmailStyleRows = () => { + const hasActions = (actionsPosition === 'top' || actionsPosition === 'above-header') && (actions || (selectable && selectedRows.length > 0 && selectedActions)); + const roundedClass = hasActions ? 'rounded-b-2xl' : 'rounded-2xl'; + + if (isLoading) { + return ( +
+ {Array.from({ length: emptyRowsCount }).map((_, index) => ( +
+ ))} +
+ ); + } + + if (data.length === 0) { + return ( +
+ {noDataMessage} +
+ ); + } + + return ( +
+ {data.map((item, rowIndex) => ( +
handleRowClick(item)} + > + {selectable && ( +
e.stopPropagation()} + > + handleSingleRowSelect(item, !!checked)} + /> +
+ )} + +
+ {/* محتوای اصلی - ستون اول */} +
+ {columns[0]?.render ? columns[0].render(item) : (item[columns[0]?.key] as React.ReactNode)} +
+ + {/* اطلاعات اضافی - سه ستون آخر در یک خط */} + {columns.length > 1 && ( +
+ {columns.slice(1).map((col) => ( +
+ {col.render ? col.render(item) : (item[col.key] as React.ReactNode)} +
+ ))} +
+ )} +
+ + {rowActions && ( +
e.stopPropagation()} + > + +
+ )} +
+ ))} +
+ ); + }; + const renderTableBody = () => { if (isLoading) { return ( @@ -165,6 +240,53 @@ const Table = ({ ); }; + // اگر header نشان داده نمی‌شود، از Gmail-style layout فقط در موبایل استفاده کن + if (!showHeader) { + return ( +
+ {/* نسخه موبایل - Gmail style */} +
+ {(actionsPosition === 'top' || actionsPosition === 'above-header') && ( +
+
+ {actions} + {selectable && selectedRows.length > 0 && selectedActions && selectedActions} +
+
+ )} + {renderGmailStyleRows()} +
+ + {/* نسخه دسکتاپ - Table معمولی */} +
+ {(actionsPosition === 'top' || actionsPosition === 'above-header') && ( +
+
+ {actions} + {selectable && selectedRows.length > 0 && selectedActions && selectedActions} +
+
+ )} +
0 && selectedActions)) ? 'rounded-b-3xl' : 'rounded-3xl'} bg-white`}> + + + {renderTableBody()} + +
+
+
+ + {pagination && ( + + )} +
+ ); + } + return (
{(actionsPosition === 'top' || actionsPosition === 'above-header') && renderActions()} diff --git a/src/components/newMessage/NewMessage.tsx b/src/components/newMessage/NewMessage.tsx index b514f68..b89533a 100644 --- a/src/components/newMessage/NewMessage.tsx +++ b/src/components/newMessage/NewMessage.tsx @@ -1,4 +1,4 @@ -import { FC, useState } from 'react' +import { FC, useState, useEffect } from 'react' import { CloseCircle } from 'iconsax-react' import { useTranslation } from 'react-i18next' import { useSharedStore } from '@/shared/store/sharedStore' @@ -12,22 +12,53 @@ const NewMessage: FC = () => { const { t } = useTranslation('global') const [value, setValue] = useState(''); const { setOpenNewMessage, openNewMessage } = useSharedStore() + const [isClosing, setIsClosing] = useState(false) + const [shouldRender, setShouldRender] = useState(false) + const [isOpening, setIsOpening] = useState(false) + + useEffect(() => { + if (openNewMessage) { + setShouldRender(true) + setIsClosing(false) + setIsOpening(true) + // شروع انیمیشن باز شدن بعد از رندر + setTimeout(() => { + setIsOpening(false) + }, 50) + } else if (shouldRender) { + setIsClosing(true) + const timer = setTimeout(() => { + setShouldRender(false) + setIsClosing(false) + }, 300) + return () => clearTimeout(timer) + } + }, [openNewMessage, shouldRender]) + + const handleClose = () => { + setIsClosing(true) + setTimeout(() => { + setOpenNewMessage(false) + }, 300) + } return ( <> - {openNewMessage && ( + {shouldRender && ( <>
setOpenNewMessage(false)} + className={`fixed inset-0 xl:bg-transparent bg-black/50 z-[9998] transition-opacity duration-300 ${isClosing ? 'opacity-0' : isOpening ? 'opacity-0' : 'opacity-100' + }`} + onClick={handleClose} /> -
+
{/* Header */}
{t('new_message.title')}
-
setOpenNewMessage(false)} className='cursor-pointer p-1'> +
diff --git a/src/shared/SideBar.tsx b/src/shared/SideBar.tsx index 41ebf81..44718f3 100644 --- a/src/shared/SideBar.tsx +++ b/src/shared/SideBar.tsx @@ -27,8 +27,8 @@ const SideBar: FC = () => { }
@@ -50,7 +50,7 @@ const SideBar: FC = () => {
-
+
{t('sidebar.menu')}