Files
ignacionelson 6e47d76ba6 ProjectSend 2.0.0
Client file sharing, rebuilt from the ground up: a private area per
client, resumable uploads, folders, groups and categories, sharing with
expiry dates and download limits, comments, file versions, an activity
log, a REST API, and sixteen languages.

This repository begins here. ProjectSend 2 was developed privately, and
that development history is not published — the previous generation
remains available, with its own history, at projectsend/legacy.

Free software under the GNU General Public License v2, or (at your
option) any later version.
2026-08-14 01:38:12 -03:00

66 lines
2.4 KiB
TypeScript

import { type ReactNode } from 'react';
/**
* A header cell. A plain string is a visible label; `null` is the unlabelled
* column that holds row actions; the object form is for a label that should
* be read out but not shown.
*/
export type TableColumn = string | null | { label: string; srOnly: true };
interface TableShellProps {
columns: TableColumn[];
/** Shown in place of the rows when there are none. */
emptyMessage: ReactNode;
isEmpty: boolean;
children: ReactNode;
}
/**
* The bordered, horizontally-scrollable table every list page is built from:
* the frame, the header row, and the centred "nothing here" message.
*
* Rows stay with the page that owns them -- the columns genuinely differ from
* one list to the next, and that is the part worth reading in context.
*/
export function TableShell({ columns, emptyMessage, isEmpty, children }: TableShellProps) {
return (
<div className="overflow-x-auto rounded-lg border">
<table className="w-full text-sm">
<thead>
<tr className="bg-muted/50 border-b text-left">
{columns.map((column, index) => {
if (column === null) {
return <th key={index} className="px-4 py-2.5" />;
}
if (typeof column === 'object') {
return (
<th key={index} className="px-4 py-2.5">
<span className="sr-only">{column.label}</span>
</th>
);
}
return (
<th key={index} className="px-4 py-2.5 font-medium">
{column}
</th>
);
})}
</tr>
</thead>
<tbody>
{isEmpty && (
<tr>
<td colSpan={columns.length} className="text-muted-foreground px-4 py-8 text-center">
{emptyMessage}
</td>
</tr>
)}
{children}
</tbody>
</table>
</div>
);
}