Current directory: /home/klas4s23/domains/585455.klas4s23.mid-ica.nl/public_html/Gastenboek/uploads
/**
* Enhanced Project Carousel
* Creates an interactive carousel for project cards with navigation and autoplay
*/
function initProjectCarousel() {
// Only enable carousel on non-mobile devices
if (window.innerWidth <= 768) {
return; // Exit early on mobile devices
}
const projectsContainer = document.querySelector('.projects__container');
const projectCards = document.querySelectorAll('.projects__card');
if (!projectsContainer || projectCards.length === 0) {
console.warn('Projects container or cards not found');
return;
}
let currentIndex = 0;
let cardsPerView = getCardsPerView();
let autoplayInterval;
let isTransitioning = false;
// Create carousel navigation
createCarouselControls();
// Initialize carousel
initializeCarousel();
// Start autoplay
startAutoplay();
// Handle window resize
window.addEventListener('resize', handleResize);
/*=============== HELPER FUNCTIONS ===============*/
function getCardsPerView() {
const width = window.innerWidth;
if (width < 768) return 1; // Mobile: 1 card
if (width < 1024) return 3; // Tablet: 3 cards
return 2; // Desktop: 2 cards
}
function updateNavigationState() {
const prevBtn = document.querySelector('.projects__nav-btn--prev');
const nextBtn = document.querySelector('.projects__nav-btn--next');
const totalPages = Math.ceil(projectCards.length / cardsPerView);
if (prevBtn && nextBtn) {
// Enable/disable navigation buttons based on current index
prevBtn.disabled = currentIndex === 0;
nextBtn.disabled = currentIndex === totalPages - 1;
}
}
/*=============== CAROUSEL CONTROLS ===============*/
function createCarouselControls() {
// Create navigation buttons container
const navContainer = document.createElement('div');
navContainer.className = 'projects__navigation';
// Previous button
const prevBtn = document.createElement('button');
prevBtn.className = 'projects__nav-btn projects__nav-btn--prev';
prevBtn.innerHTML = '<i class="ri-arrow-left-s-line"></i>';
prevBtn.addEventListener('click', () => navigateCarousel('prev'));
// Next button
const nextBtn = document.createElement('button');
nextBtn.className = 'projects__nav-btn projects__nav-btn--next';
nextBtn.innerHTML = '<i class="ri-arrow-right-s-line"></i>';
nextBtn.addEventListener('click', () => navigateCarousel('next'));
navContainer.appendChild(prevBtn);
navContainer.appendChild(nextBtn);
// Insert navigation after projects container
projectsContainer.parentNode.insertBefore(navContainer, projectsContainer.nextSibling);
// Create dots indicator
createDotsIndicator();
}
function createDotsIndicator() {
const totalPages = Math.ceil(projectCards.length / cardsPerView);
const dotsContainer = document.createElement('div');
dotsContainer.className = 'projects__dots';
for (let i = 0; i < totalPages; i++) {
const dot = document.createElement('button');
dot.className = 'projects__dot';
if (i === 0) dot.classList.add('projects__dot--active');
dot.addEventListener('click', () => goToSlide(i));
dotsContainer.appendChild(dot);
}
const navigation = document.querySelector('.projects__navigation');
if (navigation) {
navigation.appendChild(dotsContainer);
}
}
/*=============== CAROUSEL INITIALIZATION ===============*/
function initializeCarousel() {
// Add carousel wrapper class
projectsContainer.classList.add('projects__carousel');
// Set initial transform
updateCarouselPosition();
// Add touch/swipe support
addTouchSupport();
// Update navigation state
updateNavigationState();
}
function addTouchSupport() {
let startX = 0;
let endX = 0;
projectsContainer.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX;
});
projectsContainer.addEventListener('touchmove', (e) => {
endX = e.touches[0].clientX;
});
projectsContainer.addEventListener('touchend', () => {
const threshold = 50; // Minimum swipe distance
if (startX - endX > threshold) {
navigateCarousel('next');
} else if (endX - startX > threshold) {
navigateCarousel('prev');
}
});
}
/*=============== CAROUSEL NAVIGATION ===============*/
function updateCarouselPosition(animated = true) {
if (isTransitioning && animated) return;
isTransitioning = true;
const translateX = -(currentIndex * (100 / cardsPerView));
if (animated) {
projectsContainer.style.transition = 'transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
} else {
projectsContainer.style.transition = 'none';
}
projectsContainer.style.transform = `translateX(${translateX}%)`;
if (animated) {
setTimeout(() => {
isTransitioning = false;
}, 600);
} else {
isTransitioning = false;
}
updateDotsIndicator();
}
function navigateCarousel(direction) {
if (isTransitioning) return;
stopAutoplay();
const totalPages = Math.ceil(projectCards.length / cardsPerView);
if (direction === 'next') {
currentIndex = (currentIndex + 1) % totalPages;
} else {
currentIndex = currentIndex === 0 ? totalPages - 1 : currentIndex - 1;
}
updateCarouselPosition();
updateNavigationState();
// Restart autoplay after user interaction
setTimeout(startAutoplay, 3000);
}
function goToSlide(index) {
if (isTransitioning || index === currentIndex) return;
stopAutoplay();
currentIndex = index;
updateCarouselPosition();
updateNavigationState();
setTimeout(startAutoplay, 3000);
}
function updateDotsIndicator() {
const dots = document.querySelectorAll('.projects__dot');
dots.forEach((dot, index) => {
dot.classList.toggle('projects__dot--active', index === currentIndex);
});
}
/*=============== AUTOPLAY ===============*/
function startAutoplay() {
stopAutoplay();
autoplayInterval = setInterval(() => {
navigateCarousel('next');
}, 5000); // Change slide every 5 seconds
}
function stopAutoplay() {
if (autoplayInterval) {
clearInterval(autoplayInterval);
autoplayInterval = null;
}
}
/*=============== RESPONSIVE HANDLING ===============*/
function handleResize() {
// Check if we should disable/enable carousel based on screen size
if (window.innerWidth <= 768) {
// Mobile - disable carousel
const existingNav = document.querySelector('.projects__navigation');
if (existingNav) {
existingNav.remove();
}
stopAutoplay();
// Reset container styles for mobile
projectsContainer.classList.remove('projects__carousel');
projectsContainer.style.transform = '';
projectsContainer.style.transition = '';
return;
}
// Desktop/Tablet - ensure carousel is active
if (!document.querySelector('.projects__navigation')) {
createCarouselControls();
initializeCarousel();
startAutoplay();
}
const newCardsPerView = getCardsPerView();
if (newCardsPerView !== cardsPerView) {
cardsPerView = newCardsPerView;
// Recalculate current index to maintain position
const totalPages = Math.ceil(projectCards.length / cardsPerView);
currentIndex = Math.min(currentIndex, totalPages - 1);
// Recreate dots indicator
const existingDots = document.querySelector('.projects__dots');
if (existingDots) {
existingDots.remove();
createDotsIndicator();
}
// Update position without animation
updateCarouselPosition(false);
}
}
/*=============== VISIBILITY AND HOVER EVENTS ===============*/
// Pause autoplay when tab is not visible
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
stopAutoplay();
} else {
startAutoplay();
}
});
// Pause autoplay when hovering over carousel
projectsContainer.addEventListener('mouseenter', stopAutoplay);
projectsContainer.addEventListener('mouseleave', startAutoplay);
}
// Wait for components to load before initializing carousel
window.addEventListener('componentsLoaded', initProjectCarousel);