Add game-over state and pre-populate names on new game
Highlights the winning player's column in green when the game ends, changes the footer button to "New Game" (reusing the existing confirm dialog), and pre-populates player names from the previous game when starting a new one. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+3
-1
@@ -23,8 +23,10 @@ function clearGame() {
|
||||
export default function App() {
|
||||
const [game, setGame] = useState<GameState | null>(loadGame)
|
||||
const [page, setPage] = useState<Page>(() => (game ? 'scoresheet' : 'title'))
|
||||
const [previousPlayers, setPreviousPlayers] = useState<string[] | undefined>(undefined)
|
||||
|
||||
function handleNewGame() {
|
||||
setPreviousPlayers(game?.players)
|
||||
clearGame()
|
||||
setGame(null)
|
||||
setPage('setup')
|
||||
@@ -45,7 +47,7 @@ export default function App() {
|
||||
}
|
||||
|
||||
if (page === 'title') return <TitleScreen onNewGame={handleNewGame} />
|
||||
if (page === 'setup') return <PlayerSetup onStart={handleStart} />
|
||||
if (page === 'setup') return <PlayerSetup onStart={handleStart} initialNames={previousPlayers} />
|
||||
if (page === 'scoresheet') return <ScoreSheet game={game!} onScoreRound={() => setPage('enterscores')} onNewGame={handleNewGame} />
|
||||
if (page === 'enterscores') return <EnterScores game={game!} onSubmit={handleSubmitScores} />
|
||||
}
|
||||
|
||||
@@ -5,14 +5,15 @@ import styles from './PlayerSetup.module.css'
|
||||
|
||||
interface Props {
|
||||
onStart: (players: string[]) => void
|
||||
initialNames?: string[]
|
||||
}
|
||||
|
||||
function normalize(s: string) {
|
||||
return s.trim().replace(/\s+/g, ' ')
|
||||
}
|
||||
|
||||
export default function PlayerSetup({ onStart }: Props) {
|
||||
const [names, setNames] = useState<string[]>(['', '', ''])
|
||||
export default function PlayerSetup({ onStart, initialNames }: Props) {
|
||||
const [names, setNames] = useState<string[]>(initialNames ?? ['', '', ''])
|
||||
|
||||
function updateName(i: number, value: string) {
|
||||
setNames(n => n.map((v, idx) => (idx === i ? value : v)))
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
border-top: 1px solid var(--color-parchment-border);
|
||||
}
|
||||
|
||||
.winnerCell {
|
||||
background: rgba(74, 158, 106, 0.15);
|
||||
}
|
||||
|
||||
/* Small red "New Game" button in header top-right */
|
||||
.newGameBtn {
|
||||
background: #d94f4f;
|
||||
|
||||
@@ -16,6 +16,8 @@ export default function ScoreSheet({ game, onScoreRound, onNewGame }: Props) {
|
||||
|
||||
const totals = computeRunningTotals(game.rounds)
|
||||
const gameOver = isGameOver(totals)
|
||||
const lastTotals = totals[totals.length - 1] ?? []
|
||||
const winnerIndex = gameOver ? lastTotals.indexOf(Math.max(...lastTotals)) : -1
|
||||
|
||||
const newGameButton = (
|
||||
<button className={styles.newGameBtn} onClick={() => setConfirmingNewGame(true)}>
|
||||
@@ -42,7 +44,11 @@ export default function ScoreSheet({ game, onScoreRound, onNewGame }: Props) {
|
||||
title="Score Sheet"
|
||||
headerAction={newGameButton}
|
||||
overlay={confirmingNewGame ? confirmOverlay : undefined}
|
||||
footer={<PrimaryButton onClick={onScoreRound} disabled={gameOver}>Score Round</PrimaryButton>}
|
||||
footer={
|
||||
<PrimaryButton onClick={gameOver ? () => setConfirmingNewGame(true) : onScoreRound}>
|
||||
{gameOver ? 'New Game' : 'Score Round'}
|
||||
</PrimaryButton>
|
||||
}
|
||||
>
|
||||
<div className={styles.tableWrapper}>
|
||||
<div
|
||||
@@ -51,21 +57,21 @@ export default function ScoreSheet({ game, onScoreRound, onNewGame }: Props) {
|
||||
>
|
||||
<div className={styles.labelCell} />
|
||||
{game.players.map((name, j) => (
|
||||
<div key={j} className={styles.headerCell}>{name}</div>
|
||||
<div key={j} className={styles.headerCell + (j === winnerIndex ? ' ' + styles.winnerCell : '')}>{name}</div>
|
||||
))}
|
||||
|
||||
{game.rounds.map((roundScores, i) => (
|
||||
<Fragment key={i}>
|
||||
<div className={styles.labelCell}>Round {i + 1}</div>
|
||||
{roundScores.map((score, j) => (
|
||||
<div key={j} className={styles.scoreCell}>{score}</div>
|
||||
<div key={j} className={styles.scoreCell + (j === winnerIndex ? ' ' + styles.winnerCell : '')}>{score}</div>
|
||||
))}
|
||||
|
||||
{i > 0 && (
|
||||
<>
|
||||
<div className={`${styles.labelCell} ${styles.divider}`} />
|
||||
{totals[i].map((total, j) => (
|
||||
<div key={j} className={`${styles.totalCell} ${styles.divider}`}>{total}</div>
|
||||
<div key={j} className={styles.totalCell + ' ' + styles.divider + (j === winnerIndex ? ' ' + styles.winnerCell : '')}>{total}</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user