profile + summerize

This commit is contained in:
hamid zarghami
2025-07-24 17:17:55 +03:30
parent d8726db44e
commit cc744ebac9
24 changed files with 1063 additions and 20 deletions
+57
View File
@@ -0,0 +1,57 @@
import { FC, Fragment, ReactNode, useEffect } from 'react'
import HeaderModal from './HeaderModal'
interface Props {
open: boolean,
close: () => void,
children: ReactNode,
isHeader?: boolean,
title_header?: string,
width?: number
}
const DefaulModal: FC<Props> = (props: Props) => {
useEffect(() => {
if (props.open) {
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = 'auto'
}
}, [props.open])
return (
<Fragment>
{
props.open && (
<Fragment>
<div style={{ maxWidth: props.width }} className='xl:justify-center xl:items-center items-end flex overflow-x-hidden overflow-y-auto fixed inset-0 z-[60] h-auto top-0 bottom-0 m-auto outline-none focus:outline-none xl:max-w-xl mx-auto'>
<div className='relative xl:h-full max-h-[80%] bottom-0 left-0 flex xl:items-center sm:h-auto w-full xl:my-6 xl:p-2'>
<div className='border-0 h-auto p-5 lg:min-w-full overflow-y-auto rounded-3xl rounded-b-none xl:rounded-b-3xl relative flex flex-col w-full modalGlass2 outline-none focus:outline-none'>
{
props.isHeader && props.title_header &&
<div onClick={props.close} className='pb-6 border-b border-white border-opacity-20'>
<div className='h-[5px] w-[200px] mx-auto bg-[#D1D3D7] rounded-full mb-4 xl:hidden'></div>
<HeaderModal close={props.close} label={props.title_header} />
</div>
}
{props.children}
</div>
</div>
</div>
<div onClick={props.close} className='fixed size-full bg-black/3 top-0 bottom-0 right-0 inset-0 z-50 '></div>
</Fragment>
)
}
</Fragment>
)
}
export default DefaulModal
+21
View File
@@ -0,0 +1,21 @@
import { FC } from 'react'
import { CloseCircle } from 'iconsax-react'
type Props = {
label: string,
close: () => void,
}
const HeaderModal: FC<Props> = (props: Props) => {
return (
<div className='flex justify-between items-center'>
<div className='text-sm'>{props.label}</div>
<div className='size-7 rounded-full bg-white bg-opacity-35 flex justify-center items-center'>
<CloseCircle size={16} color='white' onClick={props.close} />
</div>
</div>
)
}
export default HeaderModal
+94 -7
View File
@@ -25,6 +25,7 @@ const Table = <T extends RowDataType>({
selectedRows: externalSelectedRows,
clearSelection = false,
rowActions,
inlineActions,
pagination,
}: TableProps<T>): React.ReactElement => {
@@ -145,9 +146,30 @@ const Table = <T extends RowDataType>({
checked={isRowSelected(item)}
onCheckedChange={(checked) => handleSingleRowSelect(item, !!checked)}
/>
{/* {inlineActions && (
<div
className="flex-shrink-0 flex items-center gap-2 relative z-[5]"
onClick={(e) => e.stopPropagation()}
>
{inlineActions(item).map((action, actionIndex) => (
<div
key={actionIndex}
className={`cursor-pointer ${action.className || ''}`}
onClick={action.onClick}
title={action.tooltip}
>
{action.icon}
</div>
))}
</div>
)} */}
</div>
)}
{/* Inline Actions - بعد از checkbox */}
<div className="flex-1 min-w-0">
{/* محتوای اصلی - ستون اول */}
<div className={`flex items-center mb-0.5 text-sm ${fontWeight}`}>
@@ -185,7 +207,7 @@ const Table = <T extends RowDataType>({
if (isLoading) {
return (
<Fragment>
<DefaultTableSkeleton tdCount={columns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0)} trCount={emptyRowsCount} />
<DefaultTableSkeleton tdCount={columns.length + (selectable ? 1 : 0) + (inlineActions ? 1 : 0) + (rowActions ? 1 : 0)} trCount={emptyRowsCount} />
</Fragment>
);
}
@@ -193,7 +215,7 @@ const Table = <T extends RowDataType>({
if (data.length === 0) {
return (
<tr>
<td colSpan={columns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0)} className="px-3 md:px-6 pb-6 md:pb-8 text-center text-gray-500">
<td colSpan={columns.length + (selectable ? 1 : 0) + (inlineActions ? 1 : 0) + (rowActions ? 1 : 0)} className="px-3 md:px-6 pb-6 md:pb-8 text-center text-gray-500">
{noDataMessage}
</td>
</tr>
@@ -217,12 +239,32 @@ const Table = <T extends RowDataType>({
className="px-3 md:px-6 py-3 md:py-4 w-8 md:w-10 relative z-[5]"
onClick={(e) => e.stopPropagation()}
>
<Checkbox
checked={isRowSelected(item)}
onCheckedChange={(checked) => handleSingleRowSelect(item, !!checked)}
/>
<div className='flex items-center gap-3'>
<Checkbox
checked={isRowSelected(item)}
onCheckedChange={(checked) => handleSingleRowSelect(item, !!checked)}
/>
{
inlineActions && (
<div className="flex items-center gap-2">
{inlineActions(item).map((action, actionIndex) => (
<div
key={actionIndex}
className={`cursor-pointer ${action.className || ''}`}
onClick={action.onClick}
title={action.tooltip}
>
{action.icon}
</div>
))}
</div>
)
}
</div>
</td>
)}
{columns.map((col) => (
<td
key={`${item.id}-${col.key}`}
@@ -262,6 +304,9 @@ const Table = <T extends RowDataType>({
/>
</th>
)}
{inlineActions && (
<th className="px-3 md:px-6 py-3 md:py-4 text-center text-sm font-medium">عملیات</th>
)}
{columns.map((col) => (
<Td key={col.key} text={col.title} />
))}
@@ -343,7 +388,7 @@ const Table = <T extends RowDataType>({
{actionsPosition === 'header-replace' && (
<thead>
<tr>
<th colSpan={columns.length} className="p-0">
<th colSpan={columns.length + (selectable ? 1 : 0) + (inlineActions ? 1 : 0) + (rowActions ? 1 : 0)} className="p-0">
{renderActions()}
</th>
</tr>
@@ -405,4 +450,46 @@ const MyComponent = () => {
/>
);
};
مثال استفاده با inline actions:
import Table from '@/components/Table';
import { Star1, Archive } from 'iconsax-react';
const MyEmailComponent = () => {
const columns = [
{ title: 'موضوع', key: 'subject' },
{ title: 'فرستنده', key: 'from' },
];
const data = [
{ id: 1, subject: 'سلام', from: 'ali@example.com', flagged: false },
{ id: 2, subject: 'خبرنامه', from: 'newsletter@example.com', flagged: true },
];
const getInlineActions = (item) => [
{
icon: <Star1
variant={item.flagged ? 'Bold' : 'Outline'}
size={18}
color={item.flagged ? '#FFC107' : '#8C90A3'}
/>,
onClick: () => handleFavoriteToggle(item.id),
tooltip: item.flagged ? 'حذف از علاقه‌مندی‌ها' : 'اضافه به علاقه‌مندی‌ها'
},
{
icon: <Archive size={18} color="#8C90A3" />,
onClick: () => handleArchive(item.id),
tooltip: 'بایگانی'
}
];
return (
<Table
columns={columns}
data={data}
inlineActions={getInlineActions}
/>
);
};
*/
+8
View File
@@ -19,6 +19,13 @@ export interface PaginationConfig {
onPageChange: (page: number) => void;
}
export interface InlineActionItem {
icon: React.ReactNode;
onClick: () => void;
tooltip?: string;
className?: string;
}
export interface TableProps<T extends RowDataType = RowDataType> {
columns: ColumnType<T>[];
data: T[];
@@ -39,5 +46,6 @@ export interface TableProps<T extends RowDataType = RowDataType> {
selectedRows?: T[];
clearSelection?: boolean;
rowActions?: (item: T) => RowActionItem[];
inlineActions?: (item: T) => InlineActionItem[];
pagination?: PaginationConfig;
}