mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-18 14:11:29 +08:00
fix: stabilize iOS Safari mobile navigation
This commit is contained in:
@@ -170,6 +170,10 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
.layout-wrapper.layout-nav-type-vertical {
|
||||
--layout-navbar-block-size: calc(
|
||||
env(safe-area-inset-top, 0px) + #{variables.$layout-vertical-nav-navbar-height} + var(--navbar-tab-height)
|
||||
);
|
||||
|
||||
// TODO(v2): Check why we need height in vertical nav & min-height in horizontal nav
|
||||
min-block-size: 100%;
|
||||
|
||||
@@ -185,13 +189,16 @@ export default defineComponent({
|
||||
.layout-navbar {
|
||||
position: fixed;
|
||||
z-index: variables.$layout-vertical-nav-layout-navbar-z-index;
|
||||
// iOS Safari 在地址栏收起和惯性滚动时可能把 fixed 顶栏和页面滚动层合成到一起,
|
||||
// 单独提升顶栏图层可避免导航栏短暂上移到安全区下方。
|
||||
backface-visibility: hidden;
|
||||
block-size: var(--layout-navbar-block-size);
|
||||
inline-size: calc(100vw - variables.$layout-vertical-nav-width - 0.5rem);
|
||||
inset-block-start: 0;
|
||||
transform: translate3d(0, 0, 0);
|
||||
|
||||
.navbar-content-container {
|
||||
block-size: calc(
|
||||
env(safe-area-inset-top) + variables.$layout-vertical-nav-navbar-height + var(--navbar-tab-height)
|
||||
);
|
||||
block-size: var(--layout-navbar-block-size);
|
||||
}
|
||||
|
||||
@at-root {
|
||||
|
||||
@@ -15,7 +15,7 @@ body {
|
||||
background: rgb(var(--v-theme-background));
|
||||
overscroll-behavior-y: contain;
|
||||
|
||||
--webkit-overflow-scrolling: touch;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
body,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { checkPWAStatus, isPWADisplayMode } from '@/@core/utils/navigator'
|
||||
import { checkPWAStatus, isMobileDevice, isPWADisplayMode } from '@/@core/utils/navigator'
|
||||
|
||||
// 全局PWA状态,确保只初始化一次
|
||||
const globalPwaStatus = ref<{
|
||||
@@ -34,11 +34,14 @@ async function initializePWAGlobally() {
|
||||
globalPwaStatus.value = await checkPWAStatus()
|
||||
} catch (error) {
|
||||
console.error('Failed to detect PWA status', error)
|
||||
const isStandaloneMode = isPWADisplayMode()
|
||||
|
||||
// 即使检测失败,也设置一个合理的默认值
|
||||
globalPwaStatus.value = {
|
||||
hasPWAFeatures: false,
|
||||
isStandaloneMode: isPWADisplayMode(),
|
||||
isPWAEnvironment: isPWADisplayMode(),
|
||||
isStandaloneMode,
|
||||
// iOS Safari 浏览器模式可能取不到 Service Worker 注册信息,但移动端仍应使用 App 交互。
|
||||
isPWAEnvironment: isStandaloneMode || isMobileDevice(),
|
||||
isFullPWA: false,
|
||||
}
|
||||
} finally {
|
||||
@@ -56,7 +59,8 @@ export function usePWA() {
|
||||
|
||||
// 基于新的PWA状态结构
|
||||
const pwaMode = computed(() => {
|
||||
return globalPwaStatus.value?.isPWAEnvironment ?? false
|
||||
// PWA 状态异步恢复前先用移动端特征兜底,避免 Safari 浏览器首屏阶段缺少移动端交互。
|
||||
return globalPwaStatus.value?.isPWAEnvironment ?? isMobileDevice()
|
||||
})
|
||||
|
||||
const appMode = computed(() => {
|
||||
|
||||
@@ -85,7 +85,10 @@ export function usePullDownGesture(options: PullDownOptions = {}) {
|
||||
})
|
||||
|
||||
const indicatorTransform = computed(() => {
|
||||
return `translate(-50%, ${Math.min(60 + pullDistance.value - config.SHOW_INDICATOR, 70)}px)`
|
||||
// 顶部基准位置由布局 CSS 负责,这里只让指示器跟随下拉手势轻微移动。
|
||||
const followOffset = Math.min(Math.max(pullDistance.value - config.SHOW_INDICATOR, 0), 16)
|
||||
|
||||
return `translate3d(-50%, ${followOffset}px, 0)`
|
||||
})
|
||||
|
||||
// 弹窗检测函数
|
||||
|
||||
@@ -452,6 +452,7 @@ onMounted(async () => {
|
||||
v-if="appMode && showPullIndicator"
|
||||
class="pull-indicator"
|
||||
:style="{
|
||||
'--pull-indicator-navbar-extra-height': navbarExtraHeight,
|
||||
opacity: indicatorOpacity,
|
||||
transform: indicatorTransform,
|
||||
}"
|
||||
@@ -475,7 +476,7 @@ onMounted(async () => {
|
||||
<!-- 👉 Navbar -->
|
||||
<template #navbar="{ toggleVerticalOverlayNavActive }">
|
||||
<div
|
||||
class="theme-navbar-row d-flex h-14 align-center mx-1"
|
||||
class="theme-navbar-row d-flex h-full align-center mx-1"
|
||||
:class="{ 'theme-navbar-row--horizontal': showHorizontalThemeNav }"
|
||||
>
|
||||
<RouterLink v-if="showHorizontalThemeNav" :to="canAdmin ? '/dashboard' : '/apps'" class="theme-horizontal-logo">
|
||||
@@ -801,6 +802,7 @@ onMounted(async () => {
|
||||
|
||||
.pull-indicator {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -809,11 +811,14 @@ onMounted(async () => {
|
||||
backdrop-filter: blur(20px);
|
||||
background: rgba(var(--v-theme-surface), 0.3);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 10%), 0 1px 3px rgba(0, 0, 0, 6%);
|
||||
inset-block-start: 80px;
|
||||
inset-block-start: calc(
|
||||
env(safe-area-inset-top, 0px) + 4rem + var(--pull-indicator-navbar-extra-height, 0rem) + 0.75rem
|
||||
);
|
||||
inset-inline-start: 50%;
|
||||
pointer-events: none;
|
||||
transform: translateX(-50%);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transform: translate3d(-50%, 0, 0);
|
||||
transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
.indicator-icon {
|
||||
|
||||
Reference in New Issue
Block a user