- gestione dell'editor delle pagine (non funzionante!)
This commit is contained in:
15
src/components/CMyImageGallery/CMyImageGallery.scss
Executable file
15
src/components/CMyImageGallery/CMyImageGallery.scss
Executable file
@@ -0,0 +1,15 @@
|
||||
.cmy-image-gallery {
|
||||
&.layout-grid {
|
||||
.gallery-grid { display: grid; }
|
||||
.gallery-item {
|
||||
cursor: pointer;
|
||||
.gallery-img { border-radius: 10px; overflow: hidden; }
|
||||
.gallery-caption { font-size: 0.9rem; opacity: 0.8; margin-top: 6px; }
|
||||
}
|
||||
}
|
||||
&.layout-carousel {
|
||||
.carousel-img { max-width: 100%; border-radius: 12px; }
|
||||
}
|
||||
.lightbox-card { width: min(92vw, 1100px); }
|
||||
.lightbox-img { max-height: 76vh; object-fit: contain; }
|
||||
}
|
||||
59
src/components/CMyImageGallery/CMyImageGallery.ts
Executable file
59
src/components/CMyImageGallery/CMyImageGallery.ts
Executable file
@@ -0,0 +1,59 @@
|
||||
import { defineComponent, ref, computed, type Ref } from 'vue';
|
||||
|
||||
export type GalleryImage = {
|
||||
src: string;
|
||||
alt?: string;
|
||||
caption?: string;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CMyImageGallery',
|
||||
props: {
|
||||
images: { type: Array as () => GalleryImage[], required: true },
|
||||
layout: { type: String as () => 'grid' | 'carousel', default: 'grid' },
|
||||
cols: { type: Number, default: 3 },
|
||||
gap: { type: Number, default: 12 },
|
||||
ratio: { type: Number, default: 1 },
|
||||
lightbox: { type: Boolean, default: false }
|
||||
},
|
||||
emits: ['imageClick'],
|
||||
setup(props, { emit }) {
|
||||
const slide: Ref<number> = ref(0);
|
||||
const lightboxOpen = ref(false);
|
||||
const currentIndex = ref(0);
|
||||
|
||||
const gridStyle = computed(() => ({
|
||||
gridTemplateColumns: `repeat(${props.cols}, 1fr)`,
|
||||
gap: props.gap + 'px'
|
||||
}));
|
||||
|
||||
const currentImage = computed(() => props.images?.[currentIndex.value] ?? null);
|
||||
|
||||
function onImageClick(idx: number) {
|
||||
emit('imageClick', idx, props.images[idx]);
|
||||
if (props.lightbox) {
|
||||
currentIndex.value = idx;
|
||||
lightboxOpen.value = true;
|
||||
}
|
||||
}
|
||||
function next() {
|
||||
if (!props.images?.length) return;
|
||||
currentIndex.value = (currentIndex.value + 1) % props.images.length;
|
||||
}
|
||||
function prev() {
|
||||
if (!props.images?.length) return;
|
||||
currentIndex.value = (currentIndex.value - 1 + props.images.length) % props.images.length;
|
||||
}
|
||||
|
||||
return {
|
||||
slide,
|
||||
lightboxOpen,
|
||||
currentIndex,
|
||||
currentImage,
|
||||
gridStyle,
|
||||
onImageClick,
|
||||
next,
|
||||
prev
|
||||
};
|
||||
}
|
||||
});
|
||||
67
src/components/CMyImageGallery/CMyImageGallery.vue
Executable file
67
src/components/CMyImageGallery/CMyImageGallery.vue
Executable file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="cmy-image-gallery" :class="[`layout-${layout}`]">
|
||||
<!-- GRID -->
|
||||
<div v-if="layout === 'grid'" class="gallery-grid" :style="gridStyle">
|
||||
<div
|
||||
v-for="(img, idx) in images"
|
||||
:key="idx"
|
||||
class="gallery-item"
|
||||
@click="onImageClick(idx)"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<q-img :src="img.src" :alt="img.alt || ''" :ratio="ratio" class="gallery-img" />
|
||||
<div v-if="img.caption" class="gallery-caption">{{ img.caption }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CAROUSEL -->
|
||||
<q-carousel
|
||||
v-else
|
||||
v-model="slide"
|
||||
animated
|
||||
arrows
|
||||
swipeable
|
||||
infinite
|
||||
class="gallery-carousel"
|
||||
height="auto"
|
||||
>
|
||||
<q-carousel-slide
|
||||
v-for="(img, idx) in images"
|
||||
:key="idx"
|
||||
:name="idx"
|
||||
class="column items-center q-pa-md"
|
||||
>
|
||||
<q-img :src="img.src" :alt="img.alt || ''" :ratio="ratio" class="carousel-img" />
|
||||
<div v-if="img.caption" class="gallery-caption q-mt-sm">{{ img.caption }}</div>
|
||||
</q-carousel-slide>
|
||||
</q-carousel>
|
||||
|
||||
<!-- Lightbox -->
|
||||
<q-dialog v-model="lightboxOpen" persistent>
|
||||
<q-card class="lightbox-card">
|
||||
<q-card-section class="row items-center justify-between">
|
||||
<div class="text-subtitle1">{{ currentImage?.caption }}</div>
|
||||
<q-btn flat round icon="close" @click="lightboxOpen = false" />
|
||||
</q-card-section>
|
||||
<q-separator />
|
||||
<q-card-section class="q-pa-none">
|
||||
<q-img :src="currentImage?.src" :alt="currentImage?.alt || ''" class="lightbox-img" />
|
||||
</q-card-section>
|
||||
<q-card-actions align="between">
|
||||
<q-btn flat icon="chevron_left" @click="prev" />
|
||||
<q-btn flat icon="chevron_right" @click="next" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./CMyImageGallery.ts">
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './CMyImageGallery.scss';
|
||||
</style>
|
||||
|
||||
|
||||
1
src/components/CMyImageGallery/index.ts
Executable file
1
src/components/CMyImageGallery/index.ts
Executable file
@@ -0,0 +1 @@
|
||||
export {default as CMyImageGallery} from './CMyImageGallery.vue'
|
||||
Reference in New Issue
Block a user