Flatten lightbox comment into a vue component
Deploy Livetrail / deploy (push) Successful in 18s

This commit is contained in:
2026-09-09 17:27:19 +02:00
parent e2a694ba03
commit dc4480c4e2
5 changed files with 79 additions and 60 deletions
+54 -9
View File
@@ -1,24 +1,26 @@
<script> <script>
import AppIcon from '@components/AppIcon'; import AppIcon from '@components/AppIcon';
import ProjectRelTime from '@components/ProjectRelTime';
import { getStyleProperty } from '@scripts/common'; import { getStyleProperty } from '@scripts/common';
/* lightbox (https://github.com/lokesh/lightbox2) converted to a vue component and improved to support videos */ /* lightbox (https://github.com/lokesh/lightbox2) converted to a vue component and improved to support videos */
export default { export default {
components: { components: {
AppIcon AppIcon,
ProjectRelTime
}, },
props: { props: {
alwaysShowNavOnTouchDevices: {type: Boolean, default: false}, alwaysShowNavOnTouchDevices: {type: Boolean, default: false},
positionFromTop: {type: Number, default: 50}, positionFromTop: {type: Number, default: 50},
wrapAround: {type: Boolean, default: false}, wrapAround: {type: Boolean, default: false},
disableScrolling: {type: Boolean, default: false}, disableScrolling: {type: Boolean, default: false},
sanitizeTitle: {type: Boolean, default: false},
hasVideo: {type: Boolean, default: true}, hasVideo: {type: Boolean, default: true},
maxWidth: {type: Number, default: null}, maxWidth: {type: Number, default: null},
maxHeight: {type: Number, default: null} maxHeight: {type: Number, default: null}
}, },
emits: ['media-change', 'closing'], emits: ['media-change', 'closing'],
inject: ['isMobile'],
data() { data() {
/* /*
fadeDuration/imageFadeDuration/resizeDuration read --trans-quick/--trans-slow fadeDuration/imageFadeDuration/resizeDuration read --trans-quick/--trans-slow
@@ -44,6 +46,33 @@ export default {
resizeDuration resizeDuration
}; };
}, },
computed: {
currentMedia() {
return this.album[this.currentImageIndex] || null;
},
relTimeLines() {
const media = this.currentMedia;
if(!media || this.isMobile()) return [];
const postedOn = {
key: 'posted',
icon: 'upload',
titleWrapperLangId: 'media.posted_on',
localTime: media.postedOnLocalTime,
siteTime: media.postedOnSiteTime,
offset: media.postedOnDayOffset
};
const takenOn = {
key: 'taken',
icon: media.type+'-shot',
titleWrapperLangId: 'media.'+media.type+'_taken_on',
localTime: media.takenOnLocalTime,
siteTime: media.takenOnSiteTime,
offset: media.takenOnDayOffset
};
return (media.context == 'marker') ? [takenOn, postedOn] : [postedOn, takenOn];
}
},
mounted() { mounted() {
this.setVisible(this.$refs.overlay, false); this.setVisible(this.$refs.overlay, false);
this.setVisible(this.$refs.lightboxEl, false); this.setVisible(this.$refs.lightboxEl, false);
@@ -122,12 +151,19 @@ export default {
this.album.push({ this.album.push({
alt: link.getAttribute('data-alt') || '', alt: link.getAttribute('data-alt') || '',
link: link.getAttribute('href'), link: link.getAttribute('href'),
title: link.getAttribute('data-title') || link.getAttribute('title') || '',
orientation: parseInt(link.getAttribute('data-orientation') || '0', 10), orientation: parseInt(link.getAttribute('data-orientation') || '0', 10),
type: link.getAttribute('data-type') || 'image', type: link.getAttribute('data-type') || 'image',
id: link.getAttribute('data-id'), id: link.getAttribute('data-id'),
width: parseInt(img?.getAttribute('width') || '0', 10), width: parseInt(img?.getAttribute('width') || '0', 10),
height: parseInt(img?.getAttribute('height') || '0', 10), height: parseInt(img?.getAttribute('height') || '0', 10),
context: link.getAttribute('data-context') || '',
comment: link.getAttribute('data-comment') || '',
postedOnLocalTime: link.getAttribute('data-posted-on-local-time') || '',
postedOnSiteTime: link.getAttribute('data-posted-on-site-time') || '',
postedOnDayOffset: link.getAttribute('data-posted-on-day-offset') || '',
takenOnLocalTime: link.getAttribute('data-taken-on-local-time') || '',
takenOnSiteTime: link.getAttribute('data-taken-on-site-time') || '',
takenOnDayOffset: link.getAttribute('data-taken-on-day-offset') || '',
set: link.getAttribute('data-lightbox') || '' set: link.getAttribute('data-lightbox') || ''
}); });
}, },
@@ -346,16 +382,16 @@ export default {
this.$refs.next.style.opacity = ''; this.$refs.next.style.opacity = '';
} }
}, },
hasCaption(media) {
return !!(media && (media.comment || media.postedOnSiteTime || media.takenOnSiteTime));
},
updateDetails(media = this.album[this.currentImageIndex], show = true) { updateDetails(media = this.album[this.currentImageIndex], show = true) {
if(!media) return; if(!media) return;
if(media.title) { if(this.hasCaption(media)) {
if(this.sanitizeTitle) this.$refs.caption.textContent = media.title;
else this.$refs.caption.innerHTML = media.title;
if(show) this.fade(this.$refs.caption, true, 200); if(show) this.fade(this.$refs.caption, true, 200);
else this.setVisible(this.$refs.caption, true); else this.setVisible(this.$refs.caption, true);
} else { } else {
this.$refs.caption.textContent = '';
this.setVisible(this.$refs.caption, false); this.setVisible(this.$refs.caption, false);
} }
@@ -567,10 +603,19 @@ export default {
</a> </a>
</div> </div>
</div> </div>
<div class="lb-dataContainer desktop" ref="dataContainer" @click="end()"> <div class="lb-dataContainer" ref="dataContainer" @click="end()">
<div class="lb-data"> <div class="lb-data">
<div class="lb-details"> <div class="lb-details">
<span class="lb-caption" ref="caption"></span> <span class="lb-caption" ref="caption">
<template v-if="hasCaption(currentMedia)">
<span v-if="!!currentMedia?.comment" class="lb-caption-line comment">
<AppIcon icon="post" width="fixed" size="lg" text-classes="comment-text" :text="currentMedia.comment" />
</span>
<span v-for="line in relTimeLines" :key="line.key" class="lb-caption-line">
<ProjectRelTime :icon="line.icon" :titleWrapperLangId="line.titleWrapperLangId" :localTime="line.localTime" :siteTime="line.siteTime" :offset="line.offset" />
</span>
</template>
</span>
</div> </div>
<div class="lb-closeContainer"> <div class="lb-closeContainer">
<a class="lb-close" ref="closeButton" href="#" role="button" @click.prevent.stop="end()" @keyup="onCloseKeyup"> <a class="lb-close" ref="closeButton" href="#" role="button" @click.prevent.stop="end()" @keyup="onCloseKeyup">
+9 -39
View File
@@ -1,12 +1,10 @@
<script> <script>
import appIcon from '@components/AppIcon'; import appIcon from '@components/AppIcon';
import projectRelTime from '@components/ProjectRelTime';
import projectMapLink from '@components/ProjectMapLink'; import projectMapLink from '@components/ProjectMapLink';
export default { export default {
components: { components: {
appIcon, appIcon,
projectRelTime,
projectMapLink projectMapLink
}, },
props: { props: {
@@ -14,19 +12,7 @@ export default {
type: String type: String
}, },
emits: ['opening-lightbox'], emits: ['opening-lightbox'],
data() {
return {
title:''
};
},
inject: ['lang', 'isMobile'], inject: ['lang', 'isMobile'],
mounted() {
this.title =
(this.$refs.comment?this.$refs.comment.outerHTML:'') +
this.$refs[this.type=='marker'?'takenon':'postedon'].outerHTML +
this.$refs[this.type=='marker'?'postedon':'takenon'].outerHTML
;
},
methods: { methods: {
openMedia() { openMedia() {
this.$refs.link.click(); this.$refs.link.click();
@@ -42,12 +28,19 @@ export default {
:data-lightbox="type+'-medias'" :data-lightbox="type+'-medias'"
:data-type="options.subtype" :data-type="options.subtype"
:data-id="options.id_media" :data-id="options.id_media"
:data-title="title"
:data-orientation="options.rotate" :data-orientation="options.rotate"
:data-context="type"
:data-comment="options.comment"
:data-posted-on-local-time="options.posted_on_formatted_time_local"
:data-posted-on-site-time="options.posted_on_formatted_time"
:data-posted-on-day-offset="options.posted_on_day_offset"
:data-taken-on-local-time="options.taken_on_formatted_time_local"
:data-taken-on-site-time="options.taken_on_formatted_time"
:data-taken-on-day-offset="options.taken_on_day_offset"
@click="$emit('opening-lightbox', $event)" @click="$emit('opening-lightbox', $event)"
ref="link" ref="link"
> >
<img <img
:src="options.thumb_path" :src="options.thumb_path"
:width="options.width" :width="options.width"
:height="options.height" :height="options.height"
@@ -65,27 +58,4 @@ export default {
</p> </p>
</div> </div>
</a> </a>
<div style="display:none">
<span v-if="options.comment" ref="comment" class="lb-caption-line comment desktop">
<appIcon icon="post" width="fixed" size="lg" text-classes="comment-text" :text="options.comment" />
</span>
<span ref="postedon" class="lb-caption-line">
<projectRelTime
icon="upload"
titleWrapperLangId="media.posted_on"
:localTime="options.posted_on_formatted_time_local"
:siteTime="options.posted_on_formatted_time"
:offset="options.posted_on_day_offset"
/>
</span>
<span ref="takenon" class="lb-caption-line">
<projectRelTime
:icon="options.subtype+'-shot'"
:titleWrapperLangId="'media.'+options.subtype+'_taken_on'"
:localTime="options.taken_on_formatted_time_local"
:siteTime="options.taken_on_formatted_time"
:offset="options.taken_on_day_offset"
/>
</span>
</div>
</template> </template>
+7 -8
View File
@@ -41,7 +41,8 @@
postMessage: '', postMessage: '',
quote: null, quote: null,
sending: false, sending: false,
focusZoomLevel: 15 focusZoomLevel: 15,
panAnimDuration: 500 //ms
}; };
}, },
inject: ['api', 'lang', 'project', 'feed', 'user', 'map', 'hash', 'consts', 'isMobile', 'getAnchor'], inject: ['api', 'lang', 'project', 'feed', 'user', 'map', 'hash', 'consts', 'isMobile', 'getAnchor'],
@@ -156,15 +157,13 @@
this.anchorIcon = 'link'; this.anchorIcon = 'link';
}, 5000); }, 5000);
}, },
panMapToMarker(iAnimDuration=500) { panMapToMarker(bCloseFeed=false) {
if(typeof iAnimDuration !== 'number') iAnimDuration = 500; //panMapToMarker will provide event on direct call in vue template
this.popupRequested = true; this.popupRequested = true;
if(this.isMobile()) this.feed.toggle(false); if(bCloseFeed===true) this.feed.toggle(false);
this.hash.items = [this.project.project.codename, this.options.type, this.options.id]; this.hash.items = [this.project.project.codename, this.options.type, this.options.id];
return this.map.panToBetweenPanels(this.relatedMarkerLatLng, this.focusZoomLevel, iAnimDuration).then(() => { return this.map.panToBetweenPanels(this.relatedMarkerLatLng, this.focusZoomLevel, this.panAnimDuration).then(() => {
this.openMarkerPopup(); this.openMarkerPopup();
}); });
}, },
@@ -238,7 +237,7 @@
<a v-if="replyVisible" class="reply clickable" @click="reply" :title="replyTitle"> <a v-if="replyVisible" class="reply clickable" @click="reply" :title="replyTitle">
<appIcon :icon="'reply'" /> <appIcon :icon="'reply'" />
</a> </a>
<a v-if="anchorVisible" class="link desktop" @click="copyAnchor" ref="anchor" :href="anchorLink" :title="anchorTitle"> <a v-if="anchorVisible && !isMobile()" class="link" @click="copyAnchor" ref="anchor" :href="anchorLink" :title="anchorTitle">
<appIcon :icon="anchorIcon" /> <appIcon :icon="anchorIcon" />
</a> </a>
</div> </div>
@@ -251,7 +250,7 @@
</div> </div>
<div class="body"> <div class="body">
<div v-if="options.type == 'message'" class="body-box"> <div v-if="options.type == 'message'" class="body-box">
<div class="drill" @click.prevent="panMapToMarker" @pointerenter="onMouseEnter" @pointerleave="onMouseLeave"> <div class="drill" @click.prevent="()=>{panMapToMarker(isMobile());}" @pointerenter="onMouseEnter" @pointerleave="onMouseLeave">
<span v-if="options.weather_icon && options.weather_icon!='unknown'" class="weather clickable" :title="lang.get('weather.'+options.weather_icon)"> <span v-if="options.weather_icon && options.weather_icon!='unknown'" class="weather clickable" :title="lang.get('weather.'+options.weather_icon)">
<appIcon :icon="options.weather_icon" :text="Math.round(options.weather_temp)+'°C'" text-classes="temperature" /> <appIcon :icon="options.weather_icon" :text="Math.round(options.weather_temp)+'°C'" text-classes="temperature" />
</span> </span>
+9
View File
@@ -58,6 +58,15 @@ body.lb-disable-scrolling {
.lb-caption-line.comment { .lb-caption-line.comment {
flex: 1 1 auto; flex: 1 1 auto;
min-width: 0; min-width: 0;
.app-icon-with-text {
display: flex;
min-width: 0;
}
.comment-text {
@include common.no-text-overflow();
}
} }
} }
-4
View File
@@ -10,10 +10,6 @@
--button-width: 51px; --button-width: 51px;
} }
.desktop {
display: none !important;
}
.projects { .projects {
.panel-control-elem { .panel-control-elem {
font-size: 2em; font-size: 2em;