Spaces:
Running
Running
I have this idea in mind. I want to build a website - later, also an app for mobile - that works as a sort of encyclopedia for traveling.
9f07ae2
verified
| // Tab functionality for itineraries | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Tab switching | |
| const tabButtons = document.querySelectorAll('.tab-button'); | |
| const tabPanes = document.querySelectorAll('.tab-pane'); | |
| tabButtons.forEach(button => { | |
| button.addEventListener('click', () => { | |
| // Remove active class from all buttons and panes | |
| tabButtons.forEach(btn => btn.classList.remove('active')); | |
| tabPanes.forEach(pane => pane.classList.remove('active')); | |
| // Add active class to clicked button | |
| button.classList.add('active'); | |
| // Show corresponding pane | |
| const tabIndex = Array.from(tabButtons).indexOf(button); | |
| tabPanes[tabIndex].classList.add('active'); | |
| }); | |
| }); | |
| // Mobile menu toggle | |
| const menuButton = document.querySelector('.md\\:hidden'); | |
| if (menuButton) { | |
| menuButton.addEventListener('click', function() { | |
| const nav = document.querySelector('nav'); | |
| nav.classList.toggle('hidden'); | |
| }); | |
| } | |
| // Smooth scrolling for anchor links | |
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { | |
| anchor.addEventListener('click', function(e) { | |
| e.preventDefault(); | |
| const target = document.querySelector(this.getAttribute('href')); | |
| if (target) { | |
| target.scrollIntoView({ | |
| behavior: 'smooth', | |
| block: 'start' | |
| }); | |
| } | |
| }); | |
| }); | |
| // Animation on scroll | |
| const observerOptions = { | |
| root: null, | |
| rootMargin: '0px', | |
| threshold: 0.1 | |
| }; | |
| const observer = new IntersectionObserver((entries) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| entry.target.classList.add('animate-fadeInUp'); | |
| } | |
| }); | |
| }, observerOptions); | |
| document.querySelectorAll('.animate-on-scroll').forEach(el => { | |
| observer.observe(el); | |
| }); | |
| }); | |
| // Animation utilities | |
| const animateOnScroll = { | |
| init() { | |
| const elements = document.querySelectorAll('[data-animate]'); | |
| const observer = new IntersectionObserver(entries => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| entry.target.classList.add('animated', entry.target.dataset.animate); | |
| observer.unobserve(entry.target); | |
| } | |
| }); | |
| }, { | |
| threshold: 0.1 | |
| }); | |
| elements.forEach(element => { | |
| observer.observe(element); | |
| }); | |
| } | |
| }; | |
| // Initialize when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', () => { | |
| animateOnScroll.init(); | |
| }); | |
| // Helper functions | |
| function toggleElement(elementId) { | |
| const element = document.getElementById(elementId); | |
| if (element) { | |
| element.classList.toggle('hidden'); | |
| } | |
| } | |
| function showNotification(message, type = 'info') { | |
| // Create notification element | |
| const notification = document.createElement('div'); | |
| notification.className = `fixed top-4 right-4 px-6 py-4 rounded-lg shadow-lg z-50 transform transition-all duration-300 ${ | |
| type === 'success' ? 'bg-green-500' : | |
| type === 'error' ? 'bg-red-500' : | |
| 'bg-blue-500' | |
| } text-white`; | |
| notification.innerHTML = ` | |
| <div class="flex items-center"> | |
| <i data-feather="${type === 'success' ? 'check-circle' : type === 'error' ? 'x-circle' : 'info'}" class="mr-2"></i> | |
| <span>${message}</span> | |
| </div> | |
| `; | |
| document.body.appendChild(notification); | |
| feather.replace(); | |
| // Auto remove after 3 seconds | |
| setTimeout(() => { | |
| notification.classList.add('opacity-0', 'translate-x-full'); | |
| setTimeout(() => { | |
| document.body.removeChild(notification); | |
| }, 300); | |
| }, 3000); | |
| } | |
| // Form validation example | |
| function validateSearchForm() { | |
| const input = document.querySelector('input[type="text"]'); | |
| if (input && input.value.trim() === '') { | |
| showNotification('Please describe your dream vacation', 'error'); | |
| return false; | |
| } | |
| return true; | |
| } | |
| // Add event listener to search form | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const searchForm = document.querySelector('input[type="text"]').closest('div').nextElementSibling; | |
| if (searchForm) { | |
| searchForm.addEventListener('click', function(e) { | |
| if (!validateSearchForm()) { | |
| e.preventDefault(); | |
| } | |
| }); | |
| } | |
| }); |