R6(a): de-stage code, docs, READMEs; split stage6_test
Mechanical, behaviour-preserving removal of Stage N / TODO-N / phase (RN) references from comments, doc-comments, service READMEs, the current-state docs (ARCHITECTURE, FUNCTIONAL+_ru, TESTING, UI_DESIGN), config-file comments, and the .fbs/.proto schema comments. PLAN.md / PRERELEASE.md / CLAUDE.md keep the stage history. - Rename the only stage-named identifiers: registerStage8 -> registerSocialOps, registerStage11 -> registerLinkOps (gateway transcode). - Split stage6_test.go: TestEmailLoginFlow -> email_test.go, TestGuestAutoMatchLeavesNoStats (+ provisionGuest) -> account_test.go. - Regenerated proto bindings (push.pb.go, telegram_grpc.pb.go) from the de-staged .proto comments; FB Go/TS bindings unchanged (flatc strips schema comments). go build/vet/gofmt clean across modules; integration typecheck and pnpm check green.
This commit is contained in:
@@ -94,7 +94,7 @@
|
||||
return () => cancelAnimationFrame(raf);
|
||||
});
|
||||
|
||||
// Pinch zoom (Stage 17): a two-finger spread zooms in toward the pinch midpoint, a pinch
|
||||
// Pinch zoom: a two-finger spread zooms in toward the pinch midpoint, a pinch
|
||||
// close zooms out. preventDefault fires only for two touches, so the one-finger native
|
||||
// scroll of the zoomed board is left untouched. It maps to the same two-state zoom as
|
||||
// double-tap, toggling toward the midpoint cell.
|
||||
@@ -278,7 +278,7 @@
|
||||
.cell.pending {
|
||||
background: var(--tile-pending);
|
||||
/* The placed tile owns the pointer so it can be dragged to relocate it (even on the zoomed
|
||||
board) instead of the touch starting a board pan (Stage 17). */
|
||||
board) instead of the touch starting a board pan. */
|
||||
touch-action: none;
|
||||
}
|
||||
/* Lines-off variant: a gapless checkerboard. The 1px grid gaps (and the cell-line they
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
messages: ChatMessage[];
|
||||
myId: string;
|
||||
busy: boolean;
|
||||
// Chat and nudge are mutually exclusive by turn (Stage 17): on the player's own turn the
|
||||
// Chat and nudge are mutually exclusive by turn: on the player's own turn the
|
||||
// message field + send are shown (and nudging makes no sense — there is no one to
|
||||
// hurry); on the opponent's turn only the nudge button shows. While the hourly nudge
|
||||
// cooldown is active the nudge is disabled with an "awaiting reply" caption.
|
||||
@@ -72,7 +72,7 @@
|
||||
gap: 10px;
|
||||
/* Fill the chat screen; the list scrolls and the input pins to the bottom. The screen
|
||||
fits the visual viewport (--vvh), so an open keyboard simply shrinks it and the input
|
||||
stays visible — no modal relayout, no page jump (Stage 17). */
|
||||
stays visible — no modal relayout, no page jump. */
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 10px var(--pad);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { t } from '../lib/i18n/index.svelte';
|
||||
import type { ChatMessage, StateView } from '../lib/model';
|
||||
|
||||
// The chat is its own screen (Stage 17), so the soft keyboard simply resizes the viewport with
|
||||
// The chat is its own screen, so the soft keyboard simply resizes the viewport with
|
||||
// the input pinned to the bottom — no modal relayout jank. It loads the game state (for the
|
||||
// turn-based chat/nudge toggle) and the message list, and clears the unread badge while open.
|
||||
let { id }: { id: string } = $props();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { canCheckWord, sanitizeCheckWord } from '../lib/checkword';
|
||||
import type { Variant } from '../lib/model';
|
||||
|
||||
// Word-check on its own screen (Stage 17): unlimited dictionary lookups, each with a
|
||||
// Word-check on its own screen: unlimited dictionary lookups, each with a
|
||||
// complaint, off the board so the soft keyboard never relayouts the play area.
|
||||
let { id }: { id: string } = $props();
|
||||
|
||||
|
||||
+14
-14
@@ -112,7 +112,7 @@
|
||||
}
|
||||
let draftSaveTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
// scheduleDraftSave persists the composition (rack order + pending tiles) after a short
|
||||
// debounce; best-effort, so a failed save never interrupts play (Stage 17).
|
||||
// debounce; best-effort, so a failed save never interrupts play.
|
||||
function scheduleDraftSave() {
|
||||
if (draftSaveTimer) clearTimeout(draftSaveTimer);
|
||||
draftSaveTimer = setTimeout(() => {
|
||||
@@ -178,7 +178,7 @@
|
||||
if (!e) return;
|
||||
if (e.kind === 'opponent_moved' && e.gameId === id) {
|
||||
// While composing, reload so a draft overlapping the new move is reconciled; otherwise apply
|
||||
// the move as a delta with no fetch (R4).
|
||||
// the move as a delta with no fetch.
|
||||
if (placement.pending.length > 0) void load();
|
||||
else applyDelta(applyMoveDelta(cacheSnapshot(), { move: e.move, game: e.game, bagLen: e.bagLen }));
|
||||
} else if (e.kind === 'your_turn' && e.gameId === id) {
|
||||
@@ -208,15 +208,15 @@
|
||||
let hoverKey = '';
|
||||
let hoverTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
// The empty board cell the dragged tile is currently aimed at, highlighted as a drop
|
||||
// target while carrying a tile over the board (Stage 17). Null over an occupied cell.
|
||||
// target while carrying a tile over the board. Null over an occupied cell.
|
||||
let dropTarget = $state<{ row: number; col: number } | null>(null);
|
||||
// Rack reordering (Stage 17): while a rack tile is dragged, reorderDragId is its stable id
|
||||
// Rack reordering: while a rack tile is dragged, reorderDragId is its stable id
|
||||
// (so the rack hides it — the ghost stands in) and reorderTo is the drop slot over the rack
|
||||
// (a gap opens there). Only when no tiles are pending, so the order is a clean permutation.
|
||||
let reorderDragId = $state<number | null>(null);
|
||||
let reorderTo = $state<number | null>(null);
|
||||
// While a placed (pending) board tile is dragged to relocate it, draggingPend is its cell —
|
||||
// hidden from the board (the ghost stands in) like a lifted rack tile (Stage 17).
|
||||
// hidden from the board (the ghost stands in) like a lifted rack tile.
|
||||
let draggingPend = $state<{ row: number; col: number } | null>(null);
|
||||
|
||||
let dragPointerId = -1;
|
||||
@@ -245,7 +245,7 @@
|
||||
drag = null;
|
||||
}
|
||||
function onRackDown(e: PointerEvent, index: number) {
|
||||
// Tiles may be arranged on the opponent's turn too (Stage 17 #5): only placement is
|
||||
// Tiles may be arranged on the opponent's turn too: only placement is
|
||||
// relaxed — the preview and Make-move stay your-turn-only, so an off-turn draft is
|
||||
// position-only (never scored or submitted).
|
||||
if (busy || gameOver) return;
|
||||
@@ -390,7 +390,7 @@
|
||||
window.removeEventListener('pointerdown', onExtraPointer);
|
||||
clearHover();
|
||||
clearReorder();
|
||||
// Flush a pending draft save so leaving mid-composition still persists it (Stage 17).
|
||||
// Flush a pending draft save so leaving mid-composition still persists it.
|
||||
if (draftSaveTimer) {
|
||||
clearTimeout(draftSaveTimer);
|
||||
void gateway.draftSave(id, serializeDraft(rackIds, placement.pending)).catch(() => {});
|
||||
@@ -401,7 +401,7 @@
|
||||
function onCell(row: number, col: number) {
|
||||
if (swallowClick) return;
|
||||
// A pending tile is recalled by a double-tap or by dragging it back to the rack, not
|
||||
// by a single tap (which recalled too easily — Stage 17).
|
||||
// by a single tap (which recalled too easily).
|
||||
if (pendingMap.has(`${row},${col}`)) return;
|
||||
if (selected != null) {
|
||||
// A committed tile already sits here: keep the rack selection so a stray tap
|
||||
@@ -418,7 +418,7 @@
|
||||
scheduleDraftSave();
|
||||
}
|
||||
// relocatePending moves a placed-but-unsubmitted tile from one board cell to another free one
|
||||
// (a board→board drag), keeping its rack slot and any blank letter (Stage 17).
|
||||
// (a board→board drag), keeping its rack slot and any blank letter.
|
||||
function relocatePending(fromRow: number, fromCol: number, toRow: number, toCol: number) {
|
||||
const pt = placement.pending.find((p) => p.row === fromRow && p.col === fromCol);
|
||||
if (!pt) return;
|
||||
@@ -459,7 +459,7 @@
|
||||
function recompute() {
|
||||
preview = null;
|
||||
if (previewTimer) clearTimeout(previewTimer);
|
||||
// Off-turn the composition is position-only: no score preview or evaluate (Stage 17 #5).
|
||||
// Off-turn the composition is position-only: no score preview or evaluate.
|
||||
if (!isMyTurn) return;
|
||||
const sub = toSubmit(placement, dirOverride);
|
||||
if (!sub) return;
|
||||
@@ -473,7 +473,7 @@
|
||||
}
|
||||
|
||||
// applyMoveResult renders the actor's own just-committed move from the response — the move, the
|
||||
// post-move game and the refilled rack — without a follow-up game.state + game.history (R4).
|
||||
// post-move game and the refilled rack — without a follow-up game.state + game.history.
|
||||
function applyMoveResult(r: MoveResult) {
|
||||
view = { game: r.game, seat: r.move.player, rack: r.rack, bagLen: r.bagLen, hintsRemaining: view?.hintsRemaining ?? 0 };
|
||||
moves = [...moves, r.move];
|
||||
@@ -613,7 +613,7 @@
|
||||
}
|
||||
|
||||
// Friend state for the in-game "add to friends" item, derived from the server so it is
|
||||
// correct across reloads and live-updates when a request is answered (Stage 17):
|
||||
// correct across reloads and live-updates when a request is answered:
|
||||
// `friends` are the caller's accepted friends; `requested` are the addressees already
|
||||
// requested (pending or declined — both block a re-send and read as "request sent").
|
||||
let friends = $state(new Set<string>());
|
||||
@@ -985,7 +985,7 @@
|
||||
min-width: 0;
|
||||
}
|
||||
/* A borderless icon button (like the tab bar), not a filled accent button — and disabled
|
||||
while the pending word is known to be illegal (Stage 17). */
|
||||
while the pending word is known to be illegal. */
|
||||
.make {
|
||||
min-width: 56px;
|
||||
background: none;
|
||||
@@ -1045,7 +1045,7 @@
|
||||
pointer-events: none;
|
||||
z-index: 60;
|
||||
}
|
||||
/* On touch the finger covers the tile, so enlarge the drag ghost ~1.5x (Stage 17). */
|
||||
/* On touch the finger covers the tile, so enlarge the drag ghost ~1.5x. */
|
||||
.ghost.touch {
|
||||
transform: translate(-50%, -50%) scale(1.5);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
selected: number | null;
|
||||
shuffling?: boolean;
|
||||
// While a rack tile is being dragged to reorder it, draggingId is its id (hidden here —
|
||||
// the drag ghost stands in) and dropIndex is the slot where a gap opens (Stage 17).
|
||||
// the drag ghost stands in) and dropIndex is the slot where a gap opens.
|
||||
draggingId?: number | null;
|
||||
dropIndex?: number | null;
|
||||
ondown: (e: PointerEvent, index: number) => void;
|
||||
@@ -93,7 +93,7 @@
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
/* iOS shows a tap/active highlight that can linger on the neighbour sliding into a
|
||||
dragged tile's slot (Stage 17); suppress it so only our own styles mark a tile. */
|
||||
dragged tile's slot; suppress it so only our own styles mark a tile. */
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.tile.selected {
|
||||
|
||||
Reference in New Issue
Block a user