@fy-/fws-vue 2.3.16 → 2.3.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/ui/DefaultGallery.vue +92 -52
- package/package.json +1 -1
|
@@ -155,67 +155,74 @@ function adjustImageSize(img: HTMLImageElement, availableHeightPx: number) {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
// Image size and positioning
|
|
158
|
+
// Image size and positioning - improved to prevent overflow
|
|
159
159
|
const calculateImageSize = useDebounceFn(() => {
|
|
160
160
|
if (!imageContainerRef.value) return
|
|
161
161
|
|
|
162
|
-
nextTick
|
|
163
|
-
|
|
162
|
+
// Execute immediately without waiting for nextTick to prevent delayed resizing
|
|
163
|
+
const imageElements = imageContainerRef.value?.querySelectorAll('.image-display img, .image-display .video-component') as NodeListOf<HTMLElement>
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
if (!imageElements || imageElements.length === 0) return
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
// Get current panel heights for accurate calculations
|
|
168
|
+
const topControlsCurrentHeight = topControlsRef.value?.offsetHeight || 0
|
|
169
|
+
const infoPanelCurrentHeight = infoPanel.value && infoPanelRef.value ? infoPanelRef.value.offsetHeight : 0
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
// Apply sizing to all images
|
|
172
|
+
imageElements.forEach((img) => {
|
|
173
|
+
// Reset immediately to ensure proper recalculation
|
|
174
|
+
img.style.maxHeight = '0'
|
|
175
|
+
img.style.maxWidth = '0'
|
|
172
176
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
img.style.maxHeight = ''
|
|
176
|
-
img.style.maxWidth = ''
|
|
177
|
-
// Force browser to recalculate styles
|
|
178
|
-
void img.offsetHeight
|
|
177
|
+
// Force browser to recalculate styles
|
|
178
|
+
void img.offsetHeight
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
// Apply exact pixel measurements based on actual UI elements
|
|
181
|
+
const topHeight = topControlsCurrentHeight || 0
|
|
182
|
+
const infoHeight = infoPanelCurrentHeight || 0
|
|
183
|
+
// Increase padding for reliable containment - prevent overflow
|
|
184
|
+
const availableHeightPx = windowHeight.value - topHeight - infoHeight - 48
|
|
184
185
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
if (windowWidth.value <= 768) {
|
|
187
|
+
// Mobile specific sizing - more conservative to guarantee fit
|
|
188
|
+
img.style.maxHeight = `${availableHeightPx}px`
|
|
189
|
+
img.style.maxWidth = '85vw' // Reduce from 90vw to ensure it fits
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// Desktop sizing - account for sidebar if present
|
|
193
|
+
const sidebarWidth = sidePanel.value ? sidePanelRef.value?.offsetWidth || 256 : 0
|
|
194
|
+
// More conservative width calculation to prevent overflow
|
|
195
|
+
const availableWidthPx = windowWidth.value - sidebarWidth - 64
|
|
194
196
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
img.style.maxHeight = `${availableHeightPx}px`
|
|
198
|
+
img.style.maxWidth = `${availableWidthPx}px`
|
|
199
|
+
}
|
|
198
200
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
img.onload = () => adjustImageSize(img, availableHeightPx)
|
|
206
|
-
}
|
|
201
|
+
// For images, add special handling for natural dimensions
|
|
202
|
+
if (img instanceof HTMLImageElement) {
|
|
203
|
+
if (img.complete) {
|
|
204
|
+
adjustImageSize(img, availableHeightPx)
|
|
207
205
|
}
|
|
208
|
-
|
|
206
|
+
else {
|
|
207
|
+
img.onload = () => adjustImageSize(img, availableHeightPx)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
209
210
|
})
|
|
210
|
-
},
|
|
211
|
+
}, 10) // Reduced debounce time for faster response
|
|
211
212
|
|
|
212
213
|
// Update all layout measurements when any relevant state changes
|
|
214
|
+
// More aggressive calculation to prevent layout issues
|
|
213
215
|
const updateLayout = useDebounceFn(() => {
|
|
214
|
-
//
|
|
216
|
+
// Calculate immediately
|
|
217
|
+
calculateImageSize()
|
|
218
|
+
|
|
219
|
+
// Then again after a small delay to catch any delayed DOM updates
|
|
215
220
|
setTimeout(() => {
|
|
216
221
|
calculateImageSize()
|
|
222
|
+
// And one more time for extra safety after all transitions
|
|
223
|
+
setTimeout(() => calculateImageSize(), 100)
|
|
217
224
|
}, 10)
|
|
218
|
-
},
|
|
225
|
+
}, 10) // Reduced debounce time for faster response
|
|
219
226
|
|
|
220
227
|
// Modal controls
|
|
221
228
|
function setModal(value: boolean) {
|
|
@@ -272,9 +279,14 @@ const openGalleryImage = useDebounceFn((index: number | undefined) => {
|
|
|
272
279
|
})
|
|
273
280
|
}, 50)
|
|
274
281
|
|
|
275
|
-
// Navigation functions
|
|
282
|
+
// Navigation functions - improved for immediate sizing
|
|
276
283
|
function goNextImage() {
|
|
277
284
|
direction.value = 'next'
|
|
285
|
+
|
|
286
|
+
// Calculate size immediately before changing the image
|
|
287
|
+
// This ensures we have proper sizing before transition starts
|
|
288
|
+
calculateImageSize()
|
|
289
|
+
|
|
278
290
|
if (modelValue.value < props.images.length - 1) {
|
|
279
291
|
modelValue.value++
|
|
280
292
|
}
|
|
@@ -283,14 +295,23 @@ function goNextImage() {
|
|
|
283
295
|
}
|
|
284
296
|
resetControlsTimer()
|
|
285
297
|
|
|
286
|
-
// Force layout update when image changes
|
|
298
|
+
// Force immediate layout update when image changes
|
|
299
|
+
calculateImageSize()
|
|
300
|
+
|
|
301
|
+
// Another calculation after DOM is updated to ensure correct sizing
|
|
287
302
|
nextTick(() => {
|
|
288
|
-
|
|
303
|
+
calculateImageSize()
|
|
304
|
+
// Second calculation after a small delay to catch any late DOM changes
|
|
305
|
+
setTimeout(() => calculateImageSize(), 50)
|
|
289
306
|
})
|
|
290
307
|
}
|
|
291
308
|
|
|
292
309
|
function goPrevImage() {
|
|
293
310
|
direction.value = 'prev'
|
|
311
|
+
|
|
312
|
+
// Calculate size immediately before changing the image
|
|
313
|
+
calculateImageSize()
|
|
314
|
+
|
|
294
315
|
if (modelValue.value > 0) {
|
|
295
316
|
modelValue.value--
|
|
296
317
|
}
|
|
@@ -299,9 +320,14 @@ function goPrevImage() {
|
|
|
299
320
|
}
|
|
300
321
|
resetControlsTimer()
|
|
301
322
|
|
|
302
|
-
// Force layout update when image changes
|
|
323
|
+
// Force immediate layout update when image changes
|
|
324
|
+
calculateImageSize()
|
|
325
|
+
|
|
326
|
+
// Another calculation after DOM is updated to ensure correct sizing
|
|
303
327
|
nextTick(() => {
|
|
304
|
-
|
|
328
|
+
calculateImageSize()
|
|
329
|
+
// Second calculation after a small delay to catch any late DOM changes
|
|
330
|
+
setTimeout(() => calculateImageSize(), 50)
|
|
305
331
|
})
|
|
306
332
|
}
|
|
307
333
|
|
|
@@ -678,6 +704,7 @@ onUnmounted(() => {
|
|
|
678
704
|
<div
|
|
679
705
|
:key="`image-display-${modelValue}`"
|
|
680
706
|
class="image-display relative w-full h-full flex flex-col items-center justify-center"
|
|
707
|
+
@transitionend="calculateImageSize"
|
|
681
708
|
>
|
|
682
709
|
<!-- Actual Image/Video Content -->
|
|
683
710
|
<template v-if="videoComponent && isVideo(images[modelValue])">
|
|
@@ -697,7 +724,7 @@ onUnmounted(() => {
|
|
|
697
724
|
:style="{ maxHeight: availableHeight }"
|
|
698
725
|
:src="modelValueSrc"
|
|
699
726
|
:alt="`Gallery image ${modelValue + 1}`"
|
|
700
|
-
@load="
|
|
727
|
+
@load="() => { calculateImageSize(); nextTick(() => calculateImageSize()) }"
|
|
701
728
|
>
|
|
702
729
|
<component
|
|
703
730
|
:is="imageComponent"
|
|
@@ -773,7 +800,7 @@ onUnmounted(() => {
|
|
|
773
800
|
v-if="sidePanel"
|
|
774
801
|
ref="sidePanelRef"
|
|
775
802
|
class="side-panel hidden lg:block absolute right-0 top-0 bottom-0 w-64 bg-fv-neutral-800/90 backdrop-blur-md overflow-y-auto z-40 cool-scroll"
|
|
776
|
-
:style="{ 'padding-top': `${topControlsHeight}px` }"
|
|
803
|
+
:style="{ 'padding-top': `${topControlsHeight + 8}px` }"
|
|
777
804
|
>
|
|
778
805
|
<!-- Paging Controls if needed -->
|
|
779
806
|
<div v-if="paging" class="flex items-center justify-center pt-2">
|
|
@@ -839,10 +866,13 @@ onUnmounted(() => {
|
|
|
839
866
|
>
|
|
840
867
|
<div
|
|
841
868
|
v-if="showControls && images.length > 1 && !sidePanel"
|
|
842
|
-
class="absolute bottom-0 left-0 right-0 p-2 lg:hidden bg-gradient-to-t from-fv-neutral-900/90 to-transparent backdrop-blur-sm z-45"
|
|
843
|
-
:class="{ 'pb-
|
|
869
|
+
class="absolute bottom-0 left-0 right-0 p-1 pb-2 lg:hidden bg-gradient-to-t from-fv-neutral-900/90 to-transparent backdrop-blur-sm z-45"
|
|
870
|
+
:class="{ 'pb-4': infoPanel }"
|
|
871
|
+
@touchstart.stop
|
|
872
|
+
@touchmove.stop
|
|
873
|
+
@touchend.stop
|
|
844
874
|
>
|
|
845
|
-
<div class="overflow-x-auto flex space-x-2
|
|
875
|
+
<div class="overflow-x-auto flex space-x-2 px-1 no-scrollbar">
|
|
846
876
|
<div
|
|
847
877
|
v-for="(image, idx) in images"
|
|
848
878
|
:key="`mobile_thumb_${id}_${idx}`"
|
|
@@ -1172,4 +1202,14 @@ onUnmounted(() => {
|
|
|
1172
1202
|
font-size: 0.75rem;
|
|
1173
1203
|
z-index: 10;
|
|
1174
1204
|
}
|
|
1205
|
+
|
|
1206
|
+
/* Special class to hide scrollbars on mobile */
|
|
1207
|
+
.no-scrollbar {
|
|
1208
|
+
-ms-overflow-style: none; /* IE and Edge */
|
|
1209
|
+
scrollbar-width: none; /* Firefox */
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
.no-scrollbar::-webkit-scrollbar {
|
|
1213
|
+
display: none; /* Chrome, Safari and Opera */
|
|
1214
|
+
}
|
|
1175
1215
|
</style>
|