Skip to content

Commit

Permalink
Merge branch 'unit/30-mole-game'
Browse files Browse the repository at this point in the history
  • Loading branch information
ElynnaChuang committed May 30, 2023
2 parents c199734 + 9800461 commit d247b9b
Show file tree
Hide file tree
Showing 53 changed files with 435 additions and 5 deletions.
40 changes: 40 additions & 0 deletions src/Assets/30images/dirt.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions src/Assets/30images/mole.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/Assets/Homepage/base/26.jpg
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/Assets/Homepage/base/27.jpg
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/Assets/Homepage/base/28.jpg
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/Assets/Homepage/base/29.jpg
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/Assets/Homepage/base/30.jpg
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/Assets/Homepage/l@1X/26.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/l@1X/27.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/l@1X/28.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/l@1X/29.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/l@1X/30.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/l@2X/26.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/l@2X/27.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/l@2X/28.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/l@2X/29.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/l@2X/30.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@1X/26.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@1X/27.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@1X/28.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@1X/29.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@1X/30.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@2X/26.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@2X/27.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@2X/28.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@2X/29.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/m@2X/30.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@1X/26.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@1X/27.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@1X/28.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@1X/29.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@1X/30.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@2X/26.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@2X/27.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@2X/28.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@2X/29.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@2X/30.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@3X/26.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@3X/27.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@3X/28.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@3X/29.webp
100755 → 100644
Binary file not shown.
Binary file modified src/Assets/Homepage/s@3X/30.webp
100755 → 100644
Binary file not shown.
13 changes: 13 additions & 0 deletions src/Pages/30MoleGame/Hole/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ReactComponent as Dirt } from '@/Assets/30images/dirt.svg';
import { ReactComponent as Mole } from '@/Assets/30images/mole.svg';

import styles from './styles.module.scss';

export const Hole = ({ show, onClick }) => {
return (
<div className={styles.hole}>
<Dirt className={styles.dirt} />
<Mole className={show ? styles.mole_show : styles.mole_hide} onClick={onClick} />
</div>
);
};
46 changes: 46 additions & 0 deletions src/Pages/30MoleGame/Hole/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
$size: 100px;

.hole {
position: relative;

overflow: hidden;

width: $size;
height: $size;

border-radius: 0.25rem;
}

.dirt {
position: absolute;
z-index: 3;
bottom: -15px;
left: 0;

width: 100%;
}

%base_mole {
cursor: pointer;

position: absolute;
z-index: 1;
left: 0;

width: 100%;
height: 100%;

transition: bottom 0.2s ease-out;
}

.mole_show {
@extend %base_mole;

bottom: -5%;
}

.mole_hide {
@extend %base_mole;

bottom: -90%;
}
14 changes: 14 additions & 0 deletions src/Pages/30MoleGame/Model/ModelContent/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import styles from './style.module.scss';

export const ModalContent = ({ score }) => {
return (
<div className={styles.container}>
<div className={styles.backDrop} />
<div className={styles.card}>
<div className={styles.header}>Times Up!</div>
<div>Your score is</div>
<div className={styles.score}>{score}</div>
</div>
</div>
);
};
48 changes: 48 additions & 0 deletions src/Pages/30MoleGame/Model/ModelContent/style.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.container {
position: absolute;
z-index: 99;
top: 0;
left: 0;

width: 100vw;
height: 100vh;
}

.backDrop {
width: 100%;
height: 100%;
background-color: rgba($color: #000, $alpha: 60%);
}

.card {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

display: flex;
flex-direction: column;
gap: 1rem;
align-items: center;
justify-content: center;

width: 80%;
max-width: 500px;
padding: 2rem;

font-size: 1.25rem;
font-weight: 700;
color: #b87f63;

background-color: #fff;
border-radius: 0.5rem;

.header {
font-size: 2rem;
color: #764831;
}

.score {
font-size: 5rem;
}
}
18 changes: 18 additions & 0 deletions src/Pages/30MoleGame/Model/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import { ModalContent } from './ModelContent';

export const TimeNotification = ({ open, score }) => {
const [showModal, setShowModal] = useState(false);

useEffect(() => {
setShowModal(open);
}, [open]);

return (
<>
<p style={{ display: 'none' }}>Result</p>
{showModal && createPortal(<ModalContent score={score} />, document.body)}
</>
);
};
41 changes: 41 additions & 0 deletions src/Pages/30MoleGame/Timer/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useEffect, useState } from 'react';

