├── .babelrc ├── .eslintrc.json ├── .github └── workflows │ └── linters.yml ├── .gitignore ├── .stylelintrc.json ├── README.md ├── package-lock.json ├── package.json ├── public └── index.html └── src ├── classBased ├── App.css └── components │ ├── Header.js │ ├── InputTodo.js │ ├── Navbar.js │ ├── TodoContainer.js │ ├── TodoItem.js │ ├── TodoItem.module.css │ └── TodosList.js ├── functionBased ├── App.css ├── components │ ├── Header.js │ ├── InputTodo.js │ ├── Navbar.js │ ├── TodoContainer.js │ ├── TodoItem.js │ ├── TodoItem.module.css │ └── TodosList.js └── pages │ ├── About.js │ ├── NotMatch.js │ └── SinglePage.js └── 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 | node_modules 2 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reactToDo -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-todo-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.3.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-router-dom": "^6.3.0", 12 | "react-scripts": "5.0.1", 13 | "uuid": "^8.3.2", 14 | "web-vitals": "^2.1.4" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | }, 40 | "devDependencies": { 41 | "@babel/core": "^7.18.10", 42 | "@babel/eslint-parser": "^7.18.9", 43 | "@babel/plugin-syntax-jsx": "^7.18.6", 44 | "@babel/preset-env": "^7.18.10", 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.30.1", 51 | "eslint-plugin-react-hooks": "^4.6.0", 52 | "stylelint": "^13.13.1", 53 | "stylelint-config-standard": "^21.0.0", 54 | "stylelint-csstree-validator": "^1.9.0", 55 | "stylelint-scss": "^3.21.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 26 | React App 27 | 28 | 29 | 30 |
31 | 39 | 40 | -------------------------------------------------------------------------------- /src/classBased/App.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | body { 8 | font-family: "Segoe UI", Arial, sans-serif; 9 | line-height: 1.4; 10 | color: #444; 11 | background: #fff; 12 | height: 100vh; 13 | } 14 | 15 | .container { 16 | display: flex; 17 | flex-direction: column; 18 | justify-content: center; 19 | align-items: center; 20 | max-width: 600px; 21 | margin: 0 auto; 22 | } 23 | 24 | .inner { 25 | width: 100%; 26 | padding: 8rem 10px 4rem; 27 | } 28 | 29 | .form-container { 30 | width: 100%; 31 | margin-bottom: 20px; 32 | display: flex; 33 | border-radius: calc(0.5 * 100px); 34 | box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.38); 35 | justify-content: space-evenly; 36 | } 37 | 38 | .input-text { 39 | font-size: 1rem; 40 | font-weight: 400; 41 | width: 85%; 42 | padding-right: 5px; 43 | padding-left: 10px; 44 | border-radius: calc(0.5 * 100px); 45 | } 46 | 47 | .input-text::placeholder { 48 | color: #000; 49 | } 50 | 51 | .input-submit { 52 | background: transparent; 53 | color: #5b5b5b; 54 | text-transform: capitalize; 55 | cursor: pointer; 56 | font-weight: 600; 57 | margin-right: 10px; 58 | } 59 | 60 | .input-text, 61 | .input-submit { 62 | height: 45px; 63 | outline: none; 64 | border: none; 65 | } 66 | -------------------------------------------------------------------------------- /src/classBased/components/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Header = () => { 4 | const headerStyle = { 5 | padding: '20px 0', 6 | lineHeight: '1.5em', 7 | }; 8 | 9 | return ( 10 |
11 |

22 | todos 23 |

24 |
25 | ); 26 | }; 27 | 28 | export default Header; 29 | -------------------------------------------------------------------------------- /src/classBased/components/InputTodo.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React, { Component } from 'react'; 3 | 4 | class InputTodo extends Component { 5 | state = { 6 | title: '', 7 | }; 8 | 9 | onChange = (e) => { 10 | this.setState({ 11 | [e.target.name]: e.target.value, 12 | }); 13 | }; 14 | 15 | handleSubmit = (e) => { 16 | e.preventDefault(); 17 | if (this.state.title.trim()) { 18 | this.props.addTodoProps(this.state.title); 19 | this.setState({ 20 | title: '', 21 | }); 22 | } else { 23 | alert('Please write item'); 24 | } 25 | } 26 | 27 | render() { 28 | return ( 29 |
30 | 38 | 39 |
40 | ); 41 | } 42 | } 43 | 44 | export default InputTodo; 45 | -------------------------------------------------------------------------------- /src/classBased/components/Navbar.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevHunter128/react-todo-app/64afc6505cac165f837551bb74a621df7958a900/src/classBased/components/Navbar.js -------------------------------------------------------------------------------- /src/classBased/components/TodoContainer.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React from 'react'; 3 | import { v4 as uuidv4 } from 'uuid'; 4 | import TodosList from './TodosList'; 5 | import Header from './Header'; 6 | import InputTodo from './InputTodo'; 7 | 8 | class TodoContainer extends React.Component { 9 | state = { 10 | todos: [], 11 | }; 12 | 13 | handleChange = (id) => { 14 | this.setState((prevState) => ({ 15 | todos: prevState.todos.map((todo) => { 16 | if (todo.id === id) { 17 | return { 18 | ...todo, 19 | completed: !todo.completed, 20 | }; 21 | } 22 | return todo; 23 | }), 24 | })); 25 | }; 26 | 27 | delTodo = (id) => { 28 | this.setState({ 29 | todos: [ 30 | ...this.state.todos.filter((todo) => todo.id !== id), 31 | ], 32 | }); 33 | }; 34 | 35 | addTodoItem = (title) => { 36 | const newTodo = { 37 | id: uuidv4(), 38 | title, 39 | completed: false, 40 | }; 41 | this.setState({ 42 | todos: [...this.state.todos, newTodo], 43 | }); 44 | }; 45 | 46 | setUpdate = (updatedTitle, id) => { 47 | this.setState({ 48 | todos: this.state.todos.map((todo) => { 49 | if (todo.id === id) { 50 | todo.title = updatedTitle; 51 | } 52 | return todo; 53 | }), 54 | }); 55 | } 56 | 57 | componentDidMount() { 58 | fetch('https://jsonplaceholder.typicode.com/todos?_limit=10') 59 | .then((response) => response.json()) 60 | .then((data) => this.setState({ todos: data })); 61 | } 62 | 63 | // eslint-disable-next-line 64 | componentDidMount() { 65 | const temp = localStorage.getItem('todos'); 66 | const loadedTodos = JSON.parse(temp); 67 | if (loadedTodos) { 68 | this.setState({ 69 | todos: loadedTodos, 70 | }); 71 | } 72 | } 73 | 74 | componentDidUpdate(prevProps, prevState) { 75 | if (prevState.todos !== this.state.todos) { 76 | const temp = JSON.stringify(this.state.todos); 77 | localStorage.setItem('todos', temp); 78 | } 79 | } 80 | 81 | render() { 82 | return ( 83 |
84 |
85 |
86 | 87 | 93 |
94 |
95 | ); 96 | } 97 | } 98 | export default TodoContainer; 99 | -------------------------------------------------------------------------------- /src/classBased/components/TodoItem.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React from 'react'; 3 | import styles from './TodoItem.module.css'; 4 | 5 | class TodoItem extends React.Component { 6 | state = { 7 | editing: false, 8 | } 9 | 10 | handleEditing = () => { 11 | this.setState({ 12 | editing: true, 13 | }); 14 | } 15 | 16 | handleUpdatedDone = (event) => { 17 | if (event.key === 'Enter') { 18 | this.setState({ editing: false }); 19 | } 20 | } 21 | 22 | componentWillUnmount() { 23 | console.log('Cleaning up...'); 24 | } 25 | 26 | render() { 27 | const viewMode = {}; 28 | const editMode = {}; 29 | 30 | if (this.state.editing) { 31 | viewMode.display = 'none'; 32 | } else { 33 | editMode.display = 'none'; 34 | } 35 | const completedStyle = { 36 | fontStyle: 'italic', 37 | color: '#595959', 38 | opacity: 0.4, 39 | textDecoration: 'line-through', 40 | }; 41 | const { completed, id, title } = this.props.todo; 42 | return ( 43 |
  • 44 |
    45 | this.props.handleChangeProps(id)} 50 | /> 51 | 54 | 55 | {title} 56 | 57 |
    58 | { 64 | this.props.setUpdate(e.target.value, id); 65 | }} 66 | onKeyDown={this.handleUpdatedDone} 67 | /> 68 |
  • 69 | ); 70 | } 71 | } 72 | 73 | export default TodoItem; 74 | -------------------------------------------------------------------------------- /src/classBased/components/TodoItem.module.css: -------------------------------------------------------------------------------- 1 | .item { 2 | font-size: 1.2rem; 3 | list-style-type: none; 4 | padding: 17px 0; 5 | border-bottom: 1px solid #eaeaea; 6 | } 7 | 8 | .checkbox { 9 | margin-right: 15px; 10 | } 11 | 12 | .item button { 13 | font-size: 13px; 14 | background: #f1f3f4; 15 | border: none; 16 | cursor: pointer; 17 | float: right; 18 | outline: none; 19 | border-radius: 100px; 20 | height: 50px; 21 | width: 50px; 22 | margin: -10px 0 0 10px; 23 | } 24 | 25 | .textInput { 26 | width: 100%; 27 | padding: 10px; 28 | border: 1px solid #dfdfdf; 29 | } 30 | -------------------------------------------------------------------------------- /src/classBased/components/TodosList.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React from 'react'; 3 | import TodoItem from './TodoItem'; 4 | 5 | class TodosList extends React.Component { 6 | render() { 7 | return ( 8 | 19 | ); 20 | } 21 | } 22 | 23 | export default TodosList; 24 | -------------------------------------------------------------------------------- /src/functionBased/App.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | body { 8 | font-family: "Segoe UI", Arial, sans-serif; 9 | line-height: 1.4; 10 | color: #444; 11 | background: #fff; 12 | height: 100vh; 13 | } 14 | 15 | .container { 16 | display: flex; 17 | flex-direction: column; 18 | justify-content: center; 19 | align-items: center; 20 | max-width: 600px; 21 | margin: 0 auto; 22 | } 23 | 24 | .inner { 25 | width: 100%; 26 | padding: 8rem 10px 4rem; 27 | } 28 | 29 | .form-container { 30 | width: 100%; 31 | margin-bottom: 20px; 32 | display: flex; 33 | border-radius: calc(0.5 * 100px); 34 | box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.38); 35 | justify-content: space-evenly; 36 | } 37 | 38 | .input-text { 39 | font-size: 1rem; 40 | font-weight: 400; 41 | width: 85%; 42 | padding-right: 5px; 43 | padding-left: 10px; 44 | border-radius: calc(0.5 * 100px); 45 | } 46 | 47 | .input-text::placeholder { 48 | color: #000; 49 | } 50 | 51 | .input-submit { 52 | background: transparent; 53 | color: #5b5b5b; 54 | text-transform: capitalize; 55 | cursor: pointer; 56 | font-weight: 600; 57 | margin-right: 10px; 58 | } 59 | 60 | .input-text, 61 | .input-submit { 62 | height: 45px; 63 | outline: none; 64 | border: none; 65 | } 66 | 67 | .active-link { 68 | color: orangered; 69 | text-decoration: underline; 70 | } 71 | -------------------------------------------------------------------------------- /src/functionBased/components/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Header = () => { 4 | const headerStyle = { 5 | padding: '20px 0', 6 | lineHeight: '1.5em', 7 | }; 8 | 9 | return ( 10 |
    11 |

    22 | todos 23 |

    24 |
    25 | ); 26 | }; 27 | 28 | export default Header; 29 | -------------------------------------------------------------------------------- /src/functionBased/components/InputTodo.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React, { useState } from 'react'; 3 | 4 | const InputTodo = (props) => { 5 | const [inputText, setInputText] = useState({ 6 | title: '', 7 | }); 8 | 9 | const onChange = (e) => { 10 | setInputText({ 11 | ...inputText, 12 | [e.target.name]: e.target.value, 13 | }); 14 | }; 15 | 16 | const handleSubmit = (e) => { 17 | e.preventDefault(); 18 | if (inputText.title.trim()) { 19 | props.addTodoProps(inputText.title); 20 | setInputText({ 21 | title: '', 22 | }); 23 | } else { 24 | alert('Please write item'); 25 | } 26 | }; 27 | 28 | return ( 29 |
    30 | 38 | 39 |
    40 | ); 41 | }; 42 | 43 | export default InputTodo; 44 | -------------------------------------------------------------------------------- /src/functionBased/components/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NavLink } from 'react-router-dom'; 3 | 4 | const Navbar = () => { 5 | const links = [ 6 | { 7 | id: 1, 8 | path: '/', 9 | text: 'Home', 10 | }, 11 | { 12 | id: 2, 13 | path: '/about', 14 | text: 'About', 15 | }, 16 | ]; 17 | return ( 18 | 29 | ); 30 | }; 31 | export default Navbar; 32 | -------------------------------------------------------------------------------- /src/functionBased/components/TodoContainer.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React, { useState, useEffect } from 'react'; 3 | import { Routes, Route } from 'react-router-dom'; 4 | import { v4 as uuidv4 } from 'uuid'; 5 | import TodosList from './TodosList'; 6 | import Header from './Header'; 7 | import InputTodo from './InputTodo'; 8 | import About from '../pages/About'; 9 | import NotMatch from '../pages/NotMatch'; 10 | import Navbar from './Navbar'; 11 | 12 | function getInitialTodos() { 13 | const temp = localStorage.getItem('todos'); 14 | const savedTodos = JSON.parse(temp); 15 | return savedTodos || []; 16 | } 17 | 18 | const TodoContainer = () => { 19 | const [todos, setTodos] = useState(getInitialTodos()); 20 | 21 | const handleChange = (id) => { 22 | setTodos((prevState) => prevState.map((todo) => { 23 | if (todo.id === id) { 24 | return { 25 | ...todo, 26 | completed: !todo.completed, 27 | }; 28 | } 29 | return todo; 30 | })); 31 | }; 32 | 33 | const delTodo = (id) => { 34 | setTodos([ 35 | ...todos.filter((todo) => todo.id !== id), 36 | ]); 37 | }; 38 | 39 | const addTodoItem = (title) => { 40 | const newTodo = { 41 | id: uuidv4(), 42 | title, 43 | completed: false, 44 | }; 45 | setTodos([...todos, newTodo]); 46 | }; 47 | 48 | const setUpdate = (updateTitle, id) => { 49 | setTodos( 50 | todos.map((todo) => { 51 | if (todo.id === id) { 52 | todo.title = updateTitle; 53 | } 54 | return todo; 55 | }), 56 | ); 57 | }; 58 | 59 | /* useEffect(() => { 60 | console.log("test run") 61 | const temp = localStorage.getItem("todos") 62 | const loadedTodos = JSON.parse(temp) 63 | 64 | if (loadedTodos) { 65 | setTodos(loadedTodos) 66 | } 67 | }, [setTodos]) */ 68 | 69 | useEffect(() => { 70 | const temp = JSON.stringify(todos); 71 | localStorage.setItem('todos', temp); 72 | }, [todos]); 73 | 74 | return ( 75 | <> 76 | 77 | 78 | 83 |
    84 |
    85 | 86 | 92 |
    93 | 94 | )} 95 | /> 96 | } /> 97 | } /> 98 |
    99 | 100 | ); 101 | }; 102 | 103 | export default TodoContainer; 104 | -------------------------------------------------------------------------------- /src/functionBased/components/TodoItem.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React, { useState, useEffect } from 'react'; 3 | import styles from './TodoItem.module.css'; 4 | 5 | const TodoItem = (props) => { 6 | const [editing, setEditing] = useState(false); 7 | 8 | const handleEditing = () => { 9 | setEditing(true); 10 | }; 11 | 12 | const handleUpdateDone = (event) => { 13 | if (event.key === 'Enter') { 14 | setEditing(false); 15 | } 16 | }; 17 | 18 | const completedStyle = { 19 | fontStyle: 'italic', 20 | color: '#595959', 21 | opacity: 0.4, 22 | textDecoration: 'line-through', 23 | }; 24 | 25 | const { completed, id, title } = props.todo; 26 | 27 | const viewMode = {}; 28 | const editMode = {}; 29 | 30 | if (editing) { 31 | viewMode.display = 'none'; 32 | } else { 33 | editMode.display = 'none'; 34 | } 35 | 36 | useEffect(() => () => { 37 | console.log('Cleaning up...'); 38 | }, []); 39 | 40 | return ( 41 |
  • 42 |
    43 | props.handleChangeProps(id)} 48 | /> 49 | 50 | {title} 51 |
    52 | { 58 | props.setUpdate(e.target.value, id); 59 | }} 60 | onKeyDown={handleUpdateDone} 61 | /> 62 |
  • 63 | ); 64 | }; 65 | 66 | export default TodoItem; 67 | -------------------------------------------------------------------------------- /src/functionBased/components/TodoItem.module.css: -------------------------------------------------------------------------------- 1 | .item { 2 | font-size: 1.2rem; 3 | list-style-type: none; 4 | padding: 17px 0; 5 | border-bottom: 1px solid #eaeaea; 6 | } 7 | 8 | .checkbox { 9 | margin-right: 15px; 10 | } 11 | 12 | .item button { 13 | font-size: 13px; 14 | background: #f1f3f4; 15 | border: none; 16 | cursor: pointer; 17 | float: right; 18 | outline: none; 19 | border-radius: 100px; 20 | height: 50px; 21 | width: 50px; 22 | margin: -10px 0 0 10px; 23 | } 24 | 25 | .textInput { 26 | width: 100%; 27 | padding: 10px; 28 | border: 1px solid #dfdfdf; 29 | } 30 | -------------------------------------------------------------------------------- /src/functionBased/components/TodosList.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React from 'react'; 3 | import TodoItem from './TodoItem'; 4 | 5 | const TodosList = (props) => ( 6 | 17 | ); 18 | 19 | export default TodosList; 20 | -------------------------------------------------------------------------------- /src/functionBased/pages/About.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link, Route, Routes } from 'react-router-dom'; 3 | import SinglePage from './SinglePage'; 4 | 5 | const About = () => ( 6 | 21 | ); 22 | export default About; 23 | -------------------------------------------------------------------------------- /src/functionBased/pages/NotMatch.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const NotMatch = () => ( 4 |
    5 |

    No match for this page

    6 |
    7 | ); 8 | export default NotMatch; 9 | -------------------------------------------------------------------------------- /src/functionBased/pages/SinglePage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useParams } from 'react-router-dom'; 3 | 4 | const SinglePage = () => { 5 | const aboutData = [ 6 | { 7 | slug: 'about-app', 8 | title: 'About the App', 9 | description: 10 | 'In this app, you can add, delete, submit and edit items. To edit items, simply double click on it. Once you are done, press the enter key to resubmit. This app will persist your data in the browser local storage. So whether you reload, close your app or reopened it, you still have access to your to-dos items.', 11 | }, 12 | { 13 | slug: 'about-author', 14 | title: 'About the Author', 15 | description: 16 | 'This app was developed by Ibas Majid, a self-taught web developer and a technical writer. He is opened to freelance Gig. So go ahead and connect with ibas on Twitter @ibaslogic.', 17 | }, 18 | ]; 19 | const { slug } = useParams(); 20 | const aboutContent = aboutData.find((item) => item.slug === slug); 21 | const { title, description } = aboutContent; 22 | return ( 23 |
    24 |

    {title}

    25 |

    {description}

    26 |
    27 | ); 28 | }; 29 | export default SinglePage; 30 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { BrowserRouter as Router } from 'react-router-dom'; 4 | import TodoContainer from './functionBased/components/TodoContainer'; 5 | import './functionBased/App.css'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | 11 | 12 | , 13 | document.getElementById('root'), 14 | ); 15 | --------------------------------------------------------------------------------