diff --git a/.eslintrc.json b/.eslintrc.json index e37e1e072..ef1409393 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,8 +3,8 @@ "plugins": ["prettier"], "rules": { "camelcase": ["error", { "properties": "never" }], - "prettier/prettier": "error", + "prettier/prettier": ["error", { "endOfLine": "auto" }], "eqeqeq": ["error", "always"], "no-unused-vars": ["error"] } -} +} \ No newline at end of file diff --git a/README.md b/README.md index 9b90842c4..ed2cc1b75 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,47 @@ +# Домашняя работа 1" + +Добавление нового режима: реализовать режим, при котором игра завершается после трех ошибок. + +Включение режима: режим должен включаться с помощью чек-бокса на странице выбора уровня. + +Счетчик ошибок: нужно добавить вывод количества оставшихся попыток на игровой экран («Осталось 3 попытки» и так далее). + +Отображение: внешний вид и расположение элементов остаются на ваше усмотрение, но выбор должен быть логически обоснован. + +Конец игры: при достижении трех ошибок должно появляться модальное окно о завершении игры, его можно взять из макета. + +Ожидаемое время выполнения работы: 4 часа +Фактическое время выполнения работы: 6 часов + + + + +# Домашняя работа 2" +Создание страницы "Лидерборд": Требуется разработать новую страницу в игре, которая будет носить название "Лидерборд". Формат отображения нужно взять из макета. + +Отображение “Лидерборда”: На странице должны отображаться результаты пользователей в порядке возрастания по времени, затраченному на успешное прохождение игры. + +Результат игры: Если результат игры проходит в "Лидерборд по ТОП-3, то в модальном окне нужно запросить имя пользователя и указать затраченное на игру время. Формат отображения нужно взять из макета. + +Если пользователь не проходит в “Лидерборд”, однако он выиграл, то показываем ему модальное окно победы (уже реализовано в приложении). +Отображение модального окна проигрыша остается без изменений. +Страница выбора сложности: На страницу выбора сложности нужно добавить ссылку, которая ведет на страницу лидерборда. Отображение нужно взять из макета. + +Ожидаемое время выполнения работы: 6 часа +Фактическое время выполнения работы: 8 часов + + + +# Курсовая работа" +Часть 1. Создание суперсил +Нужно создать и внедрить систему суперсил, которые будут действовать как упрощения или подсказки для игрока. Например, если игрок открывает неправильную карту, суперсила будет автоматически открывать соседнюю правильную пару. Подробная информация — в техническом задании. Для зачтения работы достаточно реализовать минимум одну из суперсил. + +Часть 2. Доработка лидерборда +Добавьте к каждой позиции в лидерборде ачивки. Например, если пользователь прошел игру без использования суперсил или в сложном режиме. Подробная информация — в техническом задании. + +Ожидаемое время выполнения работы: 8 часа +Фактическое время выполнения работы: часов + # MVP Карточная игра "Мемо" В этом репозитории реализован MVP карточкой игры "Мемо" по [тех.заданию](./docs/mvp-spec.md) diff --git a/docs/mvp-spec.md b/docs/mvp-spec.md index fab47685e..e083d7788 100644 --- a/docs/mvp-spec.md +++ b/docs/mvp-spec.md @@ -14,9 +14,10 @@ Количество карточек для каждого уровня сложности можете назначать и свои или выбрать готовый пресет. Предлагаем следующее пресеты: - - Легкий уровень - 6 карточек (3 пары) - - Средний уровень - 12 карточек (6 пар) - - Сложный уровень - 18 карточек (9 пар) + +- Легкий уровень - 6 карточек (3 пары) +- Средний уровень - 12 карточек (6 пар) +- Сложный уровень - 18 карточек (9 пар) Как только уровень сложности выбран, игроку показывается на игровой поле. diff --git a/src/api.js b/src/api.js new file mode 100644 index 000000000..cf670dc7c --- /dev/null +++ b/src/api.js @@ -0,0 +1,26 @@ +const baseHost = "https://wedev-api.sky.pro/api/v2/leaderboard"; +//Получаем список лидеров +export async function getLeaders() { + const response = await fetch(baseHost); + if (!response.status === 200) { + throw new Error("Ошибка"); + } + const data = await response.json(); + return data; +} +//Добавляем лидера в список +export async function postLeader({ name, time, achievements }) { + const response = await fetch(baseHost, { + method: "POST", + body: JSON.stringify({ + name: name, + time: time, + achievements: achievements, + }), + }); + if (response.status === 400) { + throw new Error("Полученные данные не в формате JSON"); + } + const data = await response.json(); + return data; +} diff --git a/src/components/Achievment/Achievment.jsx b/src/components/Achievment/Achievment.jsx new file mode 100644 index 000000000..5ea33c16a --- /dev/null +++ b/src/components/Achievment/Achievment.jsx @@ -0,0 +1,9 @@ +import unsuper1 from "./unsuper1.svg"; +import super1 from "./super1.svg"; + +export default function Achievment(isAchievment) { + console.log(Object.values(isAchievment)[2].isAchievment); + return ( + <>{Object.values(isAchievment)[2].isAchievment ? : } + ); +} diff --git a/src/components/Achievment/super1.svg b/src/components/Achievment/super1.svg new file mode 100644 index 000000000..3ee152c69 --- /dev/null +++ b/src/components/Achievment/super1.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/components/Achievment/unsuper1.svg b/src/components/Achievment/unsuper1.svg new file mode 100644 index 000000000..934c9486e --- /dev/null +++ b/src/components/Achievment/unsuper1.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index 7526a56c8..a213efbf6 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 { useEasyMode } from "../../context/hooks/useEasyMode"; +import superImg from "./super.png"; // Игра закончилась const STATUS_LOST = "STATUS_LOST"; @@ -41,6 +43,9 @@ function getTimerValue(startDate, endDate) { * previewSeconds - сколько секунд пользователь будет видеть все карты открытыми до начала игры */ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { + const [achievements, setAchievements] = useState([]); + const { easyMode } = useEasyMode(); + const [countTry, setCountTry] = useState(null); // В cards лежит игровое поле - массив карт и их состояние открыта\закрыта const [cards, setCards] = useState([]); // Текущий статус игры @@ -63,6 +68,7 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { } function startGame() { const startDate = new Date(); + setCountTry(easyMode ? 3 : 1); setGameEndDate(null); setGameStartDate(startDate); setTimer(getTimerValue(startDate, null)); @@ -82,17 +88,32 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { * - "Игрок проиграл", если на поле есть две открытые карты без пары * - "Игра продолжается", если не случилось первых двух условий */ + function alohomora() { + if (achievements.includes(1)) { + 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([1]); + } + const openCard = clickedCard => { // Если карта уже открыта, то ничего не делаем if (clickedCard.open) { return; } // Игровое поле после открытия кликнутой карты - const nextCards = cards.map(card => { + let nextCards = cards.map(card => { if (card.id !== clickedCard.id) { return card; } - return { ...card, open: true, @@ -123,15 +144,23 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { return false; }); - const playerLost = openCardsWithoutPair.length >= 2; + if (openCardsWithoutPair.length >= 2) { + setTimeout(() => { + openCardsWithoutPair[1].open = false; + openCardsWithoutPair[0].open = false; + }, 1000); + setCountTry(countTry - 1); - // "Игрок проиграл", т.к на поле есть две открытые карты без пары - if (playerLost) { - finishGame(STATUS_LOST); - return; - } + const playerLost = countTry === 1; - // ... игра продолжается + // "Игрок проиграл", т.к на поле есть две открытые карты без пары + if (playerLost) { + finishGame(STATUS_LOST); + return; + } + + // ... игра продолжается + } }; const isGameEnded = status === STATUS_LOST || status === STATUS_WON; @@ -195,7 +224,13 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { )} - {status === STATUS_IN_PROGRESS ? : null} + {status === STATUS_IN_PROGRESS ? ( + <> +
{easyMode && `Осталось попыток ${countTry}`}
+ super + + + ) : null}
@@ -216,6 +251,7 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { isWon={status === STATUS_WON} gameDurationSeconds={timer.seconds} gameDurationMinutes={timer.minutes} + achievements={achievements} onClick={resetGame} />
diff --git a/src/components/Cards/Cards.module.css b/src/components/Cards/Cards.module.css index 000c5006c..7fffcf0ce 100644 --- a/src/components/Cards/Cards.module.css +++ b/src/components/Cards/Cards.module.css @@ -1,5 +1,5 @@ .container { - width: 672px; + width: 700px; margin: 0 auto; padding: 26px; padding-top: 22px; @@ -11,6 +11,7 @@ flex-direction: row; gap: 10px; flex-wrap: wrap; + justify-content: space-between; } .modalContainer { @@ -70,3 +71,12 @@ margin-bottom: -12px; } + +.count { + color: #fff; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 16px; + font-style: normal; + margin-right: 10px; +} diff --git a/src/components/Cards/super.png b/src/components/Cards/super.png new file mode 100644 index 000000000..597a8a446 Binary files /dev/null and b/src/components/Cards/super.png differ diff --git a/src/components/EndGameModal/EndGameModal.jsx b/src/components/EndGameModal/EndGameModal.jsx index 722394833..f4e87f89f 100644 --- a/src/components/EndGameModal/EndGameModal.jsx +++ b/src/components/EndGameModal/EndGameModal.jsx @@ -1,12 +1,51 @@ import styles from "./EndGameModal.module.css"; - import { Button } from "../Button/Button"; - import deadImageUrl from "./images/dead.png"; import celebrationImageUrl from "./images/celebration.png"; +import { useState, useEffect } from "react"; +import { postLeader } from "../../api"; +import { useLeaders } from "../../context/hooks/useLeaders"; +import { Link } from "react-router-dom"; + +export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, achievements, onClick }) { + const [newLeader, setNewLeader] = useState({ + name: "", + time: gameDurationSeconds, + achievements: achievements, + }); + const { setLeaders, leaders } = useLeaders(); + const [btnDisabled, setBtnDisabled] = useState(false); -export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, onClick }) { - const title = isWon ? "Вы победили!" : "Вы проиграли!"; + useEffect(() => { + setLeaders(leaders.sort((a, b) => +a.time - +b.time)); + }, [leaders, setLeaders]); + + const handleInputChange = e => { + const { name, value } = e.target; + setNewLeader({ + ...newLeader, + [name]: value, + }); + }; + const handleFormSubmit = e => { + e.preventDefault(); + postLeader({ name: newLeader.name, time: newLeader.time, achievements: newLeader.achievements }) + .then(leaders => { + setLeaders(leaders.leaders); + setBtnDisabled(!btnDisabled); + // Добавьте код для очистки поля ввода + setNewLeader({ name: "", time: "", achievements: "" }); + }) + .catch(error => { + console.log(error); + alert(error); + }); + }; + let title = isWon ? "Вы победили!" : "Вы проиграли!"; + if (gameDurationMinutes * 60 + gameDurationSeconds < leaders[2].time && isWon) { + title = "Вы попали на лидерборд!"; + } + let isLeader = gameDurationMinutes * 60 + gameDurationSeconds < leaders[2].time && isWon; const imgSrc = isWon ? celebrationImageUrl : deadImageUrl; @@ -16,12 +55,34 @@ export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes,
{imgAlt}

{title}

+ {isLeader && ( +
+ + +
+ )}

Затраченное время:

{gameDurationMinutes.toString().padStart("2", "0")}.{gameDurationSeconds.toString().padStart("2", "0")}
- + +
+ +

Перейти к лидерборду

+ +
); } diff --git a/src/components/EndGameModal/EndGameModal.module.css b/src/components/EndGameModal/EndGameModal.module.css index 9368cb8b5..b3da4a9ca 100644 --- a/src/components/EndGameModal/EndGameModal.module.css +++ b/src/components/EndGameModal/EndGameModal.module.css @@ -19,7 +19,7 @@ color: #004980; font-variant-numeric: lining-nums proportional-nums; font-family: StratosSkyeng; - font-size: 40px; + font-size: 35px; font-style: normal; font-weight: 400; line-height: 48px; @@ -49,3 +49,44 @@ margin-bottom: 40px; } + +.inputDiv { + display: flex; + gap: 5px; + } + + .btnsave { + + width: 150px; + height: 30px; + + border-radius: 12px; + background: #7ac100; + + color: #fff; + text-align: center; + font-variant-numeric: lining-nums proportional-nums; + + /* Pres → Caption S */ + font-family: StratosSkyeng; + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: 32px; /* 133.333% */ + + border: none; + + cursor: pointer; + + + } + + .btnsave:hover { + background: #7ac100cc; + } + + .inputSave{ + border-radius: 8px; + border: #000; + padding-left: 10px; + } \ No newline at end of file diff --git a/src/components/ToolTip/ToolTip.module.css b/src/components/ToolTip/ToolTip.module.css new file mode 100644 index 000000000..0394b7b49 --- /dev/null +++ b/src/components/ToolTip/ToolTip.module.css @@ -0,0 +1,11 @@ +.toolTip{ + display: flex; + position: absolute; + height: 78px; + width: 174px; + color: black; + border-radius: 12px; + background-color: #C2F5FF; + text-align: center; + align-items: center; +} \ No newline at end of file diff --git a/src/components/ToolTip/ToolTipGame.jsx b/src/components/ToolTip/ToolTipGame.jsx new file mode 100644 index 000000000..8e36c7cce --- /dev/null +++ b/src/components/ToolTip/ToolTipGame.jsx @@ -0,0 +1,46 @@ +import { useRef, useState } from "react"; +import styles from "./ToolTip.module.css"; +import unsuper1 from "./unsuper1.svg"; +import super1 from "./super1.svg"; + +export default function ToolTipGame(isAchievment, i) { + const [showToolTip, setShowToolTip] = useState(false); + const refSetTimeout = useRef(); + + const onMouseEnterHandler = () => { + refSetTimeout.current = setTimeout(() => { + setShowToolTip(true); + }, 750); + }; + + const onMouseLeaveHandler = () => { + clearTimeout(refSetTimeout.current); + setShowToolTip(false); + }; + + return ( + <> + {Object.values(isAchievment)[0] ? ( + <> + + {showToolTip && ( +
+ {" "} +

