menu
This commit is contained in:
parent
4162e6ed2a
commit
864e40e25d
@ -76,4 +76,5 @@
|
||||
1767345728- 93:01
|
||||
1767373107- 6:35
|
||||
1767376587- 12:56
|
||||
1767377746- 5:52
|
||||
1767377746- 15:56
|
||||
1767379098- 24:00
|
||||
|
||||
@ -10,32 +10,44 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="props.menu">
|
||||
<Drawer v-model:visible="menuShow" header=" " position="right" :pt="{ root: 'border-0' }">
|
||||
<template #header>
|
||||
<div class="flex flex-col">
|
||||
<div>{{ auth.user.nev }}</div>
|
||||
<div class="text-xs">{{ auth.user.email }}</div>
|
||||
</div>
|
||||
<!-- Backdrop overlay -->
|
||||
<div
|
||||
class="fixed inset-0 bg-black z-40"
|
||||
:class="backdropClass"
|
||||
:style="{ opacity: backdropOpacity }"
|
||||
@click="closeMenu"
|
||||
></div>
|
||||
|
||||
</template>
|
||||
<!-- Swipeable Drawer -->
|
||||
<div
|
||||
ref="drawerRef"
|
||||
class="fixed top-0 right-0 h-full w-72 bg-surface-0 dark:bg-surface-900 z-50 shadow-xl will-change-transform"
|
||||
:class="drawerClass"
|
||||
:style="{ transform: `translateX(${translateX}px)` }"
|
||||
>
|
||||
<div class="p-4">
|
||||
<div class="flex flex-col mb-4">
|
||||
<div class="font-medium">{{ auth.user?.nev }}</div>
|
||||
<div class="text-xs opacity-70">{{ auth.user?.email }}</div>
|
||||
</div>
|
||||
<div class="flex flex-col space-y-3 text-sm">
|
||||
<NuxtLink to="/profile">Adataim</NuxtLink>
|
||||
<NuxtLink to="/profile" @click="closeMenu">Adataim</NuxtLink>
|
||||
<Divider />
|
||||
<NuxtLink :to="'/page/' + p.id" v-for="p in config?.config.menu">{{ p.label }}</NuxtLink>
|
||||
<!-- <NuxtLink to="/page/72">GYIK</NuxtLink>
|
||||
<NuxtLink to="/page/66">Autóbérlés feltételei</NuxtLink>
|
||||
<NuxtLink to="/page/69">Általános Szerződési Feltételek</NuxtLink>
|
||||
<NuxtLink to="/page/68">Adatvédelmi nyilatkozat</NuxtLink>
|
||||
<NuxtLink to="/page/70">Lemondási és távolmaradási feltételek</NuxtLink>
|
||||
<NuxtLink to="/page/65">Elérhetőség</NuxtLink> -->
|
||||
<NuxtLink
|
||||
:to="'/page/' + p.id"
|
||||
v-for="p in config?.config.menu"
|
||||
:key="p.id"
|
||||
@click="closeMenu"
|
||||
>{{ p.label }}</NuxtLink>
|
||||
<Divider />
|
||||
<NuxtLink @click="logOut()">Kijelentketés</NuxtLink>
|
||||
|
||||
<NuxtLink @click="logOut()">Kijelentkezés</NuxtLink>
|
||||
</div>
|
||||
</Drawer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button variant="link" icon="pi pi-calendar" @click="$router.push({ path: '/' })"></Button>
|
||||
<Button variant="link" icon="pi pi-user" @click="$router.push({ path: '/profile' })"></Button>
|
||||
<Button variant="link" icon="pi pi-bars" @click="menuShow = true"></Button>
|
||||
<Button variant="link" icon="pi pi-bars" @click="openMenu"></Button>
|
||||
</div>
|
||||
<div v-if="props.title">
|
||||
{{ props.title }}
|
||||
@ -65,58 +77,177 @@ const auth = useAuthStore()
|
||||
const config = useMyConfigStore()
|
||||
|
||||
const token = useCookie('_auth')
|
||||
const menuShow = ref(false)
|
||||
const router = useRouter()
|
||||
|
||||
const isHome = computed(()=>{
|
||||
const isHome = computed(() => {
|
||||
return (route.fullPath === '/')
|
||||
})
|
||||
|
||||
// Swipe gesture handling
|
||||
const touchStartX = ref(0)
|
||||
const touchEndX = ref(0)
|
||||
const minSwipeDistance = 50
|
||||
// Drawer constants
|
||||
const DRAWER_WIDTH = 288
|
||||
const SWIPE_THRESHOLD = 80
|
||||
const EDGE_ZONE = 40
|
||||
|
||||
// Simple state
|
||||
const drawerRef = ref<HTMLElement | null>(null)
|
||||
const isOpen = ref(false)
|
||||
const isDragging = ref(false)
|
||||
const dragOffset = ref(0) // 0 = fully open position, DRAWER_WIDTH = fully closed
|
||||
const menuHistoryPushed = ref(false)
|
||||
|
||||
// Touch tracking
|
||||
let touchStartX = 0
|
||||
let touchStartY = 0
|
||||
let startedFromEdge = false
|
||||
let isHorizontalSwipe: boolean | null = null
|
||||
|
||||
// Computed translate value
|
||||
const translateX = computed(() => {
|
||||
if (isDragging.value) {
|
||||
return Math.max(0, Math.min(DRAWER_WIDTH, dragOffset.value))
|
||||
}
|
||||
return isOpen.value ? 0 : DRAWER_WIDTH
|
||||
})
|
||||
|
||||
// Backdrop opacity based on position
|
||||
const backdropOpacity = computed(() => {
|
||||
const openness = 1 - (translateX.value / DRAWER_WIDTH)
|
||||
return openness * 0.5
|
||||
})
|
||||
|
||||
// Dynamic classes
|
||||
const drawerClass = computed(() => ({
|
||||
'transition-transform duration-300 ease-out': !isDragging.value,
|
||||
'pointer-events-none': !isOpen.value && !isDragging.value
|
||||
}))
|
||||
|
||||
const backdropClass = computed(() => ({
|
||||
'transition-opacity duration-300': !isDragging.value,
|
||||
'pointer-events-none': backdropOpacity.value <= 0
|
||||
}))
|
||||
|
||||
function openMenu() {
|
||||
isOpen.value = true
|
||||
if (!menuHistoryPushed.value) {
|
||||
window.history.pushState({ menuOpen: true }, '')
|
||||
menuHistoryPushed.value = true
|
||||
}
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
isOpen.value = false
|
||||
if (menuHistoryPushed.value) {
|
||||
menuHistoryPushed.value = false
|
||||
window.history.back()
|
||||
}
|
||||
}
|
||||
|
||||
function closeMenuWithoutHistory() {
|
||||
isOpen.value = false
|
||||
menuHistoryPushed.value = false
|
||||
}
|
||||
|
||||
function handlePopState() {
|
||||
if (isOpen.value) {
|
||||
closeMenuWithoutHistory()
|
||||
}
|
||||
}
|
||||
|
||||
function handleTouchStart(e: TouchEvent) {
|
||||
touchStartX.value = e.touches[0].clientX
|
||||
}
|
||||
const touch = e.touches[0]
|
||||
touchStartX = touch.clientX
|
||||
touchStartY = touch.clientY
|
||||
isHorizontalSwipe = null
|
||||
|
||||
function handleTouchEnd(e: TouchEvent) {
|
||||
touchEndX.value = e.changedTouches[0].clientX
|
||||
handleSwipe()
|
||||
}
|
||||
|
||||
function handleSwipe() {
|
||||
const swipeDistance = touchEndX.value - touchStartX.value
|
||||
const screenWidth = window.innerWidth
|
||||
startedFromEdge = touchStartX > screenWidth - EDGE_ZONE
|
||||
|
||||
// Swipe left (from right edge) -> open menu
|
||||
if (swipeDistance < -minSwipeDistance && touchStartX.value > screenWidth - 50) {
|
||||
if (props.menu) {
|
||||
menuShow.value = true
|
||||
if (isOpen.value) {
|
||||
dragOffset.value = 0
|
||||
} else if (startedFromEdge) {
|
||||
dragOffset.value = DRAWER_WIDTH
|
||||
}
|
||||
}
|
||||
|
||||
function handleTouchMove(e: TouchEvent) {
|
||||
if (!isOpen.value && !startedFromEdge) return
|
||||
|
||||
const touch = e.touches[0]
|
||||
const deltaX = touch.clientX - touchStartX
|
||||
const deltaY = touch.clientY - touchStartY
|
||||
|
||||
// Determine swipe direction on first significant movement
|
||||
if (isHorizontalSwipe === null && (Math.abs(deltaX) > 10 || Math.abs(deltaY) > 10)) {
|
||||
isHorizontalSwipe = Math.abs(deltaX) > Math.abs(deltaY)
|
||||
}
|
||||
|
||||
if (!isHorizontalSwipe) return
|
||||
|
||||
// Start dragging
|
||||
if (!isDragging.value) {
|
||||
if (isOpen.value && deltaX > 0) {
|
||||
isDragging.value = true
|
||||
} else if (startedFromEdge && deltaX < 0) {
|
||||
isDragging.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// Swipe right -> close menu (if open)
|
||||
if (swipeDistance > minSwipeDistance && menuShow.value) {
|
||||
menuShow.value = false
|
||||
if (isDragging.value) {
|
||||
if (isOpen.value) {
|
||||
// Dragging to close: deltaX > 0 means moving right
|
||||
dragOffset.value = Math.max(0, deltaX)
|
||||
} else {
|
||||
// Dragging to open: deltaX < 0 means moving left
|
||||
dragOffset.value = DRAWER_WIDTH + deltaX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleTouchEnd() {
|
||||
if (!isDragging.value) {
|
||||
startedFromEdge = false
|
||||
isHorizontalSwipe = null
|
||||
return
|
||||
}
|
||||
|
||||
const currentOffset = dragOffset.value
|
||||
|
||||
if (isOpen.value) {
|
||||
// Was open - check if should close
|
||||
if (currentOffset > SWIPE_THRESHOLD) {
|
||||
closeMenu()
|
||||
}
|
||||
} else {
|
||||
// Was closed - check if should open
|
||||
if (currentOffset < DRAWER_WIDTH - SWIPE_THRESHOLD) {
|
||||
openMenu()
|
||||
}
|
||||
}
|
||||
|
||||
// Reset
|
||||
isDragging.value = false
|
||||
startedFromEdge = false
|
||||
isHorizontalSwipe = null
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('touchstart', handleTouchStart, { passive: true })
|
||||
document.addEventListener('touchmove', handleTouchMove, { passive: true })
|
||||
document.addEventListener('touchend', handleTouchEnd, { passive: true })
|
||||
window.addEventListener('popstate', handlePopState)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('touchstart', handleTouchStart)
|
||||
document.removeEventListener('touchmove', handleTouchMove)
|
||||
document.removeEventListener('touchend', handleTouchEnd)
|
||||
window.removeEventListener('popstate', handlePopState)
|
||||
})
|
||||
|
||||
function logOut(){
|
||||
function logOut() {
|
||||
token.value = null
|
||||
auth.user = null
|
||||
router.push({path:'/login'})
|
||||
router.push({ path: '/login' })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex gap-2 p-3 w-full justify-between h-1 fixed bg-surface-50 dark:bg-surface-950 z-10 top-12">
|
||||
<div class="flex gap-2 p-3 w-full justify-between h-1 fixed bg-surface-50 dark:bg-surface-950 top-12">
|
||||
<div v-for="i in 8" :class="inidactorClass(i)" style="padding: 2px;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user