From 3f6d65fc68cb0b584535c1e632de0223c55abe95 Mon Sep 17 00:00:00 2001 From: Jacob Louis Hoover Date: Tue, 25 Jan 2022 13:00:19 -0500 Subject: [PATCH 1/4] histogram width divide by mode, not total Divide by the value that occurs the most frequently, instead of the total games, so the histogram always uses the whole space available, rather than possibly getting smaller and smaller the more games are played. --- src/components/stats/Histogram.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/stats/Histogram.tsx b/src/components/stats/Histogram.tsx index 5f3aca7..1d6e1e5 100644 --- a/src/components/stats/Histogram.tsx +++ b/src/components/stats/Histogram.tsx @@ -14,7 +14,7 @@ export const Histogram = ({ gameStats }: Props) => { ))} From b5bfad11046c9ddc13904a5b5fb1e66c29118abd Mon Sep 17 00:00:00 2001 From: Jacob Louis Hoover Date: Tue, 25 Jan 2022 13:03:27 -0500 Subject: [PATCH 2/4] Update Histogram.tsx oops missing parenthesis. --- src/components/stats/Histogram.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/stats/Histogram.tsx b/src/components/stats/Histogram.tsx index 1d6e1e5..c1b8883 100644 --- a/src/components/stats/Histogram.tsx +++ b/src/components/stats/Histogram.tsx @@ -14,7 +14,7 @@ export const Histogram = ({ gameStats }: Props) => { ))} From 8d42c8d763ff0d86a24b6387bcae302139cd6bdd Mon Sep 17 00:00:00 2001 From: Jacob Louis Hoover Date: Tue, 25 Jan 2022 13:11:04 -0500 Subject: [PATCH 3/4] set const maxValue = Math.max(...winDistribution) --- src/components/stats/Histogram.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/stats/Histogram.tsx b/src/components/stats/Histogram.tsx index c1b8883..f496309 100644 --- a/src/components/stats/Histogram.tsx +++ b/src/components/stats/Histogram.tsx @@ -6,7 +6,8 @@ type Props = { } export const Histogram = ({ gameStats }: Props) => { - const { totalGames, winDistribution } = gameStats + const winDistribution = gameStats.winDistribution + const maxValue = Math.max(...winDistribution) return (
@@ -14,7 +15,7 @@ export const Histogram = ({ gameStats }: Props) => { ))} From 762750e67d0d0921dda37952190ea7d0007c0203 Mon Sep 17 00:00:00 2001 From: Khemarato Bhikkhu Date: Mon, 24 Jan 2022 08:05:01 +0700 Subject: [PATCH 4/4] Fix #52: Put countdown timer and share button in stats modal --- package-lock.json | 21 ++++++++ package.json | 3 +- src/App.tsx | 52 ++++++++++-------- src/components/alerts/Alert.tsx | 2 +- src/components/mini-grid/MiniCell.tsx | 23 -------- src/components/mini-grid/MiniCompletedRow.tsx | 18 ------- src/components/mini-grid/MiniGrid.tsx | 15 ------ src/components/modals/StatsModal.tsx | 34 +++++++++++- src/components/modals/WinModal.tsx | 53 ------------------- src/constants/strings.ts | 1 + src/lib/share.ts | 4 +- src/lib/words.ts | 4 +- 12 files changed, 92 insertions(+), 138 deletions(-) delete mode 100644 src/components/mini-grid/MiniCell.tsx delete mode 100644 src/components/mini-grid/MiniCompletedRow.tsx delete mode 100644 src/components/mini-grid/MiniGrid.tsx delete mode 100644 src/components/modals/WinModal.tsx create mode 100644 src/constants/strings.ts diff --git a/package-lock.json b/package-lock.json index 2804f0d..6642a0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@types/react-dom": "^17.0.11", "classnames": "^2.3.1", "react": "^17.0.2", + "react-countdown": "^2.3.2", "react-dom": "^17.0.2", "react-scripts": "5.0.0", "typescript": "^4.5.4", @@ -12901,6 +12902,18 @@ "node": ">=14" } }, + "node_modules/react-countdown": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/react-countdown/-/react-countdown-2.3.2.tgz", + "integrity": "sha512-Q4SADotHtgOxNWhDdvgupmKVL0pMB9DvoFcxv5AzjsxVhzOVxnttMbAywgqeOdruwEAmnPhOhNv/awAgkwru2w==", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">= 15", + "react-dom": ">= 15" + } + }, "node_modules/react-dev-utils": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", @@ -25058,6 +25071,14 @@ "whatwg-fetch": "^3.6.2" } }, + "react-countdown": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/react-countdown/-/react-countdown-2.3.2.tgz", + "integrity": "sha512-Q4SADotHtgOxNWhDdvgupmKVL0pMB9DvoFcxv5AzjsxVhzOVxnttMbAywgqeOdruwEAmnPhOhNv/awAgkwru2w==", + "requires": { + "prop-types": "^15.7.2" + } + }, "react-dev-utils": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", diff --git a/package.json b/package.json index 95e0b53..ca3548f 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "react-dom": "^17.0.2", "react-scripts": "5.0.0", "typescript": "^4.5.4", - "web-vitals": "^2.1.3" + "web-vitals": "^2.1.3", + "react-countdown": "^2.3.2" }, "scripts": { "start": "react-scripts start", diff --git a/src/App.tsx b/src/App.tsx index 9a9b9ec..5a3c546 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,8 +6,8 @@ import { Grid } from './components/grid/Grid' import { Keyboard } from './components/keyboard/Keyboard' import { AboutModal } from './components/modals/AboutModal' import { InfoModal } from './components/modals/InfoModal' -import { WinModal } from './components/modals/WinModal' import { StatsModal } from './components/modals/StatsModal' +import { WIN_MESSAGES } from './constants/strings' import { isWordInWordList, isWinningWord, solution } from './lib/words' import { addStatsForCompletedGame, loadStats } from './lib/stats' import { @@ -15,17 +15,18 @@ import { saveGameStateToLocalStorage, } from './lib/localStorage' +const ALERT_TIME_MS = 2000; + function App() { const [currentGuess, setCurrentGuess] = useState('') const [isGameWon, setIsGameWon] = useState(false) - const [isWinModalOpen, setIsWinModalOpen] = useState(false) const [isInfoModalOpen, setIsInfoModalOpen] = useState(false) const [isAboutModalOpen, setIsAboutModalOpen] = useState(false) const [isNotEnoughLetters, setIsNotEnoughLetters] = useState(false) const [isStatsModalOpen, setIsStatsModalOpen] = useState(false) const [isWordNotFoundAlertOpen, setIsWordNotFoundAlertOpen] = useState(false) const [isGameLost, setIsGameLost] = useState(false) - const [shareComplete, setShareComplete] = useState(false) + const [successAlert, setSuccessAlert] = useState('') const [guesses, setGuesses] = useState(() => { const loaded = loadGameStateFromLocalStorage() if (loaded?.solution !== solution) { @@ -49,9 +50,18 @@ function App() { useEffect(() => { if (isGameWon) { - setIsWinModalOpen(true) + setSuccessAlert(WIN_MESSAGES[Math.floor(Math.random()*WIN_MESSAGES.length)]); + setTimeout(() => { + setSuccessAlert(''); + setIsStatsModalOpen(true); + }, ALERT_TIME_MS); } - }, [isGameWon]) + if (isGameLost) { + setTimeout(() => { + setIsStatsModalOpen(true); + }, ALERT_TIME_MS); + } + }, [isGameWon, isGameLost]) const onChar = (value: string) => { if (currentGuess.length < 5 && guesses.length < 6 && !isGameWon) { @@ -64,18 +74,19 @@ function App() { } const onEnter = () => { - if (!(currentGuess.length === 5) && !isGameLost) { + if (isGameWon || isGameLost) { return; } + if (!(currentGuess.length === 5)) { setIsNotEnoughLetters(true) return setTimeout(() => { setIsNotEnoughLetters(false) - }, 2000) + }, ALERT_TIME_MS) } if (!isWordInWordList(currentGuess)) { setIsWordNotFoundAlertOpen(true) return setTimeout(() => { setIsWordNotFoundAlertOpen(false) - }, 2000) + }, ALERT_TIME_MS) } const winningWord = isWinningWord(currentGuess) @@ -116,18 +127,6 @@ function App() { onEnter={onEnter} guesses={guesses} /> - setIsWinModalOpen(false)} - guesses={guesses} - handleShare={() => { - setIsWinModalOpen(false) - setShareComplete(true) - return setTimeout(() => { - setShareComplete(false) - }, 2000) - }} - /> setIsInfoModalOpen(false)} @@ -135,7 +134,14 @@ function App() { setIsStatsModalOpen(false)} + guesses={guesses} gameStats={stats} + isGameLost={isGameLost} + isGameWon={isGameWon} + handleShare={() => { + setSuccessAlert("Game copied to clipboard"); + return setTimeout(() => setSuccessAlert(''), ALERT_TIME_MS); + }} />
diff --git a/src/components/alerts/Alert.tsx b/src/components/alerts/Alert.tsx index 593b75e..6b0a29c 100644 --- a/src/components/alerts/Alert.tsx +++ b/src/components/alerts/Alert.tsx @@ -13,7 +13,7 @@ export const Alert = ({ isOpen, message, variant = 'warning' }: Props) => { 'fixed top-20 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-green-200': variant === 'success', + 'bg-green-200 z-20': variant === 'success', } ) diff --git a/src/components/mini-grid/MiniCell.tsx b/src/components/mini-grid/MiniCell.tsx deleted file mode 100644 index 8e96bc6..0000000 --- a/src/components/mini-grid/MiniCell.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { CharStatus } from '../../lib/statuses' -import classnames from 'classnames' - -type Props = { - status: CharStatus -} - -export const MiniCell = ({ status }: Props) => { - 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', - { - 'bg-white': status === 'absent', - 'bg-green-500': status === 'correct', - 'bg-yellow-500': status === 'present', - } - ) - - return ( - <> -
- - ) -} diff --git a/src/components/mini-grid/MiniCompletedRow.tsx b/src/components/mini-grid/MiniCompletedRow.tsx deleted file mode 100644 index 82ce014..0000000 --- a/src/components/mini-grid/MiniCompletedRow.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { getGuessStatuses } from '../../lib/statuses' -import { MiniCell } from './MiniCell' - -type Props = { - guess: string -} - -export const MiniCompletedRow = ({ guess }: Props) => { - const statuses = getGuessStatuses(guess) - - return ( -
- {guess.split('').map((letter, i) => ( - - ))} -
- ) -} diff --git a/src/components/mini-grid/MiniGrid.tsx b/src/components/mini-grid/MiniGrid.tsx deleted file mode 100644 index c0e1ae4..0000000 --- a/src/components/mini-grid/MiniGrid.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { MiniCompletedRow } from './MiniCompletedRow' - -type Props = { - guesses: string[] -} - -export const MiniGrid = ({ guesses }: Props) => { - return ( -
- {guesses.map((guess, i) => ( - - ))} -
- ) -} diff --git a/src/components/modals/StatsModal.tsx b/src/components/modals/StatsModal.tsx index 4b0ad02..fb0c5af 100644 --- a/src/components/modals/StatsModal.tsx +++ b/src/components/modals/StatsModal.tsx @@ -1,15 +1,29 @@ +import Countdown from "react-countdown" import { StatBar } from '../stats/StatBar' import { Histogram } from '../stats/Histogram' import { GameStats } from '../../lib/localStorage' +import { shareStatus } from '../../lib/share' +import { tomorrow } from '../../lib/words' import { BaseModal } from './BaseModal' type Props = { isOpen: boolean handleClose: () => void + guesses: string[] gameStats: GameStats + isGameLost: boolean + isGameWon: boolean + handleShare: () => void } -export const StatsModal = ({ isOpen, handleClose, gameStats }: Props) => { +export const StatsModal = ({ isOpen, handleClose, guesses, gameStats, isGameLost, isGameWon, handleShare }: Props) => { + if (gameStats.totalGames <= 0) { + return ( + + + + ) + } return ( @@ -17,6 +31,24 @@ export const StatsModal = ({ isOpen, handleClose, gameStats }: Props) => { Guess Distribution + {(isGameLost || isGameWon) && +
+
+
New word in
+ +
+ +
+ }
) } diff --git a/src/components/modals/WinModal.tsx b/src/components/modals/WinModal.tsx deleted file mode 100644 index a0979da..0000000 --- a/src/components/modals/WinModal.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Dialog } from '@headlessui/react' -import { CheckIcon } from '@heroicons/react/outline' -import { MiniGrid } from '../mini-grid/MiniGrid' -import { shareStatus } from '../../lib/share' -import { BaseModal } from './BaseModal' - -type Props = { - isOpen: boolean - handleClose: () => void - guesses: string[] - handleShare: () => void -} - -export const WinModal = ({ - isOpen, - handleClose, - guesses, - handleShare, -}: Props) => { - return ( - -
-
-
-
- - You won! - -
- -

Great job.

-
-
-
-
- -
-
- ) -} diff --git a/src/constants/strings.ts b/src/constants/strings.ts new file mode 100644 index 0000000..7414730 --- /dev/null +++ b/src/constants/strings.ts @@ -0,0 +1 @@ +export const WIN_MESSAGES = ["Great Job!", "Awesome", "Well done!"]; diff --git a/src/lib/share.ts b/src/lib/share.ts index 836c027..a5e1e62 100644 --- a/src/lib/share.ts +++ b/src/lib/share.ts @@ -1,9 +1,9 @@ import { getGuessStatuses } from './statuses' import { solutionIndex } from './words' -export const shareStatus = (guesses: string[]) => { +export const shareStatus = (guesses: string[], lost: boolean) => { navigator.clipboard.writeText( - `Not Wordle ${solutionIndex} ${guesses.length}/6\n\n` + + `Not Wordle ${solutionIndex} ${lost?"X":guesses.length}/6\n\n` + generateEmojiGrid(guesses) ) } diff --git a/src/lib/words.ts b/src/lib/words.ts index dd79d93..ba8122b 100644 --- a/src/lib/words.ts +++ b/src/lib/words.ts @@ -18,11 +18,13 @@ export const getWordOfDay = () => { const now = Date.now() const msInDay = 86400000 const index = Math.floor((now - epochMs) / msInDay) + const nextday = (index+1)*msInDay + epochMs; return { solution: WORDS[index].toUpperCase(), solutionIndex: index, + tomorrow: nextday, } } -export const { solution, solutionIndex } = getWordOfDay() +export const { solution, solutionIndex, tomorrow } = getWordOfDay()