Join the tab row to the frozen date row
The tab row was painted in the page ground while the day bar above it is a card, and the two sat as separate bars with the day bar's rounded corners cutting between them — so the frozen top of the screen read as two mismatched strips rather than one thing. It takes the same card now: surface colour, radius and shadow. Once the log buttons have scrolled away and the two bars meet, they lose the seam and share one frame — the day bar squares its bottom corners and gives up its shadow, the tab row squares its top, and the pair casts a single shadow below. Scrolled back to the top they are two cards again, which is right: the log buttons genuinely sit between them there. CSS has no way to ask whether a sticky element is currently stuck, so a class is toggled from JS on the simplest available test — whether the two are touching. It rides the rAF-throttled scroll handler that already existed for the timer pill, so it adds no listener, and it is re-checked on a tab switch (a shorter tab can leave the page too short to stay scrolled) and when the day bar changes height. The tab row's sticky offset is now a pixel less than the day bar's height. The safe-area inset is free to be fractional while the measured height is a whole number, and that shortfall would show as a hairline of page ground between the two; the overlap it costs is invisible, since the day bar paints on top in the same colour.
This commit is contained in:
+28
-6
@@ -4766,8 +4766,10 @@
|
||||
}
|
||||
}
|
||||
// The pill's visibility depends on whether the big card is on screen, and
|
||||
// the card only exists on one tab.
|
||||
// the card only exists on one tab. A shorter tab can also leave the page
|
||||
// too short to stay scrolled, unsticking the bars, so re-check that too.
|
||||
updateBarClockMode();
|
||||
updateTabsMerged();
|
||||
}
|
||||
|
||||
for (const [i, btn] of tabButtons.entries()) {
|
||||
@@ -4794,13 +4796,28 @@
|
||||
if (!dayBarEl) return;
|
||||
document.documentElement.style.setProperty("--day-bar-h", `${dayBarEl.offsetHeight}px`);
|
||||
}
|
||||
const onDayBarResize = () => { measureDayBar(); updateTabsMerged(); };
|
||||
if (dayBarEl && typeof ResizeObserver === "function") {
|
||||
new ResizeObserver(measureDayBar).observe(dayBarEl);
|
||||
new ResizeObserver(onDayBarResize).observe(dayBarEl);
|
||||
} else {
|
||||
addEventListener("resize", measureDayBar);
|
||||
addEventListener("resize", onDayBarResize);
|
||||
}
|
||||
measureDayBar();
|
||||
|
||||
// Once the log buttons have scrolled away the two frozen bars meet, and they
|
||||
// should look like one card rather than two stacked ones — see .merged in the
|
||||
// stylesheet. CSS cannot ask whether a sticky element is currently stuck, so
|
||||
// the test is simply whether they are touching.
|
||||
const tabsEl = document.querySelector(".tabs");
|
||||
function updateTabsMerged() {
|
||||
if (!dayBarEl || !tabsEl) return;
|
||||
const gap = tabsEl.getBoundingClientRect().top - dayBarEl.getBoundingClientRect().bottom;
|
||||
const merged = gap <= 1; // they overlap by a pixel by design
|
||||
dayBarEl.classList.toggle("merged", merged);
|
||||
tabsEl.classList.toggle("merged", merged);
|
||||
}
|
||||
updateTabsMerged();
|
||||
|
||||
showTab(loadTab());
|
||||
|
||||
// ---------- wiring ----------
|
||||
@@ -4836,14 +4853,19 @@
|
||||
});
|
||||
});
|
||||
|
||||
// Swap the timer pill in/out of the frozen bar as the big card scrolls
|
||||
// past. rAF-throttled: scroll events fire far more often than we can paint.
|
||||
// Swap the timer pill in/out of the frozen bar as the big card scrolls past,
|
||||
// and join the two frozen bars up once they meet. rAF-throttled: scroll
|
||||
// events fire far more often than we can paint.
|
||||
{
|
||||
let queued = false;
|
||||
const onScroll = () => {
|
||||
if (queued) return;
|
||||
queued = true;
|
||||
requestAnimationFrame(() => { queued = false; updateBarClockMode(); });
|
||||
requestAnimationFrame(() => {
|
||||
queued = false;
|
||||
updateBarClockMode();
|
||||
updateTabsMerged();
|
||||
});
|
||||
};
|
||||
window.addEventListener("scroll", onScroll, { passive: true });
|
||||
window.addEventListener("resize", onScroll, { passive: true });
|
||||
|
||||
Reference in New Issue
Block a user