Skip to content

Commit

Permalink
feat: migrate pricing page table, convert to semantic HTML tags, open…
Browse files Browse the repository at this point in the history
… up structure like Radix
  • Loading branch information
jamiehenson committed Mar 26, 2024
1 parent 501643f commit 43a5696
Show file tree
Hide file tree
Showing 6 changed files with 332 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/core/Table/Table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { PropsWithChildren, ReactElement, cloneElement } from "react";

type TableProps = {
id?: string;
};

export const Table = ({ id, children }: PropsWithChildren<TableProps>) => (
<table id={id} className="ui-standard-container mb-4 sm:table-fixed">
{children}
</table>
);

export const TableBody = ({ children }: PropsWithChildren) => (
<tbody>{children}</tbody>
);

export const TableHeader = ({ children }: PropsWithChildren) => (
<thead className="sticky bg-white z-10 top-0" key="sticky-block">
{cloneElement(children as ReactElement, { isHeader: true })}
</thead>
);

export const TableRowHeader = ({ children }: PropsWithChildren) => (
<tr
className="-ml-24 mt-8 sm:ml-0 sm:mt-0 ui-text-overline1 !text-cool-black bg-light-grey sm:sticky z-10"
style={{ top: "4rem" }}
>
{cloneElement(children as ReactElement, { isRowHeader: true })}
</tr>
);
84 changes: 84 additions & 0 deletions src/core/Table/TableCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { PropsWithChildren } from "react";
import Icon from "../Icon/component.tsx";

type TableCellProps = {
isRowHeader?: boolean;
} & React.TdHTMLAttributes<HTMLTableCellElement>;

const Supported = () => (
<Icon
name="icon-gui-check-circled-fill"
size="1.5rem"
color="text-gui-success"
additionalCSS="flex-grow-0 flex-shrink-0"
data-testid="supported-icon"
/>
);

const Unsupported = () => (
<Icon
name="icon-gui-cross-circled-fill"
size="1.5rem"
color="text-gui-error"
additionalCSS="flex-grow-0 flex-shrink-0"
data-testid="unsupported-icon"
/>
);

const LabelCell = ({
children,
...rest
}: PropsWithChildren<React.TdHTMLAttributes<HTMLTableCellElement>>) => {
const classes = `
ui-text-p1 !font-bold pt-24 pb-8 border-light-grey sm:p-24 sm:relative sm:top-2 flex sm:table-cell ${
rest.className ?? ""
}
`;

return (
<td {...rest} className={classes}>
{children}
</td>
);
};

const TableCell = ({
children,
isRowHeader,
...rest
}: PropsWithChildren<TableCellProps>) => (
<td
{...rest}
className={`
border-light-grey sm:p-24 leading-none flex sm:table-cell
${
isRowHeader
? "rounded-l-none rounded-r sm:rounded-lg py-20 px-24"
: "py-6"
}
${rest.className ?? ""}
`}
>
{children}
</td>
);

const HeaderCell = ({
children,
...rest
}: PropsWithChildren<React.TdHTMLAttributes<HTMLTableCellElement>>) => (
<td {...rest} className="ui-text-h3 px-24 py-24 hidden sm:table-cell">
{children}
</td>
);

const CtaCell = ({
children,
...rest
}: PropsWithChildren<React.TdHTMLAttributes<HTMLTableCellElement>>) => (
<td {...rest} className="pt-24 hidden sm:table-cell">
{children}
</td>
);

export { TableCell, LabelCell, HeaderCell, CtaCell, Supported, Unsupported };
25 changes: 25 additions & 0 deletions src/core/Table/TableRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { PropsWithChildren } from "react";

const CtaRow = ({ children }: PropsWithChildren) => (
<tr>
<td className="hidden sm:block"></td>
{children}
</tr>
);

type RowProps = {
isHeader?: boolean;
} & React.HTMLAttributes<HTMLTableRowElement>;

const TableRow = ({
children,
isHeader,
...rest
}: PropsWithChildren<RowProps>) => (
<tr {...rest}>
{isHeader && <td className="bg-white" />}
{children}
</tr>
);

export { TableRow, CtaRow };
24 changes: 24 additions & 0 deletions src/core/Table/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Table, TableRowHeader, TableHeader, TableBody } from "./Table";
import { TableRow } from "./TableRow";
import {
TableCell,
LabelCell,
HeaderCell,
CtaCell,
Supported,
Unsupported,
} from "./TableCell";

