Codex commited on
Commit
f032aa0
ยท
1 Parent(s): ff5e7c3

Add overview K rank display switch

Browse files
Files changed (3) hide show
  1. app.js +37 -8
  2. index.html +8 -0
  3. style.css +41 -0
app.js CHANGED
@@ -28,6 +28,7 @@ const state = {
28
  collapsedFilters: new Set(),
29
  recordsReady: false,
30
  view: "overview",
 
31
  sort: { key: "overall", asc: true },
32
  metric: { tier: "tier1", key: null, detail: "__all__", frequency: "__all__", sort: { key: "rank", asc: true } },
33
  strength: { tier: "tier1", mode: "k" }
@@ -185,12 +186,22 @@ function tierStats(records = includedRecords()) {
185
  return [...stats.values()].map((row) => ({ ...row, overall: row.pointwise + row.ic + row.portfolio }));
186
  }
187
  function sortedOverview() {
188
- const rows = state.recordsReady ? tierStats() : [...(state.data?.overall || [])];
 
 
 
189
  const s = state.sort;
 
 
 
 
 
 
 
190
  rows.sort((a, b) => {
191
  if (s.key === "model") return s.asc ? a.model.localeCompare(b.model) : b.model.localeCompare(a.model);
192
- const av = s.key === "pos" ? a.overall : a[s.key];
193
- const bv = s.key === "pos" ? b.overall : b[s.key];
194
  return s.asc ? av - bv : bv - av;
195
  });
196
  return rows;
@@ -457,21 +468,35 @@ function fillHowtoFrequencies() {
457
  }
458
  function renderOverview() {
459
  const rows = sortedOverview();
460
- const best = Math.min(...rows.map((r) => r.overall));
 
461
  const leader = [...(state.recordsReady ? tierStats() : (state.data?.overall || []))]
462
  .sort((a, b) => a.overall - b.overall || a.model.localeCompare(b.model))[0];
463
  const strip = $("winner-strip");
464
  if (strip && leader) {
465
  strip.innerHTML = `<span>Overall #1</span><b>${isExaone(leader.model) ? "โ˜… " : ""}${displayName(leader.model)}</b><strong>Rank sum ${fmt(leader.overall, leader.overall % 1 ? 1 : 0)}</strong>`;
466
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
467
  $("overview-body").innerHTML = rows.map((row, index) => `
468
  <tr class="model-row ${isExaone(row.model) ? "exaone-row" : ""}">
469
  <td class="num">${rankBadge(index + 1)}</td>
470
  <td class="model-name" data-model="${row.model}">${isExaone(row.model) ? "โ˜… " : ""}${displayName(row.model)}</td>
471
- <td class="num tier-rank" data-model="${row.model}" data-tier="tier1">${rankBadge(row.pointwise)}</td>
472
- <td class="num tier-rank" data-model="${row.model}" data-tier="tier2">${rankBadge(row.ic)}</td>
473
- <td class="num tier-rank" data-model="${row.model}" data-tier="tier3">${rankBadge(row.portfolio)}</td>
474
- <td class="num ${row.overall === best ? "val-best" : ""}"><b>${fmt(row.overall, row.overall % 1 ? 1 : 0)}</b></td>
475
  <td class="num"><small>${row.count.toLocaleString()}</small></td>
476
  </tr>
477
  `).join("");
@@ -738,6 +763,10 @@ async function boot() {
738
  $("detail-close").onclick = closeDrawer;
739
  $("detail2-close").onclick = closeDrawer2;
740
  $("drawer-scrim").onclick = closeDrawer;
 
 
 
 
741
  setupTabs();
742
  setupCollapsibles();
743
  buildSpecToggles();
 
28
  collapsedFilters: new Set(),
29
  recordsReady: false,
30
  view: "overview",
31
+ overviewMode: "rank",
32
  sort: { key: "overall", asc: true },
33
  metric: { tier: "tier1", key: null, detail: "__all__", frequency: "__all__", sort: { key: "rank", asc: true } },
34
  strength: { tier: "tier1", mode: "k" }
 
186
  return [...stats.values()].map((row) => ({ ...row, overall: row.pointwise + row.ic + row.portfolio }));
187
  }
188
  function sortedOverview() {
189
+ const rows = (state.recordsReady ? tierStats() : [...(state.data?.overall || [])]).map((row) => ({
190
+ ...row,
191
+ overall_k: geometricMean([row.pointwise_k, row.ic_k, row.portfolio_k])
192
+ }));
193
  const s = state.sort;
194
+ const valueForSort = (row, key) => {
195
+ if (key === "pos" || key === "overall") return state.overviewMode === "k" ? row.overall_k : row.overall;
196
+ if (state.overviewMode === "k" && key === "pointwise") return row.pointwise_k;
197
+ if (state.overviewMode === "k" && key === "ic") return row.ic_k;
198
+ if (state.overviewMode === "k" && key === "portfolio") return row.portfolio_k;
199
+ return row[key];
200
+ };
201
  rows.sort((a, b) => {
202
  if (s.key === "model") return s.asc ? a.model.localeCompare(b.model) : b.model.localeCompare(a.model);
203
+ const av = valueForSort(a, s.key);
204
+ const bv = valueForSort(b, s.key);
205
  return s.asc ? av - bv : bv - av;
206
  });
207
  return rows;
 
468
  }
469
  function renderOverview() {
470
  const rows = sortedOverview();
471
+ const isKMode = state.overviewMode === "k";
472
+ const best = Math.min(...rows.map((r) => isKMode ? r.overall_k : r.overall).filter(finite));
473
  const leader = [...(state.recordsReady ? tierStats() : (state.data?.overall || []))]
474
  .sort((a, b) => a.overall - b.overall || a.model.localeCompare(b.model))[0];
475
  const strip = $("winner-strip");
476
  if (strip && leader) {
477
  strip.innerHTML = `<span>Overall #1</span><b>${isExaone(leader.model) ? "โ˜… " : ""}${displayName(leader.model)}</b><strong>Rank sum ${fmt(leader.overall, leader.overall % 1 ? 1 : 0)}</strong>`;
478
  }
479
+ $("overview-mode-toggle").checked = !isKMode;
480
+ document.querySelector('#overview-table th[data-sort="pointwise"]').textContent = isKMode ? "Point K โ†“" : "Point rank";
481
+ document.querySelector('#overview-table th[data-sort="ic"]').textContent = isKMode ? "Ranking K โ†“" : "Ranking rank";
482
+ document.querySelector('#overview-table th[data-sort="portfolio"]').textContent = isKMode ? "Decision K โ†“" : "Decision rank";
483
+ document.querySelector('#overview-table th[data-sort="overall"]').textContent = isKMode ? "Overall K โ†“" : "Rank sum โ†“";
484
+ const tierCell = (row, tier, value) => finite(value)
485
+ ? `<td class="num tier-rank" data-model="${row.model}" data-tier="${tier}">${isKMode ? fmt(value) : rankBadge(value)}</td>`
486
+ : `<td class="num">${fmt(value)}</td>`;
487
+ const overallCell = (row) => {
488
+ const value = isKMode ? row.overall_k : row.overall;
489
+ const text = isKMode ? fmt(value) : fmt(value, value % 1 ? 1 : 0);
490
+ return `<td class="num ${value === best ? "val-best" : ""}"><b>${text}</b></td>`;
491
+ };
492
  $("overview-body").innerHTML = rows.map((row, index) => `
493
  <tr class="model-row ${isExaone(row.model) ? "exaone-row" : ""}">
494
  <td class="num">${rankBadge(index + 1)}</td>
495
  <td class="model-name" data-model="${row.model}">${isExaone(row.model) ? "โ˜… " : ""}${displayName(row.model)}</td>
496
+ ${tierCell(row, "tier1", isKMode ? row.pointwise_k : row.pointwise)}
497
+ ${tierCell(row, "tier2", isKMode ? row.ic_k : row.ic)}
498
+ ${tierCell(row, "tier3", isKMode ? row.portfolio_k : row.portfolio)}
499
+ ${overallCell(row)}
500
  <td class="num"><small>${row.count.toLocaleString()}</small></td>
501
  </tr>
502
  `).join("");
 
763
  $("detail-close").onclick = closeDrawer;
764
  $("detail2-close").onclick = closeDrawer2;
765
  $("drawer-scrim").onclick = closeDrawer;
766
+ $("overview-mode-toggle").onchange = (event) => {
767
+ state.overviewMode = event.target.checked ? "rank" : "k";
768
+ renderOverview();
769
+ };
770
  setupTabs();
771
  setupCollapsibles();
772
  buildSpecToggles();
index.html CHANGED
@@ -74,6 +74,14 @@
74
  <b>Rank sum์ด ๋‚ฎ์„์ˆ˜๋ก ์šฐ์ˆ˜</b>ํ•ฉ๋‹ˆ๋‹ค.
75
  </p>
76
  <div id="winner-strip" class="winner-strip"></div>
 
 
 
 
 
 
 
 
77
  <div class="table-wrap">
78
  <table id="overview-table" class="board">
79
  <thead>
 
74
  <b>Rank sum์ด ๋‚ฎ์„์ˆ˜๋ก ์šฐ์ˆ˜</b>ํ•ฉ๋‹ˆ๋‹ค.
75
  </p>
76
  <div id="winner-strip" class="winner-strip"></div>
77
+ <div class="overview-toolbar">
78
+ <label class="mode-switch" title="Overview table display mode">
79
+ <span>K</span>
80
+ <input id="overview-mode-toggle" type="checkbox" checked />
81
+ <i aria-hidden="true"></i>
82
+ <span>Rank</span>
83
+ </label>
84
+ </div>
85
  <div class="table-wrap">
86
  <table id="overview-table" class="board">
87
  <thead>
style.css CHANGED
@@ -125,6 +125,47 @@ main { flex: 1 1 auto; min-width: 0; padding: 22px 32px 60px; }
125
  }
126
  .hint code, code { background: #fff; padding: 1px 5px; border-radius: 5px; font-size: 12px; }
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  .specbar, .filters, .table-wrap {
129
  background: var(--card);
130
  border: 1px solid var(--line);
 
125
  }
126
  .hint code, code { background: #fff; padding: 1px 5px; border-radius: 5px; font-size: 12px; }
127
 
128
+ .overview-toolbar {
129
+ display: flex;
130
+ justify-content: flex-end;
131
+ margin: -4px 0 10px;
132
+ }
133
+ .mode-switch {
134
+ display: inline-flex;
135
+ align-items: center;
136
+ gap: 8px;
137
+ color: var(--ink-soft);
138
+ font-size: 12px;
139
+ font-weight: 700;
140
+ }
141
+ .mode-switch input { position: absolute; opacity: 0; pointer-events: none; }
142
+ .mode-switch i {
143
+ position: relative;
144
+ width: 48px;
145
+ height: 24px;
146
+ border-radius: 999px;
147
+ background: var(--line);
148
+ border: 1px solid #d4dae5;
149
+ transition: background .15s ease, border-color .15s ease;
150
+ }
151
+ .mode-switch i::after {
152
+ content: "";
153
+ position: absolute;
154
+ top: 3px;
155
+ left: 3px;
156
+ width: 16px;
157
+ height: 16px;
158
+ border-radius: 50%;
159
+ background: #fff;
160
+ box-shadow: 0 1px 3px rgba(20, 30, 60, .22);
161
+ transition: transform .15s ease;
162
+ }
163
+ .mode-switch input:checked + i {
164
+ background: var(--accent);
165
+ border-color: var(--accent);
166
+ }
167
+ .mode-switch input:checked + i::after { transform: translateX(24px); }
168
+
169
  .specbar, .filters, .table-wrap {
170
  background: var(--card);
171
  border: 1px solid var(--line);