├── .eslintrc.json ├── .github └── workflows │ └── linters.yml ├── .gitignore ├── .hintrc ├── .stylelintrc.json ├── .vscode └── settings.json ├── MIT.md ├── README.md ├── app.js ├── app_screenshot.png ├── index.html ├── murple_logo.png ├── package-lock.json ├── package.json └── style.css /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "jest": true 6 | }, 7 | "parser": "babel-eslint", 8 | "parserOptions": { 9 | "ecmaVersion": 2018, 10 | "sourceType": "module" 11 | }, 12 | "extends": ["airbnb-base"], 13 | "rules": { 14 | "no-shadow": "off", 15 | "no-param-reassign": "off", 16 | "eol-last": "off", 17 | "import/extensions": [ 18 | 1, 19 | { 20 | "js": "always", 21 | "json": "always" 22 | } 23 | ] 24 | }, 25 | "ignorePatterns": ["dist/", "build/"] 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: pull_request 4 | 5 | env: 6 | FORCE_COLOR: 1 7 | 8 | jobs: 9 | lighthouse: 10 | name: Lighthouse 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-node@v1 15 | with: 16 | node-version: "12.x" 17 | - name: Setup Lighthouse 18 | run: npm install -g @lhci/cli@0.7.x 19 | - name: Lighthouse Report 20 | run: lhci autorun --upload.target=temporary-public-storage --collect.staticDistDir=. 21 | webhint: 22 | name: Webhint 23 | runs-on: ubuntu-22.04 24 | steps: 25 | - uses: actions/checkout@v2 26 | - uses: actions/setup-node@v1 27 | with: 28 | node-version: "12.x" 29 | - name: Setup Webhint 30 | run: | 31 | npm install --save-dev hint@7.x 32 | [ -f .hintrc ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.hintrc 33 | - name: Webhint Report 34 | run: npx hint . 35 | stylelint: 36 | name: Stylelint 37 | runs-on: ubuntu-22.04 38 | steps: 39 | - uses: actions/checkout@v2 40 | - uses: actions/setup-node@v1 41 | with: 42 | node-version: "12.x" 43 | - name: Setup Stylelint 44 | run: | 45 | npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x 46 | [ -f .stylelintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.stylelintrc.json 47 | - name: Stylelint Report 48 | run: npx stylelint "**/*.{css,scss}" 49 | eslint: 50 | name: ESLint 51 | runs-on: ubuntu-22.04 52 | steps: 53 | - uses: actions/checkout@v2 54 | - uses: actions/setup-node@v1 55 | with: 56 | node-version: "12.x" 57 | - name: Setup ESLint 58 | run: | 59 | npm i -D esquery@1.4.0 --save-exact 60 | npm install --save-dev eslint@7.x eslint-config-airbnb-base@14.x eslint-plugin-import@2.x babel-eslint@10.x 61 | [ -f .eslintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.eslintrc.json 62 | - name: ESLint Report 63 | run: npx eslint . 64 | nodechecker: 65 | name: node_modules checker 66 | runs-on: ubuntu-22.04 67 | steps: 68 | - uses: actions/checkout@v2 69 | - name: Check node_modules existence 70 | run: | 71 | 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 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | n -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "connector": { 3 | "name": "local", 4 | "options": { 5 | "pattern": ["**", "!.git/**", "!node_modules/**"] 6 | } 7 | }, 8 | "extends": ["development"], 9 | "formatters": ["stylish"], 10 | "hints": [ 11 | "button-type", 12 | "disown-opener", 13 | "html-checker", 14 | "meta-charset-utf-8", 15 | "meta-viewport", 16 | "no-inline-styles:error" 17 | ] 18 | } -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "liveServer.settings.port": 5501 3 | } 4 | -------------------------------------------------------------------------------- /MIT.md: -------------------------------------------------------------------------------- 1 | ## Copyright 2023, heldricks adhola and Yidnekachew Kassahun 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this awesome books and associated documentation files, to deal in the awesome books without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the awesome books, and to permit persons to whom the awesome books is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the awesome books. 6 | 7 | THE awesome books IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE awesome books OR THE USE OR OTHER DEALINGS IN THE awesome books. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 27 | 28 |
29 | 30 | 31 |
32 | 33 | 34 | 35 |
36 | 37 | 38 | 39 | # 📗 Table of Contents 40 | 41 | - [📖 About the Project](#about-project) 42 | - [🛠 Built With](#built-with) 43 | - [Tech Stack](#tech-stack) 44 | - [Key Features](#key-features) 45 | - [🚀 Live Demo](#live-demo) 46 | - [💻 Getting Started](#getting-started) 47 | - [Setup](#setup) 48 | - [Prerequisites](#prerequisites) 49 | - [Install](#install) 50 | - [Usage](#usage) 51 | - [Run tests](#run-tests) 52 | - [Deployment](#triangular_flag_on_post-deployment) 53 | - [👥 Authors](#authors) 54 | - [🔭 Future Features](#future-features) 55 | - [🤝 Contributing](#contributing) 56 | - [⭐️ Show your support](#support) 57 | - [🙏 Acknowledgements](#acknowledgements) 58 | - [❓ FAQ (OPTIONAL)](#faq) 59 | - [📝 License](#license) 60 | 61 | 62 | 63 | # 📖 AWESOME BOOKS 64 | 65 | 66 | 67 | **Awesome books** is a project built with HTML and Javascript. 68 | 69 | ## 🛠 Built With 70 | 71 | - **HTML** 72 | - **CSS** 73 | - **JAVASCRIPT** 74 | 75 | 76 | 77 | ### Key Features 78 | 79 | 80 | 81 | - **Object Constructors** 82 | - **Local Storage** 83 | - **Object Oriented Programming** 84 | 85 |

(back to top)

86 | 87 | 88 | 89 | ## 🚀 Live Demo 90 | 91 | 92 | 93 | - [Coming soon](#) 94 | 95 |

(back to top)

96 | 97 | ## 💻 Getting Started 98 | 99 | ### Prerequisites 100 | 101 | In order to run this project you need: 102 | 103 | - Visual Studio Code 104 | - A Browser 105 | - Node 106 | - Git 107 | 108 | ### Setup 109 | 110 | Clone this repository to your desired folder: 111 | 112 | Example commands: 113 | 114 | ```sh 115 | cd 116 | git clone git@github.com:Adholah96/awesom-books.git 117 | cd awesom-books 118 | ``` 119 | 120 | ### Install 121 | 122 | Install this project with: 123 | 124 | ```sh 125 | npm install 126 | ``` 127 | 128 | ### Usage 129 | 130 | To run the project, execute the following command: 131 | 132 | - Open the the index.html file in the browser or 133 | - Install Live Server extension when using Visual code and open with Live server extension 134 | 135 |

(back to top)

136 | 137 | 138 | 139 | ## 👥 Authors 140 | 141 | 142 | 143 | 👤 **HELDRICKS ADHOLA** 144 | 145 | - GitHub: [@adholah96](https://github.com/Adholah96) 146 | - Twitter: [@nerdy*me*](https://twitter.com/nerdy_me_) 147 | - LinkedIn: [heldricks-arthur](https://linkedin.com/in/heldricks-arthur-59ab2411a) 148 | 149 | 👤 **Yidnekachew Kassahun** 150 | 151 | - GitHub: [Yidne](https://github.com/Yidnekachew-cmd) 152 | - Twitter: [Yidne](https://twitter.com/Yidnekassahun) 153 | - LinkedIn: [Yidne](https://www.linkedin.com/in/yidnekachew-kassahun-2b817a24b/) 154 | 155 |

(back to top)

156 | 157 | 158 | 159 | ## 🔭 Future Features 160 | 161 | 162 | 163 | - **More Functionality** 164 | 165 |

(back to top)

166 | 167 | 168 | 169 | ## 🤝 Contributing 170 | 171 | Contributions, issues, and feature requests are welcome! 172 | 173 | 174 | 175 |

(back to top)

176 | 177 | 178 | 179 | ## ⭐️ Show your support 180 | 181 | Always leave a ⭐️ if you like this project and any of my other projects. 182 | 183 |

(back to top)

184 | 185 | 186 | 187 | ## 🙏 Acknowledgments 188 | 189 | 190 | 191 | Passing my sincere gratitude to Cynthia from Behance for the design template. 192 | 193 |

(back to top)

194 | 195 | 196 | 197 | 200 | 201 | 210 | 211 | 212 | 213 | ## 📝 License 214 | 215 | This project is [MIT](./MIT.md) licensed. 216 | 217 |

(back to top)

218 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const libraryBooks = document.querySelector('[data-book]'); 2 | const titleName = document.getElementById('titleName'); 3 | const authorName = document.getElementById('authorName'); 4 | const form = document.getElementById('myForm'); 5 | class Library { 6 | constructor(id, author, title) { 7 | this.id = id; 8 | this.author = author; 9 | this.title = title; 10 | } 11 | 12 | // Local Storage 13 | static addLocalStorage(libraryContainer) { 14 | const storage = localStorage.setItem( 15 | 'books', 16 | JSON.stringify(libraryContainer), 17 | ); 18 | return storage; 19 | } 20 | 21 | static getLocalStorage() { 22 | const storage = localStorage.getItem('books') === null 23 | ? [] 24 | : JSON.parse(localStorage.getItem('books')); 25 | return storage; 26 | } 27 | 28 | // display in the DOM 29 | static displayBooks() { 30 | /* eslint-disable no-use-before-define */ 31 | const displayData = libraryContainer.map( 32 | (item) => ` 33 |
34 |

"${item.title}" by ${item.author}

35 | 36 |
37 | `, 38 | ); 39 | libraryBooks.innerHTML = displayData.join(' '); 40 | } 41 | 42 | // clear input once submited 43 | static clearInput() { 44 | titleName.value = ''; 45 | authorName.value = ''; 46 | } 47 | 48 | // delete book from DOM and arraylibrar 49 | static deleteBook() { 50 | libraryBooks.addEventListener('click', (e) => { 51 | if (e.target.classList.contains('delete-btn')) { 52 | e.target.parentElement.remove(); 53 | } 54 | const btnId = e.target.dataset.id; 55 | Library.removeLibraryArray(btnId); 56 | }); 57 | } 58 | 59 | static removeLibraryArray(id) { 60 | libraryContainer = libraryContainer.filter((item) => item.id !== +id); 61 | Library.addLocalStorage(libraryContainer); 62 | } 63 | 64 | static currentDate() { 65 | const date = new Date(); 66 | document.getElementById('dateDisplay').innerHTML = date; 67 | } 68 | } 69 | // innitialize form submit to create Library instance 70 | form.addEventListener('submit', (e) => { 71 | e.preventDefault(); 72 | const id = Math.floor(Math.random() * 1000); 73 | const book = new Library(id, authorName.value, titleName.value); 74 | libraryContainer.push(book); 75 | Library.displayBooks(); 76 | Library.clearInput(); 77 | Library.deleteBook(); 78 | Library.addLocalStorage(libraryContainer); 79 | }); 80 | window.addEventListener('DOMContentLoaded', () => { 81 | Library.displayBooks(); 82 | Library.deleteBook(); 83 | Library.currentDate(); 84 | }); 85 | // store values in a container referrenced by local storag 86 | let libraryContainer = Library.getLocalStorage(); 87 | // Single Page Application 88 | const books = document.querySelector('.listone'); 89 | const addNew = document.querySelector('.listtwo'); 90 | const contact = document.querySelector('.listthree'); 91 | const booksContainer = document.getElementById('booksContainer'); 92 | const contactContainer = document.getElementById('contact'); 93 | books.addEventListener('click', () => { 94 | booksContainer.style.display = 'block'; 95 | form.style.display = 'none'; 96 | contactContainer.style.display = 'none'; 97 | }); 98 | addNew.addEventListener('click', () => { 99 | booksContainer.style.display = 'none'; 100 | form.style.display = 'block'; 101 | contactContainer.style.display = 'none'; 102 | }); 103 | contact.addEventListener('click', () => { 104 | contactContainer.style.display = 'block'; 105 | booksContainer.style.display = 'none'; 106 | form.style.display = 'none'; 107 | }); 108 | -------------------------------------------------------------------------------- /app_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adholah96/awesom-books/d8ad0108ce40498fe10ebc1b3517119ac58b44a6/app_screenshot.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 19 |

20 |
21 |

All awesome books

22 |
23 |
24 |
25 |

Contact Information

26 |

27 | Do you have any question or concern. Or just want to say hello? Kindly 28 | reach out to us using the following medium. 29 |

30 | 35 |
36 |
37 |

Add a new book

38 | 39 |
40 | 41 |
42 | 43 |
44 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /murple_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adholah96/awesom-books/d8ad0108ce40498fe10ebc1b3517119ac58b44a6/murple_logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "babel-eslint": "^10.1.0", 4 | "eslint": "^7.32.0", 5 | "eslint-config-airbnb-base": "^14.2.1", 6 | "eslint-plugin-import": "^2.27.5", 7 | "esquery": "1.4.0", 8 | "hint": "^7.1.3", 9 | "stylelint": "^13.13.1", 10 | "stylelint-config-standard": "^21.0.0", 11 | "stylelint-csstree-validator": "^1.9.0", 12 | "stylelint-scss": "^3.21.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | input { 8 | margin-top: 2rem; 9 | margin-bottom: 10px; 10 | width: 100%; 11 | border: 2px solid; 12 | font-weight: bold; 13 | border-radius: 5px; 14 | padding: 1rem; 15 | } 16 | 17 | .first-h1 { 18 | margin-top: 3rem; 19 | text-align: center; 20 | } 21 | 22 | #libraryBooks { 23 | width: 70%; 24 | margin: 1rem auto; 25 | border: 1px solid rgb(147, 148, 148); 26 | border-radius: 5px; 27 | } 28 | 29 | .books { 30 | font-weight: bold; 31 | display: flex; 32 | align-items: center; 33 | width: 100%; 34 | padding: 0.5rem; 35 | } 36 | 37 | .books p { 38 | flex: 1; 39 | } 40 | 41 | .books:nth-child(even) { 42 | background: rgb(229, 229, 229); 43 | border-radius: 5px; 44 | } 45 | 46 | form { 47 | width: 40%; 48 | margin: 5rem auto; 49 | display: none; 50 | } 51 | 52 | form h1 { 53 | text-align: center; 54 | } 55 | 56 | button { 57 | box-shadow: 3px 5px 5px black; 58 | font-weight: bold; 59 | } 60 | 61 | .submit-btn { 62 | float: right; 63 | padding: 0.3rem 1rem; 64 | } 65 | 66 | .nav { 67 | display: flex; 68 | align-items: center; 69 | justify-content: space-between; 70 | border: 2px solid black; 71 | width: 70%; 72 | margin: 2rem auto; 73 | padding-left: 1rem; 74 | border-radius: 5px; 75 | } 76 | 77 | .nav-list { 78 | display: flex; 79 | align-items: center; 80 | justify-content: space-around; 81 | width: 50%; 82 | list-style-type: none; 83 | font-weight: bold; 84 | font-size: 15px; 85 | cursor: pointer; 86 | } 87 | 88 | .nav-list li:nth-child(2) { 89 | border-left: 2px solid; 90 | border-right: 2px solid; 91 | padding: 1.2rem 7rem; 92 | } 93 | 94 | .date { 95 | font-weight: bold; 96 | font-size: 15px; 97 | text-align: center; 98 | margin-top: 4rem; 99 | } 100 | 101 | footer { 102 | position: absolute; 103 | bottom: 2rem; 104 | width: 100%; 105 | padding: 2rem; 106 | font-size: 15px; 107 | } 108 | 109 | .footer p { 110 | font-weight: bold; 111 | text-align: center; 112 | } 113 | 114 | #contact { 115 | width: 40%; 116 | margin: 4rem auto; 117 | display: none; 118 | } 119 | 120 | #contact h1 { 121 | text-align: center; 122 | } 123 | 124 | #contact p { 125 | margin-top: 3rem; 126 | margin-bottom: 3rem; 127 | font-weight: bold; 128 | font-size: 20px; 129 | } 130 | 131 | #contact ul { 132 | margin-left: 4rem; 133 | font-size: 15px; 134 | font-weight: bold; 135 | } 136 | 137 | #contact ul li { 138 | margin-bottom: 1rem; 139 | } 140 | --------------------------------------------------------------------------------