Skip to content

Commit 68dc1e3

Browse files
feat: enhance SimplifiedAnalysis and TrainSection components with responsive design and optimized move rendering
1 parent abf1672 commit 68dc1e3

2 files changed

Lines changed: 147 additions & 103 deletions

File tree

src/components/Home/Sections/SimplifiedAnalysisComponents.tsx

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ const MOCK_COLOR_SAN_MAPPING: Partial<ColorSanMapping> = {
3131
e4: { san: 'e4', color: COLORS.good[0] },
3232
d4: { san: 'd4', color: COLORS.good[1] },
3333
Nf3: { san: 'Nf3', color: COLORS.ok[0] },
34-
c4: { san: 'c4', color: COLORS.ok[1] },
35-
g3: { san: 'g3', color: COLORS.blunder[0] },
3634
}
3735

36+
// Only include moves that have data in MOCK_MOVES_BY_RATING
37+
const MOVES_WITH_DATA = ['e4', 'd4', 'Nf3'] as const
38+
3839
interface MovesByRatingData {
3940
rating: number
4041
e4: number
@@ -170,6 +171,41 @@ export const SimplifiedMovesByRating = () => {
170171
tickLine={false}
171172
tickFormatter={(value) => `${value}%`}
172173
/>
174+
<defs>
175+
{MOVES_WITH_DATA.map((move) => (
176+
<linearGradient
177+
key={`color${move}`}
178+
id={`color${move}`}
179+
x1="0"
180+
y1="0"
181+
x2="0"
182+
y2="1"
183+
>
184+
<stop
185+
offset="5%"
186+
stopColor={getColorForMove(move)}
187+
stopOpacity={0.5}
188+
/>
189+
<stop
190+
offset="95%"
191+
stopColor={getColorForMove(move)}
192+
stopOpacity={0}
193+
/>
194+
</linearGradient>
195+
))}
196+
</defs>
197+
{MOVES_WITH_DATA.map((move, index) => (
198+
<Area
199+
key={move}
200+
yAxisId="left"
201+
dataKey={move}
202+
stroke={getColorForMove(move)}
203+
fill={`url(#color${move})`}
204+
strokeWidth={3}
205+
name={getSanForMove(move)}
206+
animationDuration={300}
207+
/>
208+
))}
173209
<Tooltip
174210
content={({ payload }) => {
175211
return (
@@ -228,45 +264,8 @@ export const SimplifiedMovesByRating = () => {
228264
fontSize: 14,
229265
}}
230266
iconSize={0}
267+
formatter={(value) => getSanForMove(value)}
231268
/>
232-
{Object.keys(MOCK_COLOR_SAN_MAPPING).map((move, index) => (
233-
<motion.g
234-
key={move}
235-
initial={{ opacity: 0 }}
236-
animate={{ opacity: 1 }}
237-
transition={{ duration: 0.5, delay: 0.3 + index * 0.1 }}
238-
>
239-
<Area
240-
yAxisId="left"
241-
dataKey={move}
242-
stroke={getColorForMove(move)}
243-
fill={`url(#color${move})`}
244-
strokeWidth={3}
245-
name={getSanForMove(move)}
246-
>
247-
<defs>
248-
<linearGradient
249-
id={`color${move}`}
250-
x1="0"
251-
y1="0"
252-
x2="0"
253-
y2="1"
254-
>
255-
<stop
256-
offset="5%"
257-
stopColor={getColorForMove(move)}
258-
stopOpacity={0.5}
259-
/>
260-
<stop
261-
offset="95%"
262-
stopColor={getColorForMove(move)}
263-
stopOpacity={0}
264-
/>
265-
</linearGradient>
266-
</defs>
267-
</Area>
268-
</motion.g>
269-
))}
270269
</AreaChart>
271270
</ResponsiveContainer>
272271
</div>

src/components/Home/Sections/TrainSection.tsx

Lines changed: 108 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Link from 'next/link'
22
import { motion } from 'framer-motion'
33
import { useInView } from 'react-intersection-observer'
4-
import { useState, useEffect } from 'react'
4+
import { useState, useEffect, useRef } from 'react'
55
import Chessground from '@react-chess/chessground'
66
import type { DrawShape } from 'chessground/draw'
77
import type { Key } from 'chessground/types'
@@ -159,6 +159,105 @@ const PUZZLES: ChessPuzzle[] = [
159159
},
160160
]
161161

162+
// Responsive chessboard component for TrainSection
163+
const ResponsiveTrainChessboard = ({
164+
puzzle,
165+
shapes,
166+
forceKey,
167+
}: {
168+
puzzle: ChessPuzzle
169+
shapes: DrawShape[]
170+
forceKey: number
171+
}) => {
172+
const [windowSize, setWindowSize] = useState({ width: 0, height: 0 })
173+
const containerRef = useRef<HTMLDivElement>(null)
174+
175+
const stableKey = `train-chess-${puzzle.id}-${forceKey}-${windowSize.width}-${windowSize.height}`
176+
177+
useEffect(() => {
178+
const handleResize = () => {
179+
setWindowSize({
180+
width: window.innerWidth,
181+
height: window.innerHeight,
182+
})
183+
}
184+
185+
handleResize()
186+
187+
window.addEventListener('resize', handleResize)
188+
return () => window.removeEventListener('resize', handleResize)
189+
}, [])
190+
191+
return (
192+
<div
193+
ref={containerRef}
194+
className="relative w-full"
195+
style={{
196+
transform: 'translateZ(0)',
197+
aspectRatio: '1/1',
198+
}}
199+
>
200+
<div
201+
className="h-full w-full"
202+
style={{
203+
position: 'relative',
204+
transform: 'translateZ(0)',
205+
}}
206+
>
207+
<Chessground
208+
key={stableKey}
209+
contained
210+
config={{
211+
fen: puzzle.fen,
212+
viewOnly: true,
213+
coordinates: true,
214+
drawable: {
215+
enabled: true,
216+
visible: true,
217+
defaultSnapToValidMove: true,
218+
shapes,
219+
brushes: {
220+
green: {
221+
key: 'g',
222+
color: '#15781B',
223+
opacity: 1,
224+
lineWidth: 10,
225+
},
226+
red: {
227+
key: 'r',
228+
color: '#882020',
229+
opacity: 1,
230+
lineWidth: 10,
231+
},
232+
blue: {
233+
key: 'b',
234+
color: '#003088',
235+
opacity: 1,
236+
lineWidth: 10,
237+
},
238+
yellow: {
239+
key: 'y',
240+
color: '#e68f00',
241+
opacity: 1,
242+
lineWidth: 10,
243+
},
244+
},
245+
},
246+
highlight: {
247+
lastMove: true,
248+
check: true,
249+
},
250+
animation: {
251+
duration: 0,
252+
},
253+
disableContextMenu: true,
254+
}}
255+
/>
256+
</div>
257+
</div>
258+
)
259+
}
260+
162261
export const TrainSection = ({ id }: TrainSectionProps) => {
163262
const [ref, inView] = useInView({
164263
triggerOnce: false,
@@ -237,8 +336,6 @@ export const TrainSection = ({ id }: TrainSectionProps) => {
237336

238337
const puzzle = PUZZLES[currentPuzzle]
239338

240-
const stableKey = `board-${currentPuzzle}-${renderKey}-${windowSize.width}-${windowSize.height}`
241-
242339
return (
243340
<section
244341
id={id}
@@ -311,70 +408,18 @@ export const TrainSection = ({ id }: TrainSectionProps) => {
311408
</div>
312409
<div className="flex flex-col gap-4 p-4 md:flex-row">
313410
<div className="flex w-full justify-center md:w-1/2">
314-
<div
315-
className="relative w-full"
411+
<motion.div
412+
className="w-full"
316413
style={{
317-
aspectRatio: '1/1',
318414
transform: 'translateZ(0)',
319415
}}
320416
>
321-
<motion.div
322-
className="h-full w-full"
323-
style={{
324-
position: 'relative',
325-
transform: 'translateZ(0)',
326-
}}
327-
>
328-
<Chessground
329-
key={stableKey}
330-
contained
331-
config={{
332-
fen: puzzle.fen,
333-
viewOnly: true,
334-
coordinates: true,
335-
drawable: {
336-
enabled: true,
337-
visible: true,
338-
defaultSnapToValidMove: true,
339-
shapes,
340-
brushes: {
341-
green: {
342-
key: 'g',
343-
color: '#15781B',
344-
opacity: 1,
345-
lineWidth: 10,
346-
},
347-
red: {
348-
key: 'r',
349-
color: '#882020',
350-
opacity: 1,
351-
lineWidth: 10,
352-
},
353-
blue: {
354-
key: 'b',
355-
color: '#003088',
356-
opacity: 1,
357-
lineWidth: 10,
358-
},
359-
yellow: {
360-
key: 'y',
361-
color: '#e68f00',
362-
opacity: 1,
363-
lineWidth: 10,
364-
},
365-
},
366-
},
367-
highlight: {
368-
lastMove: true,
369-
check: true,
370-
},
371-
animation: {
372-
duration: 0,
373-
},
374-
}}
375-
/>{' '}
376-
</motion.div>
377-
</div>
417+
<ResponsiveTrainChessboard
418+
puzzle={puzzle}
419+
shapes={shapes}
420+
forceKey={renderKey}
421+
/>
422+
</motion.div>
378423
</div>
379424
<div className="flex w-full flex-col md:w-1/2">
380425
<motion.div

0 commit comments

Comments
 (0)