Fix a bunch of bugs.

This commit is contained in:
Greyson Parrelli
2026-07-24 09:51:25 -04:00
parent ceab30dc2e
commit 094f38593e
8 changed files with 308 additions and 79 deletions
+50
View File
@@ -1,7 +1,9 @@
import { useMemo, useState } from 'react'
import type { Dispatch, SetStateAction } from 'react'
import { createPortal } from 'react-dom'
import { useGame } from '../useGame'
import { useCatalog } from '../useCatalog'
import { CardView } from './CardView'
import type { Card, Session } from '../types'
import { Lobby } from './Lobby'
import { ShopPhase } from './ShopPhase'
@@ -33,6 +35,10 @@ export function Table({ session, onLeave }: { session: Session; onLeave: () => v
return { round: battleRound, step: next }
})
// A shop-phase peek at an opponent's deck from the previous round's battle
// (its arranged lineup is already public). Anchored under the clicked button.
const [deckPeek, setDeckPeek] = useState<{ seat: number; rect: DOMRect } | null>(null)
// The battle outcome is known before the replay plays out, so we hold its
// "result" log entry back: it's dropped from the persistent list during the
// battle and appended as the final battle line only once the replay reaches
@@ -145,6 +151,21 @@ export function Table({ session, onLeave }: { session: Session; onLeave: () => v
{view.phase === 'shop' && p.seat !== view.youSeat && (
<span className="chip">🪙 {p.coins}</span>
)}
{/* Peek at the opponent's deck from last round's battle. */}
{view.phase === 'shop' &&
p.seat !== view.youSeat &&
(view.battle?.lineups?.[p.seat]?.length ?? 0) > 0 && (
<button
className={`chip chip-btn ${deckPeek?.seat === p.seat ? 'is-active' : ''}`}
title="See their deck from last round's battle"
onClick={(e) => {
const rect = e.currentTarget.getBoundingClientRect()
setDeckPeek((cur) => (cur?.seat === p.seat ? null : { seat: p.seat, rect }))
}}
>
👁 deck
</button>
)}
{(p.avocados ?? 0) > 0 && (
<span className="chip" title="Set-aside Avocados">🥑 {p.avocados}</span>
)}
@@ -186,6 +207,35 @@ export function Table({ session, onLeave }: { session: Session; onLeave: () => v
{view.debug && (
<DebugPanel canGrant={view.phase === 'shop'} pack={view.pack} send={send} />
)}
{deckPeek &&
view.phase === 'shop' &&
(() => {
const lineup = view.battle?.lineups?.[deckPeek.seat] ?? []
if (!lineup.length) return null
const oppName = view.players.find((p) => p.seat === deckPeek.seat)?.name ?? 'Opponent'
const left = Math.max(8, Math.min(deckPeek.rect.left, window.innerWidth - 380))
return createPortal(
<>
<div className="deck-peek-backdrop" onClick={() => setDeckPeek(null)} />
<div
className="deck-peek deck-peek-toolbar"
style={{ top: deckPeek.rect.bottom + 8, left }}
>
<div className="deck-peek-label">
{oppName}s deck last round · {lineup.length} card
{lineup.length !== 1 ? 's' : ''} (top first)
</div>
<div className="deck-peek-cards">
{lineup.map((c, i) => (
<CardView key={c.id || i} card={c} size="sm" />
))}
</div>
</div>
</>,
document.body,
)
})()}
</div>
)
}