Componentalization
This commit is contained in:
17
resources/js/pages/AboutUs.vue
Normal file
17
resources/js/pages/AboutUs.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import AppLayout from "@/layouts/AppLayout.vue";
|
||||
|
||||
defineOptions({
|
||||
layout: AppLayout
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section style="position: relative;min-height: 100vh;display:flex;align-items: center;justify-content: center;">
|
||||
<v-date-picker show-adjacent-months></v-date-picker>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -29,87 +29,6 @@ defineOptions({
|
||||
})
|
||||
|
||||
// Types
|
||||
interface IntersectionObserverOptions {
|
||||
threshold?: number;
|
||||
rootMargin?: string;
|
||||
}
|
||||
|
||||
// Intersection Observer for animations
|
||||
const createIntersectionObserver = (
|
||||
callback: IntersectionObserverCallback,
|
||||
options: IntersectionObserverOptions = {}
|
||||
): IntersectionObserver => {
|
||||
const defaultOptions: IntersectionObserverOptions = {
|
||||
threshold: 0.3,
|
||||
rootMargin: '0px 0px -50px 0px'
|
||||
};
|
||||
|
||||
return new IntersectionObserver(callback, { ...defaultOptions, ...options });
|
||||
};
|
||||
|
||||
// About section animation
|
||||
const initAboutAnimation = (): void => {
|
||||
const aboutContent = document.querySelector('.about-content') as HTMLElement | null;
|
||||
if (!aboutContent) return;
|
||||
|
||||
const observer = createIntersectionObserver((entries: IntersectionObserverEntry[]) => {
|
||||
entries.forEach((entry: IntersectionObserverEntry) => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('visible');
|
||||
} else {
|
||||
entry.target.classList.remove('visible');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
observer.observe(aboutContent);
|
||||
};
|
||||
|
||||
// Featured tours animation
|
||||
const initToursAnimation = (): void => {
|
||||
const toursHeader = document.querySelector('.tours-header') as HTMLElement | null;
|
||||
const tourCards = document.querySelectorAll('.tour-card') as NodeListOf<HTMLElement>;
|
||||
|
||||
if (!toursHeader || !tourCards.length) return;
|
||||
|
||||
// Header animation
|
||||
const headerObserver = createIntersectionObserver((entries: IntersectionObserverEntry[]) => {
|
||||
entries.forEach((entry: IntersectionObserverEntry) => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('visible');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
headerObserver.observe(toursHeader);
|
||||
|
||||
// Tour cards animation with staggered effect
|
||||
const cardsObserver = createIntersectionObserver((entries: IntersectionObserverEntry[]) => {
|
||||
entries.forEach((entry: IntersectionObserverEntry) => {
|
||||
const tourCard = entry.target as HTMLElement;
|
||||
const index = parseInt(tourCard.dataset.index || '0');
|
||||
|
||||
if (entry.isIntersecting) {
|
||||
// Staggered animation when scrolling down
|
||||
setTimeout(() => {
|
||||
tourCard.classList.add('visible');
|
||||
}, index * 150);
|
||||
} else {
|
||||
// Reverse staggered animation when scrolling up
|
||||
const reverseIndex = (tourCards.length - 1) - index;
|
||||
setTimeout(() => {
|
||||
tourCard.classList.remove('visible');
|
||||
}, reverseIndex * 100);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.2 });
|
||||
|
||||
tourCards.forEach((card: HTMLElement) => {
|
||||
cardsObserver.observe(card);
|
||||
});
|
||||
};
|
||||
|
||||
// Smooth scrolling for navigation links
|
||||
const initSmoothScrolling = (): void => {
|
||||
const navLinks = document.querySelectorAll('a[href^="#"]') as NodeListOf<HTMLAnchorElement>;
|
||||
|
||||
@@ -140,87 +59,9 @@ const initSmoothScrolling = (): void => {
|
||||
});
|
||||
};
|
||||
|
||||
// Parallax effect for hero background
|
||||
const initParallax = (): void => {
|
||||
const heroBackground = document.querySelector('.hero-bg') as HTMLElement | null;
|
||||
const heroSection = document.querySelector('.hero') as HTMLElement | null;
|
||||
if (!heroBackground || !heroSection) return;
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
const scrolled = window.pageYOffset;
|
||||
const heroRect = heroSection.getBoundingClientRect();
|
||||
const heroHeight = heroSection.offsetHeight;
|
||||
|
||||
if (heroRect.bottom > 0) {
|
||||
const rate = scrolled * -0.15;
|
||||
const maxMovement = heroHeight * 0.1;
|
||||
const constrainedRate = Math.max(rate, -maxMovement);
|
||||
|
||||
heroBackground.style.transform = `translateY(${constrainedRate}px)`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Add loading animations
|
||||
const initLoadingAnimations = (): void => {
|
||||
// Add class to trigger CSS animations
|
||||
document.body.classList.add('loaded');
|
||||
|
||||
// Animate hero content
|
||||
const heroTitle = document.querySelector('.hero-title') as HTMLElement | null;
|
||||
const heroSubtitle = document.querySelector('.hero-subtitle') as HTMLElement | null;
|
||||
|
||||
if (heroTitle) {
|
||||
setTimeout(() => {
|
||||
heroTitle.style.opacity = '1';
|
||||
heroTitle.style.transform = 'translateY(0)';
|
||||
}, 300);
|
||||
}
|
||||
|
||||
if (heroSubtitle) {
|
||||
setTimeout(() => {
|
||||
heroSubtitle.style.opacity = '1';
|
||||
heroSubtitle.style.transform = 'translateY(0)';
|
||||
}, 600);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Tour card interactions
|
||||
const initTourCardInteractions = (): void => {
|
||||
const tourCards = document.querySelectorAll('.tour-card') as NodeListOf<HTMLElement>;
|
||||
|
||||
tourCards.forEach((card: HTMLElement) => {
|
||||
const bookButton = card.querySelector('.btn') as HTMLElement | null;
|
||||
|
||||
if (bookButton) {
|
||||
bookButton.addEventListener('click', () => {
|
||||
// Add your booking logic here
|
||||
alert('Booking functionality would be implemented here!');
|
||||
});
|
||||
}
|
||||
|
||||
// Add hover effects
|
||||
card.addEventListener('mouseenter', () => {
|
||||
card.style.transform = 'translateY(-8px) scale(1.02)';
|
||||
});
|
||||
|
||||
card.addEventListener('mouseleave', () => {
|
||||
if (card.classList.contains('visible')) {
|
||||
card.style.transform = 'translateY(0) rotate(0deg) scale(1)';
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Initialize all functionality when DOM is loaded
|
||||
onMounted(() => {
|
||||
initAboutAnimation();
|
||||
initToursAnimation();
|
||||
initSmoothScrolling();
|
||||
initParallax();
|
||||
initLoadingAnimations();
|
||||
initTourCardInteractions();
|
||||
});
|
||||
|
||||
// Add performance optimization
|
||||
|
||||
Reference in New Issue
Block a user