mirror of
https://github.com/michivonah/website-v3.git
synced 2025-12-22 21:36:28 +01:00
implement dynamic project loading from api
This commit is contained in:
parent
b2eeb3b7ae
commit
f5745b9e81
5 changed files with 162 additions and 42 deletions
|
|
@ -10,3 +10,4 @@ gotop = 'Nach oben!'
|
|||
godown = 'Nach unten!'
|
||||
language = 'Sprache'
|
||||
select-language = 'Sprache auswählen'
|
||||
load-more = 'Mehr laden'
|
||||
|
|
@ -10,3 +10,4 @@ gotop = 'Go to top'
|
|||
godown = 'Scroll down!'
|
||||
language = 'Language'
|
||||
select-language = 'Select language'
|
||||
load-more = 'Load more'
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<div id="projects" class="projects">
|
||||
<h1>Projekte</h1>
|
||||
<h1>{{ T "projects" }}</h1>
|
||||
<div class="tag-filter">
|
||||
{{ range .Site.Data.tags }}
|
||||
<div class="tag">
|
||||
|
|
@ -10,37 +10,8 @@
|
|||
</div>
|
||||
|
||||
<div class="project-list">
|
||||
<div class="project-card">
|
||||
<div class="card-first">
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="card-second">
|
||||
<i class="ai-newspaper"></i>
|
||||
<h2>Mein Fazit: 1 Jahr mit dem Europa-Park ResortPass</h2>
|
||||
<p>14.01.2025</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project-card">
|
||||
<div class="card-first">
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="card-second">
|
||||
<i class="ai-newspaper"></i>
|
||||
<h2>Mein Fazit: 1 Jahr mit dem Europa-Park ResortPass</h2>
|
||||
<p>14.01.2025</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project-card">
|
||||
<div class="card-first">
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="card-second">
|
||||
<i class="ai-newspaper"></i>
|
||||
<h2>Mein Fazit: 1 Jahr mit dem Europa-Park ResortPass</h2>
|
||||
<p>14.01.2025</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button class="project-load-btn" alt='{{ T "load-more" }}' title='{{ T "load-more" }}' name='{{ T "load-more" }}'>{{ T "load-more" }}</button>
|
||||
</div>
|
||||
</div>
|
||||
100
static/main.js
100
static/main.js
|
|
@ -1,5 +1,5 @@
|
|||
// Add event listeners
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.addEventListener('DOMContentLoaded', async function(){
|
||||
scrollTopVisibilityUpdate();
|
||||
updateNavStyle();
|
||||
calculateAge(".age");
|
||||
|
|
@ -9,6 +9,9 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||
languageSelector.addEventListener('change', function(){
|
||||
window.location.href = languageSelector.value + window.location.hash;
|
||||
});
|
||||
|
||||
// load projects
|
||||
loadMoreContent('.project-list', 6);
|
||||
});
|
||||
|
||||
window.addEventListener('scroll', function(){
|
||||
|
|
@ -26,6 +29,10 @@ document.querySelectorAll(".nav-links a").forEach(element => {
|
|||
});
|
||||
});
|
||||
|
||||
document.querySelector(".project-load-btn").addEventListener('click', function(){
|
||||
loadMoreContent('.project-list', 3);
|
||||
});
|
||||
|
||||
// Generic functions
|
||||
function toggleDisplayByClass(className, displayType){
|
||||
let items = document.getElementsByClassName(className);
|
||||
|
|
@ -95,3 +102,94 @@ function calculateAge(selector){
|
|||
|
||||
obj.textContent = age;
|
||||
}
|
||||
|
||||
// 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){
|
||||
try{
|
||||
constRequestUrl = `${endpoint}/?limit=${limit}&page=${page}`;
|
||||
const response = await fetch(constRequestUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
catch(error){
|
||||
return console.error({"message":error});
|
||||
}
|
||||
}
|
||||
|
||||
// add projects to page
|
||||
async function showProjects(wrapperSelector, data){
|
||||
const wrapper = document.querySelector(wrapperSelector);
|
||||
|
||||
for (const project of data){
|
||||
wrapper.append(await getProjectCard(project));
|
||||
}
|
||||
}
|
||||
|
||||
// create project card
|
||||
async function getProjectCard(data){
|
||||
const title = data.title;
|
||||
const url = data.url;
|
||||
const image = data.image;
|
||||
const date = data.date;
|
||||
const icon = data.icon;
|
||||
const category = data.category;
|
||||
|
||||
const dateFormatted = new Date(date).toLocaleDateString("de-DE", {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric"
|
||||
});
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.classList = "project-card";
|
||||
container.classList.add(category);
|
||||
//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;
|
||||
cardFirst.appendChild(cardImage);
|
||||
|
||||
const cardSecond = document.createElement("div");
|
||||
cardSecond.classList = "card-second";
|
||||
const cardIcon = document.createElement("i");
|
||||
cardIcon.classList = icon;
|
||||
const cardTitle = document.createElement("h2");
|
||||
cardTitle.textContent = title;
|
||||
const cardDate = document.createElement("p");
|
||||
cardDate.textContent = dateFormatted;
|
||||
cardSecond.appendChild(cardIcon);
|
||||
cardSecond.appendChild(cardTitle);
|
||||
cardSecond.appendChild(cardDate);
|
||||
|
||||
container.appendChild(cardFirst);
|
||||
container.appendChild(cardSecond);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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){
|
||||
await showProjects('.project-list', await loadContent(endpoint, amount, page));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,7 +19,8 @@ body{
|
|||
--color: #f8f8f8;
|
||||
--font: "Source Sans 3", sans-serif;
|
||||
--baseRadius: 12px;
|
||||
--baseTransition: all 250ms;
|
||||
--baseTransition: all var(--baseDuration);
|
||||
--baseDuration: 250ms;
|
||||
--navSmallHeight: 66px;
|
||||
}
|
||||
|
||||
|
|
@ -367,9 +368,10 @@ nav.small .nav-links a:last-child:focus{
|
|||
color: var(--primary);
|
||||
margin: 10px 5px;
|
||||
padding: 5px 16px;
|
||||
font-size: 1rem;
|
||||
border-radius: var(--baseRadius);
|
||||
transition: var(--baseTransition);
|
||||
border: 1px solid var(--primary);
|
||||
border: 2px solid var(--primary);
|
||||
}
|
||||
|
||||
.tag input{
|
||||
|
|
@ -381,6 +383,13 @@ nav.small .nav-links a:last-child:focus{
|
|||
color: var(--color);
|
||||
}
|
||||
|
||||
.tag:hover{
|
||||
padding: 5px 26px;
|
||||
background: var(--secondary);
|
||||
color: var(--color);
|
||||
border: 2px solid var(--color);
|
||||
}
|
||||
|
||||
.project-list{
|
||||
padding: 20px 0;
|
||||
display: flex;
|
||||
|
|
@ -391,6 +400,24 @@ nav.small .nav-links a:last-child:focus{
|
|||
align-items: stretch;
|
||||
}
|
||||
|
||||
.project-load-btn{
|
||||
padding: 10px 20px;
|
||||
background: var(--primary);
|
||||
color: var(--color);
|
||||
font-size: 1rem;
|
||||
border: 2px solid transparent;
|
||||
border-radius: var(--baseRadius);
|
||||
transition: var(--baseTransition);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.project-load-btn:hover{
|
||||
padding: 10px 40px;
|
||||
background: var(--secondary);
|
||||
border: 2px solid var(--color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Card animation: https://uiverse.io/suleymanlaarabidev/perfect-husky-88 */
|
||||
.project-card{
|
||||
width: 30%;
|
||||
|
|
@ -398,7 +425,7 @@ nav.small .nav-links a:last-child:focus{
|
|||
min-height: 250px;
|
||||
margin: 20px 10px;
|
||||
padding: 0 10px;
|
||||
background-image: url(https://blog.michivonah.ch/content/images/size/w1200/2024/12/ResortPass-Review--1-.jpg);
|
||||
background: var(--primary);
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
|
|
@ -406,6 +433,27 @@ nav.small .nav-links a:last-child:focus{
|
|||
transition: var(--baseTransition);
|
||||
box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.705);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
animation: fadeIn 400ms linear;
|
||||
}
|
||||
|
||||
@keyframes fadeIn{
|
||||
0%{
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100%{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.card-first img{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media (pointer: fine){
|
||||
|
|
@ -480,8 +528,9 @@ nav.small .nav-links a:last-child:focus{
|
|||
box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.705);
|
||||
}
|
||||
|
||||
.card-first{
|
||||
display: none;
|
||||
.card-first img{
|
||||
height: calc(100% + 60px);
|
||||
filter: blur(6px);
|
||||
}
|
||||
|
||||
.card-second{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue