mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-07 00:36:41 +08:00
fix: stabilize mobile panel height
This commit is contained in:
@@ -107,7 +107,6 @@ const HISTORY_TITLE_LENGTH = 36
|
|||||||
const HISTORY_PREVIEW_LENGTH = 72
|
const HISTORY_PREVIEW_LENGTH = 72
|
||||||
|
|
||||||
const drawer = ref(false)
|
const drawer = ref(false)
|
||||||
const drawerViewportHeight = ref('100dvh')
|
|
||||||
const inputText = ref('')
|
const inputText = ref('')
|
||||||
const messages = ref<AgentChatMessage[]>([])
|
const messages = ref<AgentChatMessage[]>([])
|
||||||
const historySessions = ref<AgentSessionHistoryItem[]>([])
|
const historySessions = ref<AgentSessionHistoryItem[]>([])
|
||||||
@@ -144,7 +143,6 @@ const hasMessages = computed(() => messages.value.length > 0)
|
|||||||
const hasHistorySessions = computed(() => historySessions.value.length > 0)
|
const hasHistorySessions = computed(() => historySessions.value.length > 0)
|
||||||
const currentUserName = computed(() => userStore.getUserName || t('common.user'))
|
const currentUserName = computed(() => userStore.getUserName || t('common.user'))
|
||||||
const drawerStyle = computed(() => ({
|
const drawerStyle = computed(() => ({
|
||||||
'--agent-assistant-viewport-height': drawerViewportHeight.value,
|
|
||||||
'--agent-assistant-panel-width': drawerWidth.value,
|
'--agent-assistant-panel-width': drawerWidth.value,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -626,19 +624,6 @@ async function prepareAgentAttachments(items: AgentPendingAttachment[]): Promise
|
|||||||
return { images, files, userAttachments }
|
return { images, files, userAttachments }
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVisibleViewportHeight() {
|
|
||||||
if (typeof window === 'undefined') return '100dvh'
|
|
||||||
|
|
||||||
const height = window.visualViewport?.height || window.innerHeight || document.documentElement.clientHeight
|
|
||||||
|
|
||||||
return height > 0 ? `${Math.round(height)}px` : '100dvh'
|
|
||||||
}
|
|
||||||
|
|
||||||
// iOS 独立模式和地址栏收起时可见高度会变化,抽屉需要跟随真实 viewport。
|
|
||||||
function syncDrawerViewportHeight() {
|
|
||||||
drawerViewportHeight.value = getVisibleViewportHeight()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function streamAgentMessage(
|
async function streamAgentMessage(
|
||||||
text: string,
|
text: string,
|
||||||
images: string[] = [],
|
images: string[] = [],
|
||||||
@@ -874,13 +859,8 @@ watch(drawerWidth, () => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
restoreHistorySessions()
|
restoreHistorySessions()
|
||||||
restoreState()
|
restoreState()
|
||||||
syncDrawerViewportHeight()
|
|
||||||
syncInputHeight()
|
syncInputHeight()
|
||||||
window.addEventListener('resize', syncDrawerViewportHeight)
|
|
||||||
window.addEventListener('orientationchange', syncDrawerViewportHeight)
|
|
||||||
window.addEventListener('keydown', handleGlobalKeydown)
|
window.addEventListener('keydown', handleGlobalKeydown)
|
||||||
window.visualViewport?.addEventListener('resize', syncDrawerViewportHeight)
|
|
||||||
window.visualViewport?.addEventListener('scroll', syncDrawerViewportHeight)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onScopeDispose(clearAgentAssistantOpenState)
|
onScopeDispose(clearAgentAssistantOpenState)
|
||||||
@@ -888,11 +868,7 @@ onScopeDispose(clearPendingAttachments)
|
|||||||
onScopeDispose(() => {
|
onScopeDispose(() => {
|
||||||
if (typeof window === 'undefined') return
|
if (typeof window === 'undefined') return
|
||||||
|
|
||||||
window.removeEventListener('resize', syncDrawerViewportHeight)
|
|
||||||
window.removeEventListener('orientationchange', syncDrawerViewportHeight)
|
|
||||||
window.removeEventListener('keydown', handleGlobalKeydown)
|
window.removeEventListener('keydown', handleGlobalKeydown)
|
||||||
window.visualViewport?.removeEventListener('resize', syncDrawerViewportHeight)
|
|
||||||
window.visualViewport?.removeEventListener('scroll', syncDrawerViewportHeight)
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -1269,16 +1245,26 @@ onScopeDispose(() => {
|
|||||||
z-index: 2101;
|
z-index: 2101;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: rgb(var(--v-theme-surface));
|
background: rgb(var(--v-theme-surface));
|
||||||
block-size: var(--agent-assistant-viewport-height, 100dvh) !important;
|
|
||||||
|
/* 背景层必须覆盖完整视口,不能跟随 iOS 键盘后的 visual viewport 缩短。 */
|
||||||
|
block-size: 100vh !important;
|
||||||
border-inline-start: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
border-inline-start: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
box-shadow: var(--app-surface-shadow);
|
box-shadow: var(--app-surface-shadow);
|
||||||
inline-size: var(--agent-assistant-panel-width, 30rem);
|
inline-size: var(--agent-assistant-panel-width, 30rem);
|
||||||
inset-block-start: 0;
|
inset-block-start: 0;
|
||||||
inset-inline-end: 0;
|
inset-inline-end: 0;
|
||||||
max-block-size: var(--agent-assistant-viewport-height, 100dvh) !important;
|
max-block-size: none !important;
|
||||||
|
min-block-size: 100vh !important;
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@supports (block-size: 100lvh) {
|
||||||
|
.agent-assistant-panel {
|
||||||
|
block-size: 100lvh !important;
|
||||||
|
min-block-size: 100lvh !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.agent-assistant-shell {
|
.agent-assistant-shell {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -1345,7 +1331,7 @@ onScopeDispose(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.agent-assistant-history-list {
|
.agent-assistant-history-list {
|
||||||
max-block-size: min(26rem, calc(var(--agent-assistant-viewport-height, 100dvh) - 7rem));
|
max-block-size: min(26rem, calc(100vh - 7rem));
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: contain;
|
||||||
padding-block: 0.35rem;
|
padding-block: 0.35rem;
|
||||||
|
|
||||||
@@ -1355,6 +1341,12 @@ onScopeDispose(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@supports (block-size: 100lvh) {
|
||||||
|
.agent-assistant-history-list {
|
||||||
|
max-block-size: min(26rem, calc(100lvh - 7rem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.agent-assistant-history-empty {
|
.agent-assistant-history-empty {
|
||||||
color: rgba(var(--v-theme-on-surface), 0.58);
|
color: rgba(var(--v-theme-on-surface), 0.58);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { CSSProperties } from 'vue'
|
|
||||||
import {
|
import {
|
||||||
themeCustomizerPrimaryColors,
|
themeCustomizerPrimaryColors,
|
||||||
useThemeCustomizer,
|
useThemeCustomizer,
|
||||||
@@ -35,20 +34,6 @@ const { appMode } = usePWA()
|
|||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const { global: globalTheme } = useTheme()
|
const { global: globalTheme } = useTheme()
|
||||||
const defaultPrimaryColor = themeCustomizerPrimaryColors[0].value
|
const defaultPrimaryColor = themeCustomizerPrimaryColors[0].value
|
||||||
const customizerViewportHeight = ref('100dvh')
|
|
||||||
|
|
||||||
function getVisibleViewportHeight() {
|
|
||||||
if (typeof window === 'undefined') return '100dvh'
|
|
||||||
|
|
||||||
const height = window.visualViewport?.height || window.innerHeight || document.documentElement.clientHeight
|
|
||||||
|
|
||||||
return height > 0 ? `${Math.round(height)}px` : '100dvh'
|
|
||||||
}
|
|
||||||
|
|
||||||
// iOS 小屏的可见视口会随地址栏和独立模式 safe area 变化,面板高度需要跟随真实可见高度。
|
|
||||||
function syncCustomizerViewportHeight() {
|
|
||||||
customizerViewportHeight.value = getVisibleViewportHeight()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将主题定制器打开状态同步到根节点,供全局悬浮按钮避让右侧面板。
|
// 将主题定制器打开状态同步到根节点,供全局悬浮按钮避让右侧面板。
|
||||||
function syncThemeCustomizerOpenState(isOpen: boolean) {
|
function syncThemeCustomizerOpenState(isOpen: boolean) {
|
||||||
@@ -76,12 +61,7 @@ function handleGlobalKeydown(event: KeyboardEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
syncCustomizerViewportHeight()
|
|
||||||
window.addEventListener('keydown', handleGlobalKeydown)
|
window.addEventListener('keydown', handleGlobalKeydown)
|
||||||
window.addEventListener('resize', syncCustomizerViewportHeight)
|
|
||||||
window.addEventListener('orientationchange', syncCustomizerViewportHeight)
|
|
||||||
window.visualViewport?.addEventListener('resize', syncCustomizerViewportHeight)
|
|
||||||
window.visualViewport?.addEventListener('scroll', syncCustomizerViewportHeight)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onScopeDispose(clearThemeCustomizerOpenState)
|
onScopeDispose(clearThemeCustomizerOpenState)
|
||||||
@@ -89,16 +69,8 @@ onScopeDispose(() => {
|
|||||||
if (typeof window === 'undefined') return
|
if (typeof window === 'undefined') return
|
||||||
|
|
||||||
window.removeEventListener('keydown', handleGlobalKeydown)
|
window.removeEventListener('keydown', handleGlobalKeydown)
|
||||||
window.removeEventListener('resize', syncCustomizerViewportHeight)
|
|
||||||
window.removeEventListener('orientationchange', syncCustomizerViewportHeight)
|
|
||||||
window.visualViewport?.removeEventListener('resize', syncCustomizerViewportHeight)
|
|
||||||
window.visualViewport?.removeEventListener('scroll', syncCustomizerViewportHeight)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const customizerContainerStyle = computed<CSSProperties>(() => ({
|
|
||||||
'--theme-customizer-viewport-height': customizerViewportHeight.value,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const themeOptions = computed<Array<{ icon: string; title: string; value: ThemeCustomizerTheme }>>(() => [
|
const themeOptions = computed<Array<{ icon: string; title: string; value: ThemeCustomizerTheme }>>(() => [
|
||||||
{ title: t('theme.light'), value: 'light', icon: 'mdi-white-balance-sunny' },
|
{ title: t('theme.light'), value: 'light', icon: 'mdi-white-balance-sunny' },
|
||||||
{ title: t('theme.dark'), value: 'dark', icon: 'mdi-weather-night' },
|
{ title: t('theme.dark'), value: 'dark', icon: 'mdi-weather-night' },
|
||||||
@@ -234,7 +206,6 @@ async function handleResetSettings() {
|
|||||||
<template>
|
<template>
|
||||||
<aside
|
<aside
|
||||||
class="theme-customizer-panel-host"
|
class="theme-customizer-panel-host"
|
||||||
:style="customizerContainerStyle"
|
|
||||||
role="dialog"
|
role="dialog"
|
||||||
:aria-label="t('theme.customizer.title')"
|
:aria-label="t('theme.customizer.title')"
|
||||||
>
|
>
|
||||||
@@ -443,13 +414,23 @@ async function handleResetSettings() {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
background: rgb(var(--v-theme-surface));
|
background: rgb(var(--v-theme-surface));
|
||||||
block-size: var(--theme-customizer-viewport-height, 100dvh) !important;
|
|
||||||
|
/* 背景层保持完整视口高度,避免 iOS 键盘触发 visual viewport resize 后露出底层页面。 */
|
||||||
|
block-size: 100vh !important;
|
||||||
border-inline-start: 1px solid rgba(var(--v-theme-on-surface), 0.08) !important;
|
border-inline-start: 1px solid rgba(var(--v-theme-on-surface), 0.08) !important;
|
||||||
box-shadow: var(--app-surface-shadow) !important;
|
box-shadow: var(--app-surface-shadow) !important;
|
||||||
inline-size: 420px !important;
|
inline-size: 420px !important;
|
||||||
inset-block-start: 0 !important;
|
inset-block-start: 0 !important;
|
||||||
inset-inline-end: 0 !important;
|
inset-inline-end: 0 !important;
|
||||||
max-block-size: var(--theme-customizer-viewport-height, 100dvh) !important;
|
max-block-size: none !important;
|
||||||
|
min-block-size: 100vh !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports (block-size: 100lvh) {
|
||||||
|
.theme-customizer-panel-host {
|
||||||
|
block-size: 100lvh !important;
|
||||||
|
min-block-size: 100lvh !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-customizer-panel {
|
.theme-customizer-panel {
|
||||||
@@ -467,12 +448,12 @@ async function handleResetSettings() {
|
|||||||
max-block-size: 100%;
|
max-block-size: 100%;
|
||||||
|
|
||||||
/* 独立 App 模式会贴近 viewport-fit=cover 顶部,面板内部需要避开 iOS 状态栏。 */
|
/* 独立 App 模式会贴近 viewport-fit=cover 顶部,面板内部需要避开 iOS 状态栏。 */
|
||||||
padding-block-start: env(safe-area-inset-top);
|
padding-block-start: env(safe-area-inset-top, 0px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-customizer-panel--dialog .theme-customizer-body {
|
.theme-customizer-panel--dialog .theme-customizer-body {
|
||||||
block-size: auto;
|
block-size: auto;
|
||||||
padding-block-end: env(safe-area-inset-bottom);
|
padding-block-end: env(safe-area-inset-bottom, 0px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (width <= 600px) {
|
@media (width <= 600px) {
|
||||||
|
|||||||
Reference in New Issue
Block a user