├── .gitignore ├── .hintrc ├── .eslintrc.json ├── .stylelintrc.json ├── package.json ├── MIT.md ├── index.css ├── .github └── workflows │ └── linters.yml ├── index.html ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /.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": [ 1, { 18 | "js": "always", "json": "always" 19 | }] 20 | }, 21 | "ignorePatterns": [ 22 | "dist/", 23 | "build/" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "book_collection_project", 3 | "version": "1.0.0", 4 | "description": "
\r \r \"logo\"\r
", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/J-C-S-V/book_collection_project.git" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/J-C-S-V/book_collection_project/issues" 18 | }, 19 | "homepage": "https://github.com/J-C-S-V/book_collection_project#readme", 20 | "devDependencies": { 21 | "babel-eslint": "^10.1.0", 22 | "eslint": "^7.32.0", 23 | "eslint-config-airbnb-base": "^14.2.1", 24 | "eslint-plugin-import": "^2.27.5", 25 | "hint": "^7.1.5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /MIT.md: -------------------------------------------------------------------------------- 1 | Copyright 2023, Juan Sanchez. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | body { 2 | height: 100vh; 3 | } 4 | 5 | .tbody-container { 6 | border: 3px solid black; 7 | } 8 | 9 | .table { 10 | width: 67%; 11 | margin: auto; 12 | } 13 | 14 | .form-container { 15 | position: relative; 16 | margin: auto; 17 | display: flex; 18 | flex-direction: column; 19 | width: 72%; 20 | margin-top: 5%; 21 | } 22 | 23 | .form-container__button { 24 | position: absolute; 25 | top: 108%; 26 | right: 0%; 27 | } 28 | 29 | .input-book { 30 | padding: 2%; 31 | border-radius: 10px; 32 | } 33 | 34 | .nav-bar-container { 35 | display: flex; 36 | justify-content: flex-end; 37 | } 38 | 39 | .pipe-line { 40 | color: white; 41 | line-height: 2.4rem; 42 | } 43 | 44 | #padding-container { 45 | padding: 0 4rem; 46 | } 47 | 48 | .hidden { 49 | display: none; 50 | } 51 | 52 | #contact { 53 | width: 58%; 54 | margin: auto; 55 | } 56 | 57 | .footer { 58 | text-align: left; 59 | border: 3px solid black; 60 | margin-top: 16rem; 61 | } 62 | 63 | #date { 64 | text-align: right; 65 | margin-right: 5%; 66 | } 67 | 68 | .ul-container { 69 | padding-left: 12rem; 70 | padding-right: 10rem; 71 | } 72 | 73 | .ul-container li { 74 | text-align: left; 75 | } 76 | 77 | .form-h2 { 78 | text-align: center; 79 | } 80 | 81 | .contact-h2 { 82 | text-align: center; 83 | margin-bottom: 10%; 84 | } 85 | 86 | .w19{ 87 | width: 19% 88 | } 89 | 90 | .position-relative{ 91 | position: relative; 92 | } -------------------------------------------------------------------------------- /.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: '18.x' 17 | - name: Setup Lighthouse 18 | run: npm install -g @lhci/cli@0.9.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: '18.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: '18.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: '18.x' 57 | - name: Setup ESLint 58 | run: | 59 | npm install --save-dev eslint@7.x eslint-config-airbnb-base@14.x eslint-plugin-import@2.x babel-eslint@10.x 60 | [ -f .eslintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.eslintrc.json 61 | - name: ESLint Report 62 | run: npx eslint . 63 | nodechecker: 64 | name: node_modules checker 65 | runs-on: ubuntu-22.04 66 | steps: 67 | - uses: actions/checkout@v2 68 | - name: Check node_modules existence 69 | run: | 70 | 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 71 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 21 | Book List Colleciton 22 | 23 | 24 | 73 |

74 | 75 | 125 | 126 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | logo 4 |
5 | 6 |

Book Collection

7 | 8 |
9 | 10 | # [Book Collection] 11 | 12 | 13 | 14 | # 📗 Table of Contents 15 | 16 | - [📖 About the Project](#about-project) 17 | - [🛠 Built With](#built-with) 18 | - [Tech Stack](#tech-stack) 19 | - [Key Features](#key-features) 20 | - [🚀 Live Demo](#live-demo) 21 | - [💻 Getting Started](#getting-started) 22 | - [Setup](#setup) 23 | - [Prerequisites](#prerequisites) 24 | - [Install](#install) 25 | - [Usage](#usage) 26 | - [Run tests](#run-tests) 27 | - [Deployment](#run-tests) 28 | - [👷‍♂️ Author](#authors) 29 | - [🔭 Future Features](#future-features) 30 | - [🤝 Contributing](#contributing) 31 | - [⭐️ Show your support](#support) 32 | - [🙏 Acknowledgements](#acknowledgements) 33 | - [📝 License](#license) 34 | 35 | 36 | 37 | # 📖 [Book Collection] 38 | 39 | **[Book Collection]** this is project displays a list a books when user submits the form 40 | 41 | ## 🛠 Built With 42 | 43 | ### Tech Stack 44 | 45 |
46 | Languages and technologies 47 | 50 | 53 | 56 | 59 |
60 | 61 | 62 | 63 | ### Key Features 64 | 65 | - **[Easy navigation]** 66 | - **[Personalized product]** 67 | - **[Secure payment processing]** 68 | 69 |

(back to top)

70 | 71 | 72 | 73 | ## 🚀 Live Demo 74 | 75 | - [Live Demo Link](https://j-c-s-v.github.io/Portfolio-setup-and-mobile-first/) 76 | 77 |

(back to top)

78 | 79 | 80 | 81 | 82 | ## 💻 Getting Started 83 | 84 | To get a local copy up and running, follow these steps. 85 | 86 | ### Prerequisites 87 | 88 | In order to run this project you need GitHub account and a text editor. 89 | 90 | ### Setup 91 | 92 | Clone this repository to your desired folder: 93 | 94 | https 95 | cd my-folder 96 | git clone https://github.com/J-C-S-V/hello_microverse_project.git 97 | 98 | ### Install 99 | 100 | Install this project with: 101 | 102 | N/A 103 | 104 | ### Usage 105 | 106 | To run the project, execute the following command: 107 | 108 | N/A 109 | 110 | ### Run tests 111 | 112 | N/A 113 | 114 | ### Deployment 115 | 116 | You can deploy this project using: 117 | 118 | GitHub pages 119 | 120 |

(back to top)

121 | 122 | 123 | 124 | ## 👷‍♂️ Author 125 | 126 | 👷‍♂️ **Juan Sanchez** 127 | 128 | - GitHub: [@githubhandle](https://github.com/J-C-S-V) 129 | - Twitter: [@twitterhandle](https://twitter.com/juansan0) 130 | - LinkedIn: [@LinkedIn](https://www.linkedin.com/in/juan-carlos-sanchez-vargas-a308b014b/) 131 | 132 | 👷‍♂️ **daniela** 133 | 134 | - GitHub: [@daniela](https://github.com/danielamoreno699) 135 | - LinkedIn: [LinkedIn](https://www.linkedin.com/in/daniela-moreno-06a139124/) 136 | - twitter : [twitter](@Daniela38932450) 137 | 138 | 139 |

(back to top)

140 | 141 | 142 | 143 | ## 🔭 Future Features 144 | 145 | - [ ] **[Payment]** 146 | - [ ] **[Footer]** 147 | - [ ] **[Profile picture]** 148 | 149 |

(back to top)

150 | 151 | 152 | 153 | ## 🤝 Contributing 154 | 155 | Contributions, issues, and feature requests are welcome! 156 | 157 | Feel free to check the [issues page](../../issues/). 158 | 159 |

(back to top)

160 | 161 | 162 | 163 | ## ⭐️ Show your support 164 | 165 | If you get inspired by this project you can give me a star 🙌 166 | 167 |

(back to top)

168 | 169 | 170 | 171 | ## 🙏 Acknowledgments 172 | 173 | I would like to thank Microverse 174 | 175 |

(back to top)

176 | 177 | 178 | 179 | ## 📝 License 180 | 181 | This project is [MIT](https://github.com/J-C-S-V/Portfolio-setup-and-mobile-first/blob/main/license.md) licensed. 182 | 183 |

(back to top)

184 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-classes-per-file */ 2 | class Book { 3 | constructor(title, author) { 4 | this.title = title; 5 | this.author = author; 6 | } 7 | } 8 | 9 | class UI { 10 | // eslint-disable-next-line class-methods-use-this 11 | addBookToTheList(book) { 12 | const ul = document.getElementById('tbody-container'); 13 | 14 | const li = document.createElement('tr'); 15 | 16 | li.innerHTML = ` 17 | "${book.author}" by ${book.title} 18 | 19 | 20 | `; 21 | ul.insertBefore(li, ul.firstChild); 22 | } 23 | 24 | // eslint-disable-next-line class-methods-use-this 25 | clearFieldsInputs() { 26 | const author = document.getElementById('author'); 27 | const title = document.getElementById('book'); 28 | author.value = ''; 29 | title.value = ''; 30 | } 31 | } 32 | 33 | class Store { 34 | static getBooks() { 35 | let books; 36 | if (localStorage.getItem('books') === null) { 37 | books = []; 38 | } else { 39 | books = JSON.parse(localStorage.getItem('books')); 40 | } 41 | return books; 42 | } 43 | 44 | static displayBooks() { 45 | const books = Store.getBooks(); 46 | books.forEach((book) => { 47 | const ui = new UI(); 48 | ui.addBookToTheList(book); 49 | }); 50 | } 51 | 52 | static addBook(book) { 53 | const books = Store.getBooks(); 54 | books.push(book); 55 | localStorage.setItem('books', JSON.stringify(books)); 56 | } 57 | 58 | static removeBookFromStore(index) { 59 | const books = Store.getBooks(); 60 | 61 | books.splice(index, 1); 62 | localStorage.setItem('books', JSON.stringify(books)); 63 | } 64 | 65 | static removeBook(target) { 66 | if (target.className === 'delete') { 67 | const titleElement = target.parentElement.parentElement.querySelector('.title'); 68 | const authorElement = target.parentElement.parentElement.querySelector('.author'); 69 | const books = Store.getBooks(); 70 | const bookT = titleElement.textContent; 71 | const bookA = authorElement.textContent; 72 | const index = books.findIndex( 73 | (book) => book.title === bookT && book.author === bookA, 74 | ); 75 | 76 | books.splice(index, 1); 77 | localStorage.setItem('books', JSON.stringify(books)); 78 | target.parentElement.parentElement.remove(); 79 | } 80 | } 81 | } 82 | 83 | document.addEventListener('DOMContentLoaded', () => { 84 | Store.displayBooks(); 85 | }); 86 | 87 | const form = document.getElementById('form'); 88 | 89 | form.addEventListener('submit', (event) => { 90 | const author = document.getElementById('author').value; 91 | const title = document.getElementById('book').value; 92 | 93 | const book = new Book(author, title); 94 | 95 | const ui = new UI(); 96 | 97 | if (author === '' || title === '') { 98 | return; 99 | } 100 | 101 | ui.addBookToTheList(book); 102 | Store.addBook(book); 103 | ui.clearFieldsInputs(); 104 | event.preventDefault(); 105 | }); 106 | 107 | document.getElementById('tbody-container').addEventListener('click', (e) => { 108 | // eslint-disable-next-line no-unused-vars 109 | const ui = new UI(); 110 | Store.removeBook(e.target); 111 | e.preventDefault(); 112 | }); 113 | 114 | const formSection = document.getElementById('add-book-section'); 115 | const listSection = document.getElementById('table-books'); 116 | const contactSection = document.getElementById('contact'); 117 | const linkList = document.getElementById('listLink'); 118 | const linkForm = document.getElementById('formLink'); 119 | const linkContact = document.getElementById('contactLink'); 120 | 121 | const displayList = () => { 122 | listSection.classList.remove('hidden'); 123 | formSection.classList.add('hidden'); 124 | contactSection.classList.add('hidden'); 125 | }; 126 | 127 | const displayForm = () => { 128 | formSection.classList.remove('hidden'); 129 | listSection.classList.add('hidden'); 130 | contactSection.classList.add('hidden'); 131 | }; 132 | 133 | const displayContact = () => { 134 | contactSection.classList.remove('hidden'); 135 | listSection.classList.add('hidden'); 136 | formSection.classList.add('hidden'); 137 | }; 138 | 139 | linkList.addEventListener('click', (event) => { 140 | event.preventDefault(); 141 | displayList(); 142 | }); 143 | 144 | linkForm.addEventListener('click', (event) => { 145 | event.preventDefault(); 146 | displayForm(); 147 | }); 148 | 149 | linkContact.addEventListener('click', (event) => { 150 | event.preventDefault(); 151 | displayContact(); 152 | }); 153 | 154 | const span = document.getElementById('date'); 155 | const date = new Date(); 156 | span.innerHTML = date; 157 | 158 | const displayPage = (currentPage) => { 159 | const sections = document.querySelectorAll('section'); 160 | // eslint-disable-next-line no-restricted-syntax 161 | for (const section of sections) { 162 | if (section.id === currentPage) { 163 | section.classList.remove('hidden'); 164 | } else { 165 | section.classList.add('hidden'); 166 | } 167 | } 168 | }; 169 | 170 | const getCurrentPage = () => { 171 | const currentPage = localStorage.getItem('currentPage'); 172 | if (currentPage) { 173 | return currentPage; 174 | } 175 | return 'add-book-section'; 176 | }; 177 | 178 | const handleLinkClick = (event) => { 179 | event.preventDefault(); 180 | const currentPage = event.target.getAttribute('href').substring(1); 181 | localStorage.setItem('currentPage', currentPage); 182 | displayPage(currentPage); 183 | }; 184 | 185 | const displayCurrentPage = () => { 186 | const currentPage = getCurrentPage(); 187 | displayPage(currentPage); 188 | }; 189 | 190 | const links = document.querySelectorAll('a'); 191 | links.forEach((link) => { 192 | link.addEventListener('click', handleLinkClick); 193 | }); 194 | 195 | window.addEventListener('load', displayCurrentPage); 196 | --------------------------------------------------------------------------------