diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte index 47859f0..25fd65f 100644 --- a/packages/web/src/App.svelte +++ b/packages/web/src/App.svelte @@ -938,6 +938,9 @@ clearSelection(); } + // Press-and-hold on a wall/door/fire segment (touch has no hover). + let peekEdge = $state(null); + // A shimmering illusion wall, tapped or bumped: offer the belief test. let illusionPrompt = $state<{ cell: { x: number; y: number }; side: Side } | null>(null); function illusionEdgeParts(key: string): { cell: { x: number; y: number }; side: Side } { @@ -1130,11 +1133,13 @@ {/if} - {#if peekCard || discardPeek || peekTreasure} + {#if peekCard || discardPeek || peekTreasure || peekEdge}
{ peekCard = null; peekCreatureId = null; peekToken = null; discardPeek = null; peekTreasure = null; }} onkeydown={() => {}}> + onclick={() => { peekCard = null; peekCreatureId = null; peekToken = null; discardPeek = null; peekTreasure = null; peekEdge = null; }} onkeydown={() => {}}>
- {#if peekTreasure} + {#if peekEdge} +
{peekEdge}
+ {:else if peekTreasure}
{peekTreasure.note}
{:else} @@ -1559,6 +1564,7 @@ onGhostClick={clickGhostSlot} onCellPeek={(c) => peekAt(c)} onIllusionClick={(cell, side) => (illusionPrompt = { cell, side })} + onEdgePeek={(tip) => (peekEdge = tip)} {litCells} {sightTrace} /> diff --git a/packages/web/src/Board.svelte b/packages/web/src/Board.svelte index 42e3df7..fb769fa 100644 --- a/packages/web/src/Board.svelte +++ b/packages/web/src/Board.svelte @@ -26,6 +26,7 @@ onWarpClick, onCellPeek, onIllusionClick, + onEdgePeek, markedCell = null, markedCells = null, litCells = null, @@ -47,6 +48,8 @@ onCellPeek?: (cell: { x: number; y: number }) => void; /** Tap on a shimmering (untested) illusion wall: offer the belief test. */ onIllusionClick?: (cell: { x: number; y: number }, side: Side) => void; + /** Press-and-hold a wall/door/fire segment: its tooltip, for touch. */ + onEdgePeek?: (tip: string) => void; /** First square of a two-square spell: marked so the click reads as taken. */ markedCell?: { x: number; y: number } | null; /** A multi-square placement in progress (boobytrap tokens), in click @@ -387,7 +390,7 @@ {#each edges as e (`${e.kind}:${e.x},${e.y}`)} {#if e.state === "firewall"} - + {:else} {@const lockTitle = e.lock === "removed" ? "lock removed — swings free" : e.lock === "jammed" ? "lock jammed — sealed for good" @@ -396,7 +399,8 @@ + title={lockTitle} damage={view.wallDamage[`${e.kind}:${e.x},${e.y}`] ?? 0} + onpeek={onEdgePeek} /> {/if} {/each} diff --git a/packages/web/src/EdgeGlyph.svelte b/packages/web/src/EdgeGlyph.svelte index a122d74..f3deacc 100644 --- a/packages/web/src/EdgeGlyph.svelte +++ b/packages/web/src/EdgeGlyph.svelte @@ -2,13 +2,15 @@ // A wall or door on an edge, exactly as the board draws it. Wall-segment // effects (locks picked, jammed, removed; doors held) are color states of // this one glyph — the game has never used tokens for them. - let { x, y, kind, state, lock = null, title = null, damage = 0 }: { + let { x, y, kind, state, lock = null, title = null, damage = 0, onpeek }: { x: number; y: number; kind: "V" | "H"; state: "wall" | "door"; lock?: "removed" | "jammed" | "held" | "ajar" | null; title?: string | null; /** Battle damage taken so far (walls fall at 20, doors at 15). */ damage?: number; + /** Press-and-hold (touch has no hover): report the tooltip's text. */ + onpeek?: (tip: string) => void; } = $props(); const CELL = 48; const WALL = 7; @@ -19,6 +21,17 @@ ? `${Math.max(0, needed - damage)} of ${needed} hitpoints left` : `${needed} hitpoints`); const tip = $derived(`${title ?? (state === "door" ? "a locked door" : "a wall")} — ${hp}`); + + // Press-and-hold peeks the segment, mirroring the board's cell gesture. + let timer: ReturnType | null = null; + function press() { + if (!onpeek) return; + timer = setTimeout(() => onpeek?.(tip), 450); + } + function release() { + if (timer) clearTimeout(timer); + timer = null; + } {#if kind === "V"} @@ -26,12 +39,14 @@ x={(x + 1) * CELL - WALL / 2} y={y * CELL - WALL / 2} width={WALL} height={CELL + WALL} class={cls} + role="img" onpointerdown={press} onpointerup={release} onpointerleave={release} >{tip} {:else} {tip} {/if} diff --git a/packages/web/src/FirewallEdge.svelte b/packages/web/src/FirewallEdge.svelte index f0ad391..0a713bc 100644 --- a/packages/web/src/FirewallEdge.svelte +++ b/packages/web/src/FirewallEdge.svelte @@ -2,7 +2,21 @@ // A standing WALL OF FIRE: board furniture, not a flourish — it burns for // as long as the spell holds, so the animation is pure CSS on a handful // of shapes (no turbulence filters; those are budgeted for one-shot fx). - let { x, y, kind }: { x: number; y: number; kind: "V" | "H" } = $props(); + let { x, y, kind, onpeek }: { + x: number; y: number; kind: "V" | "H"; + /** Press-and-hold (touch has no hover): report what this fire is. */ + onpeek?: (tip: string) => void; + } = $props(); + const TIP = "a wall of fire — passing through burns for 4"; + let peekTimer: ReturnType | null = null; + function press() { + if (!onpeek) return; + peekTimer = setTimeout(() => onpeek?.(TIP), 450); + } + function release() { + if (peekTimer) clearTimeout(peekTimer); + peekTimer = null; + } const uid = $props.id(); const CELL = 48; const WALL = 7; @@ -42,10 +56,12 @@ {#if kind === "V"} + fill={`url(#fw-bar-${uid})`} class="fw-bar" + role="img" onpointerdown={press} onpointerup={release} onpointerleave={release} /> {:else} + fill={`url(#fw-bar-${uid})`} class="fw-bar" + role="img" onpointerdown={press} onpointerup={release} onpointerleave={release} /> {/if} {#each TONGUES as f (f.t)}