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
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:
@@ -44,6 +44,9 @@
|
|||||||
/* Height Telegram's native nav overlays at the top in fullscreen; set from the SDK's
|
/* Height Telegram's native nav overlays at the top in fullscreen; set from the SDK's
|
||||||
content-safe-area inset (Stage 17), 0 elsewhere. */
|
content-safe-area inset (Stage 17), 0 elsewhere. */
|
||||||
--tg-content-top: 0px;
|
--tg-content-top: 0px;
|
||||||
|
/* Telegram device safe-area top (the notch); TG's own nav controls sit between it and
|
||||||
|
--tg-content-top, so the in-app header aligns to that band (Stage 17), 0 elsewhere. */
|
||||||
|
--tg-safe-top: 0px;
|
||||||
--font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
|
--font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
|
||||||
"Noto Sans", "Liberation Sans", sans-serif;
|
"Noto Sans", "Liberation Sans", sans-serif;
|
||||||
--shadow: 0 1px 2px rgba(0, 0, 0, 0.08), 0 6px 16px rgba(0, 0, 0, 0.06);
|
--shadow: 0 1px 2px rgba(0, 0, 0, 0.08), 0 6px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
|||||||
@@ -89,17 +89,18 @@
|
|||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
}
|
}
|
||||||
/* Telegram fullscreen: TG's native nav overlays a band of height --tg-content-top at the top
|
/* Telegram fullscreen: TG's native nav occupies the band between the device notch
|
||||||
of the viewport. Pull our title + menu up into the BOTTOM of that band and centre them as a
|
(--tg-safe-top) and --tg-content-top. Our header spans that full band (so the layout below
|
||||||
pair (hamburger right of the title) so they line up with Telegram's own nav controls rather
|
is unchanged) and centres the title + menu as a pair (hamburger right of the title) within
|
||||||
than floating above them (Stage 17). */
|
it, BELOW the notch — lining them up vertically with Telegram's own back/menu controls,
|
||||||
|
which sit in the band's corners (Stage 17). */
|
||||||
:global(html.tg-fullscreen) .bar {
|
:global(html.tg-fullscreen) .bar {
|
||||||
min-height: var(--tg-content-top);
|
min-height: var(--tg-content-top);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
align-items: flex-end;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding-top: 0;
|
padding-top: var(--tg-safe-top);
|
||||||
padding-bottom: 6px;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
:global(html.tg-fullscreen) .spacer {
|
:global(html.tg-fullscreen) .spacer {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
import Header from './Header.svelte';
|
import Header from './Header.svelte';
|
||||||
import AdBanner from './AdBanner.svelte';
|
import AdBanner from './AdBanner.svelte';
|
||||||
import { navigate } from '../lib/router.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
|
// 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`
|
// optional tab bar pin to the bottom (ad directly above the content). Pass `scroll`
|
||||||
@@ -37,25 +36,28 @@
|
|||||||
const SHOW_AD_BANNER = false;
|
const SHOW_AD_BANNER = false;
|
||||||
|
|
||||||
// Edge-swipe back (Stage 17): a left-edge rightward drag returns to `back`, the standard
|
// 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
|
// mobile gesture. Listened at the window in the CAPTURE phase so the board's own pointer
|
||||||
// board's own horizontal gestures; touch/pen only. Skipped inside Telegram, whose native
|
// handlers (which capture/stop the event) can never swallow it; armed only from the very
|
||||||
// back button + swipe already cover this (and would otherwise double up).
|
// left edge (<=24px), touch/pen only, so it never competes with the board's gestures.
|
||||||
function onEdgeDown(e: PointerEvent): void {
|
$effect(() => {
|
||||||
if (!back || e.pointerType === 'mouse' || insideTelegram() || e.clientX > 24) return;
|
function onDown(e: PointerEvent) {
|
||||||
const x0 = e.clientX;
|
if (!back || e.pointerType === 'mouse' || e.clientX > 24) return;
|
||||||
const y0 = e.clientY;
|
const x0 = e.clientX;
|
||||||
const onUp = (ev: PointerEvent) => {
|
const y0 = e.clientY;
|
||||||
window.removeEventListener('pointerup', onUp);
|
const onUp = (ev: PointerEvent) => {
|
||||||
const dx = ev.clientX - x0;
|
window.removeEventListener('pointerup', onUp, true);
|
||||||
const dy = ev.clientY - y0;
|
const dx = ev.clientX - x0;
|
||||||
if (back && dx > 64 && Math.abs(dx) > Math.abs(dy) * 1.4) navigate(back);
|
const dy = ev.clientY - y0;
|
||||||
};
|
if (back && dx > 64 && Math.abs(dx) > Math.abs(dy) * 1.4) navigate(back);
|
||||||
window.addEventListener('pointerup', onUp);
|
};
|
||||||
}
|
window.addEventListener('pointerup', onUp, true);
|
||||||
|
}
|
||||||
|
window.addEventListener('pointerdown', onDown, true);
|
||||||
|
return () => window.removeEventListener('pointerdown', onDown, true);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<div class="screen">
|
||||||
<div class="screen" onpointerdown={onEdgeDown}>
|
|
||||||
<Header {title} {back} {menu} grow={growNav} />
|
<Header {title} {back} {menu} grow={growNav} />
|
||||||
{#if SHOW_AD_BANNER}<AdBanner />{/if}
|
{#if SHOW_AD_BANNER}<AdBanner />{/if}
|
||||||
<main class="content" class:scroll class:fill={!growNav} class:column>{@render children?.()}</main>
|
<main class="content" class:scroll class:fill={!growNav} class:column>{@render children?.()}</main>
|
||||||
|
|||||||
@@ -364,7 +364,7 @@
|
|||||||
zoomed = true;
|
zoomed = true;
|
||||||
telegramHaptic('light');
|
telegramHaptic('light');
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 700)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
onTelegramPath,
|
onTelegramPath,
|
||||||
telegramColorScheme,
|
telegramColorScheme,
|
||||||
telegramContentSafeAreaTop,
|
telegramContentSafeAreaTop,
|
||||||
|
telegramSafeAreaTop,
|
||||||
telegramDisableVerticalSwipes,
|
telegramDisableVerticalSwipes,
|
||||||
telegramHaptic,
|
telegramHaptic,
|
||||||
telegramLaunch,
|
telegramLaunch,
|
||||||
@@ -238,6 +239,7 @@ function syncTelegramSafeArea(): void {
|
|||||||
if (typeof document === 'undefined') return;
|
if (typeof document === 'undefined') return;
|
||||||
const top = telegramContentSafeAreaTop();
|
const top = telegramContentSafeAreaTop();
|
||||||
document.documentElement.style.setProperty('--tg-content-top', `${top}px`);
|
document.documentElement.style.setProperty('--tg-content-top', `${top}px`);
|
||||||
|
document.documentElement.style.setProperty('--tg-safe-top', `${telegramSafeAreaTop()}px`);
|
||||||
document.documentElement.classList.toggle('tg-fullscreen', top > 0);
|
document.documentElement.classList.toggle('tg-fullscreen', top > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +281,7 @@ export async function bootstrap(): Promise<void> {
|
|||||||
syncTelegramChrome();
|
syncTelegramChrome();
|
||||||
syncTelegramSafeArea();
|
syncTelegramSafeArea();
|
||||||
telegramOnEvent('contentSafeAreaChanged', syncTelegramSafeArea);
|
telegramOnEvent('contentSafeAreaChanged', syncTelegramSafeArea);
|
||||||
|
telegramOnEvent('safeAreaChanged', syncTelegramSafeArea);
|
||||||
telegramOnEvent('fullscreenChanged', syncTelegramSafeArea);
|
telegramOnEvent('fullscreenChanged', syncTelegramSafeArea);
|
||||||
telegramDisableVerticalSwipes();
|
telegramDisableVerticalSwipes();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ interface TelegramWebApp {
|
|||||||
themeParams?: TelegramThemeParams;
|
themeParams?: TelegramThemeParams;
|
||||||
colorScheme?: 'light' | 'dark';
|
colorScheme?: 'light' | 'dark';
|
||||||
isFullscreen?: boolean;
|
isFullscreen?: boolean;
|
||||||
|
safeAreaInset?: { top: number; bottom: number; left: number; right: number };
|
||||||
contentSafeAreaInset?: { top: number; bottom: number; left: number; right: number };
|
contentSafeAreaInset?: { top: number; bottom: number; left: number; right: number };
|
||||||
ready?: () => void;
|
ready?: () => void;
|
||||||
expand?: () => void;
|
expand?: () => void;
|
||||||
@@ -110,6 +111,16 @@ export function telegramContentSafeAreaTop(): number {
|
|||||||
return webApp()?.contentSafeAreaInset?.top ?? 0;
|
return webApp()?.contentSafeAreaInset?.top ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* telegramSafeAreaTop returns the device safe-area top inset (px) — the notch / status bar
|
||||||
|
* (Bot API 8.0). Telegram's own nav controls sit in the band between it and
|
||||||
|
* telegramContentSafeAreaTop, so aligning our header to that band lines it up with them. 0
|
||||||
|
* outside Telegram or on older clients.
|
||||||
|
*/
|
||||||
|
export function telegramSafeAreaTop(): number {
|
||||||
|
return webApp()?.safeAreaInset?.top ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* telegramDisableVerticalSwipes turns off Telegram's swipe-down-to-minimise gesture so
|
* telegramDisableVerticalSwipes turns off Telegram's swipe-down-to-minimise gesture so
|
||||||
* it does not fight tile drag-and-drop or the board's vertical scroll.
|
* it does not fight tile drag-and-drop or the board's vertical scroll.
|
||||||
|
|||||||
Reference in New Issue
Block a user