Implementace photoswipe
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
<script setup>
|
||||
import {formatDatetime} from "src/composables/datetimeUtils";
|
||||
import {roundWithPrecision} from "src/composables/utils";
|
||||
import EmbeddedMap from "components/map/EmbeddedMap.vue";
|
||||
|
||||
const props = defineProps({
|
||||
photo: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pswp-caption-content">
|
||||
<strong v-if="photo.name !== ''">{{ photo.name }}</strong>
|
||||
<article v-html="photo.description" v-if="photo.description !== ''"/>
|
||||
<q-list>
|
||||
<q-item v-if="photo.pointOfInterest">
|
||||
<q-item-section avatar>
|
||||
<q-avatar icon="marker"></q-avatar>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
{{ photo.pointOfInterest.name }}
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item v-if="photo.exposedAt">
|
||||
<q-item-section avatar>
|
||||
<q-avatar icon="photo_camera"></q-avatar>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
{{ formatDatetime(photo.exposedAt) }}
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item v-if="photo.gpsAltitude">
|
||||
<q-item-section avatar>
|
||||
<q-avatar icon="height"/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
Nadmořská výška: {{ roundWithPrecision(photo.gpsAltitude, 1) }} m
|
||||
<br>
|
||||
<template v-if="photo.terrainElevation">
|
||||
Výška terénu: {{ roundWithPrecision(photo.terrainElevation, 1) }} m
|
||||
<br>
|
||||
Výška nad zemí: {{ roundWithPrecision(photo.gpsAltitude - photo.terrainElevation, 1) }} m
|
||||
</template>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
|
||||
|
||||
<div style="height: 200px; width: 100%;">
|
||||
<EmbeddedMap
|
||||
v-if="photo.gpsLatitude && photo.gpsLongitude"
|
||||
height="200px"
|
||||
class="q-mb-sm"
|
||||
:gps-latitude="photo.gpsLatitude"
|
||||
:gps-longitude="photo.gpsLongitude"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,103 @@
|
||||
<script setup>
|
||||
import {onMounted, onUnmounted, ref} from "vue";
|
||||
import PhotoSwipeLightbox from "photoswipe/lightbox";
|
||||
import 'photoswipe/style.css';
|
||||
import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css";
|
||||
import PhotoSwipeDynamicCaption from "photoswipe-dynamic-caption-plugin";
|
||||
import MapWithMarkers from "components/map/MapWithMarkers.vue";
|
||||
import {formatDatetime} from "src/composables/datetimeUtils";
|
||||
import EmbeddedMap from "components/map/EmbeddedMap.vue";
|
||||
import {roundWithPrecision} from "../../composables/utils";
|
||||
import PhotoCaption from "components/photos/PhotoCaption.vue";
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
galleryId: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: () => "randomGalleryId"
|
||||
},
|
||||
photos: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
let $lightbox = null;
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
if (!$lightbox) {
|
||||
$lightbox = new PhotoSwipeLightbox({
|
||||
gallery: '#' + props.galleryId,
|
||||
children: 'a',
|
||||
pswpModule: () => import('photoswipe'),
|
||||
});
|
||||
|
||||
let captionPlugin = new PhotoSwipeDynamicCaption($lightbox, {
|
||||
type: 'auto',
|
||||
});
|
||||
|
||||
// $lightbox.on('uiRegister', function () {
|
||||
// $lightbox.pswp.ui.registerElement({
|
||||
// name: 'test-button',
|
||||
// order: 9,
|
||||
// isButton: true,
|
||||
// html: infoIcon,
|
||||
// onClick: (event, el, pswp) => {
|
||||
// for (const elem of document.querySelectorAll('.pswp__dynamic-caption')) {
|
||||
// elem.style.display = "block";
|
||||
// }
|
||||
//
|
||||
// // pswp.currSlide.dynamicCaption.element.style.display="block";
|
||||
// // pswp.currSlide.dynamicCaption.element.hidden = false;
|
||||
// pswp.dispatch("calcSlideSize", {slide: pswp.currSlide});
|
||||
// pswp.currSlide.zoomAndPanToInitial();
|
||||
//
|
||||
// // captionPlugin.recalculateZoomLevelAndBounds(pswp.currSlide);
|
||||
// // captionPlugin.storeAdjustedPanAreaSize(pswp.currSlide);
|
||||
// // captionPlugin.storeOriginalPanAreaSize(pswp.currSlide);
|
||||
// // window.resize();
|
||||
// // captionPlugin.updateCaptionPosition(pswp.currSlide);
|
||||
// // captionPlugin.adjustPanArea(pswp.currSlide, pswp.currSlide.zoomLevels.initial);
|
||||
// // // captionPlugin.showCaption(pswp.currSlide);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
$lightbox.init();
|
||||
}
|
||||
});
|
||||
onUnmounted(() => {
|
||||
if ($lightbox) {
|
||||
$lightbox.destroy();
|
||||
$lightbox = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :id="galleryId" class="row">
|
||||
<div class="col-6 col-sm-4 col-md-4 col-lg-3 q-pa-sm" v-for="photo in photos" :key="photo.id">
|
||||
<a
|
||||
:href="photo.url"
|
||||
:data-pswp-width="photo.width"
|
||||
:data-pswp-height="photo.height"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<q-img
|
||||
spinner-color="primary"
|
||||
class="rounded-borders"
|
||||
:src="photo.thumbnailUrl"
|
||||
alt=""
|
||||
>
|
||||
<div class="absolute-bottom" v-if="photo.name !== ''">
|
||||
{{ photo.name }}
|
||||
</div>
|
||||
</q-img>
|
||||
<PhotoCaption :photo="photo"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -3,33 +3,29 @@ import {computed, onMounted, reactive, ref, watch} from "vue";
|
||||
import {useQuasar} from "quasar";
|
||||
import {confirmObject} from "src/composables/dialog";
|
||||
|
||||
const $q = useQuasar();
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
photos: {
|
||||
type: Array
|
||||
},
|
||||
showActions: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
const batchEdit = ref({});
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
for (const photo of props.photos) {
|
||||
batchEdit.value[photo.id] = false;
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["edit", "delete", "batch-edit", "batch-rotate", "photo-click"])
|
||||
const emits = defineEmits(["edit", "delete", "batch-edit", "batch-rotate"])
|
||||
|
||||
const openEdit = (photo) => {
|
||||
emits("edit", photo);
|
||||
};
|
||||
|
||||
const $q = useQuasar();
|
||||
|
||||
const confirmPhotoDelete = (id) => {
|
||||
$q.dialog(confirmObject("Opravdu chces smazat tuto fotku?"))
|
||||
@@ -50,11 +46,7 @@ const confirmBatchPhotoDelete = () => {
|
||||
}
|
||||
|
||||
const handleImageClick = (photo, idx) => {
|
||||
if (props.showActions) {
|
||||
batchEdit.value[photo.id] = !batchEdit.value[photo.id];
|
||||
} else {
|
||||
emits("photo-click", {photo, idx});
|
||||
}
|
||||
batchEdit.value[photo.id] = !batchEdit.value[photo.id];
|
||||
}
|
||||
|
||||
const selectedPhotos = computed(() => {
|
||||
@@ -133,13 +125,10 @@ const batchOptionsProps = computed(() => ({
|
||||
</div>
|
||||
</q-img>
|
||||
|
||||
<q-card-actions v-if="showActions" align="right" :class="{'bg-primary': batchEdit[photo.id], 'text-white': batchEdit[photo.id]}">
|
||||
<q-card-actions align="right" :class="{'bg-primary': batchEdit[photo.id], 'text-white': batchEdit[photo.id]}">
|
||||
<div class="col-grow">
|
||||
<q-checkbox v-model="batchEdit[photo.id]"/>
|
||||
<q-icon name="star" v-if="photo.isFlightCover" color="red"/>
|
||||
<q-icon name="place" v-if="photo.pointOfInterestId"/>
|
||||
<q-icon name="gps_fixed" v-if="photo.gpsLatitude && photo.gpsLongitude"/>
|
||||
<q-icon name="gps_off" v-else/>
|
||||
</div>
|
||||
<q-btn flat icon="edit" color="black" :to="{name: 'photoEditor', params: {id: photo.id}}"/>
|
||||
<q-btn flat icon="info" color="blue" @click="openEdit(photo)"/>
|
||||
@@ -149,7 +138,7 @@ const batchOptionsProps = computed(() => ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-page-sticky :offset="[50, 50]" position="bottom" v-if="showActions && photos.length > 0">
|
||||
<q-page-sticky :offset="[50, 50]" position="bottom" v-if="photos.length > 0">
|
||||
<q-card>
|
||||
<q-card-actions>
|
||||
<q-checkbox v-model="checkAll" label="Vybrat vše"/>
|
||||
Reference in New Issue
Block a user