document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById('projects'); // Add loading state with enhanced spinner container.innerHTML = '

Loading projects...

'; // Create modal element with enhanced styling const modal = document.createElement('div'); modal.className = 'modal-overlay fixed inset-0 hidden items-center justify-center z-50 transition-opacity duration-300'; modal.innerHTML = ` `; document.body.appendChild(modal); // Add modal functions to window window.openModal = (project) => { const modalTitle = modal.querySelector('h2'); const modalImage = modal.querySelector('.modal-image'); const modalDescription = modal.querySelector('.modal-description'); const modalTags = modal.querySelector('.modal-tags'); const modalLinks = modal.querySelector('.modal-links'); const modalContent = modal.querySelector('.modal-content'); modalTitle.textContent = project.title; if (project.image_url) { modalImage.innerHTML = `${project.title}`; } else { modalImage.innerHTML = '
'; } modalDescription.innerHTML = `

${project.description || ''}

${project.long_description ? `

${project.long_description}

` : ''} `; if (project.tags) { modalTags.innerHTML = `
${project.tags.split(',').map(tag => `${tag.trim()}` ).join('')}
`; } else { modalTags.innerHTML = ''; } modalLinks.innerHTML = project.project_url ? `View Project →` : ''; // Show modal with animation modal.classList.remove('hidden'); modal.classList.add('flex'); document.body.style.overflow = 'hidden'; // Trigger animation requestAnimationFrame(() => { modalContent.classList.remove('scale-95', 'opacity-0'); modalContent.classList.add('scale-100', 'opacity-100'); }); }; window.closeModal = () => { const modalContent = modal.querySelector('.modal-content'); // Start closing animation modalContent.classList.remove('scale-100', 'opacity-100'); modalContent.classList.add('scale-95', 'opacity-0'); // Wait for animation to finish before hiding setTimeout(() => { modal.classList.add('hidden'); modal.classList.remove('flex'); document.body.style.overflow = ''; }, 300); }; // Close modal when clicking outside modal.addEventListener('click', (e) => { if (e.target === modal) { closeModal(); } }); // Close modal with Escape key document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && !modal.classList.contains('hidden')) { closeModal(); } }); // Enhanced project fetching with error handling fetch('php/get_projects.php') .then(res => { if (!res.ok) { throw new Error(`HTTP error! status: ${res.status}`); } return res.json(); }) .then(projects => { if (!Array.isArray(projects) || projects.length === 0) { container.innerHTML = `

No projects found.

Projects will appear here once added.

`; return; } container.innerHTML = ''; // Add projects with CSS animations projects.forEach((project) => { const card = document.createElement('div'); card.className = 'project-card p-5 flex flex-col cursor-pointer hover-lift'; card.onclick = () => openModal(project); if (project.image_url) { card.innerHTML += `${project.title}`; } else { card.innerHTML += `
`; } card.innerHTML += `

${project.title}

${project.description || ''}

${project.tags ? `
${project.tags.split(',').map(tag => `${tag.trim()}`).join('')}
` : ''} ${project.project_url ? `View Project →` : ''} `; container.appendChild(card); }); }) .catch(err => { console.error('Error fetching projects:', err); container.innerHTML = `

Failed to load projects.

Error: ${err.message}

`; }); }); // Add fadeInUp animation const style = document.createElement('style'); style.textContent = ` @keyframes fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } `; document.head.appendChild(style);