mirror of
https://github.com/arthur-pbty/imprimersudoku.git
synced 2026-06-03 15:07:28 +02:00
127 lines
4.4 KiB
TypeScript
127 lines
4.4 KiB
TypeScript
"use client";
|
||
|
||
import { useState, useCallback, useEffect } from "react";
|
||
import { Difficulty, getDifficultyLabel, generateSudokus, SudokuPuzzle } from "./lib/sudoku";
|
||
import SudokuGrid from "./components/SudokuGrid";
|
||
|
||
const DIFFICULTIES: Difficulty[] = ["facile", "moyen", "difficile", "expert"];
|
||
const SUDOKU_COUNT = 6;
|
||
|
||
export default function Home() {
|
||
const [difficulty, setDifficulty] = useState<Difficulty>("moyen");
|
||
const [puzzles, setPuzzles] = useState<SudokuPuzzle[] | null>(null);
|
||
const [generating, setGenerating] = useState(false);
|
||
|
||
// Générer automatiquement des sudoku "Moyen" au chargement
|
||
useEffect(() => {
|
||
setGenerating(true);
|
||
setTimeout(() => {
|
||
const generated = generateSudokus("moyen", SUDOKU_COUNT);
|
||
setPuzzles(generated);
|
||
setGenerating(false);
|
||
}, 50);
|
||
}, []);
|
||
|
||
const handleGenerate = useCallback((diff: Difficulty) => {
|
||
setDifficulty(diff);
|
||
setGenerating(true);
|
||
// Use setTimeout to let UI update before heavy computation
|
||
setTimeout(() => {
|
||
const generated = generateSudokus(diff, SUDOKU_COUNT);
|
||
setPuzzles(generated);
|
||
setGenerating(false);
|
||
}, 50);
|
||
}, []);
|
||
|
||
const handlePrint = useCallback(() => {
|
||
if (!puzzles) {
|
||
setGenerating(true);
|
||
setTimeout(() => {
|
||
const generated = generateSudokus(difficulty, SUDOKU_COUNT);
|
||
setPuzzles(generated);
|
||
setGenerating(false);
|
||
setTimeout(() => window.print(), 100);
|
||
}, 50);
|
||
} else {
|
||
window.print();
|
||
}
|
||
}, [puzzles, difficulty]);
|
||
|
||
const label = getDifficultyLabel(difficulty);
|
||
|
||
return (
|
||
<div className="app-container">
|
||
{/* Controls - hidden when printing */}
|
||
<header className="controls no-print" role="banner">
|
||
<h1 className="app-title">🧩 Générateur de Sudoku</h1>
|
||
<p className="app-subtitle">
|
||
Choisissez une difficulté pour générer {SUDOKU_COUNT} sudoku sur une feuille A4 avec leurs solutions.
|
||
</p>
|
||
|
||
<nav className="button-group" role="navigation" aria-label="Choix de difficulté">
|
||
{DIFFICULTIES.map((diff) => (
|
||
<button
|
||
key={diff}
|
||
onClick={() => handleGenerate(diff)}
|
||
disabled={generating}
|
||
aria-pressed={difficulty === diff && !!puzzles}
|
||
className={`btn-difficulty ${difficulty === diff && puzzles ? "btn-active" : ""}`}
|
||
>
|
||
{getDifficultyLabel(diff)}
|
||
</button>
|
||
))}
|
||
|
||
<button
|
||
onClick={handlePrint}
|
||
disabled={generating || !puzzles}
|
||
className="btn-print"
|
||
aria-label="Imprimer les grilles de sudoku"
|
||
>
|
||
🖨️ Imprimer
|
||
</button>
|
||
</nav>
|
||
|
||
{generating && (
|
||
<p className="generating-text" role="status" aria-live="polite">Génération en cours…</p>
|
||
)}
|
||
</header>
|
||
|
||
{/* SEO content - visible to crawlers, visually subtle */}
|
||
<section className="seo-content no-print" aria-label="À propos">
|
||
<h2>Générateur de Sudoku gratuit à imprimer</h2>
|
||
<p>
|
||
Créez et imprimez des grilles de Sudoku gratuitement. Notre générateur produit des puzzles
|
||
valides et solvables avec 4 niveaux de difficulté : facile, moyen, difficile et expert.
|
||
Chaque feuille A4 contient 6 grilles 9×9 accompagnées de leurs solutions sur une page séparée.
|
||
Idéal pour s'entraîner, jouer en famille ou en classe.
|
||
</p>
|
||
</section>
|
||
|
||
{/* Printable content */}
|
||
{puzzles && (
|
||
<main className="print-area" role="main">
|
||
{/* Page 1: Puzzles */}
|
||
<section className="print-page" aria-label={`Grilles de sudoku niveau ${label}`}>
|
||
<h2 className="page-title">Sudoku — Niveau {label}</h2>
|
||
<div className="sudoku-grid-container">
|
||
{puzzles.map((p, i) => (
|
||
<SudokuGrid key={`puzzle-${i}`} grid={p.puzzle} index={i} />
|
||
))}
|
||
</div>
|
||
</section>
|
||
|
||
{/* Page 2: Solutions */}
|
||
<section className="print-page" aria-label={`Solutions niveau ${label}`}>
|
||
<h2 className="page-title">Solutions — Niveau {label}</h2>
|
||
<div className="sudoku-grid-container">
|
||
{puzzles.map((p, i) => (
|
||
<SudokuGrid key={`solution-${i}`} grid={p.solution} index={i} isSolution />
|
||
))}
|
||
</div>
|
||
</section>
|
||
</main>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|