« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/content/dependencies/generateAlbumSidebar.js98
-rw-r--r--src/content/dependencies/generateAlbumSidebarGroupBox.js72
-rw-r--r--src/content/dependencies/generateAlbumSidebarTrackListBox.js31
-rw-r--r--src/content/dependencies/generatePageLayout.js26
-rw-r--r--src/content/dependencies/generatePageSidebar.js68
-rw-r--r--src/content/dependencies/generatePageSidebarBox.js20
-rw-r--r--src/content/dependencies/generatePageSidebarConjoinedBox.js42
7 files changed, 205 insertions, 152 deletions
diff --git a/src/content/dependencies/generateAlbumSidebar.js b/src/content/dependencies/generateAlbumSidebar.js
index 266a2662..f014139c 100644
--- a/src/content/dependencies/generateAlbumSidebar.js
+++ b/src/content/dependencies/generateAlbumSidebar.js
@@ -1,74 +1,46 @@
 export default {
   contentDependencies: [
     'generateAlbumSidebarGroupBox',
-    'generateAlbumSidebarTrackSection',
+    'generateAlbumSidebarTrackListBox',
     'generatePageSidebar',
-    'linkAlbum',
+    'generatePageSidebarConjoinedBox',
   ],
 
-  extraDependencies: ['html'],
+  relations: (relation, album, track) => ({
+    sidebar:
+      relation('generatePageSidebar'),
 
-  relations(relation, album, track) {
-    const relations = {};
+    conjoinedBox:
+      relation('generatePageSidebarConjoinedBox'),
 
-    relations.sidebar =
-      relation('generatePageSidebar');
+    trackListBox:
+      relation('generateAlbumSidebarTrackListBox', album, track),
 
-    relations.albumLink =
-      relation('linkAlbum', album);
-
-    relations.groupBoxes =
+    groupBoxes:
       album.groups.map(group =>
-        relation('generateAlbumSidebarGroupBox', album, group));
-
-    relations.trackSections =
-      album.trackSections.map(trackSection =>
-        relation('generateAlbumSidebarTrackSection', album, track, trackSection));
-
-    return relations;
-  },
-
-  data(album, track) {
-    return {isAlbumPage: !track};
-  },
-
-  generate(data, relations, {html}) {
-    const multipleContents = [];
-    const multipleAttributes = [];
-
-    multipleAttributes.push({class: 'track-list-sidebar-box'});
-    multipleContents.push(
-      html.tags([
-        html.tag('h1', relations.albumLink),
-        relations.trackSections,
-      ]));
-
-    if (data.isAlbumPage) {
-      multipleAttributes.push(...
-        relations.groupBoxes
-          .map(() => ({class: 'individual-group-sidebar-box'})));
-
-      multipleContents.push(...
-        relations.groupBoxes
-          .map(content => content.slot('mode', 'album')));
-    } else {
-      multipleAttributes.push({class: 'conjoined-group-sidebar-box'});
-      multipleContents.push(
-        relations.groupBoxes
-          .flatMap((content, i, {length}) => [
-            content.slot('mode', 'track'),
-            i < length - 1 &&
-              html.tag('hr', {
-                style: `border-color: var(--primary-color); border-style: none none dotted none`
-              }),
-          ])
-          .filter(Boolean));
-    }
-
-    return relations.sidebar.slots({
-      // stickyMode: 'column',
-      multipleContents,
-      multipleAttributes,
-    });
-  },
+        relation('generateAlbumSidebarGroupBox', album, group)),
+  }),
+
+  data: (album, track) => ({
+    isAlbumPage: !track,
+  }),
+
+  generate: (data, relations) =>
+    relations.sidebar.slots({
+      boxes: [
+        relations.trackListBox,
+
+        (data.isAlbumPage
+          ? relations.groupBoxes
+              .map(box => box.slot('mode', 'album'))
+
+          : relations.conjoinedBox.slots({
+              attributes: {class: 'conjoined-group-sidebar-box'},
+              boxes:
+                relations.groupBoxes
+                  .map(box => box.slot('mode', 'track'))
+                  .map(box => box.content), /* TODO: Kludge. */
+            })),
+      ],
+    }),
 };
