This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="text-sm">
|
<div class="text-sm pt-4">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div v-if="isPending" class="w-5 h-5">
|
<div v-if="isPending" class="w-5 h-5">
|
||||||
<ProgressSpinner style="width: 100%; height: 100%" strokeWidth="8" fill="transparent" />
|
<ProgressSpinner style="width: 100%; height: 100%" strokeWidth="8" fill="transparent" />
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="sm:max-w-prose mx-auto flex gap-3 px-4 pt-0 flex-col-reverse w-full">
|
||||||
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"
|
|
||||||
>
|
|
||||||
<!-- Форма отправки сообщений -->
|
<!-- Форма отправки сообщений -->
|
||||||
<form @submit.prevent="sendMessage" class="flex gap-2 items-center" ref="form">
|
<form @submit.prevent="sendMessage" class="flex gap-2 items-center" ref="form">
|
||||||
<InputText
|
<InputText
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!-- shadow-md dark:shadow-lg -->
|
||||||
<div
|
<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
|
<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"
|
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
|
unreadCount?: number
|
||||||
}
|
}
|
||||||
const tabs: Tab[] = [
|
const tabs: Tab[] = [
|
||||||
{ route: ROUTE_NAMES.CREATE, label: 'Создать QR-код', icon: 'plus' },
|
{ route: ROUTE_NAMES.CREATE, label: 'Создать QR‑код', icon: 'plus' },
|
||||||
{ route: ROUTE_NAMES.MANAGE_DASHBOARD_QR, label: 'Мои QR-коды', icon: 'qrcode' },
|
{ route: ROUTE_NAMES.MANAGE_DASHBOARD_QR, label: 'Мои QR‑коды', icon: 'qrcode' },
|
||||||
{ route: ROUTE_NAMES.MANAGE_DASHBOARD_CHATS, label: 'Чаты', icon: 'comments' },
|
{ route: ROUTE_NAMES.MANAGE_DASHBOARD_CHATS, label: 'Чаты', icon: 'comments' },
|
||||||
// { to: ROUTE_NAMES., label: 'Профиль', icon: 'user' },
|
// { to: ROUTE_NAMES., label: 'Профиль', icon: 'user' },
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:href="href"
|
:href="href"
|
||||||
@click="navigate"
|
@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
|
<i
|
||||||
:class="[
|
:class="[
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
]"
|
]"
|
||||||
></i>
|
></i>
|
||||||
<span
|
<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="{
|
:class="{
|
||||||
'text-primary-700 dark:text-primary-300': isActive,
|
'text-primary-700 dark:text-primary-300': isActive,
|
||||||
'text-gray-700 dark:text-gray-300': !isActive,
|
'text-gray-700 dark:text-gray-300': !isActive,
|
||||||
|
|||||||
@@ -1,22 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<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 -->
|
<!-- Content Section -->
|
||||||
<div
|
<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"
|
ref="contentScrollContainer"
|
||||||
|
@scroll="handleScroll"
|
||||||
>
|
>
|
||||||
<div class="sm:max-w-prose grid grid-cols-1 mx-auto my-5 w-full">
|
<div class="sm:max-w-prose grid grid-cols-1 mx-auto my-5 w-full">
|
||||||
<slot name="default" v-bind:scrollToBottom />
|
<slot name="default" v-bind:scrollToBottom />
|
||||||
</div>
|
</div>
|
||||||
</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 -->
|
<!-- Footer Section -->
|
||||||
|
<div class="row-start-4 row-span-1 col-start-1 sm:row-start-5">
|
||||||
<slot name="footer">
|
<slot name="footer">
|
||||||
<footer
|
<footer
|
||||||
v-if="!slots.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 class="text-nowrap">Сделайте НаСвязи удобнее.</span>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
@@ -31,13 +45,14 @@
|
|||||||
</span>
|
</span>
|
||||||
</footer>
|
</footer>
|
||||||
</slot>
|
</slot>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- TabBar -->
|
<TabBar class="row-start-5 row-span-1 col-start-1 sm:row-start-1" />
|
||||||
<TabBar />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||||
import { useTemplateRef } from 'vue'
|
import { useTemplateRef } from 'vue'
|
||||||
|
|
||||||
const slots = defineSlots<{
|
const slots = defineSlots<{
|
||||||
@@ -47,12 +62,26 @@ const slots = defineSlots<{
|
|||||||
|
|
||||||
const contentScrollContainerRef = useTemplateRef('contentScrollContainer')
|
const contentScrollContainerRef = useTemplateRef('contentScrollContainer')
|
||||||
|
|
||||||
|
const showTopShadow = ref(false)
|
||||||
|
const showBottomShadow = ref(false)
|
||||||
|
|
||||||
const scrollToBottom = () => {
|
const scrollToBottom = () => {
|
||||||
if (contentScrollContainerRef.value) {
|
if (contentScrollContainerRef.value) {
|
||||||
contentScrollContainerRef.value.scrollTop = contentScrollContainerRef.value.scrollHeight
|
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 = () => {
|
const onresize = () => {
|
||||||
document.documentElement.style.setProperty(
|
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) {
|
function preventScroll(e: TouchEvent) {
|
||||||
if (
|
if (
|
||||||
contentScrollContainerRef.value &&
|
contentScrollContainerRef.value &&
|
||||||
@@ -91,8 +130,11 @@ const layoutPageHead = useHead({
|
|||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
visualViewport?.addEventListener('resize', onresize, { passive: true })
|
// visualViewport?.addEventListener('resize', onresize, { passive: true })
|
||||||
contentScrollContainerRef.value!.addEventListener('touchmove', preventScroll, { passive: false })
|
contentScrollContainerRef.value!.addEventListener('touchmove', preventScroll, { passive: false })
|
||||||
|
|
||||||
|
// Инициализируем отображение теней
|
||||||
|
handleScroll()
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user