├── .babelrc ├── .eslintrc.json ├── .github └── workflows │ └── linters.yml ├── .gitignore ├── .stylelintrc.json ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt └── src ├── App.js ├── __tests__ ├── Calculator.test.js ├── Home.test.js ├── Items.test.js ├── Navbar.test.js ├── Quotes.spec.js └── __snapshots__ │ ├── Calculator.test.js.snap │ ├── Home.test.js.snap │ ├── Items.test.js.snap │ ├── Navbar.test.js.snap │ └── Quotes.spec.js.snap ├── components ├── Calculator.css ├── Calculator.js ├── Home.js ├── Items.js ├── Navbar.css ├── Navbar.js ├── Quotes.js └── logic │ ├── calculate.js │ ├── calculate.test.js │ ├── operate.js │ └── operate.test.js ├── index.css └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-react" 4 | ], 5 | "plugins": ["@babel/plugin-syntax-jsx"] 6 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "jest": true 6 | }, 7 | "parser": "@babel/eslint-parser", 8 | "parserOptions": { 9 | "ecmaFeatures": { 10 | "jsx": true 11 | }, 12 | "ecmaVersion": 2018, 13 | "sourceType": "module" 14 | }, 15 | "extends": ["airbnb", "plugin:react/recommended"], 16 | "plugins": ["react"], 17 | "rules": { 18 | "react/jsx-filename-extension": ["warn", { "extensions": [".js", ".jsx"] }], 19 | "react/react-in-jsx-scope": "off", 20 | "import/no-unresolved": "off", 21 | "no-shadow": "off" 22 | }, 23 | "ignorePatterns": [ 24 | "dist/", 25 | "build/" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: pull_request 4 | 5 | env: 6 | FORCE_COLOR: 1 7 | 8 | jobs: 9 | eslint: 10 | name: ESLint 11 | runs-on: ubuntu-18.04 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-node@v1 15 | with: 16 | node-version: "12.x" 17 | - name: Setup ESLint 18 | run: | 19 | npm install --save-dev eslint@7.x eslint-config-airbnb@18.x eslint-plugin-import@2.x eslint-plugin-jsx-a11y@6.x eslint-plugin-react@7.x eslint-plugin-react-hooks@4.x @babel/eslint-parser@7.x @babel/core@7.x @babel/plugin-syntax-jsx@7.x @babel/preset-env@7.x @babel/preset-react@7.x 20 | [ -f .eslintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/react-redux/.eslintrc.json 21 | [ -f .babelrc ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/react-redux/.babelrc 22 | - name: ESLint Report 23 | run: npx eslint . 24 | stylelint: 25 | name: Stylelint 26 | runs-on: ubuntu-18.04 27 | steps: 28 | - uses: actions/checkout@v2 29 | - uses: actions/setup-node@v1 30 | with: 31 | node-version: "12.x" 32 | - name: Setup Stylelint 33 | run: | 34 | npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x 35 | [ -f .stylelintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/react-redux/.stylelintrc.json 36 | - name: Stylelint Report 37 | run: npx stylelint "**/*.{css,scss}" 38 | nodechecker: 39 | name: node_modules checker 40 | runs-on: ubuntu-18.04 41 | steps: 42 | - uses: actions/checkout@v2 43 | - name: Check node_modules existence 44 | run: | 45 | if [ -d "node_modules/" ]; then echo -e "\e[1;31mThe node_modules/ folder was pushed to the repo. Please remove it from the GitHub repository and try again."; echo -e "\e[1;32mYou can set up a .gitignore file with this folder included on it to prevent this from happening in the future." && exit 1; fi 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard"], 3 | "plugins": ["stylelint-scss", "stylelint-csstree-validator"], 4 | "rules": { 5 | "at-rule-no-unknown": [ 6 | true, 7 | { 8 | "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"] 9 | } 10 | ], 11 | "scss/at-rule-no-unknown": [ 12 | true, 13 | { 14 | "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"] 15 | } 16 | ], 17 | "csstree/validator": true 18 | }, 19 | "ignoreFiles": ["build/**", "dist/**", "**/reset*.css", "**/bootstrap*.css", "**/*.js", "**/*.jsx"] 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Fayob 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Math Magician React Project 2 | 3 | ## Description 4 | 5 | "Math magicians" is a website for all fans of mathematics. It is a Single Page App (SPA) that allows users to: 6 | - Make simple calculations. 7 | - Read a random math-related quote. 8 | 9 | This project was based on learning React. 10 | 11 | ## Live Demo 12 | 13 | [Checkout the deployed app here](https://math-magician-app-by-fayob.netlify.app/) 14 | 15 | # Getting Started with Create React App 16 | 17 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 18 | 19 | ### Directory 20 | 21 | - This directory can be clone using `git clone git@github.com:Fayob/maths-magician-app.git` 22 | 23 | ## Available Scripts 24 | 25 | In the project directory, you can run: 26 | 27 | - `npm install` to install all dependencies 28 | 29 | - `npm start` to spin up the app in your web browser. 30 | 31 | ## Learn More 32 | 33 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 34 | 35 | To learn React, check out the [React documentation](https://reactjs.org/). 36 | 37 | ## Author 38 | 39 | 👨 Abimbola Favour Adedeji 40 | 41 | GitHub: [@fayob](https://github.com/fayob) 42 | 43 | Twitter: [@fabimworld2536](https://twitter.com/Fabimworld2536) 44 | 45 | LinkedIn: [@abimbola-ade](https://www.linkedin.com/in/abimbola-ade) 46 | 47 | ## Contributing 48 | 49 | Contributions, issues, and feature requests are welcome! Feel free to check the [issues page](#). 50 | 51 | ## Show your support 52 | 53 | Give a ⭐️ if you like this project! 54 | 55 | ## License 56 | 57 | This project is [MIT](./LICENSE) licensed. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "math-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "big-js": "^3.1.3", 10 | "prop-types": "^15.8.1", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0", 13 | "react-router-dom": "^6.4.2", 14 | "react-scripts": "5.0.1", 15 | "web-vitals": "^2.1.4" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | }, 41 | "devDependencies": { 42 | "@babel/core": "^7.19.6", 43 | "@babel/eslint-parser": "^7.19.1", 44 | "@babel/plugin-syntax-jsx": "^7.18.6", 45 | "@babel/preset-react": "^7.18.6", 46 | "eslint": "^7.32.0", 47 | "eslint-config-airbnb": "^18.2.1", 48 | "eslint-plugin-import": "^2.26.0", 49 | "eslint-plugin-jsx-a11y": "^6.6.1", 50 | "eslint-plugin-react": "^7.31.10", 51 | "eslint-plugin-react-hooks": "^4.6.0", 52 | "jest-watch-typeahead": "^0.6.5", 53 | "stylelint": "^13.13.1", 54 | "stylelint-config-standard": "^21.0.0", 55 | "stylelint-csstree-validator": "^1.9.0", 56 | "stylelint-scss": "^3.21.0" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohamedHNoor/maths-magician-app/ea7618fc49c8e419640fbf43cf274f97526b5225/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Math Magicians App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohamedHNoor/maths-magician-app/ea7618fc49c8e419640fbf43cf274f97526b5225/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohamedHNoor/maths-magician-app/ea7618fc49c8e419640fbf43cf274f97526b5225/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; 3 | import Navbar from './components/Navbar'; 4 | import Calculator from './components/Calculator'; 5 | import Home from './components/Home'; 6 | import Quotes from './components/Quotes'; 7 | 8 | const App = () => ( 9 | <> 10 | 11 | 12 | 13 | } /> 14 | } /> 15 | } /> 16 | 17 | 18 | 19 | 20 | ); 21 | 22 | export default App; 23 | -------------------------------------------------------------------------------- /src/__tests__/Calculator.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import '@testing-library/jest-dom'; 4 | 5 | import Calculator from '../components/Calculator'; 6 | 7 | describe('test for Calculator Component', () => { 8 | it('should render Calculator Component', () => { 9 | expect(render()).toMatchSnapshot(); 10 | }); 11 | 12 | it('should render Calculator Component', () => { 13 | render(); 14 | expect(screen.getByText('Let`s do some math!')).not.toBeNull(); 15 | expect(screen.queryByText('8')).toBeInTheDocument(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/__tests__/Home.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | 4 | import Home from '../components/Home'; 5 | 6 | describe('test for Home Component', () => { 7 | it('should render Home Component', () => { 8 | expect(render()).toMatchSnapshot(); 9 | }); 10 | 11 | it('should query text content', () => { 12 | render(); 13 | screen.debug(); 14 | 15 | expect(screen.queryByText(/Welcome to our page!/)).not.toBeNull(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/__tests__/Items.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import React from 'react'; 3 | import { render, screen, fireEvent } from '@testing-library/react'; 4 | 5 | import Item from '../components/Items'; 6 | 7 | const onClickHandler = jest.fn(); 8 | 9 | describe('test for Item Component', () => { 10 | it('should render Item component', () => { 11 | expect(render()).toMatchSnapshot(); 12 | }); 13 | 14 | it('should test for click event', () => { 15 | render( 16 | , 17 | ); 18 | 19 | fireEvent.click(screen.getByText('AC')); 20 | fireEvent.click(screen.getByText('AC')); 21 | fireEvent.click(screen.getByText('AC')); 22 | fireEvent.click(screen.getByText('AC')); 23 | 24 | expect(onClickHandler).toHaveBeenCalledTimes(4); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/__tests__/Navbar.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { BrowserRouter } from 'react-router-dom'; 4 | 5 | import Navbar from '../components/Navbar'; 6 | 7 | describe('test for Navbar Component', () => { 8 | it('should render Navbar Component', () => { 9 | expect(render(, { wrapper: BrowserRouter })).toMatchSnapshot(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/__tests__/Quotes.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import Quotes from '../components/Quotes'; 5 | 6 | describe('test for Quotes Component', () => { 7 | it('should render Quotes Component', () => { 8 | expect(render()).toMatchSnapshot(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/__tests__/__snapshots__/Calculator.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`test for Calculator Component should render Calculator Component 1`] = ` 4 | Object { 5 | "asFragment": [Function], 6 | "baseElement": 7 |
8 |
11 |

