feat: initial commit
This commit is contained in:
commit
6731fe212c
|
@ -0,0 +1,2 @@
|
|||
infinite scrolling
|
||||
https://webdesign.tutsplus.com/how-to-implement-infinite-scrolling-with-javascript--cms-37055t
|
|
@ -0,0 +1,27 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="styles.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- cards are added by JavaScript so it starts empty -->
|
||||
<div id="card-container"></div>
|
||||
|
||||
<!-- loader displays an animation before adding the next batch of cards -->
|
||||
<div id="loader">
|
||||
<div class="skeleton-card"></div>
|
||||
<div class="skeleton-card"></div>
|
||||
<div class="skeleton-card"></div>
|
||||
</div>
|
||||
|
||||
<!-- card actions shows the card count and card total (we probably do not need this) -->
|
||||
<div id="card-actions">
|
||||
<span>Showing
|
||||
<span id="card-count"></span> of
|
||||
<span id="card-total"></span> cards
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,90 @@
|
|||
// first, let's get all the elements we'll need from our DOM
|
||||
const cardContainer = document.getElementById("card-container");
|
||||
const cardCountElem = document.getElementById("card-count");
|
||||
const cardTotalElem = document.getElementById("card-total");
|
||||
const loader = document.getElementById("loader");
|
||||
|
||||
// we'll need a value for the max numaer of cards to be added to the page
|
||||
const cardLimit = 99;
|
||||
// then we'll define a variable for how many cards we want to increase the
|
||||
// page by
|
||||
const cardIncrease = 9;
|
||||
// how many times can we increase the content until we reach the max limit?
|
||||
const pageCount = Math.ceil(cardLimit / cardIncrease);
|
||||
// and define a value to determine which page we're on
|
||||
let currentPage = 1;
|
||||
|
||||
cardTotalElem.innerHTML = cardLimit;
|
||||
|
||||
|
||||
function getRandomColor() {
|
||||
const h = Math.floor(Math.random() * 360);
|
||||
return `hsl(${h}deg, 90%, 85%)`;
|
||||
}
|
||||
|
||||
|
||||
function createCard(idx) {
|
||||
const card = document.createElement("div");
|
||||
card.className = "card";
|
||||
card.innerHTML = idx;
|
||||
card.style.backgroundColor = getRandomColor();
|
||||
cardContainer.appendChild(card);
|
||||
}
|
||||
|
||||
|
||||
function addCards(pageIdx) {
|
||||
currentPage = pageIdx;
|
||||
|
||||
const startRange = (pageIdx - 1) * cardIncrease;
|
||||
const endRange = currentPage == pageCount
|
||||
? cardLimit
|
||||
: pageIdx * cardIncrease;
|
||||
|
||||
cardCountElem.innerHTML = endRange;
|
||||
|
||||
for (let i = startRange + 1; i <= endRange; i++) {
|
||||
createCard(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleInfiniteScroll() {
|
||||
throttle(() => {
|
||||
const endOfPage = window.innerHeight + window.pageYOffset >= document.body.offsetHeight;
|
||||
|
||||
if (endOfPage) {
|
||||
addCards(currentPage + 1);
|
||||
}
|
||||
|
||||
if (currentPage === pageCount) {
|
||||
removeInfiniteScroll();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
|
||||
var throttleTimer;
|
||||
function throttle(callback, time) {
|
||||
if (throttleTimer) return;
|
||||
|
||||
throttleTimer = true;
|
||||
|
||||
setTimeout(() => {
|
||||
callback();
|
||||
throttleTimer = false;
|
||||
}, time);
|
||||
}
|
||||
|
||||
|
||||
function removeInfiniteScroll() {
|
||||
loader.remove();
|
||||
window.removeEventListener("scroll", handleInfiniteScroll);
|
||||
}
|
||||
|
||||
addCards(currentPage);
|
||||
window.addEventListener("scroll", handleInfiniteScroll);
|
||||
|
||||
// TODO: define the limit of the content to be loaded on the page
|
||||
// TODO: detect when the user has reached the end of the content container
|
||||
// TODO: load more content once the end of the container has been reached
|
||||
// TODO: if there's no more content to be loaded, stop the infinite scroll
|
|
@ -0,0 +1,62 @@
|
|||
#card-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.card {
|
||||
height: 55vh;
|
||||
width: calc((100% / 3) - 16px);
|
||||
margin: 8px;
|
||||
border-radius: 3px;
|
||||
transition: all 200ms ease-in-out;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
margin: 8px;
|
||||
padding: 16px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#loader {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.skeleton-card {
|
||||
height: 55vh;
|
||||
width: calc((100% / 3) - 16px);
|
||||
margin: 8px;
|
||||
border-radius: 3px;
|
||||
transition: all 200ms ease-in-out;
|
||||
position: relative;
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
.skeleton-card::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, 0.2) 20%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0));
|
||||
animation: load is infinite;
|
||||
}
|
||||
|
||||
@keyframes load {
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (prefers-reduced-motion: reduce) {
|
||||
}
|
Loading…
Reference in New Issue