{
  "id": "csv-viewer",
  "name": "CSV Viewer",
  "category": "data",
  "tags": ["csv", "table", "data", "spreadsheet"],
  "description": "Simple CSV text viewer with table rendering.",
  "triggers": ["csv viewer", "spreadsheet", "csv", "table viewer"],
  "defaultSize": { "w": 4, "h": 4 },
  "source": "function CsvViewer() {\n  const [csvText, setCsvText] = React.useState('Name,Age,City,Score\\nAlice,30,New York,85\\nBob,25,Los Angeles,90\\nCharlie,35,Chicago,78\\nDiana,28,Miami,92');\n  const [delimiter, setDelimiter] = React.useState(',');\n\n  function parseCSV(text, delim) {\n    const lines = text.trim().split('\\n');\n    return lines.map(line => {\n      const result = [];\n      let current = '';\n      let inQuotes = false;\n      for (let i = 0; i < line.length; i++) {\n        const ch = line[i];\n        if (ch === '\"' && inQuotes && line[i + 1] === '\"') {\n          current += '\"';\n          i++;\n        } else if (ch === '\"') {\n          inQuotes = !inQuotes;\n        } else if (ch === delim && !inQuotes) {\n          result.push(current);\n          current = '';\n        } else {\n          current += ch;\n        }\n      }\n      result.push(current);\n      return result;\n    });\n  }\n\n  const rows = parseCSV(csvText, delimiter);\n  const headers = rows[0] || [];\n  const dataRows = rows.slice(1);\n\n  return (\n    <div style={{ fontFamily: 'system-ui, sans-serif', padding: 16, background: '#fff', borderRadius: 12, height: '100%', boxSizing: 'border-box', display: 'flex', flexDirection: 'column' }}>\n      <h2 style={{ margin: '0 0 12px 0', fontSize: 18, color: '#1a1a1a' }}>CSV Viewer</h2>\n      <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>\n        <input placeholder=\"Delimiter\" value={delimiter} onChange={e => setDelimiter(e.target.value)} maxLength={1} style={{ width: 50, padding: '6px 10px', borderRadius: 6, border: '1px solid #ddd', fontSize: 13, textAlign: 'center' }} />\n        <button onClick={() => setCsvText('')} style={{ padding: '6px 14px', borderRadius: 6, border: '1px solid #ddd', background: '#fff', fontSize: 13, cursor: 'pointer' }}>Clear</button>\n      </div>\n      <textarea\n        value={csvText}\n        onChange={e => setCsvText(e.target.value)}\n        style={{ width: '100%', height: 80, padding: 10, borderRadius: 6, border: '1px solid #ddd', fontSize: 12, fontFamily: 'monospace', resize: 'none', boxSizing: 'border-box', marginBottom: 12 }}\n        placeholder=\"Paste CSV data here...\"\n      />\n      <div style={{ flex: 1, overflow: 'auto', border: '1px solid #e5e7eb', borderRadius: 6 }}>\n        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>\n          <thead>\n            <tr>\n              {headers.map((h, i) => (\n                <th key={i} style={{ padding: '8px 12px', textAlign: 'left', background: '#f3f4f6', borderBottom: '1px solid #e5e7eb', fontWeight: 600, color: '#374151', whiteSpace: 'nowrap' }}>{h}</th>\n              ))}\n            </tr>\n          </thead>\n          <tbody>\n            {dataRows.map((row, ri) => (\n              <tr key={ri} style={{ background: ri % 2 === 0 ? '#fff' : '#f9fafb' }}>\n                {row.map((cell, ci) => (\n                  <td key={ci} style={{ padding: '8px 12px', borderBottom: '1px solid #e5e7eb', color: '#4b5563', whiteSpace: 'nowrap' }}>{cell}</td>\n                ))}\n                {row.length < headers.length && Array.from({ length: headers.length - row.length }).map((_, ci) => (\n                  <td key={'empty-' + ci} style={{ padding: '8px 12px', borderBottom: '1px solid #e5e7eb' }} />\n                ))}\n              </tr>\n            ))}\n          </tbody>\n        </table>\n        {rows.length <= 1 && <div style={{ textAlign: 'center', color: '#999', fontSize: 13, padding: 20 }}>Enter CSV data to view table.</div>}\n      </div>\n    </div>\n  );\n}\nrender(<CsvViewer/>);",
  "placeholders": []
}
