├── .gitignore
├── public
├── favicon.png
├── manifest.json
└── index.html
├── src
├── components
│ ├── Wrapper.js
│ ├── ButtonBox.css
│ ├── ButtonBox.js
│ ├── Wrapper.css
│ ├── Button.js
│ ├── Screen.css
│ ├── Button.css
│ └── Screen.js
├── index.js
├── index.css
└── App.js
├── README.md
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 |
4 | # production
5 | /build
6 |
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madzadev/calculator/HEAD/public/favicon.png
--------------------------------------------------------------------------------
/src/components/Wrapper.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./Wrapper.css";
3 |
4 | const Wrapper = ({ children }) => {
5 | return
{children}
;
6 | };
7 |
8 | export default Wrapper;
9 |
--------------------------------------------------------------------------------
/src/components/ButtonBox.css:
--------------------------------------------------------------------------------
1 | .buttonBox {
2 | width: 100%;
3 | height: calc(100% - 110px);
4 | display: grid;
5 | grid-template-columns: repeat(4, 1fr);
6 | grid-template-rows: repeat(5, 1fr);
7 | grid-gap: 10px;
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/ButtonBox.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./ButtonBox.css";
3 |
4 | const ButtonBox = ({ children }) => {
5 | return {children}
;
6 | };
7 |
8 | export default ButtonBox;
9 |
--------------------------------------------------------------------------------
/src/components/Wrapper.css:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | width: 340px;
3 | height: 540px;
4 | padding: 10px;
5 | border-radius: 10px;
6 | background-color: #485461;
7 | background-image: linear-gradient(315deg, #485461 0%, #28313b 74%);
8 | }
9 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Calculator App",
3 | "name": "Calculator App by Madza",
4 | "icons": [
5 | {
6 | "src": "favicon.png",
7 | "type": "image/x-icon"
8 | }
9 | ],
10 | "start_url": ".",
11 | "display": "standalone"
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/Button.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./Button.css";
3 |
4 | const Button = ({ className, value, onClick }) => {
5 | return (
6 |
9 | );
10 | };
11 |
12 | export default Button;
13 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 |
4 | import App from "./App";
5 | import "./index.css";
6 |
7 | const rootElement = document.getElementById("root");
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | rootElement
13 | );
14 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Montserrat&display=swap");
2 |
3 | * {
4 | margin: 0;
5 | padding: 0;
6 | font-family: "Montserrat", sans-serif;
7 | }
8 |
9 | body {
10 | height: 100vh;
11 | display: flex;
12 | align-items: center;
13 | justify-content: center;
14 | background-color: #fbb034;
15 | background-image: linear-gradient(315deg, #fbb034 0%, #ffdd00 74%);
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/Screen.css:
--------------------------------------------------------------------------------
1 | .screen {
2 | height: 100px;
3 | width: 340px;
4 | margin-bottom: 10px;
5 | padding: 0 10px;
6 | background-color: #4357692d;
7 | border-radius: 10px;
8 | display: flex;
9 | align-items: center;
10 | justify-content: flex-end;
11 | color: white;
12 | font-weight: bold;
13 | box-sizing: border-box;
14 | }
15 |
16 | .responsive-text {
17 | white-space: nowrap;
18 | overflow: hidden;
19 | margin: 0;
20 | }
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Calculator
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/components/Button.css:
--------------------------------------------------------------------------------
1 | button {
2 | border: none;
3 | background-color: rgb(80, 60, 209);
4 | font-size: 24px;
5 | color: rgb(255, 255, 255);
6 | font-weight: bold;
7 | cursor: pointer;
8 | border-radius: 10px;
9 | outline: none;
10 | }
11 |
12 | button:hover {
13 | background-color: rgb(61, 43, 184);
14 | }
15 |
16 | .equals {
17 | grid-column: 3 / 5;
18 | background-color: rgb(243, 61, 29);
19 | }
20 |
21 | .equals:hover {
22 | background-color: rgb(228, 39, 15);
23 | }
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Calculator
2 |
3 | A calculator project built with React.
4 |
5 | 
6 |
7 | ## Features
8 |
9 | 1. Add, subtract, multiply, divide
10 | 2. Support decimal values
11 | 3. Calculate percentages
12 | 4. Invert the values
13 | 5. Reset functionality
14 | 6. Format larger numbers
15 | 7. Output resize based on length
16 |
17 | ## Installation
18 |
19 | 1. `git clone https://github.com/madzadev/calculator.git`
20 |
21 | 2. `cd calculator`
22 |
23 | 3. `npm install`
24 |
25 | 4. `npm start`
26 |
27 | ## Contributions
28 |
29 | Any feature requests and pull requests are welcome!
30 |
31 | ## License
32 |
33 | The project is under [MIT license](https://choosealicense.com/licenses/mit/).
34 |
--------------------------------------------------------------------------------
/src/components/Screen.js:
--------------------------------------------------------------------------------
1 | import React, { useRef, useEffect } from "react";
2 | import "./Screen.css";
3 |
4 | const Screen = ({ value }) => {
5 | const textRef = useRef(null);
6 |
7 | useEffect(() => {
8 | const adjustFontSize = () => {
9 | const element = textRef.current;
10 | let fontSize = 70;
11 |
12 | element.style.fontSize = `${fontSize}px`;
13 |
14 | while (element.scrollWidth > element.clientWidth && fontSize > 1) {
15 | fontSize--;
16 | element.style.fontSize = `${fontSize}px`;
17 | }
18 | };
19 |
20 | adjustFontSize();
21 | }, [value]);
22 |
23 | return (
24 |
25 |
26 | {value}
27 |
28 |
29 | );
30 | };
31 |
32 | export default Screen;
33 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "homepage": "https://calculator-madza.netlify.app",
3 | "name": "calculator",
4 | "version": "0.1.0",
5 | "private": true,
6 | "dependencies": {
7 | "react": "^16.13.1",
8 | "react-dom": "^16.13.1",
9 | "react-scripts": "3.4.1"
10 | },
11 | "scripts": {
12 | "start": "react-scripts --openssl-legacy-provider start",
13 | "build": "react-scripts build",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": {
20 | "production": [
21 | ">0.2%",
22 | "not dead",
23 | "not op_mini all"
24 | ],
25 | "development": [
26 | "last 1 chrome version",
27 | "last 1 firefox version",
28 | "last 1 safari version"
29 | ]
30 | },
31 | "devDependencies": {
32 | "@babel/preset-react": "^7.22.5"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | import Wrapper from "./components/Wrapper";
4 | import Screen from "./components/Screen";
5 | import ButtonBox from "./components/ButtonBox";
6 | import Button from "./components/Button";
7 |
8 | const btnValues = [
9 | ["C", "+-", "%", "/"],
10 | [7, 8, 9, "X"],
11 | [4, 5, 6, "-"],
12 | [1, 2, 3, "+"],
13 | [0, ".", "="],
14 | ];
15 |
16 | const toLocaleString = (num) =>
17 | String(num).replace(/(? num.toString().replace(/\s/g, "");
20 |
21 | const math = (a, b, sign) =>
22 | sign === "+" ? a + b : sign === "-" ? a - b : sign === "X" ? a * b : a / b;
23 |
24 | const zeroDivisionError = "Can't divide with 0";
25 |
26 | const App = () => {
27 | let [calc, setCalc] = useState({
28 | sign: "",
29 | num: 0,
30 | res: 0,
31 | });
32 |
33 | const numClickHandler = (e) => {
34 | e.preventDefault();
35 | const value = e.target.innerHTML;
36 | if (removeSpaces(calc.num).length < 16) {
37 | setCalc({
38 | ...calc,
39 | num:
40 | removeSpaces(calc.num) % 1 === 0 && !calc.num.toString().includes(".")
41 | ? toLocaleString(Number(removeSpaces(calc.num + value)))
42 | : toLocaleString(calc.num + value),
43 | res: !calc.sign ? 0 : calc.res,
44 | });
45 | }
46 | };
47 |
48 | const comaClickHandler = (e) => {
49 | e.preventDefault();
50 | const value = e.target.innerHTML;
51 |
52 | setCalc({
53 | ...calc,
54 | num: !calc.num.toString().includes(".") ? calc.num + value : calc.num,
55 | });
56 | };
57 |
58 | const signClickHandler = (e) => {
59 | setCalc({
60 | ...calc,
61 | sign: e.target.innerHTML,
62 | res: !calc.num
63 | ? calc.res
64 | : !calc.res
65 | ? calc.num
66 | : toLocaleString(
67 | math(
68 | Number(removeSpaces(calc.res)),
69 | Number(removeSpaces(calc.num)),
70 | calc.sign
71 | )
72 | ),
73 | num: 0,
74 | });
75 | };
76 |
77 | const equalsClickHandler = () => {
78 | if (calc.sign && calc.num) {
79 | setCalc({
80 | ...calc,
81 | res:
82 | calc.num === "0" && calc.sign === "/"
83 | ? zeroDivisionError
84 | : toLocaleString(
85 | math(
86 | Number(removeSpaces(calc.res)),
87 | Number(removeSpaces(calc.num)),
88 | calc.sign
89 | )
90 | ),
91 | sign: "",
92 | num: 0,
93 | });
94 | }
95 | };
96 |
97 | const invertClickHandler = () => {
98 | setCalc({
99 | ...calc,
100 | num: calc.num ? toLocaleString(removeSpaces(calc.num) * -1) : 0,
101 | res: calc.res ? toLocaleString(removeSpaces(calc.res) * -1) : 0,
102 | sign: calc.sign,
103 | });
104 | };
105 |
106 | const percentClickHandler = () => {
107 | let num = calc.num ? parseFloat(removeSpaces(calc.num)) : 0;
108 | let res = calc.res ? parseFloat(removeSpaces(calc.res)) : 0;
109 | setCalc({
110 | ...calc,
111 | num: (num /= Math.pow(100, 1)),
112 | res: (res /= Math.pow(100, 1)),
113 | sign: "",
114 | });
115 | };
116 |
117 | const resetClickHandler = () => {
118 | setCalc({
119 | ...calc,
120 | sign: "",
121 | num: 0,
122 | res: 0,
123 | });
124 | };
125 |
126 | const buttonClickHandler = (e, btn) => {
127 | btn === "C" || calc.res === zeroDivisionError
128 | ? resetClickHandler()
129 | : btn === "+-"
130 | ? invertClickHandler()
131 | : btn === "%"
132 | ? percentClickHandler()
133 | : btn === "="
134 | ? equalsClickHandler()
135 | : btn === "/" || btn === "X" || btn === "-" || btn === "+"
136 | ? signClickHandler(e)
137 | : btn === "."
138 | ? comaClickHandler(e)
139 | : numClickHandler(e);
140 | };
141 |
142 | return (
143 |
144 |
145 |
146 | {btnValues.flat().map((btn, i) => {
147 | return (
148 |
157 |
158 | );
159 | };
160 |
161 | export default App;
162 |
--------------------------------------------------------------------------------