first commit
This commit is contained in:
277
app/components/home/MainMenuArea.vue
Normal file
277
app/components/home/MainMenuArea.vue
Normal file
@@ -0,0 +1,277 @@
|
||||
<script setup lang="ts">
|
||||
import type { Home, Setting, MainMenu } from "~/types";
|
||||
|
||||
interface Props {
|
||||
home?: Home | null;
|
||||
setting?: Setting | null;
|
||||
menu?: MainMenu | null;
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
|
||||
const config = useRuntimeConfig()
|
||||
const apiUrl = computed(() => config.public.BASE_API_URL || 'http://127.0.0.1:8000')
|
||||
|
||||
|
||||
// Helper function to get full image URL
|
||||
const getImageUrl = (imagePath: string | null | undefined) => {
|
||||
if (!imagePath) return '/assets/images/about3.jpg'
|
||||
if (imagePath.startsWith('http')) return imagePath
|
||||
return `${apiUrl.value}${imagePath}`
|
||||
}
|
||||
|
||||
// Current active section tracking
|
||||
const route = useRoute()
|
||||
|
||||
// Initialize currentSection based on route hash (works on both server and client)
|
||||
const initializeCurrentSection = () => {
|
||||
if (route.hash) {
|
||||
return route.hash.replace('#', '')
|
||||
}
|
||||
return 'home'
|
||||
}
|
||||
|
||||
const currentSection = ref(initializeCurrentSection())
|
||||
|
||||
// Handle hash navigation for menu items
|
||||
const handleHashNavigation = (event: Event, hash: string) => {
|
||||
const route = useRoute()
|
||||
|
||||
// If we're not on the home page, navigate to home first
|
||||
if (route.path !== '/') {
|
||||
event.preventDefault()
|
||||
navigateTo('/' + hash)
|
||||
return
|
||||
}
|
||||
|
||||
// On home page, handle smooth scroll
|
||||
event.preventDefault()
|
||||
|
||||
if (import.meta.client) {
|
||||
const targetId = hash.replace('#', '')
|
||||
|
||||
// Handle home section - scroll to top
|
||||
if (targetId === 'home') {
|
||||
currentSection.value = 'home'
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
window.history.pushState(null, '', '/')
|
||||
return
|
||||
}
|
||||
|
||||
// Handle other sections
|
||||
const targetElement = document.getElementById(targetId)
|
||||
|
||||
if (targetElement) {
|
||||
// Update current section
|
||||
currentSection.value = targetId
|
||||
|
||||
// Smooth scroll to element
|
||||
targetElement.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
})
|
||||
|
||||
// Update URL hash without page jump
|
||||
window.history.pushState(null, '', hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if menu item is active
|
||||
const isMenuActive = (path: string) => {
|
||||
// Extract hash from path (e.g., "/#about" -> "about")
|
||||
const pathHash = path.includes('#') ? path.split('#')[1] : ''
|
||||
|
||||
if (import.meta.server) {
|
||||
// Server-side: URL hash kontrolü
|
||||
if (path === '/') {
|
||||
// Home is active only if there's no hash
|
||||
return route.path === '/' && !route.hash
|
||||
}
|
||||
// Other sections: check if route hash matches
|
||||
const routeHash = route.hash.replace('#', '')
|
||||
return routeHash === pathHash
|
||||
}
|
||||
|
||||
// Client-side: currentSection state kullan
|
||||
if (path === '/') {
|
||||
return currentSection.value === '' || currentSection.value === 'home'
|
||||
}
|
||||
|
||||
return currentSection.value === pathHash
|
||||
}
|
||||
|
||||
// Update current section based on scroll
|
||||
const updateCurrentSection = () => {
|
||||
if (import.meta.client) {
|
||||
const sections = ['home', 'about', 'service', 'resume', 'project-gallery', 'contact']
|
||||
const scrollPosition = window.scrollY + 100
|
||||
|
||||
for (const section of sections) {
|
||||
const element = document.getElementById(section)
|
||||
if (element) {
|
||||
const { offsetTop, offsetHeight } = element
|
||||
if (scrollPosition >= offsetTop && scrollPosition < offsetTop + offsetHeight) {
|
||||
currentSection.value = section
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default to home if no section matched
|
||||
if (scrollPosition < 100) {
|
||||
currentSection.value = 'home'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reinitialize menu on mount and route change
|
||||
onMounted(() => {
|
||||
// Add scroll listener
|
||||
window.addEventListener('scroll', updateCurrentSection)
|
||||
|
||||
// Wait for DOM to be fully ready
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
initializeMenu()
|
||||
reinitWow()
|
||||
updateCurrentSection()
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (import.meta.client) {
|
||||
window.removeEventListener('scroll', updateCurrentSection)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => route.path, () => {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
initializeMenu()
|
||||
reinitWow()
|
||||
updateCurrentSection()
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
// Also watch for hash changes
|
||||
watch(() => route.hash, (newHash) => {
|
||||
if (newHash) {
|
||||
currentSection.value = newHash.replace('#', '')
|
||||
} else {
|
||||
currentSection.value = 'home'
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
initializeMenu()
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
const initializeMenu = () => {
|
||||
if (import.meta.client && (window as any).$) {
|
||||
// Disable jQuery onePageNav plugin completely - we handle everything with Vue
|
||||
const $mainmenu = (window as any).$('#mainmenu-area')
|
||||
if ($mainmenu.length) {
|
||||
// Remove any existing onePageNav bindings
|
||||
$mainmenu.off('click.onePageNav')
|
||||
// Don't initialize onePageNav at all - Vue handles everything
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const reinitWow = () => {
|
||||
if (import.meta.client && (window as any).WOW) {
|
||||
// Only reinitialize WOW for menu items, not profile area
|
||||
const menuItems = document.querySelectorAll('#mainmenu-area li a.wow')
|
||||
menuItems.forEach((item) => {
|
||||
item.classList.remove('animated', 'fadeInUp')
|
||||
// Force reflow
|
||||
void (item as HTMLElement).offsetWidth
|
||||
item.classList.add('animated', 'fadeInUp')
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="side-menu-wrapper">
|
||||
<div class="menu-toogle-icon">
|
||||
<div id="nav-icon3">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="side-menu">
|
||||
<div class="heading-area">
|
||||
<a href="/" class="profile-photo">
|
||||
<img :src="getImageUrl(home?.image)" :alt="home?.name || 'Profile'">
|
||||
</a>
|
||||
<div class="name">
|
||||
{{ home?.name || 'Atahan Deniz' }}
|
||||
</div>
|
||||
</div>
|
||||
<ul id="mainmenu-area">
|
||||
<li :class="{ current: isMenuActive('/') }">
|
||||
<NuxtLink to="/" @click="handleHashNavigation($event, '#home')" class="wow fadeInUp" data-wow-delay="0.4s">
|
||||
<i class="fas fa-home"></i> {{ menu?.home || 'Anasayfa' }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li :class="{ current: isMenuActive('/#about') }">
|
||||
<NuxtLink to="/#about" @click="handleHashNavigation($event, '#about')" class="wow fadeInUp" data-wow-delay="0.4s">
|
||||
<i class="fas fa-user"></i> {{ menu?.about || 'Hakkımda' }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li :class="{ current: isMenuActive('/#service') }">
|
||||
<NuxtLink to="/#service" @click="handleHashNavigation($event, '#service')" class="wow fadeInUp" data-wow-delay="0.4s">
|
||||
<i class="fas fa-briefcase"></i> {{ menu?.services || 'Hizmetlerim' }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li :class="{ current: isMenuActive('/#resume') }">
|
||||
<NuxtLink to="/#resume" @click="handleHashNavigation($event, '#resume')" class="wow fadeInUp" data-wow-delay="0.4s">
|
||||
<i class="fas fa-file-alt"></i> {{ menu?.resume || 'Becerilerim' }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li :class="{ current: isMenuActive('/#project-gallery') }">
|
||||
<NuxtLink to="/#project-gallery" @click="handleHashNavigation($event, '#project-gallery')" class="wow fadeInUp" data-wow-delay="0.4s">
|
||||
<i class="fas fa-layer-group"></i> {{ menu?.portfolio || 'Portfolio' }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li :class="{ current: isMenuActive('/#contact') }">
|
||||
<NuxtLink to="/#contact" @click="handleHashNavigation($event, '#contact')" class="wow fadeInUp" data-wow-delay="0.4s">
|
||||
<i class="fas fa-check-square"></i> {{ menu?.contact || 'İletişim' }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Ensure menu items are always visible */
|
||||
#mainmenu-area li {
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
#mainmenu-area li a {
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
/* Ensure profile photo and name are always visible */
|
||||
.heading-area .profile-photo,
|
||||
.heading-area .profile-photo img,
|
||||
.heading-area .name {
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user