Merge branch 'main' into move-alert-up

This commit is contained in:
gbear605 2022-01-29 18:20:48 -05:00 committed by GitHub
commit b3d10c1d01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 83 additions and 64 deletions

View file

@ -1,38 +1,3 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
html.dark {
background-color: rgb(15, 23, 42);
}

View file

@ -2,6 +2,22 @@ import React from 'react'
import { render, screen } from '@testing-library/react'
import App from './App'
beforeEach(() => {
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
})
})
test('renders App component', () => {
render(<App />)
const linkElement = screen.getByText(/Not Wordle/)

View file

@ -1,5 +1,8 @@
import { InformationCircleIcon } from '@heroicons/react/outline'
import { ChartBarIcon } from '@heroicons/react/outline'
import {
InformationCircleIcon,
ChartBarIcon,
SunIcon,
} from '@heroicons/react/outline'
import { useState, useEffect } from 'react'
import { Alert } from './components/alerts/Alert'
import { Grid } from './components/grid/Grid'
@ -15,9 +18,15 @@ import {
saveGameStateToLocalStorage,
} from './lib/localStorage'
import './App.css'
const ALERT_TIME_MS = 2000
function App() {
const prefersDarkMode = window.matchMedia(
'(prefers-color-scheme: dark)'
).matches
const [currentGuess, setCurrentGuess] = useState('')
const [isGameWon, setIsGameWon] = useState(false)
const [isInfoModalOpen, setIsInfoModalOpen] = useState(false)
@ -26,6 +35,13 @@ function App() {
const [isStatsModalOpen, setIsStatsModalOpen] = useState(false)
const [isWordNotFoundAlertOpen, setIsWordNotFoundAlertOpen] = useState(false)
const [isGameLost, setIsGameLost] = useState(false)
const [isDarkMode, setIsDarkMode] = useState(
localStorage.getItem('theme')
? localStorage.getItem('theme') === 'dark'
: prefersDarkMode
? true
: false
)
const [successAlert, setSuccessAlert] = useState('')
const [guesses, setGuesses] = useState<string[]>(() => {
const loaded = loadGameStateFromLocalStorage()
@ -44,6 +60,19 @@ function App() {
const [stats, setStats] = useState(() => loadStats())
useEffect(() => {
if (isDarkMode) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
}, [isDarkMode])
const handleDarkMode = (isDark: boolean) => {
setIsDarkMode(isDark)
localStorage.setItem('theme', isDark ? 'dark' : 'light')
}
useEffect(() => {
saveGameStateToLocalStorage({ guesses, solution })
}, [guesses])
@ -114,13 +143,17 @@ function App() {
return (
<div className="py-8 max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="flex w-80 mx-auto items-center mb-8 mt-12">
<h1 className="text-xl grow font-bold">Not Wordle</h1>
<h1 className="text-xl grow font-bold dark:text-white">Not Wordle</h1>
<SunIcon
className="h-6 w-6 cursor-pointer dark:stroke-white"
onClick={() => handleDarkMode(!isDarkMode)}
/>
<InformationCircleIcon
className="h-6 w-6 cursor-pointer"
className="h-6 w-6 cursor-pointer dark:stroke-white"
onClick={() => setIsInfoModalOpen(true)}
/>
<ChartBarIcon
className="h-6 w-6 cursor-pointer"
className="h-6 w-6 cursor-pointer dark:stroke-white"
onClick={() => setIsStatsModalOpen(true)}
/>
</div>

View file

@ -8,13 +8,16 @@ type Props = {
export const Cell = ({ value, status }: Props) => {
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 dark:text-white',
{
'bg-white border-slate-200': !status,
'border-black': value && !status,
'bg-slate-400 text-white border-slate-400': status === 'absent',
'bg-white dark:bg-slate-900 border-slate-200 dark:border-slate-600':
!status,
'border-black dark:border-slate-100': value && !status,
'bg-slate-400 dark:bg-slate-700 text-white border-slate-400 dark:border-slate-700':
status === 'absent',
'bg-green-500 text-white border-green-500': status === 'correct',
'bg-yellow-500 text-white border-yellow-500': status === 'present',
'bg-yellow-500 dark:bg-yellow-700 text-white border-yellow-500 dark:border-yellow-700':
status === 'present',
'cell-animation': !!value,
}
)

View file

@ -19,13 +19,14 @@ export const Key = ({
onClick,
}: Props) => {
const classes = classnames(
'flex items-center justify-center rounded mx-0.5 text-xs font-bold cursor-pointer select-none',
'flex items-center justify-center rounded mx-0.5 text-xs font-bold cursor-pointer select-none dark:text-white',
{
'bg-slate-200 hover:bg-slate-300 active:bg-slate-400': !status,
'bg-slate-200 dark:bg-slate-600 hover:bg-slate-300 active:bg-slate-400':
!status,
'bg-slate-400 text-white': status === 'absent',
'bg-green-500 hover:bg-green-600 active:bg-green-700 text-white':
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 dark:bg-yellow-700 text-white':
status === 'present',
}
)

View file

@ -8,7 +8,7 @@ type Props = {
export const AboutModal = ({ isOpen, handleClose }: Props) => {
return (
<BaseModal title="About" isOpen={isOpen} handleClose={handleClose}>
<p className="text-sm text-gray-500">
<p className="text-sm text-gray-500 dark:text-gray-300">
This is an open source clone of the game Wordle -{' '}
<a
href="https://github.com/hannahcode/wordle"

View file

@ -46,10 +46,10 @@ export const BaseModal = ({ title, children, isOpen, handleClose }: Props) => {
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div className="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full sm:p-6">
<div className="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-sm sm:w-full sm:p-6 dark:bg-gray-800">
<div className="absolute right-4 top-4">
<XCircleIcon
className="h-6 w-6 cursor-pointer"
className="h-6 w-6 cursor-pointer dark:stroke-white"
onClick={() => handleClose()}
/>
</div>
@ -57,7 +57,7 @@ export const BaseModal = ({ title, children, isOpen, handleClose }: Props) => {
<div className="text-center">
<Dialog.Title
as="h3"
className="text-lg leading-6 font-medium text-gray-900"
className="text-lg leading-6 font-medium text-gray-900 dark:text-gray-100"
>
{title}
</Dialog.Title>

View file

@ -9,7 +9,7 @@ type Props = {
export const InfoModal = ({ isOpen, handleClose }: Props) => {
return (
<BaseModal title="How to play" isOpen={isOpen} handleClose={handleClose}>
<p className="text-sm text-gray-500">
<p className="text-sm text-gray-500 dark:text-gray-300">
Guess the WORDLE in 6 tries. After each guess, the color of the tiles
will change to show how close your guess was to the word.
</p>
@ -21,7 +21,7 @@ export const InfoModal = ({ isOpen, handleClose }: Props) => {
<Cell value="R" />
<Cell value="Y" />
</div>
<p className="text-sm text-gray-500">
<p className="text-sm text-gray-500 dark:text-gray-300">
The letter W is in the word and in the correct spot.
</p>
@ -32,7 +32,7 @@ export const InfoModal = ({ isOpen, handleClose }: Props) => {
<Cell value="O" />
<Cell value="T" />
</div>
<p className="text-sm text-gray-500">
<p className="text-sm text-gray-500 dark:text-gray-300">
The letter L is in the word but in the wrong spot.
</p>
@ -43,7 +43,7 @@ export const InfoModal = ({ isOpen, handleClose }: Props) => {
<Cell value="U" status="absent" />
<Cell value="E" />
</div>
<p className="text-sm text-gray-500">
<p className="text-sm text-gray-500 dark:text-gray-300">
The letter U is not in the word in any spot.
</p>
</BaseModal>

View file

@ -35,16 +35,16 @@ export const StatsModal = ({
return (
<BaseModal title="Statistics" isOpen={isOpen} handleClose={handleClose}>
<StatBar gameStats={gameStats} />
<h4 className="text-lg leading-6 font-medium text-gray-900">
<h4 className="text-lg leading-6 font-medium text-gray-900 dark:text-gray-100">
Guess Distribution
</h4>
<Histogram gameStats={gameStats} />
{(isGameLost || isGameWon) && (
<div className="mt-5 sm:mt-6 columns-2">
<div className="mt-5 sm:mt-6 columns-2 dark:text-white">
<div>
<h5>New word in</h5>
<Countdown
className="text-lg font-medium text-gray-900"
className="text-lg font-medium text-gray-900 dark:text-gray-100"
date={tomorrow}
daysInHours={true}
/>

View file

@ -10,7 +10,7 @@ export const Histogram = ({ gameStats }: Props) => {
const maxValue = Math.max(...winDistribution)
return (
<div className="columns-1 justify-left m-2 text-sm">
<div className="columns-1 justify-left m-2 text-sm dark:text-white">
{winDistribution.map((value, i) => (
<Progress
key={i}

View file

@ -12,7 +12,7 @@ const StatItem = ({
value: string | number
}) => {
return (
<div className="items-center justify-center m-1 w-1/4">
<div className="items-center justify-center m-1 w-1/4 dark:text-white">
<div className="text-3xl font-bold">{value}</div>
<div className="text-xs">{label}</div>
</div>

View file

@ -1,6 +1,7 @@
module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}'],
theme: {
darkMode: 'class',
theme: {
extend: {},
},
plugins: [],