// Wait for DOM to fully load
document.addEventListener('DOMContentLoaded', () => {
// Initialize the SPA
initApp();
});
// Main application initialization
function initApp() {
// Initialize theme mode
initThemeMode();
// Initialize mobile menu
initMobileMenu();
// Initialize navigation
initNavigation();
// Initialize project filters
initProjectFilters();
// Initialize contact form
initContactForm();
// Initialize video player
initVideoPlayer();
}
// Theme mode toggling functionality
function initThemeMode() {
const themeToggleBtn = document.getElementById('theme-toggle-btn');
const body = document.body;
// Check if user has a saved preference
const savedTheme = localStorage.getItem('theme');
// Check for saved theme or system preference
if (savedTheme === 'dark' || (!savedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
body.classList.add('dark-mode');
} else {
body.classList.add('light-mode');
}
// Add click event to theme toggle button
themeToggleBtn.addEventListener('click', () => {
// Toggle dark/light mode
body.classList.toggle('dark-mode');
body.classList.toggle('light-mode');
// Save preference
if (body.classList.contains('dark-mode')) {
localStorage.setItem('theme', 'dark');
} else {
localStorage.setItem('theme', 'light');
}
});
}
// Mobile menu functionality
function initMobileMenu() {
const menuToggleBtn = document.getElementById('menu-toggle-btn');
const nav = document.querySelector('nav');
const navLinks = document.querySelectorAll('nav ul li a');
// Toggle menu on button click
menuToggleBtn.addEventListener('click', () => {
nav.classList.toggle('active');
// Change icon based on menu state
if (nav.classList.contains('active')) {
menuToggleBtn.innerHTML = '';
} else {
menuToggleBtn.innerHTML = '';
}
});
// Close menu when clicking on a link
navLinks.forEach(link => {
link.addEventListener('click', () => {
nav.classList.remove('active');
menuToggleBtn.innerHTML = '';
});
});
// Close menu on window resize (if in desktop mode)
window.addEventListener('resize', () => {
if (window.innerWidth > 768 && nav.classList.contains('active')) {
nav.classList.remove('active');
menuToggleBtn.innerHTML = '';
}
});
}
// Navigation functionality (smooth scrolling & active links)
function initNavigation() {
const navLinks = document.querySelectorAll('nav ul li a');
const sections = document.querySelectorAll('section');
// Function to set the active link
function setActiveLink() {
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop - 100;
const sectionHeight = section.offsetHeight;
if (window.scrollY >= sectionTop && window.scrollY < sectionTop + sectionHeight) {
current = section.getAttribute('id');
}
});
navLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href') === `#${current}`) {
link.classList.add('active');
}
});
}
// Set active link on scroll
window.addEventListener('scroll', setActiveLink);
// Set active link on page load
setActiveLink();
// Smooth scrolling for navigation links
navLinks.forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const targetId = link.getAttribute('href');
const targetSection = document.querySelector(targetId);
if (targetSection) {
window.scrollTo({
top: targetSection.offsetTop - 80,
behavior: 'smooth'
});
}
});
});
}
// Project filters functionality
function initProjectFilters() {
const filterBtns = document.querySelectorAll('.filter-btn');
const projectCards = document.querySelectorAll('.project-card');
// Default show all projects
filterProjects('all');
// Add click events to filter buttons
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
// Remove active class from all buttons
filterBtns.forEach(btn => btn.classList.remove('active'));
// Add active class to clicked button
btn.classList.add('active');
// Get filter value
const filterValue = btn.getAttribute('data-filter');
// Filter projects
filterProjects(filterValue);
});
});
// Filter projects function
function filterProjects(filter) {
projectCards.forEach(card => {
if (filter === 'all' || card.getAttribute('data-category') === filter) {
card.style.display = 'block';
// Add animation
setTimeout(() => {
card.style.opacity = '1';
card.style.transform = 'translateY(0)';
}, 100);
} else {
card.style.opacity = '0';
card.style.transform = 'translateY(20px)';
// Hide after animation completes
setTimeout(() => {
card.style.display = 'none';
}, 300);
}
});
}
}
// Contact form functionality
function initContactForm() {
const contactForm = document.getElementById('contactForm');
if (contactForm) {
contactForm.addEventListener('submit', (e) => {
e.preventDefault();
// Get form data
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
const subject = document.getElementById('subject').value;
const message = document.getElementById('message').value;
// Validate form (simple validation)
if (name.trim() === '' || email.trim() === '' || subject.trim() === '' || message.trim() === '') {
alert('กรุณากรอกข้อมูลให้ครบทุกช่อง');
return;
}
// In a real application, you would send this data to a server
// For this demo, we'll just show a success message
alert(`ขอบคุณ ${name} สำหรับข้อความของคุณ! เราจะติดต่อกลับโดยเร็วที่สุด`);
// Clear form
contactForm.reset();
});
}
}
// Helper function to animate elements on scroll
function animateOnScroll() {
const elements = document.querySelectorAll('.animate-on-scroll');
elements.forEach(element => {
const elementPosition = element.getBoundingClientRect().top;
const windowHeight = window.innerHeight;
if (elementPosition < windowHeight - 100) {
element.classList.add('animated');
}
});
}
// Call animate on scroll function on scroll
window.addEventListener('scroll', animateOnScroll);
// Video player functionality
function initVideoPlayer() {
const videoElement = document.getElementById('showcase-video');
if (videoElement) {
// Add video play/pause functionality
videoElement.addEventListener('click', () => {
if (videoElement.paused) {
videoElement.play();
} else {
videoElement.pause();
}
});
// Add keyboard controls for the video
document.addEventListener('keydown', (e) => {
if (videoElement) {
// Only handle keyboard events when video is in viewport
const rect = videoElement.getBoundingClientRect();
const isInViewport = (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
if (isInViewport) {
// Space bar to play/pause
if (e.code === 'Space') {
e.preventDefault();
if (videoElement.paused) {
videoElement.play();
} else {
videoElement.pause();
}
}
// Arrow left/right to seek backward/forward
if (e.code === 'ArrowLeft') {
videoElement.currentTime = Math.max(0, videoElement.currentTime - 5);
}
if (e.code === 'ArrowRight') {
videoElement.currentTime = Math.min(videoElement.duration, videoElement.currentTime + 5);
}
// M key to mute/unmute
if (e.code === 'KeyM') {
videoElement.muted = !videoElement.muted;
}
}
}
});
// Pause video when it's not in viewport to save resources
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (!entry.isIntersecting && !videoElement.paused) {
videoElement.pause();
}
});
}, {threshold: 0.2});
observer.observe(videoElement);
}
}