58 lines · 2.1 KB
import { useMemo } from "react";
import { parseDelimited } from "~/lib/csv";

const MAX_ROWS = 1000;
const MAX_COLUMNS = 100;

export function CsvTable({ contents, delimiter }: { contents: string; delimiter: string }) {
  const table = useMemo(() => {
    const parsed = parseDelimited(contents, delimiter, MAX_ROWS + 1);
    const rows = parsed.rows.map((cells, row) => ({
      row,
      cells: cells.slice(0, MAX_COLUMNS).map((value, column) => ({ column, value })),
    }));
    return { rows, truncated: parsed.truncated };
  }, [contents, delimiter]);
  const [header, ...body] = table.rows;
  return (
    <div className="overflow-x-auto">
      <table className="w-full border-collapse text-left font-mono text-xs">
        <thead className="bg-kumo-base/70 text-kumo-default">
          <tr>
            <th className="w-10 border-b border-kumo-hairline px-3 py-1.5 text-right text-kumo-inactive" />
            {header?.cells.map((cell) => (
              <th
                key={cell.column}
                className="border-b border-l border-kumo-hairline px-3 py-1.5 font-semibold whitespace-nowrap"
              >
                {cell.value}
              </th>
            ))}
          </tr>
        </thead>
        <tbody className="text-kumo-default">
          {body.slice(0, MAX_ROWS).map((row) => (
            <tr key={row.row} className="hover:bg-kumo-tint">
              <td className="border-b border-kumo-hairline px-3 py-1 text-right text-kumo-inactive select-none">
                {row.row}
              </td>
              {row.cells.map((cell) => (
                <td