forked from Mirrors/elk
feat: pull down to close bottom nav sidebar (#2290)
This commit is contained in:
parent
57814915d6
commit
991034115b
1 changed files with 95 additions and 9 deletions
|
@ -1,9 +1,13 @@
|
|||
<script lang="ts" setup>
|
||||
import { invoke } from '@vueuse/core'
|
||||
|
||||
const modelValue = defineModel<boolean>({ required: true })
|
||||
const colorMode = useColorMode()
|
||||
|
||||
const userSettings = useUserSettings()
|
||||
|
||||
const drawerEl = ref<HTMLDivElement>()
|
||||
|
||||
function toggleVisible() {
|
||||
modelValue.value = !modelValue.value
|
||||
}
|
||||
|
@ -12,7 +16,7 @@ const buttonEl = ref<HTMLDivElement>()
|
|||
/** Close the drop-down menu if the mouse click is not on the drop-down menu button when the drop-down menu is opened */
|
||||
function clickEvent(mouse: MouseEvent) {
|
||||
if (mouse.target && !buttonEl.value?.children[0].contains(mouse.target as any)) {
|
||||
if (modelValue) {
|
||||
if (modelValue.value) {
|
||||
document.removeEventListener('click', clickEvent)
|
||||
modelValue.value = false
|
||||
}
|
||||
|
@ -23,7 +27,7 @@ function toggleDark() {
|
|||
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
|
||||
}
|
||||
|
||||
watch($$(modelValue), (val) => {
|
||||
watch(modelValue, (val) => {
|
||||
if (val && typeof document !== 'undefined')
|
||||
document.addEventListener('click', clickEvent)
|
||||
})
|
||||
|
@ -31,6 +35,80 @@ watch($$(modelValue), (val) => {
|
|||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', clickEvent)
|
||||
})
|
||||
|
||||
// Pull down to close
|
||||
const { dragging, dragDistance } = invoke(() => {
|
||||
const triggerDistance = 120
|
||||
|
||||
let scrollTop = 0
|
||||
let beforeTouchPointY = 0
|
||||
|
||||
const dragDistance = ref(0)
|
||||
const dragging = ref(false)
|
||||
|
||||
useEventListener(drawerEl, 'scroll', (e: Event) => {
|
||||
scrollTop = (e.target as HTMLDivElement).scrollTop
|
||||
|
||||
// Prevent the page from scrolling when the drawer is being dragged.
|
||||
if (dragDistance.value > 0)
|
||||
(e.target as HTMLDivElement).scrollTop = 0
|
||||
}, { passive: true })
|
||||
|
||||
useEventListener(drawerEl, 'touchstart', (e: TouchEvent) => {
|
||||
if (!modelValue.value)
|
||||
return
|
||||
|
||||
beforeTouchPointY = e.touches[0].pageY
|
||||
dragDistance.value = 0
|
||||
}, { passive: true })
|
||||
|
||||
useEventListener(drawerEl, 'touchmove', (e: TouchEvent) => {
|
||||
if (!modelValue.value)
|
||||
return
|
||||
|
||||
// Do not move the entire drawer when its contents are not scrolled to the top.
|
||||
if (scrollTop > 0 && dragDistance.value <= 0) {
|
||||
dragging.value = false
|
||||
beforeTouchPointY = e.touches[0].pageY
|
||||
return
|
||||
}
|
||||
|
||||
const { pageY } = e.touches[0]
|
||||
|
||||
// Calculate the drag distance.
|
||||
dragDistance.value += pageY - beforeTouchPointY
|
||||
if (dragDistance.value < 0)
|
||||
dragDistance.value = 0
|
||||
beforeTouchPointY = pageY
|
||||
|
||||
// Marked as dragging.
|
||||
if (dragDistance.value > 1)
|
||||
dragging.value = true
|
||||
|
||||
// Prevent the page from scrolling when the drawer is being dragged.
|
||||
if (dragDistance.value > 0) {
|
||||
if (e?.cancelable && e?.preventDefault)
|
||||
e.preventDefault()
|
||||
e?.stopPropagation()
|
||||
}
|
||||
}, { passive: true })
|
||||
|
||||
useEventListener(drawerEl, 'touchend', () => {
|
||||
if (!modelValue.value)
|
||||
return
|
||||
|
||||
if (dragDistance.value >= triggerDistance)
|
||||
modelValue.value = false
|
||||
|
||||
dragging.value = false
|
||||
// code
|
||||
}, { passive: true })
|
||||
|
||||
return {
|
||||
dragDistance,
|
||||
dragging,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -39,12 +117,12 @@ onBeforeUnmount(() => {
|
|||
|
||||
<!-- Drawer -->
|
||||
<Transition
|
||||
enter-active-class="transition duration-250 ease-out children:(transition duration-250 ease-out)"
|
||||
enter-from-class="opacity-0 children:(transform translate-y-full)"
|
||||
enter-to-class="opacity-100 children:(transform translate-y-0)"
|
||||
leave-active-class="transition duration-250 ease-in children:(transition duration-250 ease-in)"
|
||||
leave-from-class="opacity-100 children:(transform translate-y-0)"
|
||||
leave-to-class="opacity-0 children:(transform translate-y-full)"
|
||||
enter-active-class="transition duration-250 ease-out"
|
||||
enter-from-class="opacity-0 children:(translate-y-full)"
|
||||
enter-to-class="opacity-100 children:(translate-y-0)"
|
||||
leave-active-class="transition duration-250 ease-in"
|
||||
leave-from-class="opacity-100 children:(translate-y-0)"
|
||||
leave-to-class="opacity-0 children:(translate-y-full)"
|
||||
>
|
||||
<div
|
||||
v-show="modelValue"
|
||||
|
@ -56,7 +134,15 @@ onBeforeUnmount(() => {
|
|||
<!-- corresponding to issue: #106, so please don't remove it. -->
|
||||
<div absolute inset-0 opacity-0 h="[calc(100vh+0.5px)]" />
|
||||
<div
|
||||
|
||||
ref="drawerEl"
|
||||
:style="{
|
||||
transform: dragging ? `translateY(${dragDistance}px)` : '',
|
||||
}"
|
||||
:class="{
|
||||
'duration-0': dragging,
|
||||
'duration-250': !dragging,
|
||||
}"
|
||||
transition="transform ease-in"
|
||||
flex-1 min-w-48 py-6 mb="-1px"
|
||||
of-y-auto scrollbar-hide overscroll-none max-h="[calc(100vh-200px)]"
|
||||
rounded-t-lg bg="white/85 dark:neutral-900/85" backdrop-filter backdrop-blur-md
|
||||
|
|
Loading…
Reference in a new issue