import { useMemo, useState } from "react"; import { X, Table as TableIcon, FileText } from "lucide-react"; import type { EmbedDataFile } from "../editor/embeds/embed-data-store"; import { formatBytes } from "../utils/data-files"; interface DataFileViewerProps { file: EmbedDataFile; onClose: () => void; } const MAX_PREVIEW_ROWS = 100; function splitCsvLine(line: string, delim: string): string[] { const out: string[] = []; let cur = ""; let inQuotes = false; for (let i = 0; i < line.length; i++) { const c = line[i]; if (inQuotes) { if (c === '"') { if (line[i + 1] === '"') { cur += '"'; i++; } else { inQuotes = false; } } else { cur += c; } } else if (c === '"') { inQuotes = true; } else if (c === delim) { out.push(cur); cur = ""; } else { cur += c; } } out.push(cur); return out; } function parseTable(content: string, delim: string, maxRows: number): { columns: string[]; rows: string[][]; total: number; } { const lines = content.split(/\r\n|\n|\r/).filter((l) => l.length > 0); if (lines.length === 0) return { columns: [], rows: [], total: 0 }; const columns = splitCsvLine(lines[0], delim); const rows = lines .slice(1, 1 + maxRows) .map((l) => splitCsvLine(l, delim)); return { columns, rows, total: Math.max(0, lines.length - 1) }; } function prettyJson(content: string): string { try { return JSON.stringify(JSON.parse(content), null, 2); } catch { return content; } } export function DataFileViewer({ file, onClose }: DataFileViewerProps) { const { ext } = file.meta; const isTabular = ext === "csv" || ext === "tsv"; const [mode, setMode] = useState<"table" | "raw">(isTabular ? "table" : "raw"); const parsed = useMemo(() => { if (!isTabular) return null; return parseTable(file.content, ext === "tsv" ? "\t" : ",", MAX_PREVIEW_ROWS); }, [file.content, ext, isTabular]); const raw = useMemo(() => { if (ext === "json") return prettyJson(file.content); return file.content; }, [file.content, ext]); return (
| {col} | ))}
|---|
| {row[ci] ?? ""} | ))}
{raw}
)}