Files
interview-demo-code/frontend/spa/src/App.vue
Nikita Kiselev db8d1360fc feat(search): add keyboard hide button and auto-hide Dock
- Add floating keyboard hide button that appears on search input focus
- Create KeyboardStore to manage keyboard state globally
- Auto-hide Dock component when keyboard is open on search page
- Position keyboard hide button at bottom when Dock is hidden
- Update keyboard state on focus, blur, and hide actions
2025-12-01 22:37:30 +03:00

122 lines
3.5 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"/>
</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";
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);
const routesToHideAppDock = [
'product.show',
'checkout',
'order_created',
'filters',
];
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>