Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/constants/candidates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,51 @@ export const CANDIDATES_EXTRA_IDEAS: CandidateIdea[] = [

// Drop live tournament moments here as PGN or FEN during the event.
export const CANDIDATES_FEATURED_POSITIONS: CandidatePosition[] = [
{
id: 'rd8-hikaru-technique',
title: "Rd8 Challenge 1: Hikaru's Technique",
subtitle:
'Fabi blundered and it became "a matter of technique" for Hikaru to convert. Can you finish the job? (Nakamura—Caruana)',
summary:
'Hikaru has a winning rook ending. White to move and convert cleanly.',
tag: 'Featured',
accent: 'red',
fen: '7k/R5R1/2p2p2/p6p/2P1P3/7P/r4rP1/6K1 w - - 1 33',
playerColor: 'white',
maiaVersion: 'maia_kdd_1900',
targetMoveNumber: 8,
},
{
id: 'rd8-press-like-lagno',
title: 'Rd8 Challenge 2: Press like Lagno',
subtitle:
"Black didn't take on e5 when she could have. Try to press the advantage with White. (Lagno—Goryachkina)",
summary:
'White has the initiative after Black declined a central capture. Keep pressing and convert the edge.',
tag: 'Featured',
accent: 'amber',
fen: 'r3r1k1/p1pp2bp/bnp3p1/2q1Pp2/2P5/1P4P1/P1QN1PBP/R1B1R1K1 w - f6 0 16',
playerColor: 'white',
maiaVersion: 'maia_kdd_1800',
targetMoveNumber: 8,
},
{
id: 'rd8-knights-over-bishops',
title: 'Rd8 Challenge 3: Knights over Bishops',
subtitle:
'Black has two knights and an extra pawn versus two bishops. Use them to win like Zhu did! (Tan–Zhu)',
summary:
'A complex minor-piece ending with Black pressing. Coordinate the knights and convert.',
tag: 'Featured',
accent: 'blue',
fen: '1r6/4k1p1/1pR1np2/p3p2P/P3B1n1/6B1/1P6/5K2 b - - 3 50',
playerColor: 'black',
maiaVersion: 'maia_kdd_1900',
targetMoveNumber: 8,
},
]

export const CANDIDATES_ROUND_FOUR_POSITIONS: CandidatePosition[] = [
{
id: 'rd4-sindarov-breakthrough',
title: "Rd4 Challenge 1: Sindarov's Breakthrough",
Expand Down
46 changes: 40 additions & 6 deletions src/pages/candidates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useEffect, useMemo, useState } from 'react'

import {
CANDIDATES_FEATURED_POSITIONS,
CANDIDATES_ROUND_FOUR_POSITIONS,
CANDIDATES_ROUND_THREE_POSITIONS,
CANDIDATES_ROUND_TWO_POSITIONS,
CANDIDATES_WARMUP_POSITIONS,
Expand Down Expand Up @@ -63,6 +64,9 @@ const ChallengeSectionTitle: React.FC<{ title: string }> = ({ title }) => (
</div>
)

const shouldCompactTitles = (positions: CandidatePosition[]) =>
positions.every((position) => position.title.length <= 38)

const PositionBoard: React.FC<{
position: CandidatePosition
completed?: boolean
Expand Down Expand Up @@ -136,14 +140,14 @@ const PositionPill: React.FC<{
<div className="flex h-full flex-col gap-4">
<div
className={`min-w-0 ${
compactTitle ? 'xl:min-h-[132px]' : 'xl:min-h-[150px]'
compactTitle ? 'xl:min-h-[122px]' : 'xl:min-h-[150px]'
}`}
>
<h2
className={`overflow-hidden text-lg font-semibold text-primary md:text-xl ${
className={`text-lg font-semibold leading-[1.5rem] text-primary md:text-xl md:leading-[1.75rem] ${
compactTitle
? 'h-[1.5rem] leading-[1.5rem] md:h-[1.75rem] md:leading-[1.75rem]'
: 'h-[3rem] leading-[1.5rem] md:h-[3.5rem] md:leading-[1.75rem]'
? 'xl:h-[1.75rem]'
: 'xl:h-[3.5rem] xl:overflow-hidden'
}`}
>
{position.title}
Expand Down Expand Up @@ -203,6 +207,19 @@ export default function CandidatesPage() {
const [completedChallengeIds, setCompletedChallengeIds] = useState<string[]>(
[],
)
const compactFeaturedTitles = shouldCompactTitles(
CANDIDATES_FEATURED_POSITIONS,
)
const compactRoundFourTitles = shouldCompactTitles(
CANDIDATES_ROUND_FOUR_POSITIONS,
)
const compactRoundThreeTitles = shouldCompactTitles(
CANDIDATES_ROUND_THREE_POSITIONS,
)
const compactRoundTwoTitles = shouldCompactTitles(
CANDIDATES_ROUND_TWO_POSITIONS,
)
const compactRoundOneTitles = shouldCompactTitles(CANDIDATES_WARMUP_POSITIONS)
const completedChallengeId =
typeof router.query.completedChallenge === 'string'
? router.query.completedChallenge
Expand Down Expand Up @@ -257,7 +274,7 @@ export default function CandidatesPage() {
FIDE Candidates Tournament 2026
</h1>
<p className="mt-2 text-sm uppercase tracking-[0.2em] text-white/45">
Round 4
Round 8
</p>
<div className="mt-4 flex flex-wrap gap-3">
<Link
Expand All @@ -282,12 +299,26 @@ export default function CandidatesPage() {
</header>
{CANDIDATES_FEATURED_POSITIONS.length > 0 ? (
<>
<ChallengeSectionTitle title="Round 4 Challenges" />
<ChallengeSectionTitle title="Round 8 Challenges" />
{CANDIDATES_FEATURED_POSITIONS.map((position) => (
<PositionPill
key={position.id}
position={position}
completed={completedChallengeIds.includes(position.id)}
compactTitle={compactFeaturedTitles}
/>
))}
</>
) : null}
{CANDIDATES_ROUND_FOUR_POSITIONS.length > 0 ? (
<>
<ChallengeSectionTitle title="Round 4 Challenges" />
{CANDIDATES_ROUND_FOUR_POSITIONS.map((position) => (
<PositionPill
key={position.id}
position={position}
completed={completedChallengeIds.includes(position.id)}
compactTitle={compactRoundFourTitles}
/>
))}
</>
Expand All @@ -300,6 +331,7 @@ export default function CandidatesPage() {
key={position.id}
position={position}
completed={completedChallengeIds.includes(position.id)}
compactTitle={compactRoundThreeTitles}
/>
))}
</>
Expand All @@ -312,6 +344,7 @@ export default function CandidatesPage() {
key={position.id}
position={position}
completed={completedChallengeIds.includes(position.id)}
compactTitle={compactRoundTwoTitles}
/>
))}
</>
Expand All @@ -324,6 +357,7 @@ export default function CandidatesPage() {
key={position.id}
position={position}
completed={completedChallengeIds.includes(position.id)}
compactTitle={compactRoundOneTitles}
/>
))}
</>
Expand Down
Loading