diff --git a/src/App.scss b/src/App.scss
index a4c9552..4d8b7f7 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -20,7 +20,7 @@
& > .helpButton {
display: grid;
- grid-template-columns: 20px 1fr;
+ grid-template-columns: 1fr;
align-items: center;
gap: 5px;
padding: 10px 15px;
diff --git a/src/App.tsx b/src/App.tsx
index 3943e4b..1495c83 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -3,12 +3,13 @@
// ---------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------ React --------------------------------------------------------
-import { useState } from 'react';
+import { useEffect, useState } from 'react';
// ---------------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------- Context -------------------------------------------------------
import { useRecoilState } from 'recoil';
import { gameStateAtom } from './contexts/gameState';
+import { langAtom } from './contexts/langState';
// ---------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------- Components ------------------------------------------------------
@@ -20,47 +21,83 @@ import Help from './components/Help/Help';
import LeaderBoard from './components/Leaderboard/Leaderboard';
// ---------------------------------------------------------------------------------------------------------------------
+// ------------------------------------------------------ Langs --------------------------------------------------------
+import frConf from './langs/fr.json';
+import enConf from './langs/en.json';
+// ---------------------------------------------------------------------------------------------------------------------
+
// ----------------------------------------------------- Styles --------------------------------------------------------
import Logo from './assets/logo';
-import Question from './assets/question';
import './App.scss';
+import LangToggler from './components/LangToggler/LangToggler';
// ---------------------------------------------------------------------------------------------------------------------
const App = () => {
const [helpDisplayed, displayHelp] = useState(false);
const [gameState] = useRecoilState(gameStateAtom);
+ const [lang, setLang] = useRecoilState(langAtom);
- return (
-
- {gameState.status === 'settings' &&
}
- {(gameState.status === 'idle' || gameState.status === 'playing') && (
- <>
-
-
-
-
-
-
-
- {helpDisplayed && (
-
{
- displayHelp(false);
- }}
- />
- )}
- >
- )}
- {gameState.status === 'board' && }
-
- );
+ useEffect(() => {
+ const storedLang = localStorage.getItem('lang');
+
+ if (storedLang === null) {
+ localStorage.setItem('lang', 'fr');
+ setLang({
+ key: 'fr',
+ config: frConf,
+ });
+ return;
+ }
+
+ if (storedLang === 'fr') {
+ setLang({
+ key: 'fr',
+ config: frConf,
+ });
+ return;
+ }
+
+ setLang({
+ key: 'en',
+ config: enConf,
+ });
+ }, [lang.key]);
+
+ if (lang.config) {
+ return (
+
+
+ {gameState.status === 'settings' &&
}
+ {(gameState.status === 'idle' || gameState.status === 'playing') && (
+ <>
+
+
+
+
+
+
+
+ {helpDisplayed && (
+
{
+ displayHelp(false);
+ }}
+ />
+ )}
+ >
+ )}
+ {gameState.status === 'board' && }
+
+ );
+ }
+
+ return <>>;
};
export default App;
diff --git a/src/assets/en.png b/src/assets/en.png
new file mode 100644
index 0000000..9670356
Binary files /dev/null and b/src/assets/en.png differ
diff --git a/src/assets/fr.png b/src/assets/fr.png
new file mode 100644
index 0000000..2ed2cc7
Binary files /dev/null and b/src/assets/fr.png differ
diff --git a/src/assets/question.tsx b/src/assets/question.tsx
deleted file mode 100644
index b558b4a..0000000
--- a/src/assets/question.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-const Question = (props: any) => {
- return (
-
- );
-};
-
-export default Question;
diff --git a/src/components/Grid/Grid.tsx b/src/components/Grid/Grid.tsx
index 6195b38..123fa75 100644
--- a/src/components/Grid/Grid.tsx
+++ b/src/components/Grid/Grid.tsx
@@ -9,6 +9,7 @@ import { useState } from 'react';
// ----------------------------------------------------- Context -------------------------------------------------------
import { useRecoilState } from 'recoil';
import { gameStateAtom } from '../../contexts/gameState';
+import { langAtom } from '../../contexts/langState';
// ---------------------------------------------------------------------------------------------------------------------
// ------------------------------------------------------ Hooks --------------------------------------------------------
@@ -29,6 +30,8 @@ const Grid = () => {
const [gameState, setGameState] = useRecoilState(gameStateAtom);
const [grid, setGrid] = useState(genGrid(gameState.gridSize));
+ const [lang] = useRecoilState(langAtom);
+
const { handleLeftClick, handleRightClick } = useActions(grid, setGrid, gameState, setGameState);
return (
@@ -69,7 +72,7 @@ const Grid = () => {
} as React.CSSProperties
}
>
- {gameState.endType === 'win' ? 'Gagné !' : 'Perdu !'}
+ {gameState.endType === 'win' ? lang.config.win : lang.config.loose}
{
onClick={() => setGameState((prev) => ({ ...prev, status: 'idle', endType: '', placedFlags: 0, bombs: 0, gameTime: '' }))}
>
- Rejouer
+
+ {lang.config.replay}
{
}}
>
- Supprimer
+ {lang.config.delete}
{
onClick={clearAllLeaderboards}
>
- Tout supprimer
+ {lang.config.deleteAll}
>
diff --git a/src/components/Leaderboard/styles.scss b/src/components/Leaderboard/styles.scss
index 6475ae2..85c2b16 100644
--- a/src/components/Leaderboard/styles.scss
+++ b/src/components/Leaderboard/styles.scss
@@ -16,8 +16,8 @@
& > .header {
display: grid;
- grid-template-columns: 1em 1fr 1fr 0.7fr 1fr;
- gap: 30px;
+ grid-template-columns: 1em 1fr 1fr 0.8fr 1fr;
+ gap: 20px;
padding: 15px 20px;
background-color: #333;
@@ -26,12 +26,12 @@
flex-wrap: nowrap;
align-items: center;
gap: 10px;
- font-size: 1.3em;
+ font-size: 1.1em;
font-weight: 400;
color: #fff;
& > svg {
- height: 1.3em;
+ height: 1.2em;
}
&:last-child {
@@ -47,10 +47,10 @@
& > .score {
display: grid;
- grid-template-columns: 1em 1fr 1fr 0.7fr 1fr;
+ grid-template-columns: 1em 1fr 1fr 0.8fr 1fr;
align-items: center;
justify-content: center;
- gap: 30px;
+ gap: 20px;
padding: 10px 20px;
background-color: #e1e1e1;
color: #333;
diff --git a/src/contexts/langState.ts b/src/contexts/langState.ts
new file mode 100644
index 0000000..a768a6e
--- /dev/null
+++ b/src/contexts/langState.ts
@@ -0,0 +1,9 @@
+import { atom } from 'recoil';
+
+export const langAtom = atom({
+ key: 'lang',
+ default: {
+ key: null as any,
+ config: null as any,
+ },
+});
diff --git a/src/langs/en.json b/src/langs/en.json
new file mode 100644
index 0000000..68a66d1
--- /dev/null
+++ b/src/langs/en.json
@@ -0,0 +1,32 @@
+{
+ "appTitle": "Minesweeper",
+ "settings": {
+ "size": {
+ "label": "Grid size",
+ "values": {
+ "small": "Small",
+ "medium": "Medium",
+ "large": "Large"
+ }
+ },
+ "difficulty": {
+ "label": "Difficulty",
+ "values": {
+ "beginner": "Beginner",
+ "intermediate": "Intermediate",
+ "expert": "Expert"
+ }
+ }
+ },
+ "start": "Start",
+ "how": "How to play?",
+ "win": "Win!",
+ "loose": "Loose!",
+ "leaderboardTitle": "Leaderboard",
+ "date": "Date",
+ "time": "Time",
+ "settingsBtn": "Settings",
+ "replay": "Replay",
+ "delete": "Delete",
+ "deleteAll": "Delete all"
+}
diff --git a/src/langs/fr.json b/src/langs/fr.json
new file mode 100644
index 0000000..bc61c56
--- /dev/null
+++ b/src/langs/fr.json
@@ -0,0 +1,32 @@
+{
+ "appTitle": "Démineur",
+ "settings": {
+ "size": {
+ "label": "Taille de grille",
+ "values": {
+ "small": "Petit",
+ "medium": "Moyen",
+ "large": "Grand"
+ }
+ },
+ "difficulty": {
+ "label": "Difficulté",
+ "values": {
+ "beginner": "Facile",
+ "intermediate": "Intermédiaire",
+ "expert": "Difficile"
+ }
+ }
+ },
+ "start": "Commencer",
+ "how": "Comment jouer ?",
+ "win": "Gagné !",
+ "loose": "Perdu !",
+ "leaderboardTitle": "Tableau des scores",
+ "date": "Date",
+ "time": "Temps",
+ "settingsBtn": "Paramètres",
+ "replay": "Rejouer",
+ "delete": "Supprimer",
+ "deleteAll": "Tout supprimer"
+}