Link loading overlay escapes the glass card (portal to body)
The full-screen loading screen shown the instant a Link starts navigating was rendered inside the Smart Review card. That card has backdrop-filter, which makes it a containing block for position: fixed — so the overlay was confined to a 44px strip of the card and the loading block spilled below the fold instead of covering the viewport. It is now portalled to <body> with a soft page scrim behind it; the review suite measures that it covers the viewport (390x844). SW -> freezmo-v48.
This commit is contained in:
parent
2d4d4ee776
commit
9b9e978ef2
4 changed files with 28 additions and 6 deletions
|
|
@ -1369,7 +1369,9 @@ Things I chose while building, with the reasoning:
|
||||||
homework wording (no tips — the tips are deck-specific), and the route screens pass a single
|
homework wording (no tips — the tips are deck-specific), and the route screens pass a single
|
||||||
message with no stages or progress. Cancel stays a 44px touch target and the icon animation
|
message with no stages or progress. Cancel stays a 44px touch target and the icon animation
|
||||||
respects `prefers-reduced-motion`. Verified by the freeze-loading, review, wizard and mobile
|
respects `prefers-reduced-motion`. Verified by the freeze-loading, review, wizard and mobile
|
||||||
suites.
|
suites. The link overlay is portalled to `<body>`: inside a glass card `backdrop-filter` makes
|
||||||
|
the card a containing block for `position: fixed`, so the overlay was squeezed into a 44px
|
||||||
|
strip of the card instead of covering the viewport (the review suite now measures it).
|
||||||
|
|
||||||
59. **Adding a deck or a homework syncs itself.** Sync used to be push-on-demand only: a deck
|
59. **Adding a deck or a homework syncs itself.** Sync used to be push-on-demand only: a deck
|
||||||
frozen on the laptop sat in `dirty` until someone opened Settings and pressed Sync now. The two
|
frozen on the laptop sat in `dirty` until someone opened Settings and pressed Sync now. The two
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useLinkStatus } from "next/link";
|
import { useLinkStatus } from "next/link";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
|
|
||||||
import { RouteLoading } from "@/components/RouteLoading";
|
import { RouteLoading } from "@/components/RouteLoading";
|
||||||
|
|
||||||
|
|
@ -9,15 +10,21 @@ import { RouteLoading } from "@/components/RouteLoading";
|
||||||
* `<Link>` starts navigating — before any response arrives — so a slow route
|
* `<Link>` starts navigating — before any response arrives — so a slow route
|
||||||
* never looks like a dead tap. Renders nothing while idle and disappears with
|
* never looks like a dead tap. Renders nothing while idle and disappears with
|
||||||
* the page that owns it.
|
* the page that owns it.
|
||||||
|
*
|
||||||
|
* Portalled to <body>: the link sits inside a glass card, and `backdrop-filter`
|
||||||
|
* makes such an ancestor a containing block for `position: fixed` — rendered
|
||||||
|
* in place, the overlay was confined to a 44px strip of the card instead of the
|
||||||
|
* viewport.
|
||||||
*/
|
*/
|
||||||
export function LinkLoadingScreen({ messageKey }: { messageKey: string }) {
|
export function LinkLoadingScreen({ messageKey }: { messageKey: string }) {
|
||||||
const { pending } = useLinkStatus();
|
const { pending } = useLinkStatus();
|
||||||
|
|
||||||
if (!pending) return null;
|
if (!pending || typeof document === "undefined") return null;
|
||||||
|
|
||||||
return (
|
return createPortal(
|
||||||
<div className="pointer-events-none fixed inset-0 z-50">
|
<div className="pointer-events-none fixed inset-0 z-50 bg-[color-mix(in_oklab,var(--page)_88%,transparent)]">
|
||||||
<RouteLoading messageKey={messageKey} />
|
<RouteLoading messageKey={messageKey} />
|
||||||
</div>
|
</div>,
|
||||||
|
document.body,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
* Bumping CACHE_VERSION is how a new deploy invalidates old assets.
|
* Bumping CACHE_VERSION is how a new deploy invalidates old assets.
|
||||||
*/
|
*/
|
||||||
const CACHE_VERSION = "freezmo-v47";
|
const CACHE_VERSION = "freezmo-v48";
|
||||||
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
||||||
const ASSET_CACHE = `${CACHE_VERSION}-assets`;
|
const ASSET_CACHE = `${CACHE_VERSION}-assets`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,19 @@ async function makeReviewPage(locale = "en") {
|
||||||
check("loading screen appears immediately on tap", loadingAt !== null && loadingAt - tClick < 1000, `${loadingAt ? loadingAt - tClick : "never"} ms`);
|
check("loading screen appears immediately on tap", loadingAt !== null && loadingAt - tClick < 1000, `${loadingAt ? loadingAt - tClick : "never"} ms`);
|
||||||
check("still on the library while stalled", page.url().replace(BASE, "") === "/", page.url());
|
check("still on the library while stalled", page.url().replace(BASE, "") === "/", page.url());
|
||||||
check("spinner is visible", (await page.getByRole("status").count()) >= 1);
|
check("spinner is visible", (await page.getByRole("status").count()) >= 1);
|
||||||
|
/* The overlay is portalled to <body>: rendered inside the glass card it was
|
||||||
|
confined to a 44px strip of that card (backdrop-filter is a containing
|
||||||
|
block for fixed descendants). */
|
||||||
|
const overlay = await page.evaluate(() => {
|
||||||
|
const status = document.querySelector('[role="status"][aria-busy="true"]');
|
||||||
|
const rect = status?.parentElement?.getBoundingClientRect();
|
||||||
|
return rect ? { w: Math.round(rect.width), h: Math.round(rect.height) } : null;
|
||||||
|
});
|
||||||
|
check(
|
||||||
|
"loading overlay covers the viewport",
|
||||||
|
overlay !== null && overlay.w >= 380 && overlay.h >= 800,
|
||||||
|
JSON.stringify(overlay),
|
||||||
|
);
|
||||||
|
|
||||||
release();
|
release();
|
||||||
let sessionAt = null;
|
let sessionAt = null;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue