0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Changed NewsletterList to use new Table component (#17458)

refs https://github.com/TryGhost/Product/issues/3601

- `NewsletterList` now uses the new `Table` component, along with its
subcomponents `TableRow` and `TableCell` to be able to show more
relevant data
This commit is contained in:
Djordje Vlaisavljevic 2023-07-24 09:50:02 +01:00 committed by GitHub
parent 0aa5815b26
commit 5d5d33b930
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 261 additions and 14 deletions

View file

@ -0,0 +1,38 @@
import type {Meta, StoryObj} from '@storybook/react';
import Table from './Table';
import TableCell from './TableCell';
import TableRow from './TableRow';
const meta = {
title: 'Global / Table',
component: Table,
tags: ['autodocs']
} satisfies Meta<typeof Table>;
const tableRows = (
<>
<TableRow>
<TableCell>Jamie Larson</TableCell>
<TableCell>jamie@example.com</TableCell>
</TableRow>
<TableRow>
<TableCell>Jamie Larson</TableCell>
<TableCell>jamie@example.com</TableCell>
</TableRow>
<TableRow>
<TableCell>Jamie Larson</TableCell>
<TableCell>jamie@example.com</TableCell>
</TableRow>
</>
);
export default meta;
type Story = StoryObj<typeof Table>;
export const Default: Story = {
args: {
children: tableRows
},
decorators: [(_story: any) => (<div style={{maxWidth: '600px'}}>{_story()}</div>)]
};

View file

@ -0,0 +1,35 @@
import Heading from './Heading';
import React from 'react';
import clsx from 'clsx';
interface TableProps {
/**
* If the table is the primary content on a page (e.g. Members table) then you can set a pagetitle to be consistent
*/
pageTitle?: string;
children?: React.ReactNode;
borderTop?: boolean;
className?: string;
}
const Table: React.FC<TableProps> = ({children, borderTop, pageTitle, className}) => {
const tableClasses = clsx(
(borderTop || pageTitle) && 'border-t border-grey-300',
'w-full',
pageTitle ? 'mb-0 mt-14' : 'my-0',
className
);
return (
<>
{pageTitle && <Heading>{pageTitle}</Heading>}
<table className={tableClasses}>
<tbody>
{children}
</tbody>
</table>
</>
);
};
export default Table;

View file

@ -0,0 +1,22 @@
import React from 'react';
import clsx from 'clsx';
interface TableCellProps {
className?: string;
children?: React.ReactNode;
}
const TableCell: React.FC<TableCellProps> = ({className, children}) => {
const tableCellClasses = clsx(
'!py-3 !pl-0 !pr-6 align-top',
className
);
return (
<td className={tableCellClasses}>
{children}
</td>
);
};
export default TableCell;

View file

@ -0,0 +1,47 @@
import React from 'react';
import clsx from 'clsx';
interface TableRowProps {
id?: string;
action?: React.ReactNode;
hideActions?: boolean;
className?: string;
testId?: string;
/**
* Hidden for the last item in the table
*/
separator?: boolean;
bgOnHover?: boolean;
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
children?: React.ReactNode;
}
const TableRow: React.FC<TableRowProps> = ({id, action, hideActions, className, testId, separator, bgOnHover = true, onClick, children}) => {
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
onClick?.(e);
};
separator = (separator === undefined) ? true : separator;
const tableRowClasses = clsx(
'group',
bgOnHover && 'hover:bg-gradient-to-r hover:from-white hover:to-grey-50',
onClick && 'cursor-pointer',
separator ? 'border-b border-grey-100 last-of-type:border-b-transparent hover:border-grey-200' : 'border-y border-transparent hover:border-grey-200 first-of-type:hover:border-t-transparent',
className
);
return (
<tr className={tableRowClasses} data-testid={testId} id={id} onClick={handleClick}>
{children}
{action &&
<td className={`px-6 py-3 text-center ${hideActions ? 'invisible group-hover:visible' : ''}`}>
{action}
</td>
}
</tr>
);
};
export default TableRow;

View file

