This commit is contained in:
Fabio 2026-02-21 17:48:12 +01:00
parent 9cfdef19df
commit da0e3aa992
8 changed files with 245 additions and 1 deletions

View file

@ -63,7 +63,13 @@
</script> </script>
<!-- App --> <!-- App -->
<script src="app.js"></script> <script src="js/config.js"></script>
<script src="js/data.js"></script>
<script src="js/gallery.js"></script>
<script src="js/modal.js"></script>
<script src="js/infoPanel.js"></script>
<script src="js/mapGlobal.js"></script>
<script src="js/main.js"></script>
</body> </body>
</html> </html>

12
js/config.js Normal file
View file

@ -0,0 +1,12 @@
// ===============================
// CONFIG & GLOBAL STATE
// ===============================
const API_URL = 'https://prova.patachina.it/photos';
let photosData = [];
let currentPhoto = null;
// Mappa globale
let globalMap = null;
let globalMarkers = null;

26
js/data.js Normal file
View file

@ -0,0 +1,26 @@
// ===============================
// FETCH DELLE FOTO
// ===============================
async function loadPhotos() {
console.log("Inizio fetch:", API_URL);
let res;
try {
res = await fetch(API_URL);
} catch (e) {
console.error("Errore fetch:", e);
return;
}
const text = await res.text();
try {
photosData = JSON.parse(text);
console.log("JSON parse OK, numero foto:", photosData.length);
} catch (e) {
console.error("Errore nel parse JSON:", e);
return;
}
renderGallery(photosData);
}

40
js/gallery.js Normal file
View file

@ -0,0 +1,40 @@
// ===============================
// RENDER GALLERIA
// ===============================
function renderGallery(photos) {
const gallery = document.getElementById('gallery');
gallery.innerHTML = '';
photos.forEach(photo => {
const thumbDiv = document.createElement('div');
thumbDiv.className = 'thumb';
const img = document.createElement('img');
img.src = `https://prova.patachina.it/${photo.thub1}`;
img.alt = photo.name || '';
img.loading = "lazy";
thumbDiv.appendChild(img);
if (photo.mime_type.startsWith("video/")) {
const play = document.createElement("div");
play.className = "play-icon";
play.textContent = "▶";
thumbDiv.appendChild(play);
}
const preview = photo.thub2
? `https://prova.patachina.it/${photo.thub2}`
: `https://prova.patachina.it/${photo.thub1}`;
thumbDiv.addEventListener('click', () => {
openModal(
`https://prova.patachina.it/${photo.path}`,
preview,
photo
);
});
gallery.appendChild(thumbDiv);
});
}

57
js/infoPanel.js Normal file
View file

@ -0,0 +1,57 @@
// ===============================
// PANNELLO INFO + MAPPA
// ===============================
const infoPanel = document.getElementById('infoPanel');
const infoBtn = document.getElementById('modalInfoBtn');
infoBtn.addEventListener('click', () => {
if (!currentPhoto) return;
const gps = currentPhoto.gps || { lat: '-', lng: '-', alt: '-' };
const folder = currentPhoto.path.split('/').slice(2, -1).join('/');
infoPanel.innerHTML = `
<h3>Informazioni</h3>
<div class="info-row"><b>Nome:</b> ${currentPhoto.name}</div>
<div class="info-row"><b>Data:</b> ${currentPhoto.taken_at}</div>
<div class="info-row"><b>Latitudine:</b> ${gps.lat}</div>
<div class="info-row"><b>Longitudine:</b> ${gps.lng}</div>
<div class="info-row"><b>Altitudine:</b> ${gps.alt} m</div>
<div class="info-row"><b>Dimensioni:</b> ${currentPhoto.width} × ${currentPhoto.height}</div>
<div class="info-row"><b>Peso:</b> ${(currentPhoto.size_bytes / 1024 / 1024).toFixed(2)} MB</div>
<div class="info-row"><b>Tipo:</b> ${currentPhoto.mime_type}</div>
<div class="info-row"><b>Cartella:</b> ${folder}</div>
${gps.lat !== '-' ? '<div id="infoMap" class="info-map"></div>' : ''}
`;
infoPanel.classList.add('open');
if (gps.lat !== '-' && gps.lng !== '-') {
setTimeout(() => {
const map = L.map('infoMap', {
zoomControl: false,
attributionControl: false
}).setView([gps.lat, gps.lng], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);
L.marker([gps.lat, gps.lng]).addTo(map);
}, 50);
}
});
document.addEventListener('click', (e) => {
if (!infoPanel.classList.contains('open')) return;
const inside = infoPanel.contains(e.target);
const btn = infoBtn.contains(e.target);
if (!inside && !btn) infoPanel.classList.remove('open');
});

5
js/main.js Normal file
View file

@ -0,0 +1,5 @@
// ===============================
// AVVIO
// ===============================
console.log("main.js avviato");
loadPhotos();

51
js/mapGlobal.js Normal file
View file

@ -0,0 +1,51 @@
// ===============================
// MAPPA GLOBALE
// ===============================
document.getElementById("openMapBtn").addEventListener("click", openGlobalMap);
function openGlobalMap() {
const mapDiv = document.getElementById("globalMap");
const gallery = document.getElementById("gallery");
const isOpen = mapDiv.classList.contains("open");
if (isOpen) {
mapDiv.classList.remove("open");
gallery.classList.remove("hidden");
return;
}
mapDiv.classList.add("open");
gallery.classList.add("hidden");
if (!globalMap) {
globalMap = L.map("globalMap").setView([42.5, 12.5], 6);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 19
}).addTo(globalMap);
globalMarkers = L.markerClusterGroup();
globalMap.addLayer(globalMarkers);
photosData.forEach(photo => {
if (!photo.gps || !photo.gps.lat || !photo.gps.lng) return;
const marker = L.marker([photo.gps.lat, photo.gps.lng]);
marker.on("click", () => {
openModal(
`https://prova.patachina.it/${photo.path}`,
photo.thub2
? `https://prova.patachina.it/${photo.thub2}`
: `https://prova.patachina.it/${photo.thub1}`,
photo
);
});
globalMarkers.addLayer(marker);
});
}
setTimeout(() => globalMap.invalidateSize(), 200);
}

47
js/modal.js Normal file
View file

@ -0,0 +1,47 @@
// ===============================
// MODALE (FOTO + VIDEO)
// ===============================
const modal = document.getElementById('modal');
const modalClose = document.getElementById('modalClose');
function openModal(srcOriginal, srcPreview, photo) {
currentPhoto = photo;
const container = document.getElementById("modalMediaContainer");
container.innerHTML = "";
if (photo.mime_type.startsWith("video/")) {
const video = document.createElement("video");
video.src = srcOriginal;
video.controls = true;
video.autoplay = true;
video.style.maxWidth = "100%";
video.style.maxHeight = "100%";
container.appendChild(video);
} else {
const img = document.createElement("img");
img.src = srcPreview;
img.style.maxWidth = "100%";
img.style.maxHeight = "100%";
img.style.objectFit = "contain";
container.appendChild(img);
const full = new Image();
full.src = srcOriginal;
full.onload = () => {
img.src = srcOriginal;
};
}
modal.classList.add('open');
}
function closeModal() {
modal.classList.remove('open');
document.getElementById("modalMediaContainer").innerHTML = "";
}
modalClose.addEventListener('click', closeModal);
modal.addEventListener('click', (e) => {
if (e.target === modal) closeModal();
});