├── .gitignore ├── murple_logo.png ├── modules ├── date.js ├── selector.js └── UI.js ├── .hintrc ├── .eslintrc.json ├── .stylelintrc.json ├── package.json ├── index.js ├── index.css ├── .github └── workflows │ └── linters.yml ├── index.html └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /murple_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bernabasy/AwesomeBooks_with_ES6/HEAD/murple_logo.png -------------------------------------------------------------------------------- /modules/date.js: -------------------------------------------------------------------------------- 1 | import { DateTime } from './luxon.js'; 2 | 3 | const Date = () => { 4 | const output = DateTime.local(); 5 | document.getElementById('date').innerHTML = output.toLocaleString( 6 | 7 | DateTime.DATETIME_MED_WITH_SECONDS, 8 | ); 9 | }; 10 | export default Date; -------------------------------------------------------------------------------- /.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": "awesomebooks_with_es6", 3 | "version": "1.0.0", 4 | "description": "", 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/bernabasy/AwesomeBooks_with_ES6.git" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/bernabasy/AwesomeBooks_with_ES6/issues" 18 | }, 19 | "homepage": "https://github.com/bernabasy/AwesomeBooks_with_ES6#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.26.0", 25 | "hint": "^7.1.3", 26 | "stylelint": "^13.13.1", 27 | "stylelint-config-standard": "^21.0.0", 28 | "stylelint-csstree-validator": "^1.9.0", 29 | "stylelint-scss": "^3.21.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import Book from './modules/UI.js'; 2 | import Date from './modules/date.js'; 3 | import * as module from './modules/selector.js'; 4 | 5 | window.addEventListener('load', Date()); 6 | 7 | module.contact.addEventListener('click', module.contactCall); 8 | module.addBook.addEventListener('click', module.addBookCall); 9 | window.addEventListener('load', module.onload); 10 | module.bookList.addEventListener('click', module.onload); 11 | document.addEventListener('DOMContentLoaded', Book.displayBooks); 12 | const Form = document.querySelector('#book-form'); 13 | Form.addEventListener('submit', (e) => { 14 | e.preventDefault(); 15 | 16 | const title = document.querySelector('#title').value; 17 | const author = document.querySelector('#author').value; 18 | 19 | const book = new Book(title, author); 20 | 21 | Book.addBookToList(book); 22 | 23 | Book.addBook(book); 24 | 25 | Book.clearField(); 26 | }); 27 | 28 | document.querySelector('#book-list').addEventListener('click', (e) => { 29 | Book.removeBook(e.target.parentElement.previousElementSibling.innerHTML); 30 | Book.deleteBook(e.target); 31 | }); -------------------------------------------------------------------------------- /modules/selector.js: -------------------------------------------------------------------------------- 1 | export const bookList = document.querySelector('#list'); 2 | export const addBook = document.querySelector('#add-new'); 3 | export const contact = document.querySelector('#contact'); 4 | export const addSection = document.querySelector('.add'); 5 | export const contactSection = document.querySelector('.contact'); 6 | export const listSection = document.querySelector('.list'); 7 | 8 | export const onload = () => { 9 | contactSection.style.display = 'none'; 10 | addSection.style.display = 'none'; 11 | listSection.style.display = 'block'; 12 | bookList.classList.add('active'); 13 | contact.classList.remove('active'); 14 | addBook.classList.remove('active'); 15 | }; 16 | 17 | export const addBookCall = () => { 18 | bookList.classList.remove('active'); 19 | contact.classList.remove('active'); 20 | contactSection.style.display = 'none'; 21 | addSection.style.display = 'flex'; 22 | addBook.classList.add('active'); 23 | listSection.style.display = 'none'; 24 | }; 25 | 26 | export const contactCall = () => { 27 | addBook.classList.remove('active'); 28 | bookList.classList.remove('active'); 29 | contactSection.style.display = 'flex'; 30 | addSection.style.display = 'none'; 31 | listSection.style.display = 'none'; 32 | contact.classList.add('active'); 33 | }; 34 | -------------------------------------------------------------------------------- /modules/UI.js: -------------------------------------------------------------------------------- 1 | export default class Book { 2 | constructor(title, author) { 3 | this.title = title; 4 | this.author = author; 5 | } 6 | 7 | static displayBooks() { 8 | const books = Book.getBooks(); 9 | books.forEach((book) => Book.addBookToList(book)); 10 | } 11 | 12 | static addBookToList(book) { 13 | const list = document.querySelector('#book-list'); 14 | 15 | const row = document.createElement('tr'); 16 | 17 | row.innerHTML = ` 18 | "${book.title}" by ${book.author} 19 | ${book.author} 20 | remove 21 | `; 22 | list.appendChild(row); 23 | } 24 | 25 | static deleteBook(el) { 26 | if (el.classList.contains('delete')) { 27 | el.parentElement.parentElement.remove(); 28 | } 29 | } 30 | 31 | static clearField() { 32 | document.querySelector('#title').value = ''; 33 | document.querySelector('#author').value = ''; 34 | } 35 | 36 | static getBooks() { 37 | let books; 38 | if (localStorage.getItem('books') === null) { 39 | books = []; 40 | } else { 41 | books = JSON.parse(localStorage.getItem('books')); 42 | } 43 | return books; 44 | } 45 | 46 | static addBook(book) { 47 | const books = Book.getBooks(); 48 | books.push(book); 49 | localStorage.setItem('books', JSON.stringify(books)); 50 | } 51 | 52 | static removeBook(author) { 53 | const books = Book.getBooks(); 54 | let index = 0; 55 | books.filter((book) => { 56 | if (book.author !== author) { index = +1; } 57 | return books; 58 | }); 59 | books.splice(index, 1); 60 | localStorage.setItem('books', JSON.stringify(books)); 61 | } 62 | } -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | display: flex; 7 | flex-direction: column; 8 | margin-inline: 20px; 9 | } 10 | 11 | header { 12 | display: flex; 13 | flex-direction: column; 14 | padding-bottom: 2%; 15 | } 16 | 17 | a { 18 | text-decoration: none; 19 | color: #000; 20 | } 21 | 22 | .active { 23 | color: #00f; 24 | } 25 | 26 | .navigation { 27 | border: 2px solid #000; 28 | display: flex; 29 | flex-direction: row; 30 | justify-content: space-between; 31 | align-items: center; 32 | padding: 1%; 33 | } 34 | 35 | footer p { 36 | margin-top: 0.5px; 37 | margin-bottom: auto; 38 | } 39 | 40 | .navigation > p { 41 | margin-bottom: 0; 42 | } 43 | 44 | .nav-list { 45 | list-style-type: none; 46 | display: flex; 47 | justify-content: center; 48 | align-items: center; 49 | margin-bottom: 0; 50 | gap: 20px; 51 | } 52 | 53 | .nav-list > li { 54 | padding: 5px; 55 | } 56 | 57 | #date { 58 | align-self: flex-end; 59 | padding-right: 1%; 60 | margin-bottom: 0; 61 | } 62 | 63 | #list, 64 | #add-new { 65 | border-right: 2px solid #000; 66 | padding-right: 25px; 67 | } 68 | 69 | hr { 70 | border: 1px solid #000; 71 | width: 10%; 72 | } 73 | 74 | #book-list tr:nth-child(odd) { 75 | background-color: #f2f2f2; 76 | } 77 | 78 | .add { 79 | display: flex; 80 | justify-content: center; 81 | align-items: center; 82 | width: 100%; 83 | } 84 | 85 | .contact { 86 | display: flex; 87 | flex-direction: column; 88 | justify-content: space-around; 89 | align-items: center; 90 | } 91 | 92 | footer { 93 | display: flex; 94 | padding: 20px; 95 | border: 2px solid #000; 96 | align-items: center; 97 | margin-bottom: 10px; 98 | margin-top: 400px; 99 | bottom: 0; 100 | gap: 20px; 101 | width: 100%; 102 | } 103 | -------------------------------------------------------------------------------- /.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 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 | AwsomeBooks_ES6 8 | 9 | 10 | 11 | 12 |
13 | 27 |

