Compare commits

...

2 Commits

Author SHA1 Message Date
864e40e25d menu 2026-01-02 20:02:45 +01:00
4162e6ed2a sweep menü 2026-01-02 19:22:14 +01:00
3 changed files with 205 additions and 32 deletions

View File

@ -76,4 +76,5 @@
1767345728- 93:01 1767345728- 93:01
1767373107- 6:35 1767373107- 6:35
1767376587- 12:56 1767376587- 12:56
1767377746- 3:22 1767377746- 15:56
1767379098- 24:00

View File

@ -10,32 +10,44 @@
</div> </div>
</div> </div>
<div v-if="props.menu"> <div v-if="props.menu">
<Drawer v-model:visible="menuShow" header=" " position="right" :pt="{ root: 'border-0' }"> <!-- Backdrop overlay -->
<template #header> <div
<div class="flex flex-col"> class="fixed inset-0 bg-black z-40"
<div>{{ auth.user.nev }}</div> :class="backdropClass"
<div class="text-xs">{{ auth.user.email }}</div> :style="{ opacity: backdropOpacity }"
@click="closeMenu"
></div>
<!-- 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" @click="closeMenu">Adataim</NuxtLink>
<Divider />
<NuxtLink
:to="'/page/' + p.id"
v-for="p in config?.config.menu"
:key="p.id"
@click="closeMenu"
>{{ p.label }}</NuxtLink>
<Divider />
<NuxtLink @click="logOut()">Kijelentkezés</NuxtLink>
</div> </div>
</template>
<div class="flex flex-col space-y-3 text-sm">
<NuxtLink to="/profile">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> -->
<Divider />
<NuxtLink @click="logOut()">Kijelentketés</NuxtLink>
</div> </div>
</Drawer> </div>
<Button variant="link" icon="pi pi-calendar" @click="$router.push({ path: '/' })"></Button> <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-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>
<div v-if="props.title"> <div v-if="props.title">
{{ props.title }} {{ props.title }}
@ -65,17 +77,177 @@ const auth = useAuthStore()
const config = useMyConfigStore() const config = useMyConfigStore()
const token = useCookie('_auth') const token = useCookie('_auth')
const menuShow = ref()
const router = useRouter() const router = useRouter()
const isHome = computed(()=>{ const isHome = computed(() => {
return (route.fullPath === '/') return (route.fullPath === '/')
}) })
function logOut(){ // Drawer constants
token.value = null const DRAWER_WIDTH = 288
auth.user = null const SWIPE_THRESHOLD = 80
router.push({path:'/login'}) 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) {
const touch = e.touches[0]
touchStartX = touch.clientX
touchStartY = touch.clientY
isHorizontalSwipe = null
const screenWidth = window.innerWidth
startedFromEdge = touchStartX > screenWidth - EDGE_ZONE
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
}
}
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() {
token.value = null
auth.user = null
router.push({ path: '/login' })
} }
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <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 v-for="i in 8" :class="inidactorClass(i)" style="padding: 2px;">
</div> </div>
</div> </div>