Skip to content

Commit

Permalink
added session timer
Browse files Browse the repository at this point in the history
  • Loading branch information
LooLzzz committed Aug 31, 2024
1 parent bc29957 commit 3d3f7c1
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 19 deletions.
14 changes: 6 additions & 8 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Affix, Box, Burger, Stack, useComputedColorScheme } from '@mantine/core'
import { Box, Burger, Stack, useComputedColorScheme } from '@mantine/core'
import { useDisclosure, useMediaQuery } from '@mantine/hooks'
import { Helmet } from 'react-helmet'

Expand All @@ -23,19 +23,17 @@ function App() {
onClose={closeSidebar}
/>

<Affix
zIndex={0}
position={{
top: 10,
left: 10,
}}
<Box
pos='absolute'
top={10}
left={10}
>
<Burger
opened={isSidebarOpened}
onClick={toggleSidebar}
opacity={0.6}
/>
</Affix>
</Box>

<Stack className={classes.stack} h='100%' align='center' justify='center' gap={isXs ? 30 : 50}>
<Box mah='60rem' style={{ justifySelf: 'start' }}>
Expand Down
19 changes: 16 additions & 3 deletions src/components/Sidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import { Button, Divider, Drawer, DrawerProps, Stack, Switch, Title, useMantineColorScheme } from '@mantine/core'
import { Button, Code, Divider, Drawer, DrawerProps, Group, Stack, Switch, Text, TextInput, Title, useMantineColorScheme } from '@mantine/core'

import { MoonStarsIcon, SunIcon } from '@/assets'
import { useWordleStore } from '@/hooks'
import { humanReadableSeconds } from '@/utils'

interface SidebarProps extends DrawerProps {

}

const Sidebar = ({ opened, onClose, ...props }: SidebarProps) => {
const { colorScheme, toggleColorScheme } = useMantineColorScheme()
const resetStore = useWordleStore((state) => state.resetStore)
const [
resetStore,
time,
] = useWordleStore((state) => [
state.resetStore,
state.time,
])

const handleResetStore = () => {
resetStore()
Expand All @@ -24,6 +31,12 @@ const Sidebar = ({ opened, onClose, ...props }: SidebarProps) => {
{...props}
>
<Stack>
<Text>
Session Time: <Code fz='sm'>{humanReadableSeconds(time, 1)}</Code>
</Text>

<Divider />

<Switch
color='dark.4'
label='Dark mode'
Expand All @@ -33,7 +46,7 @@ const Sidebar = ({ opened, onClose, ...props }: SidebarProps) => {
onLabel={<MoonStarsIcon strokeWidth={2.5} width='1rem' color='var(--mantine-color-blue-6)' />}
offLabel={<SunIcon strokeWidth={2.5} width='1rem' color='var(--mantine-color-yellow-7)' />}
/>
<Divider />

<Button onClick={handleResetStore}>
Restart Game
</Button>
Expand Down
18 changes: 18 additions & 0 deletions src/components/WordsGuesser/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useCallback, useEffect, useState } from 'react'

import { wordsSet } from '@/assets'
import { useWordleStore } from '@/hooks'
import { humanReadableSeconds } from '@/utils'

import Guess from './Guess'
import classes from './index.module.scss'
Expand All @@ -16,6 +17,9 @@ const WordsGuesser = () => {
answer,
currentGuess,
guesses,
time,
startTimer,
stopTimer,
submitCurrentGuess,
addLetterToCurrentGuess,
removeLetterFromCurrentGuess,
Expand All @@ -24,6 +28,9 @@ const WordsGuesser = () => {
state.answer,
state.currentGuess,
state.guesses,
state.time,
state.startTimer,
state.stopTimer,
state.submitCurrentGuess,
state.addLetterToCurrentGuess,
state.removeLetterFromCurrentGuess,
Expand Down Expand Up @@ -60,6 +67,8 @@ const WordsGuesser = () => {
const isGuessInWordsSet = wordsSet.has(currentGuessString)
const isAlreadyGuess = guesses.includes(currentGuessString)

startTimer()

switch (e.key) {
case 'Enter':
if (numberOfEmptyLetters === 0) {
Expand Down Expand Up @@ -145,6 +154,12 @@ const WordsGuesser = () => {
setSelectedIdx(undefined)
}, [answer, currentGuess])

useEffect(() => {
if (answer === lastGuess || guesses.length === TOTAL_GUESSES) {
stopTimer()
}
}, [answer, lastGuess, guesses.length, TOTAL_GUESSES])

useEffect(() => {
window.addEventListener('keydown', onKeyPress)
return () => {
Expand All @@ -169,6 +184,9 @@ const WordsGuesser = () => {
: 'Congratulations!'
}
</Text>
<Text>
Time: <Code fz='md'>{humanReadableSeconds(time)}</Code>
</Text>
<Button onClick={resetStore}>Play Again</Button>
</Stack>
</Modal>
Expand Down
45 changes: 38 additions & 7 deletions src/hooks/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,65 @@ import { devtools, persist } from 'zustand/middleware'

import { answersList } from '@/assets'

interface WordleState {
interface WordleStateValues {
answer: string
guesses: string[]
time: number
currentGuess: (null | string)[]
}

interface WordleStateActions {
resetStore: () => void

startTimer: () => void
stopTimer: () => void
addLetterToCurrentGuess: (letter: string, idx?: number) => void
removeLetterFromCurrentGuess: (idx?: number) => void
submitCurrentGuess: () => void
clearCurrentGuess: () => void
}

type WordleState = WordleStateValues & WordleStateActions

const generateRandomWord = () => answersList[Math.floor(Math.random() * answersList.length)]

const initialState: Pick<WordleState, 'answer' | 'guesses' | 'currentGuess'> = {
const initialState: WordleStateValues = {
answer: null as any,
guesses: [],
time: 0,
currentGuess: [null, null, null, null, null],
}

let timer: NodeJS.Timeout | null = null

const useWordleStore = create<WordleState>()(
devtools(
persist(
(set) => ({
(set, get) => ({
...initialState,

resetStore: () => set({
...initialState,
answer: generateRandomWord(),
}),
resetStore: () => {
set({
...initialState,
answer: generateRandomWord(),
})
get().stopTimer()
},

startTimer: () => {
if (!timer) {
timer = setInterval(() => {
set(({ time }) => ({ time: time + 0.1 }))
}, 100)
}
},

stopTimer: () => {
if (timer) {
clearInterval(timer)
timer = null
}
},

addLetterToCurrentGuess: (letter, idx = undefined) => set(({ currentGuess }) => {
if (idx === undefined) (
Expand Down Expand Up @@ -70,6 +97,10 @@ if (!useWordleStore.getState()?.answer) {
useWordleStore.setState({ answer: generateRandomWord() })
}

if (useWordleStore.getState()?.time !== 0) {
useWordleStore.getState()?.startTimer()
}

if (useWordleStore.getState()?.guesses.at(-1) === useWordleStore.getState()?.answer) {
useWordleStore.getState().resetStore()
}
Expand Down
9 changes: 8 additions & 1 deletion src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ const cssResolver: CSSVariablesResolver = (theme) => ({
})

const theme = createTheme({

components: {
Code: {
defaultProps: {
bg: 'gray',
c: 'var(--mantine-primary-color-contrast)',
}
}
}
})

createRoot(document.getElementById('root')!).render(
Expand Down
31 changes: 31 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

const humanReadableSeconds = (seconds: number, precision: number = 1) => {
const prefixes = [
'second',
'minute',
'hour',
'day',
]

let remainingSeconds = seconds
let index = 0

while (remainingSeconds >= 60 && index < prefixes.length - 1) {
remainingSeconds /= 60
index++
}

const roundedSeconds = (
remainingSeconds
.toFixed(precision)
.replace(/\.0+$/, '')
)
const unit = prefixes[index]
const plural = roundedSeconds === '1' ? '' : 's'

return `${roundedSeconds} ${unit}${plural}`
}

export {
humanReadableSeconds
}
2 changes: 2 additions & 0 deletions tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"@/hooks/*": ["./src/hooks/*"],
"@/assets": ["./src/assets"],
"@/assets/*": ["./src/assets/*"],
"@/utils": ["./src/utils"],
"@/utils/*": ["./src/utils/*"],
}
},
"include": ["src", "src/types.d.ts"]
Expand Down
1 change: 1 addition & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default defineConfig({
'@/components': path.resolve(__dirname, './src/components'),
'@/hooks': path.resolve(__dirname, './src/hooks'),
'@/assets': path.resolve(__dirname, './src/assets'),
'@/utils': path.resolve(__dirname, './src/utils'),
},
},
plugins: [
Expand Down

0 comments on commit 3d3f7c1

Please sign in to comment.