Add placeholder page flow with localStorage-backed navigation

Four screens (Title, Player Setup, Score Sheet, Enter Scores) wired together
via a simple useState state machine. Auto-resumes to Score Sheet if a game
exists in localStorage under the key 'currentGame'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 20:02:59 -05:00
parent a09e8dac7f
commit 6f9a9bc5dc
6 changed files with 105 additions and 6 deletions
+49 -6
View File
@@ -1,7 +1,50 @@
export default function App() {
return (
<div>
<h1>Black 7</h1>
</div>
)
import { useState } from 'react'
import { type Page, type GameState } from './types'
import TitleScreen from './pages/TitleScreen'
import PlayerSetup from './pages/PlayerSetup'
import ScoreSheet from './pages/ScoreSheet'
import EnterScores from './pages/EnterScores'
const STORAGE_KEY = 'currentGame'
function loadGame(): GameState | null {
const raw = localStorage.getItem(STORAGE_KEY)
return raw ? (JSON.parse(raw) as GameState) : null
}
function saveGame(game: GameState) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(game))
}
function clearGame() {
localStorage.removeItem(STORAGE_KEY)
}
export default function App() {
const [page, setPage] = useState<Page>(() =>
loadGame() ? 'scoresheet' : 'title'
)
const [game, setGame] = useState<GameState | null>(() => loadGame())
function handleNewGame() {
clearGame()
setGame(null)
setPage('setup')
}
function handleStart() {
const newGame: GameState = { players: [], rounds: [] }
saveGame(newGame)
setGame(newGame)
setPage('scoresheet')
}
function handleSubmitScores() {
setPage('scoresheet')
}
if (page === 'title') return <TitleScreen onNewGame={handleNewGame} />
if (page === 'setup') return <PlayerSetup onStart={handleStart} />
if (page === 'scoresheet') return <ScoreSheet onScoreRound={() => setPage('enterscores')} onNewGame={handleNewGame} />
if (page === 'enterscores') return <EnterScores onSubmit={handleSubmitScores} />
}
+12
View File
@@ -0,0 +1,12 @@
interface Props {
onSubmit: () => void
}
export default function EnterScores({ onSubmit }: Props) {
return (
<div>
<h1>Enter Scores</h1>
<button onClick={onSubmit}>Submit</button>
</div>
)
}
+12
View File
@@ -0,0 +1,12 @@
interface Props {
onStart: () => void
}
export default function PlayerSetup({ onStart }: Props) {
return (
<div>
<h1>Player Setup</h1>
<button onClick={onStart}>Start</button>
</div>
)
}
+14
View File
@@ -0,0 +1,14 @@
interface Props {
onScoreRound: () => void
onNewGame: () => void
}
export default function ScoreSheet({ onScoreRound, onNewGame }: Props) {
return (
<div>
<h1>Score Sheet</h1>
<button onClick={onScoreRound}>Score Round</button>
<button onClick={onNewGame} style={{ fontSize: '0.75em' }}>New Game</button>
</div>
)
}
+12
View File
@@ -0,0 +1,12 @@
interface Props {
onNewGame: () => void
}
export default function TitleScreen({ onNewGame }: Props) {
return (
<div>
<h1>Black 7</h1>
<button onClick={onNewGame}>New Game</button>
</div>
)
}
+6
View File
@@ -0,0 +1,6 @@
export type Page = 'title' | 'setup' | 'scoresheet' | 'enterscores'
export interface GameState {
players: string[]
rounds: number[][] // rounds[i][j] = player j's score in round i
}