├── .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 |
25 |
26 |
29 |
30 |
31 | All Awesome books
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Add a new book
41 |
42 |
52 |
53 |
54 |
55 |
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 |
--------------------------------------------------------------------------------