├── .gitignore ├── LICENSE ├── README.md ├── index.html ├── package.json └── src ├── css ├── avatar │ ├── avatar.css │ ├── avatar.css.map │ └── avatar.scss ├── create-post │ ├── createPost.css │ ├── createPost.css.map │ └── createPost.scss ├── fonts │ └── fonts.css ├── layout │ └── main-layout.css ├── main.css ├── modal │ └── loginModal.css ├── post │ ├── post.css │ ├── post.css.map │ └── post.scss └── reset │ └── normalize.css ├── data └── db.json ├── img ├── 150.gif ├── 1564534_customer_man_user_account_profile_icon.png ├── 25.gif ├── Project IMG.png ├── icon │ ├── comment-icon.png │ ├── create-comment-icon.png │ ├── delete-icon.png │ └── edit-icon.png └── pokemon-background.jpg └── js ├── api-communication.js ├── login.js ├── main.js ├── poke-api-communication.js └── post.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Assembler School Of Software Engineering 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `#html` `#css` `#js` `#dom` `#JSON` `#HTTP` `#API` `#Bootstrap` `#master-in-software-development` 2 | 3 | # Blog with API 4 | 5 | > In this pill we have learned how to create a blog with an API serving the necessary data to create it. 6 | > We have used: 7 | * HTML: skeleton of the project 8 | * CSS: styles of our page 9 | * Bootstrap and SASS: as css framework 10 | * JS Vanilla: project logic 11 | * PokeAPI and JSON Server: get data and send data to create our own API. 12 | 13 | 14 | ## Project Img 15 | ![This is a alt text.](./src/img/Project%20IMG.png "This is our project img.") 16 | 17 | 18 | ## Repository 19 | 20 | To get our project, you can clone it and do npm install to get the dependencies 21 | 22 | 23 | ## Team Members 24 | 25 | [Roger Olive Delgado](https://github.com/RogerOliveDelgado). 26 | [Julio Macias Caldera](https://github.com/juliomc23). 27 | 28 | 29 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 12 | 13 | 14 | Blog with API 15 | 16 | 17 |
18 |
19 |

PokemonBook

