Confirmations pin to the viewport; open ballots mark their rows

Twice the feedback was the bug: the success banner lives at the top of
the page and the user acts at the bottom of a 136-row list — so a
working "pick edition" read as broken (it worked both times; the data
proves it). showToast() pins transient confirmations to the viewport
bottom (role=status, carries buttons, auto-dismisses), and pick-
edition/edit-saved use it. Better: state stops being transient at all —
any row whose edition ballot is open shows a persistent "ballot in
Review" link where its button was, so the answer to "where did it go?"
lives on the row forever.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
Eric Wagoner
2026-08-05 21:25:49 -04:00
co-authored by Claude Fable 5
parent edb72514f4
commit c94e8bc695
4 changed files with 46 additions and 11 deletions
+2 -2
View File
@@ -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,, 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,, 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,, 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,, 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,, 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,, 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,, 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,, 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,, 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,, 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,, 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,, 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,,
1 title_raw bgg_id bgg_name year type match_status version_id version_name version_status candidates_json version_candidates_json source_photos merged_into dedupe_veto
17 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
18 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
19 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
20 Wiz-War 589 Wiz-War 1983 boardgame auto version_unknown 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
21 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
22 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
23 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 Elite Sportz Equipment Table Top Curling local [] [] IMG_4526.jpeg
84 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
85 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
86 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}] [{"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
87 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
88 Ouija local [] [] IMG_4529.jpeg
89 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
+15
View File
@@ -473,6 +473,21 @@ button.danger { color: var(--stop-ink); border-color: var(--stop); background: #
border: var(--line); border-radius: var(--radius); background: #fff; 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 -------------------------------------------------------- */ /* -- responsive -------------------------------------------------------- */
/* The rail collapses to a top bar: brand + hamburger; the nav drops /* The rail collapses to a top bar: brand + hamburger; the nav drops
+18
View File
@@ -13,6 +13,24 @@ function showBanner(html) {
document.getElementById("banner").innerHTML = 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) { function errorBanner(detail) {
// an HTTP status means the server answered — the problem is its data // an HTTP status means the server answered — the problem is its data
const httpish = /^\d{3}$/.test(String(detail)); const httpish = /^\d{3}$/.test(String(detail));
+11 -9
View File
@@ -89,6 +89,10 @@ function render() {
title="one line, several boxes? make each photo its own copy"> title="one line, several boxes? make each photo its own copy">
split into copies</button>` split into copies</button>`
: ""} : ""}
${c.version_status === "version_ambiguous"
? `<a class="linkbtn ballot" href="/review#editions"
title="this copy's edition ballot is open">ballot in Review</a>`
: ""}
${c.bgg_id && ["auto", "approved"].includes(c.status) ${c.bgg_id && ["auto", "approved"].includes(c.status)
&& ["version_unknown", "version_error", ""].includes(c.version_status || "") && ["version_unknown", "version_error", ""].includes(c.version_status || "")
? `<button class="pickedition" data-title="${esc(c.title_raw)}" ? `<button class="pickedition" data-title="${esc(c.title_raw)}"
@@ -139,9 +143,8 @@ document.getElementById("catbody").addEventListener("click", async e => {
row_ix: pe.dataset.rowix === "" ? null : Number(pe.dataset.rowix), row_ix: pe.dataset.rowix === "" ? null : Number(pe.dataset.rowix),
}); });
if (res) { if (res) {
showBanner(`<div class="banner">edition ballot ready for showToast(`edition ballot ready for <b>${esc(pe.dataset.title)}</b> —
<b>${esc(pe.dataset.title)}</b> — <a href="/review#editions">pick it in Review</a>`);
<a href="/review#editions">pick it in Review</a></div>`);
GATE.reset(); refresh().catch(() => {}); GATE.reset(); refresh().catch(() => {});
} }
return; return;
@@ -214,14 +217,13 @@ document.getElementById("catbody").addEventListener("submit", async e => {
EDITING = null; GATE.reset(); refresh().catch(() => {}); EDITING = null; GATE.reset(); refresh().catch(() => {});
// an edit re-queues any matched row: without a resolve run the line // an edit re-queues any matched row: without a resolve run the line
// sits "awaiting resolve" — say so, and offer the run right here // sits "awaiting resolve" — say so, and offer the run right here
showBanner(`<div class="banner">saved — a previously matched title const toast = showToast(`saved — a previously matched title re-matches
re-matches on the next resolve run. on the next resolve run. <button id="resolvenow">run resolve now</button>`);
<button id="resolvenow">run resolve now</button></div>`); const btn = toast.querySelector("#resolvenow");
const btn = document.getElementById("resolvenow");
if (btn) btn.addEventListener("click", async () => { if (btn) btn.addEventListener("click", async () => {
const r = await apiPost("/api/run/resolve"); const r = await apiPost("/api/run/resolve");
if (r) showBanner(`<div class="banner">resolve running — progress on if (r) showToast(`resolve running — progress on the
the <a href="/">Pipeline</a> page; this list updates itself</div>`); <a href="/">Pipeline</a> page; this list updates itself`);
}); });
} }
}); });