├── .vscode
└── settings.json
├── .gitignore
├── .hintrc
├── .eslintrc.json
├── .stylelintrc.json
├── MIT.md
├── index.html
├── styles.css
├── .github
└── workflows
│ └── linters.yml
├── script.js
└── README.md
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "liveServer.settings.port": 5503
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
3 | dist/*.html
4 | dist/*.css
5 |
6 | test.md
7 |
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/.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": [
18 | 1,
19 | {
20 | "js": "always",
21 | "json": "always"
22 | }
23 | ],
24 | "no-use-before-define": ["error", { "functions": false }]
25 | },
26 | "ignorePatterns": ["dist/", "build/"]
27 | }
28 |
--------------------------------------------------------------------------------
/.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 | }
--------------------------------------------------------------------------------
/MIT.md:
--------------------------------------------------------------------------------
1 | ## Copyright 2021, [YOUR NAME]
2 |
3 | ###### Please delete this line and the next one
4 |
5 | ###### APP TYPE can be a webpage/website, a web app, a software and so on
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this [APP TYPE] and associated documentation files, to deal in the [APP TYPE] without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the [APP TYPE], and to permit persons to whom the [APP TYPE] is furnished to do so, subject to the following conditions:
8 |
9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the [APP TYPE].
10 |
11 | THE [APP TYPE] 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 [APP TYPE] OR THE USE OR OTHER DEALINGS IN THE [APP TYPE].
12 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Book-List
9 |
10 |
11 |
12 | Awesome Books
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
56 |
57 | Contact Info
58 | Email: contact@example.com
59 | Phone: 123-456-7890
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | font-family: "Lato", sans-serif;
9 | }
10 |
11 | header {
12 | background-color: #333;
13 | color: #fff;
14 | padding: 10px;
15 | display: flex;
16 | justify-content: space-between;
17 | align-items: center;
18 | }
19 |
20 | h1 {
21 | text-align: center;
22 | margin-right: auto;
23 | }
24 |
25 | nav ul {
26 | list-style-type: none;
27 | display: flex;
28 | align-items: center;
29 | }
30 |
31 | nav li {
32 | margin: 0 10px;
33 | }
34 |
35 | nav a {
36 | color: #fff;
37 | text-decoration: none;
38 | }
39 |
40 | nav a:hover {
41 | text-decoration: underline;
42 | }
43 |
44 | main {
45 | padding: 20px;
46 | }
47 |
48 | .content-section {
49 | display: none;
50 | }
51 |
52 | .content-section.active {
53 | display: block;
54 | }
55 |
56 | .content-section h3 {
57 | margin-bottom: 10px;
58 | }
59 |
60 | .input-container {
61 | display: flex;
62 | flex-direction: column;
63 | }
64 |
65 | .inputs {
66 | width: 100%;
67 | padding: 5px;
68 | margin-bottom: 10px;
69 | }
70 |
71 | .button {
72 | display: flex;
73 | justify-content: flex-end;
74 | }
75 |
76 | .separation-line {
77 | width: 15%;
78 | border: solid 2px black;
79 | margin: 36px auto;
80 | }
81 |
82 | #book-list {
83 | margin-top: 10px;
84 | border: solid 2px black;
85 | }
86 |
87 | #book-list-container {
88 | border: 2px solid black;
89 | padding: 10px;
90 | }
91 |
92 | .book-item {
93 | display: flex;
94 | justify-content: space-between;
95 | align-items: center;
96 | margin-bottom: 10px;
97 | background-color: #fff;
98 | padding: 10px;
99 | }
100 |
101 | .book-item:nth-child(even) {
102 | background-color: #f2f2f2;
103 | }
104 |
105 | .book-item p {
106 | margin: 0;
107 | }
108 |
109 | .book-item button {
110 | box-shadow: 3px 3px;
111 | }
112 |
113 | #datetime {
114 | text-align: right;
115 | margin-top: 10px;
116 | font-size: 14px;
117 | }
118 |
--------------------------------------------------------------------------------
/.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@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 |
--------------------------------------------------------------------------------
/script.js:
--------------------------------------------------------------------------------
1 | class BookList {
2 | constructor() {
3 | this.bookListContainer = document.getElementById('book-list-container');
4 | this.inputTitle = document.getElementById('title');
5 | this.inputAuthor = document.getElementById('author');
6 | this.inputButton = document.getElementById('add-button');
7 | this.books = [];
8 |
9 | this.loadBooksFromLocalStorage();
10 | this.inputButton.addEventListener('click', this.addBook.bind(this));
11 |
12 | this.setupNavigation();
13 | }
14 |
15 | displayBooks() {
16 | const bookList = document.getElementById('book-list');
17 | bookList.innerHTML = '';
18 |
19 | this.books.forEach((book, index) => {
20 | const listItem = document.createElement('div');
21 | listItem.classList.add('book-item');
22 |
23 | const titleElement = document.createElement('p');
24 | titleElement.textContent = `Title: ${book.title}`;
25 |
26 | const authorElement = document.createElement('p');
27 | authorElement.textContent = `Author: ${book.author}`;
28 |
29 | const removeButton = document.createElement('button');
30 | removeButton.textContent = 'Remove';
31 | removeButton.addEventListener('click', () => {
32 | this.removeBook(index);
33 | });
34 |
35 | listItem.appendChild(titleElement);
36 | listItem.appendChild(authorElement);
37 | listItem.appendChild(removeButton);
38 |
39 | bookList.appendChild(listItem);
40 | });
41 |
42 | if (this.books.length === 0) {
43 | this.bookListContainer.style.display = 'none';
44 | } else {
45 | this.bookListContainer.style.display = 'block';
46 | }
47 | }
48 |
49 | loadBooksFromLocalStorage() {
50 | const storedBooks = localStorage.getItem('books');
51 | if (storedBooks) {
52 | this.books = JSON.parse(storedBooks);
53 | }
54 | this.displayBooks();
55 | }
56 |
57 | saveBooksToLocalStorage() {
58 | localStorage.setItem('books', JSON.stringify(this.books));
59 | }
60 |
61 | addBook(event) {
62 | event.preventDefault();
63 | const title = this.inputTitle.value;
64 | const author = this.inputAuthor.value;
65 | if (title !== '' && author !== '') {
66 | const book = { title, author };
67 | this.books.unshift(book);
68 | this.saveBooksToLocalStorage();
69 | this.displayBooks();
70 | this.inputTitle.value = '';
71 | this.inputAuthor.value = '';
72 | }
73 | }
74 |
75 | removeBook(index) {
76 | this.books.splice(index, 1);
77 | this.saveBooksToLocalStorage();
78 | this.displayBooks();
79 | }
80 |
81 | setupNavigation() {
82 | const navLinks = document.querySelectorAll('.nav-links li a');
83 | navLinks.forEach((link) => {
84 | link.addEventListener('click', (event) => {
85 | event.preventDefault();
86 | const targetSectionId = link.getAttribute('href').substring(1);
87 | this.showSection(targetSectionId);
88 | });
89 | });
90 | }
91 |
92 | showSection = (sectionId) => {
93 | const contentSections = document.querySelectorAll('.content-section');
94 | contentSections.forEach((section) => {
95 | if (section.id === sectionId) {
96 | section.classList.add('active');
97 | } else {
98 | section.classList.remove('active');
99 | }
100 | });
101 |
102 | const navLinks = document.querySelectorAll('.nav-links li a');
103 | navLinks.forEach((link) => {
104 | if (link.getAttribute('href').substring(1) === sectionId) {
105 | link.classList.add('active');
106 | } else {
107 | link.classList.remove('active');
108 | }
109 | });
110 | }
111 | }
112 |
113 | document.addEventListener('DOMContentLoaded', () => {
114 | const bookList = new BookList();
115 | bookList.displayBooks();
116 | updateDateTime();
117 |
118 | function updateDateTime() {
119 | const datetimeElement = document.getElementById('datetime');
120 | const now = new Date();
121 |
122 | const options = {
123 | month: 'short', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric',
124 | };
125 | const dateTimeString = now.toLocaleString('en-US', options);
126 |
127 | const formattedDateTime = dateTimeString.replace(',', '');
128 |
129 | datetimeElement.textContent = formattedDateTime;
130 | }
131 |
132 | setInterval(updateDateTime, 1000);
133 | });
134 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
23 |
24 |
25 |
26 | # 📗 Table of Contents
27 |
28 | - [📖 About the Project](#about-project)
29 | - [🛠 Built With](#built-with)
30 | - [Tech Stack](#tech-stack)
31 | - [Key Features](#key-features)
32 | - [🚀 Live Demo](#live-demo)
33 | - [💻 Getting Started](#getting-started)
34 | - [Setup](#setup)
35 | - [Prerequisites](#prerequisites)
36 | - [Install](#install)
37 | - [Usage](#usage)
38 | - [Run tests](#run-tests)
39 | - [Deployment](#deployment)
40 | - [👥 Authors](#authors)
41 | - [🔭 Future Features](#future-features)
42 | - [🤝 Contributing](#contributing)
43 | - [⭐️ Show your support](#support)
44 | - [🙏 Acknowledgements](#acknowledgements)
45 | - [❓ FAQ (OPTIONAL)](#faq)
46 | - [📝 License](#license)
47 |
48 |
49 |
50 | # 📖 [book_list]
51 |
52 | **[book_list]**
53 | This exercise involves the creation of a book list application that enables users to add and remove books. The application is built using HTML, JavaScript, and leverages the Local Storage feature of web browsers to store the book data persistently. It provides a user-friendly interface with a form where users can input the title and author of a book. Upon submitting the form, the book is added to the list, which is dynamically updated and displayed on the page. The application also allows users to easily remove books from the list with a single click. The use of Local Storage ensures that the book collection remains intact even if the page is refreshed or reopened. This project showcases the implementation of basic CRUD (Create, Read, Update, Delete) operations using web technologies, providing a practical example of data management and persistence within the browser environment.
54 |
55 | ## 🛠 Built With
56 |
57 | ### Tech Stack
58 |
59 |
60 | HTML
61 |
62 |
63 |
64 | JavaScript
65 |
66 |
67 |
68 | ### Key Features
69 |
70 | - **[Branch creation]**
71 | - **[Version control]**
72 | - **[GitHub flow]**
73 | - **[Pull request]**
74 | - **[Descriptive commits]**
75 | - **[Add Books]**
76 | - **[Remove Books]**
77 | - **[Data Persistence]**
78 | - **[Interactive User Basic Interface]**
79 | - **[JavaScript Functionality]**
80 | - **[Code Maintenance]**
81 |
82 | (back to top )
83 |
84 |
85 |
86 |
87 |
88 | ## 💻 Getting Started
89 |
90 | ### Setup
91 |
92 | Clone this repository to your local machine:
93 |
94 | git clone git@github.com:ClaudiaRojasSoto/book_list.git
95 |
96 | ### Prerequisites
97 |
98 | In order to use this project, you need to have Node.js and npm installed on your local machine.
99 |
100 | ### Install
101 |
102 | Install the necessary dependencies by running:
103 |
104 | npm install
105 |
106 |
113 |
114 | ### Usage
115 |
116 | To start the project, run the following command:
117 |
118 | npm start
119 |
120 |
126 |
127 | ### Run tests
128 |
129 | To run tests, run the following command:
130 |
131 | npm test
132 |
133 |
139 |
140 | ### Deployment
141 |
142 | You can deploy this project using: https://claudiarojassoto.github.io/book_list/
143 |
144 |
149 |
150 | (back to top )
151 |
152 |
153 |
154 | ## 👥 Authors
155 |
156 | 👤 **Claudia Rojas**
157 |
158 | - GitHub: [@ClaudiaRojasSoto](https://github.com/ClaudiaRojasSoto)
159 | - LinkedIn: [LinkedIn](https://www.linkedin.com/in/claudia-soto-260504208/)
160 |
161 | (back to top )
162 |
163 |
164 |
165 | ## 🔭 Future Features
166 |
167 | -**[Classes in JavaScript]**
168 |
169 | (back to top )
170 |
171 |
172 |
173 | ## 🤝 Contributing
174 |
175 | Feel free to check the [issues page](https://github.com/ClaudiaRojasSoto/book_list).
176 |
177 | (back to top )
178 |
179 |
180 |
181 | ## ⭐️ Show your support
182 |
183 | If you like this project, please give it a ⭐️!
184 |
185 | (back to top )
186 |
187 |
188 |
189 | ## 🙏 Acknowledgments
190 |
191 | I would like to thank...
192 |
193 | * Microverse for providing the opportunity to learn Git and GitHub in a collaborative environment.
194 | * GitHub Docs for providing a wealth of information on Git and GitHub.
195 |
196 | (back to top )
197 |
198 |
199 |
200 | (back to top )
201 |
202 |
203 |
204 | ## 📝 License
205 |
206 | This project is [MIT](https://spdx.org/licenses/MIT.html) licensed.
207 |
208 | (back to top )
209 | Footer
210 | © 2023 GitHub, Inc.
211 | Footer navigation
212 | Terms
213 | Privacy
214 | Security
215 | Status
216 | Docs
217 | Contact GitHub
218 | Pricing
219 | API
220 | Training
221 | Blog
222 | About
223 |
--------------------------------------------------------------------------------