// QuickQ Website JavaScript
// Performance optimized with lazy loading and SEO enhancements
// Wait for DOM to be fully loaded
document.addEventListener('DOMContentLoaded', function() {
console.log('QuickQ website loaded - SEO optimized for Bing');
// Mobile menu toggle
const mobileMenuToggle = document.querySelector('.mobile-menu-toggle');
const navMenu = document.querySelector('.nav-menu');
if (mobileMenuToggle) {
mobileMenuToggle.addEventListener('click', function() {
navMenu.style.display = navMenu.style.display === 'flex' ? 'none' : 'flex';
if (navMenu.style.display === 'flex') {
navMenu.style.flexDirection = 'column';
navMenu.style.position = 'absolute';
navMenu.style.top = '100%';
navMenu.style.left = '0';
navMenu.style.right = '0';
navMenu.style.backgroundColor = 'white';
navMenu.style.padding = '2rem';
navMenu.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.1)';
navMenu.style.gap = '1rem';
// Add animation
navMenu.style.animation = 'slideDown 0.3s ease forwards';
}
});
}
// Smooth scroll for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
if (targetId === '#') return;
const targetElement = document.querySelector(targetId);
if (targetElement) {
window.scrollTo({
top: targetElement.offsetTop - 100,
behavior: 'smooth'
});
// Update URL without page reload
history.pushState(null, null, targetId);
}
});
});
// Lazy load images
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.add('loaded');
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
}
// Download card animations
const downloadCards = document.querySelectorAll('.download-card');
downloadCards.forEach(card => {
card.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-5px) scale(1.02)';
});
card.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0) scale(1)';
});
});
// Feature card animations
const featureCards = document.querySelectorAll('.feature-card');
featureCards.forEach(card => {
card.addEventListener('mouseenter', function() {
const icon = this.querySelector('.feature-icon');
if (icon) {
icon.style.transform = 'rotate(5deg) scale(1.1)';
}
});
card.addEventListener('mouseleave', function() {
const icon = this.querySelector('.feature-icon');
if (icon) {
icon.style.transform = 'rotate(0) scale(1)';
}
});
});
// Performance monitoring
window.addEventListener('load', function() {
// Send performance data to analytics
if ('performance' in window) {
const perfData = window.performance.timing;
const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart;
const domReadyTime = perfData.domComplete - perfData.domLoading;
console.log('Page load time:', pageLoadTime, 'ms');
console.log('DOM ready time:', domReadyTime, 'ms');
// Log performance for SEO optimization
if (pageLoadTime < 2000) {
console.log('✅ Page load time is good for SEO');
} else {
console.log('⚠️ Page load time could be improved');
}
}
});
// Form handling (for contact page)
const contactForm = document.getElementById('contactForm');
if (contactForm) {
contactForm.addEventListener('submit', function(e) {
e.preventDefault();
// Simple validation
const name = this.querySelector('input[name="name"]');
const email = this.querySelector('input[name="email"]');
const message = this.querySelector('textarea[name="message"]');
let isValid = true;
[name, email, message].forEach(field => {
if (!field.value.trim()) {
field.style.borderColor = '#ff6b6b';
isValid = false;
} else {
field.style.borderColor = '';
}
});
if (isValid) {
// Show success message
const successMessage = document.createElement('div');
successMessage.className = 'form-success';
successMessage.innerHTML = `
Thank you! Your message has been sent successfully.
`;
successMessage.style.cssText = `
background: #4CAF50;
color: white;
padding: 1rem;
border-radius: 4px;
margin-top: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
`;
contactForm.appendChild(successMessage);
// Reset form
contactForm.reset();
// Remove message after 5 seconds
setTimeout(() => {
successMessage.remove();
}, 5000);
}
});
}
// FAQ accordion functionality
const faqItems = document.querySelectorAll('.faq-item');
faqItems.forEach(item => {
const question = item.querySelector('h3');
const answer = item.querySelector('p');
if (question && answer) {
// Create toggle button
const toggleBtn = document.createElement('button');
toggleBtn.className = 'faq-toggle';
toggleBtn.innerHTML = '';
toggleBtn.setAttribute('aria-label', 'Toggle answer');
toggleBtn.style.cssText = `
background: none;
border: none;
cursor: pointer;
font-size: 1rem;
color: #666;
position: absolute;
right: 1rem;
top: 1rem;
`;
question.style.position = 'relative';
question.style.paddingRight = '2rem';
question.appendChild(toggleBtn);
// Initially hide answer
answer.style.display = 'none';
answer.style.opacity = '0';
answer.style.maxHeight = '0';
answer.style.overflow = 'hidden';
answer.style.transition = 'all 0.3s ease';
toggleBtn.addEventListener('click', function() {
const isExpanded = answer.style.maxHeight !== '0px';
if (isExpanded) {
answer.style.maxHeight = '0';
answer.style.opacity = '0';
answer.style.paddingTop = '0';
this.innerHTML = '';
} else {
answer.style.maxHeight = answer.scrollHeight + 'px';
answer.style.opacity = '1';
answer.style.paddingTop = '1rem';
this.innerHTML = '';
}
});
// Also allow clicking the whole question
question.style.cursor = 'pointer';
question.addEventListener('click', () => toggleBtn.click());
}
});
// Real-time download stats animation
function animateStats() {
const statNumbers = document.querySelectorAll('.stat-number');
statNumbers.forEach(stat => {
const target = parseInt(stat.textContent);
if (isNaN(target)) return;
let current = 0;
const increment = target / 50; // 50 frames
const interval = 20; // 20ms per frame
const timer = setInterval(() => {
current += increment;
if (current >= target) {
current = target;
clearInterval(timer);
}
stat.textContent = Math.round(current) + (stat.textContent.includes('%') ? '%' : '+');
}, interval);
});
}
// Start animation when stats are in viewport
if ('IntersectionObserver' in window) {
const statsObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
animateStats();
statsObserver.unobserve(entry.target);
}
});
}, { threshold: 0.5 });
const statsSection = document.querySelector('.hero-stats');
if (statsSection) {
statsObserver.observe(statsSection);
}
}
// Add CSS animation for mobile menu
const style = document.createElement('style');
style.textContent = `
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Print styles */
@media print {
.mobile-menu-toggle,
.btn-download,
.btn-primary,
.btn-secondary {
display: none !important;
}
}
/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
`;
document.head.appendChild(style);
// Track download button clicks for analytics
document.querySelectorAll('.btn-download, .download-card').forEach(button => {
button.addEventListener('click', function(e) {
const platform = this.textContent.includes('Windows') ? 'windows' :
this.textContent.includes('Mac') ? 'mac' :
this.textContent.includes('Android') ? 'android' : 'ios';
// In production, send to analytics
console.log(`Download clicked for ${platform} platform`);
// You can send this to your analytics service
// gtag('event', 'download_click', { 'platform': platform });
});
});
});
// Add service worker for PWA features (optional)
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').then(registration => {
console.log('ServiceWorker registered: ', registration.scope);
}).catch(error => {
console.log('ServiceWorker registration failed: ', error);
});
});
}