├── .gitignore ├── logo.png ├── index.js ├── modules ├── dateTime.js ├── navigation.js └── library.js ├── .hintrc ├── .eslintrc.json ├── .stylelintrc.json ├── package.json ├── LICENSE.md ├── index.html ├── .github └── workflows │ └── linters.yml ├── README.md └── index.css /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oovillagran/AwesomeBooks-ES6/HEAD/logo.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import navigation from './modules/navigation.js'; 2 | import loadAwesomeBooks from './modules/library.js'; 3 | import setTimeFromLuxor from './modules/dateTime.js'; 4 | 5 | navigation(); 6 | loadAwesomeBooks(); 7 | setTimeFromLuxor(); 8 | -------------------------------------------------------------------------------- /modules/dateTime.js: -------------------------------------------------------------------------------- 1 | import { DateTime } from './luxon.js'; 2 | 3 | const setTimeFromLuxor = () => { 4 | const timeDate = document.querySelector('#date'); 5 | const date = DateTime.now().toLocaleString(DateTime.DATETIME_MED); 6 | timeDate.innerHTML = date; 7 | }; 8 | 9 | export default setTimeFromLuxor; -------------------------------------------------------------------------------- /.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": "awesomebooks-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 | "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.8", 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 | "dependencies": { 24 | "luxon": "^3.3.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Oscar Villagran 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. -------------------------------------------------------------------------------- /modules/navigation.js: -------------------------------------------------------------------------------- 1 | const navigation = () => { 2 | // Get nav bar links 3 | const linkList = document.querySelector('#link-list'); 4 | const linkAdd = document.querySelector('#link-add'); 5 | const linkContact = document.querySelector('#link-contact'); 6 | // Get page sections ID 7 | const bookListSection = document.querySelector('#book-list'); 8 | const addSection = document.querySelector('#add-section'); 9 | const contactSection = document.querySelector('#contact-info'); 10 | 11 | // Listeners for the links events 12 | linkList.addEventListener('click', (event) => { 13 | event.preventDefault(); 14 | bookListSection.style.display = 'flex'; 15 | addSection.style.display = 'none'; 16 | contactSection.style.display = 'none'; 17 | }); 18 | 19 | linkAdd.addEventListener('click', (event) => { 20 | event.preventDefault(); 21 | bookListSection.style.display = 'none'; 22 | addSection.style.display = 'flex'; 23 | contactSection.style.display = 'none'; 24 | }); 25 | 26 | linkContact.addEventListener('click', (event) => { 27 | event.preventDefault(); 28 | bookListSection.style.display = 'none'; 29 | addSection.style.display = 'none'; 30 | contactSection.style.display = 'flex'; 31 | }); 32 | }; 33 | 34 | export default navigation; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Awesome Books 11 | 12 | 13 |
14 | 24 |
25 |
26 |
27 | 28 |
29 | 30 |
31 |

All Awesome books

32 |
33 | 34 |
35 |
36 |
37 | 38 | 39 |
40 |

Add a new book

41 |
42 |
43 | 46 | 49 | 50 |
51 |
52 |
53 | 54 | 55 |
56 |

Contact information

57 |
58 |

Do have any questions or you just want to say "Hello"? You can reach out to us!

59 | 64 |
65 |
66 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /.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: "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@v2 40 | - uses: actions/setup-node@v1 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@v2 54 | - uses: actions/setup-node@v1 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@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 -------------------------------------------------------------------------------- /modules/library.js: -------------------------------------------------------------------------------- 1 | const loadAwesomeBooks = () => { 2 | let stock = []; 3 | 4 | // load books from local stoarage 5 | const loadBooks = () => { 6 | if (localStorage.getItem('stockedBooks')) { 7 | stock = JSON.parse(localStorage.getItem('stockedBooks')); 8 | } 9 | }; 10 | 11 | // function remove books 12 | 13 | const removeBook = (index) => { 14 | // Delete the book from the array 15 | stock.splice(index, 1); 16 | // saved updated array in localStorage 17 | localStorage.setItem('stockedBooks', JSON.stringify(stock)); 18 | window.location.reload(); 19 | }; 20 | 21 | // function display the books 22 | 23 | const displayBooks = () => { 24 | const bookList = document.getElementById('library'); 25 | bookList.innerHTML = ''; 26 | stock.forEach((element, index) => { 27 | // Create a book element 28 | const aBook = document.createElement('div'); 29 | const idBook = document.createElement('span'); 30 | const titleBook = document.createElement('h2'); 31 | const authorBook = document.createElement('p'); 32 | idBook.textContent = `${index}`; 33 | titleBook.textContent = `${element.title}`; 34 | authorBook.textContent = `${element.author}`; 35 | const removeButton = document.createElement('button'); 36 | const line = document.createElement('hr'); 37 | 38 | // Delete the book 39 | removeButton.textContent = 'Remove'; 40 | removeButton.addEventListener('click', () => { 41 | removeBook(index); 42 | aBook.remove(); 43 | }); 44 | 45 | // Create the book view 46 | aBook.appendChild(idBook); 47 | aBook.appendChild(titleBook); 48 | aBook.appendChild(authorBook); 49 | bookList.appendChild(aBook); 50 | aBook.appendChild(removeButton); 51 | aBook.appendChild(line); 52 | }); 53 | }; 54 | 55 | // add a new book 56 | const addBook = (title, author) => { 57 | if (title !== '' && author !== '') { 58 | const newBook = { title, author }; 59 | // Save the book 60 | stock.push(newBook); 61 | // Save on local storage 62 | localStorage.setItem('stockedBooks', JSON.stringify(stock)); 63 | // Reset form values 64 | document.getElementById('add-form').reset(); 65 | displayBooks(); 66 | } else { 67 | const messages = []; 68 | if (title === '' && author === '') { 69 | messages.push('Please enter the book\'s title and author.'); 70 | } else if (author === '' && title !== '') { 71 | messages.push('Please enter the book\'s author.'); 72 | } else if (title === '' && author !== '') { 73 | messages.push('Please enter the book\'s title.'); 74 | } 75 | 76 | if (messages.length > 0) { 77 | const errorElement = document.getElementById('error'); 78 | errorElement.innerText = messages.join(', '); 79 | // Remove the message after 3 seconds 80 | setTimeout(() => { 81 | errorElement.remove(); 82 | }, 3000); 83 | } 84 | } 85 | }; 86 | 87 | // load books from local storage on page load 88 | window.addEventListener('load', () => { 89 | loadBooks(); 90 | displayBooks(); 91 | }); 92 | 93 | const addButton = document.getElementById('add-button'); 94 | addButton.addEventListener('click', (event) => { 95 | event.preventDefault(); 96 | const title = document.querySelector('#title').value; 97 | const author = document.querySelector('#author').value; 98 | addBook(title, author); 99 | }); 100 | }; 101 | 102 | export default loadAwesomeBooks; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |

Awesome Books ES6

7 | 8 |
9 | 10 | 11 | 12 | # 📗 Table of Contents 13 | 14 | - [📖 About the Project](#about-project) 15 | - [🛠 Built With](#built-with) 16 | - [Tech Stack](#tech-stack) 17 | - [Key Features](#key-features) 18 | - [🚀 Live Demo](#live-demo) 19 | - [💻 Getting Started](#getting-started) 20 | - [Setup](#setup) 21 | - [Prerequisites](#prerequisites) 22 | - [Install](#install) 23 | - [Usage](#usage) 24 | - [Run tests](#run-tests) 25 | - [Deployment](#triangular_flag_on_post-deployment) 26 | - [👥 Authors](#authors) 27 | - [🔭 Future Features](#future-features) 28 | - [🤝 Contributing](#contributing) 29 | - [⭐️ Show your support](#support) 30 | - [🙏 Acknowledgements](#acknowledgements) 31 | - [❓ FAQ (OPTIONAL)](#faq) 32 | - [📝 License](#license) 33 | 34 | 35 | 36 | # 📖 Awesome Books 37 | 38 | 39 | **Awesome Books ES6** is a reestructured website from the original [Awesome Books](https://github.com/oovillagran/AwesomeBooks) that allows users to add/remove books from a list. We achieved that by using JavaScript objects and arrays. We also needed to dynamically modify the DOM and added basic events. 40 | 41 | ## 🛠 Built With 42 | 43 | ### Tech Stack 44 | 45 | 46 |
47 | HTML 48 | 51 |
52 | 53 |
54 | CSS 55 | 58 |
59 | 60 |
61 | JavaScript 62 | 65 |
66 | 67 | 68 | 69 | ### Key Features 70 | 71 | 72 | - Creating branches on repositories. 73 | - Use of linter on HTML&CSS&JavaScript project. 74 | - Correct use of GitHub flow. 75 | - Follow Microverse's list of best practices for JavaScript projects. 76 | - Implement a basic UI with plain HTML for a basic webpage. 77 | 78 |

(back to top)

79 | 80 | 81 | 82 | ## 🚀 Live Demo 83 | 84 | 85 | - Here is the [live-demo](https://oovillagran.github.io/AwesomeBooks/) 86 | 87 |

(back to top)

88 | 89 | 90 | 91 | ## 💻 Getting Started 92 | 93 | To get a local copy up and running, follow these steps. 94 | 95 | ### Prerequisites 96 | 97 | In order to run this project you need: 98 | 99 | - Create a repo on your repositores files. 100 | - Clone or make a copy of this repo on your local machine. 101 | - Follow GitHub flow. 102 | - A carefully reading of this README.md is required. 103 | 104 | 105 | ### Setup 106 | 107 | Clone this repository to your desired folder: 108 | 109 | ```bash 110 | cd my-folder 111 | git clone git@github.com:oovillagran/AwesomeBooks.git 112 | ``` 113 | 114 | ### Install 115 | 116 | Install this project with: 117 | 118 | ```bash 119 | npm install 120 | ``` 121 | 122 | ### Usage 123 | 124 | To run the project, you can use your favorite browser. 125 | 126 | 127 | ### Run tests 128 | 129 | To run tests, execute the following command: 130 | 131 | ```bash 132 | npx hint . 133 | ``` 134 | 135 | ### Deployment 136 | 137 | -Follow GitHub pages guideliness. 138 | 139 |

(back to top)

140 | 141 | 142 | 143 | ## 👥 Authors 144 | 145 | 👤 **Oscar Villagran** 146 | 147 | - GitHub: [@oovillagran](https://github.com/oovillagran) 148 | - Twitter: [@oovillagran](https://twitter.com/oovillagran) 149 | - LinkedIn: [Oscar Villagran](https://www.linkedin.com/in/oovillagran/) 150 | 151 | 152 |

(back to top)

153 | 154 | 155 | 156 | ## 🔭 Future Features 157 | 158 | 159 | - [ ] **Use of linter in HTML&CSS projects** 160 | - [ ] **Use README template file** 161 | - [ ] **Ask for a code review**** 162 | 163 |

(back to top)

164 | 165 | 166 | 167 | ## 🤝 Contributing 168 | 169 | Contributions, issues, and feature requests are welcome! 170 | 171 | Feel free to check the [issues page](../../issues/). 172 | 173 |

(back to top)

174 | 175 | 176 | 177 | ## ⭐️ Show your support 178 | 179 | 180 | If you like this project feel free to make any comment, all contributions are welcome!. 181 | 182 |

(back to top)

183 | 184 | 185 | 186 | ## 🙏 Acknowledgments 187 | 188 | We would like to thank Microverse comunity, they do an excellent job. 189 | 190 |

(back to top)

191 | 192 | ## 📝 License 193 | 194 | This project is [MIT](LICENSE.md) licensed. 195 | 196 | _NOTE: we recommend using the [MIT license] 197 | 198 |

(back to top)

199 | -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | /* Global Styles */ 2 | html { 3 | box-sizing: border-box; 4 | line-height: 1.15; 5 | -webkit-text-size-adjust: 100%; 6 | } 7 | 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: inherit; 12 | margin: 0; 13 | padding: 0; 14 | } 15 | 16 | h1, 17 | h3 { 18 | font-family: 'COCOGOOSE', sans-serif; 19 | font-size: 3rem; 20 | font-weight: 100; 21 | line-height: 1; 22 | letter-spacing: -8%; 23 | text-align: center; 24 | } 25 | 26 | #date, 27 | a, 28 | span, 29 | p, 30 | button, 31 | div { 32 | font-family: 'Lato', sans-serif; 33 | } 34 | 35 | h3 { 36 | font-family: 'COCOGOOSE', sans-serif; 37 | } 38 | 39 | p { 40 | font-size: 1rem; 41 | } 42 | 43 | span { 44 | font-size: 0.7rem; 45 | font-weight: 600; 46 | } 47 | 48 | .gray-line { 49 | width: 5rem; 50 | height: 0.2rem; 51 | background-color: gray; 52 | margin: 1rem; 53 | } 54 | 55 | /* Menu styles */ 56 | nav.menu { 57 | display: flex; 58 | flex-direction: row; 59 | flex-wrap: wrap; 60 | justify-content: space-between; 61 | align-content: center; 62 | align-items: center; 63 | width: 100%; 64 | height: 3rem; 65 | background-color: #3e3e3e; 66 | } 67 | 68 | .menu ul { 69 | display: flex; 70 | list-style: none; 71 | align-items: center; 72 | } 73 | 74 | .menu a { 75 | color: white; 76 | text-decoration: none; 77 | padding: 0.8rem; 78 | border-radius: 0.4rem; 79 | } 80 | 81 | nav a:hover, 82 | nav a:focus { 83 | background-color: #333; 84 | color: #fff; 85 | } 86 | 87 | .menu-link { 88 | text-decoration: none; 89 | font-style: normal; 90 | font-weight: 600; 91 | font-size: 15px; 92 | line-height: 20px; 93 | padding: 0 1rem; 94 | transition-property: all; 95 | transition-duration: 0.7s; 96 | } 97 | 98 | .image-container div { 99 | display: flex; 100 | flex-direction: row; 101 | } 102 | 103 | #logo img { 104 | align-items: center; 105 | height: 1rem; 106 | } 107 | 108 | /* Main */ 109 | body { 110 | display: flex; 111 | flex-direction: column; 112 | min-height: 100vh; 113 | } 114 | 115 | main { 116 | display: flex; 117 | flex-direction: column; 118 | padding: 1rem 5rem 5rem 5rem; 119 | align-items: center; 120 | } 121 | 122 | /* Actual time and date */ 123 | #date { 124 | display: flex; 125 | justify-content: flex-end; 126 | align-items: flex-start; 127 | width: 100%; 128 | margin-bottom: 3rem; 129 | } 130 | 131 | /* Book Shelf styles */ 132 | #book-list { 133 | display: flex; 134 | flex-direction: column; 135 | width: 100%; 136 | align-items: center; 137 | } 138 | 139 | #library { 140 | display: flex; 141 | flex-direction: column; 142 | justify-content: center; 143 | align-items: center; 144 | background-color: #d0d9d4; 145 | border-radius: 20px; 146 | width: 80%; 147 | height: min-content; 148 | padding: 1rem; 149 | margin-bottom: 2rem; 150 | gap: 1rem; 151 | } 152 | 153 | #library div { 154 | position: relative; 155 | display: flex; 156 | flex-direction: row; 157 | justify-content: flex-start; 158 | align-items: center; 159 | flex-wrap: wrap; 160 | padding: 1rem; 161 | width: 90%; 162 | height: 3.5rem; 163 | background-color: #ebf0ee; 164 | border-radius: 5px; 165 | } 166 | 167 | #library div span { 168 | position: absolute; 169 | top: 0.6rem; 170 | left: 0.6rem; 171 | margin-bottom: 1rem; 172 | color: dimgrey; 173 | } 174 | 175 | #library div h2 { 176 | text-align: center; 177 | margin: 0 1rem 0 1.5rem; 178 | width: 50%; 179 | max-height: min-content; 180 | } 181 | 182 | footer p { 183 | color: white; 184 | font-size: 1rem; 185 | font-weight: 600; 186 | } 187 | 188 | #library div p { 189 | text-align: center; 190 | padding-left: 1rem; 191 | } 192 | 193 | form button { 194 | display: flex; 195 | flex-wrap: wrap; 196 | align-content: center; 197 | font-weight: bold; 198 | text-align: center; 199 | background-color: #36b37f; 200 | color: #fff; 201 | border: none; 202 | border-radius: 4px; 203 | padding: 0.8rem; 204 | height: 2rem; 205 | } 206 | 207 | #library button { 208 | position: absolute; 209 | top: 50%; 210 | left: 90%; 211 | transform: translate(-50%, -50%); 212 | border: none; 213 | background-color: lightcoral; 214 | padding: 0.5rem; 215 | border-radius: 5px; 216 | color: white; 217 | } 218 | 219 | /* Form styles */ 220 | #add-section { 221 | display: none; 222 | flex-direction: column; 223 | align-items: center; 224 | padding: 1rem; 225 | } 226 | 227 | #add-form { 228 | display: flex; 229 | flex-direction: column; 230 | align-items: center; 231 | gap: 1rem; 232 | padding: 1rem; 233 | } 234 | 235 | #title, 236 | #author { 237 | border: 1px solid #d0d9d4; 238 | border-radius: 4px; 239 | height: 2rem; 240 | } 241 | 242 | #error { 243 | font-weight: 600; 244 | color: #ff6163; 245 | padding-top: 1rem; 246 | align-self: flex-end; 247 | } 248 | 249 | /* Contact Styles */ 250 | #contact-info { 251 | display: none; 252 | flex-direction: column; 253 | align-items: center; 254 | padding: 1rem; 255 | } 256 | 257 | #contact-info p:nth-child(3) { 258 | padding: 1rem; 259 | } 260 | 261 | #contact-info li { 262 | padding: 0.4rem 0; 263 | } 264 | 265 | #contact-info a { 266 | color: #36b; 267 | } 268 | 269 | /* Footer Styles */ 270 | footer { 271 | display: flex; 272 | flex-direction: row; 273 | justify-content: flex-start; 274 | align-items: center; 275 | padding: 1rem 3rem; 276 | background-color: #3e3e3e; 277 | margin-top: auto; 278 | width: 100%; 279 | } 280 | --------------------------------------------------------------------------------