From 5d5d33b930f1dffd35fb046cc7336f6951709ea0 Mon Sep 17 00:00:00 2001 From: Djordje Vlaisavljevic Date: Mon, 24 Jul 2023 09:50:02 +0100 Subject: [PATCH] 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 --- .../src/admin-x-ds/global/Table.stories.tsx | 38 +++++ .../src/admin-x-ds/global/Table.tsx | 35 +++++ .../src/admin-x-ds/global/TableCell.tsx | 22 +++ .../src/admin-x-ds/global/TableRow.tsx | 47 +++++++ .../email/newsletters/NewslettersList.tsx | 133 ++++++++++++++++-- 5 files changed, 261 insertions(+), 14 deletions(-) create mode 100644 apps/admin-x-settings/src/admin-x-ds/global/Table.stories.tsx create mode 100644 apps/admin-x-settings/src/admin-x-ds/global/Table.tsx create mode 100644 apps/admin-x-settings/src/admin-x-ds/global/TableCell.tsx create mode 100644 apps/admin-x-settings/src/admin-x-ds/global/TableRow.tsx diff --git a/apps/admin-x-settings/src/admin-x-ds/global/Table.stories.tsx b/apps/admin-x-settings/src/admin-x-ds/global/Table.stories.tsx new file mode 100644 index 0000000000..50017a1a03 --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/global/Table.stories.tsx @@ -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; + +const tableRows = ( + <> + + Jamie Larson + jamie@example.com + + + Jamie Larson + jamie@example.com + + + Jamie Larson + jamie@example.com + + +); + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: tableRows + }, + decorators: [(_story: any) => (
{_story()}
)] +}; diff --git a/apps/admin-x-settings/src/admin-x-ds/global/Table.tsx b/apps/admin-x-settings/src/admin-x-ds/global/Table.tsx new file mode 100644 index 0000000000..b25d93da73 --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/global/Table.tsx @@ -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 = ({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 && {pageTitle}} + + + {children} + +
+ + ); +}; + +export default Table; \ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/global/TableCell.tsx b/apps/admin-x-settings/src/admin-x-ds/global/TableCell.tsx new file mode 100644 index 0000000000..5d512a18e7 --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/global/TableCell.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import clsx from 'clsx'; + +interface TableCellProps { + className?: string; + children?: React.ReactNode; +} + +const TableCell: React.FC = ({className, children}) => { + const tableCellClasses = clsx( + '!py-3 !pl-0 !pr-6 align-top', + className + ); + + return ( + + {children} + + ); +}; + +export default TableCell; diff --git a/apps/admin-x-settings/src/admin-x-ds/global/TableRow.tsx b/apps/admin-x-settings/src/admin-x-ds/global/TableRow.tsx new file mode 100644 index 0000000000..48495104aa --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/global/TableRow.tsx @@ -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) => void; + children?: React.ReactNode; +} + +const TableRow: React.FC = ({id, action, hideActions, className, testId, separator, bgOnHover = true, onClick, children}) => { + const handleClick = (e: React.MouseEvent) => { + 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 ( + + {children} + {action && + + {action} + + } + + ); +}; + +export default TableRow; diff --git a/apps/admin-x-settings/src/components/settings/email/newsletters/NewslettersList.tsx b/apps/admin-x-settings/src/components/settings/email/newsletters/NewslettersList.tsx index 78d7abdb13..7579585216 100644 --- a/apps/admin-x-settings/src/components/settings/email/newsletters/NewslettersList.tsx +++ b/apps/admin-x-settings/src/components/settings/email/newsletters/NewslettersList.tsx @@ -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 = ({name, description, subscribers, emailsSent}) => { +// const action = tab === 'active-newsletters' ? ( +//