diff --git a/layouts/partials/projects.html b/layouts/partials/projects.html index b397713..74f5644 100644 --- a/layouts/partials/projects.html +++ b/layouts/partials/projects.html @@ -2,16 +2,31 @@

{{ T "projects" }}

{{ range .Site.Data.tags }} -
+
+ {{ .title }} + {{ end }}
-
+ +
+ +

No projects found

+
+ + + +
\ No newline at end of file diff --git a/static/main.js b/static/main.js index 034edb3..90ad4b6 100644 --- a/static/main.js +++ b/static/main.js @@ -110,6 +110,28 @@ function calculateAge(selector){ obj.textContent = age; } +// tag filtering +document.querySelectorAll(".tag-checkbox").forEach(element => { + element.addEventListener("change", function(){ + showSelectedProjects(element.value, element.checked); + }); +}); + +function showSelectedProjects(category, show = true){ + if(category){ + document.querySelectorAll(`.${category}`).forEach(project => { + project.classList.toggle("hidden", !show); + }); + } + else{ + console.error("func showSelectedProjects(): Missing category name."); + } +} + +function isCategoryEnabled(category){ + return document.querySelector(`#tag-${category}`).checked; +} + // load projects from api // content api: https://api.michivonah.ch/?limit=8&page=1 async function loadContent(endpoint = "https://api.michivonah.ch", limit = 6, page = 1){ @@ -151,18 +173,24 @@ async function getProjectCard(data){ year: "numeric" }); + const link = document.createElement("a"); + link.href = url; + link.title = title; + link.alt = title; + const container = document.createElement("div"); container.classList = "project-card fade-up"; container.classList.add(category); + if(!isCategoryEnabled(category)) container.classList.add("hidden"); //container.style.animation = "fade-up var(--baseDuration) linear"; //container.style.backgroundImage = `url(${image})`; const cardFirst = document.createElement("div"); cardFirst.classList = "card-first"; - const emptyText = document.createElement("p"); - cardFirst.appendChild(emptyText); const cardImage = document.createElement("img"); cardImage.src = image; + cardImage.alt = title; + cardImage.title = title; cardFirst.appendChild(cardImage); const cardSecond = document.createElement("div"); @@ -177,8 +205,9 @@ async function getProjectCard(data){ cardSecond.appendChild(cardTitle); cardSecond.appendChild(cardDate); - container.appendChild(cardFirst); - container.appendChild(cardSecond); + link.appendChild(cardFirst); + link.appendChild(cardSecond); + container.appendChild(link); return container; } @@ -186,18 +215,20 @@ async function getProjectCard(data){ async function loadMoreContent(wrapperSelector, amount, endpoint = "https://api.michivonah.ch", btnSelector = ".project-load-btn"){ const wrapper = document.querySelector(wrapperSelector); const page = ((wrapper.childElementCount <= 0) ? 1 : (wrapper.childElementCount / amount) + 1); + const loader = document.querySelector('.project-loader-wrapper'); // just for debugging purposes //console.log(`children: ${wrapper.childElementCount} limit: ${amount} page: ${page}`); // error validation -> only load more content when page num is valid if (page % 1 == 0){ + loader.classList.remove('hidden'); await showProjects('.project-list', await loadContent(endpoint, amount, page)); + loader.classList.add('hidden'); } else{ // hide button if no more content is available - //if (event.target.tagName == "BUTTON") event.target.style.display = "none"; - document.querySelector(btnSelector).style.opacity = 0; + document.querySelector(btnSelector).classList.add('hidden'); } } \ No newline at end of file diff --git a/static/style.css b/static/style.css index 52aab92..0ab32c8 100644 --- a/static/style.css +++ b/static/style.css @@ -385,6 +385,7 @@ nav.small .nav-links a:last-child:focus{ border-radius: var(--baseRadius); transition: var(--baseTransition); border: 2px solid var(--primary); + cursor: pointer; } .tag input{ @@ -424,6 +425,10 @@ nav.small .nav-links a:last-child:focus{ opacity: 1; } +.project-load-btn.hidden{ + opacity: 0; +} + .project-load-btn:hover{ padding: 10px 40px; background: var(--secondary); @@ -431,6 +436,27 @@ nav.small .nav-links a:last-child:focus{ cursor: pointer; } +.no-projects{ + font-size: 1.8rem; + font-weight: 600; + display: none; +} + +.no-projects i{ + font-size: 3rem; +} + +/* show no projects message, when no project exists that isn't hidden and loader is hidden */ +.project-list:not(:has(.project-card:not(.hidden))) + .no-projects:not(:has(+ .project-loader-wrapper:not(.hidden))){ + display: block; +} + +/* hide load more btn when no projects are shown */ +.project-list:not(:has(.project-card:not(.hidden))) ~ .project-load .project-load-btn{ + display: none; +} + + /* Card animation: https://uiverse.io/suleymanlaarabidev/perfect-husky-88 */ .project-card{ width: 30%; @@ -456,6 +482,16 @@ nav.small .nav-links a:last-child:focus{ --fontWeightP: 600; } +.project-card a{ + color: inherit; + text-decoration: none; + font-style: inherit; +} + +.project-card.hidden{ + display: none; +} + .card-first img{ position: absolute; top: 50%; @@ -571,6 +607,88 @@ nav.small .nav-links a:last-child:focus{ } } +/* PROJECTS LOADER */ +/* credits: https://uiverse.io/AbanoubMagdy1/evil-bullfrog-30 */ +.project-loader-wrapper{ + width: 100%; + height: calc(var(--size) * 2); + margin: 0 0 var(--size) 0; + display: flex; + justify-content: center; + align-content: center; + align-items: center; + + --size: 2.5rem; + --factor: 2.5; + --duration: 2s; +} + +.project-loader-wrapper.hidden{ + display: none; +} + +.project-loader{ + width: var(--size); + height: var(--size); + position: relative; + animation: circleLoader var(--duration) linear infinite; +} + +.project-loader-circle{ + width: calc(var(--size) / var(--factor)); + height: calc(var(--size) / var(--factor)); + background: var(--primary); + border-radius: 50%; + position: absolute; +} + +.project-loader-circle:nth-child(1){ + top: 0; + left: 0; +} + +.project-loader-circle:nth-child(2){ + top: 0; + right: 0; +} + +.project-loader-circle:nth-child(3){ + bottom: 0; + left: 0; +} + +.project-loader-circle:nth-child(4){ + bottom: 0; + right: 0; +} + +@keyframes circleLoader{ + 0%{ + scale: 1; + rotate: 0deg; + } + + 20%, 25%{ + scale: 1.3; + rotate: 90deg; + } + + 45%, 50%{ + scale: 1; + rotate: 180deg; + } + + 70%, 75%{ + scale: 1.3; + rotate: 270deg; + } + + 95%, 100%{ + scale: 1; + rotate: 360deg; + } +} + /* CONTACT */ .contact{ display: flex;