import { secToMin, padStart } from '@/Components/29Timer/helpers';

export const Timer = ({ time, startState, setEnd, className }) => {
const { start, setStart } = startState;
const intialTime = time || { min: 0, sec: 10 };

const [timeLeft, setTimeLeft] = useState(intialTime);

useEffect(() => {
let countDown;
if (start) {
let secLeft = intialTime.min * 60 + intialTime.sec;
setTimeLeft(() => secToMin(secLeft));

countDown = setInterval(() => {
secLeft -= 1;

if (secLeft < 0) {
setStart(false);

setEnd(true);
setTimeout(() => setEnd(false), 2000);

return clearInterval(countDown);
}

return setTimeLeft(() => secToMin(secLeft));
}, 1000);
}

return () => clearInterval(countDown);
}, [start]);

return (
<div className={className}>
{padStart(timeLeft.min)} : {padStart(timeLeft.sec)}
</div>
);
};
4 changes: 4 additions & 0 deletions src/Pages/30MoleGame/_color.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$primary_100: rgb(255 234 192);
$primary_500: #d8aa7c;
$primary_900: #9a6335;
$white: #fff8f0;
80 changes: 80 additions & 0 deletions src/Pages/30MoleGame/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { useEffect, useRef, useState } from 'react';
import { LayoutCol1 } from '@/Layouts';
import { Title } from '@/Components';
import { Hole } from './Hole';
import styles from './styles.module.scss';
import { Timer } from './Timer';
import { TimeNotification } from './Model';

const moles = Array.from({ length: 6 }, (_, i) => i + 1);

const getRandomIntervals = (min, max) => {
return Math.floor(Math.random() * (max - min)) + min;
};

let INTERVALS = getRandomIntervals(500, 800);

const MoleGamePage = () => {
const [nowId, setNowId] = useState(null);
const [start, setStart] = useState(false);
const [end, setEnd] = useState(false);

const score = useRef(0);

const handleGameStart = () => {
score.current = 0;
setStart(true);
};

useEffect(() => {
const randomShow = setInterval(() => {
if (start) {
const id = Math.floor(Math.random() * moles.length) + 1;
setNowId(id);

INTERVALS = getRandomIntervals(400, 600);
}
}, INTERVALS);

return () => {
clearInterval(randomShow);
setNowId(null);
};
}, [start]);

return (
<LayoutCol1 baseClassName={styles.page} layout='full'>
<Title title='Whack-a-mole!' size='m' titleClassName={styles.title} />
<div className={styles.info}>
<Timer
startState={{ start, setStart }}
time={{ min: 0, sec: 20 }}
setEnd={setEnd}
className={styles.time}
/>

<div className={styles.score}>Score : {score.current}</div>

<button className={styles.btn} onClick={handleGameStart} disabled={start}>
Game Start!
</button>
</div>

<div className={styles.holes}>
{moles.map(id => (
<Hole
key={id}
show={id === nowId}
onClick={() => {
score.current += 1;
}}
/>
))}
</div>

<TimeNotification open={end} score={score.current} />
</LayoutCol1>
);
};

export default MoleGamePage;
68 changes: 68 additions & 0 deletions src/Pages/30MoleGame/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
@use './color' as c;

%base_item {
display: flex;
align-items: center;

height: 100%;
padding: 0.5rem 1rem;

font-weight: 700;
color: c.$primary_900;

background-color: c.$white;
border: 2px solid c.$primary_500;
border-radius: 0.25rem;

transition: all 0.3s ease-out;
}

.page {
background: c.$primary_500;
}

.title {
color: c.$primary_900;
}

.info {
display: flex;
gap: 1rem;
align-items: center;
justify-content: center;

padding: 1rem;

background-color: c.$primary_100;
border-radius: 0.5rem;

.time {
@extend %base_item;
}

.score {
@extend %base_item;
}

.btn {
@extend %base_item;

box-shadow: 0 0 8px 0 rgba($color: #000, $alpha: 20%);

&:hover {
color: #fff;
background-color: c.$primary_500;
}

&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
}
}

.holes {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
}
Loading

0 comments on commit d247b9b

Please sign in to comment.