Make library search and category filters deep-linkable#50
Conversation
|
This one's a feature rather than a bug fix, so completely understand if it's not a direction you want — feel free to close it, no hard feelings. The idea: the homepage filter state (search, category, page) lives only in memory, so a filtered view can't be shared or bookmarked, a reload drops it, and back/forward don't restore it. This reflects it in the URL ( If you're open to it but want it scoped differently (e.g. query-only, no page param), I'm glad to trim. Check suite + builders pass with no artifact drift. |
mberman84
left a comment
There was a problem hiding this comment.
The URL state is bookmarkable, but three blocking issues remain:
syncUrlState()starts with a freshURLSearchParams, so loading?utm_source=newsletter&q=agentimmediately deletesutm_sourceand any other URL state the library does not own. Initialize fromwindow.location.search, then set/delete onlyq,category, andpage.- Every interaction uses
replaceState. Browser verification confirmed that after changing category or page, Back leaves the library instead of restoring the prior filter state, so the newpopstatehandler cannot deliver the behavior claimed by the PR. UsepushStatefor meaningful category/pagination navigation boundaries; reservereplaceStatefor initial canonicalization or transient search typing. - This changes
site/script.jswithout bumping the shared versioned script URL. Update the emitted/validated asset version and regenerate affected pages.
|
All three addressed:
|
|
@mberman84 ready for re-review whenever you have time — foreign params preserved, |
mberman84
left a comment
There was a problem hiding this comment.
Correction to my immediately preceding review, whose inline code formatting was stripped by the shell:
The three earlier blockers are fixed. Exact-head browser verification confirmed that foreign query params survive, category navigation pushes a history entry, and Back restores the prior query/filter state. The exact head also passes node scripts/check.mjs, syntax checks, and all builders.
This branch now needs a rebase onto current main before it can be approved. Since this PR branched, #61/#62 moved loop detail pages to the database-backed proxy and removed scripts/build-loop-pages.mjs plus site/loops/**. GitHub reports this head as conflicting, and the stale generated-page edits must not restore files intentionally removed by that migration.
Please rebase onto the latest main, keep the focused URL-state logic, update only the surviving shared script references/check assertions with a fresh version, and leave the removed generator/static loop pages deleted. Then rerun node scripts/check.mjs and the browser history checks.
a2725f0 to
4795758
Compare
mberman84
left a comment
There was a problem hiding this comment.
Rebased onto the database-backed main architecture and integrated with the newly merged clear-filters action. Exact-head browser verification confirms foreign query params survive, clearing pushes a history entry, Back restores the prior query/category, and focus returns to search. The full current CI-equivalent suite also passes locally (41/41 Worker tests).
Summary
The homepage library's filter state (search query, active category, page) lived only in memory. As a result:
This wires that state into the URL query string so a slice of the library is directly linkable — a natural fit for a catalog that's explicitly built for SEO/GEO and agent discovery (
llms.txt,catalog.json, etc.).Behavior
?q=…, category →?category=engineering, page →?page=2. Defaults (empty query,all, page 1) are omitted so the canonical homepage URL stays clean.popstate, state is restored from the URL. The category is validated against the available filter chips (unknown values fall back toall) and the page is parsed/clamped by the existing pagination logic, so hand-edited or stale URLs degrade gracefully.history.replaceState(guarded for environments without it), so typing in the search box doesn't flood the history stack.Implementation notes
applyCategory()(used by both the click handler and URL restore).syncUrlState()is called at the end ofupdateLibrary(), which already runs on every search/category/pagination change, so there's a single write path. It only callsreplaceStatewhen the URL actually changes.searchInput/results guards already short-circuitupdateLibrary).Verification
node scripts/check.mjs→Loop Library checks passed.node --check site/script.jsbuild-skill-catalog,build-loop-pages,build-social-images) → no artifact drift.?category=bogus/?page=99normalize to a valid state.