Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution of exercises #76

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9657db3
include outline none property
Camilo-Suarez98 Dec 29, 2023
a6e73bf
create input component
Camilo-Suarez98 Dec 29, 2023
7499ff0
include form in game component
Camilo-Suarez98 Dec 29, 2023
0cedab1
include validation in form
Camilo-Suarez98 Dec 29, 2023
f3d628c
include component to save all the words in the input
Camilo-Suarez98 Jan 2, 2024
d061e94
change quotes in class
Camilo-Suarez98 Jan 2, 2024
990b560
include state to save words in an array
Camilo-Suarez98 Jan 2, 2024
51a95c6
change way to save words in state
Camilo-Suarez98 Jan 2, 2024
c10b802
include a new function to save words typed in the input
Camilo-Suarez98 Jan 2, 2024
ae077e9
create new component to separate letters in word
Camilo-Suarez98 Jan 2, 2024
1806208
include guess component to replace map inside of component
Camilo-Suarez98 Jan 2, 2024
35ce284
create new component to manage style of cell
Camilo-Suarez98 Jan 3, 2024
3fbfa35
include prop inside of Previous word
Camilo-Suarez98 Jan 3, 2024
b909500
include cell component with props to validate word
Camilo-Suarez98 Jan 3, 2024
fd0862b
include answer prop to validate info
Camilo-Suarez98 Jan 3, 2024
81c5c6b
delete consoles from code
Camilo-Suarez98 Jan 3, 2024
60f32d6
create new component to show after end of game
Camilo-Suarez98 Jan 3, 2024
8047b22
include disable option if state isOver change
Camilo-Suarez98 Jan 3, 2024
1f82f7e
change some paddings to less values
Camilo-Suarez98 Jan 3, 2024
049d7b4
include validation is game over or user win
Camilo-Suarez98 Jan 3, 2024
c2dbbc2
include button style
Camilo-Suarez98 Jan 4, 2024
977f969
include reset button in main component
Camilo-Suarez98 Jan 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/components/Banner/Banner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';

function Banner({ isWinner, answer, words }) {
return (
<>
{isWinner ? (
<div className='banner happy'>
<p>
<strong>Congratulations!</strong> Got it in
{" "}
<strong>{words.length} guesses</strong>.
</p>
</div>
) : (
<div className='banner sad'>
<p>Sorry, the correct answer is <strong>{answer}</strong>.</p>
</div>
)}
</>
);
}

export default Banner;
2 changes: 2 additions & 0 deletions src/components/Banner/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Banner';
export { default } from './Banner';
9 changes: 9 additions & 0 deletions src/components/Cell/Cell.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';

function Cell({ letter, status }) {
const className = status ? `cell ${status}` : 'cell';

return <span className={className}>{letter}</span>;
}

export default Cell;
2 changes: 2 additions & 0 deletions src/components/Cell/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Cell';
export { default } from './Cell';
58 changes: 56 additions & 2 deletions src/components/Game/Game.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,69 @@
import React from 'react';
import React, { useState } from 'react';

import { sample } from '../../utils';
import { WORDS } from '../../data';
import Input from '../Input/Input';
import PreviousWord from '../PreviousWord/PreviousWord';
import Banner from '../Banner/Banner';

// Pick a random word on every pageload.
const answer = sample(WORDS);
// To make debugging easier, we'll log the solution in the console.
console.info({ answer });

function Game() {
return <>Put a game here!</>;
const [words, setWords] = useState([]);
const [isOver, setIsOver] = useState(false);
const [isWinner, setIsWinner] = useState(false);

const handleSaveWord = (input) => {
setWords([...words, input]);

if (answer === input.value) {
setIsWinner(true);
setIsOver(true);
} else if (words.length >= 5) {
setIsOver(true);
setIsWinner(false);
} else {
setIsOver(false);
}
};

const handleResetGame = () => {
const newGame = [];

setWords(newGame);
setIsOver(false);
window.location.reload();
};

return (
<>
<PreviousWord
words={words}
answer={answer}
/>
<Input
handleSaveWord={handleSaveWord}
isOver={isOver}
/>
<button
className='restart'
onClick={handleResetGame}
>
Restart
</button>
{isOver ?
<Banner
isWinner={isWinner}
answer={answer}
words={words}
/> :
undefined
}
</>
);
}

export default Game;
26 changes: 26 additions & 0 deletions src/components/Guess/Guess.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { range } from '../../utils';
import Cell from '../Cell/Cell';
import { checkGuess } from '../../game-helpers';

