fix: resolve content clipping on mobile by moving tab padding to scroll container
Moves dynamic pt-20/pt-40 padding from perspective-container-wrapper (which shrank the content area) to the inner scroll container via computed style. Removes spacer divs in CloudFolder, AppDetails, MarketplaceAppDetails. Reduces excessive bottom padding in Marketplace. Hides Cloud/Network tabs in CloudFolder detail view. Teleports mobile back buttons to body to escape CSS transform containing block. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -180,7 +180,7 @@
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* On mobile, leave room for close button + tab bar below AIUI */
|
||||
/* On mobile, pad iframe so AIUI content ends above the tab bar */
|
||||
@media (max-width: 767px) {
|
||||
.chat-iframe-mobile {
|
||||
padding-bottom: calc(var(--mobile-tab-bar-height, 72px) + 52px);
|
||||
|
||||
@@ -8,16 +8,18 @@
|
||||
{{ backButtonText }}
|
||||
</button>
|
||||
|
||||
<!-- Mobile Full-Width Back Button -->
|
||||
<button
|
||||
@click="goBack"
|
||||
class="md:hidden mobile-back-btn glass-button px-6 py-3 rounded-lg font-medium shadow-2xl flex items-center justify-center gap-2"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<span>{{ backButtonText }}</span>
|
||||
</button>
|
||||
<!-- Mobile Full-Width Back Button (teleported to escape CSS transform containing block) -->
|
||||
<Teleport to="body">
|
||||
<button
|
||||
@click="goBack"
|
||||
class="md:hidden mobile-back-btn glass-button px-6 py-3 rounded-lg font-medium shadow-2xl flex items-center justify-center gap-2"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<span>{{ backButtonText }}</span>
|
||||
</button>
|
||||
</Teleport>
|
||||
|
||||
<div v-if="pkg">
|
||||
<!-- Compact Hero Section -->
|
||||
@@ -371,9 +373,6 @@
|
||||
<p class="text-white/70">The requested application could not be found</p>
|
||||
</div>
|
||||
|
||||
<!-- Spacer for mobile back button -->
|
||||
<div class="md:hidden h-[calc(var(--mobile-tab-bar-height,_64px)+96px)]"></div>
|
||||
|
||||
<!-- Uninstall Confirmation Modal -->
|
||||
<Transition name="modal">
|
||||
<div
|
||||
|
||||
@@ -54,21 +54,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile close bar (teleported to escape CSS transform containing block) -->
|
||||
<Teleport to="body">
|
||||
<div class="md:hidden mobile-back-btn flex items-center justify-center">
|
||||
<button
|
||||
class="w-full glass-button px-6 py-2.5 rounded-lg font-medium flex items-center justify-center gap-2 text-sm"
|
||||
style="background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);"
|
||||
@click="closeChat"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
Close Chat
|
||||
</button>
|
||||
</div>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -9,16 +9,18 @@
|
||||
Back to Cloud
|
||||
</button>
|
||||
|
||||
<!-- Mobile Back Button -->
|
||||
<button
|
||||
@click="goBack"
|
||||
class="md:hidden mobile-back-btn glass-button px-6 py-3 rounded-lg font-medium shadow-2xl flex items-center justify-center gap-2"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<span>Back to Cloud</span>
|
||||
</button>
|
||||
<!-- Mobile Back Button (teleported to escape CSS transform containing block) -->
|
||||
<Teleport to="body">
|
||||
<button
|
||||
@click="goBack"
|
||||
class="md:hidden mobile-back-btn glass-button px-6 py-3 rounded-lg font-medium shadow-2xl flex items-center justify-center gap-2"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<span>Back to Cloud</span>
|
||||
</button>
|
||||
</Teleport>
|
||||
|
||||
<!-- Folder Header -->
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -150,8 +152,6 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Spacer for mobile back button -->
|
||||
<div class="md:hidden h-[calc(var(--mobile-tab-bar-height,_64px)+96px)]"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="perspective-container-wrapper glass-piece" :class="{ 'pt-40': showAppsTabs && showNetworkTabs, 'pt-20': showAppsTabs !== showNetworkTabs, 'glass-throw-content': showZoomIn && !isHomeRoute }">
|
||||
<div class="perspective-container-wrapper glass-piece" :class="{ 'glass-throw-content': showZoomIn && !isHomeRoute }">
|
||||
<div class="perspective-container">
|
||||
<RouterView v-slot="{ Component, route }">
|
||||
<Transition :name="getTransitionName(route)">
|
||||
@@ -269,11 +269,12 @@
|
||||
<div
|
||||
v-else
|
||||
:class="[
|
||||
'px-4 pt-4 pb-28 md:px-8 md:pt-8 md:pb-24 overflow-y-auto h-full',
|
||||
'px-4 pt-4 md:pt-8 md:px-8 overflow-y-auto h-full',
|
||||
needsMobileBackButtonSpace
|
||||
? 'pb-[calc(var(--mobile-tab-bar-height,_72px)+96px)] md:pb-24'
|
||||
: undefined
|
||||
? 'pb-[calc(var(--mobile-tab-bar-height,_72px)+96px)] md:pb-8'
|
||||
: 'pb-4 md:pb-8'
|
||||
]"
|
||||
:style="mobileTabPaddingTop ? { paddingTop: (mobileTabPaddingTop + 16) + 'px' } : undefined"
|
||||
>
|
||||
<component :is="Component" class="view-container" />
|
||||
</div>
|
||||
@@ -451,9 +452,18 @@ const showAppsTabs = computed(() => {
|
||||
const showNetworkTabs = computed(() => {
|
||||
if (typeof window === 'undefined') return false
|
||||
if (window.innerWidth >= 768) return false
|
||||
if (route.name === 'cloud-folder') return false
|
||||
return route.path.includes('/server') || route.path.includes('/cloud')
|
||||
})
|
||||
|
||||
// Top padding for content div to clear fixed mobile tab overlays
|
||||
const mobileTabPaddingTop = computed(() => {
|
||||
if (typeof window === 'undefined' || window.innerWidth >= 768) return 0
|
||||
if (showAppsTabs.value && showNetworkTabs.value) return 160
|
||||
if (showAppsTabs.value || showNetworkTabs.value) return 80
|
||||
return 0
|
||||
})
|
||||
|
||||
function updateTabBarHeight() {
|
||||
if (typeof window === 'undefined') return
|
||||
if (mobileTabBar.value) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="mb-4 md:mb-8">
|
||||
<div class="mb-4 md:mb-8 flex items-start justify-between gap-4">
|
||||
<div class="min-h-[4.5rem]">
|
||||
<h1 class="text-3xl font-bold text-white mb-2 drop-shadow-[0_2px_8px_rgba(0,0,0,0.6)]">
|
||||
{{ line1Text }}<span v-if="showCaretLine1" class="typing-caret"></span>
|
||||
@@ -9,11 +9,24 @@
|
||||
{{ line2Text }}<span v-if="showCaretLine2" class="typing-caret"></span>
|
||||
</p>
|
||||
</div>
|
||||
<!-- Desktop: tabs inline with header -->
|
||||
<div
|
||||
v-if="!uiMode.isChat"
|
||||
class="hidden md:flex mode-switcher flex-shrink-0 transition-opacity duration-500"
|
||||
:class="{ 'opacity-0 pointer-events-none': showWelcomeBlock && !animateCards }"
|
||||
>
|
||||
<button class="mode-switcher-btn" :class="{ 'mode-switcher-btn-active': homeTab === 'dashboard' }" @click="homeTab = 'dashboard'">Dashboard</button>
|
||||
<button class="mode-switcher-btn" :class="{ 'mode-switcher-btn-active': homeTab === 'setup' }" @click="homeTab = 'setup'">Setup</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab bar + content (all non-chat modes) -->
|
||||
<template v-if="!uiMode.isChat">
|
||||
<div class="mode-switcher mb-6 max-w-xs">
|
||||
<!-- Mobile: full-width tabs -->
|
||||
<div
|
||||
class="md:hidden mode-switcher mb-6 w-full transition-opacity duration-500"
|
||||
:class="{ 'opacity-0 pointer-events-none': showWelcomeBlock && !animateCards }"
|
||||
>
|
||||
<button class="mode-switcher-btn" :class="{ 'mode-switcher-btn-active': homeTab === 'dashboard' }" @click="homeTab = 'dashboard'">Dashboard</button>
|
||||
<button class="mode-switcher-btn" :class="{ 'mode-switcher-btn-active': homeTab === 'setup' }" @click="homeTab = 'setup'">Setup</button>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="marketplace-container flex flex-col h-full overflow-hidden -mt-4 md:mt-0">
|
||||
<div class="marketplace-container flex flex-col h-full overflow-hidden md:-mt-4">
|
||||
<!-- Fixed Header Section -->
|
||||
<div class="flex-shrink-0 -mt-4 md:mt-0">
|
||||
<div class="flex-shrink-0 md:-mt-4">
|
||||
<!-- Installation Progress Banner - Multiple Apps -->
|
||||
<div v-if="installingApps.size > 0" class="mb-6 space-y-3">
|
||||
<div
|
||||
@@ -106,19 +106,19 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Search Bar (Mobile - placeholder for later) -->
|
||||
<div class="md:hidden mb-6">
|
||||
<!-- Search Bar (Mobile) -->
|
||||
<div class="md:hidden mb-4">
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
placeholder="Search apps..."
|
||||
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-white/40 transition-colors"
|
||||
class="w-full px-4 py-3 md:py-2 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-white/40 transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scrollable Apps Section -->
|
||||
<div class="flex-1 overflow-y-auto pr-2 -mr-2 pb-48">
|
||||
<div class="flex-1 overflow-y-auto pr-2 -mr-2 pb-4">
|
||||
<!-- Apps Grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div
|
||||
@@ -203,19 +203,18 @@
|
||||
</div>
|
||||
<!-- End Scrollable Apps Section -->
|
||||
|
||||
<!-- Floating Filter Button (Mobile only) -->
|
||||
<button
|
||||
@click="showFilterModal = true"
|
||||
class="md:hidden fixed right-4 z-40 w-14 h-14 rounded-full glass-button flex items-center justify-center shadow-2xl"
|
||||
:style="{
|
||||
bottom: bottomPosition,
|
||||
filter: 'drop-shadow(0 10px 25px rgba(0, 0, 0, 0.5))'
|
||||
}"
|
||||
>
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
|
||||
</svg>
|
||||
</button>
|
||||
<!-- Floating Filter Button (teleported to escape CSS transform containing block) -->
|
||||
<Teleport to="body">
|
||||
<button
|
||||
@click="showFilterModal = true"
|
||||
class="md:hidden fixed right-4 z-40 w-14 h-14 rounded-full glass-button flex items-center justify-center shadow-2xl mobile-back-btn"
|
||||
style="left: auto;"
|
||||
>
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
|
||||
</svg>
|
||||
</button>
|
||||
</Teleport>
|
||||
|
||||
<!-- Filter Modal (Mobile only) -->
|
||||
<Transition name="modal">
|
||||
@@ -304,13 +303,11 @@ import { useRouter } from 'vue-router'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { rpcClient } from '@/api/rpc-client'
|
||||
import { useMarketplaceApp } from '@/composables/useMarketplaceApp'
|
||||
import { useMobileBackButton } from '@/composables/useMobileBackButton'
|
||||
import { useModalKeyboard } from '@/composables/useModalKeyboard'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useAppStore()
|
||||
const { setCurrentApp } = useMarketplaceApp()
|
||||
const { bottomPosition } = useMobileBackButton()
|
||||
|
||||
// Category state
|
||||
const selectedCategory = ref('all')
|
||||
|
||||
@@ -320,8 +320,6 @@
|
||||
<p class="text-white/70">The requested application could not be found in the marketplace</p>
|
||||
</div>
|
||||
|
||||
<!-- Spacer for mobile back button -->
|
||||
<div class="md:hidden h-[calc(var(--mobile-tab-bar-height,_64px)+96px)]"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user