12 | Let\`s do some math! 13 |

14 |
17 |
20 | 0 21 |
22 |
25 | AC 26 |
27 |
30 | +/- 31 |
32 |
35 | % 36 |
37 |
40 | ÷ 41 |
42 |
45 | x 46 |
47 |
50 | - 51 |
52 |
55 | + 56 |
57 |
60 | = 61 |
62 |
65 | 1 66 |
67 |
70 | 2 71 |
72 |
75 | 3 76 |
77 |
80 | 4 81 |
82 |
85 | 5 86 |
87 |
90 | 6 91 |
92 |
95 | 7 96 |
97 |
100 | 8 101 |
102 |
105 | 9 106 |
107 |
110 | 0 111 |
112 |
115 | . 116 |
117 |
118 |
119 |
120 | , 121 | "container":
122 |
125 |

126 | Let\`s do some math! 127 |

128 |
131 |
134 | 0 135 |
136 |
139 | AC 140 |
141 |
144 | +/- 145 |
146 |
149 | % 150 |
151 |
154 | ÷ 155 |
156 |
159 | x 160 |
161 |
164 | - 165 |
166 |
169 | + 170 |
171 |
174 | = 175 |
176 |
179 | 1 180 |
181 |
184 | 2 185 |
186 |
189 | 3 190 |
191 |
194 | 4 195 |
196 |
199 | 5 200 |
201 |
204 | 6 205 |
206 |
209 | 7 210 |
211 |
214 | 8 215 |
216 |
219 | 9 220 |
221 |
224 | 0 225 |
226 |
229 | . 230 |
231 |
232 |
233 |
, 234 | "debug": [Function], 235 | "findAllByAltText": [Function], 236 | "findAllByDisplayValue": [Function], 237 | "findAllByLabelText": [Function], 238 | "findAllByPlaceholderText": [Function], 239 | "findAllByRole": [Function], 240 | "findAllByTestId": [Function], 241 | "findAllByText": [Function], 242 | "findAllByTitle": [Function], 243 | "findByAltText": [Function], 244 | "findByDisplayValue": [Function], 245 | "findByLabelText": [Function], 246 | "findByPlaceholderText": [Function], 247 | "findByRole": [Function], 248 | "findByTestId": [Function], 249 | "findByText": [Function], 250 | "findByTitle": [Function], 251 | "getAllByAltText": [Function], 252 | "getAllByDisplayValue": [Function], 253 | "getAllByLabelText": [Function], 254 | "getAllByPlaceholderText": [Function], 255 | "getAllByRole": [Function], 256 | "getAllByTestId": [Function], 257 | "getAllByText": [Function], 258 | "getAllByTitle": [Function], 259 | "getByAltText": [Function], 260 | "getByDisplayValue": [Function], 261 | "getByLabelText": [Function], 262 | "getByPlaceholderText": [Function], 263 | "getByRole": [Function], 264 | "getByTestId": [Function], 265 | "getByText": [Function], 266 | "getByTitle": [Function], 267 | "queryAllByAltText": [Function], 268 | "queryAllByDisplayValue": [Function], 269 | "queryAllByLabelText": [Function], 270 | "queryAllByPlaceholderText": [Function], 271 | "queryAllByRole": [Function], 272 | "queryAllByTestId": [Function], 273 | "queryAllByText": [Function], 274 | "queryAllByTitle": [Function], 275 | "queryByAltText": [Function], 276 | "queryByDisplayValue": [Function], 277 | "queryByLabelText": [Function], 278 | "queryByPlaceholderText": [Function], 279 | "queryByRole": [Function], 280 | "queryByTestId": [Function], 281 | "queryByText": [Function], 282 | "queryByTitle": [Function], 283 | "rerender": [Function], 284 | "unmount": [Function], 285 | } 286 | `; 287 | -------------------------------------------------------------------------------- /src/__tests__/__snapshots__/Home.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`test for Home Component should render Home Component 1`] = ` 4 | Object { 5 | "asFragment": [Function], 6 | "baseElement": 7 |
8 |
11 |

12 | Welcome to our page! 13 |

14 |

15 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum 16 |

17 |

18 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum 19 |

20 |
21 |
22 | , 23 | "container":
24 |
27 |

28 | Welcome to our page! 29 |

30 |

31 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum 32 |

33 |

34 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum 35 |

36 |
37 |
, 38 | "debug": [Function], 39 | "findAllByAltText": [Function], 40 | "findAllByDisplayValue": [Function], 41 | "findAllByLabelText": [Function], 42 | "findAllByPlaceholderText": [Function], 43 | "findAllByRole": [Function], 44 | "findAllByTestId": [Function], 45 | "findAllByText": [Function], 46 | "findAllByTitle": [Function], 47 | "findByAltText": [Function], 48 | "findByDisplayValue": [Function], 49 | "findByLabelText": [Function], 50 | "findByPlaceholderText": [Function], 51 | "findByRole": [Function], 52 | "findByTestId": [Function], 53 | "findByText": [Function], 54 | "findByTitle": [Function], 55 | "getAllByAltText": [Function], 56 | "getAllByDisplayValue": [Function], 57 | "getAllByLabelText": [Function], 58 | "getAllByPlaceholderText": [Function], 59 | "getAllByRole": [Function], 60 | "getAllByTestId": [Function], 61 | "getAllByText": [Function], 62 | "getAllByTitle": [Function], 63 | "getByAltText": [Function], 64 | "getByDisplayValue": [Function], 65 | "getByLabelText": [Function], 66 | "getByPlaceholderText": [Function], 67 | "getByRole": [Function], 68 | "getByTestId": [Function], 69 | "getByText": [Function], 70 | "getByTitle": [Function], 71 | "queryAllByAltText": [Function], 72 | "queryAllByDisplayValue": [Function], 73 | "queryAllByLabelText": [Function], 74 | "queryAllByPlaceholderText": [Function], 75 | "queryAllByRole": [Function], 76 | "queryAllByTestId": [Function], 77 | "queryAllByText": [Function], 78 | "queryAllByTitle": [Function], 79 | "queryByAltText": [Function], 80 | "queryByDisplayValue": [Function], 81 | "queryByLabelText": [Function], 82 | "queryByPlaceholderText": [Function], 83 | "queryByRole": [Function], 84 | "queryByTestId": [Function], 85 | "queryByText": [Function], 86 | "queryByTitle": [Function], 87 | "rerender": [Function], 88 | "unmount": [Function], 89 | } 90 | `; 91 | -------------------------------------------------------------------------------- /src/__tests__/__snapshots__/Items.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`test for Item Component should render Item component 1`] = ` 4 | Object { 5 | "asFragment": [Function], 6 | "baseElement": 7 |
8 |
11 | a 12 |
13 |
14 | , 15 | "container":
16 |
19 | a 20 |
21 |
, 22 | "debug": [Function], 23 | "findAllByAltText": [Function], 24 | "findAllByDisplayValue": [Function], 25 | "findAllByLabelText": [Function], 26 | "findAllByPlaceholderText": [Function], 27 | "findAllByRole": [Function], 28 | "findAllByTestId": [Function], 29 | "findAllByText": [Function], 30 | "findAllByTitle": [Function], 31 | "findByAltText": [Function], 32 | "findByDisplayValue": [Function], 33 | "findByLabelText": [Function], 34 | "findByPlaceholderText": [Function], 35 | "findByRole": [Function], 36 | "findByTestId": [Function], 37 | "findByText": [Function], 38 | "findByTitle": [Function], 39 | "getAllByAltText": [Function], 40 | "getAllByDisplayValue": [Function], 41 | "getAllByLabelText": [Function], 42 | "getAllByPlaceholderText": [Function], 43 | "getAllByRole": [Function], 44 | "getAllByTestId": [Function], 45 | "getAllByText": [Function], 46 | "getAllByTitle": [Function], 47 | "getByAltText": [Function], 48 | "getByDisplayValue": [Function], 49 | "getByLabelText": [Function], 50 | "getByPlaceholderText": [Function], 51 | "getByRole": [Function], 52 | "getByTestId": [Function], 53 | "getByText": [Function], 54 | "getByTitle": [Function], 55 | "queryAllByAltText": [Function], 56 | "queryAllByDisplayValue": [Function], 57 | "queryAllByLabelText": [Function], 58 | "queryAllByPlaceholderText": [Function], 59 | "queryAllByRole": [Function], 60 | "queryAllByTestId": [Function], 61 | "queryAllByText": [Function], 62 | "queryAllByTitle": [Function], 63 | "queryByAltText": [Function], 64 | "queryByDisplayValue": [Function], 65 | "queryByLabelText": [Function], 66 | "queryByPlaceholderText": [Function], 67 | "queryByRole": [Function], 68 | "queryByTestId": [Function], 69 | "queryByText": [Function], 70 | "queryByTitle": [Function], 71 | "rerender": [Function], 72 | "unmount": [Function], 73 | } 74 | `; 75 | -------------------------------------------------------------------------------- /src/__tests__/__snapshots__/Navbar.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`test for Navbar Component should render Navbar Component 1`] = ` 4 | Object { 5 | "asFragment": [Function], 6 | "baseElement": 7 |
8 | 49 |
50 | , 51 | "container":
52 | 93 |
, 94 | "debug": [Function], 95 | "findAllByAltText": [Function], 96 | "findAllByDisplayValue": [Function], 97 | "findAllByLabelText": [Function], 98 | "findAllByPlaceholderText": [Function], 99 | "findAllByRole": [Function], 100 | "findAllByTestId": [Function], 101 | "findAllByText": [Function], 102 | "findAllByTitle": [Function], 103 | "findByAltText": [Function], 104 | "findByDisplayValue": [Function], 105 | "findByLabelText": [Function], 106 | "findByPlaceholderText": [Function], 107 | "findByRole": [Function], 108 | "findByTestId": [Function], 109 | "findByText": [Function], 110 | "findByTitle": [Function], 111 | "getAllByAltText": [Function], 112 | "getAllByDisplayValue": [Function], 113 | "getAllByLabelText": [Function], 114 | "getAllByPlaceholderText": [Function], 115 | "getAllByRole": [Function], 116 | "getAllByTestId": [Function], 117 | "getAllByText": [Function], 118 | "getAllByTitle": [Function], 119 | "getByAltText": [Function], 120 | "getByDisplayValue": [Function], 121 | "getByLabelText": [Function], 122 | "getByPlaceholderText": [Function], 123 | "getByRole": [Function], 124 | "getByTestId": [Function], 125 | "getByText": [Function], 126 | "getByTitle": [Function], 127 | "queryAllByAltText": [Function], 128 | "queryAllByDisplayValue": [Function], 129 | "queryAllByLabelText": [Function], 130 | "queryAllByPlaceholderText": [Function], 131 | "queryAllByRole": [Function], 132 | "queryAllByTestId": [Function], 133 | "queryAllByText": [Function], 134 | "queryAllByTitle": [Function], 135 | "queryByAltText": [Function], 136 | "queryByDisplayValue": [Function], 137 | "queryByLabelText": [Function], 138 | "queryByPlaceholderText": [Function], 139 | "queryByRole": [Function], 140 | "queryByTestId": [Function], 141 | "queryByText": [Function], 142 | "queryByTitle": [Function], 143 | "rerender": [Function], 144 | "unmount": [Function], 145 | } 146 | `; 147 | -------------------------------------------------------------------------------- /src/__tests__/__snapshots__/Quotes.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`test for Quotes Component should render Quotes Component 1`] = ` 4 | Object { 5 | "asFragment": [Function], 6 | "baseElement": 7 |
8 |
11 |

12 | Mathematics is not about numbers, equations, computations, or algorithms: it is about understanding. -William Paul Thurston 13 |

14 |
15 |
16 | , 17 | "container":
18 |
21 |

22 | Mathematics is not about numbers, equations, computations, or algorithms: it is about understanding. -William Paul Thurston 23 |

24 |
25 |
, 26 | "debug": [Function], 27 | "findAllByAltText": [Function], 28 | "findAllByDisplayValue": [Function], 29 | "findAllByLabelText": [Function], 30 | "findAllByPlaceholderText": [Function], 31 | "findAllByRole": [Function], 32 | "findAllByTestId": [Function], 33 | "findAllByText": [Function], 34 | "findAllByTitle": [Function], 35 | "findByAltText": [Function], 36 | "findByDisplayValue": [Function], 37 | "findByLabelText": [Function], 38 | "findByPlaceholderText": [Function], 39 | "findByRole": [Function], 40 | "findByTestId": [Function], 41 | "findByText": [Function], 42 | "findByTitle": [Function], 43 | "getAllByAltText": [Function], 44 | "getAllByDisplayValue": [Function], 45 | "getAllByLabelText": [Function], 46 | "getAllByPlaceholderText": [Function], 47 | "getAllByRole": [Function], 48 | "getAllByTestId": [Function], 49 | "getAllByText": [Function], 50 | "getAllByTitle": [Function], 51 | "getByAltText": [Function], 52 | "getByDisplayValue": [Function], 53 | "getByLabelText": [Function], 54 | "getByPlaceholderText": [Function], 55 | "getByRole": [Function], 56 | "getByTestId": [Function], 57 | "getByText": [Function], 58 | "getByTitle": [Function], 59 | "queryAllByAltText": [Function], 60 | "queryAllByDisplayValue": [Function], 61 | "queryAllByLabelText": [Function], 62 | "queryAllByPlaceholderText": [Function], 63 | "queryAllByRole": [Function], 64 | "queryAllByTestId": [Function], 65 | "queryAllByText": [Function], 66 | "queryAllByTitle": [Function], 67 | "queryByAltText": [Function], 68 | "queryByDisplayValue": [Function], 69 | "queryByLabelText": [Function], 70 | "queryByPlaceholderText": [Function], 71 | "queryByRole": [Function], 72 | "queryByTestId": [Function], 73 | "queryByText": [Function], 74 | "queryByTitle": [Function], 75 | "rerender": [Function], 76 | "unmount": [Function], 77 | } 78 | `; 79 | -------------------------------------------------------------------------------- /src/components/Calculator.css: -------------------------------------------------------------------------------- 1 | .calculator { 2 | display: flex; 3 | justify-content: center; 4 | gap: 2rem; 5 | } 6 | 7 | .calculator > h4 { 8 | font-size: 1rem; 9 | font-weight: 500; 10 | } 11 | 12 | .header { 13 | grid-area: header; 14 | color: white; 15 | padding-right: 0.5rem; 16 | font-size: 25px; 17 | height: 20px; 18 | justify-self: flex-end; 19 | align-self: center; 20 | } 21 | 22 | .AC { 23 | grid-area: AC; 24 | background: lightgray; 25 | } 26 | 27 | .addSub { 28 | grid-area: addSub; 29 | background: lightgray; 30 | } 31 | 32 | .percent { 33 | grid-area: percent; 34 | background: lightgray; 35 | } 36 | 37 | .divide { 38 | grid-area: divide; 39 | background: #ff9411; 40 | } 41 | 42 | .seven { 43 | grid-area: seven; 44 | background: lightgray; 45 | } 46 | 47 | .eight { 48 | grid-area: eight; 49 | background: lightgray; 50 | } 51 | 52 | .nine { 53 | grid-area: nine; 54 | background: lightgray; 55 | } 56 | 57 | .multiply { 58 | grid-area: multiply; 59 | background: #ff9411; 60 | } 61 | 62 | .four { 63 | grid-area: four; 64 | background: lightgray; 65 | } 66 | 67 | .five { 68 | grid-area: five; 69 | background: lightgray; 70 | } 71 | 72 | .six { 73 | grid-area: six; 74 | background: lightgray; 75 | } 76 | 77 | .minus { 78 | grid-area: minus; 79 | background: #ff9411; 80 | } 81 | 82 | .one { 83 | grid-area: one; 84 | background: lightgray; 85 | } 86 | 87 | .two { 88 | grid-area: two; 89 | background: lightgray; 90 | } 91 | 92 | .three { 93 | grid-area: three; 94 | background: lightgray; 95 | } 96 | 97 | .plus { 98 | grid-area: plus; 99 | background: #ff9411; 100 | } 101 | 102 | .zero { 103 | grid-area: zero; 104 | background: lightgray; 105 | } 106 | 107 | .dot { 108 | grid-area: dot; 109 | background: lightgray; 110 | } 111 | 112 | .equal { 113 | grid-area: equal; 114 | background: #ff9411; 115 | } 116 | 117 | .container { 118 | width: 400px; 119 | height: 400px; 120 | display: grid; 121 | text-align: center; 122 | grid-template-areas: 123 | "header header header header" 124 | "AC addSub percent divide" 125 | "seven eight nine multiply" 126 | "four five six minus" 127 | "one two three plus" 128 | "zero zero dot equal"; 129 | grid-gap: 0.15rem; 130 | background: darkgray; 131 | position: relative; 132 | } 133 | 134 | .container > div { 135 | display: flex; 136 | justify-content: center; 137 | align-items: center; 138 | } 139 | -------------------------------------------------------------------------------- /src/components/Calculator.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import Item from './Items'; 3 | import calculate from './logic/calculate'; 4 | 5 | import './Calculator.css'; 6 | 7 | const Calculator = () => { 8 | const [state, setState] = useState({ 9 | total: '0', 10 | next: null, 11 | operation: null, 12 | }); 13 | 14 | const clickHandler = (event) => { 15 | const text = event.target.textContent; 16 | const newState = calculate(state, text); 17 | setState({ ...newState }); 18 | }; 19 | 20 | const { total, next } = state; 21 | 22 | return ( 23 |
24 |

Let`s do some math!

25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
47 |
48 | ); 49 | }; 50 | 51 | export default Calculator; 52 | -------------------------------------------------------------------------------- /src/components/Home.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import React from 'react'; 3 | 4 | const Home = () => ( 5 |
6 |

Welcome to our page!

7 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum

8 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum

9 |
10 | ); 11 | 12 | export default Home; 13 | -------------------------------------------------------------------------------- /src/components/Items.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const Item = ({ value, className, onClickHandler }) => ( 5 |
6 | { value } 7 |
8 | ); 9 | 10 | Item.propTypes = { 11 | value: PropTypes.string.isRequired, 12 | className: PropTypes.string.isRequired, 13 | onClickHandler: PropTypes.func.isRequired, 14 | }; 15 | 16 | export default Item; 17 | -------------------------------------------------------------------------------- /src/components/Navbar.css: -------------------------------------------------------------------------------- 1 | .navbar { 2 | display: flex; 3 | justify-content: space-between; 4 | align-items: center; 5 | margin-bottom: 3rem; 6 | } 7 | 8 | .nav_lists { 9 | display: flex; 10 | text-decoration: underline; 11 | list-style-type: none; 12 | gap: 0.5rem; 13 | } 14 | 15 | .nav_list { 16 | height: 70%; 17 | padding-right: 0.5rem; 18 | border-right: 2px solid black; 19 | } 20 | 21 | .link { 22 | color: blue; 23 | text-decoration: none; 24 | } 25 | 26 | .hidden { 27 | border-right: none; 28 | } 29 | -------------------------------------------------------------------------------- /src/components/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | import './Navbar.css'; 4 | 5 | const Navbar = () => ( 6 | 20 | ); 21 | 22 | export default Navbar; 23 | -------------------------------------------------------------------------------- /src/components/Quotes.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import React from 'react'; 3 | 4 | const Quotes = () => ( 5 |
6 |

Mathematics is not about numbers, equations, computations, or algorithms: it is about understanding. -William Paul Thurston

7 |
8 | ); 9 | 10 | export default Quotes; 11 | -------------------------------------------------------------------------------- /src/components/logic/calculate.js: -------------------------------------------------------------------------------- 1 | import operate from './operate'; 2 | 3 | function isNumber(item) { 4 | return !!item.match(/[0-9]+/); 5 | } 6 | 7 | /** 8 | * Given a button name and a calculator data object, return an updated 9 | * calculator data object. 10 | * 11 | * Calculator data object contains: 12 | * total:s the running total 13 | * next:String the next number to be operated on with the total 14 | * operation:String +, -, etc. 15 | */ 16 | export default function calculate(obj, buttonName) { 17 | if (buttonName === 'AC') { 18 | return { 19 | total: '0', 20 | next: null, 21 | operation: null, 22 | }; 23 | } 24 | 25 | if (isNumber(buttonName)) { 26 | if (buttonName === '0' && obj.next === '0') { 27 | return {}; 28 | } 29 | // If there is an operation, update next 30 | if (obj.operation) { 31 | if (obj.next && obj.next !== '0') { 32 | return { ...obj, next: obj.next + buttonName }; 33 | } 34 | return { ...obj, next: buttonName }; 35 | } 36 | // If there is no operation, update next and clear the value 37 | if (obj.next && obj.next !== '0') { 38 | return { 39 | next: obj.next + buttonName, 40 | total: null, 41 | }; 42 | } 43 | return { 44 | next: buttonName, 45 | total: null, 46 | }; 47 | } 48 | 49 | if (buttonName === '.') { 50 | if (obj.next) { 51 | if (obj.next.includes('.')) { 52 | return { ...obj }; 53 | } 54 | return { ...obj, next: `${obj.next}.` }; 55 | } 56 | if (obj.operation) { 57 | return { ...obj, next: '0.' }; 58 | } 59 | if (obj.total) { 60 | if (obj.total.includes('.')) { 61 | return {}; 62 | } 63 | return { ...obj, next: `${obj.total}.` }; 64 | } 65 | return { ...obj, next: '0.' }; 66 | } 67 | 68 | if (buttonName === '=') { 69 | if (obj.next && obj.operation) { 70 | return { 71 | total: operate(obj.total, obj.next, obj.operation), 72 | next: null, 73 | operation: null, 74 | }; 75 | } 76 | // '=' with no operation, nothing to do 77 | return {}; 78 | } 79 | 80 | if (buttonName === '+/-') { 81 | if (obj.next) { 82 | return { ...obj, next: (-1 * parseFloat(obj.next)).toString() }; 83 | } 84 | if (obj.total) { 85 | return { ...obj, total: (-1 * parseFloat(obj.total)).toString() }; 86 | } 87 | return {}; 88 | } 89 | 90 | // Button must be an operation 91 | 92 | // When the user presses an operation button without having entered 93 | // a number first, do nothing. 94 | // if (!obj.next && !obj.total) { 95 | // return {}; 96 | // } 97 | 98 | // User pressed an operation after pressing '=' 99 | if (!obj.next && obj.total && !obj.operation) { 100 | return { ...obj, operation: buttonName }; 101 | } 102 | 103 | // User pressed an operation button and there is an existing operation 104 | if (obj.operation) { 105 | if (obj.total && !obj.next) { 106 | return { ...obj, operation: buttonName }; 107 | } 108 | 109 | if (!obj.total) { 110 | return { total: 0, operation: buttonName }; 111 | } 112 | 113 | return { 114 | total: operate(obj.total, obj.next, obj.operation), 115 | next: null, 116 | operation: buttonName, 117 | }; 118 | } 119 | 120 | // no operation yet, but the user typed one 121 | 122 | // The user hasn't typed a number yet, just save the operation 123 | if (!obj.next) { 124 | return { operation: buttonName }; 125 | } 126 | 127 | // save the operation and shift 'next' into 'total' 128 | return { 129 | total: obj.next, 130 | next: null, 131 | operation: buttonName, 132 | }; 133 | } 134 | -------------------------------------------------------------------------------- /src/components/logic/calculate.test.js: -------------------------------------------------------------------------------- 1 | import calculate from './calculate'; 2 | 3 | describe('testing calculate function', () => { 4 | test('should return an object with total', () => { 5 | expect(calculate({ total: '10', next: '5', operation: '+' }, '=')).toEqual({ total: '15', next: null, operation: null }); 6 | expect(calculate({ total: '10', next: '5', operation: '-' }, '=')).toEqual({ total: '5', next: null, operation: null }); 7 | expect(calculate({ total: '10', next: '5', operation: 'x' }, '=')).toEqual({ total: '50', next: null, operation: null }); 8 | expect(calculate({ total: '10', next: '5', operation: '÷' }, '=')).toEqual({ total: '2', next: null, operation: null }); 9 | }); 10 | 11 | test('should return an empty object', () => { 12 | expect(calculate({ total: '0', next: '5', operation: null }, '=')).toEqual({}); 13 | }); 14 | 15 | test('for the +/- buttonName', () => { 16 | expect(calculate({ total: '10', next: '5', operation: null }, '+/-')).toEqual({ total: '10', next: '-5', operation: null }); 17 | expect(calculate({ total: '10', next: null, operation: null }, '+/-')).toEqual({ total: '-10', next: null, operation: null }); 18 | }); 19 | 20 | test('should update next value property', () => { 21 | expect(calculate({ total: '10', next: '5', operation: '+' }, '8')).toEqual({ total: '10', next: '58', operation: '+' }); 22 | }); 23 | 24 | test('should reset all values to default', () => { 25 | expect(calculate({ total: '10', next: '5', operation: '+' }, 'AC')).toEqual({ total: '0', next: null, operation: null }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/components/logic/operate.js: -------------------------------------------------------------------------------- 1 | import Big from 'big-js'; 2 | 3 | export default function operate(numberOne, numberTwo, operation) { 4 | const one = Big(numberOne); 5 | const two = Big(numberTwo); 6 | if (operation === '+') { 7 | return one.plus(two).toString(); 8 | } 9 | if (operation === '-') { 10 | return one.minus(two).toString(); 11 | } 12 | if (operation === 'x') { 13 | return one.times(two).toString(); 14 | } 15 | if (operation === '÷') { 16 | try { 17 | return one.div(two).toString(); 18 | } catch (err) { 19 | return "Can't divide by 0."; 20 | } 21 | } 22 | if (operation === '%') { 23 | try { 24 | return one.mod(two).toString(); 25 | } catch (err) { 26 | return "Can't find modulo as can't divide by 0."; 27 | } 28 | } 29 | throw Error(`Unknown operation '${operation}'`); 30 | } 31 | -------------------------------------------------------------------------------- /src/components/logic/operate.test.js: -------------------------------------------------------------------------------- 1 | import operate from './operate'; 2 | 3 | describe('test for operate function', () => { 4 | it('should add numbers together', () => { 5 | expect(operate(1, 1, '+')).toBe('2'); 6 | }); 7 | 8 | it('should subtract numbers', () => { 9 | expect(operate('10', '7', '-')).toBe('3'); 10 | }); 11 | 12 | it('should multiply numbers', () => { 13 | expect(operate(10, 10, 'x')).toBe('100'); 14 | }); 15 | 16 | it('should divide numbers', () => { 17 | expect(operate('10', '2', '÷')).toBe('5'); 18 | expect(operate(3, 0, '÷')).toBe('Can\'t divide by 0.'); 19 | }); 20 | 21 | it('should find the modulus of numbers', () => { 22 | expect(operate(9, 2, '%')).toBe('1'); 23 | }); 24 | 25 | it('should throw an error', () => { 26 | expect(() => { 27 | operate(9, 2, '#'); 28 | }).toThrowError(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | margin: 1rem; 9 | padding: 1rem; 10 | font-family: 11 | -apple-system, 12 | BlinkMacSystemFont, 13 | 'Segoe UI', 14 | 'Roboto', 15 | 'Oxygen', 16 | 'Ubuntu', 17 | 'Cantarell', 18 | 'Fira Sans', 19 | 'Droid Sans', 20 | 'Helvetica Neue', 21 | sans-serif; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | } 25 | 26 | .home_component p { 27 | margin-top: 1rem; 28 | } 29 | 30 | .quotes { 31 | max-width: 968px; 32 | height: 60vh; 33 | line-height: 1.5rem; 34 | display: flex; 35 | align-items: center; 36 | justify-content: center; 37 | margin: 0 auto; 38 | } 39 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | const root = ReactDOM.createRoot(document.getElementById('root')); 7 | root.render( 8 | 9 | 10 | , 11 | ); 12 | 13 | // If you want to start measuring performance in your app, pass a function 14 | // to log results (for example: reportWebVitals(console.log)) 15 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 16 | --------------------------------------------------------------------------------