69 lines
3.0 KiB
TypeScript
69 lines
3.0 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { useApp } from '@/lib/context';
|
|
import { resolveName } from '@/lib/localization';
|
|
import { formatSI } from '@/lib/formatNumber';
|
|
import { getColorMap, getItemColor } from '@/lib/colors';
|
|
import type { ColorMap } from '@/lib/colors';
|
|
import { CardShell } from './CardShell';
|
|
import type { ChartConfig, SignalRow } from '@/lib/types';
|
|
|
|
interface Props {
|
|
config: ChartConfig;
|
|
rows: SignalRow[];
|
|
onEdit: () => void;
|
|
onDelete: () => void;
|
|
}
|
|
|
|
export default function TableViz({ config, rows, onEdit, onDelete }: Props) {
|
|
const { localeMap } = useApp();
|
|
const [colorMap, setColorMap] = useState<ColorMap>(new Map());
|
|
useEffect(() => { getColorMap().then(setColorMap); }, []);
|
|
|
|
const latest = new Map<string, { green?: number; red?: number }>();
|
|
for (const row of rows) {
|
|
latest.set(`${row.combinator}::${row.item_key}`, { green: row.green, red: row.red });
|
|
}
|
|
const tableRows = [...latest.entries()].slice(0, config.series_limit);
|
|
|
|
return (
|
|
<CardShell title={config.title} onEdit={onEdit} onDelete={onDelete} empty={rows.length === 0}>
|
|
<div className="flex-1 overflow-y-auto">
|
|
<table className="w-full text-xs text-gray-300">
|
|
<thead className="sticky top-0 bg-gray-800">
|
|
<tr>
|
|
<th className="text-left px-2 py-1">Item</th>
|
|
<th className="text-left px-2 py-1">Combinator</th>
|
|
{config.signal_type !== 'red' && <th className="text-right px-2 py-1 text-green-400">Green</th>}
|
|
{config.signal_type !== 'green' && <th className="text-right px-2 py-1 text-red-400">Red (NP)</th>}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{tableRows.map(([key, vals]) => {
|
|
const [combinator, item_key] = key.split('::');
|
|
return (
|
|
<tr key={key} className="border-t border-gray-800 hover:bg-gray-800/50">
|
|
<td className="px-2 py-0.5 flex items-center gap-1.5">
|
|
<span className="inline-block w-2 h-2 rounded-full shrink-0"
|
|
style={{ backgroundColor: getItemColor(item_key, colorMap) }} />
|
|
{resolveName(item_key, localeMap)}
|
|
</td>
|
|
<td className="px-2 py-0.5 text-gray-500">{combinator}</td>
|
|
{config.signal_type !== 'red' && (
|
|
<td className={`px-2 py-0.5 text-right font-mono ${(vals.green ?? 0) < 0 ? 'text-red-400' : 'text-green-400'}`}>
|
|
{vals.green != null ? formatSI(vals.green, undefined, 0) : '--'}
|
|
</td>
|
|
)}
|
|
{config.signal_type !== 'green' && (
|
|
<td className="px-2 py-0.5 text-right font-mono text-orange-400">
|
|
{vals.red != null ? formatSI(vals.red, undefined, 0) : '--'}
|
|
</td>
|
|
)}
|
|
</tr>
|
|
);
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</CardShell>
|
|
);
|
|
} |