feat(ui): tile-crossword loading splash for cold lobby open
CI / changes (pull_request) Successful in 3s
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 1m17s

On a cold app open the lobby's game list arrives over the network; on a
slow link the empty "no games yet" line flashed before the games loaded.
Add a full-screen tile splash that lays a Scrabble crossword of ЭРУДИТ /
ЗАГРУЗКА / ОЖИДАНИЕ (Эрудит point values, hardcoded since the alphabet
table is not cached at boot) until the lobby's first load settles, then
removes itself to reveal the populated list.

- lib/splash.ts: pure layout + reveal schedule (unit-tested).
- components/Splash.svelte: App-level overlay; per-tile drop-in; loops
  ЗАГРУЗКА → ОЖИДАНИЕ until ready, dismisses on a word boundary. Static
  ЭРУДИТ under reduced motion / the mock build.
- app state: lobbyReady (set by Lobby on first settle) + splashDone,
  reset on logout.
- App.svelte: overlay while routeIsLobby && !splashDone; the plain text
  splash now only covers non-lobby deep-links during bootstrap.
- docs: UI_DESIGN + FUNCTIONAL (+ _ru).
This commit is contained in:
Ilia Denisov
2026-06-21 10:29:39 +02:00
parent e79c1ea891
commit ba6ee90278
9 changed files with 460 additions and 1 deletions
+15 -1
View File
@@ -6,6 +6,7 @@
import { t } from './lib/i18n/index.svelte';
import { insideTelegram, telegramBackButton } from './lib/telegram';
import Toast from './components/Toast.svelte';
import Splash from './components/Splash.svelte';
import StaleInviteModal from './components/StaleInviteModal.svelte';
import WelcomeRedeemModal from './components/WelcomeRedeemModal.svelte';
import Login from './screens/Login.svelte';
@@ -22,6 +23,11 @@
void bootstrap();
});
// The lobby is the cold-start landing (an empty hash and Telegram launch params both parse
// to it). The tile loading splash overlays it until its first load settles; a deep-link to
// another screen is not covered.
const routeIsLobby = $derived(router.route.name === 'lobby');
// Inside Telegram, drive its native header back button: show it on any sub-screen
// (everything returns to the lobby root), hide it on the lobby/login. The app's own
// back chevron is hidden in Telegram (Header.svelte) so only the native one shows.
@@ -72,7 +78,11 @@
</script>
{#if !app.ready}
<div class="splash">{t('common.loading')}</div>
<!-- On a cold lobby open the tile splash (below) covers bootstrap too; a deep-link to
another screen keeps the plain text splash while bootstrap runs. -->
{#if !routeIsLobby}
<div class="splash">{t('common.loading')}</div>
{/if}
{:else if app.blocked}
<Blocked />
{:else}
@@ -113,6 +123,10 @@
<StaleInviteModal />
<WelcomeRedeemModal />
{#if routeIsLobby && !app.splashDone && !app.blocked}
<Splash />
{/if}
<style>
.splash {
height: 100%;