Animated almost functional scoreboard

This commit is contained in:
John Shaver 2023-01-17 15:37:29 -08:00
parent 28b5b22bdd
commit e36bb1adb2
6 changed files with 13179 additions and 47 deletions

13090
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,9 +13,13 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-spring": "^9.6.1",
"typescript": "^4.9.4", "typescript": "^4.9.4",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"dev-dependencies": {
"prettier": "^2.8.3"
},
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",

View File

@ -15,6 +15,9 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fredoka+One&family=Permanent+Marker&display=swap" rel="stylesheet">
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
@ -24,7 +27,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>Pax's Potty Chart</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>

View File

@ -1,38 +1,40 @@
.App { body {
text-align: center; font-family: 'Fredoka One', cursive;
color: #161a19;
} }
.App-logo { .score-board {
height: 40vmin; font-size: 75px;
pointer-events: none; padding: 30px;
margin: 20px 30px;
border: solid #161a19 3px;
-webkit-box-shadow: 3px 3px 15px 0px rgba(10,11,25,0.16);
box-shadow: 3px 3px 15px 0px rgba(10,11,25,0.16);
border-radius: 5px;
} }
.row {
@media (prefers-reduced-motion: no-preference) { display: flex;
.App-logo { font-size: 50px;
animation: App-logo-spin infinite 20s linear; width: auto;
} gap: 15px;
} padding: 10px 0;
margin: 15px 30px;
.App-header {
background-color: #282c34; }
min-height: 100vh;
.cell {
width: 80px;
height: 80px;
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: calc(10px + 2vmin); border: solid #161a19 3px;
color: white; background-color: #D1CEC9;
-webkit-box-shadow: 3px 3px 15px 0px rgba(10,11,25,0.16);
box-shadow: 3px 3px 15px 0px rgba(10,11,25,0.16);
border-radius: 5px;
} }
.App-link { .cell.checked {
color: #61dafb; background-color: unset;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
} }

View File

@ -1,24 +1,57 @@
import React from 'react'; import React from 'react';
import logo from './logo.svg';
import LoginForm from './LoginForm';
import ScoreCounter from './ScoreCounter';
import { useJSONLocalStorage, useLocalStorage } from './hooks/useLocalStorage';
import './App.css'; import './App.css';
const COLUMNS = [1,2,3,4,5,6,7,8,9,10];
interface Stats {
attempts: number;
scheduledPoops: number;
selfPoops: number;
cleanUndies: number;
streaks: number[];
currentStreakSince: number;
};
const initialStats:Stats = {
attempts: 1,
scheduledPoops: 1,
selfPoops: 1,
cleanUndies: 1,
streaks: [0,0,0,0],
currentStreakSince: Date.now()
};
function App() { function App() {
return (
const [stats, setStats] = useJSONLocalStorage<Stats>("stats", initialStats);
const [name] = useLocalStorage<string>("name", {});
const [password] = useLocalStorage<string>("password", {});
const { attempts, scheduledPoops, selfPoops, cleanUndies, streaks, currentStreakSince } = stats;
return !name || !password ? <LoginForm /> :(
<div className="App"> <div className="App">
<header className="App-header"> <div className="score-board">
<img src={logo} className="App-logo" alt="logo" /> Points: <ScoreCounter stats={stats}/>
<p> </div>
Edit <code>src/App.tsx</code> and save to reload. <div className="row attempt" onClick={() => setStats({...stats, attempts: attempts + 1 })}>
</p> {COLUMNS.map(i => <div className={`attempt cell ${i <= attempts ? "checked" : ""}`}>{i <= attempts ? "🚽" : ""}</div>)}
<a </div>
className="App-link" <div className="row scheduled-poops" onClick={() => setStats({...stats, scheduledPoops: scheduledPoops + 1 })}>
href="https://reactjs.org" {COLUMNS.map(i => <div className={`scheduled cell ${i <= scheduledPoops ? "checked" : ""}`}>{i <= scheduledPoops ? "💩" : ""}</div>)}
target="_blank" </div>
rel="noopener noreferrer" <div className="row self-poops" onClick={() => setStats({...stats, selfPoops: selfPoops + 1 })}>
> {COLUMNS.map(i => <div className={`self cell ${i <= selfPoops ? "checked" : ""}`}>{i <= selfPoops ? "💩" : ""}</div>)}
Learn React </div>
</a> <div className="row clean-undies" onClick={() => setStats({...stats, cleanUndies: cleanUndies + 1 })}>
</header> {COLUMNS.map(i => <div className={`clean-undies cell ${i <= cleanUndies ? "checked" : ""}`}>{i <= cleanUndies ? "🩲" : ""}</div>)}
</div>
<div className="streak-counter"></div>
</div> </div>
); );
} }

View File

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es6",
"lib": [ "lib": [
"dom", "dom",
"dom.iterable", "dom.iterable",