Initial import of HarborSmith website
Some checks failed
build-website / build (push) Failing after 1m2s

This commit is contained in:
2025-09-18 22:20:01 +02:00
commit ec72c5d62b
168 changed files with 65020 additions and 0 deletions

View File

@@ -0,0 +1,375 @@
// 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">&times;</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);
});
});
});