375 lines
13 KiB
JavaScript
375 lines
13 KiB
JavaScript
|
|
// Bento Grid Layout JavaScript
|
||
|
|
|
||
|
|
document.addEventListener('DOMContentLoaded', function() {
|
||
|
|
// Menu Toggle
|
||
|
|
const menuToggle = document.getElementById('menuToggle');
|
||
|
|
const menuOverlay = document.getElementById('menuOverlay');
|
||
|
|
const menuClose = document.getElementById('menuClose');
|
||
|
|
|
||
|
|
menuToggle.addEventListener('click', () => {
|
||
|
|
menuOverlay.classList.add('active');
|
||
|
|
});
|
||
|
|
|
||
|
|
menuClose.addEventListener('click', () => {
|
||
|
|
menuOverlay.classList.remove('active');
|
||
|
|
});
|
||
|
|
|
||
|
|
// Filter Toggle
|
||
|
|
const filterToggle = document.getElementById('filterToggle');
|
||
|
|
const filterBar = document.getElementById('filterBar');
|
||
|
|
|
||
|
|
filterToggle.addEventListener('click', () => {
|
||
|
|
filterBar.classList.toggle('active');
|
||
|
|
});
|
||
|
|
|
||
|
|
// Filter Functionality
|
||
|
|
const filterChips = document.querySelectorAll('.filter-chip');
|
||
|
|
const bentoTiles = document.querySelectorAll('.bento-tile');
|
||
|
|
|
||
|
|
filterChips.forEach(chip => {
|
||
|
|
chip.addEventListener('click', () => {
|
||
|
|
// Update active state
|
||
|
|
filterChips.forEach(c => c.classList.remove('active'));
|
||
|
|
chip.classList.add('active');
|
||
|
|
|
||
|
|
const filter = chip.dataset.filter;
|
||
|
|
|
||
|
|
// Filter tiles
|
||
|
|
bentoTiles.forEach(tile => {
|
||
|
|
if (filter === 'all' || tile.dataset.category === filter) {
|
||
|
|
tile.classList.remove('hiding');
|
||
|
|
tile.classList.add('showing');
|
||
|
|
} else {
|
||
|
|
tile.classList.add('hiding');
|
||
|
|
tile.classList.remove('showing');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// FAB Menu
|
||
|
|
const fabBtn = document.getElementById('fabBtn');
|
||
|
|
const fabMenu = document.getElementById('fabMenu');
|
||
|
|
|
||
|
|
fabBtn.addEventListener('click', () => {
|
||
|
|
fabMenu.classList.toggle('active');
|
||
|
|
});
|
||
|
|
|
||
|
|
// FAB Options
|
||
|
|
const fabOptions = document.querySelectorAll('.fab-option');
|
||
|
|
|
||
|
|
fabOptions.forEach(option => {
|
||
|
|
option.addEventListener('click', () => {
|
||
|
|
const action = option.dataset.action;
|
||
|
|
|
||
|
|
switch(action) {
|
||
|
|
case 'chat':
|
||
|
|
alert('Opening chat...');
|
||
|
|
break;
|
||
|
|
case 'call':
|
||
|
|
window.location.href = 'tel:4155550123';
|
||
|
|
break;
|
||
|
|
case 'book':
|
||
|
|
window.location.href = 'charter.html';
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
fabMenu.classList.remove('active');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Quick View for Yachts
|
||
|
|
const quickViewBtns = document.querySelectorAll('.quick-view-btn');
|
||
|
|
|
||
|
|
quickViewBtns.forEach(btn => {
|
||
|
|
btn.addEventListener('click', (e) => {
|
||
|
|
e.stopPropagation();
|
||
|
|
const yachtTile = btn.closest('.tile-yacht');
|
||
|
|
const yachtName = yachtTile.querySelector('.yacht-name').textContent;
|
||
|
|
|
||
|
|
// Create modal
|
||
|
|
const modal = document.createElement('div');
|
||
|
|
modal.className = 'yacht-modal';
|
||
|
|
modal.innerHTML = `
|
||
|
|
<div class="modal-content">
|
||
|
|
<button class="modal-close">×</button>
|
||
|
|
<h2>${yachtName}</h2>
|
||
|
|
<div class="modal-gallery">
|
||
|
|
<img src="${yachtTile.querySelector('img').src}" alt="${yachtName}">
|
||
|
|
</div>
|
||
|
|
<div class="modal-details">
|
||
|
|
<h3>Specifications</h3>
|
||
|
|
<ul>
|
||
|
|
<li>Length: 120ft</li>
|
||
|
|
<li>Capacity: 12 Guests</li>
|
||
|
|
<li>Cabins: 5</li>
|
||
|
|
<li>Crew: Full Professional Crew</li>
|
||
|
|
<li>Amenities: Jacuzzi, Water Toys, Full Bar</li>
|
||
|
|
</ul>
|
||
|
|
<div class="modal-actions">
|
||
|
|
<button class="btn-primary">Book Now</button>
|
||
|
|
<button class="btn-secondary">Request Info</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
|
||
|
|
document.body.appendChild(modal);
|
||
|
|
|
||
|
|
// Add styles
|
||
|
|
const modalStyles = `
|
||
|
|
.yacht-modal {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
left: 0;
|
||
|
|
right: 0;
|
||
|
|
bottom: 0;
|
||
|
|
background: rgba(0,0,0,0.8);
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
z-index: 300;
|
||
|
|
animation: fadeIn 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.modal-content {
|
||
|
|
background: white;
|
||
|
|
border-radius: 20px;
|
||
|
|
padding: 2rem;
|
||
|
|
max-width: 600px;
|
||
|
|
width: 90%;
|
||
|
|
max-height: 90vh;
|
||
|
|
overflow-y: auto;
|
||
|
|
position: relative;
|
||
|
|
animation: slideUp 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.modal-close {
|
||
|
|
position: absolute;
|
||
|
|
top: 1rem;
|
||
|
|
right: 1rem;
|
||
|
|
background: transparent;
|
||
|
|
border: none;
|
||
|
|
font-size: 2rem;
|
||
|
|
cursor: pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
.modal-gallery img {
|
||
|
|
width: 100%;
|
||
|
|
border-radius: 10px;
|
||
|
|
margin: 1rem 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.modal-details h3 {
|
||
|
|
margin: 1.5rem 0 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.modal-details ul {
|
||
|
|
list-style: none;
|
||
|
|
padding: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.modal-details li {
|
||
|
|
padding: 0.5rem 0;
|
||
|
|
border-bottom: 1px solid #e2e8f0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.modal-actions {
|
||
|
|
display: flex;
|
||
|
|
gap: 1rem;
|
||
|
|
margin-top: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.modal-actions button {
|
||
|
|
flex: 1;
|
||
|
|
padding: 0.75rem;
|
||
|
|
border-radius: 8px;
|
||
|
|
font-weight: 600;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes fadeIn {
|
||
|
|
from { opacity: 0; }
|
||
|
|
to { opacity: 1; }
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes slideUp {
|
||
|
|
from {
|
||
|
|
opacity: 0;
|
||
|
|
transform: translateY(30px);
|
||
|
|
}
|
||
|
|
to {
|
||
|
|
opacity: 1;
|
||
|
|
transform: translateY(0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
`;
|
||
|
|
|
||
|
|
if (!document.getElementById('modal-styles')) {
|
||
|
|
const styleSheet = document.createElement('style');
|
||
|
|
styleSheet.id = 'modal-styles';
|
||
|
|
styleSheet.textContent = modalStyles;
|
||
|
|
document.head.appendChild(styleSheet);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Close modal
|
||
|
|
modal.querySelector('.modal-close').addEventListener('click', () => {
|
||
|
|
modal.remove();
|
||
|
|
});
|
||
|
|
|
||
|
|
modal.addEventListener('click', (e) => {
|
||
|
|
if (e.target === modal) {
|
||
|
|
modal.remove();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Wishlist functionality
|
||
|
|
let wishlist = [];
|
||
|
|
const wishlistSidebar = document.getElementById('wishlistSidebar');
|
||
|
|
const wishlistContent = document.getElementById('wishlistContent');
|
||
|
|
|
||
|
|
// Add to wishlist buttons (would be added to tiles)
|
||
|
|
bentoTiles.forEach(tile => {
|
||
|
|
if (tile.classList.contains('tile-yacht') || tile.classList.contains('tile-experience')) {
|
||
|
|
const wishlistBtn = document.createElement('button');
|
||
|
|
wishlistBtn.className = 'wishlist-add';
|
||
|
|
wishlistBtn.innerHTML = '♡';
|
||
|
|
wishlistBtn.style.cssText = `
|
||
|
|
position: absolute;
|
||
|
|
top: 1rem;
|
||
|
|
left: 1rem;
|
||
|
|
background: white;
|
||
|
|
border: none;
|
||
|
|
width: 40px;
|
||
|
|
height: 40px;
|
||
|
|
border-radius: 50%;
|
||
|
|
font-size: 1.5rem;
|
||
|
|
cursor: pointer;
|
||
|
|
z-index: 10;
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
|
|
`;
|
||
|
|
|
||
|
|
tile.appendChild(wishlistBtn);
|
||
|
|
|
||
|
|
wishlistBtn.addEventListener('click', (e) => {
|
||
|
|
e.stopPropagation();
|
||
|
|
const itemName = tile.querySelector('h3').textContent;
|
||
|
|
|
||
|
|
if (wishlistBtn.innerHTML === '♡') {
|
||
|
|
wishlistBtn.innerHTML = '❤️';
|
||
|
|
wishlist.push(itemName);
|
||
|
|
updateWishlist();
|
||
|
|
} else {
|
||
|
|
wishlistBtn.innerHTML = '♡';
|
||
|
|
wishlist = wishlist.filter(item => item !== itemName);
|
||
|
|
updateWishlist();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
function updateWishlist() {
|
||
|
|
if (wishlist.length === 0) {
|
||
|
|
wishlistContent.innerHTML = '<p class="wishlist-empty">Select yachts and experiences to build your dream charter</p>';
|
||
|
|
} else {
|
||
|
|
wishlistContent.innerHTML = `
|
||
|
|
<h4>Selected Items (${wishlist.length})</h4>
|
||
|
|
<ul style="list-style: none; padding: 0;">
|
||
|
|
${wishlist.map(item => `
|
||
|
|
<li style="padding: 0.75rem; background: #f8fafc; margin-bottom: 0.5rem; border-radius: 8px;">
|
||
|
|
${item}
|
||
|
|
</li>
|
||
|
|
`).join('')}
|
||
|
|
</ul>
|
||
|
|
`;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Show wishlist
|
||
|
|
document.addEventListener('keydown', (e) => {
|
||
|
|
if (e.key === 'w' && e.ctrlKey) {
|
||
|
|
e.preventDefault();
|
||
|
|
wishlistSidebar.classList.toggle('active');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
document.getElementById('wishlistClose').addEventListener('click', () => {
|
||
|
|
wishlistSidebar.classList.remove('active');
|
||
|
|
});
|
||
|
|
|
||
|
|
// Parallax effect on scroll
|
||
|
|
let ticking = false;
|
||
|
|
|
||
|
|
function updateParallax() {
|
||
|
|
const scrolled = window.pageYOffset;
|
||
|
|
const heroTile = document.querySelector('.tile-hero');
|
||
|
|
|
||
|
|
if (heroTile) {
|
||
|
|
const heroVisual = heroTile.querySelector('.hero-visual');
|
||
|
|
if (heroVisual) {
|
||
|
|
heroVisual.style.transform = `translateY(${scrolled * 0.3}px)`;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ticking = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
function requestTick() {
|
||
|
|
if (!ticking) {
|
||
|
|
window.requestAnimationFrame(updateParallax);
|
||
|
|
ticking = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
window.addEventListener('scroll', requestTick);
|
||
|
|
|
||
|
|
// Auto-play/pause videos on visibility
|
||
|
|
const observer = new IntersectionObserver((entries) => {
|
||
|
|
entries.forEach(entry => {
|
||
|
|
const video = entry.target.querySelector('video');
|
||
|
|
if (video) {
|
||
|
|
if (entry.isIntersecting) {
|
||
|
|
video.play();
|
||
|
|
} else {
|
||
|
|
video.pause();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}, { threshold: 0.5 });
|
||
|
|
|
||
|
|
document.querySelectorAll('.tile-video, .tile-hero').forEach(tile => {
|
||
|
|
observer.observe(tile);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Tile click navigation
|
||
|
|
bentoTiles.forEach(tile => {
|
||
|
|
if (!tile.classList.contains('tile-yacht')) {
|
||
|
|
tile.addEventListener('click', () => {
|
||
|
|
if (tile.classList.contains('tile-service')) {
|
||
|
|
window.location.href = 'maintenance.html';
|
||
|
|
} else if (tile.classList.contains('tile-experience')) {
|
||
|
|
window.location.href = 'charter.html';
|
||
|
|
} else if (tile.classList.contains('tile-cta')) {
|
||
|
|
window.location.href = 'charter.html';
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// Smooth hover effects
|
||
|
|
bentoTiles.forEach(tile => {
|
||
|
|
tile.addEventListener('mouseenter', () => {
|
||
|
|
tile.style.zIndex = '10';
|
||
|
|
});
|
||
|
|
|
||
|
|
tile.addEventListener('mouseleave', () => {
|
||
|
|
setTimeout(() => {
|
||
|
|
tile.style.zIndex = '';
|
||
|
|
}, 300);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|