« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/content/dependencies/image.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/content/dependencies/image.js')
-rw-r--r--src/content/dependencies/image.js119
1 files changed, 71 insertions, 48 deletions
diff --git a/src/content/dependencies/image.js b/src/content/dependencies/image.js
index bf47b14f..af4b7fdd 100644
--- a/src/content/dependencies/image.js
+++ b/src/content/dependencies/image.js
@@ -2,20 +2,6 @@ import {logWarn} from '#cli';
 import {empty} from '#sugar';
 
 export default {
-  extraDependencies: [
-    'checkIfImagePathHasCachedThumbnails',
-    'getDimensionsOfImagePath',
-    'getSizeOfMediaFile',
-    'getThumbnailEqualOrSmaller',
-    'getThumbnailsAvailableForDimensions',
-    'html',
-    'language',
-    'missingImagePaths',
-    'to',
-  ],
-
-  contentDependencies: ['generateColorStyleAttribute'],
-
   relations: (relation, _artwork) => ({
     colorStyle:
       relation('generateColorStyleAttribute'),
@@ -42,6 +28,8 @@ export default {
 
   slots: {
     thumb: {type: 'string'},
+    responsiveThumb: {type: 'boolean', default: false},
+    responsiveSizes: {type: 'string'},
 
     reveal: {type: 'boolean', default: true},
     lazy: {type: 'boolean', default: false},
@@ -60,6 +48,12 @@ export default {
       mutable: false,
     },
 
+    // Added to the <img>.
+    imgAttributes: {
+      type: 'attributes',
+      mutable: false,
+    },
+
     // Added to the <img> itself.
     alt: {type: 'string'},
 
@@ -114,12 +108,11 @@ export default {
     // src string directly when a parts-formed path *is* available seems wrong.
     // It should be possible to do urls.from(slots.path[0]).to(...slots.path),
     // for example, but will require reworking the control flow here a little.
-    let mediaSrc = null;
+    let mediaSrc = decodeURIComponent(originalSrc);
     if (originalSrc.startsWith(to('media.root'))) {
-      mediaSrc =
-        originalSrc
-          .slice(to('media.root').length)
-          .replace(/^\//, '');
+      mediaSrc = mediaSrc
+        .slice(to('media.root').length)
+        .replace(/^\//, '');
     }
 
     const isMissingImageFile =
@@ -141,6 +134,8 @@ export default {
     const imgAttributes = html.attributes([
       {class: 'image'},
 
+      slots.imgAttributes,
+
       slots.alt && {alt: slots.alt},
 
       dimensions &&
@@ -189,47 +184,35 @@ export default {
       mediaSrc &&
       checkIfImagePathHasCachedThumbnails(mediaSrc);
 
-    // Warn for images that *should* have cached thumbnail information but are
-    // missing from the thumbs cache.
-    if (
-      slots.thumb &&
-      !hasThumbnails &&
-      !mediaSrc.endsWith('.gif')
-    ) {
-      logWarn`No thumbnail info cached: ${mediaSrc} - displaying original image here (instead of ${slots.thumb})`;
-    }
-
     let displaySrc = originalSrc;
 
     // This is only distinguished from displaySrc by being a thumbnail,
     // so it won't be set if thumbnails aren't available.
     let revealSrc = null;
 
+    let originalDimensions;
+    let availableThumbs;
+    let selectedThumbtack;
+
+    const getThumbSrc = (thumbtack) =>
+      to('thumb.path', mediaSrc.replace(/\.(png|jpg)$/, `.${thumbtack}.jpg`));
+
     // If thumbnails are available *and* being used, calculate thumbSrc,
     // and provide some attributes relevant to the large image overlay.
     if (hasThumbnails && slots.thumb) {
-      const selectedSize =
+      selectedThumbtack =
         getThumbnailEqualOrSmaller(slots.thumb, mediaSrc);
 
-      const mediaSrcJpeg =
-        mediaSrc.replace(/\.(png|jpg)$/, `.${selectedSize}.jpg`);
-
       displaySrc =
-        to('thumb.path', mediaSrcJpeg);
+        getThumbSrc(selectedThumbtack);
 
       if (willReveal) {
-        const miniSize =
-          getThumbnailEqualOrSmaller('mini', mediaSrc);
-
-        const mediaSrcJpeg =
-          mediaSrc.replace(/\.(png|jpg)$/, `.${miniSize}.jpg`);
-
         revealSrc =
-          to('thumb.path', mediaSrcJpeg);
+          getThumbSrc(getThumbnailEqualOrSmaller('mini', mediaSrc));
       }
 
-      const originalDimensions = getDimensionsOfImagePath(mediaSrc);
-      const availableThumbs = getThumbnailsAvailableForDimensions(originalDimensions);
+      originalDimensions = getDimensionsOfImagePath(mediaSrc);
+      availableThumbs = getThumbnailsAvailableForDimensions(originalDimensions);
 
       const fileSize =
         (willLink && mediaSrc
@@ -245,11 +228,54 @@ export default {
         !empty(availableThumbs) &&
           {'data-thumbs':
               availableThumbs
-                .map(([name, size]) => `${name}:${size}`)
+                .map(([tack, size]) => `${tack}:${size}`)
                 .join(' ')},
       ]);
     }
 
+    let displayStaticImg =
+      html.tag('img',
+        imgAttributes,
+        {src: displaySrc});
+
+    if (hasThumbnails && slots.responsiveThumb) responsive: {
+      if (slots.lazy) {
+        logWarn`${'responsiveThumb'} and ${'lazy'} are used together, but not compatible`;
+        break responsive;
+      }
+
+      if (!slots.thumb) {
+        logWarn`${'responsiveThumb'} must be used alongside a default ${'thumb'}`;
+        break responsive;
+      }
+
+      const srcset = [
+        // Never load the original source, which might be a very large
+        // uncompressed file. Bah!
+        /* [originalSrc, `${Math.min(...originalDimensions)}w`], */
+
+        ...availableThumbs.map(([tack, size]) =>
+          [getThumbSrc(tack), `${Math.floor(0.95 * size)}w`]),
+
+        // fallback
+        [displaySrc],
+      ].map(line => line.join(' ')).join(',\n');
+
+      displayStaticImg =
+        html.tag('img',
+          imgAttributes,
+
+          {sizes:
+            (slots.responsiveSizes.match(/(?=(?:,|^))\s*\S/)
+                // slot provided fallback size
+              ? slots.responsiveSizes
+                // default fallback size
+              : slots.responsiveSizes + ',\n' +
+                new Map(availableThumbs).get(selectedThumbtack) + 'px')},
+
+          {srcset});
+    }
+
     if (!displaySrc) {
       return (
         prepare(
@@ -258,10 +284,7 @@ export default {
     }
 
     const images = {
-      displayStatic:
-        html.tag('img',
-          imgAttributes,
-          {src: displaySrc}),
+      displayStatic: displayStaticImg,
 
       displayLazy:
         slots.lazy &&