1
0

PWA модуль

Теперь проект может быть установлен как приложение на телефон
This commit is contained in:
2026-01-16 16:12:34 +07:00
parent 25663a7aa4
commit c46fd3952e
16 changed files with 5388 additions and 52 deletions

View File

@@ -151,11 +151,23 @@ const unlockBodyScroll = () => {
document.body.classList.remove('panel-open')
}
// Принудительный reflow для iOS PWA - исправляет баг с safe-area при первом рендере
const forceReflow = () => {
if (panelRef.value) {
// Читаем offsetHeight чтобы вызвать reflow
void panelRef.value.offsetHeight
}
}
// Восстановление ширины при открытии (из localStorage или дефолтная)
watch(() => props.show, (newVal) => {
if (newVal) {
panelWidth.value = getSavedWidth()
lockBodyScroll()
// Два requestAnimationFrame для гарантированного reflow после рендера
requestAnimationFrame(() => {
requestAnimationFrame(forceReflow)
})
} else {
unlockBodyScroll()
}
@@ -326,14 +338,25 @@ onUnmounted(() => {
transform: scale(0.98);
}
/* На мобильных убираем transform из анимации - он ломает layout в iOS PWA */
.panel-enter-from .panel.mobile,
.panel-leave-to .panel.mobile {
transform: none;
}
/* ========== MOBILE: Fullscreen ========== */
/* height: 100% вместо 100dvh - потому что wrapper уже учитывает safe-area */
.panel.mobile {
width: 100% !important;
max-width: 100%;
height: 100%; /* Занимаем всю высоту wrapper, не viewport */
border-radius: 0;
/* Блокируем горизонтальные свайпы, чтобы не срабатывала навигация браузера */
touch-action: pan-y pinch-zoom;
overscroll-behavior: contain;
/* Градиент как на основной странице */
background: var(--bg-gradient);
background-size: 100vw 100vh;
background-position: 0 calc(-1 * var(--safe-area-top));
}
.panel.mobile .resize-handle {
@@ -346,15 +369,13 @@ onUnmounted(() => {
.panel.mobile .panel-body {
padding: 16px;
padding-bottom: calc(16px + var(--safe-area-bottom, 0px));
min-height: 0;
gap: 0; /* Убираем gap — он создаёт пустое место */
gap: 0;
overflow-y: auto;
}
.panel.mobile .panel-footer {
padding: 16px;
padding-bottom: calc(16px + var(--safe-area-bottom, 0px));
}
.panel.mobile .header-content :deep(h2) {