Skip to content

Commit b64b3e4

Browse files
feat: add Analysis Game List component to mobile devices + fix termination visualization for draws
1 parent 4ff558d commit b64b3e4

File tree

3 files changed

+184
-101
lines changed

3 files changed

+184
-101
lines changed

src/components/Analysis/AnalysisGameList.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export const AnalysisGameList: React.FC<AnalysisGameListProps> = ({
183183
})}
184184
</>
185185
)}
186-
<div className="flex flex-1 items-center justify-center gap-1 py-2">
186+
<div className="flex flex-1 items-start justify-center gap-1 py-2 md:items-center">
187187
<span className="material-symbols-outlined text-sm text-secondary">
188188
chess_pawn
189189
</span>
@@ -210,7 +210,7 @@ function Header({
210210
return (
211211
<button
212212
onClick={() => setSelected(name)}
213-
className={`relative flex items-center justify-center py-1 ${selected === name ? 'bg-human-4/30' : 'bg-background-1/80 hover:bg-background-2'} `}
213+
className={`relative flex items-center justify-center md:py-1 ${selected === name ? 'bg-human-4/30' : 'bg-background-1/80 hover:bg-background-2'} `}
214214
>
215215
<div className="flex items-center justify-start">
216216
<p

src/components/Misc/GameInfo.tsx

+25-8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ interface Props {
1111
currentMaiaModel?: string
1212
setCurrentMaiaModel?: (model: string) => void
1313
MAIA_MODELS?: string[]
14+
showGameListButton?: boolean
15+
onGameListClick?: () => void
1416
}
1517

1618
export const GameInfo: React.FC<Props> = ({
@@ -21,6 +23,8 @@ export const GameInfo: React.FC<Props> = ({
2123
currentMaiaModel,
2224
setCurrentMaiaModel,
2325
MAIA_MODELS,
26+
showGameListButton,
27+
onGameListClick,
2428
}: Props) => {
2529
const { setInstructionsModalProps } = useContext(ModalContext)
2630

@@ -52,14 +56,27 @@ export const GameInfo: React.FC<Props> = ({
5256
</p>
5357
)}
5458
</div>
55-
<button
56-
className="material-symbols-outlined duration-200 hover:text-human-3"
57-
onClick={() => {
58-
setInstructionsModalProps({ instructionsType: type })
59-
}}
60-
>
61-
help
62-
</button>
59+
<div className="flex items-center gap-2">
60+
{showGameListButton && (
61+
<button
62+
className="flex items-center gap-1 rounded bg-human-4/30 px-2 py-1 text-sm text-human-2 duration-200 hover:bg-human-4/50 md:hidden"
63+
onClick={onGameListClick}
64+
>
65+
<span className="material-symbols-outlined text-sm">
66+
format_list_bulleted
67+
</span>
68+
<span>Switch Game</span>
69+
</button>
70+
)}
71+
<button
72+
className="material-symbols-outlined duration-200 hover:text-human-3"
73+
onClick={() => {
74+
setInstructionsModalProps({ instructionsType: type })
75+
}}
76+
>
77+
help
78+
</button>
79+
</div>
6380
</div>
6481
<div className="flex w-full flex-col">{children}</div>
6582
</div>

src/pages/analysis/[...id].tsx

+157-91
Original file line numberDiff line numberDiff line change
@@ -459,45 +459,48 @@ const Analysis: React.FC<Props> = ({
459459
),
460460
)}
461461
</div>
462-
<div className="flex w-full items-center justify-between text-sm opacity-80 md:hidden">
463-
<div className="flex items-center gap-1.5">
462+
<div className="flex w-full items-center justify-between text-xs md:hidden">
463+
<div className="flex items-center gap-1">
464464
<div className="h-2 w-2 rounded-full bg-white" />
465465
<span className="font-medium">{analyzedGame.whitePlayer.name}</span>
466466
{analyzedGame.whitePlayer.rating && (
467-
<span className="text-primary/70">
467+
<span className="text-primary/60">
468468
({analyzedGame.whitePlayer.rating})
469469
</span>
470470
)}
471471
</div>
472-
<div className="flex items-center gap-1.5">
473-
<span
474-
className={
475-
analyzedGame.termination.winner === 'white'
476-
? 'font-medium text-engine-3'
477-
: 'text-primary/70'
478-
}
479-
>
480-
{analyzedGame.termination.winner === 'white' ? '1' : '0'}
481-
</span>
482-
<span className="text-primary/70">-</span>
483-
<span
484-
className={
485-
analyzedGame.termination.winner === 'black'
486-
? 'font-medium text-engine-3'
487-
: 'text-primary/70'
488-
}
489-
>
490-
{analyzedGame.termination.winner === 'black' ? '1' : '0'}
491-
</span>
492-
{analyzedGame.termination.winner === 'none' && (
493-
<span className="font-medium text-primary/70">½-½</span>
472+
<div className="flex items-center gap-1">
473+
{analyzedGame.termination.winner === 'none' ? (
474+
<span className="font-medium text-primary/80">½-½</span>
475+
) : (
476+
<span className="font-medium">
477+
<span
478+
className={
479+
analyzedGame.termination.winner === 'white'
480+
? 'text-engine-3'
481+
: 'text-primary/70'
482+
}
483+
>
484+
{analyzedGame.termination.winner === 'white' ? '1' : '0'}
485+
</span>
486+
<span className="text-primary/70">-</span>
487+
<span
488+
className={
489+
analyzedGame.termination.winner === 'black'
490+
? 'text-engine-3'
491+
: 'text-primary/70'
492+
}
493+
>
494+
{analyzedGame.termination.winner === 'black' ? '1' : '0'}
495+
</span>
496+
</span>
494497
)}
495498
</div>
496-
<div className="flex items-center gap-1.5">
499+
<div className="flex items-center gap-1">
497500
<div className="h-2 w-2 rounded-full border-[0.5px] bg-black" />
498501
<span className="font-medium">{analyzedGame.blackPlayer.name}</span>
499502
{analyzedGame.blackPlayer.rating && (
500-
<span className="text-primary/70">
503+
<span className="text-primary/60">
501504
({analyzedGame.blackPlayer.rating})
502505
</span>
503506
)}
@@ -519,9 +522,15 @@ const Analysis: React.FC<Props> = ({
519522
<div className="flex max-h-[25vh] min-h-[25vh] flex-col bg-backdrop/30">
520523
<AnalysisGameList
521524
currentId={currentId}
522-
loadNewTournamentGame={getAndSetTournamentGame}
523-
loadNewLichessGames={getAndSetLichessGames}
524-
loadNewUserGames={getAndSetUserGames}
525+
loadNewTournamentGame={(newId, setCurrentMove) =>
526+
getAndSetTournamentGame(newId, setCurrentMove)
527+
}
528+
loadNewLichessGames={(id, pgn, setCurrentMove) =>
529+
getAndSetLichessGames(id, pgn, setCurrentMove)
530+
}
531+
loadNewUserGames={(id, type, setCurrentMove) =>
532+
getAndSetUserGames(id, type, setCurrentMove)
533+
}
525534
/>
526535
</div>
527536
<div className="flex h-1/2 w-full flex-1 flex-col gap-2">
@@ -625,82 +634,139 @@ const Analysis: React.FC<Props> = ({
625634
</div>
626635
)
627636

637+
const [showGameListMobile, setShowGameListMobile] = useState(false)
638+
628639
const mobileLayout = (
629640
<>
630641
<div className="flex h-full flex-1 flex-col justify-center gap-1">
631-
<div className="flex w-full flex-col items-start justify-start gap-1">
632-
<GameInfo
633-
title="Analysis"
634-
icon="bar_chart"
635-
type="analysis"
636-
currentMaiaModel={currentMaiaModel}
637-
setCurrentMaiaModel={setCurrentMaiaModel}
638-
MAIA_MODELS={MAIA_MODELS}
639-
>
640-
<NestedGameInfo />
641-
</GameInfo>
642-
<div className="relative flex h-[100vw] w-screen">
643-
<AnalysisGameBoard
644-
game={analyzedGame}
645-
moves={moves}
646-
setCurrentSquare={setCurrentSquare}
647-
shapes={hoverArrow ? [...arrows, hoverArrow] : [...arrows]}
648-
currentNode={controller.currentNode as GameNode}
649-
orientation={controller.orientation}
650-
goToNode={controller.goToNode}
651-
/>
652-
</div>
653-
<div className="flex w-full flex-col gap-0">
654-
<div className="w-full !flex-grow-0">
655-
<AnalysisBoardController />
642+
{showGameListMobile ? (
643+
<div className="flex w-full flex-col items-start justify-start gap-1">
644+
<div className="flex w-full flex-col items-start justify-start overflow-hidden bg-background-1 p-3">
645+
<div className="flex w-full items-center justify-between">
646+
<div className="flex items-center justify-start gap-1.5">
647+
<span className="material-symbols-outlined text-xl">
648+
format_list_bulleted
649+
</span>
650+
<h2 className="text-xl font-semibold">Switch Game</h2>
651+
</div>
652+
<button
653+
className="flex items-center gap-1 rounded bg-background-2 px-2 py-1 text-sm duration-200 hover:bg-background-3"
654+
onClick={() => setShowGameListMobile(false)}
655+
>
656+
<span className="material-symbols-outlined text-sm">
657+
arrow_back
658+
</span>
659+
<span>Back to Analysis</span>
660+
</button>
661+
</div>
662+
<p className="mt-1 text-sm text-secondary">
663+
Select a game to analyze
664+
</p>
656665
</div>
657-
<div className="relative bottom-0 h-48 max-h-48 flex-1 overflow-auto overflow-y-hidden">
658-
<AnalysisMovesContainer
659-
game={analyzedGame}
660-
termination={analyzedGame.termination}
666+
<div className="flex h-[calc(100vh-10rem)] w-full flex-col overflow-hidden rounded bg-backdrop/30">
667+
<AnalysisGameList
668+
currentId={currentId}
669+
loadNewTournamentGame={(newId, setCurrentMove) =>
670+
loadGameAndCloseList(
671+
getAndSetTournamentGame(newId, setCurrentMove),
672+
)
673+
}
674+
loadNewLichessGames={(id, pgn, setCurrentMove) =>
675+
loadGameAndCloseList(
676+
getAndSetLichessGames(id, pgn, setCurrentMove),
677+
)
678+
}
679+
loadNewUserGames={(id, type, setCurrentMove) =>
680+
loadGameAndCloseList(
681+
getAndSetUserGames(id, type, setCurrentMove),
682+
)
683+
}
661684
/>
662685
</div>
663686
</div>
664-
<div className="flex w-full flex-col gap-1 overflow-hidden">
665-
<BlunderMeter
666-
hover={hover}
667-
makeMove={makeMove}
668-
data={blunderMeter}
669-
colorSanMapping={colorSanMapping}
670-
/>
671-
<Highlight
672-
hover={hover}
673-
makeMove={makeMove}
687+
) : (
688+
<div className="flex w-full flex-col items-start justify-start gap-1">
689+
<GameInfo
690+
title="Analysis"
691+
icon="bar_chart"
692+
type="analysis"
674693
currentMaiaModel={currentMaiaModel}
675-
recommendations={moveRecommendations}
676-
moveEvaluation={
677-
moveEvaluation as {
678-
maia?: MaiaEvaluation
679-
stockfish?: StockfishEvaluation
694+
setCurrentMaiaModel={setCurrentMaiaModel}
695+
MAIA_MODELS={MAIA_MODELS}
696+
onGameListClick={() => setShowGameListMobile(true)}
697+
showGameListButton={true}
698+
>
699+
<NestedGameInfo />
700+
</GameInfo>
701+
<div className="relative flex h-[100vw] w-screen">
702+
<AnalysisGameBoard
703+
game={analyzedGame}
704+
moves={moves}
705+
setCurrentSquare={setCurrentSquare}
706+
shapes={hoverArrow ? [...arrows, hoverArrow] : [...arrows]}
707+
currentNode={controller.currentNode as GameNode}
708+
orientation={controller.orientation}
709+
goToNode={controller.goToNode}
710+
/>
711+
</div>
712+
<div className="flex w-full flex-col gap-0">
713+
<div className="w-full !flex-grow-0">
714+
<AnalysisBoardController />
715+
</div>
716+
<div className="relative bottom-0 h-48 max-h-48 flex-1 overflow-auto overflow-y-hidden">
717+
<AnalysisMovesContainer
718+
game={analyzedGame}
719+
termination={analyzedGame.termination}
720+
/>
721+
</div>
722+
</div>
723+
<div className="flex w-full flex-col gap-1 overflow-hidden">
724+
<BlunderMeter
725+
hover={hover}
726+
makeMove={makeMove}
727+
data={blunderMeter}
728+
colorSanMapping={colorSanMapping}
729+
/>
730+
<Highlight
731+
hover={hover}
732+
makeMove={makeMove}
733+
currentMaiaModel={currentMaiaModel}
734+
recommendations={moveRecommendations}
735+
moveEvaluation={
736+
moveEvaluation as {
737+
maia?: MaiaEvaluation
738+
stockfish?: StockfishEvaluation
739+
}
680740
}
681-
}
682-
movesByRating={movesByRating}
683-
colorSanMapping={colorSanMapping}
684-
/>
685-
<MoveMap
686-
moveMap={moveMap}
687-
colorSanMapping={colorSanMapping}
688-
setHoverArrow={setHoverArrow}
741+
movesByRating={movesByRating}
742+
colorSanMapping={colorSanMapping}
743+
/>
744+
<MoveMap
745+
moveMap={moveMap}
746+
colorSanMapping={colorSanMapping}
747+
setHoverArrow={setHoverArrow}
748+
/>
749+
</div>
750+
<ConfigurableScreens
751+
currentMaiaModel={currentMaiaModel}
752+
setCurrentMaiaModel={setCurrentMaiaModel}
753+
launchContinue={launchContinue}
754+
MAIA_MODELS={MAIA_MODELS}
755+
game={analyzedGame}
756+
currentNode={controller.currentNode as GameNode}
689757
/>
690758
</div>
691-
<ConfigurableScreens
692-
currentMaiaModel={currentMaiaModel}
693-
setCurrentMaiaModel={setCurrentMaiaModel}
694-
launchContinue={launchContinue}
695-
MAIA_MODELS={MAIA_MODELS}
696-
game={analyzedGame}
697-
currentNode={controller.currentNode as GameNode}
698-
/>
699-
</div>
759+
)}
700760
</div>
701761
</>
702762
)
703763

764+
// Helper function to load a game and close the game list
765+
const loadGameAndCloseList = async (loadFunction: Promise<void>) => {
766+
await loadFunction
767+
setShowGameListMobile(false)
768+
}
769+
704770
return (
705771
<>
706772
<Head>

0 commit comments

Comments
 (0)