Game/Telegram review polish: USSR flag, touch drag ghost, TG fullscreen header
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 11s
CI / ui (pull_request) Successful in 31s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 55s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 11s
CI / ui (pull_request) Successful in 31s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 55s
Backlog item 2 of ~4 (owner review pass): - USSR flag emblem redrawn (canonical hammer & sickle, scaled down 1.5x below the star). - Touch drag-and-drop: enlarge the drag ghost 1.5x on touch only (the finger hides the tile); suppress the iOS tap-highlight that lingered on a rack tile sliding into a dragged tile's slot. - Telegram fullscreen: its native nav no longer hides our header -- the header drops below the content-safe-area top inset and the menu (hamburger) lifts into the nav band, centred (--tg-content-top from the SDK inset + a tg-fullscreen class; new telegram.ts helper + app wiring). Tests: UI check/test:unit/build + full e2e (60) green. The iOS tap-highlight fix and the TG-fullscreen layout want on-device verification on the deploy.
This commit is contained in:
@@ -41,6 +41,9 @@
|
||||
--radius-sm: 6px;
|
||||
--gap: 8px;
|
||||
--pad: 12px;
|
||||
/* Height Telegram's native nav overlays at the top in fullscreen; set from the SDK's
|
||||
content-safe-area inset (Stage 17), 0 elsewhere. */
|
||||
--tg-content-top: 0px;
|
||||
--font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
|
||||
"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);
|
||||
|
||||
@@ -89,4 +89,20 @@
|
||||
transform: rotate(45deg);
|
||||
margin-left: 3px;
|
||||
}
|
||||
/* Telegram fullscreen: its native nav overlays the top of the viewport (height
|
||||
--tg-content-top, set from the content-safe-area inset). Drop the header content below the
|
||||
nav and lift the menu up into the nav band, centred — Telegram's own controls sit in the
|
||||
corners, leaving the centre clear (Stage 17). */
|
||||
:global(html.tg-fullscreen) .bar {
|
||||
padding-top: var(--tg-content-top);
|
||||
}
|
||||
:global(html.tg-fullscreen) .end {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
height: var(--tg-content-top);
|
||||
justify-content: center;
|
||||
z-index: 30;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
let checkResult = $state<{ word: string; legal: boolean } | null>(null);
|
||||
let resignOpen = $state(false);
|
||||
let messages = $state<ChatMessage[]>([]);
|
||||
let drag = $state<{ letter: string; blank: boolean; x: number; y: number } | null>(null);
|
||||
let drag = $state<{ letter: string; blank: boolean; x: number; y: number; touch: boolean } | null>(null);
|
||||
|
||||
const checkedWords = new Map<string, boolean>();
|
||||
let cooling = $state(false);
|
||||
@@ -315,7 +315,7 @@
|
||||
const src = downInfo.src;
|
||||
const letter =
|
||||
src.from === 'rack' ? placement.rack[src.index] : pendingMap.get(`${src.row},${src.col}`)?.letter ?? '';
|
||||
drag = { letter, blank: letter === BLANK, x: e.clientX, y: e.clientY };
|
||||
drag = { letter, blank: letter === BLANK, x: e.clientX, y: e.clientY, touch: e.pointerType === 'touch' };
|
||||
// A rack tile is lifted out of the rack while dragged (the ghost stands in for it).
|
||||
reorderDragId = src.from === 'rack' ? rackIds[src.index] ?? null : null;
|
||||
// No zoom on drag start: the player may still change their mind. Holding the tile
|
||||
@@ -814,7 +814,7 @@
|
||||
</Screen>
|
||||
|
||||
{#if drag}
|
||||
<div class="ghost" style="left:{drag.x}px; top:{drag.y}px">
|
||||
<div class="ghost" class:touch={drag.touch} style="left:{drag.x}px; top:{drag.y}px">
|
||||
<span>{drag.blank ? '' : drag.letter}</span>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -1092,6 +1092,10 @@
|
||||
pointer-events: none;
|
||||
z-index: 60;
|
||||
}
|
||||
/* On touch the finger covers the tile, so enlarge the drag ghost ~1.5x (Stage 17). */
|
||||
.ghost.touch {
|
||||
transform: translate(-50%, -50%) scale(1.5);
|
||||
}
|
||||
.alpha {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
|
||||
@@ -91,6 +91,10 @@
|
||||
font-size: 1.4rem;
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
/* iOS shows a tap/active highlight that can linger on the neighbour sliding into a
|
||||
dragged tile's slot (Stage 17); suppress it so only our own styles mark a tile. */
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.tile.selected {
|
||||
outline: 3px solid var(--accent);
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
insideTelegram,
|
||||
onTelegramPath,
|
||||
telegramColorScheme,
|
||||
telegramContentSafeAreaTop,
|
||||
telegramDisableVerticalSwipes,
|
||||
telegramHaptic,
|
||||
telegramLaunch,
|
||||
@@ -227,6 +228,19 @@ function syncTelegramChrome(): void {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* syncTelegramSafeArea mirrors Telegram's content-safe-area top inset (the height its native
|
||||
* nav overlays the viewport in fullscreen) into the --tg-content-top CSS var and toggles a
|
||||
* `tg-fullscreen` class, so the header can drop below the nav and lift the menu into its
|
||||
* band (Stage 17). Called on launch and on Telegram's safe-area / fullscreen change events.
|
||||
*/
|
||||
function syncTelegramSafeArea(): void {
|
||||
if (typeof document === 'undefined') return;
|
||||
const top = telegramContentSafeAreaTop();
|
||||
document.documentElement.style.setProperty('--tg-content-top', `${top}px`);
|
||||
document.documentElement.classList.toggle('tg-fullscreen', top > 0);
|
||||
}
|
||||
|
||||
export async function bootstrap(): Promise<void> {
|
||||
const prefs = await loadPrefs();
|
||||
app.theme = prefs.theme ?? 'auto';
|
||||
@@ -263,6 +277,9 @@ export async function bootstrap(): Promise<void> {
|
||||
// Match Telegram's chrome to the app and stop its swipe-down-to-minimise from
|
||||
// fighting tile drag / board scroll.
|
||||
syncTelegramChrome();
|
||||
syncTelegramSafeArea();
|
||||
telegramOnEvent('contentSafeAreaChanged', syncTelegramSafeArea);
|
||||
telegramOnEvent('fullscreenChanged', syncTelegramSafeArea);
|
||||
telegramDisableVerticalSwipes();
|
||||
try {
|
||||
await adoptSession(await gateway.authTelegram(launch.initData));
|
||||
|
||||
@@ -10,6 +10,8 @@ interface TelegramWebApp {
|
||||
initDataUnsafe?: { start_param?: string };
|
||||
themeParams?: TelegramThemeParams;
|
||||
colorScheme?: 'light' | 'dark';
|
||||
isFullscreen?: boolean;
|
||||
contentSafeAreaInset?: { top: number; bottom: number; left: number; right: number };
|
||||
ready?: () => void;
|
||||
expand?: () => void;
|
||||
onEvent?: (event: string, handler: () => void) => void;
|
||||
@@ -99,6 +101,15 @@ export function telegramSetChrome(header: string, background: string, bottom: st
|
||||
if (bottom) w?.setBottomBarColor?.(bottom);
|
||||
}
|
||||
|
||||
/**
|
||||
* telegramContentSafeAreaTop returns the height (px) Telegram's own UI overlays at the top of
|
||||
* the viewport in fullscreen (its nav band; the content-safe area, Bot API 8.0). It is 0
|
||||
* outside Telegram or on clients predating it, so callers can pad/position defensively.
|
||||
*/
|
||||
export function telegramContentSafeAreaTop(): number {
|
||||
return webApp()?.contentSafeAreaInset?.top ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
Reference in New Issue
Block a user