Custom Frutiger Aero 404

app/not-found.tsx renders a standalone screen: the root layout's ice
scene is the backdrop, the glass card/rim/bubbles come from the shared
recipes (full Aero with that theme on, frosted glass in light/dark),
and the mascot is the scene's glossy ice orb at full strength with a
snowflake and a "404" chip. Two ways out - back to the library and
into the chat - both 44px targets, en + cs.

The regression suite pins the 404 status, both links and the Czech
copy; the pixel-contrast scan covers the screen in all three themes.
The service worker no longer caches non-OK navigations as the offline
shell (a typo'd URL used to write the error page into the shell
cache). Version 0.5.6, SW -> freezmo-v78.
This commit is contained in:
Martin Dvořák 2026-10-14 15:27:47 +00:00
commit 7e42b03f7e
9 changed files with 137 additions and 4 deletions

View file

@ -9,7 +9,7 @@
*
* Bumping CACHE_VERSION is how a new deploy invalidates old assets.
*/
const CACHE_VERSION = "freezmo-v77";
const CACHE_VERSION = "freezmo-v78";
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
const ASSET_CACHE = `${CACHE_VERSION}-assets`;
@ -104,8 +104,13 @@ self.addEventListener("fetch", (event) => {
(async () => {
try {
const response = await fetch(request);
const cache = await caches.open(SHELL_CACHE);
cache.put("/", response.clone()).catch(() => {});
// Only a real page becomes the offline shell: caching a 404 (a typo
// in the URL, a dead link) would serve the error page to every
// later offline navigation.
if (response.ok) {
const cache = await caches.open(SHELL_CACHE);
cache.put("/", response.clone()).catch(() => {});
}
return response;
} catch {
const cache = await caches.open(SHELL_CACHE);