diff --git a/src/Checkbox.jsx b/src/Checkbox.jsx index c61f44f..3e1c02b 100644 --- a/src/Checkbox.jsx +++ b/src/Checkbox.jsx @@ -1,28 +1,15 @@ -import React from "react"; - -/** - * @note This is a basic checkbox component without onClick event handling. - * 💡 Please check the console for warning messages. - */ -class Checkbox extends React.Component { - constructor(props) { - super(props); - - this.state = { - check: false, - }; - } - - render() { - const { name, label } = this.props; - - return ( -
- - -
- ); - } +function Checkbox({ name, label, checked, onChange }) { + return ( +
+ + +
+ ); } export default Checkbox; diff --git a/src/CheckboxOnclick.jsx b/src/CheckboxOnclick.jsx deleted file mode 100644 index 76b8976..0000000 --- a/src/CheckboxOnclick.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from "react"; - -class CheckboxOnclick extends React.Component { - constructor(props) { - super(props); - - this.state = { - checked: false, - }; - } - - handleCheck = () => { - this.setState({ - checked: !this.state.checked, - }); - }; - - render() { - const { name, label } = this.props; - - return ( -
- - -
- ); - } -} - -export default CheckboxOnclick; diff --git a/src/ExampleDidMount.jsx b/src/ExampleDidMount.jsx deleted file mode 100644 index edbaf16..0000000 --- a/src/ExampleDidMount.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; - -class ExampleDidMount extends React.Component { - constructor(props) { - super(props); - console.log("Constructor"); - } - - componentDidMount() { - console.log("Component did mount!"); - } - - render() { - return

Component Mounted

; - } -} - -export default ExampleDidMount; diff --git a/src/ExampleDidUpdate.jsx b/src/ExampleDidUpdate.jsx deleted file mode 100644 index ab04c15..0000000 --- a/src/ExampleDidUpdate.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from "react"; - -class ExampleDidUpdate extends React.Component { - constructor(props) { - super(props); - this.state = { count: 0 }; - } - - componentDidUpdate() { - console.log("Component did update!"); - } - - increment = () => { - this.setState({ count: this.state.count + 1 }); - }; - - render() { - return ( -
-

Count: {this.state.count}

- -
- ); - } -} - -export default ExampleDidUpdate; diff --git a/src/ExampleWillUnmount.jsx b/src/ExampleWillUnmount.jsx deleted file mode 100644 index e28c249..0000000 --- a/src/ExampleWillUnmount.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; - -class ExampleWillUnmount extends React.Component { - componentWillUnmount() { - console.log("Component will unmount!"); - } - - render() { - return

Goodbye!

; - } -} - -export default ExampleWillUnmount; diff --git a/src/ParentComponent.jsx b/src/ParentComponent.jsx new file mode 100644 index 0000000..24bb600 --- /dev/null +++ b/src/ParentComponent.jsx @@ -0,0 +1,21 @@ +import { useState } from "react"; +import Checkbox from "./Checkbox"; + +function ParentComponent() { + const [hasAcceptedTerms, setHasAcceptedTerms] = useState(false); + + const handleAcceptTerms = () => { + setHasAcceptedTerms(!hasAcceptedTerms); + }; + + return ( + + ); +} + +export default ParentComponent; diff --git a/src/components/Game.css b/src/components/Game.css index 308b448..034820a 100644 --- a/src/components/Game.css +++ b/src/components/Game.css @@ -1,6 +1,12 @@ .game { + display: flex; + flex-direction: row; + justify-content: space-between; + margin: 2rem 20rem; +} + +.game .left { display: flex; flex-direction: column; align-items: center; - width: 40%; } diff --git a/src/components/Game.jsx b/src/components/Game.jsx index 073a38e..2d309d8 100644 --- a/src/components/Game.jsx +++ b/src/components/Game.jsx @@ -1,29 +1,64 @@ -import React from "react"; +import { useEffect, useState } from "react"; import "./Game.css"; +import items from "../items.json"; import { Gitcoin } from "./Gitcoin"; +import { Office } from "./Office"; import { Score } from "./Score"; +import { Store } from "./Store"; -export class Game extends React.Component { - constructor(props) { - super(props); +export function Game() { + const [lines, setLines] = useState(0); + const [linesPerMillisecond, setLinesPerMillisecond] = useState(0); + const [ownedItems, setOwnedItems] = useState({}); - this.state = { - lines: 0, - }; - } + useEffect(() => { + const interval = setInterval(() => { + setLines(lines + linesPerMillisecond); + }, 100); - handleClick() { - this.setState({ - lines: this.state.lines + 1, + return () => clearInterval(interval); + }, [lines, linesPerMillisecond]); + + useEffect(() => { + let count = 0; + + for (const name of Object.keys(ownedItems)) { + const item = items.find((element) => element.name === name); + count += item.linesPerMillisecond * ownedItems[name]; + } + + setLinesPerMillisecond(count); + }, [ownedItems]); + + const handleClick = () => { + setLines(lines + 1); + }; + + const handleBuy = (item) => { + setLines(lines - item.price); + setOwnedItems({ + ...ownedItems, + [item.name]: (ownedItems[item.name] || 0) + 1, }); - } - - render() { - return ( -
- - -
- ); - } + }; + + return ( +
+
+ + +
+ +
+ +
+ +
+ +
+
+ ); } diff --git a/src/components/Gitcoin.css b/src/components/Gitcoin.css index 77ad013..87aa5ff 100644 --- a/src/components/Gitcoin.css +++ b/src/components/Gitcoin.css @@ -6,8 +6,32 @@ background: transparent; outline: none; cursor: pointer; + + & > img { + width: 100%; + border-radius: 100%; + animation: bounce-up 0.2s; + } + + &:active > img { + animation: bounce-down 0.2s; + } } -.gitcoin > img { - width: 100%; +@keyframes bounce-up { + 0% { + transform: scale(0.9) + } + 100% { + transform: scale(1) + } } + +@keyframes bounce-down { + 0% { + transform: scale(1) + } + 100% { + transform: scale(0.9) + } +} \ No newline at end of file diff --git a/src/components/Gitcoin.jsx b/src/components/Gitcoin.jsx index 1253f02..f18eac6 100644 --- a/src/components/Gitcoin.jsx +++ b/src/components/Gitcoin.jsx @@ -1,15 +1,10 @@ -import React from "react"; import "./Gitcoin.css"; -import githubIcon from "../assets/github.svg"; +import githubIcon from "@/assets/github.svg"; -export class Gitcoin extends React.Component { - render() { - const { onClick } = this.props; - - return ( - - ); - } +export function Gitcoin({ onClick }) { + return ( + + ); } diff --git a/src/components/Office.jsx b/src/components/Office.jsx new file mode 100644 index 0000000..f07f047 --- /dev/null +++ b/src/components/Office.jsx @@ -0,0 +1,16 @@ +export function Office({ items }) { + return ( + <> +

Office

+ + + ); +} diff --git a/src/components/Score.jsx b/src/components/Score.jsx index f170105..cf6cba4 100644 --- a/src/components/Score.jsx +++ b/src/components/Score.jsx @@ -1,9 +1,8 @@ -import React from "react"; - -export class Score extends React.Component { - render() { - const { lines } = this.props; - - return

{lines} lines

; - } +export function Score({ lines, linesPerSecond }) { + return ( + <> +

{lines} lines

+ per second: {linesPerSecond} + + ); } diff --git a/src/components/Store.css b/src/components/Store.css new file mode 100644 index 0000000..b7b0b21 --- /dev/null +++ b/src/components/Store.css @@ -0,0 +1,11 @@ +.item { + display: flex; + width: 15rem; + flex-direction: row; + justify-content: space-between; +} + +.item > span, +.item > button { + margin-bottom: 0.5rem; +} diff --git a/src/components/Store.jsx b/src/components/Store.jsx new file mode 100644 index 0000000..87d88af --- /dev/null +++ b/src/components/Store.jsx @@ -0,0 +1,27 @@ +import "./Store.css"; +import items from "@/items.json"; + +export function Store({ lines, onBuy }) { + const canBuy = (item) => { + return lines >= item.price; + }; + + return ( + + ); +} diff --git a/src/items.json b/src/items.json new file mode 100644 index 0000000..f53c149 --- /dev/null +++ b/src/items.json @@ -0,0 +1,27 @@ +[ + { + "name": "Bash", + "price": 10, + "linesPerMillisecond": 0.1 + }, + { + "name": "Git", + "price": 100, + "linesPerMillisecond": 1.2 + }, + { + "name": "Javascript", + "price": 10000, + "linesPerMillisecond": 14.0 + }, + { + "name": "React", + "price": 50000, + "linesPerMillisecond": 75.0 + }, + { + "name": "Vim", + "price": 999999, + "linesPerMillisecond": 10000.0 + } +] \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx index 4db58c9..b69ab72 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,49 +1,12 @@ -import React from "react"; import { createRoot } from "react-dom/client"; -import Checkbox from "./Checkbox"; -import CheckboxOnclick from "./CheckboxOnclick"; -import ExampleDidMount from "./ExampleDidMount"; -import ExampleDidUpdate from "./ExampleDidUpdate"; -import ExampleWillUnmount from "./ExampleWillUnmount"; +import ParentComponent from "./ParentComponent"; import { Game } from "./components/Game"; -class Example extends React.Component { - constructor(props) { - super(props); - this.state = { - showComponent: true, - }; - } - - toggleComponent = () => { - this.setState((prevState) => ({ - showComponent: !prevState.showComponent, - })); - }; - - render() { - return ( -
- - {this.state.showComponent && } -
- ); - } -} - const root = createRoot(document.getElementById("root")); root.render( <> - - -

React Lifecycle Methods

- - - - {/* 💡 During the demo, uncomment the following lines ↙️ */} - {/*

GitClicker

- */} + + {/* 💡 Uncomment the following to enable the Game component */} + {/* */} , ); diff --git a/vite.config.js b/vite.config.js index 8b0f57b..356efd0 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,7 +1,13 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import path from "node:path"; +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; // https://vite.dev/config/ export default defineConfig({ plugins: [react()], -}) + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, +});