fix(ui): square mobile file tiles, files scroll clearance, apps-tab swipe guard
- Apps tab: a horizontal swipe that starts on an app icon no longer flips the top tab — it lets the app-page scroll / icon tap win (swipe empty space to change tab). Fixes the swipe conflict with two pages of apps. - Files: file cover tiles are forced square on mobile (aspect driven by CSS, not a Tailwind arbitrary class) so the grid is uniform and tappable. - Files: scroll container gets bottom safe-area + tab-bar padding so the last row clears the mobile back button / bottom nav. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a0b80dd27d
commit
cebbde7bde
@ -6,7 +6,7 @@
|
|||||||
@click="handleClick"
|
@click="handleClick"
|
||||||
>
|
>
|
||||||
<!-- Cover / Thumbnail area -->
|
<!-- Cover / Thumbnail area -->
|
||||||
<div class="cloud-grid-card-cover" :class="aspectClass">
|
<div class="cloud-grid-card-cover">
|
||||||
<!-- Image thumbnail -->
|
<!-- Image thumbnail -->
|
||||||
<img
|
<img
|
||||||
v-if="isImage && thumbnailUrl && !imgFailed"
|
v-if="isImage && thumbnailUrl && !imgFailed"
|
||||||
@ -155,7 +155,9 @@ const isCurrentlyPlaying = computed(() => audioPlaying.value && currentSrc.value
|
|||||||
// Uniform card cover ratio across every file type so folders, images, videos
|
// Uniform card cover ratio across every file type so folders, images, videos
|
||||||
// and documents all render at the same height in the grid (previously images/
|
// and documents all render at the same height in the grid (previously images/
|
||||||
// videos were square while folders were 4/3, giving a ragged, mismatched grid).
|
// videos were square while folders were 4/3, giving a ragged, mismatched grid).
|
||||||
const aspectClass = computed(() => 'aspect-[4/3]')
|
// Aspect is now driven entirely by .cloud-grid-card-cover CSS (4/3 desktop,
|
||||||
|
// square on mobile) so the ratio is deterministic regardless of Tailwind layer
|
||||||
|
// ordering.
|
||||||
|
|
||||||
const coverBg = computed(() => {
|
const coverBg = computed(() => {
|
||||||
if (props.item.isDir) return 'bg-amber-500/10'
|
if (props.item.isDir) return 'bg-amber-500/10'
|
||||||
|
|||||||
@ -1827,6 +1827,22 @@ html.modal-scroll-locked .dashboard-scroll-panel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile: square, tappable tiles + bottom clearance so the last row scrolls
|
||||||
|
above the tab bar / back button (matches .mobile-scroll-pad). */
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.cloud-card-grid,
|
||||||
|
.cloud-file-list {
|
||||||
|
padding-bottom: calc(
|
||||||
|
var(--mobile-tab-bar-height, 88px) +
|
||||||
|
var(--safe-area-bottom, env(safe-area-inset-bottom, 0px)) +
|
||||||
|
var(--audio-player-height, 0px) + 24px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
.cloud-grid-card-cover {
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cloud-grid-card {
|
.cloud-grid-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -1856,6 +1872,9 @@ html.modal-scroll-locked .dashboard-scroll-panel {
|
|||||||
.cloud-grid-card-cover {
|
.cloud-grid-card-cover {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
/* Fallback aspect when the Tailwind aspect-[4/3] utility is unavailable, so
|
||||||
|
the cover never collapses to zero height. */
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 0.625rem;
|
border-radius: 0.625rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -290,14 +290,19 @@ function activeNetKey(): string {
|
|||||||
let touchStartX = 0
|
let touchStartX = 0
|
||||||
let touchStartY = 0
|
let touchStartY = 0
|
||||||
let touchStartTime = 0
|
let touchStartTime = 0
|
||||||
|
let swipeSuppressed = false
|
||||||
function onContentTouchStart(e: TouchEvent) {
|
function onContentTouchStart(e: TouchEvent) {
|
||||||
const t = e.touches[0]
|
const t = e.touches[0]
|
||||||
if (!t) return
|
if (!t) return
|
||||||
|
// Don't begin a tab swipe when the gesture starts on an app icon — let the
|
||||||
|
// icon handle the tap/long-press. Swiping anywhere else still changes tabs.
|
||||||
|
swipeSuppressed = !!(e.target instanceof Element && e.target.closest('.app-icon-item'))
|
||||||
touchStartX = t.clientX
|
touchStartX = t.clientX
|
||||||
touchStartY = t.clientY
|
touchStartY = t.clientY
|
||||||
touchStartTime = e.timeStamp
|
touchStartTime = e.timeStamp
|
||||||
}
|
}
|
||||||
function onContentTouchEnd(e: TouchEvent) {
|
function onContentTouchEnd(e: TouchEvent) {
|
||||||
|
if (swipeSuppressed) { swipeSuppressed = false; return }
|
||||||
const t = e.changedTouches[0]
|
const t = e.changedTouches[0]
|
||||||
if (!t) return
|
if (!t) return
|
||||||
const dx = t.clientX - touchStartX
|
const dx = t.clientX - touchStartX
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user