Skip to content

Commit

Permalink
Added color game! Will make some updates to this but this is a rough …
Browse files Browse the repository at this point in the history
…start
  • Loading branch information
ryqndev committed May 5, 2024
1 parent b4a9edb commit fd965e8
Show file tree
Hide file tree
Showing 21 changed files with 667 additions and 10 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
build/
node_modules/

**/.DS_Store
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"animejs": "^3.2.2",
"clsx": "^1.1.1",
"react": "^17.0.2",
"react-animate-height": "^3.2.3",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-mailchimp-subscribe": "^2.1.3",
Expand Down
3 changes: 3 additions & 0 deletions src/app/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import Designathon from "./pages/Designathons";
import Hey from "./pages/Hey";
import { HOUSES_SORTING_FORM } from "./pages/Houses/sections/Join";
import { PROJECT_TEAMS_GOOGLE_FORM } from "./pages/ProjectTeams/ProjectTeams";
import { ColorGame } from "./pages/ColorGame/ColorGame";

function App() {
useScroll();
Expand Down Expand Up @@ -71,6 +72,8 @@ function App() {

<Route path="brand" element={<Brand />} />

<Route path="color-game" element={<ColorGame />} />

{/* Redirects */}
<Route
path="discord"
Expand Down
30 changes: 22 additions & 8 deletions src/app/components/Banner/Banner.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
import { Link, useLocation } from "react-router-dom";

import cn from "./Banner.module.scss";
import { useCallback, useState } from "react";

function Banner() {
const location = useLocation();
const [show, setShow] = useState(true);

const closeBanner = useCallback(() => {
setShow(false);
}, []);

if (location.pathname.includes("/designathon")) return null;

return (
<div className={`fill blue ${cn.banner}`}>
<p>
<Link to="/houses" className={cn.underline}>
Join the DAUCI Houses
</Link>{" "}
to connect with your own design family!
</p>
</div>
show && (
<>
<div className={`fill blue ${cn.banner}`}>
<p>
<Link to="/houses" className={cn.underline}>
Join the DAUCI Houses
</Link>{" "}
to connect with your own design family!
</p>
<button className={cn.close} onClick={closeBanner}>
x
</button>
</div>
</>
)
);
}

Expand Down
11 changes: 11 additions & 0 deletions src/app/components/Banner/Banner.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,15 @@
.underline {
text-decoration: underline;
}
.close {
position: absolute;
right: 20px;
background-color: transparent;
border: none;
color: white;
top: 0;
height: 100%;
font-size: 1.3em;
cursor: pointer;
}
}
6 changes: 6 additions & 0 deletions src/app/components/Nav/Nav.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
@import "app/styles/variables";

nav {
position: sticky;
top: 0;
z-index: 1000;
}

#navSpacer {
height: 88px;
display: block;
Expand Down
78 changes: 78 additions & 0 deletions src/app/pages/ColorGame/ColorGame.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { memo, useCallback, useEffect, useRef, useState } from "react";
import cn from "./ColorGame.module.scss";
import { Text } from "app/components";
import { Section, Space } from "app/Symbols";
import clsx from "clsx";
import { Leaderboard } from "./components/Leaderboard/Leaderboard";
import {
DIGITS,
HexColorInput,
} from "./components/HexColorInput/HexColorInput";
import { Results } from "./components/Results/Results";
import Auto from "react-animate-height";
const generateRandomHexString = () => {
const randomHex = [];

for (let i = 0; i < 6; i++) {
randomHex.push(DIGITS[Math.floor(Math.random() * 16)]);
}
return randomHex;
};

const PADDING = 40;

export const ColorGame = memo(function ColorGame() {
const [color, setColor] = useState(generateRandomHexString);
const [report, setReport] = useState();
const [height, setHeight] = useState("auto");

const resetColor = useCallback(
() => setColor(generateRandomHexString()),
[]
);

useEffect(() => {
const element = contentRef.current;

const resizeObserver = new ResizeObserver(() => {
setHeight(element.clientHeight + PADDING);
});

resizeObserver.observe(element);

return () => resizeObserver.disconnect();
}, []);
const contentRef = useRef(null);

return (
<div className={cn.page}>
<Text
size="XL"
className={clsx(cn.centered, "wait dx bold color blue")}
>
Guess the color
</Text>

<Auto
duration={500}
height={height}
className={clsx(cn.container, "slim")}
contentRef={contentRef}
>
<div className={clsx(cn.split)}>
<div
className={cn.color}
style={{ backgroundColor: "#" + color.join("") }}
></div>
<HexColorInput
color={color}
setReport={setReport}
resetColor={resetColor}
/>
</div>
{report && <Results report={report} />}
</Auto>
<Leaderboard report={report} />
</div>
);
});
48 changes: 48 additions & 0 deletions src/app/pages/ColorGame/ColorGame.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

.centered {
text-align: center;
}
.page {
min-height: calc(100vh - 88px);
display: grid;
place-content: center;
box-sizing: border-box;

grid-auto-flow: row;
gap: 20px;
margin: 0 auto;

padding: 20px;
box-sizing: border-box;


.container {
padding: 20px;
border: 2px solid var(--silver);
border-radius: 18px;

.split {
display: grid;
grid-template-columns: auto 1fr;
gap: 20px;

.color {
height: 200px;
width: 200px;
border-radius: 8px;
margin-bottom: 0px;
}

@media screen and (max-width: 900px) {
grid-template-columns: auto;
gap: 20px;

.color {
width: 100%;
margin: 0 auto;
}

}
}
}
}
138 changes: 138 additions & 0 deletions src/app/pages/ColorGame/components/HexColorInput/HexColorInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { createRef, memo, useMemo, useState } from "react";
import cn from "./HexColorInput.module.scss";
import clsx from "clsx";
import { generateReport } from "./generateReport";
import REFRESH_ICON from "./refresh.png";

export const DIGITS = [
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"A",
"B",
"C",
"D",
"E",
"F",
];

const EMPTY_GUESS = ["", "", "", "", "", ""];

const focusEndOfInput = (inputEl) => {
inputEl.focus();
inputEl.setSelectionRange(-1, -1);
};

export const HexColorInput = memo(function HexColorInput({
color,
setReport,
resetColor,
}) {
const [guess, setGuess] = useState(EMPTY_GUESS);
const [input] = useState(() => Array.from({ length: 6 }, createRef));

const guessIsValid = useMemo(() => guess.join("").length === 6, [guess]);

const ignoreEvent = (event) => {
event.preventDefault();
};

const handleSubmit = (event) => {
event.preventDefault();
if (!guessIsValid) return;

setReport(generateReport(color, guess));
};

const refresh = () => {
resetColor();
setGuess(EMPTY_GUESS);
setReport();
focusEndOfInput(input[0].current);
};

const handleChange = (index) => (event) => {
const userKeyInput = event.key.toUpperCase();

switch (event.key) {
case "Backspace":
if (index > 0 && !guess[index].length) {
focusEndOfInput(input[index - 1].current);
}
setGuess((prev) => {
const next = [...prev];
next[!guess[index].length ? index - 1 : index] = "";
return next;
});
return;

case "ArrowLeft":
if (index === 0) return;
focusEndOfInput(input[index - 1].current);
return;

case "ArrowRight":
if (index > 5) return;
focusEndOfInput(input[index + 1].current);
return;

default:
if (!DIGITS.includes(userKeyInput)) return;

setGuess((prev) => {
const next = [...prev];
next[index] = userKeyInput;
return next;
});

if (index > 4) return;
focusEndOfInput(input[index + 1].current);
}
};
return (
<form className={cn.container} onSubmit={handleSubmit}>
<div className={cn.input}>
<input
className={cn.underline}
type="text"
contentEditable={false}
value="#"
readOnly
/>
{guess.map((digit, index) => (
<input
key={index}
ref={input[index]}
type="text"
value={digit}
onChange={ignoreEvent}
onKeyDown={handleChange(index)}
placeholder="F"
/>
))}
</div>
<div className={cn.actions}>
<button
className={clsx(cn.submit, guessIsValid && cn.allowed)}
type="submit"
>
Submit
</button>
<button
className={clsx(cn.retry)}
type="button"
onClick={refresh}
>
<img alt="refresh" src={REFRESH_ICON} />
</button>
</div>
</form>
);
});
Loading

0 comments on commit fd965e8

Please sign in to comment.