« get me outta code hell

properly support 4-18 item carousels - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/misc-templates.js
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2022-12-28 18:25:51 -0400
committer(quasar) nebula <qznebula@protonmail.com>2022-12-28 18:25:51 -0400
commit0fbce8a83c33a17821716d662c86a95848c7e58a (patch)
tree1b8ec19521e8390cf5e6f70893b1d4c37decef93 /src/misc-templates.js
parent4431905279d30f2f987cea1e40805ffdd7d61b5b (diff)
properly support 4-18 item carousels
Diffstat (limited to 'src/misc-templates.js')
-rw-r--r--src/misc-templates.js55
1 files changed, 55 insertions, 0 deletions
diff --git a/src/misc-templates.js b/src/misc-templates.js
index 7887dcb..71c6288 100644
--- a/src/misc-templates.js
+++ b/src/misc-templates.js
@@ -642,6 +642,48 @@ function unbound_getFlashGridHTML({
 
 // Carousel reels
 
+// Layout constants:
+//
+// Carousels support fitting 4-18 items, with a few "dead" zones to watch out
+// for, namely when a multiple of 6, 5, or 4 columns would drop the last tiles.
+//
+// Carousels are limited to 1-3 rows and 4-6 columns.
+// Lower edge case: 1-3 items are treated as 4 items (with blank space).
+// Upper edge case: all items past 18 are dropped (treated as 18 items).
+//
+// This is all done through JS instead of CSS because it's just... ANNOYING...
+// to write a mapping like this in CSS lol.
+const carouselLayoutMap = [
+  // 0-3
+  null, null, null, null,
+
+  // 4-6
+  {rows: 1, columns: 4}, //  4: 1x4, drop 0
+  {rows: 1, columns: 5}, //  5: 1x5, drop 0
+  {rows: 1, columns: 6}, //  6: 1x6, drop 0
+
+  // 7-12
+  {rows: 1, columns: 6}, //  7: 1x6, drop 1
+  {rows: 2, columns: 4}, //  8: 2x4, drop 0
+  {rows: 2, columns: 4}, //  9: 2x4, drop 1
+  {rows: 2, columns: 5}, // 10: 2x5, drop 0
+  {rows: 2, columns: 5}, // 11: 2x5, drop 1
+  {rows: 2, columns: 6}, // 12: 2x6, drop 0
+
+  // 13-18
+  {rows: 2, columns: 6}, // 13: 2x6, drop 1
+  {rows: 2, columns: 6}, // 14: 2x6, drop 2
+  {rows: 3, columns: 5}, // 15: 3x5, drop 0
+  {rows: 3, columns: 5}, // 16: 3x5, drop 1
+  {rows: 3, columns: 5}, // 17: 3x5, drop 2
+  {rows: 3, columns: 6}, // 18: 3x6, drop 0
+];
+
+const minCarouselLayoutItems = carouselLayoutMap.findIndex(x => x !== null);
+const maxCarouselLayoutItems = carouselLayoutMap.length - 1;
+const shortestCarouselLayout = carouselLayoutMap[minCarouselLayoutItems];
+const longestCarouselLayout = carouselLayoutMap[maxCarouselLayoutItems];
+
 function unbound_getCarouselHTML({
   html,
   img,
@@ -653,11 +695,24 @@ function unbound_getCarouselHTML({
   linkFn = (x, {text}) => text,
   srcFn,
 }) {
+  if (empty(items)) {
+    return;
+  }
+
+  const {rows, columns} = (
+    items.length < minCarouselLayoutItems ? shortestCarouselLayout :
+    items.length > maxCarouselLayoutItems ? longestCarouselLayout :
+    carouselLayoutMap[items.length]);
+
+  items = items.slice(0, maxCarouselLayoutItems + 1);
+
   return (x => x)(html.tag('div', {class: 'carousel-container'},
     repeat(3,
       html.tag('div',
         {
           class: 'carousel-grid',
+          'data-carousel-rows': rows,
+          'data-carousel-columns': columns,
           'aria-hidden': 'true',
         },
         items