Added About Page
This commit is contained in:
@@ -3,29 +3,25 @@
|
||||
<header class="header">
|
||||
<section class="navContainer">
|
||||
<nav class="nav">
|
||||
<div class="nav-brand">Dr Edgy Adventures</div>
|
||||
<div class="nav-brand">
|
||||
<Link href="/">
|
||||
<img src="/img/logos/logo_main.png" alt="Dr Edgy Logo" style="height:5vh; width:auto;" />
|
||||
</Link>
|
||||
</div>
|
||||
<button class="mobile-menu-btn">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="nav-menu">
|
||||
<a href="/about" class="nav-link">About</a>
|
||||
<a href="#contact" class="nav-link">Contact</a>
|
||||
<div
|
||||
class="dropdown"
|
||||
:class="{ open: dropdownOpen }"
|
||||
>
|
||||
<Link href="/about" @click="dropdownOpen = false" class="nav-link">About</Link>
|
||||
<div class="dropdown" ref="dropdownRef" :class="{ open: dropdownOpen }">
|
||||
<button
|
||||
class="dropdown-toggle nav-link"
|
||||
@click="dropdownOpen = !dropdownOpen"
|
||||
@click.stop="dropdownOpen = !dropdownOpen"
|
||||
>
|
||||
Adventures
|
||||
<svg
|
||||
class="dropdown-icon"
|
||||
width="16" height="16" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2"
|
||||
>
|
||||
<svg class="dropdown-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6,9 12,15 18,9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
@@ -47,36 +43,52 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, computed, ref } from 'vue';
|
||||
import { usePage} from "@inertiajs/vue3";
|
||||
import {GlobalProperties} from "@/types";
|
||||
import { usePage } from "@inertiajs/vue3";
|
||||
import { GlobalProperties } from "@/types";
|
||||
import { Link } from '@inertiajs/vue3';
|
||||
|
||||
const { continents_with_tours } = usePage().props as unknown as GlobalProperties
|
||||
const { continents_with_tours } = usePage().props as unknown as GlobalProperties;
|
||||
|
||||
const dropdownOpen = ref(false)
|
||||
const dropdownOpen = ref(false);
|
||||
const windowWidth = ref(window.innerWidth);
|
||||
const dropdownRef = ref<HTMLElement | null>(null);
|
||||
|
||||
|
||||
onMounted(() =>{
|
||||
initDropdown();
|
||||
initHeaderScroll()
|
||||
initMobileMenu()
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
});
|
||||
|
||||
|
||||
const isDropdownVisible = computed(() => {
|
||||
return dropdownOpen.value || windowWidth.value < 768;
|
||||
});
|
||||
const isDropdownVisible = computed(() => dropdownOpen.value || windowWidth.value < 768);
|
||||
|
||||
const handleResize = () => {
|
||||
windowWidth.value = window.innerWidth;
|
||||
};
|
||||
|
||||
// Close when clicking outside (desktop only)
|
||||
const handleClickOutside = (e: Event) => {
|
||||
if (!dropdownRef.value) return;
|
||||
if (windowWidth.value < 768) return; // on mobile we show inline; skip closing here
|
||||
|
||||
// Support composedPath for shadow DOM correctness
|
||||
const path = (e as MouseEvent).composedPath?.();
|
||||
const clickedInside = path ? path.includes(dropdownRef.value) : dropdownRef.value.contains(e.target as Node);
|
||||
|
||||
if (!clickedInside) {
|
||||
dropdownOpen.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleEsc = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') dropdownOpen.value = false;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initMobileMenu(); // keep your mobile menu init
|
||||
window.addEventListener('resize', handleResize);
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
document.addEventListener('keydown', handleEsc);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
document.removeEventListener('keydown', handleEsc);
|
||||
});
|
||||
|
||||
// Mobile menu functionality
|
||||
const initMobileMenu = (): void => {
|
||||
@@ -85,50 +97,21 @@ const initMobileMenu = (): void => {
|
||||
|
||||
if (!mobileMenuBtn || !navMenu) return;
|
||||
|
||||
// Toggle menu open/close
|
||||
mobileMenuBtn.addEventListener('click', () => {
|
||||
navMenu.classList.toggle('open');
|
||||
mobileMenuBtn.classList.toggle('open');
|
||||
});
|
||||
};
|
||||
|
||||
// Header background on scroll
|
||||
const initHeaderScroll = (): void => {
|
||||
const header = document.querySelector('.header') as HTMLElement | null;
|
||||
if (!header) return;
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
if (window.scrollY > 100) {
|
||||
header.classList.add('scrolled');
|
||||
} else {
|
||||
header.classList.remove('scrolled');
|
||||
}
|
||||
// Close menu when a link is clicked
|
||||
navMenu.querySelectorAll('.nav-link').forEach(link => {
|
||||
link.addEventListener('click', () => {
|
||||
navMenu.classList.remove('open');
|
||||
mobileMenuBtn.classList.remove('open');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const initDropdown = (): void => {
|
||||
const dropdown = document.querySelector('.dropdown') as HTMLElement | null;
|
||||
const dropdownToggle = dropdown?.querySelector('.dropdown-toggle') as HTMLElement | null;
|
||||
|
||||
if (!dropdown || !dropdownToggle) return;
|
||||
|
||||
dropdownToggle.addEventListener('click', (e: Event) => {
|
||||
e.preventDefault();
|
||||
dropdown.classList.toggle('open');
|
||||
});
|
||||
|
||||
// Close dropdown when clicking outside
|
||||
document.addEventListener('click', (e: Event) => {
|
||||
if (!dropdown.contains(e.target as Node)) {
|
||||
dropdown.classList.remove('open');
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
dropdown.classList.remove('open');
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -208,20 +191,9 @@ const initDropdown = (): void => {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
/* padding / width handled in the desktop guard above */
|
||||
}
|
||||
|
||||
/* brand */
|
||||
.nav-brand {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
background: var(--gradient-adventure);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
/* links container (desktop default) */
|
||||
.nav-menu {
|
||||
display: flex;
|
||||
@@ -359,6 +331,8 @@ const initDropdown = (): void => {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.nav-menu.open {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
@@ -370,6 +344,20 @@ const initDropdown = (): void => {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.nav-brand {
|
||||
position:relative;
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 90dvw;
|
||||
}
|
||||
|
||||
.nav-brand img {
|
||||
display: block;
|
||||
margin-left: calc(10dvw / 2);
|
||||
}
|
||||
|
||||
/* Dropdown in mobile: behave as inline sublist */
|
||||
.dropdown {
|
||||
width: 100%;
|
||||
@@ -408,6 +396,7 @@ const initDropdown = (): void => {
|
||||
|
||||
.mobile-menu-btn {
|
||||
display: flex;
|
||||
width: 10dvw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user