Skip to content

Commit 0fdfab1

Browse files
feat: migrate to lichess tsv dataset
1 parent 400c5ed commit 0fdfab1

10 files changed

Lines changed: 3925 additions & 108 deletions

File tree

next.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ const withTM = require('next-transpile-modules')(['@react-chess/chessground'])
66
module.exports = withTM({
77
reactStrictMode: false,
88
output: 'standalone',
9+
webpack: (config) => {
10+
// Load .tsv assets as resources so we can fetch their URLs at runtime
11+
config.module.rules.push({
12+
test: /\.tsv$/i,
13+
type: 'asset/resource',
14+
})
15+
return config
16+
},
917
async rewrites() {
1018
return [
1119
{

src/components/Openings/OpeningSelectionModal.tsx

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useState, useMemo, useEffect, useContext } from 'react'
2+
import { Chess } from 'chess.ts'
23
import Image from 'next/image'
34
import { motion } from 'framer-motion'
45
import Chessground from '@react-chess/chessground'
@@ -66,7 +67,18 @@ const MobileOpeningPopup: React.FC<MobileOpeningPopupProps> = ({
6667
}) => {
6768
const [selectedColor, setSelectedColor] = useState<'white' | 'black'>('white')
6869
const previewFen = useMemo(() => {
69-
return variation ? variation.fen : opening.fen
70+
const pgn = variation?.pgn || opening.pgn
71+
if (pgn) {
72+
try {
73+
const chess = new Chess()
74+
chess.loadPgn(pgn.trim())
75+
return chess.fen()
76+
} catch (err) {
77+
// fall back to any provided fen if parsing fails
78+
return variation?.fen || opening.fen || ''
79+
}
80+
}
81+
return variation?.fen || opening.fen || ''
7082
}, [opening, variation])
7183

7284
if (!isOpen) return null
@@ -201,7 +213,6 @@ const TabNavigation: React.FC<{
201213
)
202214
}
203215

204-
205216
const PreviewPanel: React.FC<{
206217
selections: OpeningSelection[]
207218
previewOpening: Opening
@@ -248,7 +259,9 @@ const PreviewPanel: React.FC<{
248259
{previewVariation && ` → ${previewVariation.name}`}
249260
</span>
250261
</p>
251-
<p className="text-xs text-secondary">{previewOpening.description}</p>
262+
<p className="font-mono text-xs text-secondary">
263+
{previewVariation ? previewVariation.pgn : previewOpening.pgn}
264+
</p>
252265
</div>
253266

254267
<div className="flex flex-col gap-1">
@@ -539,7 +552,9 @@ export const OpeningSelectionModal: React.FC<Props> = ({
539552
}, [ecoDatabase])
540553

541554
// ECO preview state - initialize with first ECO opening if available
542-
const [previewEcoOpening, setPreviewEcoOpening] = useState<EcoOpening | null>(null)
555+
const [previewEcoOpening, setPreviewEcoOpening] = useState<EcoOpening | null>(
556+
null,
557+
)
543558
const [previewEcoVariation, setPreviewEcoVariation] =
544559
useState<EcoOpeningVariation | null>(null)
545560
const [mobilePopupOpening, setMobilePopupOpening] = useState<Opening | null>(
@@ -600,17 +615,29 @@ export const OpeningSelectionModal: React.FC<Props> = ({
600615
}
601616

602617
const previewFen = useMemo(() => {
603-
if (previewEcoOpening) {
604-
return previewEcoVariation
605-
? previewEcoVariation.fen
606-
: previewEcoOpening.fen
618+
const pgn = previewEcoVariation?.pgn || previewEcoOpening?.pgn
619+
if (pgn) {
620+
try {
621+
const chess = new Chess()
622+
chess.loadPgn(pgn.trim())
623+
return chess.fen()
624+
} catch (err) {
625+
// fallback to any fen if present
626+
return (
627+
previewEcoVariation?.fen ||
628+
previewEcoOpening?.fen ||
629+
ecoData?.sections?.[0]?.openings?.[0]?.fen ||
630+
''
631+
)
632+
}
607633
}
608-
return ecoData?.sections?.[0]?.openings?.[0]?.fen || ''
609-
}, [
610-
previewEcoOpening,
611-
previewEcoVariation,
612-
ecoData,
613-
])
634+
return (
635+
previewEcoVariation?.fen ||
636+
previewEcoOpening?.fen ||
637+
ecoData?.sections?.[0]?.openings?.[0]?.fen ||
638+
''
639+
)
640+
}, [previewEcoOpening, previewEcoVariation, ecoData])
614641

615642
// ECO selection handlers
616643
const handleEcoOpeningClick = (
@@ -650,7 +677,7 @@ export const OpeningSelectionModal: React.FC<Props> = ({
650677
s.maiaVersion === selectedMaiaVersion.id &&
651678
s.targetMoveNumber === targetMoveNumber,
652679
)
653-
680+
654681
if (isDuplicate) return
655682

656683
// Track quick add usage
@@ -687,11 +714,9 @@ export const OpeningSelectionModal: React.FC<Props> = ({
687714
)
688715
}
689716

690-
691-
692717
const addSelection = () => {
693718
if (!previewEcoOpening) return
694-
719+
695720
const currentOpening = ecoToLegacyOpening(previewEcoOpening)
696721
const currentVariation = previewEcoVariation
697722
? {
@@ -711,7 +736,7 @@ export const OpeningSelectionModal: React.FC<Props> = ({
711736
s.maiaVersion === selectedMaiaVersion.id &&
712737
s.targetMoveNumber === targetMoveNumber,
713738
)
714-
739+
715740
if (isDuplicate) return
716741

717742
const newSelection: OpeningSelection = {
@@ -750,7 +775,6 @@ export const OpeningSelectionModal: React.FC<Props> = ({
750775
setSelections(selections.filter((s) => s.id !== selectionId))
751776
}
752777

753-
754778
const handleMobilePopupAdd = (color: 'white' | 'black') => {
755779
if (!mobilePopupOpening) return
756780

@@ -796,7 +820,6 @@ export const OpeningSelectionModal: React.FC<Props> = ({
796820
)
797821
}
798822

799-
800823
// Helper function to generate drill sequenc
801824
const generateDrillSequence = (
802825
selections: OpeningSelection[],
@@ -953,7 +976,6 @@ export const OpeningSelectionModal: React.FC<Props> = ({
953976
your color and opponent strength.
954977
</p>
955978
</div>
956-
957979
</div>
958980
</div>
959981

@@ -978,9 +1000,7 @@ export const OpeningSelectionModal: React.FC<Props> = ({
9781000

9791001
<div className="flex h-16 flex-col justify-center gap-1 border-b border-white/10 p-4 md:hidden">
9801002
<h2 className="text-lg font-bold">ECO Openings</h2>
981-
<p className="text-xs text-secondary">
982-
Choose from ECO database
983-
</p>
1003+
<p className="text-xs text-secondary">Choose from ECO database</p>
9841004
</div>
9851005

9861006
<EcoTreeView
@@ -1000,7 +1020,16 @@ export const OpeningSelectionModal: React.FC<Props> = ({
10001020
previewOpening={
10011021
previewEcoOpening
10021022
? ecoToLegacyOpening(previewEcoOpening)
1003-
: (ecoData?.sections?.[0]?.openings?.[0] ? ecoToLegacyOpening(ecoData.sections[0].openings[0]) : { id: '', name: '', description: '', fen: '', pgn: '', variations: [] })
1023+
: ecoData?.sections?.[0]?.openings?.[0]
1024+
? ecoToLegacyOpening(ecoData.sections[0].openings[0])
1025+
: {
1026+
id: '',
1027+
name: '',
1028+
description: '',
1029+
fen: '',
1030+
pgn: '',
1031+
variations: [],
1032+
}
10041033
}
10051034
previewVariation={
10061035
previewEcoVariation

0 commit comments

Comments
 (0)