Merge pull request #50 from jcserv/refactor/modals

Refactor modals to reduce code duplication
This commit is contained in:
Hannah Park 2022-01-23 19:54:24 -05:00 committed by GitHub
commit 8104c6cd26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 171 additions and 325 deletions

View file

@ -1,6 +1,4 @@
import { Fragment } from 'react' import { BaseModal } from './BaseModal'
import { Dialog, Transition } from '@headlessui/react'
import { XCircleIcon } from '@heroicons/react/outline'
type Props = { type Props = {
isOpen: boolean isOpen: boolean
@ -9,57 +7,7 @@ type Props = {
export const AboutModal = ({ isOpen, handleClose }: Props) => { export const AboutModal = ({ isOpen, handleClose }: Props) => {
return ( return (
<Transition.Root show={isOpen} as={Fragment}> <BaseModal title="About" isOpen={isOpen} handleClose={handleClose}>
<Dialog
as="div"
className="fixed z-10 inset-0 overflow-y-auto"
onClose={handleClose}
>
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
&#8203;
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
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="absolute right-4 top-4">
<XCircleIcon
className="h-6 w-6 cursor-pointer"
onClick={() => handleClose()}
/>
</div>
<div>
<div className="text-center">
<Dialog.Title
as="h3"
className="text-lg leading-6 font-medium text-gray-900"
>
About
</Dialog.Title>
<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
@ -76,13 +24,6 @@ export const AboutModal = ({ isOpen, handleClose }: Props) => {
play the original here play the original here
</a> </a>
</p> </p>
</div> </BaseModal>
</div>
</div>
</div>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
) )
} }

View file

@ -0,0 +1,75 @@
import { Fragment } from 'react'
import { Dialog, Transition } from '@headlessui/react'
import { XCircleIcon } from '@heroicons/react/outline'
type Props = {
title: string
children: React.ReactNode
isOpen: boolean
handleClose: () => void
}
export const BaseModal = ({ title, children, isOpen, handleClose }: Props) => {
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog
as="div"
className="fixed z-10 inset-0 overflow-y-auto"
onClose={handleClose}
>
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
&#8203;
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
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="absolute right-4 top-4">
<XCircleIcon
className="h-6 w-6 cursor-pointer"
onClick={() => handleClose()}
/>
</div>
<div>
<div className="text-center">
<Dialog.Title
as="h3"
className="text-lg leading-6 font-medium text-gray-900"
>
{title}
</Dialog.Title>
<div className="mt-2">
{children}
</div>
</div>
</div>
</div>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
)
}

View file

@ -1,7 +1,5 @@
import { Fragment } from 'react'
import { Dialog, Transition } from '@headlessui/react'
import { Cell } from '../grid/Cell' import { Cell } from '../grid/Cell'
import { XCircleIcon } from '@heroicons/react/outline' import { BaseModal } from './BaseModal'
type Props = { type Props = {
isOpen: boolean isOpen: boolean
@ -10,61 +8,10 @@ type Props = {
export const InfoModal = ({ isOpen, handleClose }: Props) => { export const InfoModal = ({ isOpen, handleClose }: Props) => {
return ( return (
<Transition.Root show={isOpen} as={Fragment}> <BaseModal title="How to play" isOpen={isOpen} handleClose={handleClose}>
<Dialog
as="div"
className="fixed z-10 inset-0 overflow-y-auto"
onClose={handleClose}
>
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
&#8203;
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
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="absolute right-4 top-4">
<XCircleIcon
className="h-6 w-6 cursor-pointer"
onClick={() => handleClose()}
/>
</div>
<div>
<div className="text-center">
<Dialog.Title
as="h3"
className="text-lg leading-6 font-medium text-gray-900"
>
How to play
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-gray-500"> <p className="text-sm text-gray-500">
Guess the WORDLE in 6 tries. After each guess, the color Guess the WORDLE in 6 tries. After each guess, the color of the tiles
of the tiles will change to show how close your guess was will change to show how close your guess was to the word.
to the word.
</p> </p>
<div className="flex justify-center mb-1 mt-4"> <div className="flex justify-center mb-1 mt-4">
@ -99,13 +46,6 @@ export const InfoModal = ({ isOpen, handleClose }: Props) => {
<p className="text-sm text-gray-500"> <p className="text-sm text-gray-500">
The letter U is not in the word in any spot. The letter U is not in the word in any spot.
</p> </p>
</div> </BaseModal>
</div>
</div>
</div>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
) )
} }

View file

@ -1,9 +1,7 @@
import { Fragment } from 'react'
import { Dialog, Transition } from '@headlessui/react'
import { XCircleIcon } from '@heroicons/react/outline'
import { StatBar } from '../stats/StatBar' import { StatBar } from '../stats/StatBar'
import { Histogram } from '../stats/Histogram' import { Histogram } from '../stats/Histogram'
import { GameStats } from '../../lib/localStorage' import { GameStats } from '../../lib/localStorage'
import { BaseModal } from './BaseModal'
type Props = { type Props = {
isOpen: boolean isOpen: boolean
@ -13,71 +11,12 @@ type Props = {
export const StatsModal = ({ isOpen, handleClose, gameStats }: Props) => { export const StatsModal = ({ isOpen, handleClose, gameStats }: Props) => {
return ( return (
<Transition.Root show={isOpen} as={Fragment}> <BaseModal title="Statistics" isOpen={isOpen} handleClose={handleClose}>
<Dialog
as="div"
className="fixed z-10 inset-0 overflow-y-auto"
onClose={handleClose}
>
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
&#8203;
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
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="absolute right-4 top-4">
<XCircleIcon
className="h-6 w-6 cursor-pointer"
onClick={handleClose}
/>
</div>
<div>
<div className="text-center">
<Dialog.Title
as="h3"
className="text-lg leading-6 font-medium text-gray-900"
>
Statistics
</Dialog.Title>
<StatBar gameStats={gameStats} /> <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">
Guess Distribution Guess Distribution
</h4> </h4>
<Histogram gameStats={gameStats} /> <Histogram gameStats={gameStats} />
</div> </BaseModal>
</div>
</div>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
) )
} }

View file

@ -1,9 +1,8 @@
import { Fragment } from 'react' import { Dialog } 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'
import { XCircleIcon } from '@heroicons/react/outline' import { BaseModal } from './BaseModal'
type Props = { type Props = {
isOpen: boolean isOpen: boolean
@ -19,54 +18,10 @@ export const WinModal = ({
handleShare, handleShare,
}: Props) => { }: Props) => {
return ( return (
<Transition.Root show={isOpen} as={Fragment}> <BaseModal title="You won!" isOpen={isOpen} handleClose={handleClose}>
<Dialog
as="div"
className="fixed z-10 inset-0 overflow-y-auto"
onClose={handleClose}
>
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
&#8203;
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
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="absolute right-4 top-4">
<XCircleIcon
className="h-6 w-6 cursor-pointer"
onClick={() => handleClose()}
/>
</div>
<div> <div>
<div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100"> <div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100">
<CheckIcon <CheckIcon className="h-6 w-6 text-green-600" aria-hidden="true" />
className="h-6 w-6 text-green-600"
aria-hidden="true"
/>
</div> </div>
<div className="mt-3 text-center sm:mt-5"> <div className="mt-3 text-center sm:mt-5">
<Dialog.Title <Dialog.Title
@ -93,10 +48,6 @@ export const WinModal = ({
Share Share
</button> </button>
</div> </div>
</div> </BaseModal>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
) )
} }