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 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 ( -
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
+
+ {tenzies && } +

Tenzies

+

Roll until all dice are the same. Click each die to freeze it at its current value between rolls.

+
+ {diceEmements} +
+ +
); } 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