diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..600d2d33 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode \ No newline at end of file diff --git a/assets/css/BASE/reset.css b/assets/css/BASE/reset.css new file mode 100644 index 00000000..9b4076e0 --- /dev/null +++ b/assets/css/BASE/reset.css @@ -0,0 +1,68 @@ +/** + * BASE - RESET + */ + +*, +*::before, +*::after { + padding: 0; + margin: 0; + border: 0; +} + +* { + box-sizing: border-box; + /* Make sure all elements are above the background */ + z-index: 1; + position: relative; +} + +/* default */ + +html { + font-size: 62.5%; + scroll-behavior: smooth; + color: var(--foreground); + transition: color var(--transition); + background-color: #ffffff; + background-blend-mode: multiply; +} + +html::before { + content: ""; + position: fixed; + height: 100%; + width: 100%; + background: var(--white); + transform: translateX(-100%); + transition: transform var(--transition); + z-index: 0; +} + +body { + font-family: 'Roboto Mono', monospace !important; + box-sizing: border-box; + mix-blend-mode: difference; +} + +ul { + list-style: none; + padding-left: 0; +} + +/* button{ + cursor: none !important; +} */ + +code{ + display: block; + padding-bottom: 0.6rem; +} + +/* headings */ + +h1, h2, h3, h4, h5, h6 { + margin-top: 0; + margin-bottom: 1rem; + letter-spacing: normal; +} diff --git a/assets/css/LAYOUT/common.css b/assets/css/LAYOUT/common.css new file mode 100644 index 00000000..1c15a9e1 --- /dev/null +++ b/assets/css/LAYOUT/common.css @@ -0,0 +1,56 @@ +/** + * LAYOUT - COMMON + */ + +.main { + background-color: #ffffff; + margin: 0 auto; + max-width: 992px; + padding: 2rem 0; +} + +.section { + margin: 2rem; + background: #F8F9FA; +} + +.header { + z-index: 2; + padding: 2rem 4rem; +} + +.footer{ + padding: 2rem 2rem 0; +} + +.full-page{ + height: calc(100vh - 4rem); + max-height: calc(100vh - 4rem); +} + +.outside { + width: 100%; + padding-top: 133.33%; /* 4:3 Aspect Ratio (divide 4 by 3 = 1.3333) */ + position: relative; /* If you want text inside of it */ +} + +/* If you want text inside of the container */ +.inside { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; +} + +.bg-black { + background-color: #121212; +} + +.bi { + font-size: 3rem; +} + +.big { + font-size: 6rem; +} diff --git a/assets/css/MODULE/blockquote.css b/assets/css/MODULE/blockquote.css new file mode 100644 index 00000000..7ae3c30c --- /dev/null +++ b/assets/css/MODULE/blockquote.css @@ -0,0 +1,28 @@ +/** + * MODULE - BLOCKQUOTE + */ + +.blockquote { + margin-left: 1.5rem; +} + +.blockquote__body{ + font-size: 1.2rem; +} + +.blockquote__header{ + color: var(--darkGrey); +} + +.blockquote__name{ + font-weight: 600; + margin-bottom: 0.5rem; +} + +.blockquote__dot{ + margin: 0 0.5rem; +} + +.blockquote__company-name{ + font-weight: 300; +} \ No newline at end of file diff --git a/assets/css/MODULE/comments.css b/assets/css/MODULE/comments.css new file mode 100644 index 00000000..6a49c9c2 --- /dev/null +++ b/assets/css/MODULE/comments.css @@ -0,0 +1,37 @@ +/** + * MODULE - COMMENTS + */ + +.comments{ + padding: 3rem 0 6rem; +} + +.comments__total{ + border-top: 1px solid var(--grey); + border-bottom: 1px solid var(--grey); + padding: 2rem 0; + margin-bottom: 1rem; +} + +.comments__item { + padding-top: 2rem; +} + +.comments__buttons{ + margin-left: 1rem; +} + +.comments__buttons button{ + background-color: transparent; +} + +.comments__buttons button i { + color: var(--darkGrey); + height: 20px; + width: 20px; + font-size: 1.8rem; +} + +.comments__buttons button:hover i { + color: var(--black); +} diff --git a/assets/css/MODULE/header.css b/assets/css/MODULE/header.css new file mode 100644 index 00000000..e2661e0a --- /dev/null +++ b/assets/css/MODULE/header.css @@ -0,0 +1,16 @@ +/** + * MODULE - HEADER + */ + +.header{ + z-index: 2; + padding: 2rem 4rem; + mix-blend-mode: difference; + color: #ffffff; + max-width: 992px; +} + +.header__title{ + font-size: 2.4rem; + margin-bottom: 0; +} \ No newline at end of file diff --git a/assets/css/MODULE/modal.css b/assets/css/MODULE/modal.css new file mode 100644 index 00000000..d6e78e6d --- /dev/null +++ b/assets/css/MODULE/modal.css @@ -0,0 +1,20 @@ +/** + * MODULE - MODAL + */ + +.modal-header { + border-bottom: 0; +} + +.modal-header .btn-close { + transform: scale(1.5); + z-index: 1100; +} + +@media (min-width: 576px) { + .modal-dialog { + width: calc(100% - 3rem); + max-width: 992px; + margin: 1.75rem auto; + } +} \ No newline at end of file diff --git a/assets/css/MODULE/post-block.css b/assets/css/MODULE/post-block.css new file mode 100644 index 00000000..ccec9184 --- /dev/null +++ b/assets/css/MODULE/post-block.css @@ -0,0 +1,41 @@ +/** + * MODULE - POST BLOCK + */ + +.posts-block{ + padding: 4rem; +} + +.post-block{ + margin-bottom: 3.5rem; +} + +.post-block__content{ + background-image: url(/assets/images/svg/anim-false.svg); + background-repeat: repeat-x; + background-size: auto 0.3rem; + background-position-y: bottom; + padding-bottom: 0.8rem; +} + +.post-block__name { + font-size: 1.2rem; + margin-bottom: 0.5rem; +} + +.post-block__title{ + cursor: pointer; + font-weight: 600; + font-size: 2.2rem; + margin-bottom: 1rem; +} + +@media only screen and (max-width: 575px) { + .posts-block{ + padding: 3rem 2rem; + margin-bottom: 3rem; + } + .post-block__title{ + font-size: 2rem; + } +} \ No newline at end of file diff --git a/assets/css/MODULE/post-card.css b/assets/css/MODULE/post-card.css new file mode 100644 index 00000000..a6426e0f --- /dev/null +++ b/assets/css/MODULE/post-card.css @@ -0,0 +1,112 @@ +/** + * MODULE - POST CARD + */ + +.posts { + margin-left: -0.75rem; + margin-right: -0.75rem; + background-color: #ffffff; +} + +.posts__swipe-label{ + text-align: center; + width: 100%; +} + +.post-card-cont { + height: 100%; + width: 100%; +} +.post-card:nth-child(1), +.post-card:nth-child(2), +.post-card:nth-child(3) { + padding-bottom: 0.75rem; +} +.post-card:nth-child(4), +.post-card:nth-child(5), +.post-card:nth-child(6) { + padding-top: 0.75rem; +} +.post-card.reset { + transition: transform 0.3s; + transform: translateX(0) !important; +} +.post-card.inactive { + transition: transform 0.3s; +} +.post-card.to-left { + transform: translateX(-30rem) rotate(-30deg) !important; +} +.post-card.to-right { + transform: translate(30rem) rotate(30deg) !important; +} +.post-card.below { + z-index: 1; +} +.post-card__top { + height: 100%; + padding: 2rem; +} +.post-card__name { + line-height: 1.25; + text-align: center; + font-size: 2rem; + font-weight: 600; + color: #fff; + padding: 1rem; + margin: 0; +} +.post-card__author { + color: #fff; + text-align: center; + font-size: 1.4rem; + padding: 1rem; + margin: 0; +} +.post-card__content { + cursor: pointer; +} + +@media only screen and (max-width: 767px) { + .posts{ + padding: 4rem 1rem; + background-color: transparent; + } + .post-card-cont { + position: relative; + width: 24rem; + min-width: 24rem; + height: 32rem; + min-height: 32rem; + margin: 0 auto; + } + .post-card { + z-index: 2; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + transform-origin: 50% 100%; + padding: 0; + } + .post-card:nth-child(n) { + padding: 0; + } + .post-card__drag { + position: block; + z-index: 5; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + cursor: grab; + } +} + +@media only screen and (max-width: 575px) { + .posts__swipe-label{ + display: none; + } +} \ No newline at end of file diff --git a/assets/css/MODULE/post-inline.css b/assets/css/MODULE/post-inline.css new file mode 100644 index 00000000..7e85ef8e --- /dev/null +++ b/assets/css/MODULE/post-inline.css @@ -0,0 +1,39 @@ +/** + * MODULE - POST INLINE + */ + +.posts-inline{ + padding: 4rem; +} + +.posts-inline__content{ + background-image: url(/assets/images/svg/anim-false.svg); + background-repeat: repeat-x; + background-size: auto 0.3rem; + background-position: 0 1.8rem; + padding-bottom: 0.8rem; +} + +.post-inline__content{ + padding-bottom: 0.5rem; +} + +.post-inline__name { + font-size: 1.2rem; +} + +.post-inline__title{ + cursor: pointer; + font-weight: 600; + font-size: 2.2rem; + line-height: 5rem; +} + +@media only screen and (max-width: 575px) { + .posts-inline{ + padding: 3rem 2rem; + } + .post-inline__title{ + font-size: 2rem; + } +} \ No newline at end of file diff --git a/assets/css/MODULE/post-main.css b/assets/css/MODULE/post-main.css new file mode 100644 index 00000000..7d97fa25 --- /dev/null +++ b/assets/css/MODULE/post-main.css @@ -0,0 +1,54 @@ +/** + * MODULE - POST MAIN + */ + +.post-main { + height: 100%; + display: flex; + flex-direction: column; +} + +.post-main__author{ + font-size: 1.6rem; + padding-top: 3rem; + margin-bottom: 3rem; +} + +.post-main__title{ + padding: 3rem; + margin-bottom: 0; + font-size: 4.6rem; +} + +.post-main__line { + background-image: url(/assets/images/svg/anim-true.svg); + background-size: 100% auto; + margin: 0 auto; + width: 4px; + -webkit-box-flex: 100; + -webkit-flex: 100; + flex: 100; + height: 150px; +} + +.post-main button{ + font-size: 1.4rem; + padding: 0.4rem 1.2rem; + margin-top: 3rem; + margin-bottom: 3rem; +} + +@media only screen and (max-width: 767px) { + .post-main__title{ + font-size: 3.6rem; + } +} + +@media only screen and (max-width: 575px) { + .post-main__author{ + font-size: 1.5rem; + } + .post-main__title{ + font-size: 3.2rem; + } +} \ No newline at end of file diff --git a/assets/css/MODULE/post-modal.css b/assets/css/MODULE/post-modal.css new file mode 100644 index 00000000..4fb9bf93 --- /dev/null +++ b/assets/css/MODULE/post-modal.css @@ -0,0 +1,48 @@ +/** + * MODULE - POST + */ + +.post .btn-close{ + position: absolute; + top: 1.5rem; + right: 1.5rem; + transform: scale(1.5); + z-index: 1100; +} + +.post__content { + overflow-y: auto; + overflow-x: hidden; + min-height: 100%; + max-height: 100vh; +} + +.post__title { + font-size: 3.6rem; +} + +.post__text { + font-size: 2.2rem; +} + +.post__avatar{ + padding-bottom: 0.5rem; +} + +.post__company-catch-phrase{ + font-weight: 1rem; + border-top: 1px solid var(--grey); + margin-top: 2rem; + padding-top: 2rem; + padding-bottom: 2rem; +} + +@media only screen and (max-width: 575px) { + .post__title { + font-size: 3.2rem; + } + + .post__text { + font-size: 2rem; + } +} \ No newline at end of file diff --git a/assets/css/MODULE/toggle.css b/assets/css/MODULE/toggle.css new file mode 100644 index 00000000..e949048c --- /dev/null +++ b/assets/css/MODULE/toggle.css @@ -0,0 +1,57 @@ +/** + * MODULE - TOGGLE + */ + +.toggle__wrapper { + width: 5rem; + display: block; +} + +.toggle { + height: 2.6rem; + width: 5rem; + background: var(--foreground); + border-radius: 13px; + padding: 4px; + position: relative; + transition: background var(--transition); + cursor: pointer; +} + +.toggle::before { + content: ""; + display: block; + height: 1.8rem; + width: 1.8rem; + border-radius: 9px; + background: var(--background); + position: absolute; + z-index: 2; + transform: translate(0); + transition: transform var(--transition), background var(--transition); +} + +.toggle.enabled::before { + transform: translateX(24px); +} + +.toggle .toggle__input { + opacity: 0; + position: absolute; + top: 0; +} + +.toggle .toggle_icons { + display: flex; + justify-content: space-between; + align-items: center; + height: 100%; +} + +.toggle .toggle_icons svg { + fill: var(--background); + height: 3rem; + width: 3rem; + z-index: 0; + margin: 0 0.5rem; +} diff --git a/assets/css/STATUS/dark-mode.css b/assets/css/STATUS/dark-mode.css new file mode 100644 index 00000000..94f72eba --- /dev/null +++ b/assets/css/STATUS/dark-mode.css @@ -0,0 +1,7 @@ +/** + * STATUS - DARK + */ + +.dark-mode::before { + transform: translateX(0); +} diff --git a/assets/css/THEME/vars.css b/assets/css/THEME/vars.css new file mode 100644 index 00000000..2dd25377 --- /dev/null +++ b/assets/css/THEME/vars.css @@ -0,0 +1,13 @@ +/** + * THEME - VARS + */ + +:root { + --black: #121212; + --white: #f5f5f5; + --grey: #d8d8d8; + --darkGrey: #424242; + --background: var(--black); + --foreground: var(--white); + --transition: 0.35s ease; +} \ No newline at end of file diff --git a/assets/css/styles.css b/assets/css/styles.css new file mode 100644 index 00000000..a65f6942 --- /dev/null +++ b/assets/css/styles.css @@ -0,0 +1,27 @@ +/** + * STYLES + */ + +/* BASE FOLDER */ +@import "BASE/reset.css"; + +/* LAYOUT FOLDER */ +@import "LAYOUT/common.css"; + +/* MODULE FOLDER */ +@import "MODULE/header.css"; +@import "MODULE/post-card.css"; +@import "MODULE/toggle.css"; +@import "MODULE/post-main.css"; +@import "MODULE/post-modal.css"; +@import "MODULE/post-inline.css"; +@import "MODULE/post-block.css"; +@import "MODULE/blockquote.css"; +@import "MODULE/modal.css"; +@import "MODULE/comments.css"; + +/* STATUS FOLDER */ +@import "STATUS/dark-mode.css"; + +/* THEME FOLDER */ +@import "THEME/vars.css"; diff --git a/data/comments.json b/assets/data/comments.json similarity index 100% rename from data/comments.json rename to assets/data/comments.json diff --git a/data/db.json b/assets/data/db.json similarity index 100% rename from data/db.json rename to assets/data/db.json diff --git a/data/posts.json b/assets/data/posts.json similarity index 100% rename from data/posts.json rename to assets/data/posts.json diff --git a/data/users.json b/assets/data/users.json similarity index 100% rename from data/users.json rename to assets/data/users.json diff --git a/assets/images/svg/anim-false.svg b/assets/images/svg/anim-false.svg new file mode 100644 index 00000000..87106faa --- /dev/null +++ b/assets/images/svg/anim-false.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/assets/images/svg/anim-true.svg b/assets/images/svg/anim-true.svg new file mode 100644 index 00000000..364dd186 --- /dev/null +++ b/assets/images/svg/anim-true.svg @@ -0,0 +1,21 @@ + + + + \ No newline at end of file diff --git a/assets/js/comments.js b/assets/js/comments.js new file mode 100644 index 00000000..e64989cd --- /dev/null +++ b/assets/js/comments.js @@ -0,0 +1,159 @@ +import { userIcon } from '/assets/js/icons.js'; + +/** + * Fill modal´s comments + * + * @param {Number} modalId id of modal + * @param {String} companyName name of user company + */ +async function fillModalComments(modalId, companyName) { + + const comments = await fetch("https://jsonplaceholder.typicode.com/comments") //id del comentario + .then(response => response.json()) + + const icon = await userIcon(companyName); + + const commentArea = document.getElementById("comments-list"); + + commentArea.innerHTML = ""; + + for (let index = comments.length; index > 0; index--) { + + const { postId, id, name, body, } = { ...comments[index] }; + if (postId === modalId) { + + const templateModalComment = ` + + `; + + commentArea.insertAdjacentHTML("beforeend", templateModalComment); + const contentTemplate = document.getElementById(`comment-template-${id}`).content; + const copyContent = document.importNode(contentTemplate, true); + document.getElementById(`comment-template-${id}`).remove(); + commentArea.appendChild(copyContent); + + document.getElementById(`comment-delete-${id}`).addEventListener("click", deleteComment); + document.getElementById(`comment-edit-${id}`).addEventListener("click", editComment); + } + } + + recountComments(); +} + +/** + * Delete comment of post + * + * @param {Object} e event + */ +async function deleteComment(e) { + const id = e.target.parentElement.dataset.id; + const baseUrl = "https://jsonplaceholder.typicode.com"; + + let response = await fetch(`${baseUrl}/comments/${id}`, { method: 'DELETE' }); + + if (response.status === 200) { + console.log("El comentario se ha borrado"); + document.getElementById(`comment-${id}`).remove(); + recountComments(); + } + + return response; +} + +/** + * Edit comment of post + * + * @param {Object} e event + */ +function editComment(e) { + const id = e.target.parentElement.dataset.id; + + let nameContainer = document.getElementById(`blockquote__name-${id}`); + let prevName = nameContainer.innerHTML; + + nameContainer.innerHTML = ` + + ` + let textContainer = document.getElementById(`blockquote__body-${id}`); + let prevText = textContainer.innerHTML; + + textContainer.innerHTML = ` + + + ` + + document.querySelector(`#comment-${id} .comments__buttons`).classList.add('d-none'); + document.querySelector(`#comment-${id} .blockquote__dot`).classList.add('d-none'); + document.querySelector(`#comment-${id} .blockquote__company-name`).classList.add('d-none'); + + document.getElementById(`comments__save-${id}`).addEventListener("click", function () { + saveEditComment(id) + }) +} + +/** + * Saves comment after edit + * + * @param {Number} id id of comment + */ +async function saveEditComment(id) { + const baseUrl = "https://jsonplaceholder.typicode.com"; + let finalName = document.getElementById(`name-text-area-${id}`).value; + document.getElementById(`blockquote__name-${id}`).innerHTML = finalName; + + let finalText = document.getElementById(`body-text-area-${id}`).value; + document.getElementById(`blockquote__body-${id}`).innerHTML = finalText; + + document.querySelector(`#comment-${id} .comments__buttons`).classList.toggle('d-none'); + document.querySelector(`#comment-${id} .blockquote__dot`).classList.toggle('d-none'); + document.querySelector(`#comment-${id} .blockquote__company-name`).classList.toggle('d-none'); + + let response = await fetch(`${baseUrl}/comments/${id}`, { + method: 'PATCH', + body: JSON.stringify({ + name: finalName, + body: finalText, + }), + headers: { + 'Content-type': 'application/json; charset=UTF-8', + }, + }); + + if (response.status === 200) { + console.log("El comentario se ha editado"); + } + + return response; +} + +/** + * Recount and modify total comments + */ +function recountComments() { + const counter = document.getElementById("comments-list").children.length; + document.getElementById("totalComments").innerHTML = `${counter} comments`; +} + +export { + fillModalComments +}; \ No newline at end of file diff --git a/assets/js/darkMode.js b/assets/js/darkMode.js new file mode 100644 index 00000000..f53acdf9 --- /dev/null +++ b/assets/js/darkMode.js @@ -0,0 +1,20 @@ +/** + * Adds eventListener to toggle input + */ +function toggleDarkMode() { + let toggleInput = document.getElementById("toggle__input"); + toggleInput.addEventListener("click", switchStyles); +} + +/** + * Toggle styles when we press the switch button + */ +function switchStyles() { + const html = document.querySelector("html"); + const toggle = document.getElementById("toggle"); + + toggle.classList.toggle("enabled"); + html.classList.toggle("dark-mode"); +} + +export { switchStyles, toggleDarkMode }; \ No newline at end of file diff --git a/assets/js/icons.js b/assets/js/icons.js new file mode 100644 index 00000000..76f047b0 --- /dev/null +++ b/assets/js/icons.js @@ -0,0 +1,53 @@ +/** + * Assings an icon to the user/company name + * + * @param {String} name name of user or company + */ +async function userIcon(name) { + + const users = await fetch("https://jsonplaceholder.typicode.com/users") //id del comentario + .then(response => response.json()) + + const userNamesArray = []; + + for (const user of users) { + const { name, company } = { ...user }; + + userNamesArray.push(name); + userNamesArray.push(company.name); + } + + const iconsArray = [ + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ] + const nameIndex = userNamesArray.indexOf(name); + let userIcon; + + nameIndex <= iconsArray.length - 1 ? userIcon = iconsArray[nameIndex] + : userIcon = iconsArray[nameIndex - iconsArray.length - 1] + + return userIcon; +} + +export { userIcon }; \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 00000000..97b26057 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,17 @@ +"use strict"; + +import { toggleDarkMode } from '/assets/js/darkMode.js'; +import { fillMainPost, fillLinesSection, fillTinderSection, fillInlineSection } from '/assets/js/posts.js'; +import { listeningTinder } from '/assets/js/tinder.js'; + +/** + * Initialize the blog + */ +(function initialize() { + toggleDarkMode(); + fillMainPost(); + fillLinesSection(); + fillTinderSection(); + listeningTinder(); + fillInlineSection(); +})() diff --git a/assets/js/posts.js b/assets/js/posts.js new file mode 100644 index 00000000..8e6a35ce --- /dev/null +++ b/assets/js/posts.js @@ -0,0 +1,301 @@ +import { userIcon } from '/assets/js/icons.js'; +import { fillModalComments } from '/assets/js/comments.js'; + +/** + * Fill main post + * + * @param {String} mainPost begining post + */ +async function fillMainPost(mainPost = 0) { + let cards = await fetchData("posts", mainPost, 1); + + const { userId, id, title } = { ...cards[0] }; + + const users = await fetchData("users", userId - 1, userId); + + const { name } = { ...users[0] }; + + const templateCard = ` + + `; + + const postMain = document.getElementById("post-main"); + postMain.insertAdjacentHTML("beforeend", templateCard); + + const contentTemplate = document.getElementById(`mainTemplate`).content; + const copyContent = document.importNode(contentTemplate, true); + postMain.innerHTML = ""; + postMain.appendChild(copyContent); + + document.getElementById("readBtn").addEventListener("click", function () { + fillModal(id, "main"); + }); +} + +/** + * Fill post of line Section + * + * @param {Number} linePost begining post + * @param {Number} lineLimit number of post to fetch + */ +async function fillLinesSection(linePost = 1, lineLimit = 6) { + let cards = await fetchData("posts", linePost, lineLimit); + + const postsContent = document.getElementById("lines-content"); + + for (const card of cards) { + const { userId, id, title } = { ...card }; + + const users = await fetchData("users", userId - 1, userId); + + const { name } = { ...users[0] }; + + const templateCard = ` + + `; + + postsContent.insertAdjacentHTML("beforeend", templateCard); + const contentTemplate = document.getElementById(`lines-template-${id}`).content; + const copyContent = document.importNode(contentTemplate, true); + + document.getElementById(`lines-template-${id}`).remove(); + postsContent.appendChild(copyContent); + document.getElementById(`post-block-${id}`).addEventListener("click", function () { + fillModal(id, "line"); + + let modal = new bootstrap.Modal(document.getElementById('postModal'), { + keyboard: false + }) + + modal.show(); + }); + } +} + +/** + * Fill post of tinder Section + * + * @param {Number} tinderPost begining post + * @param {Number} tinderLimit number of post to fetch + */ +async function fillTinderSection(tinderPost = 7, tinderLimit = 6) { + + let cards = await fetchData("posts", tinderPost, tinderLimit); + + const tinderContent = document.getElementById("tinder-content"); + + for (const card of cards) { + const { userId, id, title } = { ...card }; + + const users = await fetchData("users", userId - 1, 1); + + const { name } = { ...users[0] }; + + const templateCard = ` + + `; + + tinderContent.insertAdjacentHTML("beforeend", templateCard); + const contentTemplate = document.getElementById(`tinder-template-${id}`).content; + const copyContent = document.importNode(contentTemplate, true); + + document.getElementById(`tinder-template-${id}`).remove(); + tinderContent.appendChild(copyContent); + + document.getElementById(`card-${id}`).addEventListener("click", function () { + let card = document.getElementById(`card-${id}`); + + if (card.classList.contains('inactive')) return; + + fillModal(id, "tinder"); + + let modal = new bootstrap.Modal(document.getElementById('postModal'), { + keyboard: false + }) + + modal.show(); + }); + + } +} + +/** + * Fill post of line Section + * + * @param {Number} inlinePost begining post + * @param {Number} inlineLimit number of post to fetch + */ +async function fillInlineSection(inlinePost = 13, inlineLimit = 10) { + + let cards = await fetchData("posts", inlinePost, inlineLimit); + + const postsContent = document.getElementById("inline-content"); + + for (const card of cards) { + const { userId, id, title } = { ...card }; + + const users = await fetchData("users", userId - 1, userId); + + const { name } = { ...users[0] }; + + const templateCard = ` + + `; + + postsContent.insertAdjacentHTML("beforeend", templateCard); + const contentTemplate = document.getElementById(`lines-template-${id}`).content; + const copyContent = document.importNode(contentTemplate, true); + document.getElementById(`lines-template-${id}`).remove(); + postsContent.appendChild(copyContent); + + document.getElementById(`post-inline-${id}`).addEventListener("click", function () { + fillModal(id, "inline"); + + let modal = new bootstrap.Modal(document.getElementById('postModal'), { + keyboard: false + }) + + modal.show(); + }); + } +} + +/** + * Fill the modal when read more is clicked + * + * @param {Number} modalId id of modal + */ +async function fillModal(modalId) { + + const post = await fetchData("posts", modalId - 1, 1); + + const { userId, id, title, body } = { ...post[0] }; + + const user = await fetchData("users", userId - 1, 1); + + const { name, company, address } = { ...user[0] }; + + const icon = await userIcon(name); + + const modalContentArea = document.getElementById("postModal"); + + modalContentArea.innerHTML = ""; + + const templateModal = ` + + `; + + modalContentArea.insertAdjacentHTML("beforeend", templateModal); + const contentTemplate = document.getElementById(`modal-template-${id}`).content; + + const copyContent = document.importNode(contentTemplate, true); + document.getElementById(`modal-template-${id}`).remove(); + modalContentArea.appendChild(copyContent); + document.querySelector("i").classList.add("big") + fillModalComments(modalId, company.name); +} + +/** + * Fetch data + * + * @param {Number} from + * @param {Number} limit + * @param {String} section + */ +async function fetchData(section = "posts", from = 0, limit = 10) { + const baseUrl = "https://jsonplaceholder.typicode.com"; + + let response = await fetch(`${baseUrl}/${section}?_start=${from}&_limit=${limit}`) + .then((response) => response.json()); + + return response; +} + +export { + fillMainPost, + fillLinesSection, + fillTinderSection, + fillInlineSection +}; \ No newline at end of file diff --git a/assets/js/tinder.js b/assets/js/tinder.js new file mode 100644 index 00000000..11f090fe --- /dev/null +++ b/assets/js/tinder.js @@ -0,0 +1,96 @@ +/** + * Resize and document ready listener + */ +function listeningTinder() { + $(document).ready(function () { + swipeCard(); + }); + $(window).on("resize", function () { + swipeCard(); + }); +} + +/** + * Swipe Card + */ +function swipeCard() { + if ($(window).width() < 768) { + let animating = false; + let cardsCounter = 0; + let numOfCards = 6; + let decisionVal = 80; + let pullDeltaX = 0; + let deg = 0; + let $card; + + function pullChange() { + animating = true; + deg = pullDeltaX / 10; + $card.addClass('moving'); + $card.css( + "transform", + "translateX(" + pullDeltaX + "px) rotate(" + deg + "deg)" + ); + } + + function release() { + if (pullDeltaX >= decisionVal) { + $card.addClass("to-right"); + } else if (pullDeltaX <= -decisionVal) { + $card.addClass("to-left"); + } + + if (Math.abs(pullDeltaX) >= decisionVal) { + $card.addClass("inactive"); + + setTimeout(function () { + $card.addClass("below").removeClass("inactive to-left to-right"); + cardsCounter++; + if (cardsCounter === numOfCards) { + cardsCounter = 0; + $(".post-card").removeClass("below"); + } + }, 300); + } + + if (Math.abs(pullDeltaX) < decisionVal) { + $card.addClass("reset"); + } + + setTimeout(function () { + $card + .attr("style", "") + .removeClass("reset") + .attr("style", ""); + + pullDeltaX = 0; + animating = false; + }, 300); + } + + $(document).on("mousedown touchstart", ".post-card:not(.inactive)", function (e) { + if (animating) return; + + $card = $(this); + let startX = e.pageX || e.originalEvent.touches[0].pageX; + + $(document).on("mousemove touchmove", function (e) { + let x = e.pageX || e.originalEvent.touches[0].pageX; + pullDeltaX = x - startX; + if (!pullDeltaX) return; + pullChange(); + }); + + $(document).on("mouseup touchend", function () { + $card.removeClass('moving'); + $(document).off("mousemove touchmove mouseup touchend"); + if (!pullDeltaX) return; // prevents from rapid click events + release(); + }); + }); + } +} + +export { + listeningTinder +}; \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..90a4e598 --- /dev/null +++ b/index.html @@ -0,0 +1,120 @@ + + + + + + + + + Blog with API + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+

Blog

+ + +
+ +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ Swipe left +
+
+ Swipe right +
+
+ + +
+
+ + +
+
+ + + + +
+ + + + + + + \ No newline at end of file