├── .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 |
Remove
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 |
12 | Awesome Books 📚
13 |
14 | Books 📓
15 | add new ➕
16 | Contact ✉️
17 |
18 |
19 |
20 |
21 |
All awesome books
22 |
23 |
24 |
36 |
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 |
--------------------------------------------------------------------------------