fix(ui): mobile in-app WebView polish (tap-flash, VK haptics, swipe-back)
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m13s

- Tap-highlight: add -webkit-tap-highlight-color: transparent on #app.
  Android in-app WebViews (Telegram, VK) flashed a momentary selection-like
  box on tappable nodes on tap — seen on the header title and the back
  chevron; user-select (already none) does not govern it. Inherited, so
  this clears it app-wide.

- VK haptics: mirror the Telegram haptic set on VK via VK Bridge taptic
  (impact / notification / selection), routed through a new shared
  lib/haptics.ts dispatcher. VK users previously got no haptics; the game
  and error call sites now fire haptic() instead of telegramHaptic().

- VK swipe-back: disable VK's horizontal swipe-back at launch
  (VKWebAppSetSwipeSettings history:false) so it does not fight the app's
  own edge-swipe-back and on-board tile drag — parity with Telegram's
  disabled vertical swipes; the app owns navigation via its back chevron.

Docs: UI_DESIGN (no-select / tap-highlight, VK integration).
This commit is contained in:
Ilia Denisov
2026-06-30 23:00:19 +02:00
parent adf7c55695
commit 71c3411276
6 changed files with 80 additions and 10 deletions
+7 -6
View File
@@ -24,7 +24,8 @@
import { getCachedGame, setCachedGame, setCachedDraft, type CachedGame } from '../lib/gamecache';
import { patchLobbyGame } from '../lib/lobbycache';
import { applyGameOver, applyMoveDelta, applyOpponentJoined, type DeltaResult } from '../lib/gamedelta';
import { insideTelegram, telegramDialogsAvailable, telegramHaptic, telegramShowConfirm } from '../lib/telegram';
import { insideTelegram, telegramDialogsAvailable, telegramShowConfirm } from '../lib/telegram';
import { haptic } from '../lib/haptics';
import {
BLANK,
newPlacement,
@@ -511,7 +512,7 @@
if (drag && isCoarse() && !zoomed) {
focus = c;
zoomed = true;
telegramHaptic('light');
haptic('light');
}
}, 700)
: null;
@@ -623,7 +624,7 @@
return;
}
placement = place(placement, index, row, col);
telegramHaptic('select');
haptic('select');
recompute();
scheduleDraftSave();
}
@@ -631,7 +632,7 @@
if (!blankPrompt) return;
placement = place(placement, blankPrompt.rackIndex, blankPrompt.row, blankPrompt.col, letter);
blankPrompt = null;
telegramHaptic('select');
haptic('select');
recompute();
scheduleDraftSave();
}
@@ -687,7 +688,7 @@
busy = true;
try {
applyMoveResult(await gateway.submitPlay(id, sub.tiles, variant));
telegramHaptic('success');
haptic('success');
zoomed = false;
} catch (e) {
handleError(e);
@@ -793,7 +794,7 @@
shuffling = true;
setTimeout(() => (shuffling = false), 600);
// A short "shake": a few quick light taps rather than one.
for (let i = 0; i < 4; i++) setTimeout(() => telegramHaptic('light'), i * 55);
for (let i = 0; i < 4; i++) setTimeout(() => haptic('light'), i * 55);
scheduleDraftSave();
}
function openExchange() {