@ -1,14 +1,64 @@
import Button from '../../../../admin-x-ds/global/Button';
import List from '../../../../admin-x-ds/global/List';
import ListItem from '../../../../admin-x-ds/global/ListItem';
// import List from '../../../../admin-x-ds/global/List';
// import ListItem from '../../../../admin-x-ds/global/ListItem';
import NewsletterDetailModal from './NewsletterDetailModal';
import NiceModal from '@ebay/nice-modal-react';
import React from 'react';
import Table from '../../../../admin-x-ds/global/Table';
import TableCell from '../../../../admin-x-ds/global/TableCell';
import TableRow from '../../../../admin-x-ds/global/TableRow';
interface NewslettersListProps {
tab?: string;
}
// We should create a NewsletterItem component based on TableRow and then loop through newsletters
//
// interface NewsletterItemProps {
// name: string;
// description: string;
// subscribers: number;
// emailsSent: number;
// }
// const NewsletterItem: React.FC<NewsletterItemProps> = ({name, description, subscribers, emailsSent}) => {
// const action = tab === 'active-newsletters' ? (
// <Button color='green' label='Archive' link />
// ) : (
// <Button color='green' label='Activate' link />
// );
// return (
// <TableRow
// action={action}
// onClick={() => {
// NiceModal.show(NewsletterDetailModal);
// }}>
// hideActions
// separator
// >
// <TableCell>
// <div className={`flex grow flex-col`}>
// <span className='font-medium'>{name}</span>
// <span className='whitespace-nowrap text-xs text-grey-700'>{description}</span>
// </div>
// </TableCell>
// <TableCell>
// <div className={`flex grow flex-col`}>
// <span>{subscribers}</span>
// <span className='whitespace-nowrap text-xs text-grey-700'>Subscribers</span>
// </div>
// </TableCell>
// <TableCell>
// <div className={`flex grow flex-col`}>
// <span>{emailsSent}</span>
// <span className='whitespace-nowrap text-xs text-grey-700'>Emails sent</span>
// </div>
// </TableCell>
// </TableRow>
// );
// };
const NewslettersList: React.FC<NewslettersListProps> = ({
tab
}) => {
@ -19,26 +69,81 @@ const NewslettersList: React.FC<NewslettersListProps> = ({
);
return (
<List>
<ListItem
<Table>
<TableRow
action={action}
detail='This one is pretty good'
title='Amazing newsletter'
hideActions
onClick={() => {
NiceModal.show(NewsletterDetailModal);
}}
/>
<ListItem
}}>
<TableCell>
<div className={`flex grow flex-col`}>
<span className='font-medium'>Amazing newsletter</span>
<span className='whitespace-nowrap text-xs text-grey-700'>This one is pretty good</span>
</div>
</TableCell>
<TableCell>
<div className={`flex grow flex-col`}>
<span>259</span>
<span className='whitespace-nowrap text-xs text-grey-700'>Subscribers</span>
</div>
</TableCell>
<TableCell>
<div className={`flex grow flex-col`}>
<span>14</span>
<span className='whitespace-nowrap text-xs text-grey-700'>Emails sent</span>
</div>
</TableCell>
</TableRow>
<TableRow
action={action}
detail='This one is just spam'
title='Awful newsletter'
hideActions
onClick={() => {
NiceModal.show(NewsletterDetailModal);
}}
/>
</List>
}}>
<TableCell>
<div className={`flex grow flex-col`}>
<span className='line-clamp-1 font-medium'>Crappy newsletter</span>
<span className='whitespace-nowrap text-xs text-grey-700'>This one is just spam</span>
</div>
</TableCell>
<TableCell>
<div className={`flex grow flex-col`}>
<span>145</span>
<span className='whitespace-nowrap text-xs text-grey-700'>Subscribers</span>
</div>
</TableCell>
<TableCell>
<div className={`flex grow flex-col`}>
<span>754</span>
<span className='whitespace-nowrap text-xs text-grey-700'>Emails sent</span>
</div>
</TableCell>
</TableRow>
</Table>
// Newsletter list previously used the List component, can be removed
//
// <List>
// <ListItem
// action={action}
// detail='This one is pretty good'
// title='Amazing newsletter'
// hideActions
// onClick={() => {
// NiceModal.show(NewsletterDetailModal);
// }}
// />
// <ListItem
// action={action}
// detail='This one is just spam'
// title='Awful newsletter'
// hideActions
// onClick={() => {
// NiceModal.show(NewsletterDetailModal);
// }}
// />
// </List>
);
};