2024-12-06 21:20:27 +02:00
|
|
|
<template>
|
2024-12-07 22:37:32 +02:00
|
|
|
<div
|
|
|
|
|
class="grid h-full sm:grid-rows-[auto_1fr_auto] grid-rows-[1fr_auto_auto] overflow-hidden touch-none"
|
|
|
|
|
>
|
2024-12-07 01:33:10 +02:00
|
|
|
<div
|
2024-12-07 23:18:32 +02:00
|
|
|
class="flex overflow-hidden overflow-y-auto pb-safe-or-4 sm:pt-safe px-4 overscroll-contain touch-manipulation"
|
2024-12-07 01:33:10 +02:00
|
|
|
ref="contentScrollContainer"
|
|
|
|
|
>
|
|
|
|
|
<div class="sm:max-w-prose grid grid-cols-1 mx-auto my-5 w-full">
|
|
|
|
|
<slot name="default" v-bind:scrollToBottom />
|
2024-12-06 22:34:49 +02:00
|
|
|
</div>
|
2024-12-06 21:20:27 +02:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<slot name="footer">
|
|
|
|
|
<footer
|
|
|
|
|
v-if="!slots.footer"
|
|
|
|
|
class="bg-gray-100 text-center py-1.5 border-t text-xs sm:text-base text-gray-700 sm:order-last sm:pb-safe-or-1.5"
|
|
|
|
|
>
|
|
|
|
|
<span class="text-nowrap">Сделайте НаСвязи удобнее.</span>
|
|
|
|
|
<span> </span>
|
|
|
|
|
<span class="text-nowrap">
|
|
|
|
|
Будем рады
|
|
|
|
|
<a href="/donate" class="underline underline-offset-2">вашей поддержке</a>
|
|
|
|
|
</span>
|
|
|
|
|
</footer>
|
|
|
|
|
</slot>
|
|
|
|
|
|
|
|
|
|
<TabBar />
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2024-12-07 01:33:10 +02:00
|
|
|
import { useTemplateRef } from 'vue'
|
|
|
|
|
|
2024-12-06 21:20:27 +02:00
|
|
|
const slots = defineSlots<{
|
2024-12-07 01:33:10 +02:00
|
|
|
default?: (slotBindings: { scrollToBottom: typeof scrollToBottom }) => void
|
2024-12-06 21:20:27 +02:00
|
|
|
footer?: () => void
|
|
|
|
|
}>()
|
|
|
|
|
|
2024-12-07 01:33:10 +02:00
|
|
|
const contentScrollContainerRef = useTemplateRef('contentScrollContainer')
|
|
|
|
|
|
|
|
|
|
const scrollToBottom = () => {
|
|
|
|
|
if (contentScrollContainerRef.value) {
|
|
|
|
|
contentScrollContainerRef.value.scrollTop = contentScrollContainerRef.value.scrollHeight
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-07 22:37:32 +02:00
|
|
|
// Устанавливаем корректную высоту при загрузке и изменении размера окна
|
|
|
|
|
const onresize = () => {
|
|
|
|
|
document.documentElement.style.setProperty(
|
|
|
|
|
'--visual-viewport-offset-top',
|
|
|
|
|
`${visualViewport!.offsetTop!}px`,
|
|
|
|
|
)
|
|
|
|
|
document.documentElement.style.setProperty(
|
|
|
|
|
'--visual-viewport-height',
|
|
|
|
|
`${visualViewport!.height}px`,
|
|
|
|
|
)
|
|
|
|
|
if (document.activeElement) {
|
|
|
|
|
if ('scrollIntoViewIfNeeded' in document.activeElement) {
|
|
|
|
|
;(document.activeElement.scrollIntoViewIfNeeded as (options?: ScrollIntoViewOptions) => void)(
|
|
|
|
|
{
|
|
|
|
|
block: 'center',
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
document.activeElement.scrollIntoView({ block: 'center' })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-07 23:18:32 +02:00
|
|
|
|
|
|
|
|
function preventScroll(e: TouchEvent) {
|
|
|
|
|
if (
|
|
|
|
|
contentScrollContainerRef.value &&
|
|
|
|
|
contentScrollContainerRef.value.scrollHeight <= contentScrollContainerRef.value.clientHeight
|
|
|
|
|
) {
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-07 22:37:32 +02:00
|
|
|
|
2024-12-06 22:34:49 +02:00
|
|
|
const layoutPageHead = useHead({
|
2024-12-07 22:37:32 +02:00
|
|
|
htmlAttrs: { class: 'overflow-hidden overscroll-none touch-none fix-layout-scrolling' },
|
|
|
|
|
bodyAttrs: { class: 'overflow-hidden overscroll-none touch-none' },
|
2024-12-06 22:34:49 +02:00
|
|
|
})
|
|
|
|
|
|
2024-12-07 23:18:32 +02:00
|
|
|
onMounted(() => {
|
|
|
|
|
visualViewport?.addEventListener('resize', onresize, { passive: true })
|
|
|
|
|
contentScrollContainerRef.value!.addEventListener('touchmove', preventScroll, { passive: false })
|
|
|
|
|
})
|
|
|
|
|
|
2024-12-07 22:37:32 +02:00
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
layoutPageHead?.dispose()
|
2024-12-07 23:18:32 +02:00
|
|
|
visualViewport?.removeEventListener('resize', onresize)
|
2024-12-07 22:37:32 +02:00
|
|
|
document.documentElement.style.removeProperty('--visual-viewport-offset-top')
|
|
|
|
|
document.documentElement.style.removeProperty('--visual-viewport-height')
|
2024-12-07 23:18:32 +02:00
|
|
|
contentScrollContainerRef.value!.removeEventListener('touchmove', preventScroll)
|
2024-12-07 22:37:32 +02:00
|
|
|
})
|
2024-12-06 22:34:49 +02:00
|
|
|
</script>
|
2024-12-07 22:37:32 +02:00
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
::v-global(html.fix-layout-scrolling) {
|
|
|
|
|
--visual-viewport-height: 100dvh;
|
|
|
|
|
--visual-viewport-offset-top: 0px;
|
|
|
|
|
position: fixed;
|
|
|
|
|
width: 100dvw;
|
|
|
|
|
height: var(--visual-viewport-height);
|
|
|
|
|
top: var(--visual-viewport-offset-top);
|
|
|
|
|
bottom: 0;
|
|
|
|
|
}
|
|
|
|
|
</style>
|