157 lines
4.8 KiB
Vue
157 lines
4.8 KiB
Vue
<template>
|
|
<div class="drawer h-full">
|
|
<input id="app-drawer" type="checkbox" class="drawer-toggle" v-model="drawerOpen"/>
|
|
|
|
<div class="drawer-content">
|
|
<div class="app-container">
|
|
<header class="app-header bg-base-100 w-full"></header>
|
|
|
|
<section class="telecart-main-section">
|
|
<FullscreenViewport v-if="platform === 'ios' || platform === 'android'"/>
|
|
|
|
<AppDebugMessage v-if="settings.app_debug"/>
|
|
|
|
<RouterView v-slot="{ Component, route }">
|
|
<KeepAlive include="Home" :key="filtersStore.paramsHashForRouter">
|
|
<component :is="Component" :key="route.fullPath"/>
|
|
</KeepAlive>
|
|
</RouterView>
|
|
|
|
<PrivacyPolicy v-if="! settings.is_privacy_consented"/>
|
|
|
|
<CartButton v-if="settings.store_enabled"/>
|
|
<Dock v-if="isAppDockShown"/>
|
|
|
|
<div
|
|
v-if="swiperBack.isActive.value"
|
|
class="fixed top-1/2 left-0 z-50
|
|
w-20
|
|
h-20
|
|
-translate-y-1/2
|
|
-translate-x-18
|
|
flex items-center justify-end
|
|
shadow-xl
|
|
rounded-full
|
|
py-2
|
|
text-primary-content
|
|
"
|
|
:class="{
|
|
'bg-primary': swiperBack.deltaX.value < swiperBack.ACTIVATION_THRESHOLD,
|
|
'bg-accent': swiperBack.deltaX.value >= swiperBack.ACTIVATION_THRESHOLD,
|
|
}"
|
|
:style="{ transform: `translate(${easeOut(swiperBack.deltaX.value/10, 30)}px, -50%)` }"
|
|
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18" />
|
|
</svg>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="drawer-side z-50 safe-top">
|
|
<label for="app-drawer" aria-label="close sidebar" class="drawer-overlay"></label>
|
|
<ul class="menu bg-base-200 text-base-content min-h-full w-80 p-4">
|
|
<li><a href="#">π ΠΠ»Π°Π²Π½Π°Ρ</a></li>
|
|
<li><a href="#">π ΠΠΎΡΠ·ΠΈΠ½Π°</a></li>
|
|
<li><a @click="drawerOpen = false">β ΠΠ°ΠΊΡΡΡΡ</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {computed, onMounted, onUnmounted, ref, watch} from "vue";
|
|
import {FullscreenViewport, useMiniApp, useWebAppViewport} from 'vue-tg';
|
|
import {useRoute, useRouter} from "vue-router";
|
|
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
|
import {useProductFiltersStore} from "@/stores/ProductFiltersStore.js";
|
|
import {useKeyboardStore} from "@/stores/KeyboardStore.js";
|
|
import CartButton from "@/components/CartButton.vue";
|
|
import Dock from "@/components/Dock.vue";
|
|
import AppDebugMessage from "@/components/AppDebugMessage.vue";
|
|
import PrivacyPolicy from "@/components/PrivacyPolicy.vue";
|
|
import {useSwipeBack} from "@/composables/useSwipeBack.js";
|
|
|
|
const tg = useMiniApp();
|
|
const platform = ref();
|
|
platform.value = tg.platform;
|
|
|
|
const {disableVerticalSwipes} = useWebAppViewport();
|
|
disableVerticalSwipes();
|
|
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
const settings = useSettingsStore();
|
|
const filtersStore = useProductFiltersStore();
|
|
const keyboardStore = useKeyboardStore();
|
|
const backButton = window.Telegram.WebApp.BackButton;
|
|
const haptic = window.Telegram.WebApp.HapticFeedback;
|
|
const drawerOpen = ref(false);
|
|
|
|
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΆΠ΅ΡΡΠ° Swipe Back (Π±Π΅Π· Π²ΠΈΠ·ΡΠ°Π»ΡΠ½ΠΎΠ³ΠΎ ΠΈΠ½Π΄ΠΈΠΊΠ°ΡΠΎΡΠ°)
|
|
const swiperBack = useSwipeBack();
|
|
|
|
const routesToHideAppDock = [
|
|
'product.show',
|
|
'checkout',
|
|
'order_created',
|
|
'filters',
|
|
];
|
|
|
|
function easeOut(value, max) {
|
|
const x = Math.min(Math.abs(value) / max, 1)
|
|
const eased = 1 - (1 - x) ** 3
|
|
return Math.sign(value) * eased * max
|
|
}
|
|
|
|
const isAppDockShown = computed(() => {
|
|
if (routesToHideAppDock.indexOf(route.name) === -1) {
|
|
// Π‘ΠΊΡΡΠ²Π°Π΅ΠΌ Dock, Π΅ΡΠ»ΠΈ ΠΊΠ»Π°Π²ΠΈΠ°ΡΡΡΠ° ΠΎΡΠΊΡΡΡΠ° Π½Π° ΡΡΡΠ°Π½ΠΈΡΠ΅ ΠΏΠΎΠΈΡΠΊΠ°
|
|
if (route.name === 'search' && keyboardStore.isOpen) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
function navigateBack() {
|
|
haptic.impactOccurred('light');
|
|
router.back();
|
|
}
|
|
|
|
function toggleDrawer() {
|
|
drawerOpen.value = !drawerOpen.value;
|
|
}
|
|
|
|
watch(
|
|
() => route.name,
|
|
() => {
|
|
if (route.name === 'home') {
|
|
backButton.hide();
|
|
backButton.offClick(navigateBack);
|
|
} else {
|
|
backButton.show();
|
|
backButton.onClick(navigateBack);
|
|
}
|
|
},
|
|
{immediate: true}
|
|
);
|
|
|
|
function handleClickOutside(e) {
|
|
if (!e.target.closest('input,select,textarea')) {
|
|
document.activeElement?.blur();
|
|
}
|
|
}
|
|
|
|
onUnmounted(() => {
|
|
document.removeEventListener('click', handleClickOutside);
|
|
});
|
|
|
|
onMounted(() => {
|
|
document.addEventListener('click', handleClickOutside);
|
|
});
|
|
</script>
|