This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="text-sm">
|
||||
<div class="text-sm pt-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<div v-if="isPending" class="w-5 h-5">
|
||||
<ProgressSpinner style="width: 100%; height: 100%" strokeWidth="8" fill="transparent" />
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
class="sm:max-w-prose mx-auto flex gap-3 px-4 pt-0 flex-col-reverse pb-4 sm:pb-safe-or-4 w-full"
|
||||
>
|
||||
<div class="sm:max-w-prose mx-auto flex gap-3 px-4 pt-0 flex-col-reverse w-full">
|
||||
<!-- Форма отправки сообщений -->
|
||||
<form @submit.prevent="sendMessage" class="flex gap-2 items-center" ref="form">
|
||||
<InputText
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<!-- shadow-md dark:shadow-lg -->
|
||||
<div
|
||||
class="sticky bottom-0 bg-white dark:bg-gray-800 shadow-md dark:shadow-lg py-safe-or-4 sm:border-b dark:sm:border-gray-700 sm:order-first sm:justify-center touch-none"
|
||||
class="sticky bottom-0 bg-white dark:bg-gray-800 sm:border-b dark:sm:border-gray-700 sm:order-first sm:justify-center touch-none px-safe"
|
||||
>
|
||||
<div
|
||||
class="flex justify-around sm:justify-between sm:gap-8 sm:px-4 sm:flex-row sm:bg-white dark:sm:bg-gray-800 sm:max-w-prose mx-auto"
|
||||
@@ -27,8 +28,8 @@ type Tab = {
|
||||
unreadCount?: number
|
||||
}
|
||||
const tabs: Tab[] = [
|
||||
{ route: ROUTE_NAMES.CREATE, label: 'Создать QR-код', icon: 'plus' },
|
||||
{ route: ROUTE_NAMES.MANAGE_DASHBOARD_QR, label: 'Мои QR-коды', icon: 'qrcode' },
|
||||
{ route: ROUTE_NAMES.CREATE, label: 'Создать QR‑код', icon: 'plus' },
|
||||
{ route: ROUTE_NAMES.MANAGE_DASHBOARD_QR, label: 'Мои QR‑коды', icon: 'qrcode' },
|
||||
{ route: ROUTE_NAMES.MANAGE_DASHBOARD_CHATS, label: 'Чаты', icon: 'comments' },
|
||||
// { to: ROUTE_NAMES., label: 'Профиль', icon: 'user' },
|
||||
]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
v-bind="$attrs"
|
||||
:href="href"
|
||||
@click="navigate"
|
||||
class="flex flex-col items-center w-full sm:flex-row sm:items-center sm:w-auto gap-1 relative"
|
||||
class="flex flex-col items-center w-full sm:flex-row sm:items-center sm:w-auto gap-1 relative pt-4 pb-safe-or-4 sm:pb-4 sm:pt-safe-or-4"
|
||||
>
|
||||
<i
|
||||
:class="[
|
||||
@@ -15,7 +15,7 @@
|
||||
]"
|
||||
></i>
|
||||
<span
|
||||
class="text-xs font-medium sm:text-base text-center"
|
||||
class="text-xs font-medium sm:text-base text-center max-w-25 sm:max-w-none"
|
||||
:class="{
|
||||
'text-primary-700 dark:text-primary-300': isActive,
|
||||
'text-gray-700 dark:text-gray-300': !isActive,
|
||||
|
||||
@@ -1,22 +1,36 @@
|
||||
<template>
|
||||
<div
|
||||
class="grid h-full sm:grid-rows-[auto_1fr_auto] grid-rows-[1fr_auto_auto] overflow-hidden touch-none"
|
||||
class="grid h-full grid-rows-[_1rem_1fr_1rem_auto_auto_] sm:grid-rows-[_auto_1rem_1fr_1rem_auto_] pt-safe sm:pb-safe overflow-hidden touch-none"
|
||||
>
|
||||
<!-- Shadow Top -->
|
||||
<div
|
||||
class="row-start-1 row-span-1 col-start-1 sm:row-start-2 relative w-full h-[1rem] bg-gradient-to-b from-black/30 sm:from-black/10 to-transparent dark:from-white/10 pointer-events-none transition-opacity duration-300"
|
||||
:class="{ 'opacity-0': !showTopShadow, 'opacity-100': showTopShadow }"
|
||||
/>
|
||||
|
||||
<!-- Content Section -->
|
||||
<div
|
||||
class="flex overflow-hidden overflow-y-auto pb-safe-or-4 sm:pt-safe px-4 overscroll-contain touch-manipulation"
|
||||
class="row-start-1 row-span-3 col-start-1 sm:row-start-2 overflow-hidden overflow-y-auto px-4 overscroll-contain touch-manipulation"
|
||||
ref="contentScrollContainer"
|
||||
@scroll="handleScroll"
|
||||
>
|
||||
<div class="sm:max-w-prose grid grid-cols-1 mx-auto my-5 w-full">
|
||||
<slot name="default" v-bind:scrollToBottom />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Shadow Bottom -->
|
||||
<div
|
||||
class="row-start-3 row-span-1 col-start-1 sm:row-start-4 relative w-full h-[1rem] bg-gradient-to-t from-black/10 to-transparent dark:from-white/10 pointer-events-none transition-opacity duration-300"
|
||||
:class="{ 'opacity-0': !showBottomShadow, 'opacity-100': showBottomShadow }"
|
||||
/>
|
||||
|
||||
<!-- Footer Section -->
|
||||
<div class="row-start-4 row-span-1 col-start-1 sm:row-start-5">
|
||||
<slot name="footer">
|
||||
<footer
|
||||
v-if="!slots.footer"
|
||||
class="bg-gray-100 dark:bg-gray-800 text-center py-1.5 border-t dark:border-gray-700 text-xs sm:text-base text-gray-700 dark:text-gray-300 sm:order-last sm:pb-safe-or-1.5"
|
||||
class="bg-gray-100 dark:bg-gray-800 text-center py-1.5 border-t dark:border-gray-700 text-xs sm:text-base text-gray-700 dark:text-gray-300 sm:order-last sm:mb-safe-or-1.5"
|
||||
>
|
||||
<span class="text-nowrap">Сделайте НаСвязи удобнее.</span>
|
||||
<span> </span>
|
||||
@@ -31,13 +45,14 @@
|
||||
</span>
|
||||
</footer>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<!-- TabBar -->
|
||||
<TabBar />
|
||||
<TabBar class="row-start-5 row-span-1 col-start-1 sm:row-start-1" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useTemplateRef } from 'vue'
|
||||
|
||||
const slots = defineSlots<{
|
||||
@@ -47,12 +62,26 @@ const slots = defineSlots<{
|
||||
|
||||
const contentScrollContainerRef = useTemplateRef('contentScrollContainer')
|
||||
|
||||
const showTopShadow = ref(false)
|
||||
const showBottomShadow = ref(false)
|
||||
|
||||
const scrollToBottom = () => {
|
||||
if (contentScrollContainerRef.value) {
|
||||
contentScrollContainerRef.value.scrollTop = contentScrollContainerRef.value.scrollHeight
|
||||
}
|
||||
}
|
||||
|
||||
const handleScroll = () => {
|
||||
const el = contentScrollContainerRef.value
|
||||
if (!el) return
|
||||
|
||||
const hasScrollTop = el.scrollTop > 0
|
||||
const hasScrollBottom = el.scrollTop + el.clientHeight < el.scrollHeight
|
||||
|
||||
showTopShadow.value = hasScrollTop
|
||||
showBottomShadow.value = hasScrollBottom
|
||||
}
|
||||
|
||||
// Устанавливаем корректную высоту при загрузке и изменении размера окна
|
||||
const onresize = () => {
|
||||
document.documentElement.style.setProperty(
|
||||
@@ -76,6 +105,16 @@ const onresize = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// if ('virtualKeyboard' in navigator) {
|
||||
// // Tell the browser you are taking care of virtual keyboard occlusions yourself.
|
||||
// navigator.virtualKeyboard.overlaysContent = true;
|
||||
// navigator.virtualKeyboard.addEventListener('geometrychange', (event) => {
|
||||
// const { x, y, width, height } = event.target.boundingRect;
|
||||
// if (height > 0) console.log('keyboard is shown');
|
||||
// else console.log('keyboard is hidden');
|
||||
// });
|
||||
// }
|
||||
|
||||
function preventScroll(e: TouchEvent) {
|
||||
if (
|
||||
contentScrollContainerRef.value &&
|
||||
@@ -91,8 +130,11 @@ const layoutPageHead = useHead({
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
visualViewport?.addEventListener('resize', onresize, { passive: true })
|
||||
// visualViewport?.addEventListener('resize', onresize, { passive: true })
|
||||
contentScrollContainerRef.value!.addEventListener('touchmove', preventScroll, { passive: false })
|
||||
|
||||
// Инициализируем отображение теней
|
||||
handleScroll()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
|
||||
Reference in New Issue
Block a user