163 lines
No EOL
9.5 KiB
JavaScript
163 lines
No EOL
9.5 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function () {
|
|
// --- Start of projects.js specific logic ---
|
|
|
|
let projectsData = [];
|
|
let currentProject = null;
|
|
let currentImageIndex = 0;
|
|
|
|
// --- Core Functions for fetching and rendering project cards ---
|
|
async function loadProjects() {
|
|
try {
|
|
const response = await fetch("data/projects.json");
|
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
|
projectsData = await response.json();
|
|
renderProjects();
|
|
} catch (error) {
|
|
console.error("Error loading projects:", error);
|
|
const grid = document.getElementById("projectsGrid");
|
|
if(grid) grid.innerHTML = `<p class="text-center text-kh3-red col-span-full">Failed to load projects.</p>`;
|
|
}
|
|
}
|
|
|
|
function renderProjects() {
|
|
const grid = document.getElementById("projectsGrid");
|
|
if (!grid) return;
|
|
|
|
grid.innerHTML = projectsData.map((project, index) => `
|
|
<div class="project-card group relative overflow-hidden rounded-lg bg-kh3-grey/10 border border-white/10 cursor-pointer opacity-0"
|
|
data-anim="fade-in-up" data-anim-delay="${200 + index * 100}"
|
|
onclick="openProjectDetails('${project.id}')">
|
|
<div class="relative h-64 overflow-hidden">
|
|
<img src="${project.images[0]}" alt="${project.name}" class="project-image w-full h-full object-cover transition-all duration-600" />
|
|
<div class="project-overlay absolute inset-0 bg-black/80 flex items-center justify-center"><div class="text-center"><div class="w-12 h-12 bg-kh3-red rounded-full flex items-center justify-center mx-auto mb-4"><svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path></svg></div><p class="text-white font-medium">VIEW PROJECT</p></div></div>
|
|
</div>
|
|
<div class="p-6">
|
|
<div class="flex items-center justify-between mb-3"><span class="text-kh3-red text-sm font-medium tracking-wider">${project.category}</span><span class="text-white/60 text-sm">${project.completionDate}</span></div>
|
|
<h3 class="text-xl font-bold text-white mb-2 group-hover:text-kh3-red transition-colors duration-300">${project.name}</h3>
|
|
<p class="text-white/70 text-sm mb-4 line-clamp-2">${project.description}</p>
|
|
<div class="flex items-center justify-between"><span class="text-white/50 text-sm">${project.size}</span><span class="text-white/50 text-sm">${project.location}</span></div>
|
|
</div>
|
|
</div>
|
|
`).join("");
|
|
if (window.initDynamicAnimations) window.initDynamicAnimations();
|
|
}
|
|
|
|
// --- MODAL Functionality (Restored from original) ---
|
|
function openProjectDetails(projectId) {
|
|
const project = projectsData.find((p) => p.id === projectId);
|
|
if (!project) return;
|
|
currentProject = project;
|
|
currentImageIndex = 0;
|
|
document.getElementById("modalTitle").textContent = project.name;
|
|
document.getElementById("modalCategory").textContent = project.category;
|
|
document.getElementById("modalDescription").textContent = project.description;
|
|
document.getElementById("modalClient").textContent = project.client;
|
|
document.getElementById("modalTypeOfWork").textContent = project.typeOfWork;
|
|
document.getElementById("modalSize").textContent = project.size;
|
|
document.getElementById("modalCompletionDate").textContent = project.completionDate;
|
|
document.getElementById("modalLocation").textContent = project.location;
|
|
document.getElementById("modalHighlights").innerHTML = project.highlights.map(h => `<li class="flex items-start space-x-2"><div class="w-1.5 h-1.5 bg-kh3-red rounded-full mt-2 flex-shrink-0"></div><span class="text-white/80 text-sm">${h}</span></li>`).join("");
|
|
|
|
setupImageCarousel(project.images); // RESTORED CALL
|
|
|
|
const modal = document.getElementById("projectModal");
|
|
const modalContent = document.getElementById("modalContent");
|
|
modal.classList.remove("hidden");
|
|
document.body.style.overflow = "hidden";
|
|
setTimeout(() => modalContent.classList.remove("scale-95", "opacity-0"), 10);
|
|
}
|
|
|
|
function closeModal() {
|
|
const modal = document.getElementById("projectModal");
|
|
const modalContent = document.getElementById("modalContent");
|
|
modalContent.classList.add("scale-95", "opacity-0");
|
|
setTimeout(() => {
|
|
modal.classList.add("hidden");
|
|
document.body.style.overflow = "auto";
|
|
}, 500);
|
|
}
|
|
|
|
// --- MODAL CAROUSEL Functionality (Restored from original) ---
|
|
function setupImageCarousel(images) {
|
|
const mainImage = document.getElementById("modalMainImage");
|
|
const imageDots = document.getElementById("imageDots");
|
|
const imageCounter = document.getElementById("imageCounter");
|
|
const totalImages = document.getElementById("totalImages");
|
|
|
|
mainImage.src = images[0];
|
|
mainImage.alt = currentProject.name;
|
|
totalImages.textContent = images.length;
|
|
imageDots.innerHTML = images.map((_, index) => `<button class="w-2 h-2 rounded-full transition-all duration-300 ${index === 0 ? "bg-kh3-red" : "bg-white/30"}" onclick="goToImage(${index})"></button>`).join("");
|
|
updateImageCarousel(); // Initial call to set counter
|
|
}
|
|
|
|
function updateImageCarousel() {
|
|
const mainImage = document.getElementById("modalMainImage");
|
|
const imageDots = document.getElementById("imageDots");
|
|
const imageCounter = document.getElementById("imageCounter");
|
|
if (!mainImage || !currentProject) return;
|
|
|
|
mainImage.style.opacity = "0";
|
|
setTimeout(() => {
|
|
mainImage.src = currentProject.images[currentImageIndex];
|
|
mainImage.style.opacity = "1";
|
|
}, 250);
|
|
|
|
imageCounter.textContent = currentImageIndex + 1;
|
|
const dots = imageDots.querySelectorAll("button");
|
|
dots.forEach((dot, index) => {
|
|
dot.classList.toggle("bg-kh3-red", index === currentImageIndex);
|
|
dot.classList.toggle("bg-white/30", index !== currentImageIndex);
|
|
});
|
|
}
|
|
|
|
// --- IMAGE ENLARGEMENT Functionality (Restored from original) ---
|
|
function enlargeImage() {
|
|
if (!currentProject) return;
|
|
const enlargedImage = document.getElementById("enlargedImage");
|
|
document.getElementById("enlargedImageCounter").textContent = currentImageIndex + 1;
|
|
document.getElementById("enlargedTotalImages").textContent = currentProject.images.length;
|
|
enlargedImage.src = currentProject.images[currentImageIndex];
|
|
document.getElementById("imageEnlargeModal").classList.remove("hidden");
|
|
}
|
|
|
|
function closeEnlargeModal() {
|
|
document.getElementById("imageEnlargeModal").classList.add("hidden");
|
|
}
|
|
|
|
// --- Global Accessibility for onclick and keyboard events (Restored) ---
|
|
window.openProjectDetails = openProjectDetails;
|
|
window.closeModal = closeModal;
|
|
window.enlargeImage = enlargeImage;
|
|
window.goToImage = (index) => { currentImageIndex = index; updateImageCarousel(); };
|
|
window.nextImage = () => { currentImageIndex = (currentImageIndex + 1) % currentProject.images.length; updateImageCarousel(); };
|
|
window.prevImage = () => { currentImageIndex = (currentImageIndex === 0) ? currentProject.images.length - 1 : currentImageIndex - 1; updateImageCarousel(); };
|
|
|
|
// Event listeners for modal controls
|
|
document.getElementById("closeModal")?.addEventListener("click", closeModal);
|
|
document.getElementById("projectModal")?.addEventListener("click", (e) => { if (e.target.id === "projectModal") closeModal(); });
|
|
document.getElementById("prevImage")?.addEventListener("click", window.prevImage);
|
|
document.getElementById("nextImage")?.addEventListener("click", window.nextImage);
|
|
document.getElementById("closeEnlargeModal")?.addEventListener("click", closeEnlargeModal);
|
|
document.getElementById("enlargePrevImage")?.addEventListener("click", () => { window.prevImage(); enlargeImage(); });
|
|
document.getElementById("enlargeNextImage")?.addEventListener("click", () => { window.nextImage(); enlargeImage(); });
|
|
document.getElementById("imageEnlargeModal")?.addEventListener("click", (e) => { if (e.target.id === "imageEnlargeModal") closeEnlargeModal(); });
|
|
|
|
document.addEventListener("keydown", (e) => {
|
|
const isProjectModalOpen = !document.getElementById("projectModal")?.classList.contains("hidden");
|
|
const isEnlargeModalOpen = !document.getElementById("imageEnlargeModal")?.classList.contains("hidden");
|
|
|
|
if (isEnlargeModalOpen) {
|
|
if (e.key === "ArrowLeft") { window.prevImage(); enlargeImage(); }
|
|
if (e.key === "ArrowRight") { window.nextImage(); enlargeImage(); }
|
|
if (e.key === "Escape") closeEnlargeModal();
|
|
} else if (isProjectModalOpen) {
|
|
if (e.key === "ArrowLeft") window.prevImage();
|
|
if (e.key === "ArrowRight") window.nextImage();
|
|
if (e.key === "Escape") closeModal();
|
|
}
|
|
});
|
|
|
|
// --- Initialize Page ---
|
|
loadProjects();
|
|
}); |