Keep scroll position across same-screen re-renders (day nav, add food) instead of jumping to top
This commit is contained in:
parent
bb9f03131d
commit
5d24f8c3a3
1 changed files with 33 additions and 0 deletions
|
|
@ -220,6 +220,32 @@ async function init() {
|
|||
// Router
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Keep the vertical scroll position across a re-render of the SAME screen (day nav, adding
|
||||
// food, deletes) instead of jumping to the top. Anchor on the topmost visible top-level
|
||||
// section + its offset (robust to height changes, e.g. one more food row or async charts).
|
||||
function captureScrollAnchor(el) {
|
||||
let top = el.scrollTop, kids = el.children, idx = 0, delta = top;
|
||||
for (let i = 0; i < kids.length; i++) {
|
||||
if (kids[i].offsetTop <= top + 4) { idx = i; delta = top - kids[i].offsetTop; } else break;
|
||||
}
|
||||
return { idx, delta };
|
||||
}
|
||||
function applyScrollAnchor(el, a) {
|
||||
let kid = el.children[a.idx];
|
||||
if (kid) el.scrollTop = Math.max(0, kid.offsetTop + a.delta);
|
||||
}
|
||||
// The screen fills asynchronously (charts, nutrient strips), so re-apply for a short window as
|
||||
// content settles; stop early if the user scrolls themselves.
|
||||
function scheduleScrollRestore(el, a) {
|
||||
let stop = false, off = () => { stop = true; };
|
||||
el.addEventListener("wheel", off, { passive: true, once: true });
|
||||
el.addEventListener("touchmove", off, { passive: true, once: true });
|
||||
let apply = () => { if (!stop) applyScrollAnchor(el, a); };
|
||||
apply();
|
||||
requestAnimationFrame(apply);
|
||||
[60, 180, 400].forEach(ms => setTimeout(apply, ms));
|
||||
}
|
||||
|
||||
function renderScreen(name, fromPopstate) {
|
||||
// Release screen wake lock and compass listener when leaving recording screen
|
||||
if (window._screenLock) { try { window._screenLock.release(); } catch {} window._screenLock = null; }
|
||||
|
|
@ -243,6 +269,12 @@ function renderScreen(name, fromPopstate) {
|
|||
supplements: renderSupplements,
|
||||
settings: renderSettings,
|
||||
};
|
||||
// Re-render of the same screen: remember where we were scrolled so we can stay put.
|
||||
let scrollAnchor = null;
|
||||
if (prevScreen === name) {
|
||||
let oldContent = app.querySelector(".screen-content");
|
||||
if (oldContent && oldContent.scrollTop > 0) scrollAnchor = captureScrollAnchor(oldContent);
|
||||
}
|
||||
app.innerHTML = "";
|
||||
|
||||
// Floating recording bar (visible on all screens except recording)
|
||||
|
|
@ -271,6 +303,7 @@ function renderScreen(name, fromPopstate) {
|
|||
content.className = "screen-content";
|
||||
app.appendChild(content);
|
||||
screens[name](content);
|
||||
if (scrollAnchor) scheduleScrollRestore(content, scrollAnchor);
|
||||
}
|
||||
|
||||
function buildNav(active) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue