From 7b235ea453b25345dbdaffc98d9c46a14ca5591b Mon Sep 17 00:00:00 2001 From: George Cushen Date: Sun, 14 Feb 2021 22:59:12 +0000 Subject: [PATCH] feat: rewritten Figure shortcode supporting multi-resolutions New shortcode supports - enable re-usable *optimized* image assets from new primary media library location at `assets/images/` - new behavior: load image from page dir falling back to media library at `assets/images/` and then to remote URI. - multi-res support. leading to increased perf. - custom ID for cross-refs - efficient, vanilla (non-jQuery), MIT licensed image zooming - FancyBox now only loaded for Gallery shortcode - themeable SVG support - native lazy loading Experimental, may change. BREAKING CHANGE: Move any figure images (i.e. not the `sharing.*` image) from `static/media/` to `assets/images/` See #2164 --- package.json | 3 +- wowchemy/assets/js/_vendor/medium-zoom.esm.js | 622 ++++++++++++++++++ wowchemy/assets/js/wowchemy.js | 12 +- .../assets/scss/wowchemy/elements/_media.scss | 9 + wowchemy/layouts/partials/site_head.html | 5 +- wowchemy/layouts/partials/site_js.html | 6 +- wowchemy/layouts/shortcodes/figure.html | 88 ++- yarn.lock | 5 + 8 files changed, 696 insertions(+), 54 deletions(-) create mode 100644 wowchemy/assets/js/_vendor/medium-zoom.esm.js diff --git a/package.json b/package.json index 128c5818..137da4f0 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "main": "index.js", "dependencies": { "bootstrap": "^4.4.1", - "instant.page": "^5.1.0" + "instant.page": "^5.1.0", + "medium-zoom": "^1.0.6" }, "devDependencies": { "eslint": "^7.17.0", diff --git a/wowchemy/assets/js/_vendor/medium-zoom.esm.js b/wowchemy/assets/js/_vendor/medium-zoom.esm.js new file mode 100644 index 00000000..fa2b3776 --- /dev/null +++ b/wowchemy/assets/js/_vendor/medium-zoom.esm.js @@ -0,0 +1,622 @@ +/*! medium-zoom 1.0.6 | MIT License | https://github.com/francoischalifour/medium-zoom */ +var _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; +}; + +var isSupported = function isSupported(node) { + return node.tagName === 'IMG'; +}; + +/* eslint-disable-next-line no-prototype-builtins */ +var isNodeList = function isNodeList(selector) { + return NodeList.prototype.isPrototypeOf(selector); +}; + +var isNode = function isNode(selector) { + return selector && selector.nodeType === 1; +}; + +var isSvg = function isSvg(image) { + var source = image.currentSrc || image.src; + return source.substr(-4).toLowerCase() === '.svg'; +}; + +var getImagesFromSelector = function getImagesFromSelector(selector) { + try { + if (Array.isArray(selector)) { + return selector.filter(isSupported); + } + + if (isNodeList(selector)) { + // Do not use spread operator or Array.from() for IE support + return [].slice.call(selector).filter(isSupported); + } + + if (isNode(selector)) { + return [selector].filter(isSupported); + } + + if (typeof selector === 'string') { + // Do not use spread operator or Array.from() for IE support + return [].slice.call(document.querySelectorAll(selector)).filter(isSupported); + } + + return []; + } catch (err) { + throw new TypeError('The provided selector is invalid.\n' + 'Expects a CSS selector, a Node element, a NodeList or an array.\n' + 'See: https://github.com/francoischalifour/medium-zoom'); + } +}; + +var createOverlay = function createOverlay(background) { + var overlay = document.createElement('div'); + overlay.classList.add('medium-zoom-overlay'); + overlay.style.background = background; + + return overlay; +}; + +var cloneTarget = function cloneTarget(template) { + var _template$getBounding = template.getBoundingClientRect(), + top = _template$getBounding.top, + left = _template$getBounding.left, + width = _template$getBounding.width, + height = _template$getBounding.height; + + var clone = template.cloneNode(); + var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; + var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; + + clone.removeAttribute('id'); + clone.style.position = 'absolute'; + clone.style.top = top + scrollTop + 'px'; + clone.style.left = left + scrollLeft + 'px'; + clone.style.width = width + 'px'; + clone.style.height = height + 'px'; + clone.style.transform = ''; + + return clone; +}; + +var createCustomEvent = function createCustomEvent(type, params) { + var eventParams = _extends({ + bubbles: false, + cancelable: false, + detail: undefined + }, params); + + if (typeof window.CustomEvent === 'function') { + return new CustomEvent(type, eventParams); + } + + var customEvent = document.createEvent('CustomEvent'); + customEvent.initCustomEvent(type, eventParams.bubbles, eventParams.cancelable, eventParams.detail); + + return customEvent; +}; + +var mediumZoomEsm = function mediumZoom(selector) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + /** + * Ensure the compatibility with IE11 if no Promise polyfill are used. + */ + var Promise = window.Promise || function Promise(fn) { + function noop() {} + fn(noop, noop); + }; + + var _handleClick = function _handleClick(event) { + var target = event.target; + + + if (target === overlay) { + close(); + return; + } + + if (images.indexOf(target) === -1) { + return; + } + + toggle({ target: target }); + }; + + var _handleScroll = function _handleScroll() { + if (isAnimating || !active.original) { + return; + } + + var currentScroll = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; + + if (Math.abs(scrollTop - currentScroll) > zoomOptions.scrollOffset) { + setTimeout(close, 150); + } + }; + + var _handleKeyUp = function _handleKeyUp(event) { + var key = event.key || event.keyCode; + + // Close if escape key is pressed + if (key === 'Escape' || key === 'Esc' || key === 27) { + close(); + } + }; + + var update = function update() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + var newOptions = options; + + if (options.background) { + overlay.style.background = options.background; + } + + if (options.container && options.container instanceof Object) { + newOptions.container = _extends({}, zoomOptions.container, options.container); + } + + if (options.template) { + var template = isNode(options.template) ? options.template : document.querySelector(options.template); + + newOptions.template = template; + } + + zoomOptions = _extends({}, zoomOptions, newOptions); + + images.forEach(function (image) { + image.dispatchEvent(createCustomEvent('medium-zoom:update', { + detail: { zoom: zoom } + })); + }); + + return zoom; + }; + + var clone = function clone() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + return mediumZoomEsm(_extends({}, zoomOptions, options)); + }; + + var attach = function attach() { + for (var _len = arguments.length, selectors = Array(_len), _key = 0; _key < _len; _key++) { + selectors[_key] = arguments[_key]; + } + + var newImages = selectors.reduce(function (imagesAccumulator, currentSelector) { + return [].concat(imagesAccumulator, getImagesFromSelector(currentSelector)); + }, []); + + newImages.filter(function (newImage) { + return images.indexOf(newImage) === -1; + }).forEach(function (newImage) { + images.push(newImage); + newImage.classList.add('medium-zoom-image'); + }); + + eventListeners.forEach(function (_ref) { + var type = _ref.type, + listener = _ref.listener, + options = _ref.options; + + newImages.forEach(function (image) { + image.addEventListener(type, listener, options); + }); + }); + + return zoom; + }; + + var detach = function detach() { + for (var _len2 = arguments.length, selectors = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + selectors[_key2] = arguments[_key2]; + } + + if (active.zoomed) { + close(); + } + + var imagesToDetach = selectors.length > 0 ? selectors.reduce(function (imagesAccumulator, currentSelector) { + return [].concat(imagesAccumulator, getImagesFromSelector(currentSelector)); + }, []) : images; + + imagesToDetach.forEach(function (image) { + image.classList.remove('medium-zoom-image'); + image.dispatchEvent(createCustomEvent('medium-zoom:detach', { + detail: { zoom: zoom } + })); + }); + + images = images.filter(function (image) { + return imagesToDetach.indexOf(image) === -1; + }); + + return zoom; + }; + + var on = function on(type, listener) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + images.forEach(function (image) { + image.addEventListener('medium-zoom:' + type, listener, options); + }); + + eventListeners.push({ type: 'medium-zoom:' + type, listener: listener, options: options }); + + return zoom; + }; + + var off = function off(type, listener) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + images.forEach(function (image) { + image.removeEventListener('medium-zoom:' + type, listener, options); + }); + + eventListeners = eventListeners.filter(function (eventListener) { + return !(eventListener.type === 'medium-zoom:' + type && eventListener.listener.toString() === listener.toString()); + }); + + return zoom; + }; + + var open = function open() { + var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + target = _ref2.target; + + var _animate = function _animate() { + var container = { + width: document.documentElement.clientWidth, + height: document.documentElement.clientHeight, + left: 0, + top: 0, + right: 0, + bottom: 0 + }; + var viewportWidth = void 0; + var viewportHeight = void 0; + + if (zoomOptions.container) { + if (zoomOptions.container instanceof Object) { + // The container is given as an object with properties like width, height, left, top + container = _extends({}, container, zoomOptions.container); + + // We need to adjust custom options like container.right or container.bottom + viewportWidth = container.width - container.left - container.right - zoomOptions.margin * 2; + viewportHeight = container.height - container.top - container.bottom - zoomOptions.margin * 2; + } else { + // The container is given as an element + var zoomContainer = isNode(zoomOptions.container) ? zoomOptions.container : document.querySelector(zoomOptions.container); + + var _zoomContainer$getBou = zoomContainer.getBoundingClientRect(), + _width = _zoomContainer$getBou.width, + _height = _zoomContainer$getBou.height, + _left = _zoomContainer$getBou.left, + _top = _zoomContainer$getBou.top; + + container = _extends({}, container, { + width: _width, + height: _height, + left: _left, + top: _top + }); + } + } + + viewportWidth = viewportWidth || container.width - zoomOptions.margin * 2; + viewportHeight = viewportHeight || container.height - zoomOptions.margin * 2; + + var zoomTarget = active.zoomedHd || active.original; + var naturalWidth = isSvg(zoomTarget) ? viewportWidth : zoomTarget.naturalWidth || viewportWidth; + var naturalHeight = isSvg(zoomTarget) ? viewportHeight : zoomTarget.naturalHeight || viewportHeight; + + var _zoomTarget$getBoundi = zoomTarget.getBoundingClientRect(), + top = _zoomTarget$getBoundi.top, + left = _zoomTarget$getBoundi.left, + width = _zoomTarget$getBoundi.width, + height = _zoomTarget$getBoundi.height; + + var scaleX = Math.min(naturalWidth, viewportWidth) / width; + var scaleY = Math.min(naturalHeight, viewportHeight) / height; + var scale = Math.min(scaleX, scaleY); + var translateX = (-left + (viewportWidth - width) / 2 + zoomOptions.margin + container.left) / scale; + var translateY = (-top + (viewportHeight - height) / 2 + zoomOptions.margin + container.top) / scale; + var transform = 'scale(' + scale + ') translate3d(' + translateX + 'px, ' + translateY + 'px, 0)'; + + active.zoomed.style.transform = transform; + + if (active.zoomedHd) { + active.zoomedHd.style.transform = transform; + } + }; + + return new Promise(function (resolve) { + if (target && images.indexOf(target) === -1) { + resolve(zoom); + return; + } + + var _handleOpenEnd = function _handleOpenEnd() { + isAnimating = false; + active.zoomed.removeEventListener('transitionend', _handleOpenEnd); + active.original.dispatchEvent(createCustomEvent('medium-zoom:opened', { + detail: { zoom: zoom } + })); + + resolve(zoom); + }; + + if (active.zoomed) { + resolve(zoom); + return; + } + + if (target) { + // The zoom was triggered manually via a click + active.original = target; + } else if (images.length > 0) { +var _images = images; + active.original = _images[0]; + } else { + resolve(zoom); + return; + } + + active.original.dispatchEvent(createCustomEvent('medium-zoom:open', { + detail: { zoom: zoom } + })); + + scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; + isAnimating = true; + active.zoomed = cloneTarget(active.original); + + document.body.appendChild(overlay); + + if (zoomOptions.template) { + var template = isNode(zoomOptions.template) ? zoomOptions.template : document.querySelector(zoomOptions.template); + active.template = document.createElement('div'); + active.template.appendChild(template.content.cloneNode(true)); + + document.body.appendChild(active.template); + } + + document.body.appendChild(active.zoomed); + + window.requestAnimationFrame(function () { + document.body.classList.add('medium-zoom--opened'); + }); + + active.original.classList.add('medium-zoom-image--hidden'); + active.zoomed.classList.add('medium-zoom-image--opened'); + + active.zoomed.addEventListener('click', close); + active.zoomed.addEventListener('transitionend', _handleOpenEnd); + + if (active.original.getAttribute('data-zoom-src')) { + active.zoomedHd = active.zoomed.cloneNode(); + + // Reset the `scrset` property or the HD image won't load. + active.zoomedHd.removeAttribute('srcset'); + active.zoomedHd.removeAttribute('sizes'); + + active.zoomedHd.src = active.zoomed.getAttribute('data-zoom-src'); + + active.zoomedHd.onerror = function () { + clearInterval(getZoomTargetSize); + console.warn('Unable to reach the zoom image target ' + active.zoomedHd.src); + active.zoomedHd = null; + _animate(); + }; + + // We need to access the natural size of the full HD + // target as fast as possible to compute the animation. + var getZoomTargetSize = setInterval(function () { + if ( active.zoomedHd.complete) { + clearInterval(getZoomTargetSize); + active.zoomedHd.classList.add('medium-zoom-image--opened'); + active.zoomedHd.addEventListener('click', close); + document.body.appendChild(active.zoomedHd); + _animate(); + } + }, 10); + } else if (active.original.hasAttribute('srcset')) { + // If an image has a `srcset` attribuet, we don't know the dimensions of the + // zoomed (HD) image (like when `data-zoom-src` is specified). + // Therefore the approach is quite similar. + active.zoomedHd = active.zoomed.cloneNode(); + + // Resetting the sizes attribute tells the browser to load the + // image best fitting the current viewport size, respecting the `srcset`. + active.zoomedHd.removeAttribute('sizes'); + + // In Firefox, the `loading` attribute needs to be set to `eager` (default + // value) for the load event to be fired. + active.zoomedHd.removeAttribute('loading'); + + // Wait for the load event of the hd image. This will fire if the image + // is already cached. + var loadEventListener = active.zoomedHd.addEventListener('load', function () { + active.zoomedHd.removeEventListener('load', loadEventListener); + active.zoomedHd.classList.add('medium-zoom-image--opened'); + active.zoomedHd.addEventListener('click', close); + document.body.appendChild(active.zoomedHd); + _animate(); + }); + } else { + _animate(); + } + }); + }; + + var close = function close() { + return new Promise(function (resolve) { + if (isAnimating || !active.original) { + resolve(zoom); + return; + } + + var _handleCloseEnd = function _handleCloseEnd() { + active.original.classList.remove('medium-zoom-image--hidden'); + document.body.removeChild(active.zoomed); + if (active.zoomedHd) { + document.body.removeChild(active.zoomedHd); + } + document.body.removeChild(overlay); + active.zoomed.classList.remove('medium-zoom-image--opened'); + if (active.template) { + document.body.removeChild(active.template); + } + + isAnimating = false; + active.zoomed.removeEventListener('transitionend', _handleCloseEnd); + + active.original.dispatchEvent(createCustomEvent('medium-zoom:closed', { + detail: { zoom: zoom } + })); + + active.original = null; + active.zoomed = null; + active.zoomedHd = null; + active.template = null; + + resolve(zoom); + }; + + isAnimating = true; + document.body.classList.remove('medium-zoom--opened'); + active.zoomed.style.transform = ''; + + if (active.zoomedHd) { + active.zoomedHd.style.transform = ''; + } + + // Fade out the template so it's not too abrupt + if (active.template) { + active.template.style.transition = 'opacity 150ms'; + active.template.style.opacity = 0; + } + + active.original.dispatchEvent(createCustomEvent('medium-zoom:close', { + detail: { zoom: zoom } + })); + + active.zoomed.addEventListener('transitionend', _handleCloseEnd); + }); + }; + + var toggle = function toggle() { + var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + target = _ref3.target; + + if (active.original) { + return close(); + } + + return open({ target: target }); + }; + + var getOptions = function getOptions() { + return zoomOptions; + }; + + var getImages = function getImages() { + return images; + }; + + var getZoomedImage = function getZoomedImage() { + return active.original; + }; + + var images = []; + var eventListeners = []; + var isAnimating = false; + var scrollTop = 0; + var zoomOptions = options; + var active = { + original: null, + zoomed: null, + zoomedHd: null, + template: null + + // If the selector is omitted, it's replaced by the options + };if (Object.prototype.toString.call(selector) === '[object Object]') { + zoomOptions = selector; + } else if (selector || typeof selector === 'string' // to process empty string as a selector + ) { + attach(selector); + } + + // Apply the default option values + zoomOptions = _extends({ + margin: 0, + background: '#fff', + scrollOffset: 40, + container: null, + template: null + }, zoomOptions); + + var overlay = createOverlay(zoomOptions.background); + + document.addEventListener('click', _handleClick); + document.addEventListener('keyup', _handleKeyUp); + document.addEventListener('scroll', _handleScroll); + window.addEventListener('resize', close); + + var zoom = { + open: open, + close: close, + toggle: toggle, + update: update, + clone: clone, + attach: attach, + detach: detach, + on: on, + off: off, + getOptions: getOptions, + getImages: getImages, + getZoomedImage: getZoomedImage + }; + + return zoom; +}; + +function styleInject(css, ref) { + if ( ref === void 0 ) ref = {}; + var insertAt = ref.insertAt; + + if (!css || typeof document === 'undefined') { return; } + + var head = document.head || document.getElementsByTagName('head')[0]; + var style = document.createElement('style'); + style.type = 'text/css'; + + if (insertAt === 'top') { + if (head.firstChild) { + head.insertBefore(style, head.firstChild); + } else { + head.appendChild(style); + } + } else { + head.appendChild(style); + } + + if (style.styleSheet) { + style.styleSheet.cssText = css; + } else { + style.appendChild(document.createTextNode(css)); + } +} + +var css = ".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}"; +styleInject(css); + +export default mediumZoomEsm; diff --git a/wowchemy/assets/js/wowchemy.js b/wowchemy/assets/js/wowchemy.js index 68c12eea..02b9bf7a 100644 --- a/wowchemy/assets/js/wowchemy.js +++ b/wowchemy/assets/js/wowchemy.js @@ -5,10 +5,9 @@ * Core JS functions and initialization. **************************************************/ +import mediumZoom from './_vendor/medium-zoom.esm'; import {hugoEnvironment, codeHighlighting, searchEnabled} from '@params'; - import {fixMermaid, scrollParentToChild} from './wowchemy-utils'; - import { changeThemeModeClick, initThemeVariation, @@ -470,6 +469,15 @@ $(window).on('load', function () { scrollParentToChild(parent, child); } + // Enable images to be zoomed. + let zoomOptions = {}; + if (document.body.classList.contains('dark')) { + zoomOptions.background = 'rgba(0,0,0,0.9)'; + } else { + zoomOptions.background = 'rgba(255,255,255,0.9)'; + } + mediumZoom('[data-zoomable]', zoomOptions); + // Init Isotope Layout Engine for instances of the Portfolio widget. let isotopeCounter = 0; isotopeInstances.forEach(function (isotopeInstance, index) { diff --git a/wowchemy/assets/scss/wowchemy/elements/_media.scss b/wowchemy/assets/scss/wowchemy/elements/_media.scss index d04fa459..feb7ad61 100644 --- a/wowchemy/assets/scss/wowchemy/elements/_media.scss +++ b/wowchemy/assets/scss/wowchemy/elements/_media.scss @@ -1,3 +1,12 @@ +/************************************************* + * Image zooming. + **************************************************/ + +.medium-zoom-overlay, +.medium-zoom-image--opened { + z-index: 1031; // Nav bar index +1. +} + /************************************************* * Gallery. **************************************************/ diff --git a/wowchemy/layouts/partials/site_head.html b/wowchemy/layouts/partials/site_head.html index 93b7955e..10bd26ef 100644 --- a/wowchemy/layouts/partials/site_head.html +++ b/wowchemy/layouts/partials/site_head.html @@ -85,7 +85,10 @@ {{ printf "" (printf $css.academicons.url $css.academicons.version) $css.academicons.sri | safeHTML }} {{ end }} {{ printf "" (printf $css.fontAwesome.url $css.fontAwesome.version) $css.fontAwesome.sri | safeHTML }} - {{ printf "" (printf $css.fancybox.url $css.fancybox.version) $css.fancybox.sri | safeHTML }} + + {{ if .HasShortcode "gallery" }} + {{ printf "" (printf $css.fancybox.url $css.fancybox.version) $css.fancybox.sri | safeHTML }} + {{ end }} {{/* Default to disabling highlighting, but allow the user to override it in .Params or site.Params. Use $scr to store "highlight_enabled", so that we can read it again in footer.html. */}} diff --git a/wowchemy/layouts/partials/site_js.html b/wowchemy/layouts/partials/site_js.html index 0dd57d35..b0aa7599 100644 --- a/wowchemy/layouts/partials/site_js.html +++ b/wowchemy/layouts/partials/site_js.html @@ -6,6 +6,7 @@ {{ else }} {{ printf "" (printf $js.jQuery.url $js.jQuery.version) $js.jQuery.sri | safeHTML }} + {{ printf "" (printf $js.instantpage.url $js.instantpage.version) $js.instantpage.sri | safeHTML }} {{ $require_isotope := site.Params.require_isotope | default true }} {{ if $require_isotope }} @@ -13,8 +14,9 @@ {{ printf "" (printf $js.isotope.url $js.isotope.version) $js.isotope.sri | safeHTML }} {{ end }} - {{ printf "" (printf $js.fancybox.url $js.fancybox.version) $js.fancybox.sri | safeHTML }} - {{ printf "" (printf $js.instantpage.url $js.instantpage.version) $js.instantpage.sri | safeHTML }} + {{ if .HasShortcode "gallery" }} + {{ printf "" (printf $js.fancybox.url $js.fancybox.version) $js.fancybox.sri | safeHTML }} + {{ end }} {{ if or .Params.diagram site.Params.diagram }} {{ printf "" (printf $js.mermaid.url $js.mermaid.version) $js.mermaid.sri | safeHTML }} diff --git a/wowchemy/layouts/shortcodes/figure.html b/wowchemy/layouts/shortcodes/figure.html index 9fb38e92..831d8cbf 100644 --- a/wowchemy/layouts/shortcodes/figure.html +++ b/wowchemy/layouts/shortcodes/figure.html @@ -1,55 +1,47 @@ -{{/* Enable image to be loaded from local page dir or media library at `static/media/`. */}} +{{/* Figure Shortcode for Wowchemy. */}} +{{/* Load image from page dir falling back to media library at `assets/images/` and then to remote URI. */}} -{{ $media_dir := site.Params.media_dir | default "media" }} -{{ $asset := (.Page.Resources.ByType "image").GetMatch (.Get "src") }} -{{ $is_svg := false }} -{{ if $asset }} - {{ if eq $asset.MediaType.SubType "svg"}} - {{ $is_svg = true }} - {{ end }} -{{ end }} -{{ $image_src := (.Get "src") }} -{{ if and $asset (not $is_svg) }} - {{ $asset2 := $asset.Fit "2000x2000" }} - {{ $image_src = $asset2.RelPermalink }} -{{ else if .Get "library" }} - {{ $image_src = printf "%s/%s" $media_dir $image_src | relURL }} -{{ end }} - -{{/* Disallow user from opening image in the lightbox? */}} -{{ $lightbox := eq (.Get "lightbox" | default "true") "true" }} - -{{/* Get lightbox group for showing multiple images in a lightbox. */}} -{{ $group := .Get "lightbox-group" | default "" }} - -{{/* Get caption. Support legacy `title` option. */}} +{{ $destination := .Get "src" }} {{ $caption := .Get "title" | default (.Get "caption") | default "" }} +{{ $id := .Get "id" | default $caption }} +{{ $alt := .Get "alt" | default ($caption | plainify) }} - +{{- $img := (.Page.Resources.ByType "image").GetMatch $destination -}} +{{- if and (not $img) .Page.File -}} + {{ $path := $destination }} + {{- $img = resources.Get (path.Join "images" $path) -}} +{{- end -}} -{{ if $lightbox }} - -{{ else if .Get "link"}} - -{{ end -}} +
-{{/* Lazy load only when we know image dimensions in order to preserve anchor linking. */}} -{{ if and $asset (not $is_svg) }} - {{ with .Get -{{ else if and (.Get "width") (.Get "height") }} - {{ with .Get -{{ else }} - {{ with .Get -{{ end }} - -{{- if or $lightbox (.Get "link") }}{{ end }} - -{{ if $caption }} - {{/* Localize the figure numbering (if enabled). */}} - {{ $figure := split (i18n "figure" | default "Figure %d:") "%d" }} - - {{ $caption | markdownify | emojify }} - -{{ end }} + {{- if $img -}} + {{ $isSVG := eq $img.MediaType.SubType "svg" }} + {{ if $isSVG }} + {{ $img.Content | safeHTML }} + {{ else }} + {{- $img_lg := $img.Fit "1200x1200" -}} + {{- $img_md := $img_lg.Fit "760x760" -}}{{/* Match `.docs-article-container` max-width */}} + {{- $img_sm := $img_md.Fit "400x400" -}} + {{ $alt }} + {{ end }} + {{- else -}} + {{ $alt }} + {{- end -}} + {{ if $caption }} + {{/* Localize the figure numbering (if enabled). */}} + {{ $figure := split (i18n "figure" | default "Figure %d:") "%d" }} + + {{ $caption | markdownify | emojify }} + + {{ end }}
diff --git a/yarn.lock b/yarn.lock index 5583f4ed..afc1e05c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1269,6 +1269,11 @@ mdast-util-to-string@^2.0.0: resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== +medium-zoom@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/medium-zoom/-/medium-zoom-1.0.6.tgz#9247f21ca9313d8bbe9420aca153a410df08d027" + integrity sha512-UdiUWfvz9fZMg1pzf4dcuqA0W079o0mpqbTnOz5ip4VGYX96QjmbM+OgOU/0uOzAytxC0Ny4z+VcYQnhdifimg== + meow@^8.0.0: version "8.1.2" resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897"