|
| 1 | +/* eslint-disable jsx-a11y/click-events-have-key-events */ |
1 | 2 | import { Chess } from 'chess.ts'
|
2 |
| -import { useEffect, useState } from 'react' |
| 3 | +import { useContext, useEffect, useState } from 'react' |
3 | 4 |
|
4 |
| -import { Move } from 'src/types' |
| 5 | +import { Move, PlayedGame } from 'src/types' |
| 6 | +import { GameControllerContext } from 'src/contexts' |
5 | 7 |
|
6 | 8 | interface Props {
|
7 |
| - moves: Move[] |
| 9 | + game: PlayedGame |
| 10 | + whitePlayer: string |
| 11 | + blackPlayer: string |
| 12 | + maiaVersion: string |
8 | 13 | }
|
9 | 14 |
|
10 |
| -export const ExportGame: React.FC<Props> = ({ moves }) => { |
| 15 | +export const ExportGame: React.FC<Props> = ({ |
| 16 | + game, |
| 17 | + whitePlayer, |
| 18 | + blackPlayer, |
| 19 | + maiaVersion, |
| 20 | +}) => { |
| 21 | + const [fen, setFen] = useState('') |
11 | 22 | const [pgn, setPgn] = useState('')
|
| 23 | + const { currentIndex } = useContext(GameControllerContext) |
12 | 24 |
|
13 | 25 | useEffect(() => {
|
14 | 26 | const chess = new Chess()
|
15 |
| - moves.forEach((move) => { |
| 27 | + game.moves.forEach((move) => { |
16 | 28 | if (move.san) {
|
17 | 29 | chess.move(move.san)
|
18 | 30 | }
|
19 | 31 | })
|
20 | 32 | setPgn(chess.pgn())
|
21 |
| - }, [moves]) |
| 33 | + }, [game.moves]) |
| 34 | + |
| 35 | + useEffect(() => { |
| 36 | + const initial = new Chess(game.moves[0].board) |
| 37 | + initial.addHeader('ID', game.id) |
| 38 | + initial.addHeader('Event', `Play v. ${maiaVersion}`) |
| 39 | + initial.addHeader('Site', `https://maiachess.com/`) |
| 40 | + initial.addHeader('White', whitePlayer) |
| 41 | + initial.addHeader('Black', blackPlayer) |
| 42 | + if (game.termination) { |
| 43 | + initial.addHeader('Result', game.termination.result) |
| 44 | + if (game.termination.condition) { |
| 45 | + initial.addHeader('Termination', game.termination.condition) |
| 46 | + } |
| 47 | + } |
| 48 | + game.moves.forEach((move, index) => { |
| 49 | + if (!move.san || index > currentIndex) { |
| 50 | + return |
| 51 | + } |
| 52 | + |
| 53 | + initial.move(move.san) |
| 54 | + }) |
| 55 | + setFen(game.moves[currentIndex].board) |
| 56 | + setPgn(initial.pgn()) |
| 57 | + }, [currentIndex, game.moves]) |
22 | 58 |
|
23 | 59 | const copy = (content: string) => {
|
24 | 60 | navigator.clipboard.writeText(content)
|
25 | 61 | }
|
26 | 62 |
|
27 | 63 | return (
|
28 |
| - <div className="flex flex-row items-center justify-center gap-2"> |
29 |
| - <div className="flex h-10 items-center overflow-hidden rounded border border-primary/10 bg-background-1"> |
30 |
| - <div className="flex w-[500px] items-center justify-start bg-background-1 px-4"> |
31 |
| - <p className="whitespace-nowrap text-sm text-secondary"> |
32 |
| - {moves[moves.length - 1].board} |
| 64 | + <div className="flex flex-col gap-1"> |
| 65 | + <div className="flex flex-col gap-0.5"> |
| 66 | + <div className="flex items-center justify-between"> |
| 67 | + <p className="select-none text-sm font-semibold tracking-wider text-secondary"> |
| 68 | + FEN |
33 | 69 | </p>
|
| 70 | + <i |
| 71 | + tabIndex={0} |
| 72 | + role="button" |
| 73 | + onClick={() => copy(fen)} |
| 74 | + className="material-symbols-outlined select-none text-base text-secondary hover:text-primary" |
| 75 | + > |
| 76 | + content_copy |
| 77 | + </i> |
34 | 78 | </div>
|
35 |
| - <button |
36 |
| - onClick={() => copy(moves[moves.length - 1].board)} |
37 |
| - className="flex h-10 w-10 min-w-10 items-center justify-center border-l border-primary/10 bg-background-2 transition duration-200 hover:bg-background-3" |
| 79 | + <div |
| 80 | + role="button" |
| 81 | + tabIndex={0} |
| 82 | + onClick={() => copy(fen)} |
| 83 | + className="border-1 group flex cursor-pointer overflow-x-hidden rounded border border-white/5 bg-background-1/50 px-4 py-2" |
38 | 84 | >
|
39 |
| - <span className="material-symbols-outlined text-xl"> |
| 85 | + <p className="whitespace-nowrap text-xs text-secondary group-hover:text-secondary/80"> |
| 86 | + {fen} |
| 87 | + </p> |
| 88 | + </div> |
| 89 | + </div> |
| 90 | + <div className="flex flex-col gap-0.5"> |
| 91 | + <div className="flex items-center justify-between"> |
| 92 | + <p className="select-none text-sm font-semibold tracking-wider text-secondary"> |
| 93 | + PGN |
| 94 | + </p> |
| 95 | + <i |
| 96 | + tabIndex={0} |
| 97 | + role="button" |
| 98 | + onClick={() => copy(pgn)} |
| 99 | + className="material-symbols-outlined select-none text-base text-secondary hover:text-primary" |
| 100 | + > |
40 | 101 | content_copy
|
41 |
| - </span> |
42 |
| - </button> |
| 102 | + </i> |
| 103 | + </div> |
| 104 | + <div |
| 105 | + role="button" |
| 106 | + tabIndex={0} |
| 107 | + onClick={() => copy(pgn)} |
| 108 | + className="border-1 group flex cursor-pointer overflow-x-hidden rounded border border-white/5 bg-background-1/50 px-4 py-2" |
| 109 | + > |
| 110 | + <p className="whitespace-pre-wrap text-xs text-secondary group-hover:text-secondary/80"> |
| 111 | + {pgn} |
| 112 | + </p> |
| 113 | + </div> |
43 | 114 | </div>
|
44 |
| - <button |
45 |
| - onClick={() => copy(pgn)} |
46 |
| - className="flex h-10 items-center justify-center rounded border border-primary/10 bg-background-2 px-4 py-1 transition duration-300 hover:bg-background-3" |
47 |
| - > |
48 |
| - Copy PGN |
49 |
| - </button> |
50 | 115 | </div>
|
51 | 116 | )
|
52 | 117 | }
|
0 commit comments