fix: fix dock layout
This commit is contained in:
@@ -1,12 +1,8 @@
|
||||
<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-200 w-full"></header>
|
||||
|
||||
<section class="telecart-main-section">
|
||||
<section class="app-content">
|
||||
<FullscreenViewport v-if="platform === 'ios' || platform === 'android'"/>
|
||||
|
||||
<div class="fixed inset-0 z-50 bg-white flex items-center justify-center text-center p-4
|
||||
@@ -25,6 +21,7 @@
|
||||
<PrivacyPolicy v-if="! settings.is_privacy_consented"/>
|
||||
|
||||
<Dock v-if="isAppDockShown"/>
|
||||
<div class="dock-spacer bg-base-100 z-50"></div>
|
||||
|
||||
<div
|
||||
v-if="swiperBack.isActive.value"
|
||||
@@ -52,17 +49,6 @@
|
||||
</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>
|
||||
@@ -72,12 +58,11 @@ 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";
|
||||
import BrowserNotSupported from "@/BrowserNotSupported.vue";
|
||||
import {useSwipeBack} from "@/composables/useSwipeBack.js";
|
||||
|
||||
const tg = useMiniApp();
|
||||
const platform = ref();
|
||||
@@ -93,9 +78,6 @@ 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 = [
|
||||
@@ -127,10 +109,6 @@ function navigateBack() {
|
||||
router.back();
|
||||
}
|
||||
|
||||
function toggleDrawer() {
|
||||
drawerOpen.value = !drawerOpen.value;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => route.name,
|
||||
() => {
|
||||
@@ -151,6 +129,16 @@ function handleClickOutside(e) {
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => route.name,
|
||||
(name) => {
|
||||
let height = '72px'; // дефолт
|
||||
if (name === 'product.show') height = '146px';
|
||||
document.documentElement.style.setProperty('--dock-height', height);
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
});
|
||||
@@ -159,3 +147,19 @@ onMounted(() => {
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dock-spacer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
height: calc(
|
||||
var(--tg-content-safe-area-inset-bottom, 0px)
|
||||
+ var(--tg-safe-area-inset-bottom, 0px)
|
||||
);
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -77,3 +77,25 @@ function onDockItemClick() {
|
||||
haptic.selectionChanged();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dock {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
height: var(--dock-height);
|
||||
bottom: calc(
|
||||
var(--tg-content-safe-area-inset-bottom, 0px)
|
||||
+ var(--tg-safe-area-inset-bottom, 0px)
|
||||
);
|
||||
padding-bottom: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
|
||||
background: var(--color-base-100);
|
||||
z-index: 50;
|
||||
}
|
||||
</style>
|
||||
@@ -17,9 +17,9 @@
|
||||
<SwiperSlide
|
||||
v-for="product in block.data.products.data"
|
||||
:key="product.id"
|
||||
class="radius-box bg-base-100 shadow-sm p-2"
|
||||
class="pb-1"
|
||||
>
|
||||
<div>
|
||||
<div class="radius-box bg-base-100 shadow-sm p-2">
|
||||
<RouterLink
|
||||
:to="{name: 'product.show', params: {id: product.id}}"
|
||||
@click="slideClick(product)"
|
||||
@@ -30,7 +30,6 @@
|
||||
</div>
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
</BaseBlock>
|
||||
|
||||
10
frontend/spa/src/components/SwipeToBack.vue
Normal file
10
frontend/spa/src/components/SwipeToBack.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useSwipeBack} from "@/composables/useSwipeBack.js";
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {createApp} from 'vue';
|
||||
import {createApp, ref} from 'vue';
|
||||
import App from './App.vue';
|
||||
import './style.css';
|
||||
import {VueTelegramPlugin} from 'vue-tg';
|
||||
@@ -118,8 +118,16 @@ settings.load()
|
||||
app.mount('#app');
|
||||
})
|
||||
.then(() => window.Telegram.WebApp.ready())
|
||||
.then(() => {
|
||||
const con = console;
|
||||
window.Telegram.WebApp.onEvent('viewportChanged', (state) => {
|
||||
|
||||
con.log('[Init]: viewportChanged', state.isStateStable, this.viewportHeight);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
const code = error.code ?? error.response._data.code;
|
||||
console.error(error);
|
||||
const code = error.code ?? error?.response?._data.code;
|
||||
let ErrorComponent;
|
||||
|
||||
switch (code) {
|
||||
|
||||
@@ -64,3 +64,4 @@ router.beforeEach((to, from, next) => {
|
||||
ym.prevPath = from.path;
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
@plugin "daisyui" {
|
||||
@@ -11,6 +12,7 @@
|
||||
|
||||
html, body, #app {
|
||||
overflow-x: hidden;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
:root {
|
||||
@@ -20,24 +22,37 @@ html, body, #app {
|
||||
--swiper-pagination-bottom: 0px;
|
||||
--product_list_title_max_lines: 2;
|
||||
--tc-navbar-min-height: 3rem;
|
||||
}
|
||||
|
||||
#app {
|
||||
position: relative;
|
||||
/*padding-top: var(--tg-content-safe-area-inset-top);*/
|
||||
padding-bottom: var(--tg-content-safe-area-inset-bottom);
|
||||
padding-left: var(--tg-content-safe-area-inset-left);
|
||||
padding-right: var(--tg-content-safe-area-inset-right);
|
||||
--dock-height: 72px;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
/*padding-top: calc(var(--tg-content-safe-area-inset-top) + var(--tg-safe-area-inset-top));*/
|
||||
padding-bottom: calc(
|
||||
var(--tg-safe-area-inset-bottom, 0px)
|
||||
+ 72px
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
padding-left: calc(
|
||||
var(--tg-content-safe-area-inset-left, 0px)
|
||||
+ var(--tg-safe-area-inset-left, 0px)
|
||||
);
|
||||
padding-right: calc(
|
||||
var(--tg-content-safe-area-inset-right, 0px)
|
||||
+ var(--tg-safe-area-inset-right, 0px)
|
||||
);
|
||||
}
|
||||
|
||||
.app-content {
|
||||
flex: 1 1 auto;
|
||||
|
||||
padding-top: calc(
|
||||
var(--tg-content-safe-area-inset-top, 0px)
|
||||
+ var(--tg-safe-area-inset-top, 0px)
|
||||
);
|
||||
|
||||
padding-bottom: calc(
|
||||
var(--dock-height)
|
||||
+ var(--tg-content-safe-area-inset-bottom, 0px)
|
||||
+ var(--tg-safe-area-inset-bottom, 0px)
|
||||
);
|
||||
padding-left: var(--tg-safe-area-inset-left, 0px);
|
||||
padding-right: var(--tg-safe-area-inset-right, 0px);
|
||||
}
|
||||
|
||||
.safe-top {
|
||||
@@ -57,15 +72,6 @@ html, body, #app {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.telecart-main-section {
|
||||
padding-top: calc(
|
||||
var(--tg-content-safe-area-inset-top, 0rem)
|
||||
+ var(--tg-safe-area-inset-top, 0rem)
|
||||
/*+ var(--tc-navbar-min-height)*/
|
||||
/*+ 1rem*/
|
||||
);
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: var(--color-base-200);
|
||||
}
|
||||
@@ -73,3 +79,10 @@ html {
|
||||
.radius-box {
|
||||
border-radius: var(--radius-xl);
|
||||
}
|
||||
|
||||
.bottom-fix {
|
||||
bottom: calc(
|
||||
var(--tg-content-safe-area-inset-bottom, 0px)
|
||||
+ var(--tg-safe-area-inset-bottom, 0px)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="fixed px-4 pb-4 pt-4 bottom-0 left-0 w-full bg-base-200 z-50 flex flex-col justify-between items-center gap-2 border-t-1 border-t-base-300">
|
||||
class="fixed bottom-fix px-4 pb-4 pt-4 bottom-0 left-0 w-full bg-base-200 z-50 flex flex-col justify-between items-center gap-2 border-t-1 border-t-base-300">
|
||||
|
||||
<div class="text-error">{{ checkout.errorMessage }}</div>
|
||||
<div>
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
<div v-else-if="imagesLoaded && images.length === 0">
|
||||
<div class="bg-base-200 aspect-square flex items-center justify-center flex-col text-base-300">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-18">
|
||||
<path fill-rule="evenodd" d="M1.5 6a2.25 2.25 0 0 1 2.25-2.25h16.5A2.25 2.25 0 0 1 22.5 6v12a2.25 2.25 0 0 1-2.25 2.25H3.75A2.25 2.25 0 0 1 1.5 18V6ZM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0 0 21 18v-1.94l-2.69-2.689a1.5 1.5 0 0 0-2.12 0l-.88.879.97.97a.75.75 0 1 1-1.06 1.06l-5.16-5.159a1.5 1.5 0 0 0-2.12 0L3 16.061Zm10.125-7.81a1.125 1.125 0 1 1 2.25 0 1.125 1.125 0 0 1-2.25 0Z" clip-rule="evenodd" />
|
||||
<path fill-rule="evenodd"
|
||||
d="M1.5 6a2.25 2.25 0 0 1 2.25-2.25h16.5A2.25 2.25 0 0 1 22.5 6v12a2.25 2.25 0 0 1-2.25 2.25H3.75A2.25 2.25 0 0 1 1.5 18V6ZM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0 0 21 18v-1.94l-2.69-2.689a1.5 1.5 0 0 0-2.12 0l-.88.879.97.97a.75.75 0 1 1-1.06 1.06l-5.16-5.159a1.5 1.5 0 0 0-2.12 0L3 16.061Zm10.125-7.81a1.125 1.125 0 1 1 2.25 0 1.125 1.125 0 0 1-2.25 0Z"
|
||||
clip-rule="evenodd"/>
|
||||
</svg>
|
||||
<span class="text-xl">Нет изображений</span>
|
||||
</div>
|
||||
@@ -119,8 +121,8 @@
|
||||
</div>
|
||||
|
||||
<div v-if="product.product_id"
|
||||
class="fixed px-4 pb-4 pt-4 bottom-0 left-0 w-full bg-base-100/95 backdrop-blur-md z-50 flex flex-col gap-3 border-t border-base-300 shadow-lg"
|
||||
style="padding-bottom: calc(0.5rem + env(safe-area-inset-bottom));">
|
||||
class="fixed bottom-fix px-4 pb-4 pt-4 left-0 w-full bg-base-100/95 backdrop-blur-md z-50 flex flex-col gap-3 border-t border-base-300 shadow-lg"
|
||||
>
|
||||
<template v-if="settings.store_enabled">
|
||||
<div v-if="error" class="alert alert-error alert-sm py-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-4 w-4" fill="none"
|
||||
@@ -306,7 +308,7 @@ function setQuantity(newQuantity) {
|
||||
|
||||
onMounted(async () => {
|
||||
// Явно сбрасываем скролл наверх при открытии страницы товара
|
||||
window.scrollTo({ top: 0, behavior: 'instant' });
|
||||
window.scrollTo({top: 0, behavior: 'instant'});
|
||||
|
||||
isLoading.value = true;
|
||||
imagesLoaded.value = false;
|
||||
|
||||
Reference in New Issue
Block a user