bugfix: measure bar heights with ResizeObserver instead of magic numbers (0.21.2)
This commit is contained in:
@@ -14,11 +14,32 @@
|
||||
|
||||
let { children } = $props();
|
||||
let loggingOut = $state(false);
|
||||
let headerEl: HTMLElement | undefined = $state();
|
||||
|
||||
onMount(() => {
|
||||
theme.init();
|
||||
preferences.init();
|
||||
if (!session.loaded) session.refresh();
|
||||
|
||||
// Publish the header's measured height as a CSS custom
|
||||
// property so sticky descendants (e.g. the reader nav) can
|
||||
// pin themselves directly below it without guessing. A
|
||||
// ResizeObserver keeps it in sync as the viewport reflows
|
||||
// (the nav `flex-wrap: wrap`s on narrow widths), the user
|
||||
// zooms, or fonts swap. Hard-coded pixel offsets in tokens
|
||||
// are wrong in principle — actual height varies with all
|
||||
// of the above.
|
||||
if (!headerEl) return;
|
||||
const publish = () => {
|
||||
document.documentElement.style.setProperty(
|
||||
'--app-header-h',
|
||||
`${headerEl!.offsetHeight}px`
|
||||
);
|
||||
};
|
||||
publish();
|
||||
const ro = new ResizeObserver(publish);
|
||||
ro.observe(headerEl);
|
||||
return () => ro.disconnect();
|
||||
});
|
||||
|
||||
// Pull fresh server preferences whenever the user changes (login,
|
||||
@@ -46,7 +67,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<header bind:this={headerEl}>
|
||||
<nav aria-label="primary">
|
||||
<a class="brand" href="/">Mangalord</a>
|
||||
<a class="nav-link" href="/upload">
|
||||
|
||||
@@ -68,6 +68,33 @@
|
||||
})();
|
||||
let index = $state(initialIndex);
|
||||
let continuousPageEls: HTMLImageElement[] = $state([]);
|
||||
let chapterBarEl: HTMLElement | undefined = $state();
|
||||
|
||||
// Publish the bottom chapter-bar's actual measured height so the
|
||||
// continuous container's `padding-bottom` exactly matches it. Same
|
||||
// rationale as the layout header's measurement: the bar's height
|
||||
// changes with font size, padding, browser zoom, and content
|
||||
// wrap on narrow viewports — a single hard-coded number is wrong.
|
||||
// Only present in continuous mode, so the effect only runs there
|
||||
// and cleans up when the bar unmounts on mode toggle.
|
||||
$effect(() => {
|
||||
if (mode !== 'continuous' || !chapterBarEl) return;
|
||||
const publish = () => {
|
||||
document.documentElement.style.setProperty(
|
||||
'--reader-bar-h',
|
||||
`${chapterBarEl!.offsetHeight}px`
|
||||
);
|
||||
};
|
||||
publish();
|
||||
const ro = new ResizeObserver(publish);
|
||||
ro.observe(chapterBarEl);
|
||||
return () => {
|
||||
ro.disconnect();
|
||||
// Clear so other pages (single mode, /upload, etc.) don't
|
||||
// inherit a stale reservation.
|
||||
document.documentElement.style.removeProperty('--reader-bar-h');
|
||||
};
|
||||
});
|
||||
|
||||
// ---- Navigation ----
|
||||
//
|
||||
@@ -538,7 +565,11 @@
|
||||
|
||||
<!-- Sticky bottom bar — always visible at the foot of the viewport
|
||||
in continuous mode. Slides off when full-screen is toggled. -->
|
||||
<div class="chapter-bar" data-testid="chevrons-inline-bottom">
|
||||
<div
|
||||
class="chapter-bar"
|
||||
bind:this={chapterBarEl}
|
||||
data-testid="chevrons-inline-bottom"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-btn"
|
||||
|
||||
Reference in New Issue
Block a user