diff --git a/src/content/dependencies/generateAlbumSidebarGroupBox.js b/src/content/dependencies/generateAlbumSidebarGroupBox.js
index 93ebf5d4..00a96c31 100644
--- a/src/content/dependencies/generateAlbumSidebarGroupBox.js
+++ b/src/content/dependencies/generateAlbumSidebarGroupBox.js
@@ -3,6 +3,7 @@ import {atOffset, empty} from '#sugar';
 
 export default {
   contentDependencies: [
+    'generatePageSidebarBox',
     'linkAlbum',
     'linkExternal',
     'linkGroup',
@@ -40,6 +41,9 @@ export default {
   relations(relation, query, album, group) {
     const relations = {};
 
+    relations.box =
+      relation('generatePageSidebarBox');
+
     relations.groupLink =
       relation('linkGroup', group);
 
@@ -72,39 +76,41 @@ export default {
     },
   },
 
-  generate(relations, slots, {html, language}) {
-    return html.tags([
-      html.tag('h1',
-        language.$('albumSidebar.groupBox.title', {
-          group: relations.groupLink,
-        })),
-
-      slots.mode === 'album' &&
-        relations.description
-          ?.slot('mode', 'multiline'),
-
-      !empty(relations.externalLinks) &&
-        html.tag('p',
-          language.$('releaseInfo.visitOn', {
-            links:
-              language.formatDisjunctionList(
-                relations.externalLinks
-                  .map(link => link.slot('context', 'group'))),
-          })),
-
-      slots.mode === 'album' &&
-      relations.nextAlbumLink &&
-        html.tag('p', {class: 'group-chronology-link'},
-          language.$('albumSidebar.groupBox.next', {
-            album: relations.nextAlbumLink,
+  generate: (relations, slots, {html, language}) =>
+    relations.box.slots({
+      attributes: {class: 'individual-group-sidebar-box'},
+      content: [
+        html.tag('h1',
+          language.$('albumSidebar.groupBox.title', {
+            group: relations.groupLink,
           })),
 
-      slots.mode === 'album' &&
-      relations.previousAlbumLink &&
-        html.tag('p', {class: 'group-chronology-link'},
-          language.$('albumSidebar.groupBox.previous', {
-            album: relations.previousAlbumLink,
-          })),
-    ]);
-  },
+        slots.mode === 'album' &&
+          relations.description
+            ?.slot('mode', 'multiline'),
+
+        !empty(relations.externalLinks) &&
+          html.tag('p',
+            language.$('releaseInfo.visitOn', {
+              links:
+                language.formatDisjunctionList(
+                  relations.externalLinks
+                    .map(link => link.slot('context', 'group'))),
+            })),
+
+        slots.mode === 'album' &&
+        relations.nextAlbumLink &&
+          html.tag('p', {class: 'group-chronology-link'},
+            language.$('albumSidebar.groupBox.next', {
+              album: relations.nextAlbumLink,
+            })),
+
+        slots.mode === 'album' &&
+        relations.previousAlbumLink &&
+          html.tag('p', {class: 'group-chronology-link'},
+            language.$('albumSidebar.groupBox.previous', {
+              album: relations.previousAlbumLink,
+            })),
+      ],
+    }),
 };
diff --git a/src/content/dependencies/generateAlbumSidebarTrackListBox.js b/src/content/dependencies/generateAlbumSidebarTrackListBox.js
new file mode 100644
index 00000000..3a244e3a
--- /dev/null
+++ b/src/content/dependencies/generateAlbumSidebarTrackListBox.js
@@ -0,0 +1,31 @@
+export default {
+  contentDependencies: [
+    'generateAlbumSidebarTrackSection',
+    'generatePageSidebarBox',
+    'linkAlbum',
+  ],
+
+  extraDependencies: ['html'],
+
+  relations: (relation, album, track) => ({
+    box:
+      relation('generatePageSidebarBox'),
+
+    albumLink:
+      relation('linkAlbum', album),
+
+    trackSections:
+      album.trackSections.map(trackSection =>
+        relation('generateAlbumSidebarTrackSection', album, track, trackSection)),
+  }),
+
+  generate: (relations, {html}) =>
+    relations.box.slots({
+      attributes: {class: 'track-list-sidebar-box'},
+
+      content: [
+        html.tag('h1', relations.albumLink),
+        relations.trackSections,
+      ],
+    })
+};
diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js
index 7fc6764c..318c8940 100644
--- a/src/content/dependencies/generatePageLayout.js
+++ b/src/content/dependencies/generatePageLayout.js
@@ -35,6 +35,7 @@ export default {
     'generateColorStyleRules',
     'generateFooterLocalizationLinks',
     'generatePageSidebar',
+    'generatePageSidebarBox',
     'generateStickyHeadingContainer',
     'transformContent',
   ],
@@ -73,11 +74,11 @@ export default {
     relations.stickyHeadingContainer =
       relation('generateStickyHeadingContainer');
 
-    relations.leftSidebar =
+    relations.sidebar =
       relation('generatePageSidebar');
 
-    relations.rightSidebar =
-      relation('generatePageSidebar');
+    relations.sidebarBox =
+      relation('generatePageSidebarBox');
 
     if (sprawl.footerContent) {
       relations.defaultFooterContent =
@@ -409,7 +410,7 @@ export default {
         ]);
 
     const applyLegacySidebarSlots = (side, id) =>
-      relations[side].slots({
+      relations.sidebar.clone().slots({
         content: slots[side + 'Content'],
 
         attributes: [
@@ -418,16 +419,15 @@ export default {
             {class: slots[side + 'Class']},
         ],
 
-        multipleContents:
-          (slots[side + 'Multiple']
-            ? slots[side + 'Multiple']
-                .map(({content}) => content)
-            : null),
-
-        multipleAttributes:
+        boxes:
           (slots[side + 'Multiple']
-            ? slots[side + 'Multiple']
-                .map(({class: className}) => [{class: className}])
+            ? slots[side + 'Multiple'].map(box =>
+                relations.sidebarBox
+                  .clone()
+                  .slots({
+                    content: box.content,
+                    attributes: {class: box.class},
+                  }))
             : null),
 
         stickyMode: slots[side + 'StickyMode'],
diff --git a/src/content/dependencies/generatePageSidebar.js b/src/content/dependencies/generatePageSidebar.js
index 10576270..a7da3d1d 100644
--- a/src/content/dependencies/generatePageSidebar.js
+++ b/src/content/dependencies/generatePageSidebar.js
@@ -1,10 +1,14 @@
-import {empty, filterMultipleArrays, stitchArrays} from '#sugar';
-
 export default {
+  contentDependencies: ['generatePageSidebarBox'],
   extraDependencies: ['html'],
 
+  relations: (relation) => ({
+    box:
+      relation('generatePageSidebarBox'),
+  }),
+
   slots: {
-    // Content is a flat HTML array. It'll generate one sidebar section
+    // Content is a flat HTML array. It'll all be placed into one sidebar box
     // if specified.
     content: {
       type: 'html',
@@ -19,14 +23,10 @@ export default {
       mutable: false,
     },
 
-    // Chunks of content to be split into separate sections or "boxes" in the
-    // sidebar. Each of these can also be associated with HTML attributes.
-    multipleContents: {
-      validate: v => v.strictArrayOf(v.isHTML),
-    },
-
-    multipleAttributes: {
-      validate: v => v.strictArrayOf(v.isAttributes),
+    // Chunks of content to be split into separate boxes in the sidebar.
+    boxes: {
+      type: 'html',
+      mutable: false,
     },
 
     // Sticky mode controls which sidebar sections, if any, follow the
@@ -62,9 +62,12 @@ export default {
     },
   },
 
-  generate(slots, {html}) {
+  generate(relations, slots, {html}) {
     const attributes =
-      html.attributes({class: 'sidebar-column'});
+      html.attributes({class: [
+        'sidebar-column',
+        'sidebar-multiple',
+      ]});
 
     attributes.add(slots.attributes);
 
@@ -84,38 +87,17 @@ export default {
       attributes.add('class', `sticky-${slots.stickyMode}`);
     }
 
-    let content = slots.content;
+    const boxes =
+      (!html.isBlank(slots.boxes)
+        ? slots.boxes
+     : !html.isBlank(slots.content)
+        ? relations.box.slot('content', slots.content)
+        : html.blank());
 
-    if (html.isBlank(content)) {
-      if (!slots.multipleContents) {
-        return html.blank();
-      }
-
-      const multipleContents = slots.multipleContents.slice();
-      const multipleAttributes = slots.multipleAttributes?.slice() ?? [];
-
-      filterMultipleArrays(
-        multipleContents,
-        multipleAttributes,
-        content => !html.isBlank(content));
-
-      if (empty(multipleContents)) {
-        return html.blank();
-      }
-
-      attributes.add('class', 'sidebar-multiple');
-      content =
-        stitchArrays({
-          content: multipleContents,
-          attributes: multipleAttributes,
-        }).map(({content, attributes}) =>
-            html.tag('div', {class: 'sidebar'},
-              attributes,
-              content));
+    if (html.isBlank(boxes)) {
+      return html.blank();
     } else {
-      attributes.add('class', 'sidebar');
+      return html.tag('div', attributes, boxes);
     }
-
-    return html.tag('div', attributes, content);
   },
 };
diff --git a/src/content/dependencies/generatePageSidebarBox.js b/src/content/dependencies/generatePageSidebarBox.js
new file mode 100644
index 00000000..51835452
--- /dev/null
+++ b/src/content/dependencies/generatePageSidebarBox.js
@@ -0,0 +1,20 @@
+export default {
+  extraDependencies: ['html'],
+
+  slots: {
+    content: {
+      type: 'html',
+      mutable: false,
+    },
+
+    attributes: {
+      type: 'attributes',
+      mutable: false,
+    },
+  },
+
+  generate: (slots, {html}) =>
+    html.tag('div', {class: 'sidebar'},
+      slots.attributes,
+      slots.content),
+};
diff --git a/src/content/dependencies/generatePageSidebarConjoinedBox.js b/src/content/dependencies/generatePageSidebarConjoinedBox.js
new file mode 100644
index 00000000..05b1d469
--- /dev/null
+++ b/src/content/dependencies/generatePageSidebarConjoinedBox.js
@@ -0,0 +1,42 @@
+// This component is kind of unfortunately magical. It reads the content of
+// various boxes and joins them together, discarding the boxes' attributes.
+// Since it requires access to the actual box *templates* (rather than those
+// templates' resolved content), take care when slotting into this.
+
+export default {
+  contentDependencies: ['generatePageSidebarBox'],
+  extraDependencies: ['html'],
+
+  relations: (relation) => ({
+    box:
+      relation('generatePageSidebarBox'),
+  }),
+
+  slots: {
+    attributes: {
+      type: 'attributes',
+      mutable: false,
+    },
+
+    boxes: {
+      validate: v => v.looseArrayOf(v.isTemplate),
+    },
+  },
+
+  generate: (relations, slots, {html}) =>
+    relations.box.slots({
+      attributes: slots.attributes,
+      content:
+        slots.boxes.slice()
+          .map(box => box.getSlotValue('content'))
+          .map((content, index, {length}) => [
+            content,
+            index < length - 1 &&
+              html.tag('hr', {
+                style:
+                  `border-color: var(--primary-color); ` +
+                  `border-style: none none dotted none`,
+              }),
+          ]),
+    }),
+};