function Guess({ word, answer }) {
const result = checkGuess(word, answer);

return (
<p className="guess">
{
range(5).map(num => {
return (
<Cell
key={num}
letter={result ? result[num].letter : undefined}
status={result ? result[num].status : undefined}
/>
);
})
}
</p>
);
}

export default Guess;
2 changes: 2 additions & 0 deletions src/components/Guess/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Guess';
export { default } from './Guess';
42 changes: 42 additions & 0 deletions src/components/Input/Input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { useState } from 'react';

const Input = ({ handleSaveWord, isOver }) => {
const [tentativeGuess, setTentativeGuess] = useState('');

const handleSubmit = (e) => {
e.preventDefault();
if (tentativeGuess.length !== 5) {
alert('The word must be equal to 5 letters');
return;
};

const newWord = {
id: crypto.randomUUID(),
value: tentativeGuess
}

handleSaveWord(newWord);
setTentativeGuess('');
};

return (
<form
className='guess-input-wrapper'
onSubmit={handleSubmit}
>
<label htmlFor='guess-input'>Enter guess:</label>
<input
required
id='guess-input'
type='text'
disabled={isOver}
value={tentativeGuess}
onChange={event => {
setTentativeGuess(event.target.value.toUpperCase())
}}
/>
</form>
);
};

export default Input;
2 changes: 2 additions & 0 deletions src/components/Input/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Input';
export { default } from './Input';
18 changes: 18 additions & 0 deletions src/components/PreviousWord/PreviousWord.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import Guess from '../Guess/Guess';
import { NUM_OF_GUESSES_ALLOWED } from '../../constants';
import { range } from '../../utils';

function PreviousWord({ words, answer }) {
return (
<div className="guess-results">
{range(NUM_OF_GUESSES_ALLOWED).map(num => {
return (
<Guess key={num} word={words[num]?.value} answer={answer} />
);
})}
</div>
);
}

export default PreviousWord;
2 changes: 2 additions & 0 deletions src/components/PreviousWord/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './PreviousWord';
export { default } from './PreviousWord';
27 changes: 22 additions & 5 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
html {
overflow-y: scroll;

--game-spacing: 32px;
--game-spacing: 20px;
--header-height: 4rem;

--color-success: hsl(150deg 70% 30%);
Expand Down Expand Up @@ -77,17 +77,16 @@ h1 {
display: flex;
flex-direction: column;
gap: var(--game-spacing);
padding: var(--game-spacing) 32px;
padding: var(--game-spacing) 15px;
margin: 0 auto;
min-width: 250px;
max-width: min(500px, 58vh, 100%);
}

.guess-results {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
justify-content: flex-start;
}

.guess {
Expand All @@ -114,12 +113,15 @@ h1 {
.guess:first-of-type .cell:first-of-type {
--radius: 4px 0px 0px 0px;
}

.guess:first-of-type .cell:last-of-type {
--radius: 0px 4px 0px 0px;
}

.guess:last-of-type .cell:last-of-type {
--radius: 0px 0px 4px 0px;
}

.guess:last-of-type .cell:first-of-type {
--radius: 0px 0px 0px 4px;
}
Expand All @@ -129,11 +131,13 @@ h1 {
border-color: var(--color-success);
color: white;
}

.cell.incorrect {
background: var(--color-gray-300);
border-color: var(--color-gray-300);
color: white;
}

.cell.misplaced {
background: var(--color-warning);
border-color: var(--color-warning);
Expand All @@ -159,6 +163,7 @@ h1 {
border-radius: 4px;
padding: 8px 16px;
outline-offset: 4px;
outline: none;
}

.banner {
Expand All @@ -180,6 +185,7 @@ h1 {
background: var(--color-success);
color: white;
}

.sad.banner {
background: var(--color-error);
color: white;
Expand Down Expand Up @@ -208,25 +214,36 @@ h1 {
border-radius: 8px;
padding: 24px 32px;
}

.modal-close-btn {
position: absolute;
top: 0;
right: 0;
padding: 16px;
cursor: pointer;
}

.modal-title {
margin-bottom: 0.5em;
}

.restart {
text-align: center;
padding: 10px 15px;
background-color: var(--color-gray-300);
color: #fff;
border-radius: var(--radius);
}

/*
Keyframe animations
*/
@keyframes slideUp {
from {
transform: translateY(100%);
}

to {
transform: translateY(0%);
}
}
}