add styles

This commit is contained in:
Sergey Krylov 2022-07-26 08:21:40 +05:00
parent 9ab31e6c35
commit 534e185c55
16 changed files with 143 additions and 46 deletions

View File

@ -1,14 +1,14 @@
@import url('https://fonts.googleapis.com/css2?family=Pacifico&display=swap');
.CardWrapper{
.CardWrapper {
display: flex;
align-items: center;
justify-content: center;
transition: opacity 1300ms ease-in;
.Card {
width: 100px;
height: 100px;
width: 80px;
height: 80px;
font-family: 'Pacifico', sans-serif;
font-size: 48px;
display: flex;
@ -56,3 +56,13 @@
}
@media(max-width: 400px) {
.CardWrapper {
.Card {
width: 50px;
height: 50px;
}
}
}

View File

@ -3,15 +3,8 @@
position: relative;
border: 2px solid #fff;
border-radius: 10px;
width: 500px;
height: 500px;
min-height: 500px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-auto-flow: row;
grid-template-areas:
". . ."
". . ."
". . ."
". . .";
gap: 15px;
padding: 20px;
}

View File

@ -1,3 +1,4 @@
import { DiffLevel, FieldSize } from 'pages/Options/Options';
import React, { useCallback, useEffect, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
@ -34,7 +35,7 @@ const CardsField: React.FC<CardsFieldProps> = ({cards, isGameStarted = false, fi
const [cardsState, setCardsState] = useState<CardComponentProps[]>(getInitialConfig(isNewGame));
const [currentCardPare, setCurrentCardPare] = useState<CurrentCardPareType>({first: null, second: null})
const {addMistakesCount} = useMatchGame();
const {addMistakesCount, filedSize, diffLevel} = useMatchGame();
function getInitialConfig(isNewGame: boolean): CardComponentProps[] {
if (!isNewGame) {
@ -142,8 +143,25 @@ const CardsField: React.FC<CardsFieldProps> = ({cards, isGameStarted = false, fi
));
}
function getStyles(): React.CSSProperties {
const size = {
gridTemplateColumns: '',
gridTemplateRows: '',
};
if (diffLevel === DiffLevel.Easy) size.gridTemplateColumns = 'repeat(3, 1fr)';
if (diffLevel === DiffLevel.Normal) size.gridTemplateColumns = 'repeat(4, 1fr)';
if (diffLevel === DiffLevel.Hard) size.gridTemplateColumns = 'repeat(5, 1fr)';
if (filedSize === FieldSize.Small) size.gridTemplateRows = 'repeat(2, 1fr)';
if (filedSize === FieldSize.Normal) size.gridTemplateRows = 'repeat(4, 1fr)';
if (filedSize === FieldSize.Big) size.gridTemplateRows = 'repeat(6, 1fr)';
return size;
}
return (
<div className={cls.CardsField}>
<div className={cls.CardsField} style={getStyles()}>
{renderCards()}
</div>
);

View File

@ -0,0 +1,4 @@
.Button {
width: 45px;
height: 45px;
}

View File

@ -0,0 +1,20 @@
import React from 'react';
import Button from 'components/UI/Button/Button';
import { useMatchGame } from 'context/MatchGameContext';
import cls from './GoToMenuButton.module.scss';
const GoToMenuButton = () => {
const {setCurrentMenuItem, setIsGameStarted} = useMatchGame();
function onClickHandler() {
setIsGameStarted?.(false);
setCurrentMenuItem?.('menu')
}
return (
<Button className={cls.Button} onClick={onClickHandler}>&#8678;</Button>
);
};
export default GoToMenuButton;

View File

@ -7,5 +7,6 @@
align-items: center;
border: 2px solid #fff;
border-radius: 10px;
max-width: 100%;
}

View File

@ -2,11 +2,13 @@ import React from 'react';
import cls from './BottomPanel.module.scss';
type BottomPanelProps = {}
type BottomPanelProps = {
style?: React.CSSProperties;
}
const BottomPanel: React.FC<BottomPanelProps> = ({children}) => {
const BottomPanel: React.FC<BottomPanelProps> = ({children, style}) => {
return (
<div className={cls.BottomPanel}>
<div className={cls.BottomPanel} style={style}>
{ children }
</div>
);

View File

@ -9,18 +9,32 @@
font-size: 22px;
text-transform: uppercase;
text-align: center;
letter-spacing: 3px;
font-weight: 600;
color: #524f4e;
background: white;
box-shadow: 0 8px 15px rgba(0, 0, 0, .1);
transition: .3s;
&:hover, &:focus {
&:hover {
background: #7986cb;
box-shadow: 0 15px 20px rgba(121, 134, 203, 0.4);
color: white;
transform: translateY(-7px);
cursor: pointer;
}
&:active {
color: #524f4e;
transform: translateY(-5px);
}
}
@media (max-width: 400px) {
.Button {
width: 120px;
margin: 5px;
font-size: 20px;
letter-spacing: normal;
padding: 0;
}
}

View File

@ -3,12 +3,13 @@ import cls from './Button.module.scss';
type ButtonProps = {
className?: string,
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
style?: React.CSSProperties;
}
const Button: React.FC<ButtonProps> = ({children, className, onClick}) => {
const Button: React.FC<ButtonProps> = ({children, className, style, onClick}) => {
return (
<button className={[cls.Button, className].join(' ')} onClick={onClick}>
<button className={[cls.Button, className].join(' ')} style={style} onClick={onClick}>
{children}
</button>
);

View File

@ -22,21 +22,43 @@ interface MatchGameContextType {
const MatchGameContext = React.createContext<MatchGameContextType>({});
export const useMatchGame = () => useContext(MatchGameContext);
function getInitialSize() {
const sizeFromLocalStorage = localStorage.getItem('match-game:size');
return sizeFromLocalStorage ? JSON.parse(sizeFromLocalStorage) : FieldSize.Small;
}
function getInitialDiffLevel() {
const diffLevelFromLocalStorage = localStorage.getItem('match-game:diffLevel');
return diffLevelFromLocalStorage ? JSON.parse(diffLevelFromLocalStorage) : DiffLevel.Easy;
}
function getInitialTime() {
const timeFromLocalStorage = localStorage.getItem('match-game:time');
return timeFromLocalStorage ? JSON.parse(timeFromLocalStorage) : 0;
}
function getInitialMistakesCount() {
const mistakesCountFromLocalStorage = localStorage.getItem('match-game:mistakesCount');
return mistakesCountFromLocalStorage ? JSON.parse(mistakesCountFromLocalStorage) : 0;
}
export const MatchGameProvider: React.FC = ({children}) => {
const [mistakesCount, setMistakesCount] = useState(0)
const [gameTime, setGameTime] = useState(0);
const [mistakesCount, setMistakesCount] = useState<number>(getInitialMistakesCount)
const [gameTime, setGameTime] = useState<number>(getInitialTime);
const [currentMenuItem, setCurrentMenuItem] = useState<MenuItem>('menu');
const [isGameStarted, setIsGameStarted] = useState(false);
const [isGameFinished, setIsGameFinished] = useState(false);
const [filedSize, setFieldSize] = useState(FieldSize.Small);
const [diffLevel, setDiffLevel] = useState(DiffLevel.Easy);
const [filedSize, setFieldSize] = useState<number>(getInitialSize);
const [diffLevel, setDiffLevel] = useState<number>(getInitialDiffLevel);
const addMistakesCount = () => {
localStorage.setItem('match-game:mistakesCount', JSON.stringify(mistakesCount + 1));
return setMistakesCount(prev => prev + 1)
};
const changeGameTime = (time: number) => {
setGameTime(time);
localStorage.setItem('match-game:time', JSON.stringify(time));
}
const resetGameProgress = () => {
@ -44,12 +66,18 @@ export const MatchGameProvider: React.FC = ({children}) => {
setGameTime(0);
setIsGameStarted(false);
setIsGameFinished(false);
localStorage.removeItem('match-game:cards');
localStorage.removeItem('match-game:time');
localStorage.removeItem('match-game:mistakesCount');
}
const saveOptions = (options: OptionsType) => {
setFieldSize(options.size);
setDiffLevel(options.diffLevel);
localStorage.setItem('match-game:size', JSON.stringify(options.size));
localStorage.setItem('match-game:diffLevel', JSON.stringify(options.diffLevel));
}
return (

View File

@ -0,0 +1,4 @@
.MatchGameField {
width: 500px;
max-width: 100%;
}

View File

@ -1,3 +1,4 @@
import GoToMenuButton from 'components/GoToMenuButton/GoToMenuButton';
import React, { useEffect, useState } from 'react';
import BottomPanel from 'components/UI/BottomPanel/BottomPanel';
import Button from 'components/UI/Button/Button';
@ -7,6 +8,8 @@ import Timer from 'components/UI/Timer/Timer';
import { createCards, randomizeElementInArray } from 'src/utils';
import { useMatchGame } from 'context/MatchGameContext';
import cls from './MatchGame.module.scss';
interface MatchGameProps {
isNewGame: boolean;
}
@ -22,7 +25,6 @@ const MatchGame: React.FC<MatchGameProps> = ({isNewGame}) => {
isGameFinished,
isGameStarted,
changeGameTime,
setCurrentMenuItem,
diffLevel,
filedSize
} = useMatchGame();
@ -51,12 +53,10 @@ const MatchGame: React.FC<MatchGameProps> = ({isNewGame}) => {
}
function retryGame() {
setIsGameFinished?.(false);
setIsGameStarted?.(false);
setIsTimerStarted?.(false);
setCards(prev => randomizeElementInArray(prev.map(el => ({...el, disabled: true, isMatched: false, toggled: true}))))
resetGameProgress?.();
setCards(prev => randomizeElementInArray(prev.map(el => ({...el, disabled: true, isMatched: false, toggled: true}))))
}
function finishGame() {
@ -68,15 +68,10 @@ const MatchGame: React.FC<MatchGameProps> = ({isNewGame}) => {
setCards(randomizeElementInArray([...cards]));
}
function goToMenu() {
setIsGameStarted?.(false);
setCurrentMenuItem?.('menu');
}
function renderRetryStatePanel() {
return (
<>
<Button onClick={goToMenu}>&#8678;</Button>
<GoToMenuButton/>
<Button onClick={retryGame}>RETRY</Button>
</>
)
@ -85,12 +80,12 @@ const MatchGame: React.FC<MatchGameProps> = ({isNewGame}) => {
function renderStartStatePanel() {
return isTimerStarted
? <>
<Button onClick={goToMenu}>&#8678;</Button>
<GoToMenuButton/>
<Timer isStarted={isTimerStarted} startTime={gameTime || 0} isFinished={isTimerStopped} changeTime={changeGameTime}/>
</>
: <>
<Button onClick={goToMenu}>&#8678;</Button>
<Button onClick={startGame}>{isNewGame ? 'START' : 'Continue'}</Button>
<GoToMenuButton/>
<Button style={{width: 'auto', minWidth: '120px'}} onClick={startGame}>{isNewGame ? 'START' : 'CONTINUE'}</Button>
{isNewGame && <Button onClick={shuffleCards}>SHUFFLE</Button>}
</>
}
@ -109,7 +104,7 @@ const MatchGame: React.FC<MatchGameProps> = ({isNewGame}) => {
}
return (
<>
<div className={cls.MatchGameField}>
<div style={{marginBottom: 20}}>
{
isGameFinished
@ -117,10 +112,10 @@ const MatchGame: React.FC<MatchGameProps> = ({isNewGame}) => {
: <CardsField cards={cards} isGameStarted={isGameStarted} finishGameCallback={finishGame} isNewGame={isNewGame}/>
}
</div>
<BottomPanel>
<BottomPanel style={{width: '100%'}}>
{ renderPanelByState(panelState) }
</BottomPanel>
</>
</div>
);
};

View File

@ -9,6 +9,7 @@
ul {
list-style: none;
margin: 0;
padding: 0;
li {
text-align: center;
cursor: pointer;

View File

@ -25,6 +25,9 @@ const MatchMenu: React.FC<GameMenuProps> = () => {
function clickItemHandler(item: MenuItem) {
setCurrentMenuItem?.(item);
if (item === 'exit') {
window.location = 'https://google.com' as any;
}
}
function canContinueGame() {

View File

@ -9,10 +9,12 @@
border-radius: 10px;
color: #ffffff;
margin-bottom: 20px;
max-width: 100%;
ul {
list-style: none;
margin: 0;
padding: 0;
}
h2 {
@ -24,7 +26,7 @@
display: flex;
justify-content: space-between;
align-items: center;
font-size: 30px;
font-size: 1.5rem;
.button {
width: 45px;

View File

@ -1,3 +1,4 @@
import GoToMenuButton from 'components/GoToMenuButton/GoToMenuButton';
import BottomPanel from 'components/UI/BottomPanel/BottomPanel';
import Button from 'components/UI/Button/Button';
import { useMatchGame } from 'context/MatchGameContext';
@ -62,7 +63,7 @@ const Options: React.FC = () => {
</ul>
</div>
<BottomPanel>
<Button onClick={() => setCurrentMenuItem?.('menu')}>&#8678;</Button>
<GoToMenuButton/>
<Button onClick={saveOptionHandler}>Save</Button>
</BottomPanel>
</>