Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/CaiJimmy/hugo-theme-stack.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJimmy Cai <github@jimmycai.com>2022-06-12 15:10:17 +0300
committerGitHub <noreply@github.com>2022-06-12 15:10:17 +0300
commit9d4ab5afcf1c839d4d9d5972311e9344fdf3f319 (patch)
tree183d10246230093977a9d3424000a565c752c03d
parente5f3cb11d59773e45aec0c57fb914e73dae211e0 (diff)
feat: upgrade to PhotoSwipe v5
-rw-r--r--assets/ts/gallery.ts240
-rw-r--r--assets/ts/main.ts2
-rw-r--r--layouts/partials/article/components/photoswipe.html88
3 files changed, 93 insertions, 237 deletions
diff --git a/assets/ts/gallery.ts b/assets/ts/gallery.ts
index 9840f1e..e0124d1 100644
--- a/assets/ts/gallery.ts
+++ b/assets/ts/gallery.ts
@@ -1,186 +1,92 @@
-declare global {
- interface Window {
- PhotoSwipe: any;
- PhotoSwipeUI_Default: any
- }
-}
+const wrap = (figures: HTMLElement[]) => {
+ const galleryContainer = document.createElement('div');
+ galleryContainer.className = 'gallery';
-interface PhotoSwipeItem {
- w: number;
- h: number;
- src: string;
- msrc: string;
- title?: string;
- el: HTMLElement;
-}
+ const parentNode = figures[0].parentNode,
+ first = figures[0];
-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;
- }
+ parentNode.insertBefore(galleryContainer, first)
- this.galleryUID = galleryUID;
-
- StackGallery.createGallery(container);
- this.loadItems(container);
- this.bindClick();
+ for (const figure of figures) {
+ galleryContainer.appendChild(figure);
}
+}
- 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);
+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') 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
+ const paragraph = img.closest('p');
+
+ if (!paragraph || !container.contains(paragraph)) continue;
+
+ if (paragraph.textContent.trim() == '') {
+ /// Once we insert figcaption, this check no longer works
+ /// So we add a class to paragraph to mark it
+ paragraph.classList.add('no-text');
}
- }
-
- public static createGallery(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');
- 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
- const paragraph = img.closest('p');
-
- if (!paragraph || !container.contains(paragraph)) continue;
-
- if (paragraph.textContent.trim() == '') {
- /// Once we insert figcaption, this check no longer works
- /// So we add a class to paragraph to mark it
- paragraph.classList.add('no-text');
- }
-
- let isNewLineImage = paragraph.classList.contains('no-text');
- if (!isNewLineImage) continue;
- const hasLink = img.parentElement.tagName == 'A';
+ let isNewLineImage = paragraph.classList.contains('no-text');
+ if (!isNewLineImage) continue;
- let el: HTMLElement = img;
- /// Wrap image with figure tag, with flex-grow and flex-basis values extracted from img's data attributes
- const figure = document.createElement('figure');
- figure.style.setProperty('flex-grow', img.getAttribute('data-flex-grow') || '1');
- figure.style.setProperty('flex-basis', img.getAttribute('data-flex-basis') || '0');
- if (hasLink) {
- /// Wrap <a> if it exists
- el = img.parentElement;
- }
- el.parentElement.insertBefore(figure, el);
- figure.appendChild(el);
+ const hasLink = img.parentElement.tagName == 'A';
- /// Add figcaption if it exists
- if (img.hasAttribute('alt')) {
- const figcaption = document.createElement('figcaption');
- figcaption.innerText = img.getAttribute('alt');
- figure.appendChild(figcaption);
- }
-
- /// Wrap img tag with <a> tag if image was not wrapped by <a> tag
- if (!hasLink) {
- figure.className = 'gallery-image';
-
- const a = document.createElement('a');
- a.href = img.src;
- a.setAttribute('target', '_blank');
- img.parentNode.insertBefore(a, img);
- a.appendChild(img);
- }
+ let el: HTMLElement = img;
+ /// Wrap image with figure tag, with flex-grow and flex-basis values extracted from img's data attributes
+ const figure = document.createElement('figure');
+ figure.style.setProperty('flex-grow', img.getAttribute('data-flex-grow') || '1');
+ figure.style.setProperty('flex-basis', img.getAttribute('data-flex-basis') || '0');
+ if (hasLink) {
+ /// Wrap <a> if it exists
+ el = img.parentElement;
}
-
- const figuresEl = container.querySelectorAll('figure.gallery-image');
-
- let currentGallery = [];
-
- for (const figure of figuresEl) {
- if (!currentGallery.length) {
- /// First iteration
- currentGallery = [figure];
- }
- else if (figure.previousElementSibling === currentGallery[currentGallery.length - 1]) {
- /// Adjacent figures
- currentGallery.push(figure);
- }
- else if (currentGallery.length) {
- /// End gallery
- StackGallery.wrap(currentGallery);
- currentGallery = [figure];
- }
+ el.parentElement.insertBefore(figure, el);
+ figure.appendChild(el);
+
+ /// Add figcaption if it exists
+ if (img.hasAttribute('alt')) {
+ const figcaption = document.createElement('figcaption');
+ figcaption.innerText = img.getAttribute('alt');
+ figure.appendChild(figcaption);
}
- if (currentGallery.length > 0) {
- StackGallery.wrap(currentGallery);
+ /// Wrap img tag with <a> tag if image was not wrapped by <a> tag
+ if (!hasLink) {
+ figure.className = 'gallery-image';
+
+ 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);
}
}
- /**
- * 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);
+ const figuresEl = container.querySelectorAll('figure.gallery-image') as NodeListOf<HTMLElement>;
+ let currentGallery = [];
+ for (const figure of Array.from(figuresEl)) {
+ if (!currentGallery.length) {
+ /// First iteration
+ currentGallery = [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);
- })
+ else if (figure.previousElementSibling === currentGallery[currentGallery.length - 1]) {
+ /// Adjacent figures
+ currentGallery.push(figure);
+ }
+ else if (currentGallery.length) {
+ /// End gallery
+ wrap(currentGallery);
+ currentGallery = [figure];
}
}
-}
-export default StackGallery; \ No newline at end of file
+ if (currentGallery.length > 0) {
+ wrap(currentGallery);
+ }
+}; \ No newline at end of file
diff --git a/assets/ts/main.ts b/assets/ts/main.ts
index 5370b2c..0668c7c 100644
--- a/assets/ts/main.ts
+++ b/assets/ts/main.ts
@@ -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();
}
diff --git a/layouts/partials/article/components/photoswipe.html b/layouts/partials/article/components/photoswipe.html
index c33ff49..425825c 100644
--- a/layouts/partials/article/components/photoswipe.html
+++ b/layouts/partials/article/components/photoswipe.html
@@ -1,68 +1,20 @@
-<!-- Root element of PhotoSwipe. Must have class pswp. -->
-<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
-
- <!-- Background of PhotoSwipe.
- It's a separate element as animating opacity is faster than rgba(). -->
- <div class="pswp__bg"></div>
-
- <!-- Slides wrapper with overflow:hidden. -->
- <div class="pswp__scroll-wrap">
-
- <!-- 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>
-
- <!-- 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") -}} \ No newline at end of file
+{{- $opts := dict "minify" hugo.IsProduction "format" "esm" -}}
+{{- $galleryScript := resources.Get "ts/gallery.ts" | js.Build $opts -}}
+
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@5.2.7/dist/photoswipe.css"
+ integrity="sha256-olf9rfn3AG8zR6lkPXkN3PZq63z8tElx7Ela6T4eklo=" crossorigin="anonymous">
+
+<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';
+
+ console.log(StackGallery)
+ StackGallery(document.querySelector('.article-content'));
+
+ 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> \ No newline at end of file