@fy-/fws-vue 2.3.49 → 2.3.50
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 +67 -88
- package/package.json +1 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# This file has been completely rewritten and optimized
|
|
2
1
|
<script setup lang="ts">
|
|
3
2
|
import type { Component } from 'vue'
|
|
4
3
|
import type { APIPaging } from '../../composables/rest'
|
|
@@ -129,29 +128,46 @@ const currentImage = computed(() => {
|
|
|
129
128
|
const imageCount = computed(() => props.images.length)
|
|
130
129
|
const currentIndex = computed(() => modelValue.value + 1)
|
|
131
130
|
|
|
132
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Dynamically update the size of the displayed image/video
|
|
133
|
+
* so it fits inside the viewport, taking into account:
|
|
134
|
+
* - Top controls
|
|
135
|
+
* - Info panel (if open)
|
|
136
|
+
* - Side panel (if open)
|
|
137
|
+
* - A little padding
|
|
138
|
+
*/
|
|
133
139
|
const updateImageSizes = useDebounceFn(() => {
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
// Only adjust if gallery is open
|
|
141
|
+
if (!isGalleryOpen.value) return
|
|
142
|
+
|
|
143
|
+
// Find the container and the main media element (img or video)
|
|
144
|
+
const container = document.querySelector('.image-display') as HTMLDivElement
|
|
145
|
+
if (!container) return
|
|
146
|
+
const mainMedia = container.querySelector('img, video') as HTMLElement | null
|
|
147
|
+
if (!mainMedia) return
|
|
137
148
|
|
|
138
149
|
// Standard padding
|
|
139
150
|
const padding = 24
|
|
140
151
|
|
|
141
|
-
//
|
|
152
|
+
// Side panel width if visible
|
|
142
153
|
const sidebarWidth = sidePanel.value ? 256 : 0
|
|
154
|
+
|
|
155
|
+
// Calculate available width
|
|
143
156
|
const availableWidth = windowWidth.value - sidebarWidth - padding * 2
|
|
144
157
|
|
|
145
|
-
// Set width
|
|
146
|
-
|
|
147
|
-
? '90vw'
|
|
148
|
-
: `${availableWidth}px`
|
|
158
|
+
// Set max width
|
|
159
|
+
mainMedia.style.maxWidth
|
|
160
|
+
= windowWidth.value <= 768 ? '90vw' : `${availableWidth}px`
|
|
149
161
|
|
|
150
|
-
//
|
|
151
|
-
|
|
162
|
+
// Preserve aspect ratio; let height be auto
|
|
163
|
+
mainMedia.style.height = 'auto'
|
|
152
164
|
|
|
153
|
-
//
|
|
154
|
-
|
|
165
|
+
// Deduct top controls height + info panel height (if open) + padding
|
|
166
|
+
const topSpace = topControlsHeight.value || 0
|
|
167
|
+
const infoSpace = infoPanel.value ? (infoPanelHeight.value || 0) : 0
|
|
168
|
+
const availableHeight = windowHeight.value - topSpace - infoSpace - padding * 2
|
|
169
|
+
|
|
170
|
+
mainMedia.style.maxHeight = `${availableHeight}px`
|
|
155
171
|
}, 50)
|
|
156
172
|
|
|
157
173
|
// Modal controls
|
|
@@ -164,8 +180,6 @@ function setModal(value: boolean) {
|
|
|
164
180
|
useEventListener(document, 'keydown', handleKeyboardInput)
|
|
165
181
|
useEventListener(document, 'keyup', handleKeyboardRelease)
|
|
166
182
|
}
|
|
167
|
-
|
|
168
|
-
// No longer auto-hide controls on mobile
|
|
169
183
|
}
|
|
170
184
|
else {
|
|
171
185
|
if (props.onClose) props.onClose()
|
|
@@ -185,7 +199,6 @@ function setModal(value: boolean) {
|
|
|
185
199
|
}
|
|
186
200
|
isGalleryOpen.value = value
|
|
187
201
|
showControls.value = true
|
|
188
|
-
// Don't reset info panel state when opening/closing
|
|
189
202
|
}
|
|
190
203
|
|
|
191
204
|
// Open gallery with debounce to prevent accidental double-clicks
|
|
@@ -207,7 +220,6 @@ const openGalleryImage = useDebounceFn((index: number | undefined) => {
|
|
|
207
220
|
// Navigation functions
|
|
208
221
|
function goNextImage() {
|
|
209
222
|
direction.value = 'next'
|
|
210
|
-
|
|
211
223
|
if (modelValue.value < props.images.length - 1) {
|
|
212
224
|
modelValue.value++
|
|
213
225
|
}
|
|
@@ -216,7 +228,6 @@ function goNextImage() {
|
|
|
216
228
|
}
|
|
217
229
|
resetControlsTimer()
|
|
218
230
|
|
|
219
|
-
// Force image sizing update after navigation
|
|
220
231
|
nextTick(() => {
|
|
221
232
|
updateImageSizes()
|
|
222
233
|
})
|
|
@@ -224,7 +235,6 @@ function goNextImage() {
|
|
|
224
235
|
|
|
225
236
|
function goPrevImage() {
|
|
226
237
|
direction.value = 'prev'
|
|
227
|
-
|
|
228
238
|
if (modelValue.value > 0) {
|
|
229
239
|
modelValue.value--
|
|
230
240
|
}
|
|
@@ -233,7 +243,6 @@ function goPrevImage() {
|
|
|
233
243
|
}
|
|
234
244
|
resetControlsTimer()
|
|
235
245
|
|
|
236
|
-
// Force image sizing update after navigation
|
|
237
246
|
nextTick(() => {
|
|
238
247
|
updateImageSizes()
|
|
239
248
|
})
|
|
@@ -245,11 +254,6 @@ function resetControlsTimer() {
|
|
|
245
254
|
showControls.value = true
|
|
246
255
|
}
|
|
247
256
|
|
|
248
|
-
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
249
|
-
function toggleControls() {
|
|
250
|
-
showControls.value = !showControls.value
|
|
251
|
-
}
|
|
252
|
-
|
|
253
257
|
function toggleInfoPanel() {
|
|
254
258
|
infoPanel.value = !infoPanel.value
|
|
255
259
|
resetControlsTimer()
|
|
@@ -257,10 +261,8 @@ function toggleInfoPanel() {
|
|
|
257
261
|
// Update layout immediately AND after nextTick to ensure DOM updates
|
|
258
262
|
updateImageSizes()
|
|
259
263
|
|
|
260
|
-
// Schedule multiple updates to handle any transition effects
|
|
261
264
|
nextTick(() => {
|
|
262
265
|
updateImageSizes()
|
|
263
|
-
|
|
264
266
|
// Additional delayed updates to catch transitions
|
|
265
267
|
setTimeout(() => updateImageSizes(), 50)
|
|
266
268
|
setTimeout(() => updateImageSizes(), 300)
|
|
@@ -271,7 +273,6 @@ function toggleSidePanel() {
|
|
|
271
273
|
sidePanel.value = !sidePanel.value
|
|
272
274
|
resetControlsTimer()
|
|
273
275
|
|
|
274
|
-
// Update layout after panel toggle
|
|
275
276
|
nextTick(() => {
|
|
276
277
|
updateImageSizes()
|
|
277
278
|
})
|
|
@@ -283,7 +284,6 @@ function toggleFullscreen() {
|
|
|
283
284
|
enterFullscreen()
|
|
284
285
|
.then(() => {
|
|
285
286
|
isFullscreen.value = true
|
|
286
|
-
// Give browser time to adjust fullscreen before updating sizing
|
|
287
287
|
if (fullscreenResizeTimeout) clearTimeout(fullscreenResizeTimeout)
|
|
288
288
|
fullscreenResizeTimeout = window.setTimeout(() => {
|
|
289
289
|
updateImageSizes()
|
|
@@ -311,12 +311,11 @@ const touchStart = useDebounceFn((event: TouchEvent) => {
|
|
|
311
311
|
const touch = event.touches[0]
|
|
312
312
|
const targetElement = touch.target as HTMLElement
|
|
313
313
|
|
|
314
|
-
// Store start time for tap detection
|
|
315
314
|
touchStartTime.value = Date.now()
|
|
316
315
|
|
|
317
|
-
//
|
|
316
|
+
// Ignore swipes if starting on an interactive element
|
|
318
317
|
if (targetElement.closest('button, a, input, textarea, select')) {
|
|
319
|
-
return
|
|
318
|
+
return
|
|
320
319
|
}
|
|
321
320
|
|
|
322
321
|
start.x = touch.screenX
|
|
@@ -328,9 +327,9 @@ const touchEnd = useDebounceFn((event: TouchEvent) => {
|
|
|
328
327
|
const targetElement = touch.target as HTMLElement
|
|
329
328
|
const touchDuration = Date.now() - touchStartTime.value
|
|
330
329
|
|
|
331
|
-
//
|
|
330
|
+
// Ignore swipes if ending on an interactive element
|
|
332
331
|
if (targetElement.closest('button, a, input, textarea, select')) {
|
|
333
|
-
return
|
|
332
|
+
return
|
|
334
333
|
}
|
|
335
334
|
|
|
336
335
|
const end = { x: touch.screenX, y: touch.screenY }
|
|
@@ -338,12 +337,12 @@ const touchEnd = useDebounceFn((event: TouchEvent) => {
|
|
|
338
337
|
const diffX = start.x - end.x
|
|
339
338
|
const diffY = start.y - end.y
|
|
340
339
|
|
|
341
|
-
//
|
|
340
|
+
// If it's a quick tap (not a swipe), do nothing
|
|
342
341
|
if (Math.abs(diffX) < 10 && Math.abs(diffY) < 10 && touchDuration < 300) {
|
|
343
342
|
return
|
|
344
343
|
}
|
|
345
344
|
|
|
346
|
-
//
|
|
345
|
+
// Left/right swipe
|
|
347
346
|
if (Math.abs(diffX) > Math.abs(diffY) && Math.abs(diffX) > 50) {
|
|
348
347
|
if (diffX > 0) {
|
|
349
348
|
goNextImage()
|
|
@@ -401,14 +400,14 @@ function closeGallery() {
|
|
|
401
400
|
setModal(false)
|
|
402
401
|
}
|
|
403
402
|
|
|
404
|
-
// Click outside gallery content to close - with debounce
|
|
403
|
+
// Click outside gallery content to close - with debounce
|
|
405
404
|
const handleBackdropClick = useDebounceFn((event: MouseEvent) => {
|
|
406
405
|
if (event.target === event.currentTarget) {
|
|
407
406
|
setModal(false)
|
|
408
407
|
}
|
|
409
408
|
}, 200)
|
|
410
409
|
|
|
411
|
-
// Watch for
|
|
410
|
+
// Watch for changes that affect sizing
|
|
412
411
|
watch(
|
|
413
412
|
[
|
|
414
413
|
currentImage,
|
|
@@ -462,7 +461,7 @@ onUnmounted(() => {
|
|
|
462
461
|
eventBus.off(`${props.id}GalleryClose`, closeGallery)
|
|
463
462
|
|
|
464
463
|
if (!import.meta.env.SSR) {
|
|
465
|
-
document.body.style.overflow = '' //
|
|
464
|
+
document.body.style.overflow = '' // Restore scrolling
|
|
466
465
|
}
|
|
467
466
|
|
|
468
467
|
// Clear any remaining timeouts
|
|
@@ -500,7 +499,7 @@ onUnmounted(() => {
|
|
|
500
499
|
aria-modal="true"
|
|
501
500
|
@click="handleBackdropClick"
|
|
502
501
|
>
|
|
503
|
-
<!-- Top Controls Bar
|
|
502
|
+
<!-- Top Controls Bar -->
|
|
504
503
|
<transition
|
|
505
504
|
enter-active-class="transition-opacity duration-300"
|
|
506
505
|
enter-from-class="opacity-0"
|
|
@@ -551,19 +550,19 @@ onUnmounted(() => {
|
|
|
551
550
|
</div>
|
|
552
551
|
</transition>
|
|
553
552
|
|
|
554
|
-
<!-- Main Gallery Content
|
|
553
|
+
<!-- Main Gallery Content -->
|
|
555
554
|
<div
|
|
556
555
|
ref="galleryContentRef"
|
|
557
556
|
class="w-full h-full flex flex-col lg:flex-row"
|
|
558
557
|
>
|
|
559
|
-
<!-- Main Image Area
|
|
558
|
+
<!-- Main Image Area -->
|
|
560
559
|
<div
|
|
561
560
|
class="relative flex-1 h-full flex flex-col"
|
|
562
561
|
:style="{ paddingTop: `${topControlsHeight}px` }"
|
|
563
562
|
:class="{ 'lg:pr-64': sidePanel, 'lg:max-w-[calc(100%-16rem)]': sidePanel }"
|
|
564
563
|
style="max-width: 100%;"
|
|
565
564
|
>
|
|
566
|
-
<!--
|
|
565
|
+
<!-- Left Navigation (Previous) -->
|
|
567
566
|
<transition
|
|
568
567
|
enter-active-class="transition-opacity duration-300"
|
|
569
568
|
enter-from-class="opacity-0"
|
|
@@ -586,7 +585,7 @@ onUnmounted(() => {
|
|
|
586
585
|
</div>
|
|
587
586
|
</transition>
|
|
588
587
|
|
|
589
|
-
<!-- Image Container
|
|
588
|
+
<!-- Image/Video Container -->
|
|
590
589
|
<div
|
|
591
590
|
ref="imageContainerRef"
|
|
592
591
|
class="flex-grow flex items-center justify-center"
|
|
@@ -603,17 +602,19 @@ onUnmounted(() => {
|
|
|
603
602
|
:key="`image-display-${modelValue}`"
|
|
604
603
|
class="image-display relative w-full h-full flex flex-col items-center justify-center"
|
|
605
604
|
>
|
|
606
|
-
<!--
|
|
605
|
+
<!-- If video -->
|
|
607
606
|
<template v-if="videoComponent && isVideo(images[modelValue])">
|
|
608
607
|
<ClientOnly>
|
|
609
608
|
<component
|
|
610
609
|
:is="videoComponent"
|
|
611
610
|
:src="isVideo(images[modelValue])"
|
|
612
611
|
class="shadow max-w-full h-auto object-contain video-component"
|
|
613
|
-
@
|
|
612
|
+
@loadedmetadata="updateImageSizes"
|
|
613
|
+
@loadeddata="updateImageSizes"
|
|
614
614
|
/>
|
|
615
615
|
</ClientOnly>
|
|
616
616
|
</template>
|
|
617
|
+
<!-- Otherwise, image -->
|
|
617
618
|
<template v-else>
|
|
618
619
|
<img
|
|
619
620
|
v-if="modelValueSrc && imageComponent === 'img'"
|
|
@@ -635,7 +636,7 @@ onUnmounted(() => {
|
|
|
635
636
|
</transition>
|
|
636
637
|
</div>
|
|
637
638
|
|
|
638
|
-
<!--
|
|
639
|
+
<!-- Right Navigation (Next) -->
|
|
639
640
|
<transition
|
|
640
641
|
enter-active-class="transition-opacity duration-300"
|
|
641
642
|
enter-from-class="opacity-0"
|
|
@@ -659,7 +660,7 @@ onUnmounted(() => {
|
|
|
659
660
|
</div>
|
|
660
661
|
</transition>
|
|
661
662
|
|
|
662
|
-
<!-- Info Panel
|
|
663
|
+
<!-- Info Panel -->
|
|
663
664
|
<transition
|
|
664
665
|
enter-active-class="transition-all duration-300 ease-out"
|
|
665
666
|
enter-from-class="opacity-0 transform translate-y-4"
|
|
@@ -678,7 +679,7 @@ onUnmounted(() => {
|
|
|
678
679
|
</transition>
|
|
679
680
|
</div>
|
|
680
681
|
|
|
681
|
-
<!-- Side Thumbnails Panel -->
|
|
682
|
+
<!-- Side Thumbnails Panel (Desktop) -->
|
|
682
683
|
<transition
|
|
683
684
|
enter-active-class="transform transition ease-in-out duration-300"
|
|
684
685
|
enter-from-class="translate-x-full"
|
|
@@ -693,12 +694,12 @@ onUnmounted(() => {
|
|
|
693
694
|
class="side-panel hidden lg:block absolute right-0 top-0 bottom-0 w-64 overflow-y-auto z-40 cool-scroll"
|
|
694
695
|
:style="{ paddingTop: `${topControlsHeight + 8}px` }"
|
|
695
696
|
>
|
|
696
|
-
<!-- Paging Controls
|
|
697
|
+
<!-- Paging Controls -->
|
|
697
698
|
<div v-if="paging" class="flex items-center justify-center pt-2">
|
|
698
699
|
<DefaultPaging :id="id" :items="paging" />
|
|
699
700
|
</div>
|
|
700
701
|
|
|
701
|
-
<!--
|
|
702
|
+
<!-- Thumbnails -->
|
|
702
703
|
<div class="grid grid-cols-2 gap-2 p-2">
|
|
703
704
|
<div
|
|
704
705
|
v-for="i in images.length"
|
|
@@ -746,7 +747,7 @@ onUnmounted(() => {
|
|
|
746
747
|
</div>
|
|
747
748
|
</transition>
|
|
748
749
|
|
|
749
|
-
<!-- Mobile Thumbnail
|
|
750
|
+
<!-- Mobile Thumbnail Row (Bottom) -->
|
|
750
751
|
<transition
|
|
751
752
|
enter-active-class="transition-transform duration-300 ease-out"
|
|
752
753
|
enter-from-class="translate-y-full"
|
|
@@ -799,7 +800,7 @@ onUnmounted(() => {
|
|
|
799
800
|
</div>
|
|
800
801
|
</transition>
|
|
801
802
|
|
|
802
|
-
<!-- Thumbnail Grid/
|
|
803
|
+
<!-- Thumbnail Grid/Masonry/Custom Layouts if gallery is not open -->
|
|
803
804
|
<div v-if="mode === 'grid' || mode === 'mason' || mode === 'custom'" class="gallery-grid">
|
|
804
805
|
<div
|
|
805
806
|
:class="{
|
|
@@ -809,8 +810,11 @@ onUnmounted(() => {
|
|
|
809
810
|
}"
|
|
810
811
|
>
|
|
811
812
|
<slot name="thumbnail" />
|
|
813
|
+
|
|
814
|
+
<!-- Iterate images -->
|
|
812
815
|
<template v-for="i in images.length" :key="`g_${id}_${i}`">
|
|
813
816
|
<template v-if="mode === 'mason'">
|
|
817
|
+
<!-- Example naive "masonry" approach -->
|
|
814
818
|
<div
|
|
815
819
|
v-if="i + (1 % gridHeight) === 0"
|
|
816
820
|
class="masonry-column relative"
|
|
@@ -818,7 +822,6 @@ onUnmounted(() => {
|
|
|
818
822
|
<div v-if="ranking" class="img-gallery-ranking">
|
|
819
823
|
{{ i }}
|
|
820
824
|
</div>
|
|
821
|
-
|
|
822
825
|
<template v-for="j in gridHeight" :key="`gi_${id}_${i + j}`">
|
|
823
826
|
<div class="masonry-item">
|
|
824
827
|
<img
|
|
@@ -893,12 +896,10 @@ onUnmounted(() => {
|
|
|
893
896
|
</template>
|
|
894
897
|
|
|
895
898
|
<style scoped>
|
|
896
|
-
/* Ensure controls stay fixed at top */
|
|
897
899
|
.controls-bar {
|
|
898
900
|
height: auto;
|
|
899
901
|
}
|
|
900
902
|
|
|
901
|
-
/* Layout container for main image and info panel */
|
|
902
903
|
.image-container {
|
|
903
904
|
position: relative;
|
|
904
905
|
display: flex;
|
|
@@ -909,87 +910,74 @@ onUnmounted(() => {
|
|
|
909
910
|
width: 100%;
|
|
910
911
|
}
|
|
911
912
|
|
|
912
|
-
/* Side panel positioning */
|
|
913
913
|
.side-panel {
|
|
914
914
|
height: 100vh;
|
|
915
915
|
overflow-y: auto;
|
|
916
916
|
overflow-x: hidden;
|
|
917
917
|
}
|
|
918
918
|
|
|
919
|
-
/* Info panel styling */
|
|
920
919
|
.info-panel {
|
|
921
920
|
width: 100%;
|
|
922
921
|
border-top-left-radius: 0.5rem;
|
|
923
922
|
border-top-right-radius: 0.5rem;
|
|
924
923
|
}
|
|
925
924
|
|
|
926
|
-
/*
|
|
925
|
+
/* Transitions for next/prev images */
|
|
927
926
|
.slide-next-enter-active,
|
|
928
|
-
.slide-next-leave-active
|
|
927
|
+
.slide-next-leave-active,
|
|
928
|
+
.slide-prev-enter-active,
|
|
929
|
+
.slide-prev-leave-active {
|
|
929
930
|
transition:
|
|
930
931
|
opacity 0.15s,
|
|
931
932
|
transform 0.15s,
|
|
932
933
|
filter 0.15s;
|
|
933
934
|
}
|
|
934
935
|
|
|
936
|
+
/* Next (slide from right) */
|
|
935
937
|
.slide-next-enter-from {
|
|
936
938
|
opacity: 0;
|
|
937
939
|
transform: translateX(30px);
|
|
938
940
|
filter: blur(8px);
|
|
939
941
|
}
|
|
940
|
-
|
|
941
942
|
.slide-next-enter-to {
|
|
942
943
|
opacity: 1;
|
|
943
944
|
transform: translateX(0);
|
|
944
945
|
filter: blur(0);
|
|
945
946
|
}
|
|
946
|
-
|
|
947
947
|
.slide-next-leave-from {
|
|
948
948
|
opacity: 1;
|
|
949
949
|
transform: translateX(0);
|
|
950
950
|
filter: blur(0);
|
|
951
951
|
}
|
|
952
|
-
|
|
953
952
|
.slide-next-leave-to {
|
|
954
953
|
opacity: 0;
|
|
955
954
|
transform: translateX(-30px);
|
|
956
955
|
filter: blur(8px);
|
|
957
956
|
}
|
|
958
957
|
|
|
959
|
-
/*
|
|
960
|
-
.slide-prev-enter-active,
|
|
961
|
-
.slide-prev-leave-active {
|
|
962
|
-
transition:
|
|
963
|
-
opacity 0.15s,
|
|
964
|
-
transform 0.15s,
|
|
965
|
-
filter 0.15s;
|
|
966
|
-
}
|
|
967
|
-
|
|
958
|
+
/* Prev (slide from left) */
|
|
968
959
|
.slide-prev-enter-from {
|
|
969
960
|
opacity: 0;
|
|
970
961
|
transform: translateX(-30px);
|
|
971
962
|
filter: blur(8px);
|
|
972
963
|
}
|
|
973
|
-
|
|
974
964
|
.slide-prev-enter-to {
|
|
975
965
|
opacity: 1;
|
|
976
966
|
transform: translateX(0);
|
|
977
967
|
filter: blur(0);
|
|
978
968
|
}
|
|
979
|
-
|
|
980
969
|
.slide-prev-leave-from {
|
|
981
970
|
opacity: 1;
|
|
982
971
|
transform: translateX(0);
|
|
983
972
|
filter: blur(0);
|
|
984
973
|
}
|
|
985
|
-
|
|
986
974
|
.slide-prev-leave-to {
|
|
987
975
|
opacity: 0;
|
|
988
976
|
transform: translateX(30px);
|
|
989
977
|
filter: blur(8px);
|
|
990
978
|
}
|
|
991
979
|
|
|
992
|
-
/* Grid layouts
|
|
980
|
+
/* Grid layouts */
|
|
993
981
|
.gallery-grid {
|
|
994
982
|
min-height: 200px;
|
|
995
983
|
}
|
|
@@ -999,32 +987,27 @@ onUnmounted(() => {
|
|
|
999
987
|
grid-template-columns: repeat(1, 1fr);
|
|
1000
988
|
gap: 0.75rem;
|
|
1001
989
|
}
|
|
1002
|
-
|
|
1003
990
|
@media (min-width: 480px) {
|
|
1004
991
|
.standard-grid {
|
|
1005
992
|
grid-template-columns: repeat(2, 1fr);
|
|
1006
993
|
}
|
|
1007
994
|
}
|
|
1008
|
-
|
|
1009
995
|
@media (min-width: 768px) {
|
|
1010
996
|
.standard-grid {
|
|
1011
997
|
grid-template-columns: repeat(3, 1fr);
|
|
1012
998
|
gap: 1rem;
|
|
1013
999
|
}
|
|
1014
1000
|
}
|
|
1015
|
-
|
|
1016
1001
|
@media (min-width: 1024px) {
|
|
1017
1002
|
.standard-grid {
|
|
1018
1003
|
grid-template-columns: repeat(4, 1fr);
|
|
1019
1004
|
}
|
|
1020
1005
|
}
|
|
1021
|
-
|
|
1022
1006
|
@media (min-width: 1280px) {
|
|
1023
1007
|
.standard-grid {
|
|
1024
1008
|
grid-template-columns: repeat(5, 1fr);
|
|
1025
1009
|
}
|
|
1026
1010
|
}
|
|
1027
|
-
|
|
1028
1011
|
@media (min-width: 1536px) {
|
|
1029
1012
|
.standard-grid {
|
|
1030
1013
|
grid-template-columns: repeat(6, 1fr);
|
|
@@ -1036,20 +1019,17 @@ onUnmounted(() => {
|
|
|
1036
1019
|
grid-template-columns: repeat(1, 1fr);
|
|
1037
1020
|
gap: 0.75rem;
|
|
1038
1021
|
}
|
|
1039
|
-
|
|
1040
1022
|
@media (min-width: 480px) {
|
|
1041
1023
|
.masonry-grid {
|
|
1042
1024
|
grid-template-columns: repeat(2, 1fr);
|
|
1043
1025
|
}
|
|
1044
1026
|
}
|
|
1045
|
-
|
|
1046
1027
|
@media (min-width: 768px) {
|
|
1047
1028
|
.masonry-grid {
|
|
1048
1029
|
grid-template-columns: repeat(3, 1fr);
|
|
1049
1030
|
gap: 1rem;
|
|
1050
1031
|
}
|
|
1051
1032
|
}
|
|
1052
|
-
|
|
1053
1033
|
@media (min-width: 1024px) {
|
|
1054
1034
|
.masonry-grid {
|
|
1055
1035
|
grid-template-columns: repeat(4, 1fr);
|
|
@@ -1087,13 +1067,12 @@ onUnmounted(() => {
|
|
|
1087
1067
|
z-index: 10;
|
|
1088
1068
|
}
|
|
1089
1069
|
|
|
1090
|
-
/*
|
|
1070
|
+
/* Hide scrollbars on mobile */
|
|
1091
1071
|
.no-scrollbar {
|
|
1092
1072
|
-ms-overflow-style: none; /* IE and Edge */
|
|
1093
1073
|
scrollbar-width: none; /* Firefox */
|
|
1094
1074
|
}
|
|
1095
|
-
|
|
1096
1075
|
.no-scrollbar::-webkit-scrollbar {
|
|
1097
|
-
display: none; /* Chrome, Safari and Opera */
|
|
1076
|
+
display: none; /* Chrome, Safari, and Opera */
|
|
1098
1077
|
}
|
|
1099
1078
|
</style>
|