From 2d48838fe6aa7223f1eab58130a4fa982536db37 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 13 Jun 2026 17:39:44 -0400 Subject: [PATCH] finish peeps tables --- site/drop-tables.js | 152 ++++++++++++++++++++++++++++++++++++++++---- site/drops.html | 2 +- site/style.css | 34 ++++++++++ 3 files changed, 173 insertions(+), 15 deletions(-) diff --git a/site/drop-tables.js b/site/drop-tables.js index 312da66..282398f 100644 --- a/site/drop-tables.js +++ b/site/drop-tables.js @@ -14,6 +14,12 @@ section: "", search: "", }, + sort: { + key: "source", + dir: "asc", + }, + page: 1, + pageSize: 100, }; const RARE_MODIFIER_VERSIONS = new Set(["v2", "bb"]); @@ -184,6 +190,89 @@ fillSelect(qs("#drops-section"), uniqueSorted(rows, "section_id"), "All Section IDs"); } + const SORT_COLUMNS = [ + ["mode", "Mode"], + ["episode", "Episode"], + ["difficulty", "Difficulty"], + ["section_id", "SECID"], + ["source", "Source"], + ["item", "Item"], + ["item_code", "Code"], + ["rate", "Rate"], + ]; + + const DIFFICULTY_SORT_ORDER = { + Normal: 0, + Hard: 1, + VeryHard: 2, + Ultimate: 3, + }; + + function rateSortValue(rate) { + const text = String(rate || "").replaceAll(",", ""); + const match = text.match(/^(\d+(?:\.\d+)?)\/(\d+(?:\.\d+)?)$/); + if (!match) return Number.NEGATIVE_INFINITY; + + const num = Number(match[1]); + const den = Number(match[2]); + + if (!Number.isFinite(num) || !Number.isFinite(den) || den <= 0) { + return Number.NEGATIVE_INFINITY; + } + + // Sort by actual probability, same as percentage conversion. + // 5/8 => 0.625, 1/8192 => 0.000122... + return num / den; + } + + function sortValue(row, key) { + if (key === "difficulty") { + return DIFFICULTY_SORT_ORDER[row.difficulty] ?? 999; + } + + if (key === "rate") { + return rateSortValue(adjustedRate(row.rate)); + } + + if (key === "item") { + return row.item || row.item_code || ""; + } + + return row[key] || ""; + } + + function sortedRows(rows) { + const { key, dir } = state.sort; + const factor = dir === "desc" ? -1 : 1; + + return [...rows].sort((a, b) => { + const av = sortValue(a, key); + const bv = sortValue(b, key); + + if (typeof av === "number" && typeof bv === "number") { + return (av - bv) * factor; + } + + return String(av).localeCompare(String(bv), undefined, { + numeric: true, + sensitivity: "base", + }) * factor; + }); + } + + function sortHeader(key, label) { + const active = state.sort.key === key; + const arrow = active ? (state.sort.dir === "asc" ? "▲" : "▼") : ""; + const ariaSort = active ? (state.sort.dir === "asc" ? "ascending" : "descending") : "none"; + + return ` + + `; + } + function visibleRows() { const search = state.filters.search.trim().toLowerCase(); @@ -216,9 +305,14 @@ const box = qs("#drops-placeholder"); if (!box) return; - const rows = visibleRows(); + const rows = sortedRows(visibleRows()); const tableLabel = state.table?.label || "Peeps"; - const shown = rows.slice(0, 1000); + const totalPages = Math.max(1, Math.ceil(rows.length / state.pageSize)); + state.page = Math.min(Math.max(1, state.page), totalPages); + + const start = (state.page - 1) * state.pageSize; + const shown = rows.slice(start, start + state.pageSize); + const end = start + shown.length; const body = shown.map((row) => { const item = row.item || row.item_code || "—"; @@ -238,8 +332,8 @@ `; }).join(""); - const truncation = rows.length > shown.length - ? ` Showing first ${shown.length.toLocaleString()}.` + const rangeText = rows.length + ? ` Showing ${Number(start + 1).toLocaleString()}-${Number(end).toLocaleString()}.` : ""; const modifier = currentRareModifier(); const modifierNote = rareModifierEnabled() && modifier.pct > 0 @@ -250,7 +344,7 @@
Peeps ${esc(tableLabel)} drop table - ${rows.length.toLocaleString()} matching rows.${truncation} + ${rows.length.toLocaleString()} matching rows.${rangeText} ${modifierNote}
${state.rows.length.toLocaleString()} total rows @@ -259,19 +353,17 @@ - - - - - - - - + ${SORT_COLUMNS.map(([key, label]) => sortHeader(key, label)).join("")} ${body || ``}
ModeEpisodeDifficultySection IDSourceItemItem CodeRate
No drops match these filters.
+
+ + Page ${state.page} of ${totalPages} + +
`; } @@ -299,6 +391,7 @@ state.filters.difficulty = ""; state.filters.section = ""; state.filters.search = ""; + state.page = 1; if (qs("#drops-search")) qs("#drops-search").value = ""; @@ -335,30 +428,61 @@ document.addEventListener("DOMContentLoaded", () => { qs("#drops-mode")?.addEventListener("change", updateMode); qs("#drops-version")?.addEventListener("change", loadPeeps); - qs("#drops-rare-modifier")?.addEventListener("change", renderTable); + qs("#drops-rare-modifier")?.addEventListener("change", () => { + state.page = 1; + state.page = 1; + renderTable(); + }); qs("#drops-rare-mode")?.addEventListener("change", (event) => { state.filters.mode = event.target.value; + state.page = 1; renderTable(); }); qs("#drops-episode")?.addEventListener("change", (event) => { state.filters.episode = event.target.value; + state.page = 1; renderTable(); }); qs("#drops-difficulty")?.addEventListener("change", (event) => { state.filters.difficulty = event.target.value; + state.page = 1; renderTable(); }); qs("#drops-section")?.addEventListener("change", (event) => { state.filters.section = event.target.value; + state.page = 1; renderTable(); }); qs("#drops-search")?.addEventListener("input", (event) => { state.filters.search = event.target.value; + state.page = 1; + renderTable(); + }); + + qs("#drops-placeholder")?.addEventListener("click", (event) => { + const pageButton = event.target.closest("[data-drops-page]"); + if (pageButton) { + state.page += pageButton.dataset.dropsPage === "next" ? 1 : -1; + renderTable(); + return; + } + + const button = event.target.closest("[data-drops-sort]"); + if (!button) return; + + const key = button.dataset.dropsSort; + if (state.sort.key === key) { + state.sort.dir = state.sort.dir === "asc" ? "desc" : "asc"; + } else { + state.sort.key = key; + state.sort.dir = "asc"; + } + renderTable(); }); diff --git a/site/drops.html b/site/drops.html index 9bec22d..1a7886f 100644 --- a/site/drops.html +++ b/site/drops.html @@ -126,6 +126,6 @@ - + diff --git a/site/style.css b/site/style.css index d8e7993..a1b9e83 100644 --- a/site/style.css +++ b/site/style.css @@ -2839,3 +2839,37 @@ button.inline-link, white-space: nowrap; } + +.drops-sort-button { + display: inline-flex; + align-items: center; + justify-content: space-between; + gap: 0.4rem; + width: 100%; + padding: 0; + border: 0; + background: transparent; + color: inherit; + font: inherit; + letter-spacing: inherit; + text-align: left; + text-transform: inherit; + cursor: pointer; +} + +.drops-sort-button:hover, +.drops-sort-button.is-active { + color: rgba(255, 255, 255, 0.96); +} + +.drops-sort-arrow { + min-width: 0.75rem; + color: rgba(255, 255, 255, 0.62); + font-size: 0.66rem; +} + + +.drops-pager { + margin: 0.9rem 1rem 1rem; +} +