Implement CS bingo
This commit is contained in:
parent
350920f436
commit
986e35ecc7
@ -7,7 +7,7 @@
|
|||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Web site created using create-react-app"
|
content="CS Copenhagen Major Bingo"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<!--
|
<!--
|
||||||
@ -24,7 +24,7 @@
|
|||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>React App</title>
|
<title>CS Tournament Bingo</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"short_name": "React App",
|
"short_name": "CS Tournament Bingo",
|
||||||
"name": "Create React App Sample",
|
"name": "CS Copenhagen Major Bingo",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
|
84
src/App.css
84
src/App.css
@ -1,38 +1,70 @@
|
|||||||
.App {
|
@font-face {
|
||||||
text-align: center;
|
font-family: "cs_regular";
|
||||||
|
src: url(./cs_regular.ttf) format("ttf");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
h1, span {
|
||||||
.App-logo {
|
user-select: none;
|
||||||
height: 40vmin;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
|
.container {
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
padding: 5px;
|
||||||
.App-logo {
|
|
||||||
animation: App-logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-header {
|
|
||||||
background-color: #282c34;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
margin: auto;
|
||||||
font-size: calc(10px + 2vmin);
|
}
|
||||||
|
.bingo-board {
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
.bingo-board > div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.bingo-board > div > div {
|
||||||
|
background: #E48720;
|
||||||
|
display: grid;
|
||||||
|
border-radius: .5rem;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
.bingo-board div span {
|
||||||
|
font-size: 3.5rem;
|
||||||
|
place-self: center;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
.legend {
|
||||||
.App-link {
|
display: grid;
|
||||||
color: #61dafb;
|
grid-template-columns: auto 1fr;
|
||||||
|
column-gap: 1rem;
|
||||||
|
}
|
||||||
|
.legend .header span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
div.highlighted {
|
||||||
|
animation: fadeinout 1s linear;
|
||||||
|
}
|
||||||
|
div > div.begone {
|
||||||
|
animation: disappear 1s forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes App-logo-spin {
|
@keyframes fadeinout {
|
||||||
from {
|
0% {
|
||||||
transform: rotate(0deg);
|
background-color: white;
|
||||||
}
|
}
|
||||||
to {
|
50% {
|
||||||
transform: rotate(360deg);
|
background-color: yellow;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes disappear {
|
||||||
|
0% {
|
||||||
|
transform: scale(1) rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(0) rotate(720deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
118
src/App.tsx
118
src/App.tsx
@ -1,24 +1,106 @@
|
|||||||
import React from 'react';
|
import React, { Fragment, useEffect, useState } from 'react';
|
||||||
import logo from './logo.svg';
|
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
|
||||||
function App() {
|
import {prompts} from './prompts';
|
||||||
|
|
||||||
|
const alphabet = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
|
||||||
|
const lskey_prompts = "cs_bingo_prompts";
|
||||||
|
const lskey_ticked = "cs_bingo_ticked";
|
||||||
|
|
||||||
|
const shuffle = <T,>(array: T[]): T[] => {
|
||||||
|
return array
|
||||||
|
.map((item) => ({ key: Math.random(), value: item }))
|
||||||
|
.sort((a, b) => b.key - a.key)
|
||||||
|
.map((item) => item.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const App: React.FC<{}> = () => {
|
||||||
|
const [resetCounter, setResetCounter] = useState(0);
|
||||||
|
const [lines, setLines] = useState<[string,string][]>([]);
|
||||||
|
const saveLines = (lines: [string,string][]) => {
|
||||||
|
localStorage.setItem(lskey_prompts, JSON.stringify(lines));
|
||||||
|
};
|
||||||
|
const saveTicks = (lines: boolean[]) => {
|
||||||
|
localStorage.setItem(lskey_ticked, JSON.stringify(lines));
|
||||||
|
};
|
||||||
|
const [highlighted, setHighlighted] = useState<null| number>(null);
|
||||||
|
const highlight = (index: number) => {
|
||||||
|
setHighlighted(index);
|
||||||
|
setTimeout(() => setHighlighted(null), 800);
|
||||||
|
document.getElementById("letter-" + alphabet[index])?.scrollIntoView();
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("no lines");
|
||||||
|
if (lines.length !== 0) return;
|
||||||
|
const loadLines = localStorage.getItem(lskey_prompts);
|
||||||
|
const loadTicks = localStorage.getItem(lskey_ticked);
|
||||||
|
if (loadLines === null || loadTicks === null) {
|
||||||
|
const newPrompts = shuffle(prompts).slice(0, 25)
|
||||||
|
const newTicks = new Array(25).fill(false);
|
||||||
|
setLines(newPrompts);
|
||||||
|
setTicked(newTicks);
|
||||||
|
saveLines(newPrompts);
|
||||||
|
saveTicks(newTicks);
|
||||||
|
} else {
|
||||||
|
setLines(JSON.parse(loadLines));
|
||||||
|
setTicked(JSON.parse(loadTicks));
|
||||||
|
}
|
||||||
|
}, [lines])
|
||||||
|
|
||||||
|
const [ticked, setTicked] = useState<boolean[]>(new Array(25).fill(false) );
|
||||||
|
const toggleField = (index: number) => {
|
||||||
|
console.log("ticking", index);
|
||||||
|
setTicked((old) => {
|
||||||
|
const newTicks = old.map((e, i) => i === index ? !e : e);
|
||||||
|
saveTicks(newTicks);
|
||||||
|
return newTicks;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const incCounter = () => {
|
||||||
|
setResetCounter((old) => {
|
||||||
|
if (old === 15) {
|
||||||
|
const newPrompts = shuffle(prompts).slice(0, 25)
|
||||||
|
const newTicked = new Array(25).fill(false) ;
|
||||||
|
setLines(newPrompts);
|
||||||
|
setTicked(newTicked);
|
||||||
|
saveLines(newPrompts);
|
||||||
|
saveTicks(newTicked)
|
||||||
|
}
|
||||||
|
return old + 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="container">
|
||||||
<header className="App-header">
|
<h1 onClick={incCounter}>CS Bingo</h1>
|
||||||
<img src={logo} className="App-logo" alt="logo" />
|
<div className="bingo-board">
|
||||||
<p>
|
{Array.from(alphabet).map((e, index) =>
|
||||||
Edit <code>src/App.tsx</code> and save to reload.
|
<div key={index} >
|
||||||
</p>
|
<div className={ticked[index] ? "begone": undefined} onClick={() => highlight(index)} onContextMenu={(e) => {e.preventDefault(); toggleField(index);}}>
|
||||||
<a
|
<span>{e}</span>
|
||||||
className="App-link"
|
</div>
|
||||||
href="https://reactjs.org"
|
</div>
|
||||||
target="_blank"
|
)}
|
||||||
rel="noopener noreferrer"
|
</div>
|
||||||
>
|
<hr/>
|
||||||
Learn React
|
<div className="legend">
|
||||||
</a>
|
<div className="header">
|
||||||
</header>
|
<span>Letter</span>
|
||||||
|
</div>
|
||||||
|
<div className="header">
|
||||||
|
<span>Goal</span>
|
||||||
|
</div>
|
||||||
|
{lines.map(([category, line], index)=>
|
||||||
|
<Fragment key={index}>
|
||||||
|
<div className="entry-letter" id={"letter-" + alphabet[index]}>
|
||||||
|
<span>{alphabet[index]}</span>
|
||||||
|
</div>
|
||||||
|
<div className={"entry-text" + (highlighted === index ? " highlighted" : "")} >
|
||||||
|
<span>{line}</span>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
BIN
src/cs_regular.ttf
Normal file
BIN
src/cs_regular.ttf
Normal file
Binary file not shown.
40
src/prompts.ts
Normal file
40
src/prompts.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
type Categories = "kills" | "rounds" | "fails" | "epic" | "meta" | "unexpected";
|
||||||
|
export const prompts: [Categories, string][] = [
|
||||||
|
["kills", "Zeus Kill"],
|
||||||
|
["kills", "Knife Kill"],
|
||||||
|
["kills", "Team Kill"],
|
||||||
|
["kills", "HE Kill"],
|
||||||
|
["kills", "Molotov Kill"],
|
||||||
|
["rounds", "9 rounds in a row"],
|
||||||
|
["rounds", "10 rounds in one half"],
|
||||||
|
["fails", "Ninja Defuse"],
|
||||||
|
["fails", "Eco win vs Full Buy"],
|
||||||
|
["fails", "Trigger discipline moment"],
|
||||||
|
["fails", "Knife try"],
|
||||||
|
["fails", "Underestimated bomb radius"],
|
||||||
|
["fails", "T dies after time"],
|
||||||
|
["fails", "4:3 Moment"],
|
||||||
|
["fails", "CT forgot defuser"],
|
||||||
|
["fails", "CS2 is bug free"],
|
||||||
|
["fails", "Death while throwing util"],
|
||||||
|
["fails", "#Chicken Moment"],
|
||||||
|
["epic", "Ace"],
|
||||||
|
["epic", "IGL > 15 kills"],
|
||||||
|
["epic", "30 bomb"],
|
||||||
|
["epic", "AWP Collat"],
|
||||||
|
["epic", "Clutch 1v3"],
|
||||||
|
["epic", "Clutch 2v5"],
|
||||||
|
["epic", "Get down Mr. President!"],
|
||||||
|
["meta", "Inferno picked"],
|
||||||
|
["meta", "Double OT"],
|
||||||
|
["meta", "Rush B Blyat"],
|
||||||
|
["meta", "5 CTs save"],
|
||||||
|
["unexpected", "Ladder kill"],
|
||||||
|
["unexpected", "Kill while flashed"],
|
||||||
|
["unexpected", "AWP noscope"],
|
||||||
|
["unexpected", "Tech Timeout"],
|
||||||
|
["unexpected", "Player hiding in smoke"],
|
||||||
|
["unexpected", "150 damage with 1 HE"],
|
||||||
|
]
|
||||||
|
|
||||||
|
export default {};
|
Loading…
Reference in New Issue
Block a user