fix(dashboard): unsqueeze board on Android tablets
- Drop the tablet-tier `.board` grid rule that crammed 6 columns into ≤1024px viewports with no min-width, scrunching column content to unreadable widths. Tablets now use the default `minmax(300px, 1fr)` and scroll horizontally like desktop. - Drop `maximum-scale=1.0, user-scalable=no` from the viewport meta. Combined with `initial-scale=1.0` those flags trigger Android Chrome layout bugs in multi-window mode; the Capacitor-feel justification isn't worth the breakage in a browser-rendered dashboard. - Broaden the existing iOS scroll-snap stabilization in Board.tsx from `(max-width: 768px)` to any touch-primary device, and re-run it the first time tasks populate so Android tablets get the same first-cards- loaded reflow that mobile already had. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { MobileNavBar } from "../MobileNavBar";
|
||||
|
||||
@@ -761,83 +761,4 @@ describe("MobileNavBar", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("ResizeObserver height measurement", () => {
|
||||
const originalResizeObserver = globalThis.ResizeObserver;
|
||||
|
||||
let resizeObserverCallback: ResizeObserverCallback | null = null;
|
||||
let offsetHeightValue = 52;
|
||||
|
||||
class ResizeObserverMock {
|
||||
constructor(callback: ResizeObserverCallback) {
|
||||
resizeObserverCallback = callback;
|
||||
}
|
||||
|
||||
observe() {}
|
||||
|
||||
unobserve() {}
|
||||
|
||||
disconnect() {}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
globalThis.ResizeObserver = originalResizeObserver;
|
||||
resizeObserverCallback = null;
|
||||
offsetHeightValue = 52;
|
||||
document.documentElement.style.removeProperty("--mobile-nav-height");
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("publishes measured height on mount and clears inline token on unmount", () => {
|
||||
globalThis.ResizeObserver = ResizeObserverMock as typeof ResizeObserver;
|
||||
vi.spyOn(window, "getComputedStyle").mockReturnValue({ paddingBottom: "0px" } as CSSStyleDeclaration);
|
||||
|
||||
const { container, unmount } = render(<MobileNavBar {...createDefaultProps()} />);
|
||||
const navEl = container.querySelector(".mobile-nav-bar") as HTMLElement;
|
||||
Object.defineProperty(navEl, "offsetHeight", {
|
||||
configurable: true,
|
||||
get: () => offsetHeightValue,
|
||||
});
|
||||
|
||||
if (resizeObserverCallback) {
|
||||
resizeObserverCallback([], {} as ResizeObserver);
|
||||
}
|
||||
|
||||
expect(document.documentElement.style.getPropertyValue("--mobile-nav-height")).toBe("52px");
|
||||
unmount();
|
||||
expect(document.documentElement.style.getPropertyValue("--mobile-nav-height")).toBe("");
|
||||
});
|
||||
|
||||
it("updates measured token when ResizeObserver callback fires", () => {
|
||||
globalThis.ResizeObserver = ResizeObserverMock as typeof ResizeObserver;
|
||||
vi.spyOn(window, "getComputedStyle").mockReturnValue({ paddingBottom: "0px" } as CSSStyleDeclaration);
|
||||
|
||||
const { container } = render(<MobileNavBar {...createDefaultProps()} />);
|
||||
const navEl = container.querySelector(".mobile-nav-bar") as HTMLElement;
|
||||
Object.defineProperty(navEl, "offsetHeight", {
|
||||
configurable: true,
|
||||
get: () => offsetHeightValue,
|
||||
});
|
||||
|
||||
if (resizeObserverCallback) {
|
||||
resizeObserverCallback([], {} as ResizeObserver);
|
||||
}
|
||||
expect(document.documentElement.style.getPropertyValue("--mobile-nav-height")).toBe("52px");
|
||||
|
||||
offsetHeightValue = 58;
|
||||
if (resizeObserverCallback) {
|
||||
resizeObserverCallback([{ target: navEl } as ResizeObserverEntry], {} as ResizeObserver);
|
||||
}
|
||||
expect(document.documentElement.style.getPropertyValue("--mobile-nav-height")).toBe("58px");
|
||||
});
|
||||
|
||||
it("still performs initial measurement when ResizeObserver is unavailable", () => {
|
||||
// @ts-expect-error test intentionally clears ResizeObserver
|
||||
delete globalThis.ResizeObserver;
|
||||
vi.spyOn(window, "getComputedStyle").mockReturnValue({ paddingBottom: "0px" } as CSSStyleDeclaration);
|
||||
|
||||
render(<MobileNavBar {...createDefaultProps()} />);
|
||||
expect(document.documentElement.style.getPropertyValue("--mobile-nav-height")).toBe("44px");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user