product category page: front-end sorting and filtering using turboframes

This commit is contained in:
elvira
2026-08-31 22:56:40 +03:00
parent b070a7d1e6
commit 8a07c772f8
20 changed files with 428 additions and 148 deletions
+64
View File
@@ -0,0 +1,64 @@
// Make a refresh land back where you were — accurately.
//
// Turbo Drive is off site-wide (see app.js), so a refresh is a full browser
// load. The browser restores the scroll position early in that load — before
// the Manrope web fonts swap in and reflow the header, <h1> and result count
// above the product grid — so it settles a bit too low. We record the position
// ourselves and re-apply it once the layout has actually stopped moving.
//
// Separately: drop focus on the way out. Otherwise the browser re-focuses
// whatever filter control was active and scrolls it into view on reload, and
// that sidebar stacks below the grid on narrow screens — hence the jump to the
// bottom.
//
// The real fix for the drift is preloading the above-the-fold font weights so
// there's no reflow to chase; this keeps the restore correct until then, and
// harmless after.
const key = 'scrollY:' + location.pathname + location.search
let frame = 0
window.addEventListener(
'scroll',
() => {
if (frame) return
frame = requestAnimationFrame(() => {
frame = 0
try {
sessionStorage.setItem(key, String(Math.round(window.scrollY)))
} catch {}
})
},
{ passive: true },
)
window.addEventListener('pagehide', () => {
const el = document.activeElement
if (el && el !== document.body) el.blur()
})
// Only reloads and back/forward should resume a position; a fresh visit to the
// page starts where it naturally would.
const [nav] = performance.getEntriesByType('navigation')
if (nav && (nav.type === 'reload' || nav.type === 'back_forward')) {
let saved = null
try {
saved = sessionStorage.getItem(key)
} catch {}
if (saved !== null) {
const y = Number(saved)
const apply = () => window.scrollTo(0, y)
window.addEventListener(
'load',
() => {
apply()
// Fonts (and any late above-the-fold image) can still nudge
// layout a frame or two after load — re-apply once they settle.
document.fonts?.ready.then(() => requestAnimationFrame(apply))
},
{ once: true },
)
}
}