Files
defiQUG 64e78dad47
Some checks failed
Deploy Explorer Live / deploy (push) Failing after 15s
feat(explorer): token signing surface card, ERC-5267 domain read, tabular top holders
- Add TokenSigningSurfaceCard: ABI flags, eip712Domain eth_call decode, verification metadata
- Pass contract profile into GRU standards detection on token page
- Table layout=tabular for Top Holders column layout at all breakpoints
- Fallback provenance name/symbol; show signing card when token API empty
- eip712Domain.ts: decode ERC-5267 tuple return data

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 21:09:40 -07:00

111 lines
3.6 KiB
TypeScript

import { ReactNode } from 'react'
import clsx from 'clsx'
interface Column<T> {
header: string
accessor: (row: T) => ReactNode
className?: string
}
interface TableProps<T> {
columns: Column<T>[]
data: T[]
className?: string
emptyMessage?: string
/**
* responsive: stacked cards below `md`, table at md+.
* tabular: always use columnar HTML table (holder lists, dense numeric tables).
*/
layout?: 'responsive' | 'tabular'
/** Stable key for each row (e.g. row => row.id or row => row.hash). Falls back to index if not provided. */
keyExtractor?: (row: T) => string | number
}
export function Table<T>({
columns,
data,
className,
emptyMessage = 'No data available right now.',
layout = 'responsive',
keyExtractor,
}: TableProps<T>) {
if (data.length === 0) {
return (
<div
className={clsx(
'rounded-xl border border-dashed border-gray-300 bg-white px-4 py-6 text-sm text-gray-600 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-400',
className,
)}
>
{emptyMessage}
</div>
)
}
const stackedClass = layout === 'tabular' ? 'hidden' : 'grid gap-3 md:hidden'
const tableWrapperClass = layout === 'tabular' ? 'overflow-x-auto' : 'hidden overflow-x-auto md:block'
return (
<div className={clsx('space-y-3', className)}>
<div className={stackedClass}>
{data.map((row, rowIndex) => (
<div
key={keyExtractor ? keyExtractor(row) : rowIndex}
className="rounded-xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-900"
>
<dl className="space-y-3">
{columns.map((column, colIndex) => (
<div key={colIndex} className="space-y-1">
<dt className="text-[11px] font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
{column.header}
</dt>
<dd className={clsx('min-w-0 text-sm text-gray-900 dark:text-gray-100', column.className)}>
{column.accessor(row)}
</dd>
</div>
))}
</dl>
</div>
))}
</div>
<div className={tableWrapperClass}>
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead className="bg-gray-50 dark:bg-gray-800">
<tr>
{columns.map((column, index) => (
<th
key={index}
className={clsx(
'px-4 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500 dark:text-gray-400 lg:px-6',
column.className
)}
>
{column.header}
</th>
))}
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white dark:divide-gray-700 dark:bg-gray-900">
{data.map((row, rowIndex) => (
<tr key={keyExtractor ? keyExtractor(row) : rowIndex} className="hover:bg-gray-50 dark:hover:bg-gray-800">
{columns.map((column, colIndex) => (
<td
key={colIndex}
className={clsx(
'px-4 py-4 align-top text-sm text-gray-900 dark:text-gray-100 lg:px-6',
column.className
)}
>
{column.accessor(row)}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
)
}