Animated almost functional scoreboard
This commit is contained in:
parent
28b5b22bdd
commit
e36bb1adb2
6 changed files with 13179 additions and 47 deletions
13090
package-lock.json
generated
13090
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -13,9 +13,13 @@
|
|||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-spring": "^9.6.1",
|
||||
"typescript": "^4.9.4",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"dev-dependencies": {
|
||||
"prettier": "^2.8.3"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
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="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.
|
||||
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.
|
||||
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>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
|
60
src/App.css
60
src/App.css
|
@ -1,38 +1,40 @@
|
|||
.App {
|
||||
text-align: center;
|
||||
body {
|
||||
font-family: 'Fredoka One', cursive;
|
||||
color: #161a19;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
.score-board {
|
||||
font-size: 75px;
|
||||
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;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
.row {
|
||||
display: flex;
|
||||
font-size: 50px;
|
||||
width: auto;
|
||||
gap: 15px;
|
||||
padding: 10px 0;
|
||||
margin: 15px 30px;
|
||||
|
||||
}
|
||||
|
||||
.cell {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
border: solid #161a19 3px;
|
||||
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 {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
.cell.checked {
|
||||
background-color: unset;
|
||||
}
|
||||
|
|
65
src/App.tsx
65
src/App.tsx
|
@ -1,24 +1,57 @@
|
|||
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';
|
||||
|
||||
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() {
|
||||
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">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" />
|
||||
<p>
|
||||
Edit <code>src/App.tsx</code> and save to reload.
|
||||
</p>
|
||||
<a
|
||||
className="App-link"
|
||||
href="https://reactjs.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learn React
|
||||
</a>
|
||||
</header>
|
||||
<div className="score-board">
|
||||
Points: <ScoreCounter stats={stats}/>
|
||||
</div>
|
||||
<div className="row attempt" onClick={() => setStats({...stats, attempts: attempts + 1 })}>
|
||||
{COLUMNS.map(i => <div className={`attempt cell ${i <= attempts ? "checked" : ""}`}>{i <= attempts ? "🚽" : ""}</div>)}
|
||||
</div>
|
||||
<div className="row scheduled-poops" onClick={() => setStats({...stats, scheduledPoops: scheduledPoops + 1 })}>
|
||||
{COLUMNS.map(i => <div className={`scheduled cell ${i <= scheduledPoops ? "checked" : ""}`}>{i <= scheduledPoops ? "💩" : ""}</div>)}
|
||||
</div>
|
||||
<div className="row self-poops" onClick={() => setStats({...stats, selfPoops: selfPoops + 1 })}>
|
||||
{COLUMNS.map(i => <div className={`self cell ${i <= selfPoops ? "checked" : ""}`}>{i <= selfPoops ? "💩" : ""}</div>)}
|
||||
</div>
|
||||
<div className="row clean-undies" onClick={() => setStats({...stats, cleanUndies: cleanUndies + 1 })}>
|
||||
{COLUMNS.map(i => <div className={`clean-undies cell ${i <= cleanUndies ? "checked" : ""}`}>{i <= cleanUndies ? "🩲" : ""}</div>)}
|
||||
</div>
|
||||
<div className="streak-counter"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"target": "es6",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
|
|
Loading…
Reference in a new issue