Sifa professional network frontend (Next.js, React, TailwindCSS) sifa.id/
at main 54 lines 1.9 kB view raw
1interface DataTableProps { 2 columns: { key: string; label: string }[]; 3 rows: Record<string, string | number | boolean | null>[]; 4 caption?: string; 5} 6 7export function DataTable({ columns, rows, caption }: DataTableProps) { 8 if (!rows.length) return null; 9 10 return ( 11 <details className="mt-4"> 12 <summary className="inline-flex cursor-pointer items-center rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"> 13 Show data as table 14 </summary> 15 <div className="mt-2 overflow-x-auto"> 16 <table className="w-full border-collapse text-sm"> 17 {caption && <caption className="sr-only">{caption}</caption>} 18 <thead> 19 <tr> 20 {columns.map((col) => ( 21 <th 22 key={col.key} 23 className="border-b border-border px-3 py-2 text-left font-medium text-foreground" 24 > 25 {col.label} 26 </th> 27 ))} 28 </tr> 29 </thead> 30 <tbody> 31 {rows.map((row, i) => ( 32 <tr key={i} className={i % 2 === 1 ? 'bg-secondary/50' : undefined}> 33 {columns.map((col) => ( 34 <td 35 key={col.key} 36 className="border-b border-border px-3 py-2 text-muted-foreground" 37 > 38 {formatCell(row[col.key])} 39 </td> 40 ))} 41 </tr> 42 ))} 43 </tbody> 44 </table> 45 </div> 46 </details> 47 ); 48} 49 50function formatCell(value: string | number | boolean | null | undefined): string { 51 if (value === null || value === undefined) return '--'; 52 if (typeof value === 'boolean') return value ? 'Yes' : 'No'; 53 return String(value); 54}