DISEPICGALL
by Manuel Castro
HTML
<div class="galeria"></div>
<div id="modal" class="modal">
<span class="cerrar">×</span>
<img id="modalImg">
</div>
CSS
.galeria {
display: grid;
grid-template-columns: repeat(4, 0.5fr);
gap: 20px;
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
justify-content: center;
}
.galeria .item {
aspect-ratio: 1 / 1;
overflow: hidden;
border-radius: 12px;
/*background: #e0e0e0;*/
margin: 10px 15px;
box-shadow: 0 2px 10px rgba(0,0,0,0.08);
}
.galeria .item a {
display: block;
width: 100%;
height: 100%;
}
.galeria .item img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* Modal */
.modal{
position:fixed;
inset:0;
background:rgba(0,0,0,.82);
display:flex;
justify-content:center;
align-items:center;
opacity:0;
visibility:hidden;
transition:.28s ease;
z-index:9999;
}
.modal.activo{
opacity:1;
visibility:visible;
}
.modal img{
max-width:90vw;
max-height:90vh;
border-radius:12px;
transform:scale(.92);
transition:.28s ease;
box-shadow:0 25px 70px rgba(0,0,0,.45);
}
.modal.activo img{
transform:scale(1);
}
.cerrar{
position:absolute;
top:25px;
right:35px;
font-size:42px;
color:white;
cursor:pointer;
user-select:none;
font-family:Arial;
}
JavaScript
const API = "https://script.google.com/macros/s/AKfycbyBjZL328x9u-1kVmaaWqftxhwTRTa9HSlwqF4SGDUwkWdEF5KdZU-j1TLq_5pWg3XDXg/exec";
const galeria = document.querySelector(".galeria");
const modal = document.getElementById("modal");
const modalImg = document.getElementById("modalImg");
const cerrar = document.querySelector(".cerrar");
let archivos = [];
let indice = 0;
const LOTE = 20;
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
observer.unobserve(entries[0].target);
if (indice < archivos.length) {
cargarLote();
}
}
}, {
rootMargin: "300px"
});
fetch(API)
.then(res => res.json())
.then(data => {
archivos = data;
cargarLote();
});
function cargarLote() {
const fragment = document.createDocumentFragment();
const fin = Math.min(indice + LOTE, archivos.length);
let ultimoItem = null;
for (let i = indice; i < fin; i++) {
const file = archivos[i];
const item = document.createElement("div");
item.className = "item";
const img = document.createElement("img");
img.loading = "lazy";
img.src = file.thumb;
img.alt = file.name;
img.dataset.full = file.thumb;
img.onclick = () => {
modalImg.src = img.dataset.full;
modal.classList.add("activo");
document.body.style.overflow = "hidden";
};
item.appendChild(img);
fragment.appendChild(item);
ultimoItem = item;
}
galeria.appendChild(fragment);
indice = fin;
if (ultimoItem && indice < archivos.length) {
observer.observe(ultimoItem);
}
}
cerrar.onclick = cerrarModal;
modal.onclick = (e)=>{
if(e.target===modal){
cerrarModal();
}
};
document.addEventListener("keydown",(e)=>{
...