Initial AI-generated site
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// ===== Mobile Menu Toggle =====
|
||||
const mobileMenuToggle = document.querySelector('.mobile-menu-toggle');
|
||||
const mobileNav = document.querySelector('.mobile-nav');
|
||||
|
||||
if (mobileMenuToggle && mobileNav) {
|
||||
mobileMenuToggle.addEventListener('click', function() {
|
||||
const isExpanded = this.getAttribute('aria-expanded') === 'true';
|
||||
this.setAttribute('aria-expanded', !isExpanded);
|
||||
mobileNav.hidden = isExpanded;
|
||||
});
|
||||
|
||||
// Close mobile menu when clicking a link
|
||||
mobileNav.querySelectorAll('a').forEach(link => {
|
||||
link.addEventListener('click', function() {
|
||||
mobileMenuToggle.setAttribute('aria-expanded', 'false');
|
||||
mobileNav.hidden = true;
|
||||
});
|
||||
});
|
||||
|
||||
// Close mobile menu on Escape key
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape' && !mobileNav.hidden) {
|
||||
mobileMenuToggle.setAttribute('aria-expanded', 'false');
|
||||
mobileNav.hidden = true;
|
||||
mobileMenuToggle.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Reduced Motion Check =====
|
||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
|
||||
// ===== Scroll Reveal Animation =====
|
||||
const revealElements = document.querySelectorAll('.reveal');
|
||||
|
||||
if ('IntersectionObserver' in window && !prefersReducedMotion.matches) {
|
||||
const revealObserver = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('visible');
|
||||
revealObserver.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.1,
|
||||
rootMargin: '0px 0px -50px 0px'
|
||||
});
|
||||
|
||||
revealElements.forEach(el => revealObserver.observe(el));
|
||||
} else {
|
||||
// Fallback for older browsers or reduced motion preference
|
||||
revealElements.forEach(el => el.classList.add('visible'));
|
||||
}
|
||||
|
||||
// ===== Smooth Scroll for Navigation =====
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function(e) {
|
||||
const targetId = this.getAttribute('href');
|
||||
if (targetId === '#') return;
|
||||
|
||||
const targetElement = document.querySelector(targetId);
|
||||
if (targetElement) {
|
||||
e.preventDefault();
|
||||
const headerHeight = document.querySelector('.site-header').offsetHeight;
|
||||
const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - headerHeight - 20;
|
||||
|
||||
window.scrollTo({
|
||||
top: targetPosition,
|
||||
behavior: prefersReducedMotion.matches ? 'auto' : 'smooth'
|
||||
});
|
||||
|
||||
// Set focus to target for accessibility
|
||||
targetElement.setAttribute('tabindex', '-1');
|
||||
targetElement.focus({ preventScroll: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ===== Form Handling =====
|
||||
const leadForm = document.getElementById('leadForm');
|
||||
const formSuccess = document.getElementById('formSuccess');
|
||||
|
||||
if (leadForm && formSuccess) {
|
||||
leadForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Basic validation
|
||||
const inputs = this.querySelectorAll('input[required]');
|
||||
let isValid = true;
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.classList.remove('error');
|
||||
if (!input.value.trim()) {
|
||||
isValid = false;
|
||||
input.classList.add('error');
|
||||
}
|
||||
});
|
||||
|
||||
// Email validation
|
||||
const emailInput = document.getElementById('email');
|
||||
if (emailInput && emailInput.value) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(emailInput.value)) {
|
||||
isValid = false;
|
||||
emailInput.classList.add('error');
|
||||
}
|
||||
}
|
||||
|
||||
// Phone validation (basic Israeli format)
|
||||
const phoneInput = document.getElementById('phone');
|
||||
if (phoneInput && phoneInput.value) {
|
||||
const phoneRegex = /^[\d\-\+\s\(\)]{9,}$/;
|
||||
if (!phoneRegex.test(phoneInput.value)) {
|
||||
isValid = false;
|
||||
phoneInput.classList.add('error');
|
||||
}
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
// Simulate form submission
|
||||
const submitBtn = this.querySelector('.btn-submit');
|
||||
const originalText = submitBtn.innerHTML;
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.innerHTML = '<span>שולח...</span>';
|
||||
|
||||
setTimeout(() => {
|
||||
leadForm.hidden = true;
|
||||
formSuccess.hidden = false;
|
||||
// Announce to screen readers
|
||||
formSuccess.focus();
|
||||
}, 1000);
|
||||
} else {
|
||||
// Focus first error field
|
||||
const firstError = this.querySelector('.error');
|
||||
if (firstError) {
|
||||
firstError.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Clear error styling on input
|
||||
leadForm.querySelectorAll('input').forEach(input => {
|
||||
input.addEventListener('input', function() {
|
||||
this.classList.remove('error');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Header Background on Scroll =====
|
||||
const header = document.querySelector('.site-header');
|
||||
let lastScroll = 0;
|
||||
let ticking = false;
|
||||
|
||||
function updateHeader() {
|
||||
const currentScroll = window.pageYOffset;
|
||||
|
||||
if (currentScroll > 50) {
|
||||
header.style.boxShadow = 'var(--shadow)';
|
||||
} else {
|
||||
header.style.boxShadow = 'none';
|
||||
}
|
||||
|
||||
lastScroll = currentScroll;
|
||||
ticking = false;
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', function() {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(updateHeader);
|
||||
ticking = true;
|
||||
}
|
||||
}, { passive: true });
|
||||
|
||||
// ===== Dashboard Card Animation =====
|
||||
if (!prefersReducedMotion.matches) {
|
||||
const pendingCard = document.querySelector('.dash-card.pending');
|
||||
|
||||
if (pendingCard) {
|
||||
let pulseInterval;
|
||||
|
||||
const startPulse = () => {
|
||||
pendingCard.style.transition = 'box-shadow 0.5s ease';
|
||||
let isPulsing = true;
|
||||
|
||||
pulseInterval = setInterval(() => {
|
||||
if (isPulsing) {
|
||||
pendingCard.style.boxShadow = '0 0 0 3px rgba(217, 119, 6, 0.3)';
|
||||
} else {
|
||||
pendingCard.style.boxShadow = 'none';
|
||||
}
|
||||
isPulsing = !isPulsing;
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// Start pulse animation when hero is visible
|
||||
const heroObserver = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
startPulse();
|
||||
} else {
|
||||
clearInterval(pulseInterval);
|
||||
if (pendingCard) {
|
||||
pendingCard.style.boxShadow = 'none';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const heroSection = document.querySelector('.hero');
|
||||
if (heroSection) {
|
||||
heroObserver.observe(heroSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Shield Pulse Animation — only when visible =====
|
||||
if (!prefersReducedMotion.matches) {
|
||||
const trustVisual = document.querySelector('.trust-visual');
|
||||
|
||||
if (trustVisual) {
|
||||
const trustObserver = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('visible');
|
||||
} else {
|
||||
entry.target.classList.remove('visible');
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.5 });
|
||||
|
||||
trustObserver.observe(trustVisual);
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user