Merge pull request #15 from HaithamLeo/enhancements
enhancement: apply prettier for automatic code formatting
This commit is contained in:
commit
26a6fb0ce9
31 changed files with 13357 additions and 13343 deletions
2
.prettierrc
Normal file
2
.prettierrc
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
singleQuote: true
|
||||||
|
semi: false
|
17
package-lock.json
generated
17
package-lock.json
generated
|
@ -18,6 +18,7 @@
|
||||||
"@types/react": "^17.0.38",
|
"@types/react": "^17.0.38",
|
||||||
"@types/react-dom": "^17.0.11",
|
"@types/react-dom": "^17.0.11",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
|
"prettier": "^2.5.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-scripts": "5.0.0",
|
"react-scripts": "5.0.0",
|
||||||
|
@ -12628,6 +12629,17 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin-prettier.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.13.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pretty-bytes": {
|
"node_modules/pretty-bytes": {
|
||||||
"version": "5.6.0",
|
"version": "5.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
|
||||||
|
@ -24849,6 +24861,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
|
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
|
||||||
},
|
},
|
||||||
|
"prettier": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg=="
|
||||||
|
},
|
||||||
"pretty-bytes": {
|
"pretty-bytes": {
|
||||||
"version": "5.6.0",
|
"version": "5.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^10.4.2",
|
"autoprefixer": "^10.4.2",
|
||||||
"postcss": "^8.4.5",
|
"postcss": "^8.4.5",
|
||||||
"tailwindcss": "^3.0.12"
|
"tailwindcss": "^3.0.12",
|
||||||
|
"prettier": "^2.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react'
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react'
|
||||||
import App from './App';
|
import App from './App'
|
||||||
|
|
||||||
test('renders learn react link', () => {
|
test('renders learn react link', () => {
|
||||||
render(<App />);
|
render(<App />)
|
||||||
const linkElement = screen.getByText(/learn react/i);
|
const linkElement = screen.getByText(/learn react/i)
|
||||||
expect(linkElement).toBeInTheDocument();
|
expect(linkElement).toBeInTheDocument()
|
||||||
});
|
})
|
||||||
|
|
92
src/App.tsx
92
src/App.tsx
|
@ -1,77 +1,77 @@
|
||||||
import { InformationCircleIcon } from "@heroicons/react/outline";
|
import { InformationCircleIcon } from '@heroicons/react/outline'
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from 'react'
|
||||||
import { Alert } from "./components/alerts/Alert";
|
import { Alert } from './components/alerts/Alert'
|
||||||
import { Grid } from "./components/grid/Grid";
|
import { Grid } from './components/grid/Grid'
|
||||||
import { Keyboard } from "./components/keyboard/Keyboard";
|
import { Keyboard } from './components/keyboard/Keyboard'
|
||||||
import { AboutModal } from "./components/modals/AboutModal";
|
import { AboutModal } from './components/modals/AboutModal'
|
||||||
import { InfoModal } from "./components/modals/InfoModal";
|
import { InfoModal } from './components/modals/InfoModal'
|
||||||
import { WinModal } from "./components/modals/WinModal";
|
import { WinModal } from './components/modals/WinModal'
|
||||||
import { isWordInWordList, isWinningWord, solution } from "./lib/words";
|
import { isWordInWordList, isWinningWord, solution } from './lib/words'
|
||||||
import {
|
import {
|
||||||
loadGameStateFromLocalStorage,
|
loadGameStateFromLocalStorage,
|
||||||
saveGameStateToLocalStorage,
|
saveGameStateToLocalStorage,
|
||||||
} from "./lib/localStorage";
|
} from './lib/localStorage'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [guesses, setGuesses] = useState<string[]>(() => {
|
const [guesses, setGuesses] = useState<string[]>(() => {
|
||||||
const loaded = loadGameStateFromLocalStorage();
|
const loaded = loadGameStateFromLocalStorage()
|
||||||
return loaded?.solution === solution ? loaded.guesses : [];
|
return loaded?.solution === solution ? loaded.guesses : []
|
||||||
});
|
})
|
||||||
const [currentGuess, setCurrentGuess] = useState("");
|
const [currentGuess, setCurrentGuess] = useState('')
|
||||||
const [isGameWon, setIsGameWon] = useState(false);
|
const [isGameWon, setIsGameWon] = useState(false)
|
||||||
const [isWinModalOpen, setIsWinModalOpen] = useState(false);
|
const [isWinModalOpen, setIsWinModalOpen] = useState(false)
|
||||||
const [isInfoModalOpen, setIsInfoModalOpen] = useState(false);
|
const [isInfoModalOpen, setIsInfoModalOpen] = useState(false)
|
||||||
const [isAboutModalOpen, setIsAboutModalOpen] = useState(false);
|
const [isAboutModalOpen, setIsAboutModalOpen] = useState(false)
|
||||||
const [isWordNotFoundAlertOpen, setIsWordNotFoundAlertOpen] = useState(false);
|
const [isWordNotFoundAlertOpen, setIsWordNotFoundAlertOpen] = useState(false)
|
||||||
const [isGameLost, setIsGameLost] = useState(false);
|
const [isGameLost, setIsGameLost] = useState(false)
|
||||||
const [shareComplete, setShareComplete] = useState(false);
|
const [shareComplete, setShareComplete] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
saveGameStateToLocalStorage({ guesses, solution });
|
saveGameStateToLocalStorage({ guesses, solution })
|
||||||
}, [guesses]);
|
}, [guesses])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isGameWon) {
|
if (isGameWon) {
|
||||||
setIsWinModalOpen(true);
|
setIsWinModalOpen(true)
|
||||||
}
|
}
|
||||||
}, [isGameWon]);
|
}, [isGameWon])
|
||||||
|
|
||||||
const onChar = (value: string) => {
|
const onChar = (value: string) => {
|
||||||
if (currentGuess.length < 5 && guesses.length < 6) {
|
if (currentGuess.length < 5 && guesses.length < 6) {
|
||||||
setCurrentGuess(`${currentGuess}${value}`);
|
setCurrentGuess(`${currentGuess}${value}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const onDelete = () => {
|
const onDelete = () => {
|
||||||
setCurrentGuess(currentGuess.slice(0, -1));
|
setCurrentGuess(currentGuess.slice(0, -1))
|
||||||
};
|
}
|
||||||
|
|
||||||
const onEnter = () => {
|
const onEnter = () => {
|
||||||
if (!isWordInWordList(currentGuess)) {
|
if (!isWordInWordList(currentGuess)) {
|
||||||
setIsWordNotFoundAlertOpen(true);
|
setIsWordNotFoundAlertOpen(true)
|
||||||
return setTimeout(() => {
|
return setTimeout(() => {
|
||||||
setIsWordNotFoundAlertOpen(false);
|
setIsWordNotFoundAlertOpen(false)
|
||||||
}, 2000);
|
}, 2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
const winningWord = isWinningWord(currentGuess);
|
const winningWord = isWinningWord(currentGuess)
|
||||||
|
|
||||||
if (currentGuess.length === 5 && guesses.length < 6 && !isGameWon) {
|
if (currentGuess.length === 5 && guesses.length < 6 && !isGameWon) {
|
||||||
setGuesses([...guesses, currentGuess]);
|
setGuesses([...guesses, currentGuess])
|
||||||
setCurrentGuess("");
|
setCurrentGuess('')
|
||||||
|
|
||||||
if (winningWord) {
|
if (winningWord) {
|
||||||
return setIsGameWon(true);
|
return setIsGameWon(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guesses.length === 5) {
|
if (guesses.length === 5) {
|
||||||
setIsGameLost(true);
|
setIsGameLost(true)
|
||||||
return setTimeout(() => {
|
return setTimeout(() => {
|
||||||
setIsGameLost(false);
|
setIsGameLost(false)
|
||||||
}, 2000);
|
}, 2000)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="py-8 max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<div className="py-8 max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
|
@ -104,11 +104,11 @@ function App() {
|
||||||
handleClose={() => setIsWinModalOpen(false)}
|
handleClose={() => setIsWinModalOpen(false)}
|
||||||
guesses={guesses}
|
guesses={guesses}
|
||||||
handleShare={() => {
|
handleShare={() => {
|
||||||
setIsWinModalOpen(false);
|
setIsWinModalOpen(false)
|
||||||
setShareComplete(true);
|
setShareComplete(true)
|
||||||
return setTimeout(() => {
|
return setTimeout(() => {
|
||||||
setShareComplete(false);
|
setShareComplete(false)
|
||||||
}, 2000);
|
}, 2000)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<InfoModal
|
<InfoModal
|
||||||
|
@ -128,7 +128,7 @@ function App() {
|
||||||
About this game
|
About this game
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
import { Fragment } from "react";
|
import { Fragment } from 'react'
|
||||||
import { Transition } from "@headlessui/react";
|
import { Transition } from '@headlessui/react'
|
||||||
import classNames from "classnames";
|
import classNames from 'classnames'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean
|
||||||
message: string;
|
message: string
|
||||||
variant?: "success" | "warning";
|
variant?: 'success' | 'warning'
|
||||||
};
|
}
|
||||||
|
|
||||||
export const Alert = ({ isOpen, message, variant = "warning" }: Props) => {
|
export const Alert = ({ isOpen, message, variant = 'warning' }: Props) => {
|
||||||
const classes = classNames(
|
const classes = classNames(
|
||||||
"fixed top-2.5 left-1/2 transform -translate-x-1/2 max-w-sm w-full shadow-lg rounded-lg pointer-events-auto ring-1 ring-black ring-opacity-5 overflow-hidden",
|
'fixed top-2.5 left-1/2 transform -translate-x-1/2 max-w-sm w-full shadow-lg rounded-lg pointer-events-auto ring-1 ring-black ring-opacity-5 overflow-hidden',
|
||||||
{
|
{
|
||||||
"bg-rose-200": variant === "warning",
|
'bg-rose-200': variant === 'warning',
|
||||||
"bg-green-200": variant === "success",
|
'bg-green-200': variant === 'success',
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition
|
<Transition
|
||||||
|
@ -36,5 +36,5 @@ export const Alert = ({ isOpen, message, variant = "warning" }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import { CharStatus } from "../../lib/statuses";
|
import { CharStatus } from '../../lib/statuses'
|
||||||
import classnames from "classnames";
|
import classnames from 'classnames'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
value?: string;
|
value?: string
|
||||||
status?: CharStatus;
|
status?: CharStatus
|
||||||
};
|
}
|
||||||
|
|
||||||
export const Cell = ({ value, status }: Props) => {
|
export const Cell = ({ value, status }: Props) => {
|
||||||
const classes = classnames(
|
const classes = classnames(
|
||||||
"w-14 h-14 border-solid border-2 flex items-center justify-center mx-0.5 text-lg font-bold rounded",
|
'w-14 h-14 border-solid border-2 flex items-center justify-center mx-0.5 text-lg font-bold rounded',
|
||||||
{
|
{
|
||||||
"bg-white border-slate-200": !status,
|
'bg-white border-slate-200': !status,
|
||||||
"bg-slate-400 text-white border-slate-400": status === "absent",
|
'bg-slate-400 text-white border-slate-400': status === 'absent',
|
||||||
"bg-green-500 text-white border-green-500": status === "correct",
|
'bg-green-500 text-white border-green-500': status === 'correct',
|
||||||
"bg-yellow-500 text-white border-yellow-500": status === "present",
|
'bg-yellow-500 text-white border-yellow-500': status === 'present',
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={classes}>{value}</div>
|
<div className={classes}>{value}</div>
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { getGuessStatuses } from "../../lib/statuses";
|
import { getGuessStatuses } from '../../lib/statuses'
|
||||||
import { Cell } from "./Cell";
|
import { Cell } from './Cell'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
guess: string;
|
guess: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export const CompletedRow = ({ guess }: Props) => {
|
export const CompletedRow = ({ guess }: Props) => {
|
||||||
const statuses = getGuessStatuses(guess);
|
const statuses = getGuessStatuses(guess)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center mb-1">
|
<div className="flex justify-center mb-1">
|
||||||
{guess.split("").map((letter, i) => (
|
{guess.split('').map((letter, i) => (
|
||||||
<Cell key={i} value={letter} status={statuses[i]} />
|
<Cell key={i} value={letter} status={statuses[i]} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Cell } from "./Cell";
|
import { Cell } from './Cell'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
guess: string;
|
guess: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export const CurrentRow = ({ guess }: Props) => {
|
export const CurrentRow = ({ guess }: Props) => {
|
||||||
const splitGuess = guess.split("");
|
const splitGuess = guess.split('')
|
||||||
const emptyCells = Array.from(Array(5 - splitGuess.length));
|
const emptyCells = Array.from(Array(5 - splitGuess.length))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center mb-1">
|
<div className="flex justify-center mb-1">
|
||||||
|
@ -17,5 +17,5 @@ export const CurrentRow = ({ guess }: Props) => {
|
||||||
<Cell key={i} />
|
<Cell key={i} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Cell } from "./Cell";
|
import { Cell } from './Cell'
|
||||||
|
|
||||||
export const EmptyRow = () => {
|
export const EmptyRow = () => {
|
||||||
const emptyCells = Array.from(Array(5));
|
const emptyCells = Array.from(Array(5))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center mb-1">
|
<div className="flex justify-center mb-1">
|
||||||
|
@ -9,5 +9,5 @@ export const EmptyRow = () => {
|
||||||
<Cell key={i} />
|
<Cell key={i} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { CompletedRow } from "./CompletedRow";
|
import { CompletedRow } from './CompletedRow'
|
||||||
import { CurrentRow } from "./CurrentRow";
|
import { CurrentRow } from './CurrentRow'
|
||||||
import { EmptyRow } from "./EmptyRow";
|
import { EmptyRow } from './EmptyRow'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
guesses: string[];
|
guesses: string[]
|
||||||
currentGuess: string;
|
currentGuess: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export const Grid = ({ guesses, currentGuess }: Props) => {
|
export const Grid = ({ guesses, currentGuess }: Props) => {
|
||||||
const empties =
|
const empties =
|
||||||
guesses.length < 5 ? Array.from(Array(5 - guesses.length)) : [];
|
guesses.length < 5 ? Array.from(Array(5 - guesses.length)) : []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pb-6">
|
<div className="pb-6">
|
||||||
|
@ -21,5 +21,5 @@ export const Grid = ({ guesses, currentGuess }: Props) => {
|
||||||
<EmptyRow key={i} />
|
<EmptyRow key={i} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { ReactNode } from "react";
|
import { ReactNode } from 'react'
|
||||||
import classnames from "classnames";
|
import classnames from 'classnames'
|
||||||
import { KeyValue } from "../../lib/keyboard";
|
import { KeyValue } from '../../lib/keyboard'
|
||||||
import { CharStatus } from "../../lib/statuses";
|
import { CharStatus } from '../../lib/statuses'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children?: ReactNode;
|
children?: ReactNode
|
||||||
value: KeyValue;
|
value: KeyValue
|
||||||
width?: number;
|
width?: number
|
||||||
status?: CharStatus;
|
status?: CharStatus
|
||||||
onClick: (value: KeyValue) => void;
|
onClick: (value: KeyValue) => void
|
||||||
};
|
}
|
||||||
|
|
||||||
export const Key = ({
|
export const Key = ({
|
||||||
children,
|
children,
|
||||||
|
@ -19,24 +19,24 @@ export const Key = ({
|
||||||
onClick,
|
onClick,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const classes = classnames(
|
const classes = classnames(
|
||||||
"flex items-center justify-center rounded mx-0.5 text-xs font-bold cursor-pointer",
|
'flex items-center justify-center rounded mx-0.5 text-xs font-bold cursor-pointer',
|
||||||
{
|
{
|
||||||
"bg-slate-200 hover:bg-slate-300 active:bg-slate-400": !status,
|
'bg-slate-200 hover:bg-slate-300 active:bg-slate-400': !status,
|
||||||
"bg-slate-400 text-white": status === "absent",
|
'bg-slate-400 text-white': status === 'absent',
|
||||||
"bg-green-500 hover:bg-green-600 active:bg-green-700 text-white":
|
'bg-green-500 hover:bg-green-600 active:bg-green-700 text-white':
|
||||||
status === "correct",
|
status === 'correct',
|
||||||
"bg-yellow-500 hover:bg-yellow-600 active:bg-yellow-700 text-white":
|
'bg-yellow-500 hover:bg-yellow-600 active:bg-yellow-700 text-white':
|
||||||
status === "present",
|
status === 'present',
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{ width: `${width}px`, height: "58px" }}
|
style={{ width: `${width}px`, height: '58px' }}
|
||||||
className={classes}
|
className={classes}
|
||||||
onClick={() => onClick(value)}
|
onClick={() => onClick(value)}
|
||||||
>
|
>
|
||||||
{children || value}
|
{children || value}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,87 +1,87 @@
|
||||||
import { KeyValue } from "../../lib/keyboard";
|
import { KeyValue } from '../../lib/keyboard'
|
||||||
import { getStatuses } from "../../lib/statuses";
|
import { getStatuses } from '../../lib/statuses'
|
||||||
import { Key } from "./Key";
|
import { Key } from './Key'
|
||||||
import {useEffect} from "react";
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onChar: (value: string) => void;
|
onChar: (value: string) => void
|
||||||
onDelete: () => void;
|
onDelete: () => void
|
||||||
onEnter: () => void;
|
onEnter: () => void
|
||||||
guesses: string[];
|
guesses: string[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export const Keyboard = ({ onChar, onDelete, onEnter, guesses }: Props) => {
|
export const Keyboard = ({ onChar, onDelete, onEnter, guesses }: Props) => {
|
||||||
const charStatuses = getStatuses(guesses);
|
const charStatuses = getStatuses(guesses)
|
||||||
|
|
||||||
const onClick = (value: KeyValue) => {
|
const onClick = (value: KeyValue) => {
|
||||||
if (value === "ENTER") {
|
if (value === 'ENTER') {
|
||||||
onEnter();
|
onEnter()
|
||||||
} else if (value === "DELETE") {
|
} else if (value === 'DELETE') {
|
||||||
onDelete();
|
onDelete()
|
||||||
} else {
|
} else {
|
||||||
onChar(value);
|
onChar(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const listener = (e:KeyboardEvent) => {
|
const listener = (e: KeyboardEvent) => {
|
||||||
if(e.code === "Enter") {
|
if (e.code === 'Enter') {
|
||||||
onEnter();
|
onEnter()
|
||||||
} else if(e.code === "Backspace") {
|
} else if (e.code === 'Backspace') {
|
||||||
onDelete();
|
onDelete()
|
||||||
} else {
|
} else {
|
||||||
const key = e.key.toUpperCase();
|
const key = e.key.toUpperCase()
|
||||||
if(key.length === 1 && key >= "A" && key <= "Z") {
|
if (key.length === 1 && key >= 'A' && key <= 'Z') {
|
||||||
onChar(key);
|
onChar(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
window.addEventListener("keyup", listener);
|
window.addEventListener('keyup', listener)
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("keyup", listener);
|
window.removeEventListener('keyup', listener)
|
||||||
};
|
}
|
||||||
}, [onEnter, onDelete, onChar]);
|
}, [onEnter, onDelete, onChar])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-center mb-1">
|
<div className="flex justify-center mb-1">
|
||||||
<Key value="Q" onClick={onClick} status={charStatuses["Q"]} />
|
<Key value="Q" onClick={onClick} status={charStatuses['Q']} />
|
||||||
<Key value="W" onClick={onClick} status={charStatuses["W"]} />
|
<Key value="W" onClick={onClick} status={charStatuses['W']} />
|
||||||
<Key value="E" onClick={onClick} status={charStatuses["E"]} />
|
<Key value="E" onClick={onClick} status={charStatuses['E']} />
|
||||||
<Key value="R" onClick={onClick} status={charStatuses["R"]} />
|
<Key value="R" onClick={onClick} status={charStatuses['R']} />
|
||||||
<Key value="T" onClick={onClick} status={charStatuses["T"]} />
|
<Key value="T" onClick={onClick} status={charStatuses['T']} />
|
||||||
<Key value="Y" onClick={onClick} status={charStatuses["Y"]} />
|
<Key value="Y" onClick={onClick} status={charStatuses['Y']} />
|
||||||
<Key value="U" onClick={onClick} status={charStatuses["U"]} />
|
<Key value="U" onClick={onClick} status={charStatuses['U']} />
|
||||||
<Key value="I" onClick={onClick} status={charStatuses["I"]} />
|
<Key value="I" onClick={onClick} status={charStatuses['I']} />
|
||||||
<Key value="O" onClick={onClick} status={charStatuses["O"]} />
|
<Key value="O" onClick={onClick} status={charStatuses['O']} />
|
||||||
<Key value="P" onClick={onClick} status={charStatuses["P"]} />
|
<Key value="P" onClick={onClick} status={charStatuses['P']} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center mb-1">
|
<div className="flex justify-center mb-1">
|
||||||
<Key value="A" onClick={onClick} status={charStatuses["A"]} />
|
<Key value="A" onClick={onClick} status={charStatuses['A']} />
|
||||||
<Key value="S" onClick={onClick} status={charStatuses["S"]} />
|
<Key value="S" onClick={onClick} status={charStatuses['S']} />
|
||||||
<Key value="D" onClick={onClick} status={charStatuses["D"]} />
|
<Key value="D" onClick={onClick} status={charStatuses['D']} />
|
||||||
<Key value="F" onClick={onClick} status={charStatuses["F"]} />
|
<Key value="F" onClick={onClick} status={charStatuses['F']} />
|
||||||
<Key value="G" onClick={onClick} status={charStatuses["G"]} />
|
<Key value="G" onClick={onClick} status={charStatuses['G']} />
|
||||||
<Key value="H" onClick={onClick} status={charStatuses["H"]} />
|
<Key value="H" onClick={onClick} status={charStatuses['H']} />
|
||||||
<Key value="J" onClick={onClick} status={charStatuses["J"]} />
|
<Key value="J" onClick={onClick} status={charStatuses['J']} />
|
||||||
<Key value="K" onClick={onClick} status={charStatuses["K"]} />
|
<Key value="K" onClick={onClick} status={charStatuses['K']} />
|
||||||
<Key value="L" onClick={onClick} status={charStatuses["L"]} />
|
<Key value="L" onClick={onClick} status={charStatuses['L']} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<Key width={65.4} value="ENTER" onClick={onClick}>
|
<Key width={65.4} value="ENTER" onClick={onClick}>
|
||||||
Enter
|
Enter
|
||||||
</Key>
|
</Key>
|
||||||
<Key value="Z" onClick={onClick} status={charStatuses["Z"]} />
|
<Key value="Z" onClick={onClick} status={charStatuses['Z']} />
|
||||||
<Key value="X" onClick={onClick} status={charStatuses["X"]} />
|
<Key value="X" onClick={onClick} status={charStatuses['X']} />
|
||||||
<Key value="C" onClick={onClick} status={charStatuses["C"]} />
|
<Key value="C" onClick={onClick} status={charStatuses['C']} />
|
||||||
<Key value="V" onClick={onClick} status={charStatuses["V"]} />
|
<Key value="V" onClick={onClick} status={charStatuses['V']} />
|
||||||
<Key value="B" onClick={onClick} status={charStatuses["B"]} />
|
<Key value="B" onClick={onClick} status={charStatuses['B']} />
|
||||||
<Key value="N" onClick={onClick} status={charStatuses["N"]} />
|
<Key value="N" onClick={onClick} status={charStatuses['N']} />
|
||||||
<Key value="M" onClick={onClick} status={charStatuses["M"]} />
|
<Key value="M" onClick={onClick} status={charStatuses['M']} />
|
||||||
<Key width={65.4} value="DELETE" onClick={onClick}>
|
<Key width={65.4} value="DELETE" onClick={onClick}>
|
||||||
Delete
|
Delete
|
||||||
</Key>
|
</Key>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
import { CharStatus } from "../../lib/statuses";
|
import { CharStatus } from '../../lib/statuses'
|
||||||
import classnames from "classnames";
|
import classnames from 'classnames'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
status: CharStatus;
|
status: CharStatus
|
||||||
};
|
}
|
||||||
|
|
||||||
export const MiniCell = ({ status }: Props) => {
|
export const MiniCell = ({ status }: Props) => {
|
||||||
const classes = classnames(
|
const classes = classnames(
|
||||||
"w-10 h-10 border-solid border-2 border-slate-200 flex items-center justify-center mx-0.5 text-lg font-bold rounded",
|
'w-10 h-10 border-solid border-2 border-slate-200 flex items-center justify-center mx-0.5 text-lg font-bold rounded',
|
||||||
{
|
{
|
||||||
"bg-white": status === "absent",
|
'bg-white': status === 'absent',
|
||||||
"bg-green-500": status === "correct",
|
'bg-green-500': status === 'correct',
|
||||||
"bg-yellow-500": status === "present",
|
'bg-yellow-500': status === 'present',
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={classes}></div>
|
<div className={classes}></div>
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { getGuessStatuses } from "../../lib/statuses";
|
import { getGuessStatuses } from '../../lib/statuses'
|
||||||
import { MiniCell } from "./MiniCell";
|
import { MiniCell } from './MiniCell'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
guess: string;
|
guess: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export const MiniCompletedRow = ({ guess }: Props) => {
|
export const MiniCompletedRow = ({ guess }: Props) => {
|
||||||
const statuses = getGuessStatuses(guess);
|
const statuses = getGuessStatuses(guess)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center mb-1">
|
<div className="flex justify-center mb-1">
|
||||||
{guess.split("").map((letter, i) => (
|
{guess.split('').map((letter, i) => (
|
||||||
<MiniCell key={i} status={statuses[i]} />
|
<MiniCell key={i} status={statuses[i]} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { MiniCompletedRow } from "./MiniCompletedRow";
|
import { MiniCompletedRow } from './MiniCompletedRow'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
guesses: string[];
|
guesses: string[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export const MiniGrid = ({ guesses }: Props) => {
|
export const MiniGrid = ({ guesses }: Props) => {
|
||||||
return (
|
return (
|
||||||
|
@ -11,5 +11,5 @@ export const MiniGrid = ({ guesses }: Props) => {
|
||||||
<MiniCompletedRow key={i} guess={guess} />
|
<MiniCompletedRow key={i} guess={guess} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { Fragment } from "react";
|
import { Fragment } from 'react'
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from '@headlessui/react'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean
|
||||||
handleClose: () => void;
|
handleClose: () => void
|
||||||
};
|
}
|
||||||
|
|
||||||
export const AboutModal = ({ isOpen, handleClose }: Props) => {
|
export const AboutModal = ({ isOpen, handleClose }: Props) => {
|
||||||
return (
|
return (
|
||||||
|
@ -54,14 +54,14 @@ export const AboutModal = ({ isOpen, handleClose }: Props) => {
|
||||||
</Dialog.Title>
|
</Dialog.Title>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<p className="text-sm text-gray-500">
|
<p className="text-sm text-gray-500">
|
||||||
This is an open source clone of the game Wordle -{" "}
|
This is an open source clone of the game Wordle -{' '}
|
||||||
<a
|
<a
|
||||||
href="https://github.com/hannahcode/wordle"
|
href="https://github.com/hannahcode/wordle"
|
||||||
className="underline font-bold"
|
className="underline font-bold"
|
||||||
>
|
>
|
||||||
check out the code here
|
check out the code here
|
||||||
</a>{" "}
|
</a>{' '}
|
||||||
and{" "}
|
and{' '}
|
||||||
<a
|
<a
|
||||||
href="https://www.powerlanguage.co.uk/wordle/"
|
href="https://www.powerlanguage.co.uk/wordle/"
|
||||||
className="underline font-bold"
|
className="underline font-bold"
|
||||||
|
@ -77,5 +77,5 @@ export const AboutModal = ({ isOpen, handleClose }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { Fragment } from "react";
|
import { Fragment } from 'react'
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from '@headlessui/react'
|
||||||
import { Cell } from "../grid/Cell";
|
import { Cell } from '../grid/Cell'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean
|
||||||
handleClose: () => void;
|
handleClose: () => void
|
||||||
};
|
}
|
||||||
|
|
||||||
export const InfoModal = ({ isOpen, handleClose }: Props) => {
|
export const InfoModal = ({ isOpen, handleClose }: Props) => {
|
||||||
return (
|
return (
|
||||||
|
@ -100,5 +100,5 @@ export const InfoModal = ({ isOpen, handleClose }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { Fragment } from "react";
|
import { Fragment } from 'react'
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from '@headlessui/react'
|
||||||
import { CheckIcon } from "@heroicons/react/outline";
|
import { CheckIcon } from '@heroicons/react/outline'
|
||||||
import { MiniGrid } from "../mini-grid/MiniGrid";
|
import { MiniGrid } from '../mini-grid/MiniGrid'
|
||||||
import { shareStatus } from "../../lib/share";
|
import { shareStatus } from '../../lib/share'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean
|
||||||
handleClose: () => void;
|
handleClose: () => void
|
||||||
guesses: string[];
|
guesses: string[]
|
||||||
handleShare: () => void;
|
handleShare: () => void
|
||||||
};
|
}
|
||||||
|
|
||||||
export const WinModal = ({
|
export const WinModal = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
|
@ -79,8 +79,8 @@ export const WinModal = ({
|
||||||
type="button"
|
type="button"
|
||||||
className="inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:text-sm"
|
className="inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:text-sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
shareStatus(guesses);
|
shareStatus(guesses)
|
||||||
handleShare();
|
handleShare()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Share
|
Share
|
||||||
|
@ -91,5 +91,5 @@ export const WinModal = ({
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,17 +1,17 @@
|
||||||
import React from 'react';
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom'
|
||||||
import './index.css';
|
import './index.css'
|
||||||
import App from './App';
|
import App from './App'
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from './reportWebVitals'
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<App />
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
)
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
// If you want to start measuring performance in your app, pass a function
|
||||||
// to log results (for example: reportWebVitals(console.log))
|
// to log results (for example: reportWebVitals(console.log))
|
||||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||||
reportWebVitals();
|
reportWebVitals()
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import { CharValue } from "./statuses";
|
import { CharValue } from './statuses'
|
||||||
|
|
||||||
export type KeyValue = CharValue | "ENTER" | "DELETE";
|
export type KeyValue = CharValue | 'ENTER' | 'DELETE'
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
const gameStateKey = "gameState";
|
const gameStateKey = 'gameState'
|
||||||
|
|
||||||
type StoredGameState = {
|
type StoredGameState = {
|
||||||
guesses: string[];
|
guesses: string[]
|
||||||
solution: string;
|
solution: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export const saveGameStateToLocalStorage = (gameState: StoredGameState) => {
|
export const saveGameStateToLocalStorage = (gameState: StoredGameState) => {
|
||||||
localStorage.setItem(gameStateKey, JSON.stringify(gameState));
|
localStorage.setItem(gameStateKey, JSON.stringify(gameState))
|
||||||
};
|
}
|
||||||
|
|
||||||
export const loadGameStateFromLocalStorage = () => {
|
export const loadGameStateFromLocalStorage = () => {
|
||||||
const state = localStorage.getItem(gameStateKey);
|
const state = localStorage.getItem(gameStateKey)
|
||||||
|
|
||||||
return state ? (JSON.parse(state) as StoredGameState) : null;
|
return state ? (JSON.parse(state) as StoredGameState) : null
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
import { getGuessStatuses } from "./statuses";
|
import { getGuessStatuses } from './statuses'
|
||||||
import { solutionIndex } from "./words";
|
import { solutionIndex } from './words'
|
||||||
|
|
||||||
export const shareStatus = (guesses: string[]) => {
|
export const shareStatus = (guesses: string[]) => {
|
||||||
navigator.clipboard.writeText(
|
navigator.clipboard.writeText(
|
||||||
"Wordle " +
|
'Wordle ' +
|
||||||
solutionIndex +
|
solutionIndex +
|
||||||
" " +
|
' ' +
|
||||||
guesses.length +
|
guesses.length +
|
||||||
"/6\n\n" +
|
'/6\n\n' +
|
||||||
generateEmojiGrid(guesses)
|
generateEmojiGrid(guesses)
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export const generateEmojiGrid = (guesses: string[]) => {
|
export const generateEmojiGrid = (guesses: string[]) => {
|
||||||
return guesses
|
return guesses
|
||||||
.map((guess) => {
|
.map((guess) => {
|
||||||
const status = getGuessStatuses(guess);
|
const status = getGuessStatuses(guess)
|
||||||
return guess
|
return guess
|
||||||
.split("")
|
.split('')
|
||||||
.map((letter, i) => {
|
.map((letter, i) => {
|
||||||
switch (status[i]) {
|
switch (status[i]) {
|
||||||
case "correct":
|
case 'correct':
|
||||||
return "🟩";
|
return '🟩'
|
||||||
case "present":
|
case 'present':
|
||||||
return "🟨";
|
return '🟨'
|
||||||
default:
|
default:
|
||||||
return "⬜";
|
return '⬜'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join("");
|
.join('')
|
||||||
})
|
})
|
||||||
.join("\n");
|
.join('\n')
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,102 +1,102 @@
|
||||||
import { solution } from "./words";
|
import { solution } from './words'
|
||||||
|
|
||||||
export type CharStatus = "absent" | "present" | "correct";
|
export type CharStatus = 'absent' | 'present' | 'correct'
|
||||||
|
|
||||||
export type CharValue =
|
export type CharValue =
|
||||||
| "Q"
|
| 'Q'
|
||||||
| "W"
|
| 'W'
|
||||||
| "E"
|
| 'E'
|
||||||
| "R"
|
| 'R'
|
||||||
| "T"
|
| 'T'
|
||||||
| "Y"
|
| 'Y'
|
||||||
| "U"
|
| 'U'
|
||||||
| "I"
|
| 'I'
|
||||||
| "O"
|
| 'O'
|
||||||
| "P"
|
| 'P'
|
||||||
| "A"
|
| 'A'
|
||||||
| "S"
|
| 'S'
|
||||||
| "D"
|
| 'D'
|
||||||
| "F"
|
| 'F'
|
||||||
| "G"
|
| 'G'
|
||||||
| "H"
|
| 'H'
|
||||||
| "J"
|
| 'J'
|
||||||
| "K"
|
| 'K'
|
||||||
| "L"
|
| 'L'
|
||||||
| "Z"
|
| 'Z'
|
||||||
| "X"
|
| 'X'
|
||||||
| "C"
|
| 'C'
|
||||||
| "V"
|
| 'V'
|
||||||
| "B"
|
| 'B'
|
||||||
| "N"
|
| 'N'
|
||||||
| "M";
|
| 'M'
|
||||||
|
|
||||||
export const getStatuses = (
|
export const getStatuses = (
|
||||||
guesses: string[]
|
guesses: string[]
|
||||||
): { [key: string]: CharStatus } => {
|
): { [key: string]: CharStatus } => {
|
||||||
const charObj: { [key: string]: CharStatus } = {};
|
const charObj: { [key: string]: CharStatus } = {}
|
||||||
|
|
||||||
guesses.forEach((word) => {
|
guesses.forEach((word) => {
|
||||||
word.split("").forEach((letter, i) => {
|
word.split('').forEach((letter, i) => {
|
||||||
if (!solution.includes(letter)) {
|
if (!solution.includes(letter)) {
|
||||||
// make status absent
|
// make status absent
|
||||||
return (charObj[letter] = "absent");
|
return (charObj[letter] = 'absent')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (letter === solution[i]) {
|
if (letter === solution[i]) {
|
||||||
//make status correct
|
//make status correct
|
||||||
return (charObj[letter] = "correct");
|
return (charObj[letter] = 'correct')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (charObj[letter] !== "correct") {
|
if (charObj[letter] !== 'correct') {
|
||||||
//make status present
|
//make status present
|
||||||
return (charObj[letter] = "present");
|
return (charObj[letter] = 'present')
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
return charObj;
|
return charObj
|
||||||
};
|
}
|
||||||
|
|
||||||
export const getGuessStatuses = (guess: string): CharStatus[] => {
|
export const getGuessStatuses = (guess: string): CharStatus[] => {
|
||||||
const splitSolution = solution.split("");
|
const splitSolution = solution.split('')
|
||||||
const splitGuess = guess.split("");
|
const splitGuess = guess.split('')
|
||||||
|
|
||||||
const solutionCharsTaken = splitSolution.map((_) => false);
|
const solutionCharsTaken = splitSolution.map((_) => false)
|
||||||
|
|
||||||
const statuses: CharStatus[] = Array.from(Array(guess.length));
|
const statuses: CharStatus[] = Array.from(Array(guess.length))
|
||||||
|
|
||||||
// handle all correct cases first
|
// handle all correct cases first
|
||||||
splitGuess.forEach((letter, i) => {
|
splitGuess.forEach((letter, i) => {
|
||||||
if (letter === splitSolution[i]) {
|
if (letter === splitSolution[i]) {
|
||||||
statuses[i] = "correct";
|
statuses[i] = 'correct'
|
||||||
solutionCharsTaken[i] = true;
|
solutionCharsTaken[i] = true
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
splitGuess.forEach((letter, i) => {
|
splitGuess.forEach((letter, i) => {
|
||||||
if (statuses[i]) return;
|
if (statuses[i]) return
|
||||||
|
|
||||||
if (!splitSolution.includes(letter)) {
|
if (!splitSolution.includes(letter)) {
|
||||||
// handles the absent case
|
// handles the absent case
|
||||||
statuses[i] = "absent";
|
statuses[i] = 'absent'
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we are left with "present"s
|
// now we are left with "present"s
|
||||||
const indexOfPresentChar = splitSolution.findIndex(
|
const indexOfPresentChar = splitSolution.findIndex(
|
||||||
(x, index) => x === letter && !solutionCharsTaken[index]
|
(x, index) => x === letter && !solutionCharsTaken[index]
|
||||||
);
|
)
|
||||||
|
|
||||||
if (indexOfPresentChar > -1) {
|
if (indexOfPresentChar > -1) {
|
||||||
statuses[i] = "present";
|
statuses[i] = 'present'
|
||||||
solutionCharsTaken[indexOfPresentChar] = true;
|
solutionCharsTaken[indexOfPresentChar] = true
|
||||||
return;
|
return
|
||||||
} else {
|
} else {
|
||||||
statuses[i] = "absent";
|
statuses[i] = 'absent'
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
return statuses;
|
return statuses
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
import { WORDS } from "../constants/wordlist";
|
import { WORDS } from '../constants/wordlist'
|
||||||
import { VALIDGUESSES } from "../constants/validGuesses";
|
import { VALIDGUESSES } from '../constants/validGuesses'
|
||||||
|
|
||||||
export const isWordInWordList = (word: string) => {
|
export const isWordInWordList = (word: string) => {
|
||||||
return (
|
return (
|
||||||
WORDS.includes(word.toLowerCase()) ||
|
WORDS.includes(word.toLowerCase()) ||
|
||||||
VALIDGUESSES.includes(word.toLowerCase())
|
VALIDGUESSES.includes(word.toLowerCase())
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export const isWinningWord = (word: string) => {
|
export const isWinningWord = (word: string) => {
|
||||||
return solution === word;
|
return solution === word
|
||||||
};
|
}
|
||||||
|
|
||||||
export const getWordOfDay = () => {
|
export const getWordOfDay = () => {
|
||||||
// January 1, 2022 Game Epoch
|
// January 1, 2022 Game Epoch
|
||||||
const epochMs = 1641013200000;
|
const epochMs = 1641013200000
|
||||||
const now = Date.now();
|
const now = Date.now()
|
||||||
const msInDay = 86400000;
|
const msInDay = 86400000
|
||||||
const index = Math.floor((now - epochMs) / msInDay);
|
const index = Math.floor((now - epochMs) / msInDay)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
solution: WORDS[index].toUpperCase(),
|
solution: WORDS[index].toUpperCase(),
|
||||||
solutionIndex: index,
|
solutionIndex: index,
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const { solution, solutionIndex } = getWordOfDay();
|
export const { solution, solutionIndex } = getWordOfDay()
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { ReportHandler } from 'web-vitals';
|
import { ReportHandler } from 'web-vitals'
|
||||||
|
|
||||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||||
getCLS(onPerfEntry);
|
getCLS(onPerfEntry)
|
||||||
getFID(onPerfEntry);
|
getFID(onPerfEntry)
|
||||||
getFCP(onPerfEntry);
|
getFCP(onPerfEntry)
|
||||||
getLCP(onPerfEntry);
|
getLCP(onPerfEntry)
|
||||||
getTTFB(onPerfEntry);
|
getTTFB(onPerfEntry)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default reportWebVitals;
|
export default reportWebVitals
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
// allows you to do things like:
|
// allows you to do things like:
|
||||||
// expect(element).toHaveTextContent(/react/i)
|
// expect(element).toHaveTextContent(/react/i)
|
||||||
// learn more: https://github.com/testing-library/jest-dom
|
// learn more: https://github.com/testing-library/jest-dom
|
||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ["./src/**/*.{js,jsx,ts,tsx}"],
|
content: ['./src/**/*.{js,jsx,ts,tsx}'],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
@ -20,7 +16,5 @@
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx"
|
"jsx": "react-jsx"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src"]
|
||||||
"src"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue