├── .gitignore ├── .DS_Store ├── modules ├── .DS_Store ├── book.js ├── dateManager.js ├── bookManager.js └── bookListView.js ├── .hintrc ├── .eslintrc.json ├── .stylelintrc.json ├── package.json ├── LICENSE.md ├── index.js ├── index.html ├── .github └── workflows │ └── linters.yml ├── index.css └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ClaudiaRojasSoto/Awesome_Books_ES6/HEAD/.DS_Store -------------------------------------------------------------------------------- /modules/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ClaudiaRojasSoto/Awesome_Books_ES6/HEAD/modules/.DS_Store -------------------------------------------------------------------------------- /modules/book.js: -------------------------------------------------------------------------------- 1 | export default class Book { 2 | constructor(id, title, author) { 3 | this.author = author; 4 | this.title = title; 5 | this.id = id; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /modules/dateManager.js: -------------------------------------------------------------------------------- 1 | import { DateTime } from './luxon.js'; 2 | 3 | const displayDate = (elementId) => { 4 | const dateElement = document.getElementById(elementId); 5 | 6 | const updateTime = () => { 7 | const today = DateTime.now(); 8 | const format = today.toLocaleString(DateTime.DATETIME_FULL_WITH_SECONDS); 9 | dateElement.textContent = format; 10 | }; 11 | 12 | updateTime(); 13 | setInterval(updateTime, 1000); 14 | }; 15 | 16 | export default displayDate; 17 | -------------------------------------------------------------------------------- /modules/bookManager.js: -------------------------------------------------------------------------------- 1 | export default class BookManager { 2 | constructor() { 3 | this.books = JSON.parse(localStorage.getItem('book')) || []; 4 | } 5 | 6 | addBook(book) { 7 | this.books = [book, ...this.books]; 8 | localStorage.setItem('book', JSON.stringify(this.books)); 9 | } 10 | 11 | removeBook(bookIndex) { 12 | this.books.splice(bookIndex, 1); 13 | localStorage.setItem('book', JSON.stringify(this.books)); 14 | } 15 | 16 | getBooks() { 17 | return this.books; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.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 | "no-use-before-define": "off", 17 | "eol-last": "off", 18 | "import/extensions": [ 1, { 19 | "js": "always", "json": "always" 20 | }] 21 | }, 22 | "ignorePatterns": [ 23 | "dist/", 24 | "build/" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /.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": "awesome_books_es6", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "babel-eslint": "^10.1.0", 15 | "eslint": "^7.32.0", 16 | "eslint-config-airbnb-base": "^14.2.1", 17 | "eslint-plugin-import": "^2.27.5", 18 | "hint": "^7.1.8", 19 | "stylelint": "^13.13.1", 20 | "stylelint-config-standard": "^21.0.0", 21 | "stylelint-csstree-validator": "^1.9.0", 22 | "stylelint-scss": "^3.21.0" 23 | }, 24 | "dependencies": { 25 | "luxon": "^3.3.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## Copyright 2021, [Claudia Rojas] 2 | 3 | ###### Please delete this line and the next one 4 | ###### Awesome_Books_ES6 can be a webpage/website, a web app, a software and so on 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this [Awesome_Books_ES6] and associated documentation files, to deal in the [Awesome_Books_ES6] without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the [Awesome_Books_ES6], and to permit persons to whom the [Awesome_Books_ES6] is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the [Awesome_Books_ES6]. 9 | 10 | THE Awesome_Books_ES6 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_ES6] OR THE USE OR OTHER DEALINGS IN THE [Awesome_Books_ES6]. 11 | -------------------------------------------------------------------------------- /modules/bookListView.js: -------------------------------------------------------------------------------- 1 | export function displayBooks(bookListElement, bookManager) { 2 | const books = bookManager.getBooks(); 3 | 4 | bookListElement.innerHTML = ''; 5 | const list = document.createElement('ul'); 6 | list.classList.add('list-container'); 7 | 8 | books.forEach((book, index) => { 9 | const listItem = document.createElement('li'); 10 | 11 | const booksInfo = document.createElement('span'); 12 | booksInfo.textContent = `${book.title} by ${book.author}`; 13 | listItem.classList.add(index % 2 === 0 ? 'even' : 'odd'); 14 | listItem.appendChild(booksInfo); 15 | const removeButton = document.createElement('button'); 16 | removeButton.id = `remove-button-${book.id}`; 17 | 18 | removeButton.textContent = 'remove'; 19 | removeButton.setAttribute('data-index', index); 20 | 21 | listItem.appendChild(removeButton); 22 | list.appendChild(listItem); 23 | }); 24 | 25 | bookListElement.appendChild(list); 26 | attachRemoveButtonListeners(bookListElement, bookManager); 27 | } 28 | 29 | export function attachRemoveButtonListeners(bookListElement, bookManager) { 30 | const removeButtons = bookListElement.querySelectorAll("button[id^='remove-button-']"); 31 | removeButtons.forEach((button) => { 32 | button.addEventListener('click', (event) => { 33 | const bookIndex = event.target.dataset.index; 34 | bookManager.removeBook(bookIndex); 35 | displayBooks(bookListElement, bookManager); 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import Book from './modules/book.js'; 2 | import BookManager from './modules/bookManager.js'; 3 | import displayDate from './modules/dateManager.js'; 4 | import { displayBooks } from './modules/bookListView.js'; 5 | 6 | class BookList { 7 | constructor() { 8 | this.bookList = document.getElementById('book-list'); 9 | this.inputTitle = document.getElementById('title'); 10 | this.inputAuthor = document.getElementById('author'); 11 | this.inputButton = document.getElementById('add-button'); 12 | this.listButton = document.getElementById('contact-section'); 13 | this.newButton = document.getElementById('form-section'); 14 | this.books = []; 15 | this.bookManager = new BookManager(); 16 | this.inputButton.addEventListener('click', (event) => this.addBooks(event)); 17 | // Use the method through the instance itself 18 | this.displayBooks(); 19 | 20 | this.listLink = document.getElementById('list'); 21 | this.addLink = document.getElementById('new'); 22 | this.contactLink = document.getElementById('contact'); 23 | 24 | this.listLink.addEventListener('click', () => this.showSection('div-list')); 25 | this.addLink.addEventListener('click', () => this.showSection('form-section')); 26 | this.contactLink.addEventListener('click', () => this.showSection('contact-section')); 27 | 28 | // Use the method through the instance itself 29 | this.displayDate(); 30 | } 31 | 32 | addBooks(event) { 33 | event.preventDefault(); 34 | const title = this.inputTitle.value; 35 | const author = this.inputAuthor.value; 36 | if (title !== '' && author !== '') { 37 | const book = new Book(Date.now(), title, author); 38 | this.bookManager.addBook(book); 39 | } 40 | 41 | this.displayBooks(); 42 | this.inputAuthor.value = ''; 43 | this.inputTitle.value = ''; 44 | } 45 | 46 | showSection = (sectionId) => { 47 | const sections = document.getElementsByClassName('list-section'); 48 | 49 | for (let i = 0; i < sections.length; i += 1) { 50 | const content = sections[i]; 51 | if (content.id === sectionId) { 52 | content.classList.remove('hidden'); 53 | } else { 54 | content.classList.add('hidden'); 55 | } 56 | } 57 | } 58 | 59 | displayDate = () => { 60 | displayDate('date'); 61 | } 62 | 63 | displayBooks = () => { 64 | displayBooks(this.bookList, this.bookManager); 65 | } 66 | } 67 | 68 | const bookList = new BookList(); 69 | bookList.displayBooks(); 70 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Awesome Books 14 | 15 | 16 | 29 |
30 |
31 |

All Awesome books

32 |
33 |
34 | 52 | 59 |
60 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /.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@v3 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: "18.x" 17 | - name: Setup Lighthouse 18 | run: npm install -g @lhci/cli@0.11.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@v3 26 | - uses: actions/setup-node@v3 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@v3 40 | - uses: actions/setup-node@v3 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@v3 54 | - uses: actions/setup-node@v3 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@v3 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.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 5px 5px; 3 | font-family: 'Lato', sans-serif; 4 | text-decoration: none; 5 | } 6 | 7 | #nav-bar { 8 | border: 2px solid black; 9 | margin: 12px 0; 10 | padding: 5px 12px; 11 | display: flex; 12 | justify-content: space-between; 13 | align-items: center; 14 | flex-wrap: wrap; 15 | } 16 | 17 | .menu-list { 18 | display: flex; 19 | margin-right: 1.5%; 20 | margin-left: 1.5%; 21 | font-size: 1.3rem; 22 | font-weight: bold; 23 | list-style: none; 24 | } 25 | 26 | .menu-list li a { 27 | color: #000; 28 | } 29 | 30 | .menu-list li a:hover { 31 | color: rgb(80, 207, 253); 32 | } 33 | 34 | .line { 35 | height: 30px; 36 | width: 1px; 37 | background-color: black; 38 | border: solid 1px black; 39 | } 40 | 41 | #header { 42 | display: flex; 43 | flex-direction: column; 44 | align-self: flex-end; 45 | margin-left: 1.5%; 46 | margin-right: 1.5%; 47 | } 48 | 49 | h1, 50 | h3 { 51 | text-align: center; 52 | padding-top: 24px; 53 | margin-bottom: 24px; 54 | } 55 | 56 | .list-container { 57 | border: solid 2px black; 58 | display: flex; 59 | flex-direction: column; 60 | margin-left: 1.5%; 61 | margin-right: 1.5%; 62 | } 63 | 64 | li { 65 | display: flex; 66 | justify-content: space-between; 67 | } 68 | 69 | button { 70 | align-self: flex-end; 71 | box-shadow: 3px 3px; 72 | } 73 | 74 | .even { 75 | background-color: grey; 76 | } 77 | 78 | .separation-line { 79 | display: flex; 80 | flex-direction: row; 81 | justify-content: center; 82 | width: 15%; 83 | border: solid 2px black; 84 | margin-left: 42.5%; 85 | margin-top: 36px; 86 | } 87 | 88 | .input-container { 89 | margin-left: 35%; 90 | margin-right: 35%; 91 | display: flex; 92 | flex-direction: column; 93 | } 94 | 95 | .inputs { 96 | width: 100%; 97 | border: solid 2px black; 98 | padding: 5px; 99 | } 100 | 101 | .button { 102 | display: flex; 103 | justify-content: flex-end; 104 | } 105 | 106 | #contact-section { 107 | text-align: center; 108 | } 109 | 110 | #contact-section p, 111 | #contact-section ul { 112 | margin-bottom: 12px; 113 | } 114 | 115 | .contact-list { 116 | display: flex; 117 | flex-direction: column; 118 | justify-content: center; 119 | } 120 | 121 | .contact-list li { 122 | align-self: center; 123 | } 124 | 125 | .hidden { 126 | display: none; 127 | } 128 | 129 | .active { 130 | display: block; 131 | } 132 | 133 | #date { 134 | text-align: right; 135 | } 136 | 137 | #div-list h2 { 138 | text-align: center; 139 | margin-bottom: 25px; 140 | } 141 | 142 | .copyright { 143 | position: absolute; 144 | top: 90%; 145 | width: 90%; 146 | margin-left: 1.5%; 147 | margin-right: 1.5%; 148 | border: 2px solid black; 149 | } 150 | 151 | @media (min-width: 768px) { 152 | .copyright { 153 | padding-left: 50px; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 |

Awesome Books Javascript

7 | 8 |
9 | 10 | # 📗 Table of Contents 11 | 12 | - [📗 Table of Contents](#-table-of-contents) 13 | - [📖 \[Awesome\_Books\_ES6\] ](#-awesome_books_es6-) 14 | - [🛠 Built With ](#-built-with-) 15 | - [Tech Stack ](#tech-stack-) 16 | - [Key Features ](#key-features-) 17 | - [🚀 Live Demo ](#-live-demo-) 18 | - [💻 Getting Started ](#-getting-started-) 19 | - [Prerequisites](#prerequisites) 20 | - [Setup](#setup) 21 | - [Install](#install) 22 | - [Usage](#usage) 23 | - [Run tests](#run-tests) 24 | - [👥 Authors ](#-authors-) 25 | - [🔭 Future Features ](#-future-features-) 26 | - [🤝 Contributing ](#-contributing-) 27 | - [⭐️ Show your support ](#️-show-your-support-) 28 | - [🙏 Acknowledgments ](#-acknowledgments-) 29 | - [📝 License ](#-license-) 30 | 31 | # 📖 [Awesome_Books_ES6] 32 | 33 | > This is a web application for managing your book collection. Keep track of your favorite books, add new ones, and explore a curated list of recommendations. Built with modern technologies, including ES6 modules, Luxon, and npm. 34 | 35 | ## 🛠 Built With 36 | 37 | ### Tech Stack 38 | 39 | > HTML 40 | > JS (Javascript) 41 | 42 |
43 | Client 44 | 47 |
48 | 49 |
50 | Server 51 | 53 |
54 | 55 |
56 | Database 57 | 59 |
60 | 61 | ### Key Features 62 | 63 | - **[Branch creation]** 64 | - **[Version control]** 65 | - **[GitHub flow]** 66 | - **[Pull request]** 67 | - **[Descriptive commits]** 68 | - **[Data Persistence]** 69 | - **[Interactive User Basic Interface]** 70 | - **[JavaScript Functionality]** 71 | - **[Code Maintenance]** 72 | - **[Modular Structure]** 73 | - **[ES6 Syntax]** 74 | - **[Responsive Design]** 75 | - **[User-friendly Interface]** 76 | 77 |

(back to top)

78 | 79 | ## 🚀 Live Demo 80 | 81 | > You can see a Demo here: [Demo](https://claudiarojassoto.github.io/Awesome_Books_ES6/) 82 | 83 |

(back to top)

84 | 85 | ## 💻 Getting Started 86 | 87 | > To get a local copy up and running, follow these steps. 88 | 89 | ### Prerequisites 90 | 91 | In order to run this project you need: you need to know the basic of HTML5, Javascript, and basic knowledge about Git 92 | 93 | ### Setup 94 | 95 | Clone this repository to your desired folder: https://github.com/ClaudiaRojasSoto/Awesoem_Books_ES6.git 96 | 97 | ### Install 98 | 99 | Install this project with: install WebLint and ESLint 100 | 101 | ### Usage 102 | 103 | To run the project, execute the following command: just need a web Brwosser 104 | 105 | ### Run tests 106 | 107 | To run tests, run the following command: you just need a simple web browser to run this project for a test 108 | 109 | 110 | 111 | ## 👥 Authors 112 | 113 | 👤 **Author1** 114 | 115 | - GitHub: [@githubhandle](https://github.com/ClaudiaRojasSoto) 116 | - LinkedIn: [LinkedIn](https://www.linkedin.com/in/claudia-soto-260504208/) 117 | 118 | 119 |

(back to top)

120 | 121 | ## 🔭 Future Features 122 | 123 | > Describe 1 - 3 features you will add to the project. 124 | 125 | - [ ] **[]** 126 | - [ ] **[]** 127 | - [ ] **[]** 128 | 129 |

(back to top)

130 | 131 | ## 🤝 Contributing 132 | 133 | Contributions, issues, and feature requests are welcome! 134 | 135 | Feel free to check the [issues page](https://github.com/ClaudiaRojasSoto/Awesoem_Books_ES6/issues). 136 | 137 |

(back to top)

138 | 139 | ## ⭐️ Show your support 140 | 141 | > If you like this project show support by following this account 142 | 143 |

(back to top)

144 | 145 | 146 | 147 | ## 🙏 Acknowledgments 148 | 149 | > - Microverse for providing the opportunity to learn Git and GitHub in a collaborative environment. 150 | 151 | > - GitHub Docs for providing a wealth of information on Git and GitHub. 152 | 153 |

(back to top)

154 | 155 | 156 | 157 | ## 📝 License 158 | 159 | This project is [MIT](https://github.com/ClaudiaRojasSoto/awesome_Books_ES6/blob/master/MIT.md)) licensed. 160 | 161 |

(back to top)

162 | --------------------------------------------------------------------------------