28 |
29 |
30 |
31 |

All awesome Books

32 | 33 | 34 |
35 |
36 |
37 |
38 |

Add a new book

39 |
40 | 41 |
42 |
43 | 44 |
45 | 46 |
47 |
48 |
49 |

Contact information

50 |

Do you have any questions or you just want to say "Hello"?
You can reach out to us!

51 | 56 |
57 |
58 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | logo 6 |
7 | 8 |

AwesomeBooks_with_ES6

9 | 10 |
11 | 12 | 13 | 14 | # 📗 Table of Contents 15 | 16 | - [📖 About the Project](#about-project) 17 | - [🛠 Built With](#built-with) 18 | - [Key Features](#key-features) 19 | - [🚀 Live Demo](#live-demo) 20 | - [💻 Getting Started](#getting-started) 21 | - [Clone](#clone) 22 | - [Run](#run) 23 | - [👥 Authors](#authors) 24 | - [🙏 Acknowledgements](#acknowledgements) 25 | - [🤝 Contributing](#contributing) 26 | - [⭐️ Show your support](#support) 27 | - [📝 License](#license) 28 | 29 | 30 | 31 | # 📖 Awesome books 32 | 33 | > "AwesomeBooks_with_ES6" is a simple website that displays a list of books and allows you to add and remove books from that list. . 34 | 35 | ## 🛠 Built With HTML, CSS, & Javascript 36 | 37 | 38 |

