This commit is contained in:
Stefan
2025-11-23 20:56:30 +01:00
parent c5b763d646
commit 1f2300e476
11 changed files with 846 additions and 44 deletions
+17 -3
View File
@@ -18,6 +18,7 @@ import { CapturedPieces } from "./CapturedPieces";
interface ChessGameProps {
initialFen?: string;
initialPgn?: string;
initialPersonality: Personality;
initialColor: 'white' | 'black';
onBack: () => void;
@@ -32,7 +33,7 @@ const PIECE_VALUES: Record<string, number> = {
'k': 0
};
export default function ChessGame({ initialFen, initialPersonality, initialColor, onBack }: ChessGameProps) {
export default function ChessGame({ initialFen, initialPgn, initialPersonality, initialColor, onBack }: ChessGameProps) {
const gameRef = useRef(new Chess(initialFen || "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"));
const [fen, setFen] = useState(gameRef.current.fen());
const [stockfish, setStockfish] = useState<Stockfish | null>(null);
@@ -89,6 +90,17 @@ export default function ChessGame({ initialFen, initialPersonality, initialColor
updateCapturedPieces(); // Update captured pieces for loaded game
}
// If initialPgn is provided, load it to restore history
if (initialPgn) {
try {
gameRef.current.loadPgn(initialPgn);
setFen(gameRef.current.fen());
updateCapturedPieces();
} catch (e) {
console.error("Failed to load PGN:", e);
}
}
// If computer is white (player is black) and it's the start of the game, make a move
// But only if we are at the start position
if (initialColor === 'black' &&
@@ -117,7 +129,9 @@ export default function ChessGame({ initialFen, initialPersonality, initialColor
language,
selectedPersonality,
apiKey,
playerColor // Save player color too
apiKey,
playerColor, // Save player color too
pgn: gameRef.current.pgn()
};
localStorage.setItem("chess_tutor_save", JSON.stringify(saveData));
}, [fen, language, selectedPersonality, apiKey, playerColor]);
@@ -307,7 +321,7 @@ export default function ChessGame({ initialFen, initialPersonality, initialColor
return (
<>
<Header language={language} />
<div className="flex flex-col md:flex-row gap-8 w-full max-w-6xl mx-auto p-4">
<div className="flex-grow flex flex-col md:flex-row gap-8 w-full max-w-6xl mx-auto p-4">
<div className="w-full md:w-2/3 flex flex-col gap-4">
{/* Header with Back Button */}
<div className="flex justify-between items-center">
+45
View File
@@ -0,0 +1,45 @@
import Link from "next/link";
export default function Footer() {
// Read environment variables at runtime (Server Component)
const imprintUrl = process.env.IMPRINT_URL;
return (
<footer className="bg-gray-100 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-800 py-6 mt-auto">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex flex-col md:flex-row justify-between items-center gap-4">
<div className="text-sm text-gray-500 dark:text-gray-400">
© {new Date().getFullYear()} Chess Tutor AI. All rights reserved.
</div>
<div className="flex gap-6 text-sm">
{imprintUrl ? (
<a
href={imprintUrl}
target="_blank"
rel="noopener noreferrer"
className="text-gray-600 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
>
Imprint
</a>
) : (
<Link
href="/imprint"
className="text-gray-600 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
>
Imprint
</Link>
)}
<Link
href="/privacy"
className="text-gray-600 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
>
Data Privacy
</Link>
</div>
</div>
</div>
</footer>
);
}
+7 -7
View File
@@ -48,7 +48,7 @@ export default function StartScreen({ onStartGame, onResumeGame, hasSavedGame }:
return (
<>
<Header language={language} />
<div className="min-h-screen bg-gray-100 dark:bg-gray-900 p-4 flex flex-col items-center justify-center">
<div className="flex-grow bg-gray-100 dark:bg-gray-900 p-4 flex flex-col items-center justify-center relative">
<div className="absolute top-4 right-4 md:top-8 md:right-8">
<button
onClick={() => router.push("/settings")}
@@ -105,8 +105,8 @@ export default function StartScreen({ onStartGame, onResumeGame, hasSavedGame }:
<button
onClick={() => setColorSelection('white')}
className={`py-4 px-4 rounded-xl border-2 text-sm font-bold transition-all flex flex-col items-center gap-2 ${colorSelection === 'white'
? 'bg-blue-50 border-blue-600 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400'
: 'bg-white dark:bg-gray-700 border-gray-200 dark:border-gray-600 hover:border-blue-300 dark:hover:border-blue-500'
? 'bg-blue-50 border-blue-600 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400'
: 'bg-white dark:bg-gray-700 border-gray-200 dark:border-gray-600 hover:border-blue-300 dark:hover:border-blue-500'
}`}
>
<span className="text-3xl"></span> {t.start.playAsWhite}
@@ -114,8 +114,8 @@ export default function StartScreen({ onStartGame, onResumeGame, hasSavedGame }:
<button
onClick={() => setColorSelection('black')}
className={`py-4 px-4 rounded-xl border-2 text-sm font-bold transition-all flex flex-col items-center gap-2 ${colorSelection === 'black'
? 'bg-blue-50 border-blue-600 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400'
: 'bg-white dark:bg-gray-700 border-gray-200 dark:border-gray-600 hover:border-blue-300 dark:hover:border-blue-500'
? 'bg-blue-50 border-blue-600 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400'
: 'bg-white dark:bg-gray-700 border-gray-200 dark:border-gray-600 hover:border-blue-300 dark:hover:border-blue-500'
}`}
>
<span className="text-3xl"></span> {t.start.playAsBlack}
@@ -123,8 +123,8 @@ export default function StartScreen({ onStartGame, onResumeGame, hasSavedGame }:
<button
onClick={() => setColorSelection('random')}
className={`py-4 px-4 rounded-xl border-2 text-sm font-bold transition-all flex flex-col items-center gap-2 ${colorSelection === 'random'
? 'bg-blue-50 border-blue-600 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400'
: 'bg-white dark:bg-gray-700 border-gray-200 dark:border-gray-600 hover:border-blue-300 dark:hover:border-blue-500'
? 'bg-blue-50 border-blue-600 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400'
: 'bg-white dark:bg-gray-700 border-gray-200 dark:border-gray-600 hover:border-blue-300 dark:hover:border-blue-500'
}`}
>
<span className="text-3xl">🎲</span> {t.start.randomColor}