Add an onCentre control to StammbaumSidePanel (title row, both desktop aside and mobile sheet). The page drives a one-shot centreOnId so StammbaumTree recentres the canvas on the focal node (US-PAN-005). Also tighten the panel spec's deathYear fixture to a valid type. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
76 lines
2.2 KiB
Svelte
76 lines
2.2 KiB
Svelte
<script lang="ts">
|
|
import { m } from '$lib/paraglide/messages.js';
|
|
import { trapFocus } from '$lib/shared/actions/trapFocus';
|
|
import StammbaumSidePanel from '$lib/person/genealogy/StammbaumSidePanel.svelte';
|
|
import type { components } from '$lib/generated/api';
|
|
|
|
type PersonNodeDTO = components['schemas']['PersonNodeDTO'];
|
|
|
|
interface Props {
|
|
node: PersonNodeDTO;
|
|
canWrite: boolean;
|
|
onClose: () => void;
|
|
onCentre?: () => void;
|
|
}
|
|
|
|
let { node, canWrite, onClose, onCentre }: Props = $props();
|
|
|
|
// Swipe the sheet down past this threshold to dismiss it (Leonie).
|
|
const SWIPE_DISMISS_PX = 80;
|
|
let dragY = $state(0);
|
|
let dragging = false;
|
|
let startY = 0;
|
|
|
|
function onHandleDown(event: PointerEvent) {
|
|
dragging = true;
|
|
startY = event.clientY;
|
|
(event.currentTarget as HTMLElement).setPointerCapture?.(event.pointerId);
|
|
}
|
|
function onHandleMove(event: PointerEvent) {
|
|
if (dragging) dragY = Math.max(0, event.clientY - startY);
|
|
}
|
|
function onHandleUp() {
|
|
if (!dragging) return;
|
|
dragging = false;
|
|
if (dragY >= SWIPE_DISMISS_PX) onClose();
|
|
dragY = 0;
|
|
}
|
|
|
|
function onKeydown(event: KeyboardEvent) {
|
|
if (event.key === 'Escape') onClose();
|
|
}
|
|
</script>
|
|
|
|
<!-- Backdrop: a full-screen button so tap-outside dismiss is keyboard- and
|
|
screen-reader-accessible without a static-element click handler. -->
|
|
<button
|
|
type="button"
|
|
class="fixed inset-0 z-30 bg-black/30 md:hidden"
|
|
aria-label={m.stammbaum_close_panel()}
|
|
onclick={onClose}
|
|
></button>
|
|
|
|
<div
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label={node.displayName}
|
|
class="fixed inset-x-0 bottom-0 z-40 max-h-[60dvh] overflow-y-auto rounded-t-xl border-t border-line bg-surface shadow-lg md:hidden"
|
|
style="transform: translateY({dragY}px);"
|
|
use:trapFocus
|
|
onkeydown={onKeydown}
|
|
>
|
|
<!-- Drag handle grip — swipe down to dismiss. -->
|
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
<div
|
|
class="flex cursor-grab justify-center py-2 active:cursor-grabbing"
|
|
onpointerdown={onHandleDown}
|
|
onpointermove={onHandleMove}
|
|
onpointerup={onHandleUp}
|
|
onpointercancel={onHandleUp}
|
|
>
|
|
<div class="h-1 w-10 rounded-full bg-line" aria-hidden="true"></div>
|
|
</div>
|
|
|
|
<StammbaumSidePanel node={node} canWrite={canWrite} onClose={onClose} onCentre={onCentre} />
|
|
</div>
|