4a0689a4ac
targetSdk 36 forces edge-to-edge, so the WebView draws behind the system bars. On Android WebView < 140, env(safe-area-inset-*) wrongly reports 0, so the app chrome (which only read env()) drew under the status bar (top nav untappable) and the gesture-nav home indicator (the game's centre Hint button intercepted; side buttons fine). Capacitor 8's SystemBars core plugin (built into @capacitor/core, insetsHandling:'css' by default) injects the correct --safe-area-inset-* values on every WebView; consume them ahead of env(): --tg-safe-*: var(--safe-area-inset-*, env(safe-area-inset-*, 0px)) Web / PWA / Telegram / VK are unchanged (--safe-area-inset-* is unset there, so it falls back to env()). Verified on-device (Pixel_10 / API 37) via the injected var — the emulator's auto-updated WebView 149 hides the env() bug, so the visual alone won't reproduce it.
83 lines
2.6 KiB
Svelte
83 lines
2.6 KiB
Svelte
<script lang="ts">
|
|
import { onMount, onDestroy } from 'svelte';
|
|
import { t } from '../lib/i18n/index.svelte';
|
|
import { app } from '../lib/app.svelte';
|
|
|
|
// A cute emoji cycler shown while a game's dictionary warms for the local move
|
|
// preview (docs/UI_DESIGN.md). One emoji per 500ms tick — 300ms static, then a
|
|
// 200ms clockwise spin with the current emoji fading out and the next fading in —
|
|
// looping through the sequence; the ten emojis span the 5s warm-up cap.
|
|
const EMOJIS = ['🎲', '🤔', '📡', '📀', '💾', '⏳', '🐌', '🙈', '🇷🇺', '✌️'];
|
|
const TICK_MS = 500;
|
|
const SPIN_MS = 200;
|
|
|
|
let index = $state(0);
|
|
let timer: ReturnType<typeof setInterval> | null = null;
|
|
|
|
onMount(() => {
|
|
timer = setInterval(() => (index = (index + 1) % EMOJIS.length), TICK_MS);
|
|
});
|
|
onDestroy(() => {
|
|
if (timer) clearInterval(timer);
|
|
});
|
|
|
|
// A simultaneous fade + clockwise spin used as both the in and out transition on the
|
|
// keyed glyph, so the outgoing and incoming emoji cross-fade in place. Under
|
|
// reduce-motion it degrades to a plain fade.
|
|
function spinFade(_node: Element, { duration = SPIN_MS }: { duration?: number } = {}) {
|
|
const spin = !app.reduceMotion;
|
|
return {
|
|
duration,
|
|
css: (u: number) => (spin ? `opacity:${u};transform:rotate(${(1 - u) * 360}deg)` : `opacity:${u}`),
|
|
};
|
|
}
|
|
</script>
|
|
|
|
<div class="overlay" role="status" aria-live="polite">
|
|
<div class="box">
|
|
<div class="stage">
|
|
{#key index}
|
|
<span class="emoji" in:spinFade out:spinFade>{EMOJIS[index]}</span>
|
|
{/key}
|
|
</div>
|
|
<span class="caption">{t('dict.loading')}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 200;
|
|
display: grid;
|
|
place-items: center;
|
|
/* Darker than the onboarding scrim — this blocks the board until the dictionary is ready. */
|
|
background: rgba(0, 0, 0, 0.72);
|
|
/* Via the shared --tg-safe-* tokens so the Android WebView < 140 env() bug is covered (app.css). */
|
|
padding: var(--tg-safe-top) var(--tg-safe-right) var(--tg-safe-bottom) var(--tg-safe-left);
|
|
}
|
|
.box {
|
|
display: grid;
|
|
justify-items: center;
|
|
gap: 1rem;
|
|
}
|
|
.stage {
|
|
display: grid;
|
|
place-items: center;
|
|
/* Reserve the glyph box so the caption never shifts as the emoji swaps. */
|
|
width: 4rem;
|
|
height: 4rem;
|
|
}
|
|
.emoji {
|
|
grid-area: 1 / 1;
|
|
font-size: 3.25rem; /* about twice a tab-bar button */
|
|
line-height: 1;
|
|
will-change: transform, opacity;
|
|
}
|
|
.caption {
|
|
color: #fff;
|
|
font-size: 1rem;
|
|
opacity: 0.85;
|
|
}
|
|
</style>
|