forked from Sync/hugo-theme-stack
feat: upgrade to PhotoSwipe v5
This commit is contained in:
parent
e5f3cb11d5
commit
9d4ab5afcf
@ -1,67 +1,22 @@
|
||||
declare global {
|
||||
interface Window {
|
||||
PhotoSwipe: any;
|
||||
PhotoSwipeUI_Default: any
|
||||
const wrap = (figures: HTMLElement[]) => {
|
||||
const galleryContainer = document.createElement('div');
|
||||
galleryContainer.className = 'gallery';
|
||||
|
||||
const parentNode = figures[0].parentNode,
|
||||
first = figures[0];
|
||||
|
||||
parentNode.insertBefore(galleryContainer, first)
|
||||
|
||||
for (const figure of figures) {
|
||||
galleryContainer.appendChild(figure);
|
||||
}
|
||||
}
|
||||
|
||||
interface PhotoSwipeItem {
|
||||
w: number;
|
||||
h: number;
|
||||
src: string;
|
||||
msrc: string;
|
||||
title?: string;
|
||||
el: HTMLElement;
|
||||
}
|
||||
|
||||
class StackGallery {
|
||||
private galleryUID: number;
|
||||
private items: PhotoSwipeItem[] = [];
|
||||
|
||||
constructor(container: HTMLElement, galleryUID = 1) {
|
||||
if (window.PhotoSwipe == undefined || window.PhotoSwipeUI_Default == undefined) {
|
||||
console.error("PhotoSwipe lib not loaded.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.galleryUID = galleryUID;
|
||||
|
||||
StackGallery.createGallery(container);
|
||||
this.loadItems(container);
|
||||
this.bindClick();
|
||||
}
|
||||
|
||||
private loadItems(container: HTMLElement) {
|
||||
this.items = [];
|
||||
|
||||
const figures = container.querySelectorAll('figure.gallery-image');
|
||||
|
||||
for (const el of figures) {
|
||||
const figcaption = el.querySelector('figcaption'),
|
||||
img = el.querySelector('img');
|
||||
|
||||
let aux: PhotoSwipeItem = {
|
||||
w: parseInt(img.getAttribute('width')),
|
||||
h: parseInt(img.getAttribute('height')),
|
||||
src: img.src,
|
||||
msrc: img.getAttribute('data-thumb') || img.src,
|
||||
el: el
|
||||
}
|
||||
|
||||
if (figcaption) {
|
||||
aux.title = figcaption.innerHTML;
|
||||
}
|
||||
|
||||
this.items.push(aux);
|
||||
}
|
||||
}
|
||||
|
||||
public static createGallery(container: HTMLElement) {
|
||||
export default (container: HTMLElement) => {
|
||||
/// The process of wrapping image with figure tag is done using JavaScript instead of only Hugo markdown render hook
|
||||
/// because it can not detect whether image is being wrapped by a link or not
|
||||
/// and it lead to a invalid HTML construction (<a><figure><img></figure></a>)
|
||||
|
||||
const images = container.querySelectorAll('img.gallery-image');
|
||||
const images = container.querySelectorAll('img.gallery-image') as NodeListOf<HTMLImageElement>;
|
||||
for (const img of Array.from(images)) {
|
||||
/// Images are wrapped with figure tag if the paragraph has only images without texts
|
||||
/// This is done to allow inline images within paragraphs
|
||||
@ -106,16 +61,16 @@ class StackGallery {
|
||||
const a = document.createElement('a');
|
||||
a.href = img.src;
|
||||
a.setAttribute('target', '_blank');
|
||||
a.setAttribute('data-pswp-width', img.width.toString());
|
||||
a.setAttribute('data-pswp-height', img.height.toString());
|
||||
img.parentNode.insertBefore(a, img);
|
||||
a.appendChild(img);
|
||||
}
|
||||
}
|
||||
|
||||
const figuresEl = container.querySelectorAll('figure.gallery-image');
|
||||
|
||||
const figuresEl = container.querySelectorAll('figure.gallery-image') as NodeListOf<HTMLElement>;
|
||||
let currentGallery = [];
|
||||
|
||||
for (const figure of figuresEl) {
|
||||
for (const figure of Array.from(figuresEl)) {
|
||||
if (!currentGallery.length) {
|
||||
/// First iteration
|
||||
currentGallery = [figure];
|
||||
@ -126,61 +81,12 @@ class StackGallery {
|
||||
}
|
||||
else if (currentGallery.length) {
|
||||
/// End gallery
|
||||
StackGallery.wrap(currentGallery);
|
||||
wrap(currentGallery);
|
||||
currentGallery = [figure];
|
||||
}
|
||||
}
|
||||
|
||||
if (currentGallery.length > 0) {
|
||||
StackGallery.wrap(currentGallery);
|
||||
wrap(currentGallery);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap adjacent figure tags with div.gallery
|
||||
* @param figures
|
||||
*/
|
||||
public static wrap(figures: HTMLElement[]) {
|
||||
const galleryContainer = document.createElement('div');
|
||||
galleryContainer.className = 'gallery';
|
||||
|
||||
const parentNode = figures[0].parentNode,
|
||||
first = figures[0];
|
||||
|
||||
parentNode.insertBefore(galleryContainer, first)
|
||||
|
||||
for (const figure of figures) {
|
||||
galleryContainer.appendChild(figure);
|
||||
}
|
||||
}
|
||||
|
||||
public open(index: number) {
|
||||
const pswp = document.querySelector('.pswp') as HTMLDivElement;
|
||||
const ps = new window.PhotoSwipe(pswp, window.PhotoSwipeUI_Default, this.items, {
|
||||
index: index,
|
||||
galleryUID: this.galleryUID,
|
||||
getThumbBoundsFn: (index) => {
|
||||
const thumbnail = this.items[index].el.getElementsByTagName('img')[0],
|
||||
pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
|
||||
rect = thumbnail.getBoundingClientRect();
|
||||
|
||||
return { x: rect.left, y: rect.top + pageYScroll, w: rect.width };
|
||||
}
|
||||
});
|
||||
|
||||
ps.init();
|
||||
}
|
||||
|
||||
private bindClick() {
|
||||
for (const [index, item] of this.items.entries()) {
|
||||
const a = item.el.querySelector('a');
|
||||
|
||||
a.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.open(index);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default StackGallery;
|
||||
};
|
@ -5,7 +5,6 @@
|
||||
* @website: https://jimmycai.com
|
||||
* @link: https://github.com/CaiJimmy/hugo-theme-stack
|
||||
*/
|
||||
import StackGallery from "ts/gallery";
|
||||
import StackCodeBlock from "ts/codeblock";
|
||||
import menu from 'ts/menu';
|
||||
import createElement from 'ts/createElement';
|
||||
@ -22,7 +21,6 @@ let Stack = {
|
||||
|
||||
const articleContent = document.querySelector('.article-content') as HTMLElement;
|
||||
if (articleContent) {
|
||||
new StackGallery(articleContent);
|
||||
setupSmoothAnchors();
|
||||
setupScrollspy();
|
||||
}
|
||||
|
@ -1,68 +1,20 @@
|
||||
<!-- Root element of PhotoSwipe. Must have class pswp. -->
|
||||
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
{{- $opts := dict "minify" hugo.IsProduction "format" "esm" -}}
|
||||
{{- $galleryScript := resources.Get "ts/gallery.ts" | js.Build $opts -}}
|
||||
|
||||
<!-- Background of PhotoSwipe.
|
||||
It's a separate element as animating opacity is faster than rgba(). -->
|
||||
<div class="pswp__bg"></div>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@5.2.7/dist/photoswipe.css"
|
||||
integrity="sha256-olf9rfn3AG8zR6lkPXkN3PZq63z8tElx7Ela6T4eklo=" crossorigin="anonymous">
|
||||
|
||||
<!-- Slides wrapper with overflow:hidden. -->
|
||||
<div class="pswp__scroll-wrap">
|
||||
<script type="module">
|
||||
import StackGallery from '{{ $galleryScript.RelPermalink }}';
|
||||
import PhotoSwipeLightbox from 'https://cdn.jsdelivr.net/npm/photoswipe@5.2.7/dist/photoswipe-lightbox.esm.min.js';
|
||||
|
||||
<!-- Container that holds slides.
|
||||
PhotoSwipe keeps only 3 of them in the DOM to save memory.
|
||||
Don't modify these 3 pswp__item elements, data is added later on. -->
|
||||
<div class="pswp__container">
|
||||
<div class="pswp__item"></div>
|
||||
<div class="pswp__item"></div>
|
||||
<div class="pswp__item"></div>
|
||||
</div>
|
||||
console.log(StackGallery)
|
||||
StackGallery(document.querySelector('.article-content'));
|
||||
|
||||
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
|
||||
<div class="pswp__ui pswp__ui--hidden">
|
||||
|
||||
<div class="pswp__top-bar">
|
||||
|
||||
<!-- Controls are self-explanatory. Order can be changed. -->
|
||||
|
||||
<div class="pswp__counter"></div>
|
||||
|
||||
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
|
||||
|
||||
<button class="pswp__button pswp__button--share" title="Share"></button>
|
||||
|
||||
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
|
||||
|
||||
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
|
||||
|
||||
<!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
|
||||
<!-- element will get class pswp__preloader--active when preloader is running -->
|
||||
<div class="pswp__preloader">
|
||||
<div class="pswp__preloader__icn">
|
||||
<div class="pswp__preloader__cut">
|
||||
<div class="pswp__preloader__donut"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
|
||||
<div class="pswp__share-tooltip"></div>
|
||||
</div>
|
||||
|
||||
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
|
||||
</button>
|
||||
|
||||
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
|
||||
</button>
|
||||
|
||||
<div class="pswp__caption">
|
||||
<div class="pswp__caption__center"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{- partial "helper/external" (dict "Context" . "Namespace" "PhotoSwipe") -}}
|
||||
const lightbox = new PhotoSwipeLightbox({
|
||||
gallery: '.article-content',
|
||||
children: '.gallery-image a',
|
||||
pswpModule: () => import('https://cdn.jsdelivr.net/npm/photoswipe@5.2.7/dist/photoswipe.esm.min.js')
|
||||
});
|
||||
lightbox.init();
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user