globetrotter-ai / script.js
alkiskoudounas's picture
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();
}
});
}
});