(back to top)

39 | 40 | ### Key Features 41 | 42 | - Responsive 43 | - Fast 44 | - Modern 45 | 46 |

(back to top)

47 | 48 | > Describe between 1-3 key features of the application. 49 | - **[add more animation]** 50 | 51 |

(back to top)

52 | 53 | 54 | ## 🚀 Live Demo 55 | 56 | > Here is a link to deployed project. 57 | 58 | - [Live Demo Link](https://bernabasy.github.io/AwesomeBooks_with_ES6/) 59 | 60 |

(back to top)

61 | 62 | 63 | 64 | ## 💻 Getting Started 65 | 66 | > Describe how a new developer could make use of your project. 67 | 68 | To get a local copy up and running, follow these steps. 69 | 70 | ### Clone 71 | 72 | Clone this repository to your desired folder: 73 | 74 | git clone 75 | 76 | 77 | ### Run 78 | 79 | To run project, run the following command: 80 | 81 | Open in desired editor. 82 | 83 |

(back to top)

84 | 85 | 86 | 87 | ## 👥 Authors 88 | 89 | > Mention all of the collaborators of this project. 90 | 91 | 👤 Bernabas yosef 92 | 93 | GitHub: [@githubhandle](https://github.com/bernabasy) 94 | LinkedIn: [LinkedIn](https://www.linkedin.com/in/bernabasjosef/) 95 | 96 |

(back to top)

97 | 98 | 99 | 100 | ## 🙏 Acknowledgments 101 | 102 | I would like to thank Microverse for this opportunity. 103 | 104 |

(back to top)

105 | 106 | 107 | 108 | ## 🤝 Contributing 109 | 110 | Contributions, issues, and feature requests are welcome! 111 | 112 |

(back to top)

113 | 114 | 115 | 116 | ## ⭐️ Show your support 117 | 118 | If you like this project please give a star... 119 | 120 |

(back to top)

121 | 122 | 123 | 124 | ## 📝 License 125 | 126 | This project is [MIT](./mit.md) licensed. 127 | 128 |

(back to top)

129 | --------------------------------------------------------------------------------