Skip to content

Commit 3cf141f

Browse files
feat: implement new analysis layout for training + opening page
1 parent 0bc71a9 commit 3cf141f

5 files changed

Lines changed: 436 additions & 167 deletions

File tree

src/components/Analysis/MoveMap.tsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,25 @@ export const MoveMap: React.FC<Props> = ({
9494
return 14 // Extra large screens
9595
}
9696

97+
// Responsive dy values for Y-axis labels
98+
const getMainLabelDy = () => {
99+
if (width < 640) return 20 // Mobile - keep original value
100+
if (width < 1280) return 20 // Small desktop screens - reduce offset
101+
return 32 // Large screens - original value
102+
}
103+
104+
const getUnlikelyLabelDy = () => {
105+
if (width < 640) return 100 // Mobile - keep original value
106+
if (width < 1280) return 110 // Small desktop screens - reduce offset
107+
return 130 // Large screens - original value
108+
}
109+
110+
const getLikelyLabelDy = () => {
111+
if (width < 640) return -30 // Mobile - keep original value
112+
if (width < 1280) return -30 // Small desktop screens - reduce offset
113+
return -48 // Large screens - original value
114+
}
115+
97116
const onMouseEnter = (
98117
move: string,
99118
moveData: MoveMapEntry,
@@ -209,7 +228,7 @@ export const MoveMap: React.FC<Props> = ({
209228
fontSize: getYAxisLabelFontSize(),
210229
fontWeight: 600,
211230
dx: isMobile ? 5 : 10,
212-
dy: isMobile ? 20 : 32,
231+
dy: getMainLabelDy(),
213232
}}
214233
tickCount={4}
215234
tick={{
@@ -227,7 +246,7 @@ export const MoveMap: React.FC<Props> = ({
227246
angle={-90}
228247
fontSize={getDirectionalLabelFontSize()}
229248
fontWeight={500}
230-
dy={isMobile ? 100 : 140}
249+
dy={getUnlikelyLabelDy()}
231250
position="insideLeft"
232251
fill="#BF5F52"
233252
/>
@@ -239,7 +258,7 @@ export const MoveMap: React.FC<Props> = ({
239258
dx={10}
240259
angle={-90}
241260
fontWeight={500}
242-
dy={isMobile ? -30 : -56}
261+
dy={getLikelyLabelDy()}
243262
/>
244263
</YAxis>
245264
{moveMap?.map((entry, index) => {

src/components/Home/Sections/TrainSection.tsx

Lines changed: 82 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,19 @@ export const TrainSection = ({ id }: TrainSectionProps) => {
170170

171171
const [windowSize, setWindowSize] = useState({ width: 0, height: 0 })
172172

173+
// Force re-mounts of the board to ensure Chessground recalculates its
174+
// dimensions correctly on small screens after layout shifts.
175+
const [renderKey, setRenderKey] = useState(0)
176+
173177
useEffect(() => {
174178
const handleResize = () => {
175179
setWindowSize({
176180
width: window.innerWidth,
177181
height: window.innerHeight,
178182
})
183+
184+
// Re-render the board on window resize so it always fits its container
185+
setRenderKey((prev) => prev + 1)
179186
}
180187

181188
handleResize()
@@ -195,8 +202,23 @@ export const TrainSection = ({ id }: TrainSectionProps) => {
195202
setCurrentPuzzle((prev) => (prev + 1) % PUZZLES.length)
196203
}, 8000)
197204

205+
// Allow the layout to settle and then re-mount the board a few times so
206+
// Chessground can pick up the final container size, similar to the
207+
// behaviour in AnalysisSection.
208+
const timeoutIds: NodeJS.Timeout[] = []
209+
const delays = [100, 300, 500]
210+
delays.forEach((delay) => {
211+
timeoutIds.push(
212+
setTimeout(() => {
213+
setRenderKey((prev) => prev + 1)
214+
}, delay),
215+
)
216+
})
217+
198218
return () => {
199219
clearInterval(positionInterval)
220+
221+
timeoutIds.forEach((id) => clearTimeout(id))
200222
}
201223
}, [inView])
202224

@@ -215,7 +237,7 @@ export const TrainSection = ({ id }: TrainSectionProps) => {
215237

216238
const puzzle = PUZZLES[currentPuzzle]
217239

218-
const stableKey = `board-${currentPuzzle}-${windowSize.width}-${windowSize.height}`
240+
const stableKey = `board-${currentPuzzle}-${renderKey}-${windowSize.width}-${windowSize.height}`
219241

220242
return (
221243
<section
@@ -288,69 +310,71 @@ export const TrainSection = ({ id }: TrainSectionProps) => {
288310
<p className="text-sm text-secondary">{puzzle.description}</p>
289311
</div>
290312
<div className="flex flex-col gap-4 p-4 md:flex-row">
291-
<div
292-
className="relative w-full md:w-1/2"
293-
style={{
294-
aspectRatio: '1/1',
295-
transform: 'translateZ(0)',
296-
}}
297-
>
298-
<motion.div
299-
className="h-full w-full"
313+
<div className="flex w-full justify-center md:w-1/2">
314+
<div
315+
className="relative w-full"
300316
style={{
301-
position: 'relative',
317+
aspectRatio: '1/1',
302318
transform: 'translateZ(0)',
303319
}}
304320
>
305-
<Chessground
306-
key={stableKey}
307-
contained
308-
config={{
309-
fen: puzzle.fen,
310-
viewOnly: true,
311-
coordinates: true,
312-
drawable: {
313-
enabled: true,
314-
visible: true,
315-
defaultSnapToValidMove: true,
316-
shapes,
317-
brushes: {
318-
green: {
319-
key: 'g',
320-
color: '#15781B',
321-
opacity: 1,
322-
lineWidth: 10,
323-
},
324-
red: {
325-
key: 'r',
326-
color: '#882020',
327-
opacity: 1,
328-
lineWidth: 10,
329-
},
330-
blue: {
331-
key: 'b',
332-
color: '#003088',
333-
opacity: 1,
334-
lineWidth: 10,
335-
},
336-
yellow: {
337-
key: 'y',
338-
color: '#e68f00',
339-
opacity: 1,
340-
lineWidth: 10,
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+
},
341365
},
342366
},
343-
},
344-
highlight: {
345-
lastMove: true,
346-
check: true,
347-
},
348-
animation: {
349-
duration: 0,
350-
},
351-
}}
352-
/>{' '}
353-
</motion.div>
367+
highlight: {
368+
lastMove: true,
369+
check: true,
370+
},
371+
animation: {
372+
duration: 0,
373+
},
374+
}}
375+
/>{' '}
376+
</motion.div>
377+
</div>
354378
</div>
355379
<div className="flex w-full flex-col md:w-1/2">
356380
<motion.div

0 commit comments

Comments
 (0)