Stage 17 (contour round 3): Telegram Mini Apps polish, board scroll, keyboard overlay
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 10s
CI / ui (pull_request) Successful in 27s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 54s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 10s
CI / ui (pull_request) Successful in 27s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 54s
- Telegram (lib/telegram.ts): chrome colours (setHeaderColor/setBackgroundColor/setBottomBarColor) match Telegram's header/bg/bottom bar to the app; native BackButton on sub-screens (app chevron hidden in TG); HapticFeedback on tile place/commit/error; enableClosingConfirmation while a game is open; disableVerticalSwipes so swipe-to-minimise doesn't fight tile drag / board scroll - #9 board-only vertical scroll: Screen 'column' mode lets the board area scroll while score/status/rack/tab bar stay fixed (zoom keeps its own scroll) - #10 check-word dialog opens in Modal keyboard-overlay mode (top-anchored, keyboard overlays the empty area) — no resize/relayout jank; other modals stay keyboard-aware - docs: UI_DESIGN Telegram integration + vertical fit/keyboard; PLAN round 2-3 follow-ups
This commit is contained in:
+18
-3
@@ -19,6 +19,7 @@
|
||||
import { canCheckWord, sanitizeCheckWord } from '../lib/checkword';
|
||||
import { shareOrDownloadGcg } from '../lib/share';
|
||||
import { getCachedGame, setCachedGame } from '../lib/gamecache';
|
||||
import { telegramClosingConfirmation, telegramHaptic } from '../lib/telegram';
|
||||
import {
|
||||
BLANK,
|
||||
newPlacement,
|
||||
@@ -112,6 +113,8 @@
|
||||
}
|
||||
}
|
||||
onMount(() => {
|
||||
// Guard against an accidental swipe-close losing the open game (Telegram).
|
||||
telegramClosingConfirmation(true);
|
||||
// Render instantly from the cache (a game opened before), then refresh in the
|
||||
// background. A cold open shows the loading state until load() resolves.
|
||||
const cached = getCachedGame(id);
|
||||
@@ -185,6 +188,7 @@
|
||||
onDestroy(() => {
|
||||
window.removeEventListener('pointermove', onWinMove);
|
||||
window.removeEventListener('pointerup', onWinUp);
|
||||
telegramClosingConfirmation(false);
|
||||
});
|
||||
|
||||
function onCell(row: number, col: number) {
|
||||
@@ -212,12 +216,14 @@
|
||||
return;
|
||||
}
|
||||
placement = place(placement, index, row, col);
|
||||
telegramHaptic('select');
|
||||
recompute();
|
||||
}
|
||||
function chooseBlank(letter: string) {
|
||||
if (!blankPrompt) return;
|
||||
placement = place(placement, blankPrompt.rackIndex, blankPrompt.row, blankPrompt.col, letter);
|
||||
blankPrompt = null;
|
||||
telegramHaptic('select');
|
||||
recompute();
|
||||
}
|
||||
|
||||
@@ -242,6 +248,7 @@
|
||||
busy = true;
|
||||
try {
|
||||
await gateway.submitPlay(id, sub.dir, sub.tiles, variant);
|
||||
telegramHaptic('success');
|
||||
zoomed = false;
|
||||
await load();
|
||||
} catch (e) {
|
||||
@@ -449,7 +456,7 @@
|
||||
]);
|
||||
</script>
|
||||
|
||||
<Screen title={t('app.title')} back="/" growNav scroll={!historyOpen}>
|
||||
<Screen title={t('app.title')} back="/" growNav column scroll={false}>
|
||||
{#snippet menu()}
|
||||
<Menu items={menuItems} />
|
||||
{/snippet}
|
||||
@@ -596,7 +603,7 @@
|
||||
{/if}
|
||||
|
||||
{#if checkOpen}
|
||||
<Modal title={t('game.checkWord')} onclose={() => (checkOpen = false)}>
|
||||
<Modal title={t('game.checkWord')} overlayKeyboard onclose={() => (checkOpen = false)}>
|
||||
<div class="check">
|
||||
<input
|
||||
value={checkWord}
|
||||
@@ -635,6 +642,7 @@
|
||||
<style>
|
||||
.scoreboard {
|
||||
display: flex;
|
||||
flex: none;
|
||||
gap: 6px;
|
||||
padding: 8px var(--pad);
|
||||
background: var(--bg-elev);
|
||||
@@ -681,7 +689,12 @@
|
||||
}
|
||||
.stage {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
/* The board is the only part that scrolls vertically when the game does not fit;
|
||||
the score bar, status, rack and tab bar stay put (#9). */
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.history {
|
||||
position: absolute;
|
||||
@@ -741,6 +754,7 @@
|
||||
}
|
||||
.status {
|
||||
display: flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 2px var(--pad) 6px;
|
||||
@@ -762,6 +776,7 @@
|
||||
}
|
||||
.rack-row {
|
||||
display: flex;
|
||||
flex: none;
|
||||
gap: 8px;
|
||||
align-items: stretch;
|
||||
padding: 0 var(--pad) 6px;
|
||||
|
||||
Reference in New Issue
Block a user