From 0e15b388565b21a33b1e657170f3e4cf5982db53 Mon Sep 17 00:00:00 2001 From: Radin Hamidi Rad Date: Wed, 20 May 2026 02:35:19 -0400 Subject: [PATCH] =?UTF-8?q?leaderboard:=20polish=20=E2=80=94=20filter-bar?= =?UTF-8?q?=20grouping,=20stacked=20column=20headers,=20scrollable=20matri?= =?UTF-8?q?x,=20robust=20sort?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Filter bar: each label+chips pair is its own flex group so "Metric:" no longer orphans from its buttons when the bar wraps. - Matrix column headers: dataset name and metric label stack on two lines (dataset on top, metric in small gray below) instead of one long line that wraps to 2-3 lines per cell. Each line is whitespace-nowrap, so headers are tight and stable-width. - Home matrix + per-dataset table: vertical scroll inside a max-h-[70vh] container with a sticky thead, so a 120-row table doesn't blow out the page height. - InteractiveTable sort: read data-sort-value live from the DOM on every sort call instead of using a cache captured at init. Fixes sort after the home page's metric toggle (which rewrites sort values) and after filter chips change. setSort now re-runs the search/visibility pass after reordering, so chip-hidden rows stay hidden across sorts. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/InteractiveTable.astro | 33 +++++---- .../site/src/pages/datasets/[id].astro | 14 ++-- reproducibility/site/src/pages/index.astro | 67 ++++++++++--------- 3 files changed, 64 insertions(+), 50 deletions(-) diff --git a/reproducibility/site/src/components/InteractiveTable.astro b/reproducibility/site/src/components/InteractiveTable.astro index 2e1c683..f124377 100644 --- a/reproducibility/site/src/components/InteractiveTable.astro +++ b/reproducibility/site/src/components/InteractiveTable.astro @@ -77,17 +77,22 @@ const initialSortAttr = initialSort if (totalCounter) totalCounter.textContent = String(allRows.length); - // Pre-cache sortable values + searchable text per row. + // Cache only the searchable text per row. Sort values are read live + // from the DOM on each setSort() so dynamic updates (e.g. the home + // page's metric toggle rewriting data-sort-value when switching + // between nDCG and recall) take effect immediately. const meta = allRows.map((tr) => ({ tr, searchText: tr.textContent?.toLowerCase() ?? "", - cells: Array.from(tr.cells).map((c) => { - const raw = c.dataset.sortValue ?? c.textContent ?? ""; - const num = parseFloat(raw); - return { raw, num: Number.isFinite(num) ? num : null }; - }), })); + function cellSortValue(tr: HTMLTableRowElement, colIdx: number): { raw: string; num: number | null } { + const c = tr.cells[colIdx]; + const raw = c?.dataset?.sortValue ?? c?.textContent ?? ""; + const n = parseFloat(raw); + return { raw, num: Number.isFinite(n) ? n : null }; + } + let currentSort: { column: number; direction: "asc" | "desc" } | null = null; function addArrows() { @@ -114,18 +119,22 @@ const initialSortAttr = initialSort } }); const sorted = [...meta].sort((a, b) => { - const av = a.cells[colIdx]; - const bv = b.cells[colIdx]; - if (av?.num !== null && bv?.num !== null) { - return dir === "asc" ? av.num! - bv.num! : bv.num! - av.num!; + const av = cellSortValue(a.tr, colIdx); + const bv = cellSortValue(b.tr, colIdx); + if (av.num !== null && bv.num !== null) { + return dir === "asc" ? av.num - bv.num : bv.num - av.num; } return dir === "asc" - ? (av?.raw ?? "").localeCompare(bv?.raw ?? "") - : (bv?.raw ?? "").localeCompare(av?.raw ?? ""); + ? av.raw.localeCompare(bv.raw) + : bv.raw.localeCompare(av.raw); }); const frag = document.createDocumentFragment(); sorted.forEach((m) => frag.appendChild(m.tr)); tbody.appendChild(frag); + // After moving rows, re-apply search so chip-hidden / search-filtered + // rows stay hidden (display state lives on the inline style of each tr + // but appendChild doesn't preserve it implicitly across all browsers). + applySearch(); } function applySearch() { diff --git a/reproducibility/site/src/pages/datasets/[id].astro b/reproducibility/site/src/pages/datasets/[id].astro index bbb6aa4..fdf0065 100644 --- a/reproducibility/site/src/pages/datasets/[id].astro +++ b/reproducibility/site/src/pages/datasets/[id].astro @@ -50,15 +50,15 @@ const metricCols: string[] = view?.metric_columns ?? datasetMeta?.eval_metrics ? ) : (
-
+
- - - - - + + + + + {metricCols.map((m) => ( - + ))} diff --git a/reproducibility/site/src/pages/index.astro b/reproducibility/site/src/pages/index.astro index 6b82e7c..66c3153 100644 --- a/reproducibility/site/src/pages/index.astro +++ b/reproducibility/site/src/pages/index.astro @@ -61,25 +61,31 @@ const datasetCols = matrix.dataset_columns; { populated && (
-
- Retriever: -
- - {retrievers.map((r: any) => ( - - ))} +
+
+ Retriever: +
+ + {retrievers.map((r: any) => ( + + ))} +
- Model: -
- - {models.map((m: any) => ( - - ))} +
+ Model: +
+ + {models.map((m: any) => ( + + ))} +
- Metric: -
- - +
+ Metric: +
+ + +
@@ -89,26 +95,25 @@ const datasetCols = matrix.dataset_columns; { populated ? ( -
+
MethodModelRetriever
MethodModelRetriever{m}{m}Run
- + - - - + + + {datasetCols.map((d: any) => ( ))}
MethodModelRetrieverMethodModelRetriever - - {SHORT[d.id] ?? d.name} - / {METRIC_LABEL[d.primary_metric] ?? d.primary_metric} - - +
{SHORT[d.id] ?? d.name}
+
+ {METRIC_LABEL[d.primary_metric] ?? d.primary_metric} +
+