Simplify lightbox

This commit is contained in:
2026-05-04 00:04:07 +02:00
parent a4e0a345d6
commit b759508779
4 changed files with 118 additions and 128 deletions

View File

@@ -4,7 +4,7 @@ import { Map, NavigationControl, Marker, LngLatBounds, LngLat, Popup } from 'map
import { createApp, ref, provide, inject } from 'vue';
import Simplebar from 'simplebar-vue';
import lightbox from '@scripts/lightbox';
import Lightbox from '@scripts/lightbox';
import { getOuterWidth } from '@scripts/common';
import SpotIcon from '@components/spotIcon';
@@ -44,6 +44,7 @@ export default {
baseMaps: {},
baseMap: null,
map: null,
lightbox: null,
hikes: {
colors:{'main':'#00ff78', 'off-track':'#0000ff', 'hitchhiking':'#FF7814'},
width: 4
@@ -120,9 +121,8 @@ export default {
*/
},
async init() {
let bFirstLoad = (typeof this.currProject.codename == 'undefined');
this.initProject();
if(bFirstLoad) this.initLightbox();
this.initLightbox();
await Promise.all([
this.initFeed(),
@@ -133,7 +133,7 @@ export default {
if(this.hash.items.length == 3) await this.findPost(this.hash.items[1], this.hash.items[2]);
},
quit() {
lightbox.end();
this.lightbox?.end();
this.$refs.feedSimpleBar.scrollElement.removeEventListener('scroll', this.onFeedScroll);
this.setFeedUpdateTimer(-1);
this.map.remove();
@@ -147,7 +147,7 @@ export default {
this.baseMaps = {};
},
initLightbox() {
lightbox.option({
this.lightbox = new Lightbox({
alwaysShowNavOnTouchDevices: true,
albumLabel: 'Media %1 / %2',
fadeDuration: 300,

View File

@@ -23,7 +23,7 @@ export default {
'spot-icon',
this.icon,
...(this.classes || '').split(/\s+/),
this.margin?'margin-'+this.margin:null || this.hasText?'margin-right':null
this.margin?'margin-'+this.margin:null
].filter(Boolean).join(' ');
},
resolvedFixedWidth() {
@@ -49,7 +49,7 @@ export default {
</script>
<template>
<span :title="title" v-if="title || hasText">
<span :title="title" v-if="title || hasText" class="spot-icon-box">
<FontAwesomeIcon :icon="iconDefinition" :class="classNames" :fixed-width="resolvedFixedWidth" :width-auto="resolvedAutoWidth" :size="resolvedSize" :transform="resolvedTransform" />
<span v-if="hasText" :class="textClasses">{{ text }}</span>
</span>
@@ -59,6 +59,16 @@ export default {
<style lang="scss" scoped>
@use "@styles/var";
.spot-icon-box {
display: flex;
gap: var.$elem-spacing;
align-items: center;
span {
flex: 1 1 auto;
}
}
.spot-icon {
&.margin-right {
margin-right: var.$elem-spacing;

View File

@@ -1,29 +1,26 @@
import { icon } from '@fortawesome/fontawesome-svg-core';
import { getIcon } from '@scripts/icons';
const defaults = {
albumLabel: 'Image %1 of %2',
alwaysShowNavOnTouchDevices: false,
fadeDuration: 600,
fitImagesInViewport: true,
imageFadeDuration: 600,
positionFromTop: 50,
resizeDuration: 700,
wrapAround: false,
disableScrolling: false,
sanitizeTitle: false,
hasVideo: true,
onMediaChange: () => {},
onClosing: () => {}
};
class Lightbox {
constructor() {
export default class Lightbox {
constructor(options = {}) {
this.album = [];
this.currentImageIndex = 0;
this.options = { ...defaults };
this.options = {
albumLabel: 'Image %1 of %2',
alwaysShowNavOnTouchDevices: false,
fadeDuration: 600,
fitImagesInViewport: true,
imageFadeDuration: 600,
positionFromTop: 50,
resizeDuration: 700,
wrapAround: false,
disableScrolling: false,
sanitizeTitle: false,
hasVideo: true,
onMediaChange: () => {},
onClosing: () => {}
};
this.option(options);
this.gMouseDownOffsetX = 0;
this.gMouseDownOffsetY = 0;
this.resizeTimer = null;
@@ -123,8 +120,8 @@ class Lightbox {
this.video.autoplay = true;
this.image.insertAdjacentElement('afterend', this.video);
this.overlay.style.display = 'none';
this.lightbox.style.display = 'none';
this.setVisible(this.overlay, false);
this.setVisible(this.lightbox, false);
this.containerPadding = this.getBoxMetrics(this.container, 'padding');
this.imageBorderWidth = this.getBoxMetrics(this.image, 'border');
@@ -157,6 +154,7 @@ class Lightbox {
});
this.closeButton.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
this.end();
});
this.closeButton.addEventListener('keyup', (event) => {
@@ -381,19 +379,19 @@ class Lightbox {
}
updateNav() {
this.nav.style.display = 'block';
this.prev.style.display = 'none';
this.next.style.display = 'none';
this.setVisible(this.nav, true);
this.setVisible(this.prev, false);
this.setVisible(this.next, false);
const alwaysShowNav = ('ontouchstart' in window) && this.options.alwaysShowNavOnTouchDevices;
if (this.album.length <= 1) return;
if (this.options.wrapAround) {
this.prev.style.display = '';
this.next.style.display = '';
this.setVisible(this.prev, true);
this.setVisible(this.next, true);
} else {
if (this.currentImageIndex > 0) this.prev.style.display = '';
if (this.currentImageIndex < this.album.length - 1) this.next.style.display = '';
if (this.currentImageIndex > 0) this.setVisible(this.prev, true);
if (this.currentImageIndex < this.album.length - 1) this.setVisible(this.next, true);
}
if (alwaysShowNav) {
@@ -413,12 +411,12 @@ class Lightbox {
if (this.options.sanitizeTitle) this.caption.textContent = media.title;
else this.caption.innerHTML = media.title;
this.fade(this.caption, true, 200);
this.fade(this.closeButton, true, 200);
} else {
this.caption.textContent = '';
this.caption.style.display = 'none';
this.setVisible(this.caption, false);
}
this.fade(this.closeButton, true, 200);
this.outerContainer.classList.remove('animating');
this.fade(this.dataContainer, true, this.options.resizeDuration);
}
@@ -529,24 +527,31 @@ class Lightbox {
hideElements(elements) {
elements.forEach((element) => {
if (element) element.style.display = 'none';
this.setVisible(element, false);
});
}
setVisible(element, visible) {
if (!element) return;
element.style.visibility = visible ? 'visible' : 'hidden';
element.style.pointerEvents = visible ? '' : 'none';
}
fade(element, show, duration, done) {
if (!element) return;
const safeDuration = duration || 0;
element.style.transition = `opacity ${safeDuration}ms`;
if (show) {
element.style.display = element === this.lightbox ? 'flex' : 'block';
this.setVisible(element, true);
requestAnimationFrame(() => {
element.style.opacity = element === this.overlay ? '0.8' : '1';
});
} else {
element.style.opacity = '0';
element.style.pointerEvents = 'none';
window.setTimeout(() => {
element.style.display = 'none';
this.setVisible(element, false);
}, safeDuration);
}
@@ -569,8 +574,3 @@ class Lightbox {
this.options.onClosing();
}
}
const lightbox = new Lightbox();
export const options = defaults;
export default lightbox;

View File

@@ -7,6 +7,7 @@ body.lb-disable-scrolling {
}
.lightboxOverlay {
display: block;
position: absolute;
top: 0;
left: 0;
@@ -15,7 +16,6 @@ body.lb-disable-scrolling {
z-index: 9999;
background-color: black;
opacity: 0.8;
display: none;
outline: none;
}
@@ -30,29 +30,62 @@ body.lb-disable-scrolling {
height: 100%;
overflow: hidden;
/* Data Container (comments, close) */
.lb-dataContainer {
position: relative;
margin: 0;
padding: 0;
width: 100%;
flex: 0 0 auto;
overflow: hidden;
.lb-data {
display: flex;
margin: var.$elem-spacing;
gap: var.$block-spacing;
color: color.$default-inv;
.lb-caption {
display: flex;
gap: var.$block-spacing;
.lb-caption-line {
flex: 0 0 auto;
line-height: 1.33333333333em; //icon height
white-space: nowrap;
}
}
.lb-closeContainer .lb-close {
@extend .clickable;
font-size: 1.3333333333em;
line-height: 1em;
color: color.$default-inv;
&:hover {
color: color.$default-inv-hover;
}
}
}
}
&.vertical {
flex-direction: column;
.lb-dataContainer {
width: 100%;
.lb-data {
flex-direction: row;
.lb-details {
flex: 1 1 auto;
min-width: 0;
width: 100%;
.lb-caption {
.lb-caption-line {
padding-right: var.$block-spacing;
line-height: 1.33333333333em; //icon height
overflow: hidden;
&.comment {
max-width: 50%;
@include common.no-text-overflow();
}
}
.lb-caption-line.comment {
flex: 1 1 auto;
min-width: 0;
@include common.no-text-overflow();
}
}
@@ -73,47 +106,29 @@ body.lb-disable-scrolling {
.lb-data {
flex-direction: column;
.lb-caption-line {
display: block;
margin-top: var.$block-spacing;
line-height: 1.33333333em;
&.comment {
.spot-icon {
vertical-align: center;
}
.comment-text {
display: inline-block;
width: calc(100% - 1.25em*1.33333333333 - var.$elem-spacing);
vertical-align: top;
}
}
.lb-caption {
flex-direction: column;
}
.lb-closeContainer .lb-close {
margin-top: calc(1em/1.33333333);
float: none;
}
}
}
}
/* Picture Container */
.lb-outerContainer {
position: relative;
width: 250px;
height: 250px;
margin: 0;
border-radius:0;
background-color: color.$default-bg-trans;
&:after {
content: "";
display: table;
clear: both;
}
.lb-container {
overflow: hidden;
height: 100%;
&.moveable {
cursor: grab;
@@ -124,7 +139,6 @@ body.lb-disable-scrolling {
}
.lb-image {
display: block;
height: auto;
max-width: inherit;
max-height: none;
@@ -143,6 +157,9 @@ body.lb-disable-scrolling {
.lb-video {
box-sizing: content-box;
position: absolute;
top: 0;
left: 0;
}
&.lb-video-nav .lb-nav {
@@ -229,41 +246,4 @@ body.lb-disable-scrolling {
}
}
}
.lb-dataContainer {
margin: 0;
padding: 0;
width: 100%;
flex: 0 0 auto;
overflow: hidden;
.lb-data {
text-align: left;
padding: var.$elem-spacing;
display: flex;
color: color.$default-inv;
.lb-details {
float: none;
.lb-caption-line:first-child {
margin-top: 0;
}
}
.lb-closeContainer .lb-close {
@extend .clickable;
height: auto;
font-size: 1.3333333333em;
line-height: 1em;
text-align: center;
width: 1.25em;
color: color.$default-inv;
&:hover {
color: color.$default-inv-hover;
}
}
}
}
}