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

View File

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

View File

@@ -1,7 +1,11 @@
import { icon } from '@fortawesome/fontawesome-svg-core'; import { icon } from '@fortawesome/fontawesome-svg-core';
import { getIcon } from '@scripts/icons'; import { getIcon } from '@scripts/icons';
const defaults = { export default class Lightbox {
constructor(options = {}) {
this.album = [];
this.currentImageIndex = 0;
this.options = {
albumLabel: 'Image %1 of %2', albumLabel: 'Image %1 of %2',
alwaysShowNavOnTouchDevices: false, alwaysShowNavOnTouchDevices: false,
fadeDuration: 600, fadeDuration: 600,
@@ -16,14 +20,7 @@ const defaults = {
onMediaChange: () => {}, onMediaChange: () => {},
onClosing: () => {} onClosing: () => {}
}; };
this.option(options);
class Lightbox {
constructor() {
this.album = [];
this.currentImageIndex = 0;
this.options = { ...defaults };
this.gMouseDownOffsetX = 0; this.gMouseDownOffsetX = 0;
this.gMouseDownOffsetY = 0; this.gMouseDownOffsetY = 0;
this.resizeTimer = null; this.resizeTimer = null;
@@ -123,8 +120,8 @@ class Lightbox {
this.video.autoplay = true; this.video.autoplay = true;
this.image.insertAdjacentElement('afterend', this.video); this.image.insertAdjacentElement('afterend', this.video);
this.overlay.style.display = 'none'; this.setVisible(this.overlay, false);
this.lightbox.style.display = 'none'; this.setVisible(this.lightbox, false);
this.containerPadding = this.getBoxMetrics(this.container, 'padding'); this.containerPadding = this.getBoxMetrics(this.container, 'padding');
this.imageBorderWidth = this.getBoxMetrics(this.image, 'border'); this.imageBorderWidth = this.getBoxMetrics(this.image, 'border');
@@ -157,6 +154,7 @@ class Lightbox {
}); });
this.closeButton.addEventListener('click', (event) => { this.closeButton.addEventListener('click', (event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation();
this.end(); this.end();
}); });
this.closeButton.addEventListener('keyup', (event) => { this.closeButton.addEventListener('keyup', (event) => {
@@ -381,19 +379,19 @@ class Lightbox {
} }
updateNav() { updateNav() {
this.nav.style.display = 'block'; this.setVisible(this.nav, true);
this.prev.style.display = 'none'; this.setVisible(this.prev, false);
this.next.style.display = 'none'; this.setVisible(this.next, false);
const alwaysShowNav = ('ontouchstart' in window) && this.options.alwaysShowNavOnTouchDevices; const alwaysShowNav = ('ontouchstart' in window) && this.options.alwaysShowNavOnTouchDevices;
if (this.album.length <= 1) return; if (this.album.length <= 1) return;
if (this.options.wrapAround) { if (this.options.wrapAround) {
this.prev.style.display = ''; this.setVisible(this.prev, true);
this.next.style.display = ''; this.setVisible(this.next, true);
} else { } else {
if (this.currentImageIndex > 0) this.prev.style.display = ''; if (this.currentImageIndex > 0) this.setVisible(this.prev, true);
if (this.currentImageIndex < this.album.length - 1) this.next.style.display = ''; if (this.currentImageIndex < this.album.length - 1) this.setVisible(this.next, true);
} }
if (alwaysShowNav) { if (alwaysShowNav) {
@@ -413,12 +411,12 @@ class Lightbox {
if (this.options.sanitizeTitle) this.caption.textContent = media.title; if (this.options.sanitizeTitle) this.caption.textContent = media.title;
else this.caption.innerHTML = media.title; else this.caption.innerHTML = media.title;
this.fade(this.caption, true, 200); this.fade(this.caption, true, 200);
this.fade(this.closeButton, true, 200);
} else { } else {
this.caption.textContent = ''; 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.outerContainer.classList.remove('animating');
this.fade(this.dataContainer, true, this.options.resizeDuration); this.fade(this.dataContainer, true, this.options.resizeDuration);
} }
@@ -529,24 +527,31 @@ class Lightbox {
hideElements(elements) { hideElements(elements) {
elements.forEach((element) => { 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) { fade(element, show, duration, done) {
if (!element) return; if (!element) return;
const safeDuration = duration || 0; const safeDuration = duration || 0;
element.style.transition = `opacity ${safeDuration}ms`; element.style.transition = `opacity ${safeDuration}ms`;
if (show) { if (show) {
element.style.display = element === this.lightbox ? 'flex' : 'block'; this.setVisible(element, true);
requestAnimationFrame(() => { requestAnimationFrame(() => {
element.style.opacity = element === this.overlay ? '0.8' : '1'; element.style.opacity = element === this.overlay ? '0.8' : '1';
}); });
} else { } else {
element.style.opacity = '0'; element.style.opacity = '0';
element.style.pointerEvents = 'none';
window.setTimeout(() => { window.setTimeout(() => {
element.style.display = 'none'; this.setVisible(element, false);
}, safeDuration); }, safeDuration);
} }
@@ -569,8 +574,3 @@ class Lightbox {
this.options.onClosing(); 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 { .lightboxOverlay {
display: block;
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
@@ -15,7 +16,6 @@ body.lb-disable-scrolling {
z-index: 9999; z-index: 9999;
background-color: black; background-color: black;
opacity: 0.8; opacity: 0.8;
display: none;
outline: none; outline: none;
} }
@@ -30,31 +30,64 @@ body.lb-disable-scrolling {
height: 100%; height: 100%;
overflow: hidden; 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 { &.vertical {
flex-direction: column; flex-direction: column;
.lb-dataContainer { .lb-dataContainer {
width: 100%;
.lb-data { .lb-data {
flex-direction: row; flex-direction: row;
.lb-details { .lb-details {
flex: 1 1 auto; flex: 1 1 auto;
min-width: 0;
width: 100%;
.lb-caption { .lb-caption-line.comment {
.lb-caption-line { flex: 1 1 auto;
padding-right: var.$block-spacing; min-width: 0;
line-height: 1.33333333333em; //icon height
overflow: hidden;
&.comment {
max-width: 50%;
@include common.no-text-overflow(); @include common.no-text-overflow();
} }
} }
}
}
.lb-closeContainer { .lb-closeContainer {
.lb-close { .lb-close {
@@ -73,47 +106,29 @@ body.lb-disable-scrolling {
.lb-data { .lb-data {
flex-direction: column; flex-direction: column;
.lb-caption-line { .lb-caption {
display: block; flex-direction: column;
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-closeContainer .lb-close { .lb-closeContainer .lb-close {
margin-top: calc(1em/1.33333333); margin-top: calc(1em/1.33333333);
float: none;
} }
} }
} }
} }
/* Picture Container */
.lb-outerContainer { .lb-outerContainer {
position: relative; position: relative;
width: 250px; width: 250px;
height: 250px; height: 250px;
margin: 0; margin: 0;
border-radius:0;
background-color: color.$default-bg-trans; background-color: color.$default-bg-trans;
&:after {
content: "";
display: table;
clear: both;
}
.lb-container { .lb-container {
overflow: hidden; overflow: hidden;
height: 100%;
&.moveable { &.moveable {
cursor: grab; cursor: grab;
@@ -124,7 +139,6 @@ body.lb-disable-scrolling {
} }
.lb-image { .lb-image {
display: block;
height: auto; height: auto;
max-width: inherit; max-width: inherit;
max-height: none; max-height: none;
@@ -143,6 +157,9 @@ body.lb-disable-scrolling {
.lb-video { .lb-video {
box-sizing: content-box; box-sizing: content-box;
position: absolute;
top: 0;
left: 0;
} }
&.lb-video-nav .lb-nav { &.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;
}
}
}
}
} }