├── .gitignore
├── .hintrc
├── .eslintrc.json
├── .stylelintrc.json
├── package.json
├── LICENSE
├── .github
└── workflows
│ └── blank.yml
├── index.js
├── index.html
├── README.md
└── style.css
/.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 | }
--------------------------------------------------------------------------------
/.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 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "awesome_book",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-eslint": "^10.1.0",
14 | "eslint": "^7.32.0",
15 | "eslint-config-airbnb-base": "^14.2.1",
16 | "eslint-plugin-import": "^2.27.5",
17 | "hint": "^7.1.10",
18 | "stylelint": "^13.13.1",
19 | "stylelint-config-standard": "^21.0.0",
20 | "stylelint-csstree-validator": "^1.9.0",
21 | "stylelint-scss": "^3.21.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 MIKE
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/blank.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.js:
--------------------------------------------------------------------------------
1 | class BookCollection {
2 | constructor() {
3 | this.books = JSON.parse(localStorage.getItem('bookCollection')) || [];
4 | }
5 |
6 | displayBooks() {
7 | const bookListDiv = document.getElementById('bookList');
8 | bookListDiv.innerHTML = '';
9 |
10 | this.books.forEach((book, index) => {
11 | const bookDiv = document.createElement('div');
12 | bookDiv.classList.add('book-details');
13 | bookDiv.innerHTML = `
14 |
15 | ${book.title} By: ${book.author}
16 |
17 | `;
18 |
19 | const removeBtn = document.createElement('button');
20 | removeBtn.classList.add('remove-btn');
21 | removeBtn.textContent = 'Remove';
22 | removeBtn.addEventListener('click', () => this.removeBook(index));
23 |
24 | bookDiv.appendChild(removeBtn);
25 | bookListDiv.appendChild(bookDiv);
26 | });
27 | }
28 |
29 | addBook(event) {
30 | event.preventDefault();
31 |
32 | const titleInput = document.getElementById('title');
33 | const authorInput = document.getElementById('author');
34 |
35 | const title = titleInput.value;
36 | const author = authorInput.value;
37 |
38 | if (title && author) {
39 | const newBook = {
40 | title,
41 | author,
42 | };
43 |
44 | this.books.push(newBook);
45 |
46 | localStorage.setItem('bookCollection', JSON.stringify(this.books));
47 |
48 | titleInput.value = '';
49 | authorInput.value = '';
50 |
51 | this.displayBooks();
52 | }
53 | }
54 |
55 | removeBook(index) {
56 | this.books.splice(index, 1);
57 |
58 | localStorage.setItem('bookCollection', JSON.stringify(this.books));
59 |
60 | this.displayBooks();
61 | }
62 | }
63 |
64 | const bookCollection = new BookCollection();
65 |
66 | const addBookForm = document.getElementById('addBookForm');
67 | addBookForm.addEventListener('submit', (event) => bookCollection.addBook(event));
68 |
69 | bookCollection.displayBooks();
70 |
71 | // Displaying the navitems individually
72 |
73 | const mainLink = document.getElementById('Main-Link');
74 | const addLink = document.getElementById('Add-Page-Link');
75 | const contactLink = document.getElementById('Contact_Link');
76 |
77 | const awesomeBooks = document.querySelector('.books-content-top');
78 | const contactPage = document.querySelector('.contact-container');
79 | const formPage = document.querySelector('.form-container');
80 |
81 | mainLink.addEventListener('click', () => {
82 | mainLink.classList.toggle('clicked');
83 | contactLink.classList.remove('clicked3');
84 | addLink.classList.remove('clicked2');
85 | formPage.classList.add('less');
86 | formPage.classList.remove('remove');
87 |
88 | contactPage.classList.remove('add');
89 | awesomeBooks.classList.add('more');
90 | });
91 |
92 | addLink.addEventListener('click', () => {
93 | addLink.classList.toggle('clicked2');
94 | mainLink.classList.remove('clicked');
95 | contactLink.classList.remove('clicked3');
96 | awesomeBooks.classList.remove('more');
97 | contactPage.classList.remove('add');
98 | formPage.classList.remove('less', 'remove');
99 | });
100 |
101 | contactLink.addEventListener('click', () => {
102 | addLink.classList.remove('clicked2');
103 | contactLink.classList.toggle('clicked3');
104 | mainLink.classList.remove('clicked');
105 | awesomeBooks.classList.remove('more');
106 | contactPage.classList.add('add');
107 | formPage.classList.add('remove');
108 | });
109 |
110 | const dateTime = document.querySelector('.date-time');
111 | dateTime.innerHTML = new Date().toString().slice(0, 34);
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Awesome Book
7 |
8 |
9 |
10 |
11 |
12 |
22 |
23 | July 12th 2023 10:43AM
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
Awesome Books
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
82 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Awesome Book
6 |
7 |
8 |
9 |
10 |
11 | # 📗 Table of Contents
12 |
13 | - [📗 Table of Contents](#-table-of-contents)
14 | - [📖 \[Awesome Book\] ](#-awesome-book-)
15 | - [🛠 Built With ](#-built-with-)
16 | - [Tech Stack ](#tech-stack-)
17 | - [Key Features ](#key-features-)
18 | - [💻 Getting Started ](#-getting-started-)
19 | - [Prerequisites](#prerequisites)
20 | - [Setup](#setup)
21 | - [Usage](#usage)
22 | - [👥 Authors ](#-authors-)
23 | - [🔭 Future Features ](#-future-features-)
24 | - [🤝 Contributing ](#-contributing-)
25 | - [⭐️ Show your support ](#️-show-your-support-)
26 | - [🙏 Acknowledgments ](#-acknowledgments-)
27 | - [📝 License ](#-license-)
28 |
29 |
30 |
31 | # 📖 [Awesome Book]
32 |
33 | > Describe your project in 1 or 2 sentences.
34 |
35 | **[Awesome Book]** is a webpage for storing and displying books from the localStorage of the browser
36 |
37 | ## 🛠 Built With
38 |
39 | ### Tech Stack
40 |
41 | > Describe the tech stack and include only the relevant sections that apply to your project.
42 |
43 |
44 | HTML
45 |
48 |
49 |
50 |
51 | JavaScript
52 |
55 |
56 |
57 |
58 |
59 | ### Key Features
60 |
61 | > Describe between 1-3 key features of the application.
62 |
63 | - **[local storage]**
64 | - **[dynamic pages]**
65 | - **[navigation]**
66 |
67 | (back to top )
68 |
69 | - [Awesome Book](https://github.com/Mike47ip/Awesome_Book/)
70 |
71 |
72 |
73 | ## 💻 Getting Started
74 |
75 | To get a local copy up and running, follow these steps.
76 |
77 | ### Prerequisites
78 |
79 | In order to run this project you need:
80 |
81 | ```sh
82 | sudo apt install git-all
83 | or
84 | npm install
85 | ```
86 |
87 | ### Setup
88 |
89 | Clone this repository to your desired folder:
90 |
91 | ```sh
92 | cd my-folder
93 | git clone https://github.com/Mike47ip/Awesome_Book.git
94 | ```
95 |
96 | ### Usage
97 |
98 | To run the project, execute the following command:
99 |
100 | ```sh
101 | Open index.html in browser
102 | or
103 | open with Live server in Vscode
104 | ```
105 |
106 | (back to top )
107 |
108 |
109 |
110 | ## 👥 Authors
111 |
112 | > Mention all of the collaborators of this project.
113 |
114 | 👤 **Michael Darkwah**
115 | 👤 **Enoch Bett**
116 | 👤 **Uzair Manzoor**
117 |
118 | - GitHub: [@Mike47ip](https://github.com/Mike47ip)
119 | - GitHub: [@bettenoch](https://github.com/Bettenoch)
120 | - GitHub: [@Uzair-Manzoor](https://github.com/Uzair-Manzoor)
121 |
122 |
123 |
124 | ## 🔭 Future Features
125 |
126 | > Describe 1 - 3 features you will add to the project.
127 |
128 | - [ ] **[Add more pages]**
129 |
130 | (back to top )
131 |
132 |
133 |
134 | ## 🤝 Contributing
135 |
136 | Contributions, issues, and feature requests are welcome!
137 |
138 | Feel free to check the [issues page](https://github.com/Yacoubou-seidou/awesome_book/issues).
139 |
140 |
141 |
142 | ## ⭐️ Show your support
143 |
144 | > Write a message to encourage readers to support your project
145 |
146 | If you like this project show some love by commenting
147 |
148 |
149 |
150 | ## 🙏 Acknowledgments
151 |
152 | > Give credit to everyone who inspired your codebase.
153 |
154 | I would like to thank Microverse staff for their support
155 |
156 |
157 |
158 | ## 📝 License
159 |
160 | This project is [MIT](https://github.com/Mike47ip/Awesome_Book/blob/main/LICENSE) licensed.
161 |
162 | (back to top )
163 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | list-style: none;
5 | text-decoration: none;
6 | box-sizing: border-box;
7 | }
8 |
9 | .main-container {
10 | position: relative;
11 | min-height: 100vh;
12 | }
13 |
14 | /* <==========Header Section ===========> */
15 |
16 | header {
17 | display: flex;
18 | flex-direction: column;
19 | width: 100vw;
20 | padding: 2rem;
21 | gap: 1rem;
22 | position: fixed;
23 | }
24 |
25 | .header-container {
26 | width: 100%;
27 | display: flex;
28 | align-items: center;
29 | justify-content: space-between;
30 | padding: 0.5rem 2rem;
31 | border: 2px solid rgb(67, 64, 64);
32 | border-radius: 5px;
33 | }
34 |
35 | .logo a {
36 | color: rgb(11, 11, 11);
37 | font-size: 1.3rem;
38 | font-weight: 600;
39 | }
40 |
41 | .navLinks li a {
42 | color: rgb(11, 11, 11);
43 | }
44 |
45 | .logo a:hover {
46 | color: blue;
47 | }
48 |
49 | .navLinks {
50 | text-decoration: none;
51 | list-style: none;
52 | display: flex;
53 | gap: 1rem;
54 | }
55 |
56 | .navLinks li {
57 | padding: 0.5rem;
58 | }
59 |
60 | .contact-details li {
61 | list-style: circle;
62 | }
63 |
64 | .navLinks li:nth-child(1),
65 | .navLinks li:nth-child(2) {
66 | border-right: 1px solid rgb(121, 118, 118);
67 | }
68 |
69 | .date-time {
70 | display: flex;
71 | justify-content: flex-end;
72 | }
73 |
74 | /* <==========Header End ===========> */
75 |
76 | .books-container {
77 | display: flex;
78 | align-items: center;
79 | justify-content: center;
80 | padding-top: 6rem;
81 | }
82 |
83 | .book-collections {
84 | display: flex;
85 | flex-direction: column;
86 | gap: 1.5rem;
87 | align-items: flex-start;
88 | justify-content: center;
89 | width: 100%;
90 | padding: 2rem;
91 | }
92 |
93 | .book-collections h1 {
94 | font-weight: 600;
95 | font-size: 2.2rem;
96 | }
97 |
98 | .book-collections .heading {
99 | text-align: center;
100 | }
101 |
102 | .books-content {
103 | display: flex;
104 | width: 100%;
105 | justify-content: center;
106 | align-items: center;
107 | flex-direction: column;
108 | }
109 |
110 | .books-content-top {
111 | width: 100%;
112 | display: none;
113 | flex-direction: column;
114 | gap: 2rem;
115 | padding-bottom: 4rem;
116 | }
117 |
118 | #bookList {
119 | border: 2px solid black;
120 | border-radius: 5px;
121 | display: flex;
122 | flex-direction: column;
123 | width: 100%;
124 | height: auto;
125 | }
126 |
127 | .book-details {
128 | display: flex;
129 | justify-content: space-between;
130 | gap: 1rem;
131 | padding: 0.5rem 1rem;
132 | }
133 |
134 | .form-container {
135 | display: flex;
136 | flex-direction: column;
137 | justify-content: center;
138 | align-items: center;
139 | padding-top: 3rem;
140 | }
141 |
142 | form {
143 | display: flex;
144 | flex-direction: column;
145 | gap: 0.5rem;
146 | }
147 |
148 | #addBookForm {
149 | width: 360px;
150 | }
151 |
152 | #title {
153 | height: 35px;
154 | }
155 |
156 | #author {
157 | height: 35px;
158 | }
159 |
160 | .btn-holder {
161 | display: flex;
162 | align-items: flex-end;
163 | justify-content: flex-end;
164 | }
165 |
166 | .remove-btn {
167 | width: 70px;
168 | padding: 5px;
169 | box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.5);
170 | }
171 |
172 | .form-btn {
173 | width: 70px;
174 | padding: 5px;
175 | box-shadow: 10px 10px 8px #888;
176 | }
177 |
178 | #bookList .book-details:nth-child(odd) {
179 | background: rgb(170, 165, 165);
180 | }
181 |
182 | /* <==========Contact Section ===========> */
183 | .contact-container {
184 | display: none;
185 | flex-direction: column;
186 | gap: 3rem;
187 | align-items: center;
188 | }
189 |
190 | .contact-info {
191 | display: flex;
192 | flex-direction: column;
193 | gap: 1rem;
194 | }
195 |
196 | .contact-details {
197 | padding-left: 3rem;
198 | }
199 |
200 | /* <==========Footer Section ===========> */
201 | .footer-container {
202 | display: flex;
203 | flex-direction: column;
204 | width: 100vw;
205 | padding: 2rem;
206 | position: absolute;
207 | bottom: 0;
208 | }
209 |
210 | footer {
211 | width: 100%;
212 | display: flex;
213 | align-items: center;
214 | justify-content: space-between;
215 | padding: 0.5rem 2rem;
216 | border: 2px solid rgb(67, 64, 64);
217 | border-radius: 5px;
218 | }
219 |
220 | .clicked {
221 | color: blue !important;
222 | }
223 |
224 | .clicked2 {
225 | color: blue !important;
226 | }
227 |
228 | .clicked3 {
229 | color: blue !important;
230 | }
231 |
232 | .more {
233 | display: flex;
234 | }
235 |
236 | .less {
237 | display: none;
238 | }
239 |
240 | .remove {
241 | display: none;
242 | }
243 |
244 | .add {
245 | display: flex;
246 | }
247 |
--------------------------------------------------------------------------------