Every matched name links out to its BGG (or RPGGeek) page
The one outbound link in the whole app was the detail-page crumb, and it sent RPG items to a /boardgame/ URL — the wrong home for things that live on RPGGeek. A shared bggUrl(id, type) helper now routes by type, and the link grew into the places where opening the real page is the point: every matched name on the Titles catalog (verifying a match IS opening its page), each Review ballot candidate (a "view ↗" that stops propagation so checking a candidate doesn't vote for it), and the version ballot's title links to BGG's own /versions list. Verified against live data: RPGs route to rpggeek.com, board games to boardgamegeek.com, 127 outbound links on the Titles page. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
co-authored by
Claude Fable 5
parent
e9168044f3
commit
2542560d57
@@ -125,9 +125,22 @@ setInterval(() => refreshBadges().catch(() => {}), 5000);
|
||||
|
||||
/* One-line match summary for a titles/photo table row. Empty when the
|
||||
* row has no BGG data yet, so the mobile stacker can hide the cell. */
|
||||
/* Canonical outbound URL for a matched thing. RPG items live on RPGGeek
|
||||
* (same database, different site) — a /boardgame/ URL is the wrong home
|
||||
* for them. */
|
||||
function bggUrl(id, type) {
|
||||
return type === "rpgitem"
|
||||
? `https://rpggeek.com/rpgitem/${encodeURIComponent(id)}`
|
||||
: `https://boardgamegeek.com/boardgame/${encodeURIComponent(id)}`;
|
||||
}
|
||||
|
||||
function metaLine(c) {
|
||||
const name = !c.bgg_name ? "" : c.bgg_id
|
||||
? `<a href="${bggUrl(c.bgg_id, c.type)}" target="_blank" rel="noopener"
|
||||
title="open on ${c.type === "rpgitem" ? "RPGGeek" : "BGG"}">${esc(c.bgg_name)} ↗</a>`
|
||||
: esc(c.bgg_name);
|
||||
return [
|
||||
c.bgg_name ? esc(c.bgg_name) + (c.bgg_id ? " · " + esc(c.bgg_id) : "") : "",
|
||||
name,
|
||||
c.version_name ? esc(c.version_name) : "",
|
||||
c.type === "rpgitem" ? `<span class="chip open">RPG · local only</span>` : "",
|
||||
].filter(Boolean).join(" · ");
|
||||
|
||||
@@ -108,8 +108,8 @@ function render(g) {
|
||||
local ? `<span class="chip open">not on BGG · local</span>` : "",
|
||||
rpg ? `<span class="chip open">RPG · local only</span>` : "",
|
||||
g.bgg_id
|
||||
? `<a href="https://boardgamegeek.com/boardgame/${encodeURIComponent(g.bgg_id)}"
|
||||
target="_blank" rel="noopener">view on BGG ↗</a>`
|
||||
? `<a href="${bggUrl(g.bgg_id, g.type)}" target="_blank" rel="noopener">
|
||||
view on ${rpg ? "RPGGeek" : "BGG"} ↗</a>`
|
||||
: "",
|
||||
].filter(Boolean).join(" · ");
|
||||
|
||||
|
||||
@@ -61,7 +61,9 @@ function matchCard(row, idx) {
|
||||
<kbd>${i + 1}</kbd> ${thumbHtml(c)}
|
||||
<span><span class="cname">${esc(c.name)}</span>
|
||||
<span class="cmeta">${esc(c.year ?? "—")} · ${esc(c.type || "?")}
|
||||
· rank ${esc(c.rank ?? "—")} · owned ${esc(c.owned ?? "—")}</span></span>
|
||||
· rank ${esc(c.rank ?? "—")} · owned ${esc(c.owned ?? "—")}
|
||||
· <a href="${bggUrl(c.bgg_id, c.type)}" target="_blank" rel="noopener"
|
||||
title="check this candidate before picking">view ↗</a></span></span>
|
||||
</li>`).join("");
|
||||
return `
|
||||
<section class="card actionable" data-kind="match" data-rowix="${row.row_ix}"
|
||||
@@ -104,7 +106,10 @@ function versionCard(row, idx) {
|
||||
data-title="${esc(row.title_raw)}" data-photos="${esc(row.source_photos)}">
|
||||
${shots(row.photos || [])}
|
||||
<div class="body">
|
||||
<p class="title">${esc(row.bgg_name || row.title_raw)}</p>
|
||||
<p class="title">${esc(row.bgg_name || row.title_raw)}
|
||||
${row.bgg_id ? `<a class="cmeta" href="${bggUrl(row.bgg_id, row.type)}/versions"
|
||||
target="_blank" rel="noopener"
|
||||
title="BGG's own list of every printing">versions on BGG ↗</a>` : ""}</p>
|
||||
<p class="status">which edition${row.photos && row.photos.length
|
||||
? ` is the copy in ${esc(row.photos.join(", "))}`
|
||||
: ""}? (skippable — <kbd>u</kbd> records "unknown", or just move on)</p>
|
||||
@@ -192,6 +197,9 @@ function render() {
|
||||
if (ACTIVE >= cards.length) ACTIVE = Math.max(0, cards.length - 1);
|
||||
highlight();
|
||||
|
||||
// an outbound "view ↗" inside a pick row must not also cast the vote
|
||||
m.querySelectorAll("[data-pick] a, [data-pickver] a").forEach(a =>
|
||||
a.onclick = e => e.stopPropagation());
|
||||
m.querySelectorAll("[data-pick]").forEach(li => li.onclick = () => {
|
||||
const card = li.closest(".card");
|
||||
decide(card, "pick", Number(li.dataset.pick));
|
||||
|
||||
Reference in New Issue
Block a user