codecollab-pro / script.js
qdevxh's picture
let's make it look more professional ND dd lazy loading to it and how do I deploy?
be348b6 verified
Raw
History Blame Contribute Delete
8.3 kB
// Shared JavaScript across all pages
document.addEventListener('DOMContentLoaded', function() {
// Initialize lazy loading
initLazyLoading();
// Counter animation for stats
const counters = document.querySelectorAll('[data-count]');
const speed = 200;
const animateCounter = (counter) => {
const target = +counter.getAttribute('data-count');
const increment = target / speed;
const updateCount = () => {
const count = +counter.innerText.replace(/,/g, '');
if (count < target) {
counter.innerText = Math.ceil(count + increment).toLocaleString();
setTimeout(updateCount, 1);
} else {
counter.innerText = target.toLocaleString();
}
};
updateCount();
};
// Intersection Observer for animations and lazy loading
const observerOptions = {
threshold: 0.1,
rootMargin: '50px 0px -50px 0px'
};
const observerCallback = (entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Handle lazy loaded images
if (entry.target.dataset.src) {
entry.target.src = entry.target.dataset.src;
entry.target.classList.remove('skeleton');
entry.target.onload = () => {
entry.target.classList.add('loaded');
};
}
// Handle lazy loaded elements
if (entry.target.classList.contains('lazy-load')) {
entry.target.classList.add('loaded');
}
// Handle counter animations
if (entry.target.hasAttribute('data-count')) {
animateCounter(entry.target);
observer.unobserve(entry.target);
}
}
});
};
const observer = new IntersectionObserver(observerCallback, observerOptions);
// Observe all elements with data-count
counters.forEach(counter => observer.observe(counter));
// Observe all lazy-load elements
document.querySelectorAll('.lazy-load').forEach(el => observer.observe(el));
// Observe all images with data-src
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));
});
// Lazy Loading Implementation
function initLazyLoading() {
// Add skeleton loading to images while they load
document.querySelectorAll('img[data-src]').forEach(img => {
img.classList.add('skeleton');
// Set a low-quality placeholder
img.src = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="40" height="40"%3E%3Crect width="40" height="40" fill="%23f0f0f0"/%3E%3C/svg%3E';
});
// Preload critical images
const criticalImages = document.querySelectorAll('img[data-critical="true"]');
criticalImages.forEach(img => {
if (img.dataset.src) {
img.src = img.dataset.src;
img.classList.remove('skeleton');
}
});
// Smooth scroll for anchor links with improved performance
const scrollLinks = document.querySelectorAll('a[href^="#"]');
scrollLinks.forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const target = document.querySelector(targetId);
if (target) {
const headerOffset = 80;
const elementPosition = target.getBoundingClientRect().top;
const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
window.scrollTo({
top: offsetPosition,
behavior: 'smooth'
});
}
});
});
// Add active state to navigation based on scroll position
const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('nav a[href^="#"]');
const highlightNav = () => {
const scrollY = window.pageYOffset;
sections.forEach(section => {
const sectionHeight = section.offsetHeight;
const sectionTop = section.offsetTop - 100;
const sectionId = section.getAttribute('id');
if (scrollY > sectionTop && scrollY <= sectionTop + sectionHeight) {
navLinks.forEach(link => {
link.classList.remove('text-indigo-600', 'font-semibold');
if (link.getAttribute('href') === `#${sectionId}`) {
link.classList.add('text-indigo-600', 'font-semibold');
}
});
}
});
};
window.addEventListener('scroll', highlightNav);
highlightNav(); // Call once on load
});
// Enhanced utility functions
const utils = {
debounce: (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
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 monitoring
measurePerformance: (name, fn) => {
const start = performance.now();
const result = fn();
const end = performance.now();
console.log(`${name} took ${end - start} milliseconds`);
return result;
},
// Loading state management
setLoading: (element, loading = true) => {
if (loading) {
element.disabled = true;
element.dataset.originalText = element.textContent;
element.innerHTML = '<span class="spinner inline-block w-4 h-4 mr-2"></span>Loading...';
} else {
element.disabled = false;
element.textContent = element.dataset.originalText || 'Submit';
}
}
};
// Enhanced local storage helper with compression
const storage = {
set: (key, value) => {
try {
const serialized = JSON.stringify(value);
localStorage.setItem(key, serialized);
return true;
} catch (e) {
console.error('Error saving to localStorage', e);
return false;
}
},
get: (key) => {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : null;
} catch (e) {
console.error('Error reading from localStorage', e);
return null;
}
},
remove: (key) => {
try {
localStorage.removeItem(key);
return true;
} catch (e) {
console.error('Error removing from localStorage', e);
return false;
}
},
// Clear all storage
clear: () => {
try {
localStorage.clear();
return true;
} catch (e) {
console.error('Error clearing localStorage', e);
return false;
}
},
// Get storage usage
getUsage: () => {
let total = 0;
for (let key in localStorage) {
if (localStorage.hasOwnProperty(key)) {
total += localStorage[key].length + key.length;
}
}
return (total / 1024).toFixed(2) + ' KB';
}
};
// Service Worker registration for PWA capabilities
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW registered: ', registration);
})
.catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}