Nahledy v detailu fotky

This commit is contained in:
Michal Kváček
2023-08-31 12:03:54 +02:00
parent ab1e20e6eb
commit 33cfca0815
4 changed files with 83 additions and 44 deletions
+6
View File
@@ -10,6 +10,10 @@ const props = defineProps({
coverPhotoUrl: { coverPhotoUrl: {
type: String, type: String,
required: false required: false
},
defaultTitle: {
type: String,
required: false
} }
}) })
@@ -36,6 +40,7 @@ watch(() => props.photos, (newVal) => {
swipeable swipeable
height="auto" height="auto"
infinite infinite
v-bind="$attrs"
> >
<q-carousel-slide style="padding: 0" v-for="(photo, idx) in photos" :key="photo.url" :name="photo.url"> <q-carousel-slide style="padding: 0" v-for="(photo, idx) in photos" :key="photo.url" :name="photo.url">
<q-img :src="photo.url" @click="openDetail({photo, idx, allPhotos: photos})"/> <q-img :src="photo.url" @click="openDetail({photo, idx, allPhotos: photos})"/>
@@ -45,6 +50,7 @@ watch(() => props.photos, (newVal) => {
<PhotoDetail <PhotoDetail
v-if="photoData" v-if="photoData"
v-model="openPhotoDetail" v-model="openPhotoDetail"
:default-title="defaultTitle"
:photo="photoData.photo" :photo="photoData.photo"
:photos="photoData.allPhotos" :photos="photoData.allPhotos"
:opened-index="photoData.idx" :opened-index="photoData.idx"
+70 -38
View File
@@ -1,6 +1,6 @@
<script setup> <script setup>
import EmbeddedMap from "components/map/EmbeddedMap.vue"; import EmbeddedMap from "components/map/EmbeddedMap.vue";
import {computed, onMounted, ref} from "vue"; import {computed, onMounted, ref, watch} from "vue";
import {formatDatetime} from "src/composables/datetimeUtils"; import {formatDatetime} from "src/composables/datetimeUtils";
import 'vue-inner-image-zoom/lib/vue-inner-image-zoom.css' import 'vue-inner-image-zoom/lib/vue-inner-image-zoom.css'
import {useQuasar} from "quasar"; import {useQuasar} from "quasar";
@@ -19,6 +19,10 @@ const props = defineProps({
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false
},
defaultTitle: {
type: String,
required: false
} }
}); });
@@ -53,10 +57,24 @@ const prevPhoto = () => {
if (photoIndex.value > 0) photoIndex.value--; if (photoIndex.value > 0) photoIndex.value--;
} }
const showDetail = (idx) => {
photoIndex.value = idx;
}
const thumbnailsRef = ref(null);
watch(photoIndex, (newVal) => {
if (!thumbnailsRef.value) return;
const thumbnailWidth = 200;
const thumbnailBarWidth = thumbnailsRef.value.$el.clientWidth;
const thumbnailPosition = newVal * thumbnailWidth;
const scrollTo = Math.max(0, thumbnailPosition - thumbnailBarWidth/2);
thumbnailsRef.value.setScrollPosition("horizontal", scrollTo, 500)
});
const showExtra = ref(false); const showExtra = ref(false);
const $q = useQuasar(); const $q = useQuasar();
const isMaximized = computed(() => $q.screen.width <= $q.screen.sizes.md); const isMaximized = computed(() => $q.screen.width <= $q.screen.sizes.sm);
const imageFullscreen = ref(false); const imageFullscreen = ref(false);
</script> </script>
@@ -75,7 +93,7 @@ const imageFullscreen = ref(false);
<q-card-section class="bg-black text-white" v-if="isMaximized"> <q-card-section class="bg-black text-white" v-if="isMaximized">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<strong v-if="photo.name !== ''">{{ photo.name }}</strong> <strong>{{ photo.name || defaultTitle }}</strong>
</div> </div>
<div class="col text-right"> <div class="col text-right">
<q-btn round text-color="white" size="sm" icon="close" @click="open = false"/> <q-btn round text-color="white" size="sm" icon="close" @click="open = false"/>
@@ -88,8 +106,8 @@ const imageFullscreen = ref(false);
<div :class="{'relative-position': true, 'image-full-height': imageFullscreen}"> <div :class="{'relative-position': true, 'image-full-height': imageFullscreen}">
<div class="text-center"> <div class="text-center">
<inner-image-zoom <inner-image-zoom
move-type="drag" :move-type="isMaximized ? 'drag' : 'pan'"
:zoomScale="0.5" :zoomScale="0.75"
:hide-hint="true" :hide-hint="true"
:after-zoom-in="() => imageFullscreen = true" :after-zoom-in="() => imageFullscreen = true"
:after-zoom-out="() => imageFullscreen = false" :after-zoom-out="() => imageFullscreen = false"
@@ -97,41 +115,52 @@ const imageFullscreen = ref(false);
/> />
</div> </div>
<q-btn <template v-if="!imageFullscreen">
class="absolute all-pointer-events" <q-btn
round class="absolute all-pointer-events"
flat round
icon="info" flat
:text-color="showExtra ? 'primary' : 'white'" icon="info"
style="background: rgba(0, 0, 0, 0.25); bottom: 16px; left: 8px" :text-color="showExtra ? 'primary' : 'white'"
@click="showExtra = !showExtra" style="background: rgba(0, 0, 0, 0.25); bottom: 16px; left: 8px"
/> @click="showExtra = !showExtra"
<q-btn />
class="absolute all-pointer-events" <q-btn
style="background: rgba(0, 0, 0, 0.25); top: 50%; left: 8px;" class="absolute all-pointer-events"
@click="prevPhoto" style="background: rgba(0, 0, 0, 0.25); top: 50%; left: 8px;"
v-if="photoIndex > 0 && !isMaximized" @click="prevPhoto"
icon="chevron_left" v-if="photoIndex > 0 && !isMaximized"
text-color="white" icon="chevron_left"
flat text-color="white"
rounded flat
> rounded
</q-btn> />
<q-btn <q-btn
class="absolute all-pointer-events" class="absolute all-pointer-events"
style="background: rgba(0, 0, 0, 0.25); top: 50%; right: 8px;" style="background: rgba(0, 0, 0, 0.25); top: 50%; right: 8px;"
@click="nextPhoto" @click="nextPhoto"
v-if="photoIndex < photos.length - 1 && !isMaximized" v-if="photoIndex < photos.length - 1 && !isMaximized"
icon-right="chevron_right" icon-right="chevron_right"
text-color="white" text-color="white"
flat flat
rounded rounded
> />
</q-btn> </template>
<strong v-if="photo.name !== '' && !isMaximized">{{ photo.name }}</strong>
<p v-if="photo.description !== ''">{{ photo.description }}</p>
</div> </div>
<q-scroll-area ref="thumbnailsRef" style="height: 170px; width: 100%;" v-show="!imageFullscreen">
<div class="row no-wrap flex-center">
<q-img
v-for="(thumb, idx) in photos"
:key="thumb.thumbnailUrl"
:src="thumb.thumbnailUrl"
@click="showDetail(idx)"
:style="`width: 150px; ${idx === photoIndex ? 'outline: solid 2px' : ''}`"
class="q-ma-sm shadow-5"
/>
</div>
</q-scroll-area>
<div class="row"> <div class="row">
<div class="col-12 q-my-md" v-if="showExtra"> <div class="col-12 q-my-md" v-if="showExtra">
<EmbeddedMap <EmbeddedMap
@@ -141,6 +170,9 @@ const imageFullscreen = ref(false);
:gps-longitude="photo.gpsLongitude" :gps-longitude="photo.gpsLongitude"
/> />
<strong v-if="photo.name !== '' && !isMaximized">{{ photo.name }}</strong>
<p v-if="photo.description !== ''">{{ photo.description }}</p>
<q-list dense> <q-list dense>
<q-item v-if="photo.pointOfInterest"> <q-item v-if="photo.pointOfInterest">
<q-item-section avatar> <q-item-section avatar>
+6 -6
View File
@@ -46,11 +46,11 @@ useMeta(() => ({
title: pageTitle.value !== '' ? `${pageTitle.value} - Polétání.cz` : 'Polétání.cz' title: pageTitle.value !== '' ? `${pageTitle.value} - Polétání.cz` : 'Polétání.cz'
})); }));
onMounted(() => { // onMounted(() => {
if (loggedUser || useUserStore().hasAccessToken()) { // if (loggedUser || useUserStore().hasAccessToken()) {
// poll once per 5 minutes to keep access token active // // poll once per 5 minutes to keep access token active
setInterval(useUserStore().fetchLoggedUserDetail, 5*60*1000); // setInterval(useUserStore().fetchLoggedUserDetail, 5*60*1000);
} // }
}) // })
</script> </script>
+1
View File
@@ -40,6 +40,7 @@ watch(flight, (newVal) => {
<q-card class="q-mx-md q-my-md flight-detail-card"> <q-card class="q-mx-md q-my-md flight-detail-card">
<PhotoCarousel <PhotoCarousel
:default-title="flightName(flight)"
:cover-photo-url="flight.coverPhoto?.url" :cover-photo-url="flight.coverPhoto?.url"
:photos="flight.photos" :photos="flight.photos"
/> />