diff --git a/data/matches.csv b/data/matches.csv index eb2a01a..8c5c3fe 100644 --- a/data/matches.csv +++ b/data/matches.csv @@ -17,7 +17,7 @@ Cards Against Humanity,50381,Cards Against Humanity,2009,boardgame,auto,,,versio Joking Hazard,193621,Joking Hazard,2016,boardgame,auto,,,version_unknown,"[{""bgg_id"": 193621, ""name"": ""Joking Hazard"", ""year"": 2016, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4501.jpeg;IMG_4502.jpeg,, SKIP-BO,1269,Skip-Bo,1967,boardgame,auto,,,version_unknown,"[{""bgg_id"": 1269, ""name"": ""Skip-Bo"", ""year"": 1967, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4501.jpeg;IMG_4542.jpeg,, EXPLODING KITTENS,172225,Exploding Kittens,2015,boardgame,auto,,,version_unknown,"[{""bgg_id"": 172225, ""name"": ""Exploding Kittens"", ""year"": 2015, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4501.jpeg;IMG_4505.jpeg,, -Wiz-War,589,Wiz-War,1983,boardgame,auto,,,version_unknown,"[{""bgg_id"": 589, ""name"": ""Wiz-War"", ""year"": 1983, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4502.jpeg,, +Wiz-War,589,Wiz-War,1983,boardgame,auto,,,version_ambiguous,"[{""bgg_id"": 589, ""name"": ""Wiz-War"", ""year"": 1983, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 188937, ""name"": ""First edition"", ""year"": 1985, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 360421, ""name"": ""Second edition"", ""year"": 1985, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 360420, ""name"": ""Third edition"", ""year"": 1986, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 29214, ""name"": ""Fourth edition"", ""year"": 1987, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 26114, ""name"": ""Fifth edition"", ""year"": 1991, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 27352, ""name"": ""Chessex sixth edition"", ""year"": 1993, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 28612, ""name"": ""Chessex classic edition 1997"", ""year"": 1997, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}]",IMG_4502.jpeg,, SCRAWL,202982,Scrawl,2016,boardgame,auto,,,version_unknown,"[{""bgg_id"": 202982, ""name"": ""Scrawl"", ""year"": 2016, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4502.jpeg,, FLAT TOP,2529,Flat Top,1977,boardgame,auto,,,version_unknown,"[{""bgg_id"": 2529, ""name"": ""Flat Top"", ""year"": 1977, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4502.jpeg,, Diplomacy,483,Diplomacy,1959,boardgame,auto,,,version_unknown,"[{""bgg_id"": 483, ""name"": ""Diplomacy"", ""year"": 1959, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]",[],IMG_4502.jpeg,, @@ -83,7 +83,7 @@ Poetry for Neanderthals,312786,Poetry for Neanderthals,2020,boardgame,auto,,,ver Elite Sportz Equipment Table Top Curling,,,,,local,,,,[],[],IMG_4526.jpeg,, Simon's Cat Card Game,188614,Simon's Cat Card Game,2016,boardgame,auto,,,version_ambiguous,"[{""bgg_id"": 188614, ""name"": ""Simon's Cat Card Game"", ""year"": 2016, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": 1429, ""rank"": 12119}, {""bgg_id"": 330317, ""name"": ""NOM: Simon's Cat Card Game"", ""year"": 2021, ""type"": ""boardgame"", ""exact"": false, ""fuzzy"": 91.3, ""owned"": 70, ""rank"": null}]","[{""version_id"": 292307, ""name"": ""English edition, first printing"", ""year"": 2016, ""publishers"": [""Steve Jackson Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 779792, ""name"": ""English edition, second printing"", ""year"": 2016, ""publishers"": [""Steve Jackson Games""], ""languages"": [""English""], ""score"": 3}]",IMG_4526.jpeg,, The Red Dragon Inn: Smorgasbox,273240,The Red Dragon Inn Smorgasbox,2019,boardgame,auto,,,version_ambiguous,"[{""bgg_id"": 273240, ""name"": ""The Red Dragon Inn Smorgasbox"", ""year"": 2019, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 446786, ""name"": ""Collector's edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 446788, ""name"": ""Eco-Collector's edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 446787, ""name"": ""Eco-Kickstarter edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 446069, ""name"": ""Kickstarter edition"", ""year"": 2019, ""publishers"": [""SlugFest Games""], ""languages"": [""English""], ""score"": 3}]",IMG_4527.jpeg,, -WIZ-WAR,589,Wiz-War,1983,boardgame,auto,,,version_ambiguous,"[{""bgg_id"": 589, ""name"": ""Wiz-War"", ""year"": 1983, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 26114, ""name"": ""Fifth edition"", ""year"": 1991, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 29214, ""name"": ""Fourth edition"", ""year"": 1987, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 360420, ""name"": ""Third edition"", ""year"": 1986, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 3}]",IMG_4528.jpeg,, +WIZ-WAR,589,Wiz-War,1983,boardgame,auto,,,version_ambiguous,"[{""bgg_id"": 589, ""name"": ""Wiz-War"", ""year"": 1983, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 360420, ""name"": ""Third edition"", ""year"": 1986, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 29214, ""name"": ""Fourth edition"", ""year"": 1987, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 26114, ""name"": ""Fifth edition"", ""year"": 1991, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 188937, ""name"": ""First edition"", ""year"": 1985, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 360421, ""name"": ""Second edition"", ""year"": 1985, ""publishers"": [""Jolly Games""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 27352, ""name"": ""Chessex sixth edition"", ""year"": 1993, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}, {""version_id"": 28612, ""name"": ""Chessex classic edition 1997"", ""year"": 1997, ""publishers"": [""Chessex""], ""languages"": [""English""], ""score"": 1}]",IMG_4528.jpeg,, RISK THE LORD OF THE RINGS: The Middle-earth Conquest Game,4324,Risk: The Lord of the Rings,2002,boardgame,auto,26859,English edition 2002,version_approved,"[{""bgg_id"": 4324, ""name"": ""Risk: The Lord of the Rings"", ""year"": 2002, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 57.1, ""owned"": null, ""rank"": null}]","[{""version_id"": 33264, ""name"": ""English (UK) edition 2002"", ""year"": 2002, ""publishers"": [""Hasbro"", ""Parker Brothers""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 26859, ""name"": ""English edition 2002"", ""year"": 2002, ""publishers"": [""Hasbro"", ""Parker Brothers""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 26863, ""name"": ""English/French edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""English"", ""French""], ""score"": 3}, {""version_id"": 26865, ""name"": ""Danish edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""Danish""], ""score"": 2}, {""version_id"": 26861, ""name"": ""Dutch edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""Dutch""], ""score"": 2}, {""version_id"": 77144, ""name"": ""French edition 2002"", ""year"": 2002, ""publishers"": [""Hasbro"", ""Parker Brothers""], ""languages"": [""French""], ""score"": 2}, {""version_id"": 26862, ""name"": ""German edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""German""], ""score"": 2}, {""version_id"": 75135, ""name"": ""Norwegian edition"", ""year"": 2002, ""publishers"": [""Parker Brothers""], ""languages"": [""Norwegian""], ""score"": 2}]",IMG_4529.jpeg,, Ouija,,,,,local,,,,[],[],IMG_4529.jpeg,, Munchkin Big Box,419687,Munchkin Big Box,2025,boardgame,auto,711400,English edition,version_auto,"[{""bgg_id"": 419687, ""name"": ""Munchkin Big Box"", ""year"": 2025, ""type"": ""boardgame"", ""exact"": true, ""fuzzy"": 100.0, ""owned"": null, ""rank"": null}]","[{""version_id"": 711400, ""name"": ""English edition"", ""year"": 2025, ""publishers"": [""Steve Jackson Games""], ""languages"": [""English""], ""score"": 3}, {""version_id"": 777457, ""name"": ""Russian edition"", ""year"": 2025, ""publishers"": [""Hobby World"", ""Steve Jackson Games""], ""languages"": [""Russian""], ""score"": 2}]",IMG_4530.jpeg,, diff --git a/src/bggpipe/static/app.css b/src/bggpipe/static/app.css index 063fa60..26dd71a 100644 --- a/src/bggpipe/static/app.css +++ b/src/bggpipe/static/app.css @@ -473,6 +473,21 @@ button.danger { color: var(--stop-ink); border-color: var(--stop); background: # border: var(--line); border-radius: var(--radius); background: #fff; } +/* -- toast: viewport-pinned transient confirmations --------------------- */ +#toast { + position: fixed; bottom: 1.1rem; left: 50%; transform: translateX(-50%); + z-index: 20; max-width: min(92vw, 34rem); + background: var(--navy); color: #fff; + border: var(--line); border-radius: var(--radius-lg); + box-shadow: var(--shadow-raised); + padding: .7rem 1rem; font-size: .9rem; line-height: 1.45; +} +#toast a { color: var(--gold); } +#toast button { + font-size: .8rem; padding: .25rem .7rem; margin-left: .5rem; + box-shadow: none; +} + /* -- responsive -------------------------------------------------------- */ /* The rail collapses to a top bar: brand + hamburger; the nav drops diff --git a/src/bggpipe/static/app.js b/src/bggpipe/static/app.js index faeac20..3e3f57d 100644 --- a/src/bggpipe/static/app.js +++ b/src/bggpipe/static/app.js @@ -13,6 +13,24 @@ function showBanner(html) { document.getElementById("banner").innerHTML = html; } +/* Transient confirmation pinned to the viewport: the #banner region sits + * at the top of the page, which a user deep in a long list never sees. + * The toast may carry buttons — wire them before the timer clears it. */ +function showToast(html, ms = 8000) { + let el = document.getElementById("toast"); + if (!el) { + el = document.createElement("div"); + el.id = "toast"; + el.setAttribute("role", "status"); + document.body.appendChild(el); + } + el.innerHTML = html; + el.hidden = false; + clearTimeout(showToast._timer); + showToast._timer = setTimeout(() => { el.hidden = true; }, ms); + return el; +} + function errorBanner(detail) { // an HTTP status means the server answered — the problem is its data const httpish = /^\d{3}$/.test(String(detail)); diff --git a/src/bggpipe/templates/pages/titles.html b/src/bggpipe/templates/pages/titles.html index 44a4dbb..f717546 100644 --- a/src/bggpipe/templates/pages/titles.html +++ b/src/bggpipe/templates/pages/titles.html @@ -89,6 +89,10 @@ function render() { title="one line, several boxes? make each photo its own copy"> split into copies` : ""} + ${c.version_status === "version_ambiguous" + ? `ballot in Review` + : ""} ${c.bgg_id && ["auto", "approved"].includes(c.status) && ["version_unknown", "version_error", ""].includes(c.version_status || "") ? ``); - const btn = document.getElementById("resolvenow"); + const toast = showToast(`saved — a previously matched title re-matches + on the next resolve run. `); + const btn = toast.querySelector("#resolvenow"); if (btn) btn.addEventListener("click", async () => { const r = await apiPost("/api/run/resolve"); - if (r) showBanner(``); + if (r) showToast(`resolve running — progress on the + Pipeline page; this list updates itself`); }); } });