export default {
Root: Table,
Row: TableRow,
Cell: TableCell,
LabelCell,
HeaderCell,
CtaCell,
RowHeader: TableRowHeader,
Body: TableBody,
Header: TableHeader,
Supported,
Unsupported,
};
16 changes: 16 additions & 0 deletions src/core/Table/stories/Table.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from "react";
import { Table } from "../Table";
import { PricingPageTable } from "./data";

export default {
title: "Components/Table",
component: Table,
tags: ["autodocs"],
parameters: {
layout: "fullscreen",
},
};

export const PricingPage = {
render: () => <PricingPageTable />,
};
153 changes: 153 additions & 0 deletions src/core/Table/stories/data.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import React, { Fragment, ReactNode } from "react";

import Tooltip from "../../Tooltip/component";
import { Supported, Unsupported } from "../TableCell";
import Table from "..";

const testRow = (index) => ({
label: `Label ${index + 1}`,
cells: [
{ label: "text", content: "Cell content", column: "Free" },
{
label: "yes",
content: (
<div className="flex items-center sm:flex-col sm:items-start">
<span className="sm:order-1 px-6 sm:py-6 sm:px-0">Supported</span>
<span className="sm:order-0">
<Supported />
</span>
</div>
),
column: "PAYG",
},
{
label: "no",
content: (
<div className="flex items-center sm:flex-col sm:items-start">
<span className="sm:order-1 px-6 sm:py-6 sm:px-0">Unsupported</span>
<span className="sm:order-0">
<Unsupported />
</span>
</div>
),
column: "Committed Use",
},
],
});

const sections = ["Features", "Support", "Technical Support"].map((label) => ({
label,
rows: [...Array(5)].map((_, i) => testRow(i)),
}));

type PricingPageTableCellProps = {
packageName: string;
content: ReactNode;
icon: ReactNode;
};

export const PricingPageTableCell = ({
packageName,
content,
icon,
}: PricingPageTableCellProps) => {
const mobile = (
<>
<p className="text-dark-grey ui-text-overline2 flex-shrink-0">
{packageName}
</p>
<div className="ml-auto flex items-center pl-12">
{content ? (
<p className="ui-text-p2 text-right mr-12">{content}</p>
) : null}
<div className="relative top-1">{icon}</div>
</div>
</>
);

const desktop = (
<>
{icon}
{content ? <p className="ui-text-p2 mt-12">{content}</p> : null}
</>
);

return (
<>
<div className="hidden sm:block">{desktop}</div>
<div className="flex sm:hidden items-center">{mobile}</div>
</>
);
};

export const PricingPageTable = () => {
return (
<div className="ui-standard-container">
<h2 className="ui-text-h2 text-center m-32">Pricing Page Table</h2>
<p className="text-center m-32">Example content</p>
<Table.Root>
<Table.Header>
<Table.Row>
<Table.Cell>
<span className="ui-text-h3 hidden sm:block">Free</span>
</Table.Cell>
<Table.Cell>
<span className="ui-text-h3 hidden sm:block">PAYG</span>
</Table.Cell>
<Table.Cell>
<span className="ui-text-h3 hidden sm:block">Committed Use</span>
</Table.Cell>
</Table.Row>
</Table.Header>
<Table.Body>
{sections.map((section) => (
<Fragment key={section.label}>
<Table.RowHeader>
<Table.Cell colSpan={4}>{section.label}</Table.Cell>
</Table.RowHeader>
{section.rows.map((row) => (
<Table.Row key={row.label}>
<Table.LabelCell
key={row.label}
className="border-t border-light-grey"
>
<a className="ui-link" href="#">
{row.label}
</a>
<Tooltip>Example tooltip</Tooltip>
</Table.LabelCell>
{row.cells.map((cell) => (
<Table.Cell key={cell.label} className="last:mb-16 sm:mb-0">
<div className="flex-1 sm:hidden !text-dark-grey ui-text-overline2">
{cell.column}
</div>
{cell.content}
</Table.Cell>
))}
</Table.Row>
))}
</Fragment>
))}
<Table.Row>
<Table.Cell></Table.Cell>
<Table.CtaCell>
<a href="#" className="ui-btn-secondary">
Get started
</a>
</Table.CtaCell>
<Table.CtaCell>
<a href="#" className="ui-btn-secondary">
Get started
</a>
</Table.CtaCell>
<Table.CtaCell>
<a href="#" className="ui-btn">
Contact sales
</a>
</Table.CtaCell>
</Table.Row>
</Table.Body>
</Table.Root>
</div>
);
};

0 comments on commit 43a5696

Please sign in to comment.