Files
atahan/app/components/home/MainMenuArea.vue
Beyhan Oğur 763b147cc3 first commit
2026-04-26 22:04:35 +03:00

277 lines
7.8 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>