Skip to content

Commit 2cdb05c

Browse files
Merge pull request #280 from CSSLab/codex/broadcast-analysis-match-new-layout
Add candidates challenge hub
2 parents 44b3d4c + c126b14 commit 2cdb05c

11 files changed

Lines changed: 961 additions & 41 deletions

File tree

src/components/Common/Header.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export const Header: React.FC = () => {
148148
/>
149149
<h2 className="text-2xl font-bold">Maia Chess</h2>
150150
</Link>
151-
<div className="hidden flex-row gap-1 text-sm tracking-wider md:flex">
151+
<div className="hidden flex-row items-center gap-1 text-sm tracking-wider md:flex">
152152
<div
153153
className="relative"
154154
onMouseEnter={() => setShowPlayDropdown(true)}
@@ -233,6 +233,16 @@ export const Header: React.FC = () => {
233233
BROADCASTS
234234
</Link>
235235
)}
236+
<Link
237+
href="/candidates"
238+
className={`inline-flex h-[30px] items-center rounded-full border px-3 transition-all duration-200 ${
239+
router.pathname.startsWith('/candidates')
240+
? 'bg-rose-500/14 border-rose-300/45 !text-rose-100'
241+
: 'border-rose-300/25 bg-rose-500/10 !text-rose-200/90 hover:border-rose-200/40 hover:!text-rose-100'
242+
}`}
243+
>
244+
CANDIDATES
245+
</Link>
236246
<div
237247
className="relative"
238248
onMouseEnter={() => setShowMoreDropdown(true)}
@@ -415,6 +425,16 @@ export const Header: React.FC = () => {
415425
<Link href="/broadcast" className="uppercase">
416426
Broadcasts
417427
</Link>
428+
<Link
429+
href="/candidates"
430+
className={`rounded-full border px-4 py-2 uppercase ${
431+
router.pathname.startsWith('/candidates')
432+
? 'bg-rose-500/14 border-rose-300/45 text-rose-100'
433+
: 'border-rose-300/25 bg-rose-500/10 text-rose-200/90'
434+
}`}
435+
>
436+
Candidates
437+
</Link>
418438
<Link href="/leaderboard" className="uppercase">
419439
Leaderboard
420440
</Link>

src/components/Common/PlaySetupModal.tsx

Lines changed: 96 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,35 @@ interface Props {
8282
sampleMoves?: boolean
8383
simulateMaiaTime?: boolean
8484
startFen?: string
85+
returnTo?: string
86+
challengeId?: string
87+
forcedPlayerColor?: Color
88+
modalTitle?: string
89+
modalSubtitle?: string
8590
}
8691

8792
export const PlaySetupModal: React.FC<Props> = (props: Props) => {
8893
const { setPlaySetupModalProps } = useContext(ModalContext)
89-
const { push } = useRouter()
94+
const router = useRouter()
95+
const { push } = router
96+
97+
const dismissModal = useCallback(() => {
98+
setPlaySetupModalProps(undefined)
99+
100+
if (
101+
props.returnTo &&
102+
router.pathname === '/play' &&
103+
router.asPath !== props.returnTo
104+
) {
105+
push(props.returnTo)
106+
}
107+
}, [
108+
props.returnTo,
109+
push,
110+
router.asPath,
111+
router.pathname,
112+
setPlaySetupModalProps,
113+
])
90114

91115
const [timeControl, setTimeControl] = useState<TimeControl>(
92116
props.timeControl || TimeControlOptions[0],
@@ -118,9 +142,22 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
118142
const [fen, setFen] = useState<string | undefined>(
119143
props.startFen ? props.startFen : undefined,
120144
)
145+
const forcedPlayerColor = props.forcedPlayerColor
146+
const colorSelectionLocked = forcedPlayerColor !== undefined
147+
const positionLocked = forcedPlayerColor !== undefined
121148

122149
const [openMoreOptions, setMoreOptionsOpen] = useState<boolean>(true)
123150
const compactHandBrainLayout = props.playType === 'handAndBrain'
151+
const modalTitle =
152+
props.modalTitle ||
153+
(props.playType == 'againstMaia'
154+
? 'Play Against Maia'
155+
: 'Play Hand and Brain')
156+
const modalSubtitle =
157+
props.modalSubtitle ||
158+
(props.playType == 'againstMaia'
159+
? 'Configure your game settings and choose your side'
160+
: 'Team up with Maia in Hand and Brain chess')
124161

125162
const handlePresetSelect = useCallback((preset: TimeControl) => {
126163
setTimeControl(preset)
@@ -156,7 +193,16 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
156193

157194
const start = useCallback(
158195
(color: Color | undefined) => {
196+
if (
197+
forcedPlayerColor &&
198+
color !== undefined &&
199+
color !== forcedPlayerColor
200+
) {
201+
return
202+
}
203+
159204
const player = color ?? ['white', 'black'][Math.floor(Math.random() * 2)]
205+
const resolvedPlayer = forcedPlayerColor ?? player
160206

161207
if (fen && !new Chess().validateFen(fen).valid) {
162208
toast.error('Invalid Starting FEN provided')
@@ -169,20 +215,25 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
169215
push({
170216
pathname: '/play/maia',
171217
query: {
172-
player: player,
218+
player: resolvedPlayer,
173219
//maiaPartnerVersion: maiaPartnerVersion,
174220
maiaVersion: maiaVersion,
175221
timeControl: timeControl,
176222
sampleMoves: sampleMoves,
177223
simulateMaiaTime: simulateMaiaTime,
178224
startFen: fen,
225+
returnTo: props.returnTo,
226+
challengeId: props.challengeId,
227+
forcedColor: forcedPlayerColor,
228+
modalTitle: props.modalTitle,
229+
modalSubtitle: props.modalSubtitle,
179230
},
180231
})
181232
} else {
182233
push({
183234
pathname: '/play/hb',
184235
query: {
185-
player: player,
236+
player: resolvedPlayer,
186237
maiaPartnerVersion: maiaPartnerVersion,
187238
maiaVersion: maiaVersion,
188239
timeControl: timeControl,
@@ -204,13 +255,18 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
204255
sampleMoves,
205256
simulateMaiaTime,
206257
fen,
258+
forcedPlayerColor,
207259
isBrain,
260+
props.challengeId,
261+
props.modalSubtitle,
262+
props.modalTitle,
263+
props.returnTo,
208264
],
209265
)
210266

211267
return (
212268
<AnimatePresence>
213-
<ModalContainer dismiss={() => setPlaySetupModalProps(undefined)}>
269+
<ModalContainer dismiss={dismissModal}>
214270
<motion.div
215271
initial={{ opacity: 0 }}
216272
animate={{ opacity: 1 }}
@@ -231,7 +287,7 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
231287
<button
232288
className="absolute right-4 top-4 z-10 text-secondary transition-colors hover:text-primary"
233289
title="Close"
234-
onClick={() => setPlaySetupModalProps(undefined)}
290+
onClick={dismissModal}
235291
>
236292
<span className="material-symbols-outlined">close</span>
237293
</button>
@@ -242,16 +298,8 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
242298
compactHandBrainLayout ? 'px-4 py-3' : 'p-4'
243299
}`}
244300
>
245-
<h2 className="text-xl font-bold text-primary">
246-
{props.playType == 'againstMaia'
247-
? 'Play Against Maia'
248-
: 'Play Hand and Brain'}
249-
</h2>
250-
<p className="text-xs text-secondary">
251-
{props.playType == 'againstMaia'
252-
? 'Configure your game settings and choose your side'
253-
: 'Team up with Maia in Hand and Brain chess'}
254-
</p>
301+
<h2 className="text-xl font-bold text-primary">{modalTitle}</h2>
302+
<p className="text-xs text-secondary">{modalSubtitle}</p>
255303
</div>
256304

257305
{/* Settings Section */}
@@ -484,11 +532,18 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
484532
type="text"
485533
value={fen}
486534
placeholder="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
535+
readOnly={positionLocked}
487536
onChange={(e) => setFen(e.target.value)}
488-
className="w-full rounded border border-glass-border bg-glass px-3 py-2 font-mono text-xs text-white/90 placeholder-white/60 focus:outline-none"
537+
className={`w-full rounded border border-glass-border px-3 py-2 font-mono text-xs placeholder-white/60 focus:outline-none ${
538+
positionLocked
539+
? 'bg-glass text-white/90'
540+
: 'bg-glass text-white/90'
541+
}`}
489542
/>
490543
<p className="mt-1 text-xs text-secondary">
491-
Enter a valid FEN string to start from a specific position
544+
{positionLocked
545+
? 'This challenge uses a fixed starting position.'
546+
: 'Enter a valid FEN string to start from a specific position'}
492547
</p>
493548
</div>
494549
)}
@@ -508,11 +563,22 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
508563
>
509564
Choose your color:
510565
</p>
566+
{colorSelectionLocked ? (
567+
<p className="mb-3 text-center text-xs text-secondary">
568+
This challenge starts with{' '}
569+
{forcedPlayerColor === 'white' ? 'White' : 'Black'} to move.
570+
</p>
571+
) : null}
511572
<div className="flex items-center justify-center gap-4">
512573
<button
513574
onClick={() => start('black')}
514575
title="Play as black"
515-
className="flex h-16 w-16 cursor-pointer items-center justify-center rounded border border-glass-border bg-glass transition-colors hover:bg-glass-stronger"
576+
disabled={colorSelectionLocked && forcedPlayerColor !== 'black'}
577+
className={`flex h-16 w-16 items-center justify-center rounded border border-glass-border transition-colors ${
578+
colorSelectionLocked && forcedPlayerColor !== 'black'
579+
? 'cursor-not-allowed bg-glass/40 opacity-40'
580+
: 'cursor-pointer bg-glass hover:bg-glass-stronger'
581+
}`}
516582
>
517583
<div className="relative h-10 w-10">
518584
<Image
@@ -525,7 +591,12 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
525591
<button
526592
onClick={() => start(undefined)}
527593
title="Play as random color"
528-
className="flex h-20 w-20 cursor-pointer items-center justify-center rounded border border-glass-border bg-glass transition-colors hover:bg-glass-stronger"
594+
disabled={colorSelectionLocked}
595+
className={`flex h-20 w-20 items-center justify-center rounded border border-glass-border transition-colors ${
596+
colorSelectionLocked
597+
? 'cursor-not-allowed bg-glass/40 opacity-40'
598+
: 'cursor-pointer bg-glass hover:bg-glass-stronger'
599+
}`}
529600
>
530601
<div className="relative h-12 w-12">
531602
<Image
@@ -538,7 +609,12 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
538609
<button
539610
onClick={() => start('white')}
540611
title="Play as white"
541-
className="flex h-16 w-16 cursor-pointer items-center justify-center rounded border border-glass-border bg-glass transition-colors hover:bg-glass-stronger"
612+
disabled={colorSelectionLocked && forcedPlayerColor !== 'white'}
613+
className={`flex h-16 w-16 items-center justify-center rounded border border-glass-border transition-colors ${
614+
colorSelectionLocked && forcedPlayerColor !== 'white'
615+
? 'cursor-not-allowed bg-glass/40 opacity-40'
616+
: 'cursor-pointer bg-glass hover:bg-glass-stronger'
617+
}`}
542618
>
543619
<div className="relative h-10 w-10">
544620
<Image

0 commit comments

Comments
 (0)