Repository navigation
feat(search): search games on /search and in the navbar quick search - #58
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Genres now write IGDB's [] list, minRatingCount is a shared filter so search takes it too, search takes pageSize 24, and discover can leave out the sort field condition so unrated games are counted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rating filters type=game is accepted while the games library is on. Every filter is sent to IGDB, so each game shown meets them and the count is IGDB's own; the bar adds a platform picker with a filter box and labels the rating as IGDB's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The navbar search, tabs and logo follow game on /search too: GAMES switches /search in place, the quick search reads IGDB through /api/search, and the quick result field tmdbRating becomes rating. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y builder The control character pattern moves to lib/igdb/constants.ts, so the /search parser (which the client filter bar imports) no longer pulls query.ts into the browser bundle (lib/igdb/AGENTS.md, What lives where). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SEARCH_CATALOGS holds each type's minimum year, filter id cap, page cap and quick search count endpoint, replacing scattered type === "game" branches. Components read IGDB's limits through it instead of importing lib/igdb/constants directly (lib/igdb/AGENTS.md, What lives where). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The results, the filter bar and /api/search each repeated the type === "game" && getGamesLibrary() === "on" check; gameSearchEnabled now holds it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- parseSearchParams and quickSearchRequestSchema take { gamesEnabled }
rather than a bare boolean; without it the parse returns
TmdbSearchParams, so the shows and movies branch needs no cast.
- parseGameSearchParams narrows a games parse at runtime, replacing the
as GameSearchParams casts in the results and the filter bar.
- searchMode is an exhaustive switch, and its games overload leaves out
filtered_search, so the "Games never filter locally" throw is gone
(spec 0029, AC-1).
- settleList and readGameLists replace the two near identical list
loaders in the results and the filter bar.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Spec 0029, AC-16 asks the loader test to prove the row's 42px sizes resolves to a real IGDB_COVER_LADDER rung at 1x, 2x and 3x. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Spec 0029, AC-9: a typed query and a games list toggle made together make one navigation whichever pause fires first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d row AC-15 now says the static /games shells hold the real field, since no fallback shows there; AC-16 says 2:3, the frame every card uses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This adds games to search.
/search?type=gamefinds games by title and lets you narrow them by genre, platform, release year and minimum IGDB rating. The navbar quick search now works on every games page too. It all sits behindNEXT_PUBLIC_GAMES_LIBRARY, so production does not change.Why
This builds scope feature G7 from spec 0029 (rationale). Until now the games tabs and pages had no search, a gap spec 0027 had accepted. IGDB applies every filter inside the search query and returns an exact count. So games need no page scan and no partial counts: every result meets every filter, and every count is IGDB's own (AGENTS.md section 10).
Changes
URL and modes (
lib/search/)SearchTypeis nowLibraryType(tv | movie | game).gameis accepted only while the flag ison, and the flag is read only when the rawtypeisgame. That way an invalid flag value can never break shows or movies search.MediaType, so the compiler makes you narrow the type before each call, andgamecan never reach TMDB.platformparameter, repeatable, up to 20 ids. Ontvormovieit is invalid.searchHrefwrites platforms sorted after genres, so one search has one URL./games/popularuses), discover (filters only, most rated first, unrated games after them and still counted) and search (a title plus any filters, in IGDB relevance order).lib/search/game-read.ts(server only) for the three reads.{n} games, and is left out when IGDB sends no count. Pages stop at 50, and apageabove 50 is refused before any IGDB request.IGDB module (
lib/igdb/). Callers from G6 pass none of these options and work as before.cond.allOfwritesgenres = [ids], so several genres mean all of. Platforms keep any of.minRatingCountmoves intoGameFilters, so search accepts it too. Its condition is now written once, insharedConditions.searchGamesacceptspageSize20 or 24.discoverGamesacceptsrequireSortField(defaulttrue).pnpm igdb:livegets two new checks: a two genre filter returns only games with both genres, and unrated games come after rated ones and are counted.Filter bar (
components/search/)type=gamethe bar shows the IGDB genres (MUST HAVE ALL OF), a newPlatformPicker(ON ANY OF, a filter box that gets focus when it opens,No platforms match), years from next year down to 1950, andAny IGDB ratingwith5+to9+. A note,Only games with at least 10 IGDB ratings, shows when a rating is set.Up to 20). Checkbox toggles wait 400 ms after the last click, so several quick clicks make one IGDB read. Hidden inputs keep the selection if you submit before the page hydrates.Couldn't reach IGDBstates, each with a retry or clear path.Navigation and quick search
libraryTypethroughWithLibraryTypedPage(WithTypedPageis removed). It showsSearch gameson/games*, on the library pages withtype=gameand on/search?type=game./searchthe GAMES tab switchestypein place. It keepsq,ratingand anyyearthe new type can take, and drops genre, platform and page. On/search?type=gamethe logo links to/games.GET /api/searchacceptstype=gamewhen the flag is on and returns the first 5 games from the cached IGDB search page 1.IgdbErroranswers 502, andIgdbValidationErroranswers 400, never 500.tmdbRatingis renamedratingfor every type, andtotalResultsis nownumber | null.Shared and showcase
lib/catalog-list-read.ts, shared by the list pages and search.GameListCardtakes an optionalmetaline (the release year)./showcasegets a Game search section: the platform picker with a filter typed,No platforms match,Platforms unavailable, and quick search rows with and without a cover.How to test / verify
You can run these with
pnpm dev:docker,NEXT_PUBLIC_GAMES_LIBRARY=onand the IGDB credentials in.env.local. The full checklist is in verify.md, and every item there is ticked.pnpm typecheck && pnpm lint && pnpm test,pnpm igdb:live,pnpm build./search,/gamesand the five/games/*list pages should be partially prerendered (◐)./search?type=game&q=zelda. You should see 24 cards,{n} gamesand numbered pages, and page 2 shares no game with page 1./search?type=game&q=mario&genre=8&platform=130&platform=508&rating=7. Every card should be a Platform game on Switch or Switch 2 rated 7 or more./search?type=game. You should seePopular games on IGDBand the same first 24 games as/games/popular.?type=game&platform=0,?type=game&year=1949,?type=movie&platform=6and?type=game&q=%01. Each should showThat filter isn't validnaming the parameter.?type=game&page=51should showThat page doesn't exist.switch, thenzzz. Tick 20 platforms, and the rest should disable./search?type=movie&q=dune&year=1940&genre=878, press GAMES. You should land on/search?type=game&q=dune.hollowin the navbar on/games/top-rated. You should get game rows andSee allto/search?type=game&q=hollow.curl -i 'http://localhost:3000/api/search?type=game&q=zelda'should give 200 withpublic, s-maxage=300andratingfields.q=%01%01should give 400./search?type=gameshould show the invalidtypepanel,/api/search?type=gameshould answer 400, and there should be no GAMES tab.Risk & rollout
No migrations and nothing stored. The games paths are behind
NEXT_PUBLIC_GAMES_LIBRARY, which production leaves unset. Shows and movies search are touched in two places. First,SearchTypeis wider, and the TMDB reads are kept narrowed by type. Second, the quick search response has changed:tmdbRatingis nowratingandtotalResultscan be null. The only consumer is the app's own quick search, updated here. Rollback is a plain revert.Known tradeoffs the spec accepts:
Open follow up: each new filter combination is an uncached IGDB read against the shared 4 per second limiter, and the Vercel Firewall rule covers only
/api/search. The spec leaves that decision for before G10.Notes for reviewers
gameaway from TMDB (lib/search/params.ts,components/search/search-results.tsx), and the flag being read only for a rawtype=game.WithTypedPageis removed. The navbar search now sharesWithLibraryTypedPagewith the tabs. On/games/{id}and the typed paths,Search showsshows once before the type resolves (the brief flash spec 0027 already accepted).🤖 Generated with Claude Code