The panel had an inset for this; the calendar never did. Its root filled the leaf, and Obsidian's phone navbar floats over a leaf rather than shortening it, so the scroll container ran to the bottom of the screen and the last row of the list sat under the bar - unreachable. `lib/inset.ts` is the same pure measurement the panel plugin grew, with the same tests: the deeper of navbar and keyboard, never their sum, and a bar that sits beside the view covers nothing of it. The view re-measures by frame until it holds still and writes `--bcal-inset-bottom`. `viewport()` subtracts the bar too, so anchored panels and the quick look are placed against what is actually reachable instead of ending under it.
69 lines
2.1 KiB
TypeScript
69 lines
2.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { BOTTOM_BARS, insetFor } from "../src/lib/inset";
|
|
import type { Rect } from "../src/lib/inset";
|
|
|
|
const rect = (over: Partial<Rect> = {}): Rect => ({
|
|
top: 0,
|
|
left: 0,
|
|
right: 390,
|
|
bottom: 780,
|
|
height: 780,
|
|
...over,
|
|
});
|
|
|
|
// A phone: 780 tall, a 56px navbar floating over the bottom, 340px of keyboard.
|
|
const NAVBAR = rect({ top: 724, bottom: 780, height: 56 });
|
|
|
|
describe("insetFor", () => {
|
|
it("clears nothing when the view stands alone", () => {
|
|
expect(insetFor(rect(), [], null)).toBe(0);
|
|
});
|
|
|
|
it("clears the navbar that paints over the view", () => {
|
|
expect(insetFor(rect(), [NAVBAR], null)).toBe(56);
|
|
});
|
|
|
|
it("clears the keyboard, which shortens no layout", () => {
|
|
expect(insetFor(rect(), [], { height: 440, offsetTop: 0 })).toBe(340);
|
|
});
|
|
|
|
it("takes the deeper of the two rather than their sum", () => {
|
|
// The navbar hides behind the keyboard while it is up.
|
|
expect(insetFor(rect(), [NAVBAR], { height: 440, offsetTop: 0 })).toBe(340);
|
|
});
|
|
|
|
it("comes back to the navbar once the keyboard goes", () => {
|
|
expect(insetFor(rect(), [NAVBAR], { height: 780, offsetTop: 0 })).toBe(56);
|
|
});
|
|
|
|
it("ignores a bar that sits beside the view, not over it", () => {
|
|
const sidedock = rect({ right: 300 });
|
|
const statusBar = rect({
|
|
top: 760,
|
|
bottom: 780,
|
|
height: 20,
|
|
left: 700,
|
|
right: 980,
|
|
});
|
|
expect(insetFor(sidedock, [statusBar], null)).toBe(0);
|
|
});
|
|
|
|
it("measures from where the visible area starts", () => {
|
|
expect(insetFor(rect(), [], { height: 440, offsetTop: 100 })).toBe(240);
|
|
});
|
|
|
|
it("says nothing about a view with no height yet", () => {
|
|
expect(insetFor(rect({ height: 0, bottom: 0 }), [NAVBAR], null)).toBe(0);
|
|
});
|
|
|
|
it("never returns a negative inset", () => {
|
|
const short = rect({ bottom: 300, height: 300 });
|
|
expect(insetFor(short, [], { height: 780, offsetTop: 0 })).toBe(0);
|
|
});
|
|
|
|
it("names the bars that float rather than make room", () => {
|
|
expect(BOTTOM_BARS).toContain(".mobile-navbar");
|
|
expect(BOTTOM_BARS).toContain(".status-bar");
|
|
});
|
|
});
|