Review fixes: swipe (capture-phase, enabled in TG), TG header aligns to the nav band, DnD zoom delay 1s->0.7s
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 32s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m8s

- Edge-swipe back now listens at the window in the CAPTURE phase (the board's
  pointer handlers can't swallow it) and is no longer skipped inside Telegram
  (where the owner tests it).
- TG-fullscreen header: expose the device safe-area top (--tg-safe-top) and
  centre the title + menu pair within Telegram's nav band ([safe-top,
  content-top]) below the notch, keeping the band's height — lining up with
  Telegram's own controls.
- DnD auto-zoom-on-hover delay reduced 1000ms -> 700ms.

(Client-IP: diagnosed as the owner's home-router SNAT — the host caddy already
receives 192.168.0.1 with no XFF, so the real IP is lost upstream of our stack;
correct in prod. No code change.)
This commit is contained in:
Ilia Denisov
2026-06-08 22:01:43 +02:00
parent 645df52c0b
commit 7e34897d6d
6 changed files with 46 additions and 26 deletions
+20 -18
View File
@@ -3,7 +3,6 @@
import Header from './Header.svelte';
import AdBanner from './AdBanner.svelte';
import { navigate } from '../lib/router.svelte';
import { insideTelegram } from '../lib/telegram';
// The app-shell layout (all screens): the nav bar grows; the ad strip, content and
// optional tab bar pin to the bottom (ad directly above the content). Pass `scroll`
@@ -37,25 +36,28 @@
const SHOW_AD_BANNER = false;
// Edge-swipe back (Stage 17): a left-edge rightward drag returns to `back`, the standard
// mobile gesture. Armed only from the very left edge (<=24px) so it never competes with the
// board's own horizontal gestures; touch/pen only. Skipped inside Telegram, whose native
// back button + swipe already cover this (and would otherwise double up).
function onEdgeDown(e: PointerEvent): void {
if (!back || e.pointerType === 'mouse' || insideTelegram() || e.clientX > 24) return;
const x0 = e.clientX;
const y0 = e.clientY;
const onUp = (ev: PointerEvent) => {
window.removeEventListener('pointerup', onUp);
const dx = ev.clientX - x0;
const dy = ev.clientY - y0;
if (back && dx > 64 && Math.abs(dx) > Math.abs(dy) * 1.4) navigate(back);
};
window.addEventListener('pointerup', onUp);
}
// mobile gesture. Listened at the window in the CAPTURE phase so the board's own pointer
// handlers (which capture/stop the event) can never swallow it; armed only from the very
// left edge (<=24px), touch/pen only, so it never competes with the board's gestures.
$effect(() => {
function onDown(e: PointerEvent) {
if (!back || e.pointerType === 'mouse' || e.clientX > 24) return;
const x0 = e.clientX;
const y0 = e.clientY;
const onUp = (ev: PointerEvent) => {
window.removeEventListener('pointerup', onUp, true);
const dx = ev.clientX - x0;
const dy = ev.clientY - y0;
if (back && dx > 64 && Math.abs(dx) > Math.abs(dy) * 1.4) navigate(back);
};
window.addEventListener('pointerup', onUp, true);
}
window.addEventListener('pointerdown', onDown, true);
return () => window.removeEventListener('pointerdown', onDown, true);
});
</script>
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="screen" onpointerdown={onEdgeDown}>
<div class="screen">
<Header {title} {back} {menu} grow={growNav} />
{#if SHOW_AD_BANNER}<AdBanner />{/if}
<main class="content" class:scroll class:fill={!growNav} class:column>{@render children?.()}</main>