-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
feat: create responsive table #8079
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
1cb18b0
feat: create card component
araujogui 17793ff
feat: create responsive table
araujogui 5bb7a10
refactor(PreviousReleasesTable): use responsive table
araujogui 9be3ae1
refactor: remove type casting
araujogui a6731ee
fix: add accessibility attributes
araujogui 4da53c7
refactor: remove classname concatenation
araujogui 6a1a1a3
feat: add markdown support
araujogui c8a6a01
fix: remove flex container
araujogui 8a37bfa
fix: uppercase
araujogui 2d40b7f
refactor: review
araujogui File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
@reference "../../styles/index.css"; | ||
|
||
.card { | ||
@apply rounded-xs | ||
border | ||
border-neutral-200 | ||
bg-transparent | ||
p-4 | ||
dark:border-neutral-800; | ||
|
||
.header { | ||
@apply mb-2 | ||
text-sm | ||
font-medium | ||
text-gray-500 | ||
dark:text-gray-400; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import type { Meta as MetaObj, StoryObj } from '@storybook/react'; | ||
|
||
import { Card, CardHeader, CardBody } from './index'; | ||
|
||
type Story = StoryObj<typeof Card>; | ||
type Meta = MetaObj<typeof Card>; | ||
|
||
export const Default: Story = { | ||
render: args => ( | ||
<Card {...args}> | ||
<CardHeader>Card Header</CardHeader> | ||
<CardBody>Card Body Content</CardBody> | ||
</Card> | ||
), | ||
}; | ||
|
||
export default { | ||
component: Card, | ||
} as Meta; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import classNames from 'classnames'; | ||
import type { ComponentPropsWithRef, FC } from 'react'; | ||
|
||
import styles from './index.module.css'; | ||
|
||
type CardProps = ComponentPropsWithRef<'div'>; | ||
|
||
export const Card: FC<CardProps> = ({ className, ...props }) => { | ||
return <div className={classNames(styles.card, className)} {...props} />; | ||
}; | ||
|
||
export const CardHeader: FC<CardProps> = ({ className, ...props }) => { | ||
return <div className={classNames(styles.header, className)} {...props} />; | ||
}; | ||
|
||
export const CardBody: FC<CardProps> = props => { | ||
return <div {...props} />; | ||
}; |
32 changes: 32 additions & 0 deletions
32
packages/ui-components/src/Common/ResponsiveTable/DesktopTable/index.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import type { TableData } from '#ui/types'; | ||
|
||
import type { ResponsiveTableProps } from '..'; | ||
|
||
function DesktopTable<T extends TableData>({ | ||
data, | ||
columns, | ||
getRowId, | ||
}: ResponsiveTableProps<T>) { | ||
return ( | ||
<table> | ||
<thead> | ||
<tr> | ||
{columns.map(column => ( | ||
<th key={column.key}>{column.header}</th> | ||
))} | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{data.map((row, index) => ( | ||
<tr key={getRowId(row, index)}> | ||
{columns.map(column => ( | ||
<td key={column.key}>{row[column.key]}</td> | ||
))} | ||
</tr> | ||
))} | ||
</tbody> | ||
araujogui marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</table> | ||
); | ||
} | ||
|
||
export default DesktopTable; |
25 changes: 25 additions & 0 deletions
25
packages/ui-components/src/Common/ResponsiveTable/MobileTable/index.module.css
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
@reference "../../../styles/index.css"; | ||
|
||
.row { | ||
@apply flex | ||
items-center | ||
justify-between | ||
gap-2 | ||
border-b | ||
border-gray-100 | ||
py-2 | ||
last:border-b-0 | ||
dark:border-neutral-800; | ||
|
||
.header { | ||
@apply font-medium | ||
text-gray-700 | ||
dark:text-gray-200; | ||
} | ||
|
||
.value { | ||
@apply text-right | ||
text-gray-600 | ||
dark:text-gray-300; | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
packages/ui-components/src/Common/ResponsiveTable/MobileTable/index.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import type { TableData } from '#ui/types'; | ||
|
||
import type { ResponsiveTableProps } from '..'; | ||
import styles from './index.module.css'; | ||
import { Card, CardBody, CardHeader } from '../../Card'; | ||
|
||
function MobileTable<T extends TableData>({ | ||
data, | ||
columns, | ||
getRowId, | ||
getRowLabel, | ||
}: ResponsiveTableProps<T>) { | ||
return ( | ||
<div role="table" className="space-y-4"> | ||
{data.map((row, index) => ( | ||
<Card role="rowgroup" key={getRowId(row, index)}> | ||
{getRowLabel && <CardHeader>{getRowLabel(row)}</CardHeader>} | ||
|
||
<CardBody role="row"> | ||
{columns.map(column => ( | ||
<div key={column.key} className={styles.row}> | ||
<div role="columnheader" className={styles.header}> | ||
{column.header} | ||
</div> | ||
|
||
<div role="cell" className={styles.value}> | ||
{row[column.key]} | ||
</div> | ||
</div> | ||
))} | ||
</CardBody> | ||
</Card> | ||
))} | ||
</div> | ||
); | ||
} | ||
|
||
export default MobileTable; |
25 changes: 25 additions & 0 deletions
25
packages/ui-components/src/Common/ResponsiveTable/index.stories.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import type { Meta as MetaObj, StoryObj } from '@storybook/react'; | ||
|
||
import ResponsiveTable from './index'; | ||
|
||
type Story = StoryObj<typeof ResponsiveTable>; | ||
type Meta = MetaObj<typeof ResponsiveTable>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
data: [ | ||
{ id: 1, name: 'John Doe', email: '[email protected]' }, | ||
{ id: 2, name: 'Jane Smith', email: '[email protected]' }, | ||
{ id: 3, name: 'Bob Johnson', email: '[email protected]' }, | ||
], | ||
columns: [ | ||
{ key: 'id', header: 'ID' }, | ||
{ key: 'name', header: 'Name' }, | ||
{ key: 'email', header: 'Email' }, | ||
], | ||
getRowId: row => String(row.id), | ||
getRowLabel: row => String(row.name), | ||
}, | ||
}; | ||
|
||
export default { component: ResponsiveTable } as Meta; |
27 changes: 27 additions & 0 deletions
27
packages/ui-components/src/Common/ResponsiveTable/index.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import type { TableColumn, TableData } from '#ui/types'; | ||
|
||
import DesktopTable from './DesktopTable'; | ||
import MobileTable from './MobileTable'; | ||
|
||
export interface ResponsiveTableProps<T extends TableData> { | ||
data: Array<T>; | ||
columns: Array<TableColumn>; | ||
getRowId: (row: T, index: number) => string; | ||
getRowLabel?: (row: T) => string; | ||
} | ||
|
||
function ResponsiveTable<T extends TableData>(props: ResponsiveTableProps<T>) { | ||
return ( | ||
<div className="w-full"> | ||
<div className="hidden overflow-x-auto lg:block"> | ||
<DesktopTable {...props} /> | ||
</div> | ||
|
||
<div className="lg:hidden"> | ||
<MobileTable {...props} /> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default ResponsiveTable; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import type { ReactNode } from 'react'; | ||
|
||
import { parseTableStructure } from '#ui/util/table'; | ||
|
||
import ResponsiveTable from '../../Common/ResponsiveTable'; | ||
|
||
const Table = ({ children }: { children: ReactNode }) => { | ||
const { data, columns } = parseTableStructure(children); | ||
|
||
return ( | ||
<ResponsiveTable | ||
data={data} | ||
columns={columns} | ||
// We have to use index as row id fallback | ||
getRowId={(row, index) => String(index)} | ||
/> | ||
); | ||
}; | ||
|
||
export default Table; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's my spicy take on this:
import Table
from#ui/common/Table
What is really confusing here is the separate DOM structure for Mobile and Desktop tables and that you are pretty much rendering a much larger and complex DOM structure https://github.com/nodejs/nodejs.org/pull/8079/files#diff-e77faf52f4e475e7e36e8b4f5c935b9a8c2fb506f89b70ec130a6ed602007c0cR13-R25 for every table.
I know this might sound harder, but I do really believe you can achieve all you want with pure CSS.
I don't even think we need a custom component, it's like we're reinventing the wheel here. I do believe you can achieve all you want purely based on CSS. Might be harder? Hell yes, even more that heading separation. Below is an example query I gave to ChatGPT:
Check the example styles below:
How It Works
max-width: 600px
):<thead>
is visually hidden for space-saving, but remains accessible.<tr>
becomes a block, spaced out like its own mini-card.<td>
displays a label from itsdata-title
attribute using::before
, mimicking column headers.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note the above is just an example, but you can absolutely 100% achieve this with pure CSS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually don't think you can achieve the card-based layout with CSS (since, it requires addition text to be displayed) but you definitely can with a custom component matching the syntax of a table.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You posted this twice. But yes, it is possible to do it with pure CSS.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, GitHub Mobile 😭
This would still require a custom component / modifying the markdown to add this field.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really... You can do that directly on Remark.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if not on Remark, yes, you can make a wrapper, like a
WithResponseTable
that just introspects the thead and tbody and adds the title tag to the tr's. But I do prefer theremark
path, as it can be easily done as a plugin for specifciallytable
elements, and visits the Nodes and then just updates the attributes :)Which adds a bit more of processing (CPU) but at least less JSX/interpretation for the client-side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense, I'll give a try