Files
cobble/src/components/general/file-preview-table.tsx
T
tbenandClaude Opus 5.5 faa554d5e3 Open bot files in a preview modal instead of a new tab
Markdown rendered, CSV/TSV as a table, images, PDFs, audio, video and
sandboxed HTML in place, other text as code, with Download and Open in a
new tab. Used by file chips, message attachments, the files modal, task
files and the files browser.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 19:25:49 +01:00

55 lines
2.1 KiB
TypeScript

import { useMemo } from "react";
import P from "@moduletrace/twui/layout/P";
import Stack from "@moduletrace/twui/layout/Stack";
import { AppData } from "@/src/data/app-data";
import parseCsv from "@/src/utils/parse-csv";
import FilePreviewNotice from "./file-preview-notice";
import FilePreviewTableRow from "./file-preview-table-row";
type Props = {
text: string;
delimiter: string;
};
/**
* A CSV or TSV file as a table: its first row the header (kept in view
* while scrolling), up to `AppData.FilePreviewMaxTableRows` rows. Cells
* are text only. Tables have no children-based twui equivalent, so they're
* styled elements, as in a message.
*/
export default function FilePreviewTable({ text, delimiter }: Props) {
const { rows, truncated } = useMemo(
() => parseCsv({ text, delimiter, max_rows: AppData.FilePreviewMaxTableRows + 1 }),
[text, delimiter],
);
if (!rows.length) return <FilePreviewNotice message="This file is empty." />;
const [header, ...body] = rows;
return (
<Stack className="grow min-h-0 w-full items-stretch gap-0!">
<Stack className="grow min-h-0 w-full overflow-auto items-start">
<table className="text-[13px] leading-5 text-ink border-separate border-spacing-0">
<thead className="sticky top-0 bg-surface">
<FilePreviewTableRow cells={header!} header />
</thead>
<tbody>
{body.map((cells, index) => (
<FilePreviewTableRow key={index} cells={cells} />
))}
</tbody>
</table>
</Stack>
<P
noMargin
className="shrink-0 px-5 py-2 text-[12px] leading-4 text-ink-secondary border-0 border-t border-solid border-hairline"
>
{truncated
? `Showing the first ${body.length} rows. Download the file for the rest.`
: `${body.length} ${body.length == 1 ? "row" : "rows"}`}
</P>
</Stack>
);
}