Stage 7 (wip): UI shell, libs, mock transport, screens (lobby->game), e2e smoke

- plain Svelte 5 + TS + Vite (no SvelteKit); CSS-token design system (Telegram-ready), hash router, IndexedDB session
- pure libs: domain model, premium/value maps ported from solver, board replay, placement state machine, i18n en/ru
- in-memory mock transport + seed data; pnpm start runs lobby->active game->board with no backend
- board: pointer-drag + tap placement, MakeMove (popup / 1s-hold commit), two-state zoom, blank chooser, exchange, hint, word-check, chat
- Playwright smoke (mock) green; svelte-check clean; mock bundle ~37 KB gzip
This commit is contained in:
Ilia Denisov
2026-06-03 00:32:50 +02:00
parent 19ae8f04a2
commit 453ddc5e94
48 changed files with 5696 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
<script lang="ts">
import type { RackSlot } from '../lib/placement';
import { BLANK } from '../lib/placement';
import { tileValue } from '../lib/premiums';
import type { Variant } from '../lib/model';
let {
slots,
variant,
selected,
ondown,
}: {
slots: RackSlot[];
variant: Variant;
selected: number | null;
ondown: (e: PointerEvent, index: number) => void;
} = $props();
</script>
<div class="rack">
{#each slots as slot (slot.index)}
{#if slot.used}
<span class="slot empty"></span>
{:else}
<button
class="slot tile"
class:selected={selected === slot.index}
data-rack-index={slot.index}
onpointerdown={(e) => ondown(e, slot.index)}
>
<span class="letter">{slot.letter === BLANK ? '' : slot.letter}</span>
{#if slot.letter !== BLANK}<span class="val">{tileValue(variant, slot.letter)}</span>{/if}
</button>
{/if}
{/each}
</div>
<style>
.rack {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 5px;
}
.slot {
aspect-ratio: 1;
border-radius: 5px;
}
.empty {
background: var(--surface-2);
border: 1px dashed var(--border);
}
.tile {
position: relative;
background: var(--tile-bg);
color: var(--tile-text);
border: none;
box-shadow: inset 0 -3px 0 var(--tile-edge);
font-weight: 700;
font-size: 1.4rem;
touch-action: none;
user-select: none;
}
.tile.selected {
outline: 3px solid var(--accent);
outline-offset: -3px;
}
.val {
position: absolute;
right: 3px;
bottom: 1px;
font-size: 0.7rem;
font-weight: 600;
}
</style>