diff --git a/.eslintrc.json b/.eslintrc.json
index e37e1e072..c08a50b84 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -2,8 +2,13 @@
"extends": ["eslint:recommended", "prettier", "react-app", "react-app/jest"],
"plugins": ["prettier"],
"rules": {
- "camelcase": ["error", { "properties": "never" }],
- "prettier/prettier": "error",
+ "camelcase": ["error"],
+ "prettier/prettier": [
+ "error",
+ {
+ "endOfLine": "auto"
+ }
+ ],
"eqeqeq": ["error", "always"],
"no-unused-vars": ["error"]
}
diff --git a/.prettierrc.js b/.prettierrc.js
index 65e18f5ff..1cccb3ea5 100644
--- a/.prettierrc.js
+++ b/.prettierrc.js
@@ -1,4 +1,5 @@
module.exports = {
+ endOfLine: "auto",
printWidth: 120,
tabWidth: 2,
useTabs: false,
diff --git a/src/api.js b/src/api.js
new file mode 100644
index 000000000..8f1a309f5
--- /dev/null
+++ b/src/api.js
@@ -0,0 +1,29 @@
+const hostUrl = "https://wedev-api.sky.pro/api/v2/leaderboard";
+export async function getLeaders() {
+ const response = await fetch(hostUrl, {
+ method: "GET",
+ });
+ if (!response.status === 200) {
+ throw new Error("Не удалось получить список лидеров");
+ }
+ const data = await response.json();
+ return data;
+}
+
+export async function addLeaders({ name, time, achievements }) {
+ const response = await fetch(hostUrl, {
+ method: "POST",
+ body: JSON.stringify({
+ name,
+ time,
+ achievements,
+ }),
+ });
+ if (!response.status === 201) {
+ throw new Error("Не удалось добавить в список лидеров");
+ } else if (response.status === 400) {
+ throw new Error("Введите Ваше имя");
+ }
+ const data = await response.json();
+ return data;
+}
diff --git a/src/components/Button/Button.module.css b/src/components/Button/Button.module.css
index 5d3f1f80e..34e78e477 100644
--- a/src/components/Button/Button.module.css
+++ b/src/components/Button/Button.module.css
@@ -10,7 +10,7 @@
font-variant-numeric: lining-nums proportional-nums;
/* Pres → Caption S */
- font-family: StratosSkyeng;
+ font-family: Roboto;
font-size: 24px;
font-style: normal;
font-weight: 400;
diff --git a/src/components/Card/Card.module.css b/src/components/Card/Card.module.css
index 86c3fbb5b..97c538c60 100644
--- a/src/components/Card/Card.module.css
+++ b/src/components/Card/Card.module.css
@@ -40,7 +40,7 @@
color: #000;
font-variant-numeric: lining-nums proportional-nums;
- font-family: StratosSkyeng;
+ font-family: Roboto;
font-size: 24px;
font-style: normal;
font-weight: 400;
diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx
index 7526a56c8..cabe8aa00 100644
--- a/src/components/Cards/Cards.jsx
+++ b/src/components/Cards/Cards.jsx
@@ -5,6 +5,8 @@ import styles from "./Cards.module.css";
import { EndGameModal } from "../../components/EndGameModal/EndGameModal";
import { Button } from "../../components/Button/Button";
import { Card } from "../../components/Card/Card";
+import CardsIcon from "../../icon/cards.svg";
+import ToolsComponent from "../Tools/ToolsComponent";
// Игра закончилась
const STATUS_LOST = "STATUS_LOST";
@@ -40,7 +42,7 @@ function getTimerValue(startDate, endDate) {
* pairsCount - сколько пар будет в игре
* previewSeconds - сколько секунд пользователь будет видеть все карты открытыми до начала игры
*/
-export function Cards({ pairsCount = 3, previewSeconds = 5 }) {
+export function Cards({ pairsCount = 3, previewSeconds = 5, isGameMode }) {
// В cards лежит игровое поле - массив карт и их состояние открыта\закрыта
const [cards, setCards] = useState([]);
// Текущий статус игры
@@ -57,6 +59,15 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) {
minutes: 0,
});
+ // Стейт для счетчика попыток
+ const [numberOfAttempts, setNumberOfAttempts] = useState(2);
+
+ const [achievements, setAchievements] = useState([]);
+
+ const minusOneAttempt = () => {
+ setNumberOfAttempts(numberOfAttempts - 1);
+ };
+
function finishGame(status = STATUS_LOST) {
setGameEndDate(new Date());
setStatus(status);
@@ -68,11 +79,14 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) {
setTimer(getTimerValue(startDate, null));
setStatus(STATUS_IN_PROGRESS);
}
+ //добавлено кол-во попыток setNumberOfAttempts и ачивки setAchievements
function resetGame() {
setGameStartDate(null);
setGameEndDate(null);
setTimer(getTimerValue(null, null));
setStatus(STATUS_PREVIEW);
+ setNumberOfAttempts(2);
+ setAchievements(prevState => prevState.filter(achieve => achieve !== 2));
}
/**
@@ -125,17 +139,47 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) {
const playerLost = openCardsWithoutPair.length >= 2;
- // "Игрок проиграл", т.к на поле есть две открытые карты без пары
- if (playerLost) {
- finishGame(STATUS_LOST);
- return;
- }
-
// ... игра продолжается
+ if (isGameMode === "true") {
+ if (playerLost) {
+ minusOneAttempt();
+ if (numberOfAttempts < 1) {
+ finishGame(STATUS_LOST);
+ return;
+ } else {
+ setTimeout(() => {
+ setCards(cards.map(card => (openCardsWithoutPair.includes(card) ? { ...card, open: false } : card)));
+ }, 1000);
+ }
+ }
+ } else {
+ if (playerLost) {
+ finishGame(STATUS_LOST);
+ return;
+ }
+ }
};
const isGameEnded = status === STATUS_LOST || status === STATUS_WON;
+ //Ачивка на открытие пары карт
+ const alohomora = () => {
+ if (achievements.includes(2)) {
+ alert("Подсказкой можно воспользоваться только 1 раз");
+ return;
+ }
+
+ let closedCards = cards.filter(card => !card.open);
+ closedCards = shuffle(closedCards);
+ closedCards[0].open = true;
+ closedCards.forEach(card => {
+ if (card.suit === closedCards[0].suit && card.rank === closedCards[0].rank) {
+ card.open = true;
+ }
+ });
+ setAchievements(prevState => [...prevState, 2]);
+ };
+
// Игровой цикл
useEffect(() => {
// В статусах кроме превью доп логики не требуется
@@ -171,6 +215,12 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) {
clearInterval(intervalId);
};
}, [gameStartDate, gameEndDate]);
+ //Отслеживание состояния использования ачивки
+ useEffect(() => {
+ if (!isGameMode) {
+ setAchievements(prevState => [...prevState, 1]);
+ }
+ }, [isGameMode]);
return (
@@ -195,7 +245,17 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) {
>
)}
- {status === STATUS_IN_PROGRESS ? : null}
+ {status === STATUS_IN_PROGRESS ? (
+ <>
+ {isGameMode === "true" ? (
+ осталось попыток: {numberOfAttempts + 1}
+ ) : null}
+
+
+
+
+ >
+ ) : null}
@@ -217,6 +277,7 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) {
gameDurationSeconds={timer.seconds}
gameDurationMinutes={timer.minutes}
onClick={resetGame}
+ isGameMode={isGameMode}
/>
) : null}
diff --git a/src/components/Cards/Cards.module.css b/src/components/Cards/Cards.module.css
index 000c5006c..851d70320 100644
--- a/src/components/Cards/Cards.module.css
+++ b/src/components/Cards/Cards.module.css
@@ -37,7 +37,7 @@
align-items: end;
color: #fff;
- font-family: StratosSkyeng;
+ font-family: Roboto;
font-size: 64px;
font-style: normal;
font-weight: 400;
@@ -62,7 +62,7 @@
.timerDescription {
color: #fff;
font-variant-numeric: lining-nums proportional-nums;
- font-family: StratosSkyeng;
+ font-family: Roboto;
font-size: 16px;
font-style: normal;
font-weight: 400;
@@ -70,3 +70,14 @@
margin-bottom: -12px;
}
+
+.attemptСounter {
+ text-align: center;
+ color: #fff;
+ font-variant-numeric: lining-nums proportional-nums;
+ font-family: Roboto;
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 32px;
+}
diff --git a/src/components/Context/Context.js b/src/components/Context/Context.js
new file mode 100644
index 000000000..9c093b0dd
--- /dev/null
+++ b/src/components/Context/Context.js
@@ -0,0 +1,9 @@
+import { createContext, useState } from "react";
+
+export const EasyModeContext = createContext();
+
+export const GameProvider = ({ children }) => {
+ const [selectedLevel, setSelectedLevel] = useState(null);
+
+ return {children};
+};
diff --git a/src/components/EndGameModal/EndGameModal.jsx b/src/components/EndGameModal/EndGameModal.jsx
index 722394833..2f7852685 100644
--- a/src/components/EndGameModal/EndGameModal.jsx
+++ b/src/components/EndGameModal/EndGameModal.jsx
@@ -1,13 +1,68 @@
import styles from "./EndGameModal.module.css";
-
import { Button } from "../Button/Button";
-
import deadImageUrl from "./images/dead.png";
import celebrationImageUrl from "./images/celebration.png";
+import { Link, useNavigate, useParams } from "react-router-dom";
+import { useState } from "react";
+import { addLeaders } from "../../api";
export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, onClick }) {
- const title = isWon ? "Вы победили!" : "Вы проиграли!";
+ //const title = isWon ? "Вы победили!" : "Вы проиграли!"; -изменно
+ const maxLevel = 9; // Переменная для числа
+ const { pairsCount } = useParams();
+ const isMaxLevel = pairsCount === maxLevel; // Переменная для условия
+
+ const navigate = useNavigate();
+ const gameSeconds = gameDurationMinutes * 60 + gameDurationSeconds;
+ const [userData, setuserData] = useState({
+ name: "",
+ time: gameSeconds,
+ achievements: [],
+ });
+ //если isGameMode true то в userData.achievements нужно добавить 1
+
+ const handleInputChange = e => {
+ const { name, value } = e.target; // Извлекаем имя поля и его значение
+ setuserData({
+ ...userData, // Копируем текущие данные из состояния
+ [name]: value, // Обновляем нужное поле
+ });
+ };
+
+ async function handleAddUser(e) {
+ e.preventDefault();
+ try {
+ await addLeaders(userData).then(data => {
+ navigate(`/leaderboard`);
+ });
+ } catch (error) {
+ alert(error.message);
+ }
+ }
+ async function handleAddUserButton(e) {
+ e.preventDefault();
+ try {
+ await addLeaders(userData).then(data => {
+ onClick();
+ });
+ } catch (error) {
+ alert(error.message);
+ }
+ }
+
+ let title = "";
+ if (isMaxLevel) {
+ // Используем переменную вместо условия
+ title = isWon ? "Вы попали на лидерборд!" : "Вы проиграли!";
+ } else {
+ title = isWon ? "Вы победили!" : "Вы проиграли!";
+ }
+
+ const startTheGame = e => {
+ e.preventDefault();
+ navigate(`/`);
+ };
const imgSrc = isWon ? celebrationImageUrl : deadImageUrl;
const imgAlt = isWon ? "celebration emodji" : "dead emodji";
@@ -16,12 +71,35 @@ export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes,
{title}
+ {isMaxLevel && isWon ? (
+
+ ) : null}
Затраченное время:
{gameDurationMinutes.toString().padStart("2", "0")}.{gameDurationSeconds.toString().padStart("2", "0")}
-
-
+ {isMaxLevel && isWon ? (
+ <>
+
+
+ Перейти к лидерборду
+
+ >
+ ) : (
+ <>
+
+ >
+ )}
);
}
diff --git a/src/components/EndGameModal/EndGameModal.module.css b/src/components/EndGameModal/EndGameModal.module.css
index 9368cb8b5..ecf8a61a1 100644
--- a/src/components/EndGameModal/EndGameModal.module.css
+++ b/src/components/EndGameModal/EndGameModal.module.css
@@ -1,6 +1,7 @@
.modal {
width: 480px;
- height: 459px;
+ padding-top: 30px;
+ padding-bottom: 30px;
border-radius: 12px;
background: #c2f5ff;
display: flex;
@@ -18,19 +19,19 @@
.title {
color: #004980;
font-variant-numeric: lining-nums proportional-nums;
- font-family: StratosSkyeng;
+ font-family: Roboto;
font-size: 40px;
font-style: normal;
font-weight: 400;
line-height: 48px;
-
+ text-align: center;
margin-bottom: 28px;
}
.description {
color: #000;
font-variant-numeric: lining-nums proportional-nums;
- font-family: StratosSkyeng;
+ font-family: Roboto;
font-size: 24px;
font-style: normal;
font-weight: 400;
@@ -41,7 +42,7 @@
.time {
color: #000;
- font-family: StratosSkyeng;
+ font-family: Roboto;
font-size: 64px;
font-style: normal;
font-weight: 400;
@@ -49,3 +50,62 @@
margin-bottom: 40px;
}
+.leaderBoardLink {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ color: #004980;
+ text-align: center;
+ font-variant-numeric: lining-nums proportional-nums;
+ font-family: Roboto;
+ font-size: 18px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 32px;
+ text-decoration: underline;
+}
+
+.leaderBoardLink:hover {
+ text-decoration: none;
+}
+
+.form {
+ padding-top: 10px;
+ padding-bottom: 20px;
+}
+.nameInput {
+ width: 276px;
+ height: 45px;
+ border-radius: 10px;
+ border: none;
+ color: #999999;
+ text-align: center;
+ font-variant-numeric: lining-nums proportional-nums;
+ font-family: Roboto;
+ font-size: 24px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 32px;
+}
+
+.leaderBoardLinkBox {
+ color: red;
+ font-family: Roboto;
+ text-decoration: none;
+ text-transform: uppercase;
+ padding: 10px;
+}
+
+.leaderBoardLinkBox:hover {
+ text-decoration: underline;
+}
+
+.leaderBoardLinkBox:active {
+ color: black;
+}
+
+.leaderBoardLinkBox:visited {
+ color: purple;
+}
+.LeaderBoardGlob {
+ margin: 15px;
+}
diff --git a/src/components/Tools/ToolsComponent.jsx b/src/components/Tools/ToolsComponent.jsx
new file mode 100644
index 000000000..422deb640
--- /dev/null
+++ b/src/components/Tools/ToolsComponent.jsx
@@ -0,0 +1,25 @@
+import React, { useRef, useState } from "react";
+import styles from "./ToolsComponent.module.css";
+
+const ToolsComponent = ({ children, text, customClass }) => {
+ const refSetTimeout = useRef();
+ const [showToolTip, setShowToolTip] = useState(false);
+ const toolTipClasses = customClass ? `${styles.tooltip} ${customClass}` : `${styles.tooltip}`;
+ const onMouseEnterHandler = () => {
+ refSetTimeout.current = setTimeout(() => {
+ setShowToolTip(true);
+ }, 750);
+ };
+ const onMouseLeaveHandler = () => {
+ clearTimeout(refSetTimeout.current);
+ setShowToolTip(false);
+ };
+ return (
+
+ {children}
+ {showToolTip &&
{text}
}
+
+ );
+};
+
+export default ToolsComponent;
diff --git a/src/components/Tools/ToolsComponent.module.css b/src/components/Tools/ToolsComponent.module.css
new file mode 100644
index 000000000..6a5b4ed1a
--- /dev/null
+++ b/src/components/Tools/ToolsComponent.module.css
@@ -0,0 +1,23 @@
+.container {
+ position: relative;
+ display: flex;
+}
+
+.tooltip {
+ position: absolute;
+
+ padding: 20px 20px;
+ margin-top: 80px;
+ justify-content: center;
+ color: #004980;
+ background-color: #c2f5ff;
+ font-family: Roboto;
+ border-radius: 12px;
+ text-align: center;
+ white-space: pre-line;
+ font-size: 18px;
+ line-height: 25px;
+ font-weight: 400;
+ pointer-events: none;
+ z-index: 99999999;
+}
diff --git a/src/icon/cards.svg b/src/icon/cards.svg
new file mode 100644
index 000000000..08a4dc8a2
--- /dev/null
+++ b/src/icon/cards.svg
@@ -0,0 +1,15 @@
+
diff --git a/src/index.css b/src/index.css
index 78f0d3a2b..a0f94c4cf 100644
--- a/src/index.css
+++ b/src/index.css
@@ -28,7 +28,7 @@ ol {
}
@font-face {
- font-family: "StratosSkyeng";
+ font-family: Roboto;
src:
url("../public/assets/fonts/StratosSkyeng.woff2") format("woff2"),
local("Arial");
diff --git a/src/index.js b/src/index.js
index f689c5f0b..741064575 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,10 +3,13 @@ import ReactDOM from "react-dom/client";
import "./index.css";
import { RouterProvider } from "react-router-dom";
import { router } from "./router";
+import { GameProvider } from "./components/Context/Context";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
-
+
+
+
,
);
diff --git a/src/pages/GamePage/GamePage.jsx b/src/pages/GamePage/GamePage.jsx
index a4be871db..84cc083e5 100644
--- a/src/pages/GamePage/GamePage.jsx
+++ b/src/pages/GamePage/GamePage.jsx
@@ -4,10 +4,10 @@ import { Cards } from "../../components/Cards/Cards";
export function GamePage() {
const { pairsCount } = useParams();
-
+ const { isGameMode } = useParams();
return (
<>
-
+
>
);
}
diff --git a/src/pages/LeaderBoardPage/LeaderBoardPage.jsx b/src/pages/LeaderBoardPage/LeaderBoardPage.jsx
new file mode 100644
index 000000000..62d34e132
--- /dev/null
+++ b/src/pages/LeaderBoardPage/LeaderBoardPage.jsx
@@ -0,0 +1,54 @@
+import styles from "./LeaderBoardPage.module.css";
+import { useEffect, useState } from "react";
+import { Button } from "../../components/Button/Button";
+import { useNavigate } from "react-router-dom";
+import { getLeaders } from "../../api";
+
+export function LeaderBoardPage() {
+ const [leaders, setLeaders] = useState([]);
+ useEffect(() => {
+ getLeaders().then(leadersList => {
+ setLeaders(leadersList.leaders);
+ });
+ }, []);
+ const navigate = useNavigate();
+ const startTheGame = e => {
+ e.preventDefault();
+ navigate(`/`);
+ };
+
+ let i = 1;
+
+ return (
+
+
+
Лидерборд
+
+
+
+
+ );
+}
diff --git a/src/pages/LeaderBoardPage/LeaderBoardPage.module.css b/src/pages/LeaderBoardPage/LeaderBoardPage.module.css
new file mode 100644
index 000000000..e236f2505
--- /dev/null
+++ b/src/pages/LeaderBoardPage/LeaderBoardPage.module.css
@@ -0,0 +1,124 @@
+* {
+ margin: 0;
+ padding: 0;
+}
+
+.container {
+ padding: 40px;
+ padding-left: 25%;
+ padding-right: 25%;
+ padding-top: 15%;
+}
+
+.header {
+ display: flex;
+ justify-content: space-between;
+}
+
+.leaderBoard {
+ padding-top: 40px;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.headerTitle {
+ color: #ffffff;
+ font-variant-numeric: lining-nums proportional-nums;
+ font-family: Roboto;
+ font-size: 24px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 32px;
+ text-align: center;
+}
+
+.leadersItemTitle {
+ color: #999999;
+ list-style-type: none;
+ background-color: #ffffff;
+ padding: 10px 20px;
+ border-radius: 12px;
+ display: flex;
+ justify-content: space-between;
+ font-variant-numeric: lining-nums proportional-nums;
+ font-family: Roboto;
+ font-size: 24px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 32px;
+}
+
+.leadersItem {
+ list-style-type: none;
+ background-color: #ffffff;
+ padding: 10px 20px;
+ border-radius: 12px;
+ display: flex;
+ justify-content: space-between;
+ font-variant-numeric: lining-nums proportional-nums;
+ font-family: Roboto;
+ font-size: 24px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 32px;
+}
+.iconBtn:hover {
+ cursor: pointer;
+}
+.nameBox {
+ /* min-width: 150px; */
+ /* max-width: 150px; */
+ overflow-wrap: break-word;
+ white-space: normal;
+ min-width: 300px;
+ display: flex;
+ align-items:start;
+
+}
+.numberBox {
+ display: block;
+ min-width: 70px;
+ max-width: 70px;
+ overflow-wrap: break-word;
+ white-space: normal;
+ margin-right: 25%;
+
+}
+
+.timeBox{
+ min-width: 100px;
+ display: flex;
+ justify-content: flex-end;
+ padding-right: 2%;
+
+}
+
+.achivBox {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ min-width: 80px;
+ max-width: 80px;
+ overflow-wrap: break-word;
+ white-space: normal;
+}
+.toolsCustom {
+ position: absolute;
+ min-width: 180px;
+ padding: 20px 20px;
+ margin-top: 80px;
+ justify-content: center;
+ color: #004980;
+ background-color: #c2f5ff;
+ font-family: Roboto;
+ border-radius: 12px;
+ text-align: center;
+ white-space: pre-line;
+ font-size: 18px;
+ line-height: 25px;
+ font-weight: 400;
+ pointer-events: none;
+ z-index: 99999999;
+}
diff --git a/src/pages/LeaderBoardPage/imgLeader/iconCardMinus.svg b/src/pages/LeaderBoardPage/imgLeader/iconCardMinus.svg
new file mode 100644
index 000000000..1a29eb93c
--- /dev/null
+++ b/src/pages/LeaderBoardPage/imgLeader/iconCardMinus.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/pages/LeaderBoardPage/imgLeader/iconCardPlus.svg b/src/pages/LeaderBoardPage/imgLeader/iconCardPlus.svg
new file mode 100644
index 000000000..5cfaa9bd4
--- /dev/null
+++ b/src/pages/LeaderBoardPage/imgLeader/iconCardPlus.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/pages/SelectLevelPage/SelectLevelPage.jsx b/src/pages/SelectLevelPage/SelectLevelPage.jsx
index 758942e51..2c3ac5b94 100644
--- a/src/pages/SelectLevelPage/SelectLevelPage.jsx
+++ b/src/pages/SelectLevelPage/SelectLevelPage.jsx
@@ -1,28 +1,81 @@
-import { Link } from "react-router-dom";
-import styles from "./SelectLevelPage.module.css";
+import { Link, useNavigate } from "react-router-dom";
+import { useContext, useState } from "react";
+import styles from "../SelectLevelPage/SelectLevelPage.module.css";
+import { EasyModeContext } from "../../components/Context/Context";
export function SelectLevelPage() {
+ //Выбор легкого-сложного режима через контекст
+ const { selectedLevel, setSelectedLevel } = useContext(EasyModeContext); // Состояние для хранения выбранного уровня
+ const [isEasyMode, setIsEasyMode] = useState(false); // Локальное состояние для отслеживания режима игры
+ //const [checked, setChecked] = useState(false); //отслеживания режима игры
+ const navigate = useNavigate(); // Хук для навигации
+ const handleStartGame = () => {
+ if (selectedLevel !== null) {
+ navigate(`/game/${selectedLevel}/${isEasyMode ? true : false}`);
+ //navigate(`/game/${selectedLevel}/${checked ? true : false}`); // Переход на страницу игры с выбранным уровнем
+ } else {
+ alert("Пожалуйста, выберите уровень!"); // Предупреждение, если уровень не выбран
+ }
+ };
+
return (
Выбери сложность
-
-
+ setSelectedLevel(3)} // Устанавливаем уровень 1
+ >
1
+ {/*
+ 1
+ */}
-
-
+ setSelectedLevel(6)} // Устанавливаем уровень 2
+ >
2
+ {/*
+ 2
+ */}
-
-
+ setSelectedLevel(9)} // Устанавливаем уровень 3
+ >
3
+ {/*
+ 3
+ */}
+
+ setIsEasyMode(!isEasyMode)} // переключалка режима игры при каждом изменении
+ id="easyMode"
+ />
+
+
+
+
+
+ Перейти к лидерборду
+
+
);
diff --git a/src/pages/SelectLevelPage/SelectLevelPage.module.css b/src/pages/SelectLevelPage/SelectLevelPage.module.css
index 390ac0def..56664b005 100644
--- a/src/pages/SelectLevelPage/SelectLevelPage.module.css
+++ b/src/pages/SelectLevelPage/SelectLevelPage.module.css
@@ -21,7 +21,7 @@
color: #004980;
text-align: center;
font-variant-numeric: lining-nums proportional-nums;
- font-family: StratosSkyeng;
+ font-family: Roboto;
font-size: 40px;
font-style: normal;
font-weight: 400;
@@ -35,6 +35,10 @@
margin-top: 48px;
margin-bottom: 28px;
}
+.selected {
+ background: #56df8f; /* Цвет для выделенной кнопки */
+ color: #fff; /* Цвет текста для выделенной кнопки */
+}
.level {
display: flex;
@@ -51,14 +55,88 @@
.levelLink {
color: #0080c1;
text-align: center;
- font-family: StratosSkyeng;
+ font-family: Roboto;
font-size: 64px;
font-style: normal;
font-weight: 400;
- line-height: 72px;
+ line-height: 97px;
text-decoration: none;
+ border-radius: 12px;
}
.levelLink:visited {
color: #0080c1;
}
+.easyMode {
+ font-family: Roboto;
+ font-size: 20px;
+}
+.easyMode::after {
+ content: "";
+ display: block;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%) scale(0);
+ width: 12px;
+ height: 12px;
+ background-color: blue;
+ border-radius: 3px;
+ transition: 0.3s;
+}
+.checkbox-input {
+ display: none;
+ &:checked + label .checkbox {
+ &:after {
+ transform: translate(-50%, -50%) scale(1);
+ }
+ }
+}
+.button {
+ width: 246px;
+ height: 48px;
+ margin: 15px;
+ border-radius: 12px;
+ background: #56df8f;
+
+ color: #fff;
+ text-align: center;
+ font-variant-numeric: lining-nums proportional-nums;
+
+ font-family: Roboto;
+ font-size: 24px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 32px;
+
+ border: none;
+
+ cursor: pointer;
+}
+
+.button:hover {
+ background: #00d41ccc;
+}
+
+.leaderBoardLinkBox {
+ color: red;
+ font-family: Roboto;
+ text-decoration: none;
+ text-transform: uppercase;
+ padding: 10px;
+}
+
+.leaderBoardLinkBox:hover {
+ text-decoration: underline;
+}
+
+.leaderBoardLinkBox:active {
+ color: black;
+}
+
+.leaderBoardLinkBox:visited {
+ color: purple;
+}
+.LeaderBoardGlob {
+ margin: 15px;
+}
diff --git a/src/router.js b/src/router.js
index da6e94b51..7740fee09 100644
--- a/src/router.js
+++ b/src/router.js
@@ -1,6 +1,7 @@
import { createBrowserRouter } from "react-router-dom";
import { GamePage } from "./pages/GamePage/GamePage";
import { SelectLevelPage } from "./pages/SelectLevelPage/SelectLevelPage";
+import { LeaderBoardPage } from "./pages/LeaderBoardPage/LeaderBoardPage";
export const router = createBrowserRouter(
[
@@ -9,13 +10,17 @@ export const router = createBrowserRouter(
element: ,
},
{
- path: "/game/:pairsCount",
+ path: "/game/:pairsCount/:isGameMode",
element: ,
},
+ {
+ path: "/LeaderBoard",
+ element: ,
+ },
],
- /**
- * basename нужен для корректной работы в gh pages
- * он же указан в homepage package.json и в index.html
- */
- { basename: "/react-memo" },
+ {
+ // basename нужен для корректной работы в gh pages
+ // он же указан в homepage package.json и в index.html
+ basename: "/react-memo",
+ },
);