20 | 28 | 31 |
32 |
33 | create-post__avatar 34 | 35 | 36 |
37 | 38 | 57 | 58 | 76 | 77 | 90 |
91 |
92 |
93 |
94 | 95 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blog-with-api", 3 | "version": "1.0.0", 4 | "description": "`#html` `#css` `#js` `#dom` `#JSON` `#HTTP` `#API` `#Bootstrap` `#master-in-software-development`", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "server": "json-server --watch ./src/data/db.json" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/RogerOliveDelgado/blog-with-api.git" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/RogerOliveDelgado/blog-with-api/issues" 18 | }, 19 | "homepage": "https://github.com/RogerOliveDelgado/blog-with-api#readme", 20 | "keywords": [], 21 | "dependencies": { 22 | "json-server": "^0.17.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/css/avatar/avatar.css: -------------------------------------------------------------------------------- 1 | .avatar { 2 | display: -webkit-box; 3 | display: -ms-flexbox; 4 | display: flex; 5 | -webkit-box-orient: horizontal; 6 | -webkit-box-direction: normal; 7 | -ms-flex-direction: row; 8 | flex-direction: row; 9 | } 10 | 11 | .avatar__image { 12 | width: 4rem; 13 | height: 4rem; 14 | margin-left: 0.5rem; 15 | padding: 0.3rem; 16 | background-color: black; 17 | border: 1px solid black; 18 | border-radius: 50%; 19 | } 20 | 21 | .avatar__user { 22 | margin-left: 0.5rem; 23 | } 24 | /*# sourceMappingURL=avatar.css.map */ -------------------------------------------------------------------------------- /src/css/avatar/avatar.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AAAA,AAAA,OAAO,CAAA;EACH,OAAO,EAAE,IAAI;EACb,cAAc,EAAE,GAAG;CAgBtB;;AAdI,AAAD,cAAQ,CAAA;EACJ,KAAK,EAAC,IAAI;EACV,MAAM,EAAE,IAAI;EACZ,WAAW,EAAE,MAAM;EACnB,OAAO,EAAE,MAAM;EACf,gBAAgB,EAAE,KAAK;EACvB,MAAM,EAAE,eAAe;EACvB,aAAa,EAAE,GAAG;CACrB;;AAEA,AAAD,aAAO,CAAA;EACH,WAAW,EAAE,MAAM;CACtB", 4 | "sources": [ 5 | "avatar.scss" 6 | ], 7 | "names": [], 8 | "file": "avatar.css" 9 | } -------------------------------------------------------------------------------- /src/css/avatar/avatar.scss: -------------------------------------------------------------------------------- 1 | .avatar{ 2 | display: flex; 3 | flex-direction: row; 4 | 5 | &__image{ 6 | width:4rem; 7 | height: 4rem; 8 | margin-left: 0.5rem; 9 | padding: 0.3rem; 10 | background-color: black; 11 | border: 1px solid black; 12 | border-radius: 50%; 13 | } 14 | 15 | &__user{ 16 | margin-left: 0.5rem; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/css/create-post/createPost.css: -------------------------------------------------------------------------------- 1 | .create-post { 2 | display: -webkit-box; 3 | display: -ms-flexbox; 4 | display: flex; 5 | position: relative; 6 | width: 100%; 7 | border-top: 1px solid #ccc; 8 | border-bottom: 1px solid #ccc; 9 | margin-bottom: 0.5rem; 10 | } 11 | 12 | .create-post__avatar { 13 | width: 4rem; 14 | height: 4rem; 15 | margin-top: 1rem; 16 | margin-left: 1rem; 17 | border: 1px solid black; 18 | border-radius: 50%; 19 | background-color: #f56161; 20 | } 21 | 22 | .create-post__text { 23 | width: 100%; 24 | margin-left: 1rem; 25 | padding-top: 2.0rem; 26 | font-size: 1.5rem; 27 | border: 1px solid #688a95; 28 | border-radius: 0.5rem; 29 | outline: none; 30 | resize: none; 31 | } 32 | 33 | .btn__createPost { 34 | -ms-flex-item-align: end; 35 | align-self: flex-end; 36 | width: -webkit-fit-content; 37 | width: -moz-fit-content; 38 | width: fit-content; 39 | height: -webkit-fit-content; 40 | height: -moz-fit-content; 41 | height: fit-content; 42 | margin-right: 0.5rem; 43 | margin-bottom: 0.5rem; 44 | background-color: #57a0a1; 45 | color: black; 46 | font-weight: bold; 47 | border-color: #ccc; 48 | -webkit-transition: all 300ms; 49 | transition: all 300ms; 50 | } 51 | 52 | .btn__createPost:hover { 53 | background-color: transparent; 54 | color: black; 55 | -webkit-transform: scale(1.1); 56 | transform: scale(1.1); 57 | border-color: #919191; 58 | } 59 | /*# sourceMappingURL=createPost.css.map */ -------------------------------------------------------------------------------- /src/css/create-post/createPost.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AAAA,AAAA,YAAY,CAAA;EACR,OAAO,EAAE,IAAI;EACb,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,cAAc;EAC1B,aAAa,EAAE,cAAc;EAC7B,aAAa,EAAE,MAAM;CAuBxB;;AArBI,AAAD,oBAAS,CAAA;EACL,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,IAAI;EAChB,WAAW,EAAE,IAAI;EACjB,MAAM,EAAE,eAAe;EACvB,aAAa,EAAE,GAAG;EAClB,gBAAgB,EAAE,OAAgB;CACrC;;AAEA,AAAD,kBAAO,CAAC;EACJ,KAAK,EAAE,IAAI;EACX,WAAW,EAAE,IAAI;EACjB,WAAW,EAAE,MAAM;EACnB,SAAS,EAAE,MAAM;EACjB,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,OAAkB;EACpC,aAAa,EAAE,MAAM;EACrB,OAAO,EAAE,IAAI;EACb,MAAM,EAAE,IAAI;CACf;;AAIL,AAAA,gBAAgB,CAAA;EACZ,UAAU,EAAE,QAAQ;EACpB,KAAK,EAAE,WAAW;EAClB,MAAM,EAAE,WAAW;EACnB,YAAY,EAAE,MAAM;EACpB,aAAa,EAAE,MAAM;EACrB,gBAAgB,EAAE,OAAiB;EACnC,KAAK,EAAE,KAAK;EACZ,WAAW,EAAE,IAAI;EACjB,YAAY,EAAE,IAAI;EAClB,UAAU,EAAE,SAAS;CACxB;;AAED,AAAA,gBAAgB,AAAA,MAAM,CAAA;EAClB,gBAAgB,EAAE,WAAW;EAC7B,KAAK,EAAE,KAAK;EACZ,SAAS,EAAE,UAAU;EACrB,YAAY,EAAE,OAAkB;CACnC", 4 | "sources": [ 5 | "createPost.scss" 6 | ], 7 | "names": [], 8 | "file": "createPost.css" 9 | } -------------------------------------------------------------------------------- /src/css/create-post/createPost.scss: -------------------------------------------------------------------------------- 1 | .create-post{ 2 | display: flex; 3 | position: relative; 4 | width: 100%; 5 | border-top: 1px solid #ccc; 6 | border-bottom: 1px solid #ccc; 7 | margin-bottom: 0.5rem; 8 | 9 | &__avatar{ 10 | width: 4rem; 11 | height: 4rem; 12 | margin-top: 1rem; 13 | margin-left: 1rem; 14 | border: 1px solid black; 15 | border-radius: 50%; 16 | background-color: rgb(245, 97, 97); 17 | } 18 | 19 | &__text { 20 | width: 100%; 21 | margin-left: 1rem; 22 | padding-top: 2.0rem; 23 | font-size: 1.5rem; 24 | border: 1px solid rgb(104, 138, 149); 25 | border-radius: 0.5rem; 26 | outline: none; 27 | resize: none; 28 | } 29 | 30 | } 31 | 32 | .btn__createPost{ 33 | align-self: flex-end; 34 | width: fit-content; 35 | height: fit-content; 36 | margin-right: 0.5rem; 37 | margin-bottom: 0.5rem; 38 | background-color: rgb(87, 160, 161); 39 | color: black; 40 | font-weight: bold; 41 | border-color: #ccc; 42 | transition: all 300ms; 43 | } 44 | 45 | .btn__createPost:hover{ 46 | background-color: transparent; 47 | color: black; 48 | transform: scale(1.1); 49 | border-color: rgb(145, 145, 145); 50 | } -------------------------------------------------------------------------------- /src/css/fonts/fonts.css: -------------------------------------------------------------------------------- 1 | /*FONTS*/ 2 | 3 | @import url('https://fonts.googleapis.com/css2?family=Rubik:wght@300&display=swap'); 4 | 5 | .main__container{ 6 | font-family: 'Rubik', sans-serif; 7 | } 8 | -------------------------------------------------------------------------------- /src/css/layout/main-layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | align-items: center; 6 | background: url(../../img/pokemon-background.jpg) center repeat; 7 | } 8 | 9 | .main__posts{ 10 | display: flex; 11 | flex-direction: column; 12 | } 13 | 14 | .main__container{ 15 | display: flex; 16 | flex-direction: column; 17 | width: 50%; 18 | min-width: 30rem; 19 | border-left: 1px solid #ccc; 20 | border-right: 1px solid #ccc; 21 | background: rgb(179, 219, 248); 22 | } 23 | 24 | .main__header{ 25 | display: flex; 26 | justify-content: space-between; 27 | align-items: center; 28 | width: 100%; 29 | margin-bottom: 2rem; 30 | } 31 | 32 | .header__title{ 33 | margin-left: 2rem; 34 | } 35 | .img__userProfile{ 36 | width: 2rem; 37 | height: 2rem; 38 | margin-right: 2rem; 39 | cursor: pointer; 40 | } 41 | 42 | .posts__article { 43 | display: flex; 44 | flex-direction: column; 45 | border-bottom: 1px solid #ccc; 46 | margin-bottom: 0.5rem; 47 | padding: 0.5rem; 48 | } 49 | 50 | .post__title, .article__span--username{ 51 | text-transform: uppercase; 52 | font-weight: bold; 53 | } 54 | 55 | .post__body, .article__span--comment{ 56 | margin-left: 0.3rem; 57 | margin-bottom: 5rem; 58 | } 59 | 60 | .article__button--showComments{ 61 | background: url('../../img/icon/comment-icon.png') center no-repeat; 62 | width: 3rem; 63 | height: 3rem; 64 | /* position: absolute; */ 65 | /* top: 75%; */ 66 | /* left: 1%; */ 67 | border: none; 68 | } 69 | 70 | .article__button--createComments{ 71 | background: url('../../img/icon/create-comment-icon.png') center no-repeat; 72 | width: 3rem; 73 | height: 3rem; 74 | position: absolute; 75 | top: 75%; 76 | left: 9%; 77 | border: none; 78 | } 79 | 80 | .article__button--editButton{ 81 | background: url('../../img/icon/edit-icon.png') center no-repeat; 82 | width: 3rem; 83 | height: 3rem; 84 | position: absolute; 85 | top: 75%; 86 | left: 17%; 87 | border: none; 88 | } 89 | 90 | .article__button--deleteButton{ 91 | background: url('../../img/icon/delete-icon.png') center no-repeat; 92 | width: 3rem; 93 | height: 3rem; 94 | position: absolute; 95 | top: 75%; 96 | left: 25%; 97 | border: none; 98 | } 99 | 100 | .comments__article{ 101 | display: flex; 102 | flex-direction: column; 103 | border: 1px solid rgb(10, 10, 10); 104 | padding: 0.3rem; 105 | } 106 | 107 | .comment__avatar{ 108 | width: 3rem; 109 | height: 3rem; 110 | border: 1px solid black; 111 | border-radius: 50%; 112 | padding: 0.25rem; 113 | background: lightcyan; 114 | } -------------------------------------------------------------------------------- /src/css/main.css: -------------------------------------------------------------------------------- 1 | /*RESET*/ 2 | @import url(./reset/normalize.css); 3 | 4 | /*FONTS*/ 5 | @import url(./fonts/fonts.css); 6 | 7 | /*MODAL*/ 8 | @import url(./modal/loginModal.css); 9 | 10 | /*MAIN LAYOUT*/ 11 | @import url(./layout/main-layout.css); 12 | 13 | /*CREATE POST*/ 14 | @import url(./create-post/createPost.css); 15 | 16 | /*AVATAR*/ 17 | @import url(./avatar/avatar.css); 18 | 19 | /*POST*/ 20 | @import url(./post/post.css) 21 | -------------------------------------------------------------------------------- /src/css/modal/loginModal.css: -------------------------------------------------------------------------------- 1 | .btn__openModal{ 2 | background-color: transparent; 3 | border: none; 4 | margin-right: 2rem; 5 | } 6 | 7 | .modal-body{ 8 | display: flex; 9 | flex-direction: column; 10 | } 11 | 12 | .register__form{ 13 | height: 5rem; 14 | display: flex; 15 | flex-direction: column; 16 | justify-content: space-around; 17 | } 18 | 19 | .hide{ 20 | display: none; 21 | } 22 | 23 | .wrong{ 24 | border: 1px solid red; 25 | } -------------------------------------------------------------------------------- /src/css/post/post.css: -------------------------------------------------------------------------------- 1 | .post__header { 2 | display: -webkit-box; 3 | display: -ms-flexbox; 4 | display: flex; 5 | -webkit-box-orient: horizontal; 6 | -webkit-box-direction: normal; 7 | -ms-flex-direction: row; 8 | flex-direction: row; 9 | -webkit-box-pack: justify; 10 | -ms-flex-pack: justify; 11 | justify-content: space-between; 12 | } 13 | 14 | .post__text { 15 | width: 90%; 16 | padding-left: 0.5rem; 17 | margin-top: 1rem; 18 | margin-left: 5%; 19 | border: 1px solid black; 20 | border-radius: 0.25rem; 21 | } 22 | 23 | .post__comments-status { 24 | display: -webkit-box; 25 | display: -ms-flexbox; 26 | display: flex; 27 | -webkit-box-orient: horizontal; 28 | -webkit-box-direction: normal; 29 | -ms-flex-direction: row; 30 | flex-direction: row; 31 | -webkit-box-pack: center; 32 | -ms-flex-pack: center; 33 | justify-content: center; 34 | -webkit-box-align: center; 35 | -ms-flex-align: center; 36 | align-items: center; 37 | } 38 | 39 | .post__comments-btn { 40 | background: url("../../img/icon/edit-icon.png") center no-repeat; 41 | position: absolute; 42 | width: 3rem; 43 | height: 3rem; 44 | border: none; 45 | } 46 | 47 | .post__comments-counter { 48 | padding-top: 0.8rem; 49 | } 50 | 51 | .post__modify-cont { 52 | display: -webkit-box; 53 | display: -ms-flexbox; 54 | display: flex; 55 | -webkit-box-orient: horizontal; 56 | -webkit-box-direction: normal; 57 | -ms-flex-direction: row; 58 | flex-direction: row; 59 | } 60 | 61 | .post__delete-btn { 62 | background: url("../../img/icon/delete-icon.png") center no-repeat; 63 | width: 3rem; 64 | height: 3rem; 65 | border: none; 66 | } 67 | 68 | .post__edit-btn { 69 | background: url("../../img/icon/edit-icon.png") center no-repeat; 70 | width: 3rem; 71 | height: 3rem; 72 | border: none; 73 | } 74 | /*# sourceMappingURL=post.css.map */ -------------------------------------------------------------------------------- /src/css/post/post.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AACK,AAAD,aAAS,CAAA;EACL,OAAO,EAAE,IAAI;EACb,cAAc,EAAE,GAAG;EACnB,eAAe,EAAE,aAAa;CACjC;;AAEA,AAAD,WAAO,CAAA;EACH,KAAK,EAAE,GAAG;EACV,YAAY,EAAE,MAAM;EACpB,UAAU,EAAE,IAAI;EAChB,WAAW,EAAE,EAAE;EACf,MAAM,EAAE,eAAe;EACvB,aAAa,EAAE,OAAO;CACzB;;AAGI,AAAD,sBAAQ,CAAA;EACJ,OAAO,EAAE,IAAI;EACb,cAAc,EAAE,GAAG;EACnB,eAAe,EAAE,MAAM;EACvB,WAAW,EAAE,MAAM;CACtB;;AACA,AAAD,mBAAK,CAAA;EACD,UAAU,EAAE,mCAAmC,CAAC,MAAM,CAAC,SAAS;EAChE,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,IAAI;CACf;;AACA,AAAD,uBAAS,CAAA;EACL,WAAW,EAAE,MAAM;CACtB;;AAGJ,AAAD,kBAAc,CAAA;EACV,OAAO,EAAC,IAAI;EACZ,cAAc,EAAE,GAAG;CACtB;;AAEA,AAAD,iBAAa,CAAA;EACT,UAAU,EAAE,qCAAqC,CAAC,MAAM,CAAC,SAAS;EAClE,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,IAAI;CACf;;AAEA,AAAD,eAAW,CAAA;EACP,UAAU,EAAE,mCAAmC,CAAC,MAAM,CAAC,SAAS;EAChE,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,IAAI;CACf", 4 | "sources": [ 5 | "post.scss" 6 | ], 7 | "names": [], 8 | "file": "post.css" 9 | } -------------------------------------------------------------------------------- /src/css/post/post.scss: -------------------------------------------------------------------------------- 1 | .post{ 2 | &__header{ 3 | display: flex; 4 | flex-direction: row; 5 | justify-content: space-between; 6 | } 7 | 8 | &__text{ 9 | width: 90%; 10 | padding-left: 0.5rem; 11 | margin-top: 1rem; 12 | margin-left: 5%; 13 | border: 1px solid black; 14 | border-radius: 0.25rem; 15 | } 16 | 17 | &__comments{ 18 | &-status{ 19 | display: flex; 20 | flex-direction: row; 21 | justify-content: center; 22 | align-items: center; 23 | } 24 | &-btn{ 25 | background: url('../../img/icon/edit-icon.png') center no-repeat; 26 | position: absolute; 27 | width: 3rem; 28 | height: 3rem; 29 | border: none; 30 | } 31 | &-counter{ 32 | padding-top: 0.8rem; 33 | } 34 | } 35 | 36 | &__modify-cont{ 37 | display:flex; 38 | flex-direction: row; 39 | } 40 | 41 | &__delete-btn{ 42 | background: url('../../img/icon/delete-icon.png') center no-repeat; 43 | width: 3rem; 44 | height: 3rem; 45 | border: none; 46 | } 47 | 48 | &__edit-btn{ 49 | background: url('../../img/icon/edit-icon.png') center no-repeat; 50 | width: 3rem; 51 | height: 3rem; 52 | border: none; 53 | } 54 | } -------------------------------------------------------------------------------- /src/css/reset/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Render the `main` element consistently in IE. 29 | */ 30 | 31 | main { 32 | display: block; 33 | } 34 | 35 | /** 36 | * Correct the font size and margin on `h1` elements within `section` and 37 | * `article` contexts in Chrome, Firefox, and Safari. 38 | */ 39 | 40 | h1 { 41 | font-size: 2em; 42 | margin: 0.67em 0; 43 | } 44 | 45 | /* Grouping content 46 | ========================================================================== */ 47 | 48 | /** 49 | * 1. Add the correct box sizing in Firefox. 50 | * 2. Show the overflow in Edge and IE. 51 | */ 52 | 53 | hr { 54 | box-sizing: content-box; /* 1 */ 55 | height: 0; /* 1 */ 56 | overflow: visible; /* 2 */ 57 | } 58 | 59 | /** 60 | * 1. Correct the inheritance and scaling of font size in all browsers. 61 | * 2. Correct the odd `em` font sizing in all browsers. 62 | */ 63 | 64 | pre { 65 | font-family: monospace, monospace; /* 1 */ 66 | font-size: 1em; /* 2 */ 67 | } 68 | 69 | /* Text-level semantics 70 | ========================================================================== */ 71 | 72 | /** 73 | * Remove the gray background on active links in IE 10. 74 | */ 75 | 76 | a { 77 | background-color: transparent; 78 | } 79 | 80 | /** 81 | * 1. Remove the bottom border in Chrome 57- 82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 83 | */ 84 | 85 | abbr[title] { 86 | border-bottom: none; /* 1 */ 87 | text-decoration: underline; /* 2 */ 88 | text-decoration: underline dotted; /* 2 */ 89 | } 90 | 91 | /** 92 | * Add the correct font weight in Chrome, Edge, and Safari. 93 | */ 94 | 95 | b, 96 | strong { 97 | font-weight: bolder; 98 | } 99 | 100 | /** 101 | * 1. Correct the inheritance and scaling of font size in all browsers. 102 | * 2. Correct the odd `em` font sizing in all browsers. 103 | */ 104 | 105 | code, 106 | kbd, 107 | samp { 108 | font-family: monospace, monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /** 113 | * Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /** 121 | * Prevent `sub` and `sup` elements from affecting the line height in 122 | * all browsers. 123 | */ 124 | 125 | sub, 126 | sup { 127 | font-size: 75%; 128 | line-height: 0; 129 | position: relative; 130 | vertical-align: baseline; 131 | } 132 | 133 | sub { 134 | bottom: -0.25em; 135 | } 136 | 137 | sup { 138 | top: -0.5em; 139 | } 140 | 141 | /* Embedded content 142 | ========================================================================== */ 143 | 144 | /** 145 | * Remove the border on images inside links in IE 10. 146 | */ 147 | 148 | img { 149 | border-style: none; 150 | } 151 | 152 | /* Forms 153 | ========================================================================== */ 154 | 155 | /** 156 | * 1. Change the font styles in all browsers. 157 | * 2. Remove the margin in Firefox and Safari. 158 | */ 159 | 160 | button, 161 | input, 162 | optgroup, 163 | select, 164 | textarea { 165 | font-family: inherit; /* 1 */ 166 | font-size: 100%; /* 1 */ 167 | line-height: 1.15; /* 1 */ 168 | margin: 0; /* 2 */ 169 | } 170 | 171 | /** 172 | * Show the overflow in IE. 173 | * 1. Show the overflow in Edge. 174 | */ 175 | 176 | button, 177 | input { /* 1 */ 178 | overflow: visible; 179 | } 180 | 181 | /** 182 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 183 | * 1. Remove the inheritance of text transform in Firefox. 184 | */ 185 | 186 | button, 187 | select { /* 1 */ 188 | text-transform: none; 189 | } 190 | 191 | /** 192 | * Correct the inability to style clickable types in iOS and Safari. 193 | */ 194 | 195 | button, 196 | [type="button"], 197 | [type="reset"], 198 | [type="submit"] { 199 | -webkit-appearance: button; 200 | } 201 | 202 | /** 203 | * Remove the inner border and padding in Firefox. 204 | */ 205 | 206 | button::-moz-focus-inner, 207 | [type="button"]::-moz-focus-inner, 208 | [type="reset"]::-moz-focus-inner, 209 | [type="submit"]::-moz-focus-inner { 210 | border-style: none; 211 | padding: 0; 212 | } 213 | 214 | /** 215 | * Restore the focus styles unset by the previous rule. 216 | */ 217 | 218 | button:-moz-focusring, 219 | [type="button"]:-moz-focusring, 220 | [type="reset"]:-moz-focusring, 221 | [type="submit"]:-moz-focusring { 222 | outline: 1px dotted ButtonText; 223 | } 224 | 225 | /** 226 | * Correct the padding in Firefox. 227 | */ 228 | 229 | fieldset { 230 | padding: 0.35em 0.75em 0.625em; 231 | } 232 | 233 | /** 234 | * 1. Correct the text wrapping in Edge and IE. 235 | * 2. Correct the color inheritance from `fieldset` elements in IE. 236 | * 3. Remove the padding so developers are not caught out when they zero out 237 | * `fieldset` elements in all browsers. 238 | */ 239 | 240 | legend { 241 | box-sizing: border-box; /* 1 */ 242 | color: inherit; /* 2 */ 243 | display: table; /* 1 */ 244 | max-width: 100%; /* 1 */ 245 | padding: 0; /* 3 */ 246 | white-space: normal; /* 1 */ 247 | } 248 | 249 | /** 250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 251 | */ 252 | 253 | progress { 254 | vertical-align: baseline; 255 | } 256 | 257 | /** 258 | * Remove the default vertical scrollbar in IE 10+. 259 | */ 260 | 261 | textarea { 262 | resize: none; 263 | overflow: auto; 264 | } 265 | 266 | /** 267 | * 1. Add the correct box sizing in IE 10. 268 | * 2. Remove the padding in IE 10. 269 | */ 270 | 271 | [type="checkbox"], 272 | [type="radio"] { 273 | box-sizing: border-box; /* 1 */ 274 | padding: 0; /* 2 */ 275 | } 276 | 277 | /** 278 | * Correct the cursor style of increment and decrement buttons in Chrome. 279 | */ 280 | 281 | [type="number"]::-webkit-inner-spin-button, 282 | [type="number"]::-webkit-outer-spin-button { 283 | height: auto; 284 | } 285 | 286 | /** 287 | * 1. Correct the odd appearance in Chrome and Safari. 288 | * 2. Correct the outline style in Safari. 289 | */ 290 | 291 | [type="search"] { 292 | -webkit-appearance: textfield; /* 1 */ 293 | outline-offset: -2px; /* 2 */ 294 | } 295 | 296 | /** 297 | * Remove the inner padding in Chrome and Safari on macOS. 298 | */ 299 | 300 | [type="search"]::-webkit-search-decoration { 301 | -webkit-appearance: none; 302 | } 303 | 304 | /** 305 | * 1. Correct the inability to style clickable types in iOS and Safari. 306 | * 2. Change font properties to `inherit` in Safari. 307 | */ 308 | 309 | ::-webkit-file-upload-button { 310 | -webkit-appearance: button; /* 1 */ 311 | font: inherit; /* 2 */ 312 | } 313 | 314 | /* Interactive 315 | ========================================================================== */ 316 | 317 | /* 318 | * Add the correct display in Edge, IE 10+, and Firefox. 319 | */ 320 | 321 | details { 322 | display: block; 323 | } 324 | 325 | /* 326 | * Add the correct display in all browsers. 327 | */ 328 | 329 | summary { 330 | display: list-item; 331 | } 332 | 333 | /* Misc 334 | ========================================================================== */ 335 | 336 | /** 337 | * Add the correct display in IE 10+. 338 | */ 339 | 340 | template { 341 | display: none; 342 | } 343 | 344 | /** 345 | * Add the correct display in IE 10. 346 | */ 347 | 348 | [hidden] { 349 | display: none; 350 | } 351 | -------------------------------------------------------------------------------- /src/data/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "posts": [ 3 | { 4 | "userId": "6", 5 | "id": 1, 6 | "username": "charizard", 7 | "body": "Soy un poquito chulillo", 8 | "commentsQty": 3 9 | }, 10 | { 11 | "userId": "3", 12 | "id": 2, 13 | "username": "venusaur", 14 | "body": "Ataque rayo solar!", 15 | "commentsQty": 2 16 | }, 17 | { 18 | "userId": "25", 19 | "id": 3, 20 | "username": "pikachu", 21 | "body": "Bon dia nois!\n\nComencem PHP!", 22 | "commentsQty": 4 23 | }, 24 | { 25 | "userId": "15", 26 | "id": 5, 27 | "username": "beedrill", 28 | "body": "Abejita", 29 | "commentsQty": 1 30 | }, 31 | { 32 | "userId": "144", 33 | "id": 6, 34 | "username": "articuno", 35 | "body": "Buenos días, \n\nQue frío hace!", 36 | "commentsQty": 0 37 | }, 38 | { 39 | "userId": "151", 40 | "id": 7, 41 | "username": "mew", 42 | "body": "Mew Mew Mew", 43 | "commentsQty": 0 44 | }, 45 | { 46 | "userId": "150", 47 | "id": 8, 48 | "username": "mewtwo", 49 | "body": "He venido a colonizar la tierra!\n\nTodos tranquilitos.\n\n;)", 50 | "commentsQty": 0 51 | }, 52 | { 53 | "userId": "9", 54 | "id": 10, 55 | "username": "blastoise", 56 | "body": "Blastoise!\n\nBlastoise\n\nBlastoise", 57 | "commentsQty": 0 58 | }, 59 | { 60 | "userId": "145", 61 | "id": 11, 62 | "username": "zapdos", 63 | "body": "Assembler School!", 64 | "commentsQty": 0 65 | }, 66 | { 67 | "userId": "145", 68 | "id": 12, 69 | "username": "zapdos", 70 | "body": "Zapdos dos dos", 71 | "commentsQty": 0 72 | }, 73 | { 74 | "userId": "145", 75 | "id": 13, 76 | "username": "zapdos", 77 | "body": "Zapdos dos dos", 78 | "commentsQty": 0 79 | }, 80 | { 81 | "userId": "145", 82 | "id": 14, 83 | "username": "zapdos", 84 | "body": "Zapdos dos dos dos", 85 | "commentsQty": 0 86 | }, 87 | { 88 | "userId": "145", 89 | "id": 15, 90 | "username": "zapdos", 91 | "body": "d asjdfn ajf asdhfbsdnfhudsbfhijsd", 92 | "commentsQty": 0 93 | }, 94 | { 95 | "userId": "145", 96 | "id": 16, 97 | "username": "zapdos", 98 | "body": "wwwwwwwww", 99 | "commentsQty": 0 100 | }, 101 | { 102 | "userId": "145", 103 | "id": 17, 104 | "username": "zapdos", 105 | "body": "dadfjqdnuqwndfq\ndfjneqjdfnq\ndfqjwedfnqjdfnq+\ndfmqd", 106 | "commentsQty": 0 107 | }, 108 | { 109 | "userId": "145", 110 | "id": 18, 111 | "username": "zapdos", 112 | "body": "dadasd", 113 | "commentsQty": 0 114 | }, 115 | { 116 | "userId": "145", 117 | "id": 19, 118 | "username": "zapdos", 119 | "body": "dda dfjnadf\nafjadfkmaf\nadfikadmfoadksifmqawe,f\nweiof\nwefkowek\nfwefko\nwekfo\nwefwe", 120 | "commentsQty": 0 121 | }, 122 | { 123 | "userId": "3", 124 | "id": 20, 125 | "username": "venusaur", 126 | "body": "dad", 127 | "commentsQty": 0 128 | }, 129 | { 130 | "userId": "6", 131 | "id": 21, 132 | "username": "charizard", 133 | "body": "Fire\n\nfire \n\nfire", 134 | "commentsQty": 0 135 | }, 136 | { 137 | "userId": "25", 138 | "id": 22, 139 | "username": "pikachu", 140 | "body": "dadsdadad", 141 | "commentsQty": 0 142 | } 143 | ], 144 | "users": [ 145 | { 146 | "id": 1, 147 | "username": "bulbasaur", 148 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/1.gif" 149 | }, 150 | { 151 | "id": 2, 152 | "username": "ivysaur", 153 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/2.gif" 154 | }, 155 | { 156 | "id": 3, 157 | "username": "venusaur", 158 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/3.gif" 159 | }, 160 | { 161 | "id": 4, 162 | "username": "charmander", 163 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/4.gif" 164 | }, 165 | { 166 | "id": 5, 167 | "username": "charmeleon", 168 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/5.gif" 169 | }, 170 | { 171 | "id": 6, 172 | "username": "charizard", 173 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/6.gif" 174 | }, 175 | { 176 | "id": 7, 177 | "username": "squirtle", 178 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/7.gif" 179 | }, 180 | { 181 | "id": 8, 182 | "username": "wartortle", 183 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/8.gif" 184 | }, 185 | { 186 | "id": 9, 187 | "username": "blastoise", 188 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/9.gif" 189 | }, 190 | { 191 | "id": 10, 192 | "username": "caterpie", 193 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/10.gif" 194 | }, 195 | { 196 | "id": 11, 197 | "username": "metapod", 198 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/11.gif" 199 | }, 200 | { 201 | "id": 12, 202 | "username": "butterfree", 203 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/12.gif" 204 | }, 205 | { 206 | "id": 13, 207 | "username": "weedle", 208 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/13.gif" 209 | }, 210 | { 211 | "id": 14, 212 | "username": "kakuna", 213 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/14.gif" 214 | }, 215 | { 216 | "id": 15, 217 | "username": "beedrill", 218 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/15.gif" 219 | }, 220 | { 221 | "id": 22, 222 | "username": "fearow", 223 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/22.gif" 224 | }, 225 | { 226 | "id": 23, 227 | "username": "ekans", 228 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/23.png" 229 | }, 230 | { 231 | "id": 24, 232 | "username": "arbok", 233 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/24.png" 234 | }, 235 | { 236 | "id": 25, 237 | "username": "pikachu", 238 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/25.gif" 239 | }, 240 | { 241 | "id": 27, 242 | "username": "sandshrew", 243 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/27.png" 244 | }, 245 | { 246 | "id": 28, 247 | "username": "sandslash", 248 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/28.png" 249 | }, 250 | { 251 | "id": 26, 252 | "username": "raichu", 253 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/26.gif" 254 | }, 255 | { 256 | "id": 29, 257 | "username": "nidoran-f", 258 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/29.png" 259 | }, 260 | { 261 | "id": 30, 262 | "username": "nidorina", 263 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/30.png" 264 | }, 265 | { 266 | "id": 31, 267 | "username": "nidoqueen", 268 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/31.png" 269 | }, 270 | { 271 | "id": 144, 272 | "username": "articuno", 273 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/144.gif" 274 | }, 275 | { 276 | "id": 145, 277 | "username": "zapdos", 278 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/145.gif" 279 | }, 280 | { 281 | "id": 146, 282 | "username": "moltres", 283 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/146.gif" 284 | }, 285 | { 286 | "id": 147, 287 | "username": "datrini", 288 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/147.gif" 289 | }, 290 | { 291 | "id": 148, 292 | "username": "dagronair", 293 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/148.gif" 294 | }, 295 | { 296 | "id": 149, 297 | "username": "dragonite", 298 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/149.gif" 299 | }, 300 | { 301 | "id": 150, 302 | "username": "mewtwo", 303 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/150.gif" 304 | }, 305 | { 306 | "id": 151, 307 | "username": "mew", 308 | "imgSrc": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/151.gif" 309 | } 310 | ], 311 | "comments": [ 312 | { 313 | "postId": 1, 314 | "userId": 3, 315 | "id": 1, 316 | "name": "venusaur", 317 | "body": "Tranquilo amigo, que nosotros también estamos aquí!" 318 | }, 319 | { 320 | "postId": 1, 321 | "userId": 9, 322 | "id": 2, 323 | "name": "blastoise", 324 | "body": "Si te quema, yo te tiro un poco de agua" 325 | }, 326 | { 327 | "postId": 1, 328 | "userId": 150, 329 | "id": 3, 330 | "name": "mewtwo", 331 | "body": "Como no paréis, os paro yo" 332 | }, 333 | { 334 | "postId": 2, 335 | "userId": 3, 336 | "id": 4, 337 | "name": "venusaur", 338 | "body": "No me quemes, por favor" 339 | }, 340 | { 341 | "postId": 2, 342 | "userId": 9, 343 | "id": 5, 344 | "name": "blastoise", 345 | "body": "Si te quema, yo te tiro un poco de agua" 346 | }, 347 | { 348 | "postId": 3, 349 | "userId": 150, 350 | "id": 6, 351 | "name": "mewtwo", 352 | "body": "Como no paréis, os paro yo" 353 | }, 354 | { 355 | "postId": 3, 356 | "userId": 3, 357 | "id": 7, 358 | "name": "venusaur", 359 | "body": "No me quemes, por favor" 360 | }, 361 | { 362 | "postId": 3, 363 | "userId": 9, 364 | "id": 8, 365 | "name": "blastoise", 366 | "body": "Si te quema, yo te tiro un poco de agua" 367 | }, 368 | { 369 | "postId": 3, 370 | "userId": 150, 371 | "id": 9, 372 | "name": "mewtwo", 373 | "body": "Como no paréis, os paro yo" 374 | }, 375 | { 376 | "postId": 5, 377 | "userId": 150, 378 | "id": 12, 379 | "name": "mewtwo", 380 | "body": "Como no paréis, os paro yo" 381 | } 382 | ] 383 | } -------------------------------------------------------------------------------- /src/img/150.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomc23/blog-with-api/02fa0d0bd78efbd17e4f80ff038b686ebbb9486f/src/img/150.gif -------------------------------------------------------------------------------- /src/img/1564534_customer_man_user_account_profile_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomc23/blog-with-api/02fa0d0bd78efbd17e4f80ff038b686ebbb9486f/src/img/1564534_customer_man_user_account_profile_icon.png -------------------------------------------------------------------------------- /src/img/25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomc23/blog-with-api/02fa0d0bd78efbd17e4f80ff038b686ebbb9486f/src/img/25.gif -------------------------------------------------------------------------------- /src/img/Project IMG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomc23/blog-with-api/02fa0d0bd78efbd17e4f80ff038b686ebbb9486f/src/img/Project IMG.png -------------------------------------------------------------------------------- /src/img/icon/comment-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomc23/blog-with-api/02fa0d0bd78efbd17e4f80ff038b686ebbb9486f/src/img/icon/comment-icon.png -------------------------------------------------------------------------------- /src/img/icon/create-comment-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomc23/blog-with-api/02fa0d0bd78efbd17e4f80ff038b686ebbb9486f/src/img/icon/create-comment-icon.png -------------------------------------------------------------------------------- /src/img/icon/delete-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomc23/blog-with-api/02fa0d0bd78efbd17e4f80ff038b686ebbb9486f/src/img/icon/delete-icon.png -------------------------------------------------------------------------------- /src/img/icon/edit-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomc23/blog-with-api/02fa0d0bd78efbd17e4f80ff038b686ebbb9486f/src/img/icon/edit-icon.png -------------------------------------------------------------------------------- /src/img/pokemon-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliomc23/blog-with-api/02fa0d0bd78efbd17e4f80ff038b686ebbb9486f/src/img/pokemon-background.jpg -------------------------------------------------------------------------------- /src/js/api-communication.js: -------------------------------------------------------------------------------- 1 | //API url path 2 | const commentsPath = 'http://localhost:3000/comments' 3 | const postsPath = 'http://localhost:3000/posts' 4 | const usersPath = 'http://localhost:3000/users' 5 | 6 | // Comments 7 | async function createComment(body, postId){ 8 | try { 9 | fetch(`${commentsPath}`, { 10 | method: "POST", 11 | headers: {"Content-type": "application/json; charset=UTF-8"}, 12 | body: JSON.stringify({ 13 | userId: parseInt(sessionStorage.getItem("userId")), 14 | id: "", 15 | postId: postId, 16 | name: sessionStorage.getItem("username"), 17 | body: body 18 | }) 19 | }) 20 | } catch (error) { 21 | console.error(error) 22 | } 23 | } 24 | 25 | async function editComment(id, edittedBody){ 26 | try{ 27 | fetch(`${commentsPath}/${id}`, { 28 | method: 'PATCH', 29 | headers: {"Content-type": "application/json; charset= UTF-8"}, 30 | body: JSON.stringify({body: edittedBody}) 31 | }) 32 | } catch(error) { 33 | console.error(error) 34 | } 35 | } 36 | 37 | async function deleteComment(id){ 38 | try{ 39 | fetch(`${commentsPath}/${id}`, { 40 | method: 'DELETE', 41 | headers: {"Content-type": "application/json; charset= UTF-8"}, 42 | }); 43 | 44 | }catch(error){ 45 | console.error(error) 46 | } 47 | } 48 | 49 | //Posts 50 | 51 | async function getPost(id){ 52 | try { 53 | fetch(`${postsPath}/${id}`,{ 54 | method:'GET' 55 | }) 56 | const post = await response.json() 57 | return post 58 | } catch (error) { 59 | console.error(error) 60 | } 61 | } 62 | 63 | async function getPosts(){ 64 | try { 65 | const response = await fetch(`${postsPath}`, { 66 | method: 'GET' 67 | }) 68 | const posts = await response.json() 69 | return posts 70 | } catch (error) { 71 | console.error(error) 72 | } 73 | } 74 | 75 | async function getPostsCommentsQty (postId){ 76 | try{ 77 | const response = await fetch(`${commentsPath}/?postId=${postId}`, { 78 | method: 'GET' 79 | }) 80 | const posts = await response.json() 81 | return posts.length 82 | } catch (error) { 83 | console.error(error) 84 | } 85 | } 86 | 87 | async function createPost(body){ 88 | try { 89 | fetch(`${postsPath}`, { 90 | method: "POST", 91 | headers: {"Content-type": "application/json; charset=UTF-8"}, 92 | body: JSON.stringify({ 93 | userId: sessionStorage.getItem("userId"), 94 | id: "", 95 | username: sessionStorage.getItem("username"), 96 | body: body, 97 | commentsQty: 0 98 | }) 99 | }) 100 | } catch (error) { 101 | console.error(error) 102 | } 103 | } 104 | 105 | async function deletePost(id){ 106 | try{ 107 | fetch(`${postsPath}/${id}`, { 108 | method: 'DELETE', 109 | headers: {"Content-type": "application/json; charset= UTF-8"}, 110 | }); 111 | 112 | }catch(error){ 113 | console.error(error) 114 | } 115 | } 116 | 117 | async function editPost(id, edittedBody){ 118 | try{ 119 | fetch(`${postsPath}/${id}`, { 120 | method: 'PATCH', 121 | headers: {"Content-type": "application/json; charset= UTF-8"}, 122 | body: JSON.stringify({body: edittedBody}) 123 | }) 124 | } catch(error) { 125 | console.error(error) 126 | } 127 | } 128 | 129 | //Users 130 | async function getUser(id){ 131 | try{ 132 | const response = await fetch(`${usersPath}/${id}`, { 133 | method : 'GET' 134 | }) 135 | const user = await response.json() 136 | return user 137 | } catch(error) { 138 | console.error(error) 139 | } 140 | } 141 | 142 | async function getUserName(name){ 143 | try{ 144 | const response = await fetch(`${usersPath}/?username=${name}`, { 145 | method : 'GET' 146 | }) 147 | const user = await response.json() 148 | return user 149 | } catch(error) { 150 | console.error(error) 151 | } 152 | } 153 | 154 | async function getUsers(){ 155 | try{ 156 | const response = await fetch(`${usersPath}`, { 157 | method : 'GET' 158 | }) 159 | const users = await response.json() 160 | return users 161 | } catch(error) { 162 | console.error(error) 163 | } 164 | } 165 | 166 | async function postUser(userId, userName, pokemonImg){ 167 | try { 168 | await fetch(`${usersPath}`, { 169 | method: 'POST', 170 | headers: { 171 | "Content-type": "application/json; charset=UTF-8", 172 | }, 173 | body: JSON.stringify({ 174 | id: userId, 175 | username: `${userName}`, 176 | imgSrc: `${pokemonImg}` 177 | }) 178 | }) 179 | } catch (err) { 180 | console.error(err) 181 | } 182 | } 183 | 184 | export {createComment, editComment, deleteComment} 185 | export {getPost, getPosts, createPost, editPost, deletePost, getPostsCommentsQty} 186 | export {getUser, getUserName, getUsers, postUser} -------------------------------------------------------------------------------- /src/js/login.js: -------------------------------------------------------------------------------- 1 | import {getUserName} from './api-communication.js' 2 | 3 | //Username & Email 4 | async function loginUser(username) { 5 | 6 | const registeredUsers = await getUserName(username) 7 | 8 | if(registeredUsers.length !== 0){ 9 | sessionStorage.setItem('userId', registeredUsers[0].id) 10 | sessionStorage.setItem('username', registeredUsers[0].username) 11 | sessionStorage.setItem('avatarimg', registeredUsers[0].imgSrc) 12 | 13 | location.reload() 14 | } 15 | } 16 | 17 | export default loginUser -------------------------------------------------------------------------------- /src/js/main.js: -------------------------------------------------------------------------------- 1 | /*IMPORTS*/ 2 | import loginUser from "./login.js" 3 | import {createComment, editComment, deleteComment} from './api-communication.js' 4 | import {getPosts, createPost, editPost, deletePost} from './api-communication.js' 5 | import {createPostCard} from './post.js' 6 | 7 | /*VARIABLES*/ 8 | const postsCont = document.getElementById('main__posts') 9 | const loginBtn = document.getElementById('loginButton') 10 | const saveComment = document.getElementById('editModal__save') 11 | const deleteCommentBtn = document.getElementById('deleteModalBtn'); 12 | const createPostButton = document.getElementById('createPostButton'); 13 | 14 | window.onload = async function (){ 15 | if (!sessionStorage.getItem('userId')){ 16 | defaultUser() 17 | } 18 | await displayPosts() 19 | getUserLoginImg() 20 | } 21 | 22 | //Default user 23 | const defaultUser = () => { 24 | sessionStorage.setItem('username', "pikachu") 25 | sessionStorage.setItem('userId', 25) 26 | sessionStorage.setItem('avatarimg', "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png") 27 | } 28 | 29 | //Load userInfo from sessionStorage 30 | const getUserLoginImg = () =>{ 31 | const userDiv = document.getElementById('dropdownMenuLink') 32 | const createPostAvatar = document.getElementById('createPostAvatar') 33 | userDiv.textContent = sessionStorage.getItem('username') 34 | createPostAvatar.src = sessionStorage.getItem('avatarimg') 35 | } 36 | 37 | //Create Post 38 | createPostButton.addEventListener('click', async () => { 39 | const textPost = document.getElementById('create-post__text').value; 40 | const response = await createPost(textPost) 41 | location.reload() 42 | }) 43 | 44 | //Login 45 | loginBtn.addEventListener('click', () => { 46 | const userName = document.getElementById('login__Username'); 47 | loginUser(userName.value) 48 | }) 49 | 50 | //Show/hide post comments 51 | postsCont.addEventListener('click', (e) => { 52 | 53 | if (e.target.hasAttribute('data-hide-comments')){ 54 | const postId = e.target.getAttribute('data-show-comments') 55 | e.target.removeAttribute('data-hide-comments') 56 | const postContainer =document.querySelector(`[data-post-comments="${postId}"]`) 57 | postContainer.remove() 58 | 59 | } else if (e.target.hasAttribute('data-show-comments')){ 60 | 61 | e.target.setAttribute('data-hide-comments', '') 62 | 63 | const postId = e.target.getAttribute('data-show-comments') 64 | const postContainer = document.querySelector(`[data-post-id="${postId}"]`) 65 | const commentsContainer = document.createElement(`div`) 66 | 67 | commentsContainer.setAttribute(`data-post-comments`, postId ) 68 | postContainer.append(commentsContainer) 69 | 70 | displayComments(postId, commentsContainer) 71 | 72 | // e.target.disabled = true 73 | } 74 | }) 75 | 76 | //SaveComment 77 | saveComment.addEventListener('click', async () => { 78 | let newText = document.getElementById('editModal__text').value 79 | const saveAttrb = saveComment.getAttribute('data-edit') 80 | const id = saveComment.getAttribute('data-id') 81 | 82 | if(saveAttrb === 'post'){ 83 | await editPost(id, newText) 84 | } else if (saveAttrb === 'comment'){ 85 | await editComment(id, newText) 86 | } 87 | 88 | location.reload() 89 | newText = '' 90 | }) 91 | 92 | deleteCommentBtn.addEventListener('click', async ()=> { 93 | const deleteAttrb = deleteCommentBtn.getAttribute('data-delete') 94 | const id = deleteCommentBtn.getAttribute('data-id') 95 | if(deleteAttrb === 'post'){ 96 | await deletePost(id) 97 | } else if (deleteAttrb === 'comment'){ 98 | await deleteComment(id) 99 | } 100 | location.reload() 101 | }) 102 | 103 | async function displayPosts() { 104 | const postList = await getPosts() 105 | postList.map(post => { 106 | postsCont.append(createPostCard(post)) 107 | }) 108 | } 109 | 110 | const displayComments = async (postId, postContainer) => { 111 | fetch('http://localhost:3000/comments', { 112 | method: 'GET' 113 | }) 114 | .then(response => response.json()) 115 | .then(data => data.map(commentsData => { 116 | 117 | if (parseInt(postId) === commentsData.postId) { 118 | const comment = document.createElement('article') 119 | comment.setAttribute('class', 'comments__article') 120 | const name = document.createElement('span') 121 | const body = document.createElement('span'); 122 | const avatarImage = document.createElement('img') 123 | avatarImage.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/${commentsData.userId}.gif` 124 | avatarImage.classList.add('comment__avatar') 125 | 126 | const deleteButton = document.createElement('button'); 127 | deleteButton.textContent = "DELETE"; 128 | deleteButton.setAttribute('data-delete-comment', commentsData.id) 129 | 130 | const editButton = document.createElement('button'); 131 | editButton.textContent = "EDIT"; 132 | editButton.setAttribute('data-edit-comment', commentsData.id) 133 | editButton.setAttribute('data-bs-toggle', "modal") 134 | editButton.setAttribute('data-bs-target', "#editModal") 135 | 136 | editButton.addEventListener('click', () => { 137 | const saveComment = document.getElementById('editModal__save') 138 | saveComment.setAttribute("data-edit", "comment"); 139 | saveComment.setAttribute('data-id', commentsData.id); 140 | }) 141 | 142 | deleteButton.addEventListener('click', ()=>{ 143 | const deleteComment = document.getElementById('deleteModalBtn') 144 | deleteComment.setAttribute('data-delete', "comment"); 145 | deleteComment.setAttribute('data-id', commentsData.id); 146 | }) 147 | 148 | comment.setAttribute('data-comment-id', commentsData.id) 149 | comment.setAttribute('data-post-id', commentsData.postId) 150 | 151 | name.classList.add('article__span--username'); 152 | body.classList.add('article__span--comment'); 153 | name.textContent = `@${commentsData.name}` 154 | body.textContent = commentsData.body 155 | 156 | comment.append(avatarImage, name, body) 157 | 158 | if (commentsData.userId === parseInt(sessionStorage.getItem("userId"))) { 159 | comment.append(editButton, deleteButton) 160 | } 161 | 162 | postContainer.append(comment) 163 | } 164 | 165 | })) 166 | .catch(err => console.warn(err)) 167 | } -------------------------------------------------------------------------------- /src/js/poke-api-communication.js: -------------------------------------------------------------------------------- 1 | import {postUser} from './api-communication.js' 2 | const url = `https://pokeapi.co/api/v2/pokemon` 3 | 4 | async function getPokemon(){ 5 | 6 | try { 7 | for (let id = 16; id<=31; id++){ 8 | const response = await fetch(`${url}/${id}`) 9 | const data = await response.json() 10 | postUser(id, data.name, data.sprites.front_default) 11 | } 12 | } catch(error) { 13 | console.error(error) 14 | } 15 | 16 | } 17 | 18 | export default getPokemon -------------------------------------------------------------------------------- /src/js/post.js: -------------------------------------------------------------------------------- 1 | const avatarCard = params => { 2 | const avatar = document.createElement('div') 3 | const avatarImage = document.createElement('img') 4 | const avatarName = document.createElement('p') 5 | 6 | avatar.classList.add('avatar') 7 | avatarImage.classList.add('avatar__image') 8 | avatarName.classList.add('avatar__user') 9 | 10 | avatarImage.src = `${params.src}` 11 | avatarImage.alt = `${params.alt}` 12 | avatarName.textContent = `@${params.name}` 13 | 14 | avatar.append(avatarImage, avatarName) 15 | 16 | return avatar 17 | } 18 | 19 | const postStatusCard = (postId, commentQty) => { 20 | const comments = document.createElement('div') 21 | const commentsCounter = document.createElement('p') 22 | const commentsBtn = document.createElement('button') 23 | const createCommentBtn = document.createElement('p') 24 | 25 | createCommentBtn.setAttribute('data-create-comment', postId) 26 | createCommentBtn.classList.add('post__comment-create') 27 | 28 | //this next lines are going to be refactored 29 | createCommentBtn.addEventListener('click', ()=>{ 30 | const idPost = createCommentButton.getAttribute('data-create-comment'); 31 | const textPost = document.getElementById('create-post__text').value; 32 | createComment(textPost, parseInt(idPost)) 33 | location.reload(); 34 | }) 35 | commentsCounter.textContent = commentQty 36 | 37 | comments.classList.add('post__comments-status') 38 | commentsCounter.classList.add('post__comments-counter') 39 | commentsBtn.classList.add('article__button--showComments') 40 | commentsBtn.setAttribute('data-show-comments', postId) 41 | 42 | comments.append(commentsBtn, commentsCounter, createCommentBtn) 43 | 44 | return comments 45 | } 46 | 47 | const modifyCard = postId => { 48 | const modifyCont = document.createElement('div') 49 | const editBtn = document.createElement('button') 50 | const deleteBtn = document.createElement('button') 51 | 52 | modifyCont.classList.add('post__modify-cont') 53 | editBtn.classList.add('post__edit-btn') 54 | editBtn.setAttribute('data-bs-toggle', "modal") 55 | editBtn.setAttribute('data-bs-target', "#editModal") 56 | deleteBtn.classList.add('post__delete-btn') 57 | deleteBtn.setAttribute('data-bs-toggle', "modal") 58 | deleteBtn.setAttribute('data-bs-target', "#deleteModal") 59 | 60 | editBtn.addEventListener('click', () => { 61 | const saveComment = document.getElementById('editModal__save') 62 | saveComment.setAttribute('data-edit', "post"); 63 | saveComment.setAttribute('data-id', postId); 64 | }) 65 | deleteBtn.addEventListener('click', ()=>{ 66 | const deleteComment = document.getElementById('deleteModalBtn') 67 | deleteComment.setAttribute('data-delete', "post"); 68 | deleteComment.setAttribute('data-id', postId); 69 | }) 70 | 71 | modifyCont.append(editBtn, deleteBtn) 72 | 73 | return modifyCont 74 | } 75 | 76 | //params is post information {userId, id, username, body} 77 | function createPostCard (params){ 78 | const content = document.createElement('article') 79 | const header = document.createElement('div') 80 | const text = document.createElement('p') 81 | const imgSrc = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/${params.userId}.gif` 82 | const avatar = avatarCard({src: imgSrc, alt: params.username, name: params.username}) 83 | const postDescription = postStatusCard(params.id, params.commentsQty) 84 | const modify = modifyCard(params.id) 85 | const activeUserId = sessionStorage.getItem('userId') 86 | 87 | text.innerText = params.body 88 | 89 | content.setAttribute('data-post-id', params.id) 90 | content.setAttribute('data-user-id', params.userId) 91 | content.classList.add('posts__article') 92 | 93 | text.classList.add('post__text') 94 | header.classList.add('post__header') 95 | 96 | if (params.userId === activeUserId){ 97 | header.append(avatar, modify) 98 | } else { 99 | header.append(avatar) 100 | } 101 | 102 | content.append(header,text,postDescription) 103 | 104 | return content 105 | } 106 | 107 | export {createPostCard} 108 | 109 | --------------------------------------------------------------------------------