feat(stammbaum): land a fresh visit at readable z=3, keep fit-to-screen at z=1 (#692)

A fresh visit (no URL state) now opens at INITIAL_VIEW (z=3) so node tiles and
generation labels are legible on arrival; the fit-to-screen control still zooms
out to the whole tree (DEFAULT_VIEW, z=1). Shared links with ?z still win.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-29 18:00:17 +02:00
parent 578bebbd8b
commit bb2a89da58
3 changed files with 24 additions and 13 deletions

View File

@@ -1,7 +1,7 @@
import { error, redirect } from '@sveltejs/kit';
import { createApiClient, extractErrorCode } from '$lib/shared/api.server';
import { getErrorMessage } from '$lib/shared/errors';
import { parsePanZoomParams } from '$lib/person/genealogy/panZoom';
import { parsePanZoomParams, INITIAL_VIEW } from '$lib/person/genealogy/panZoom';
export async function load({ fetch, url }) {
const api = createApiClient(fetch);
@@ -13,14 +13,17 @@ export async function load({ fetch, url }) {
throw error(result.response.status, getErrorMessage(extractErrorCode(result.error)));
}
// Sanitise the shareable pan/zoom params server-side so a crafted link
// (?z=Infinity, ?cx=NaN) degrades to a safe view before reaching layout
// geometry (Nora #692).
const initialView = parsePanZoomParams({
cx: url.searchParams.get('cx'),
cy: url.searchParams.get('cy'),
z: url.searchParams.get('z')
});
// A fresh visit (no shared pan/zoom state) lands at the readable INITIAL_VIEW
// (z=3). When a link carries a zoom param we honour it, sanitising server-side
// so a crafted link (?z=Infinity, ?cx=NaN) degrades to a safe view before
// reaching layout geometry (Nora #692).
const initialView = url.searchParams.has('z')
? parsePanZoomParams({
cx: url.searchParams.get('cx'),
cy: url.searchParams.get('cy'),
z: url.searchParams.get('z')
})
: INITIAL_VIEW;
const network = result.data!;
return { nodes: network.nodes ?? [], edges: network.edges ?? [], initialView };