├── .gitignore
├── .vscode
└── settings.json
├── .hintrc
├── .eslintrc.json
├── .stylelintrc.json
├── package.json
├── README.md
├── index.html
├── .github
└── workflows
│ └── linters.yml
├── style.css
└── script.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "liveServer.settings.port": 5501
3 | }
--------------------------------------------------------------------------------
/.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": "awsome-books",
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/nedjwab/Awsome-Books.git"
12 | },
13 | "keywords": [],
14 | "author": "",
15 | "license": "ISC",
16 | "bugs": {
17 | "url": "https://github.com/nedjwab/Awsome-Books/issues"
18 | },
19 | "homepage": "https://github.com/nedjwab/Awsome-Books#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": "^6.1.11",
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Awsome Books
4 |
5 | In this Project, we have built A Books websites.
6 |
7 |
8 |
9 | ## Built With 🔨
10 |
11 | - HTML
12 | - CSS
13 | - javascript
14 | - Git & Github
15 |
16 | ## Live Demo
17 | [Here](https://nedjwab.github.io/Awsome-Books/) you can find the live Demo of the website
18 |
19 | ### Install
20 | Download the zip file.
21 | extract the folder.
22 | go to the index.html file.
23 |
24 |
25 | ### Prerequisites
26 |
27 | - IDE ( VCode For me 🔥).
28 | - Git.
29 | - Npm and node.js installed.
30 |
31 |
32 | ### Usage
33 |
34 | - For anyone who wants to practice html5 or/and css3
35 | - For anyone who wants to create a CRUD website.
36 |
37 | ## Authors
38 |
39 | 👤 **Nedjwa Bouraiou**
40 | 👤 **Shaquille Ndunda**
41 | 👤 **Sonia Karungi**
42 |
43 |
44 |
45 |
46 | - GitHub: [@Nedjwab](https://github.com/nedjwab)
47 | - LinkedIn: [@Bouraiounedjwa](https://www.linkedin.com/feed/)
48 |
49 | - GitHub:[@shaqdeff](https://github.com/shaqdeff)
50 | - LinkedIn:[Shaquille Ndunda](https://www.linkedin.com/in/shaquille-ndunda-b13a95107/)
51 |
52 | - GitHub: [@SoniaKarungi](https://github.com/SoniaKarungi)
53 | - LinkedIn:[Sonia Karungi](https://www.linkedin.com/in/soniarmkarungi/)
54 |
55 |
56 | ## 🤝 Contributing
57 |
58 | Contributions, issues, and feature requests are welcome!
59 |
60 | ## Show your support
61 |
62 | Give a ⭐️ if you like this project!
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Awesome Books
10 |
11 |
12 |
13 | Awesome Books
14 |
21 |
22 |
23 |
24 | All Awesome Books
25 |
26 |
27 |
30 |
31 |
32 | Add a new book
33 |
34 |
39 |
40 |
54 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/.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-18.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-18.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@6.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-18.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-18.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 .
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 |
2 | @import url('https://fonts.googleapis.com/css2?family=Anek+Telugu&display=swap');
3 |
4 | body {
5 | margin: 0;
6 | font-family: 'Anek Telugu', sans-serif;
7 | }
8 |
9 | header {
10 | display: flex;
11 | justify-content: space-between;
12 | align-items: center;
13 | border: 2px solid black;
14 | width: 90%;
15 | margin: 15px auto 0 auto;
16 | }
17 |
18 | nav ul {
19 | display: flex;
20 | list-style: none;
21 | gap: 20px;
22 | padding-right: 10px;
23 | }
24 |
25 | nav ul li {
26 | border-right: 1px solid black;
27 | padding-right: 15px;
28 | cursor: pointer;
29 | }
30 |
31 | nav ul li:hover {
32 | color: purple;
33 | }
34 |
35 | #nav-contact {
36 | border: none;
37 | }
38 |
39 | .heading-title {
40 | font-size: 24px;
41 | padding-left: 15px;
42 | }
43 |
44 | #date {
45 | position: absolute;
46 | text-align: right;
47 | right: 5%;
48 | }
49 |
50 | .heading h1 {
51 | margin-top: 70px;
52 | text-align: center;
53 | font-size: 30px;
54 | font-family: 'Anek Telugu', sans-serif;
55 | }
56 |
57 | hr {
58 | width: 30%;
59 | margin-inline: auto;
60 | border: none;
61 | height: 3px;
62 | background: black;
63 | }
64 |
65 | .tinyhr {
66 | width: 20%;
67 | margin-inline: auto;
68 | border: none;
69 | height: 2px;
70 | background: black;
71 | }
72 |
73 | h2 {
74 | text-align: center;
75 | font-size: 30px;
76 | font-family: 'Anek Telugu', sans-serif;
77 | }
78 |
79 | .bookscontainer {
80 | width: 89%;
81 | display: flex;
82 | flex-direction: column;
83 | justify-content: space-evenly;
84 | border: solid 4px black;
85 | margin-left: auto;
86 | margin-right: auto;
87 | padding: 0;
88 | }
89 |
90 | .book-details {
91 | list-style: none;
92 | }
93 |
94 | .book {
95 | width: 99%;
96 | display: flex;
97 | flex-direction: row;
98 | font-size: 28px;
99 | font-family: 'Anek Telugu', sans-serif;
100 | font-weight: 600;
101 | padding: 5px;
102 | overflow-x: hidden;
103 | overflow-y: hidden;
104 | }
105 |
106 | .book:nth-child(odd) {
107 | background-color: #dfdfde;
108 | }
109 |
110 | .remove-btn {
111 | background-color: white;
112 | border: solid 2px black;
113 | font-size: 17px;
114 | font-weight: 600;
115 | font-family: 'Anek Telugu', sans-serif;
116 | box-shadow: 3px 3px;
117 | margin-left: auto;
118 | text-align: center;
119 | }
120 |
121 | .remove-btn:hover {
122 | cursor: pointer;
123 | }
124 |
125 | .form {
126 | display: flex;
127 | flex-direction: column;
128 | align-items: center;
129 | padding: 20px;
130 | }
131 |
132 | input {
133 | width: 30%;
134 | border: solid 2px black;
135 | padding: 17px;
136 | font-size: 19px;
137 | }
138 |
139 | #add-button {
140 | background-color: white;
141 | border: solid 2px black;
142 | font-size: 17px;
143 | font-weight: 600;
144 | font-family: 'Anek Telugu', sans-serif;
145 | box-shadow: 3px 3px;
146 | padding: 10px;
147 | }
148 |
149 | #add-button:hover {
150 | cursor: pointer;
151 | }
152 |
153 | .contact-info {
154 | display: flex;
155 | justify-content: center;
156 | flex-direction: column;
157 | align-items: center;
158 | font-size: 19px;
159 | }
160 |
161 | footer {
162 | border: solid 2px black;
163 | width: 88%;
164 | margin: 15px auto 0 auto;
165 | padding: 9px;
166 | font-weight: 600;
167 | }
168 |
--------------------------------------------------------------------------------
/script.js:
--------------------------------------------------------------------------------
1 | // Select the Elements
2 | const container = document.querySelector('.bookscontainer');
3 | const addBtn = document.querySelector('form');
4 | const titleI = document.querySelector('.title');
5 | const authorI = document.querySelector('.author');
6 |
7 | // Class of Books
8 | class Books {
9 | static books = [];
10 |
11 | id = `${Date.now()}`.slice(-10);
12 |
13 | constructor(id, title, author) {
14 | this.id = id;
15 | this.title = title;
16 | this.author = author;
17 | }
18 |
19 | // Data Storage
20 | static storage(books) {
21 | localStorage.setItem('books', JSON.stringify(books));
22 | }
23 |
24 | addBook() {
25 | Books.books.push(this);
26 | Books.storage(Books.books);
27 | Books.displayBook();
28 | titleI.value = '';
29 | authorI.value = '';
30 | }
31 |
32 | // Display Book
33 | static displayBook() {
34 | if (JSON.parse(localStorage.getItem('books'))) {
35 | Books.books = JSON.parse(localStorage.getItem('books'));
36 | }
37 |
38 | let list = '';
39 | Books.books.forEach((book) => {
40 | list += `
41 |
42 | "${book.title}" by ${book.author}
43 |
44 |
45 | `;
46 | });
47 |
48 | const addNewSection = document.getElementById('add-new');
49 | const contactSection = document.getElementById('contact');
50 | const dateSection = document.getElementById('date');
51 | addNewSection.style.display = 'none';
52 | contactSection.style.display = 'none';
53 | dateSection.innerText = new Date().toLocaleString('en-US', {
54 | day: 'numeric',
55 | year: 'numeric',
56 | month: 'long',
57 | hour: 'numeric',
58 | minute: 'numeric',
59 | second: 'numeric',
60 | });
61 |
62 | container.innerHTML = list;
63 |
64 | // Remove Book eventlistner
65 | document.querySelectorAll('.remove-btn').forEach((btn) => {
66 | btn.addEventListener('click', (e) => {
67 | const targetId = e.target.parentElement.id;
68 | Books.books = Books.books.filter((book) => book.id !== targetId);
69 | Books.storage(Books.books);
70 | e.target.parentElement.remove();
71 | });
72 | });
73 | }
74 | }
75 |
76 | let id;
77 | // Add Book eventlistner
78 | addBtn.addEventListener('submit', (e) => {
79 | e.preventDefault();
80 | id = `${Date.now()}`.slice(-10);
81 | const title = titleI.value;
82 | const author = authorI.value;
83 | const newBook = new Books(id, title, author);
84 | newBook.addBook();
85 | // eslint-disable-next-line no-restricted-globals
86 | location.reload();
87 | });
88 |
89 | const addNewSection = document.getElementById('add-new');
90 | const contactSection = document.getElementById('contact');
91 | const ListSection = document.getElementById('list');
92 |
93 | document.querySelector('#nav-add-new').addEventListener('click', () => {
94 | addNewSection.style.display = 'block';
95 | contactSection.style.display = 'none';
96 | ListSection.style.display = 'none';
97 | });
98 |
99 | document.querySelector('#nav-list').addEventListener('click', () => {
100 | addNewSection.style.display = 'none';
101 | contactSection.style.display = 'none';
102 | ListSection.style.display = 'block';
103 | });
104 |
105 | document.querySelector('#nav-contact').addEventListener('click', () => {
106 | addNewSection.style.display = 'none';
107 | contactSection.style.display = 'block';
108 | ListSection.style.display = 'none';
109 | });
110 |
111 | // Reload function
112 | window.onload = () => {
113 | Books.displayBook();
114 | };
115 |
--------------------------------------------------------------------------------