Files
Base-website/static/js/main.js
2025-07-15 11:33:04 +02:00

291 lines
8.6 KiB
JavaScript

// Kobelly Base Website - Main JavaScript
document.addEventListener('DOMContentLoaded', function() {
'use strict';
// Initialize all components
initNavbar();
initAnimations();
initFormValidation();
initScrollEffects();
initContactForm();
initAccordion();
initTooltips();
initModals();
console.log('Kobelly Base Website loaded successfully!');
});
// Navbar functionality
function initNavbar() {
const navbar = document.querySelector('.navbar');
const navbarToggler = document.querySelector('.navbar-toggler');
const navbarCollapse = document.querySelector('.navbar-collapse');
// Navbar scroll effect
window.addEventListener('scroll', function() {
if (window.scrollY > 50) {
navbar.classList.add('scrolled');
} else {
navbar.classList.remove('scrolled');
}
});
// Close mobile menu when clicking on a link
const navLinks = document.querySelectorAll('.navbar-nav .nav-link');
navLinks.forEach(link => {
link.addEventListener('click', function() {
if (navbarCollapse.classList.contains('show')) {
navbarToggler.click();
}
});
});
}
// Animation initialization
function initAnimations() {
// Intersection Observer for fade-in animations
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('fade-in');
observer.unobserve(entry.target);
}
});
}, observerOptions);
// Observe elements for animation
const animateElements = document.querySelectorAll('.card, .feature-icon, .service-icon, .value-icon');
animateElements.forEach(el => {
observer.observe(el);
});
}
// Form validation
function initFormValidation() {
const forms = document.querySelectorAll('form[data-validate]');
forms.forEach(form => {
form.addEventListener('submit', function(e) {
if (!validateForm(form)) {
e.preventDefault();
}
});
});
}
function validateForm(form) {
let isValid = true;
const inputs = form.querySelectorAll('input[required], textarea[required]');
inputs.forEach(input => {
if (!input.value.trim()) {
showFieldError(input, 'This field is required');
isValid = false;
} else if (input.type === 'email' && !isValidEmail(input.value)) {
showFieldError(input, 'Please enter a valid email address');
isValid = false;
} else {
clearFieldError(input);
}
});
return isValid;
}
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function showFieldError(input, message) {
clearFieldError(input);
const errorDiv = document.createElement('div');
errorDiv.className = 'invalid-feedback d-block';
errorDiv.textContent = message;
input.classList.add('is-invalid');
input.parentNode.appendChild(errorDiv);
}
function clearFieldError(input) {
input.classList.remove('is-invalid');
const errorDiv = input.parentNode.querySelector('.invalid-feedback');
if (errorDiv) {
errorDiv.remove();
}
}
// Scroll effects
function initScrollEffects() {
// Smooth scrolling for anchor links
const anchorLinks = document.querySelectorAll('a[href^="#"]');
anchorLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
// Back to top button
const backToTopBtn = document.createElement('button');
backToTopBtn.innerHTML = '<i class="bi bi-arrow-up"></i>';
backToTopBtn.className = 'btn btn-primary position-fixed';
backToTopBtn.style.cssText = 'bottom: 20px; right: 20px; z-index: 1000; display: none; border-radius: 50%; width: 50px; height: 50px;';
backToTopBtn.setAttribute('aria-label', 'Back to top');
document.body.appendChild(backToTopBtn);
window.addEventListener('scroll', function() {
if (window.scrollY > 300) {
backToTopBtn.style.display = 'block';
} else {
backToTopBtn.style.display = 'none';
}
});
backToTopBtn.addEventListener('click', function() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
}
// Contact form handling
function initContactForm() {
const contactForm = document.querySelector('form[action*="contact"]');
if (!contactForm) return;
contactForm.addEventListener('submit', function(e) {
const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.textContent;
// Show loading state
submitBtn.disabled = true;
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Sending...';
submitBtn.classList.add('loading');
});
}
// Accordion functionality
function initAccordion() {
const accordionButtons = document.querySelectorAll('.accordion-button');
accordionButtons.forEach(button => {
button.addEventListener('click', function() {
const isExpanded = this.getAttribute('aria-expanded') === 'true';
// Add animation class
const accordionCollapse = this.nextElementSibling;
if (!isExpanded) {
accordionCollapse.classList.add('expanding');
}
// Remove animation class after transition
setTimeout(() => {
accordionCollapse.classList.remove('expanding');
}, 300);
});
});
}
// Tooltip initialization
function initTooltips() {
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function(tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
}
// Modal initialization
function initModals() {
const modalTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="modal"]'));
modalTriggerList.map(function(modalTriggerEl) {
return new bootstrap.Modal(modalTriggerEl);
});
}
// Utility functions
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// Performance optimization
const optimizedScrollHandler = throttle(function() {
// Handle scroll events efficiently
}, 16); // ~60fps
window.addEventListener('scroll', optimizedScrollHandler);
// Error handling
window.addEventListener('error', function(e) {
console.error('JavaScript error:', e.error);
});
// Service Worker registration (for PWA features)
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js')
.then(function(registration) {
console.log('ServiceWorker registration successful');
})
.catch(function(err) {
console.log('ServiceWorker registration failed');
});
});
}
// Accessibility improvements
function initAccessibility() {
// Skip to main content link
const skipLink = document.createElement('a');
skipLink.href = '#main-content';
skipLink.textContent = 'Skip to main content';
skipLink.className = 'sr-only sr-only-focusable position-absolute';
skipLink.style.cssText = 'top: 10px; left: 10px; z-index: 1001; padding: 10px; background: white; border: 1px solid #ccc;';
document.body.insertBefore(skipLink, document.body.firstChild);
// Add main content id
const mainContent = document.querySelector('main');
if (mainContent) {
mainContent.id = 'main-content';
}
}
// Initialize accessibility features
initAccessibility();