168 lines
6.3 KiB
JavaScript
168 lines
6.3 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
|
// Navbar Scroll Effect
|
|
const navbar = document.querySelector('.navbar');
|
|
window.addEventListener('scroll', () => {
|
|
if (navbar) {
|
|
if (window.scrollY > 50) {
|
|
navbar.classList.add('scrolled');
|
|
} else {
|
|
navbar.classList.remove('scrolled');
|
|
}
|
|
}
|
|
});
|
|
|
|
// Mobile Menu Toggle
|
|
const mobileMenuToggle = document.querySelector('.mobile-menu-toggle');
|
|
const navLinks = document.querySelector('.nav-links');
|
|
|
|
if (mobileMenuToggle) {
|
|
mobileMenuToggle.addEventListener('click', () => {
|
|
navLinks.classList.toggle('active');
|
|
const icon = mobileMenuToggle.querySelector('i');
|
|
if (navLinks.classList.contains('active')) {
|
|
icon.classList.replace('fa-bars', 'fa-times');
|
|
} else {
|
|
icon.classList.replace('fa-times', 'fa-bars');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Hero Swiper
|
|
const heroSwiper = new Swiper('.hero-swiper', {
|
|
loop: true,
|
|
effect: 'fade',
|
|
fadeEffect: {
|
|
crossFade: true
|
|
},
|
|
autoplay: {
|
|
delay: 6000,
|
|
disableOnInteraction: false,
|
|
}
|
|
});
|
|
|
|
// Portfolio Filtering
|
|
const filterBtns = document.querySelectorAll('.filter-btn');
|
|
const portfolioItems = document.querySelectorAll('.portfolio-item');
|
|
|
|
filterBtns.forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
filterBtns.forEach(b => b.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
|
|
const filterValue = btn.getAttribute('data-filter');
|
|
|
|
portfolioItems.forEach(item => {
|
|
if (filterValue === 'all' || item.classList.contains(filterValue)) {
|
|
item.style.display = 'block';
|
|
item.style.animation = 'fadeIn 0.5s ease forwards';
|
|
} else {
|
|
item.style.display = 'none';
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// Contact Form Submission
|
|
const contactForm = document.getElementById('contactForm');
|
|
const toast = document.getElementById('toast');
|
|
|
|
// Simple I18N for JS messages based on html lang attribute
|
|
const htmlLang = document.documentElement.lang || 'en';
|
|
const messages = {
|
|
en: { sending: 'Sending...', success: 'Message sent successfully!', error: 'Failed to send. Please try again.' },
|
|
zh: { sending: '发送中...', success: '消息已成功发送!', error: '发送失败,请稍后再试。' },
|
|
ja: { sending: '送信中...', success: '送信が完了しました!', error: '送信に失敗しました。' },
|
|
ko: { sending: '전송 중...', success: '메시지가 성공적으로 전송되었습니다!', error: '전송 실패. 다시 시도하십시오.' },
|
|
de: { sending: 'Senden...', success: 'Nachricht erfolgreich gesendet!', error: 'Fehler beim Senden.' },
|
|
fr: { sending: 'Envoi...', success: 'Message envoyé avec succès !', error: 'Échec de l\'envoi.' },
|
|
es: { sending: 'Enviando...', success: '¡Mensaje enviado con éxito!', error: 'Error al enviar.' },
|
|
ar: { sending: 'جاري الإرسال...', success: 'تم إرسال الرسالة بنجاح!', error: 'فشل الإرسال. يرجى المحاولة مرة أخرى.' }
|
|
};
|
|
const msg = messages[htmlLang] || messages['en'];
|
|
|
|
if (contactForm) {
|
|
contactForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const formData = new FormData(contactForm);
|
|
const submitBtn = contactForm.querySelector('.btn-submit');
|
|
const originalBtnContent = submitBtn.innerHTML;
|
|
|
|
submitBtn.disabled = true;
|
|
submitBtn.innerHTML = `<span>${msg.sending}</span> <i class="fas fa-spinner fa-spin"></i>`;
|
|
|
|
try {
|
|
const response = await fetch('contact.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
showToast(msg.success);
|
|
contactForm.reset();
|
|
} else {
|
|
showToast(msg.error + ' ' + (result.error || ''));
|
|
}
|
|
} catch (error) {
|
|
showToast(msg.error);
|
|
} finally {
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = originalBtnContent;
|
|
}
|
|
});
|
|
}
|
|
|
|
function showToast(message) {
|
|
if (!toast) return;
|
|
toast.innerText = message;
|
|
toast.style.display = 'block';
|
|
toast.style.animation = 'slideInUp 0.5s ease forwards';
|
|
|
|
setTimeout(() => {
|
|
toast.style.animation = 'slideOutDown 0.5s ease forwards';
|
|
setTimeout(() => {
|
|
toast.style.display = 'none';
|
|
}, 500);
|
|
}, 5000);
|
|
}
|
|
|
|
// Smooth scroll for nav links
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
anchor.addEventListener('click', function (e) {
|
|
if (this.hash !== "") {
|
|
e.preventDefault();
|
|
const target = document.querySelector(this.hash);
|
|
if (target) {
|
|
if (navLinks && navLinks.classList.contains('active')) {
|
|
navLinks.classList.remove('active');
|
|
const icon = mobileMenuToggle.querySelector('i');
|
|
icon.classList.replace('fa-times', 'fa-bars');
|
|
}
|
|
window.scrollTo({
|
|
top: target.offsetTop - 80,
|
|
behavior: 'smooth'
|
|
});
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
const animStyle = document.createElement('style');
|
|
animStyle.textContent = "
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(20px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
@keyframes slideInUp {
|
|
from { transform: translateY(100%); opacity: 0; }
|
|
to { transform: translateY(0); opacity: 1; }
|
|
}
|
|
@keyframes slideOutDown {
|
|
from { transform: translateY(0); opacity: 1; }
|
|
to { transform: translateY(100%); opacity: 0; }
|
|
}
|
|
";
|
|
document.head.appendChild(animStyle); |