Игра пройдена в сложном режиме

{" "} +
+ )} + + ) : ( + <> + + {showToolTip && ( +
+ {" "} +

Игра пройдена в сложном режиме

{" "} +
+ )} + + )} + + ); +} diff --git a/src/components/ToolTip/ToolTipSuper.jsx b/src/components/ToolTip/ToolTipSuper.jsx new file mode 100644 index 000000000..e9f827b0f --- /dev/null +++ b/src/components/ToolTip/ToolTipSuper.jsx @@ -0,0 +1,38 @@ +import { useRef, useState } from "react"; +import styles from "./ToolTip.module.css"; + +import unsuper2 from "./unsuper2.svg"; +import super2 from "./super2.svg"; + +export default function ToolTipSuper(isAchievment) { + const [showToolTip, setShowToolTip] = useState(false); + const refSetTimeout = useRef(); + + const onMouseEnterHandler = () => { + refSetTimeout.current = setTimeout(() => { + setShowToolTip(true); + }, 750); + console.log(isAchievment); + }; + + const onMouseLeaveHandler = () => { + clearTimeout(refSetTimeout.current); + setShowToolTip(false); + }; + + return ( + <> + {Object.values(isAchievment)[0] ? ( + <> + + {showToolTip &&
Игра пройдена без супер сил
} + + ) : ( + <> + + {showToolTip &&
Игра пройдена без супер сил
} + + )} + + ); +} diff --git a/src/components/ToolTip/super1.svg b/src/components/ToolTip/super1.svg new file mode 100644 index 000000000..3ee152c69 --- /dev/null +++ b/src/components/ToolTip/super1.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/components/ToolTip/super2.svg b/src/components/ToolTip/super2.svg new file mode 100644 index 000000000..7949f73ed --- /dev/null +++ b/src/components/ToolTip/super2.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/ToolTip/unsuper1.svg b/src/components/ToolTip/unsuper1.svg new file mode 100644 index 000000000..934c9486e --- /dev/null +++ b/src/components/ToolTip/unsuper1.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/components/ToolTip/unsuper2.svg b/src/components/ToolTip/unsuper2.svg new file mode 100644 index 000000000..f0976a430 --- /dev/null +++ b/src/components/ToolTip/unsuper2.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/context/Leaders.jsx b/src/context/Leaders.jsx new file mode 100644 index 000000000..8995a0409 --- /dev/null +++ b/src/context/Leaders.jsx @@ -0,0 +1,8 @@ +import { createContext, useState } from "react"; + +export const LeadersContext = createContext(null); +export const LeadersProvider = ({ children }) => { + const [leaders, setLeaders] = useState(); + + return {children}; +}; diff --git a/src/context/easyMode.jsx b/src/context/easyMode.jsx new file mode 100644 index 000000000..1d1825497 --- /dev/null +++ b/src/context/easyMode.jsx @@ -0,0 +1,14 @@ +import { createContext, useState } from "react"; + +export const EasyModeContext = createContext(null); +export const EasyModeProvider = ({ children }) => { + const [easyMode, setEasyMode] = useState(false); + const easyModeSelect = () => { + setEasyMode(!easyMode); + console.log(easyMode); + }; + + return ( + {children} + ); +}; diff --git a/src/context/hooks/useEasyMode.js b/src/context/hooks/useEasyMode.js new file mode 100644 index 000000000..18d05bd2c --- /dev/null +++ b/src/context/hooks/useEasyMode.js @@ -0,0 +1,6 @@ +import { useContext } from "react"; +import { EasyModeContext } from "../easyMode"; + +export function useEasyMode() { + return useContext(EasyModeContext); +} diff --git a/src/context/hooks/useLeaders.js b/src/context/hooks/useLeaders.js new file mode 100644 index 000000000..45efa7c68 --- /dev/null +++ b/src/context/hooks/useLeaders.js @@ -0,0 +1,6 @@ +import { useContext } from "react"; +import { LeadersContext } from "../Leaders"; + +export function useLeaders() { + return useContext(LeadersContext); +} diff --git a/src/index.js b/src/index.js index f689c5f0b..c14da6fc5 100644 --- a/src/index.js +++ b/src/index.js @@ -3,10 +3,16 @@ import ReactDOM from "react-dom/client"; import "./index.css"; import { RouterProvider } from "react-router-dom"; import { router } from "./router"; +import { EasyModeProvider } from "./context/easyMode"; +import { LeadersProvider } from "./context/Leaders"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - + + + + + , ); diff --git a/src/pages/LeaderboardPage/LeaderboardPage.jsx b/src/pages/LeaderboardPage/LeaderboardPage.jsx new file mode 100644 index 000000000..ba98d053c --- /dev/null +++ b/src/pages/LeaderboardPage/LeaderboardPage.jsx @@ -0,0 +1,57 @@ +import { Link } from "react-router-dom"; +import { Button } from "../../components/Button/Button"; +import styles from "./LeaderboardPage.module.css"; +import { useLeaders } from "../../context/hooks/useLeaders"; +import ToolTipGame from "../../components/ToolTip/ToolTipGame"; +import ToolTipSuper from "../../components/ToolTip/ToolTipSuper"; + +export function LeaderboardPage() { + const { leaders, setLeaders } = useLeaders(); + setLeaders(leaders.sort((a, b) => +a.time - +b.time)); + let leadersAchievments = leaders.map(leader => leader.achievements); + + console.log(leadersAchievments); + return ( +
+
+

Лидерборд

+ + + +
+
+
+
+

Позиция

+
+
+

Пользователь

+
+
+
Достижения
+
+
+

Время

+
+
+ {leaders.map((leader, i) => ( +
+
+

{leaders.indexOf(leader) + 1}

+
+
+

{leader.name}

+
+
+ + +
+
+

{leader.time}

+
+
+ ))} +
+
+ ); +} diff --git a/src/pages/LeaderboardPage/LeaderboardPage.module.css b/src/pages/LeaderboardPage/LeaderboardPage.module.css new file mode 100644 index 000000000..1298923b6 --- /dev/null +++ b/src/pages/LeaderboardPage/LeaderboardPage.module.css @@ -0,0 +1,42 @@ +.title { + font-family: Roboto; + font-size: 24px; + font-weight: 400; + line-height: 32px; + text-align: left; + width: 127px; + height: 32px; + top: 61px; + left: 40px; + gap: 0px; + opacity: 0px; + color: white; + +} + +.header { + display: flex; + justify-content: space-between; + padding: 20px; +} + +.block { + display: flex; + justify-content: space-between; + background-color: white; + border-radius: 12px; + margin: 5px; + height: 30px; + align-items: center; +} + +.name { + padding-left: 50px; + padding-right: 50px; +} + +.grid { + width: 300px; + display: flex; + justify-content: space-evenly; +} \ No newline at end of file diff --git a/src/pages/LeaderboardPage/super1.svg b/src/pages/LeaderboardPage/super1.svg new file mode 100644 index 000000000..3ee152c69 --- /dev/null +++ b/src/pages/LeaderboardPage/super1.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/pages/LeaderboardPage/super2.svg b/src/pages/LeaderboardPage/super2.svg new file mode 100644 index 000000000..7949f73ed --- /dev/null +++ b/src/pages/LeaderboardPage/super2.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pages/LeaderboardPage/unsuper1.svg b/src/pages/LeaderboardPage/unsuper1.svg new file mode 100644 index 000000000..934c9486e --- /dev/null +++ b/src/pages/LeaderboardPage/unsuper1.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/pages/LeaderboardPage/unsuper2.svg b/src/pages/LeaderboardPage/unsuper2.svg new file mode 100644 index 000000000..f0976a430 --- /dev/null +++ b/src/pages/LeaderboardPage/unsuper2.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/pages/SelectLevelPage/SelectLevelPage.jsx b/src/pages/SelectLevelPage/SelectLevelPage.jsx index 758942e51..e5022b6cc 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.jsx +++ b/src/pages/SelectLevelPage/SelectLevelPage.jsx @@ -1,10 +1,25 @@ import { Link } from "react-router-dom"; import styles from "./SelectLevelPage.module.css"; +import { useEasyMode } from "../../context/hooks/useEasyMode"; +import { getLeaders } from "../../api"; +import { useLeaders } from "../../context/hooks/useLeaders"; +import { useEffect } from "react"; export function SelectLevelPage() { + const { setLeaders } = useLeaders(); + const { easyModeSelect } = useEasyMode(); + useEffect(() => { + getLeaders().then(response => { + setLeaders(response.leaders); + }); + }, [setLeaders]); return (
+
+ + +

Выбери сложность

+
+ +

Перейти к лидерборду

+ +
); diff --git a/src/pages/SelectLevelPage/SelectLevelPage.module.css b/src/pages/SelectLevelPage/SelectLevelPage.module.css index 390ac0def..b10315eb7 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.module.css +++ b/src/pages/SelectLevelPage/SelectLevelPage.module.css @@ -46,6 +46,7 @@ border-radius: 12px; background: #fff; + cursor: pointer; } .levelLink { @@ -62,3 +63,36 @@ .levelLink:visited { color: #0080c1; } + +.toggleSwitch { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 30px; + + input[type="checkbox"] { + position: relative; + width: 24px; + height: 13px; + border-radius: 100px; + background: #eaeef6; + outline: none; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } + input[type="checkbox"]::before { + content: ""; + position: absolute; + top: 1px; + left: 1px; + width: 11px; + height: 11px; + border-radius: 50%; + background-color: #94a6be; + transition: 0.5s; + } + input:checked[type="checkbox"]::before { + left: 12px; + } +} diff --git a/src/router.js b/src/router.js index da6e94b51..ecd8d90ae 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( [ @@ -12,6 +13,10 @@ export const router = createBrowserRouter( path: "/game/:pairsCount", element: , }, + { + path: "/leaderboard", + element: , + }, ], /** * basename нужен для корректной работы в gh pages