diff --git a/package-lock.json b/package-lock.json
index 72153a1..922856f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,9 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "nanoid": "^4.0.0",
"react": "^18.2.0",
+ "react-confetti": "^6.1.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
@@ -11953,14 +11955,14 @@
}
},
"node_modules/nanoid": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
- "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
+ "integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==",
"bin": {
- "nanoid": "bin/nanoid.cjs"
+ "nanoid": "bin/nanoid.js"
},
"engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ "node": "^14 || ^16 || >=18"
}
},
"node_modules/natural-compare": {
@@ -13759,6 +13761,17 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
+ "node_modules/postcss/node_modules/nanoid": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
+ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -14026,6 +14039,20 @@
"node": ">=14"
}
},
+ "node_modules/react-confetti": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz",
+ "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==",
+ "dependencies": {
+ "tween-functions": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=10.18"
+ },
+ "peerDependencies": {
+ "react": "^16.3.0 || ^17.0.1 || ^18.0.0"
+ }
+ },
"node_modules/react-dev-utils": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@@ -15793,6 +15820,11 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
+ "node_modules/tween-functions": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz",
+ "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA=="
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -25553,9 +25585,9 @@
}
},
"nanoid": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
- "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
+ "integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg=="
},
"natural-compare": {
"version": "1.4.0",
@@ -26015,6 +26047,13 @@
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
+ },
+ "dependencies": {
+ "nanoid": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
+ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
+ }
}
},
"postcss-attribute-case-insensitive": {
@@ -26857,6 +26896,14 @@
"whatwg-fetch": "^3.6.2"
}
},
+ "react-confetti": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz",
+ "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==",
+ "requires": {
+ "tween-functions": "^1.2.0"
+ }
+ },
"react-dev-utils": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@@ -28168,6 +28215,11 @@
}
}
},
+ "tween-functions": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz",
+ "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA=="
+ },
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/package.json b/package.json
index 2a881f5..933abbe 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,9 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "nanoid": "^4.0.0",
"react": "^18.2.0",
+ "react-confetti": "^6.1.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
diff --git a/public/index.html b/public/index.html
index aa069f2..90829b2 100644
--- a/public/index.html
+++ b/public/index.html
@@ -10,6 +10,7 @@
content="Web site created using create-react-app"
/>
+
-
React App
+ Tenzies
You need to enable JavaScript to run this app.
diff --git a/public/logo192.png b/public/logo192.png
deleted file mode 100644
index fc44b0a..0000000
Binary files a/public/logo192.png and /dev/null differ
diff --git a/public/logo512.png b/public/logo512.png
deleted file mode 100644
index a4e47a6..0000000
Binary files a/public/logo512.png and /dev/null differ
diff --git a/public/manifest.json b/public/manifest.json
index 080d6c7..52f7e44 100644
--- a/public/manifest.json
+++ b/public/manifest.json
@@ -6,17 +6,8 @@
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
- },
- {
- "src": "logo192.png",
- "type": "image/png",
- "sizes": "192x192"
- },
- {
- "src": "logo512.png",
- "type": "image/png",
- "sizes": "512x512"
}
+
],
"start_url": ".",
"display": "standalone",
diff --git a/src/App.css b/src/App.css
index 74b5e05..2cbdb8f 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,38 +1,152 @@
-.App {
- text-align: center;
+*{
+ box-sizing: border-box;
}
-.App-logo {
- height: 40vmin;
- pointer-events: none;
+body {
+ margin: 0;
+ background-color: #0B2434;
+ padding: 60px 30px;
+ font-family: "Karla", sans-serif;
+ /* display: flex;
+ justify-content: center; */
+ -webkit-user-select: none;
+ user-select: none;
+
+}
+main {
+ background-color: #F5F5F5;
+ height: 700px;
+ max-width: 100%;
+ padding: 15px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+ align-items: center;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ border-radius: 20px;
}
-@media (prefers-reduced-motion: no-preference) {
- .App-logo {
- animation: App-logo-spin infinite 20s linear;
- }
+.title {
+ font-size: 50px;
+ margin: 0;
+ color: #0f3d5a;
+ text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15);
}
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
+.dice-container {
+ display: grid;
+ grid-template: auto auto / repeat(5, 1fr);
+ gap: 10px;
+ padding: 0px 10px 0px 10px;
+ margin-bottom: 40px;
+}
+
+.dice {
+ height: 70px;
+ width: 70px;
+ padding: 12px;
+ margin: 4px;
+ background-color: white;
+ box-shadow: 0px 2px 2px 1px rgba(0.20, 0.5, 0.5, 0.20);
+ border-radius: 10px;
display: flex;
- flex-direction: column;
+ justify-content: center;
align-items: center;
+ cursor: pointer;
+
+}
+.die-face {
+ border-radius: 10px;
+}
+.dot {
+ display: block;
+ width: 13px;
+ height: 13px;
+ border-radius: 50%;
+ background-color: rgb(32, 29, 29);
+ display: flex;
+ align-self:auto;
+}
+
+.first-face {
+ display: flex;
justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
}
-.App-link {
- color: #61dafb;
+
+.second-face {
+ display: flex;
+ justify-content: space-between;
+ align-items: stretch;
+}
+
+.second-face .dot:nth-of-type(2) {
+ align-self: flex-end;
+}
+
+.third-face {
+ display: flex;
+ justify-content: space-between;
+ align-items: stretch;
+}
+
+.third-face .dot:nth-of-type(1) {
+ align-self: flex-end;
+}
+
+.third-face .dot:nth-of-type(2) {
+ align-self: center;
}
-@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
+.fourth-face,
+.sixth-face,
+.fifth-face {
+ display: flex;
+ justify-content: space-between;
+ align-items: stretch;
+}
+
+.fourth-face .column,
+.sixth-face .column,
+.fifth-face .column {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+
}
+
+.fifth-face .column:nth-of-type(2) {
+ justify-content: center;
+}
+
+.roll-dice{
+ width: 150px;
+ height: 50px;
+ border-radius: 6px;
+ border: none;
+ box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15);
+ background-color: #3eb86f;
+ font-size: 1.2rem;
+ font-weight: 700;
+ color: white;
+ font-family: "Karla";
+ cursor: pointer;
+}
+.roll-dice:focus {
+ outline: none;
+}
+.roll-dice:active {
+ box-shadow: inset 5px 5px 10px -3px rgba(0, 0, 0, 0.7);
+}
+
+.instructions {
+ font-family: 'Inter', sans-serif;
+ font-weight: 400;
+ color: #0f3d5a;
+ margin-top: 0;
+ padding: 0px 30px 0px;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/src/App.js b/src/App.js
index 3784575..47669a1 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,24 +1,76 @@
-import logo from './logo.svg';
+import React, { useState, useEffect} from "react";
+import { nanoid } from "nanoid";
import './App.css';
+import Die from "./Die";
+import Confetti from "react-confetti";
function App() {
+ const [dice, setDice] = useState(allNewDice());
+ const [tenzies, setTenzies] = React.useState(false)
+
+ useEffect(() => {
+ const allHeld = dice.every(die => die.isHeld)
+ const firstValue = dice[0].value
+ const allSameValue = dice.every(die => die.value === firstValue)
+ if (allHeld && allSameValue) {
+ setTenzies(true)
+ console.log("You won!")
+ }
+ }, [dice])
+
+ function generateNewDie() {
+ return {
+ value: Math.ceil(Math.random() * 6),
+ isHeld: false,
+ id: nanoid()
+ }
+ }
+
+ function allNewDice() {
+ const newDice = [];
+ for (let i = 0; i < 10; i++) {
+ newDice.push(generateNewDie())
+ }
+ return newDice;
+ }
+
+ function rollDice() {
+ if(!tenzies){
+ setDice(oldDice => oldDice.map(die => {
+ return die.isHeld ? die : generateNewDie()
+ }));
+ }else {
+ setTenzies(false)
+ setDice(allNewDice())
+ }
+ }
+
+ function holdDice(id) {
+ setDice(oldDice => oldDice.map(die => {
+ return die.id === id ?
+ {...die, isHeld: !die.isHeld} :
+ die
+ }))
+ }
+
+ const diceEmements = dice.map(die =>
+ holdDice(die.id)}
+ />
+ )
return (
-
+
+ {tenzies && }
+ Tenzies
+ Roll until all dice are the same. Click each die to freeze it at its current value between rolls.
+
+ {diceEmements}
+
+ {tenzies ? "New Game" : "Roll"}
+
);
}
diff --git a/src/Die.js b/src/Die.js
new file mode 100644
index 0000000..3600c5f
--- /dev/null
+++ b/src/Die.js
@@ -0,0 +1,94 @@
+
+
+function Die(props) {
+
+ const styles = {
+ backgroundColor: props.isHeld ? "#59E391" : "white"
+}
+
+ function face() {
+ switch (props.value) {
+ case 1:
+ return (
+
+
+
+ );
+ case 2:
+ return (
+
+
+
+
+ );
+ case 3:
+ return (
+
+
+
+
+
+ );
+ case 4:
+ return (
+
+ );
+ case 5:
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ case 6:
+ return (
+
+ );
+ default:
+ }
+ }
+
+
+
+ return(
+
+ {face()}
+
+ );
+}
+
+export default Die;
\ No newline at end of file
diff --git a/src/logo.svg b/src/logo.svg
deleted file mode 100644
index 9dfc1c0..0000000
--- a/src/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file