├── .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 |
14 | Awesome Books
15 |
26 |
27 |
28 |
29 |
30 |
31 | All awesome Books
32 |
35 |
36 |
48 |
57 |
58 |
59 | Copyright
60 | ...
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
--------------------------------------------------------------------------------