« get me outta code hell

content: generateAlbumSidebar + misc fixes - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/content/dependencies/generateAlbumSidebar.js
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-04-15 12:22:48 -0300
committer(quasar) nebula <qznebula@protonmail.com>2023-04-15 12:24:22 -0300
commit6b35077eb1542eaf9a89534d6920c35fee86cc04 (patch)
tree3ff4e6bb1860b67b9b2a4f2e39cdcd76cbeaa4b9 /src/content/dependencies/generateAlbumSidebar.js
parent3a5b49cf3a10702c0dae1190c9baabd8a2c2ef3b (diff)
content: generateAlbumSidebar + misc fixes
This restores the CSS for sticky sidebars, but removes the
specific lines applying that effect (for the album sidebar).
There's also an experimental new splitter for the joined
group info box but we might go back on that or do something
different.

No tests for the new stuff here yet!
Diffstat (limited to 'src/content/dependencies/generateAlbumSidebar.js')
-rw-r--r--src/content/dependencies/generateAlbumSidebar.js241
1 files changed, 241 insertions, 0 deletions
diff --git a/src/content/dependencies/generateAlbumSidebar.js b/src/content/dependencies/generateAlbumSidebar.js
new file mode 100644
index 0000000..223b1b7
--- /dev/null
+++ b/src/content/dependencies/generateAlbumSidebar.js
@@ -0,0 +1,241 @@
+import {empty} from '../../util/sugar.js';
+
+function groupRelationships(album) {
+  return album.groups.map(group => {
+    const albums = group.albums.filter(album => album.date);
+    const index = albums.indexOf(album);
+
+    const previousAlbum = (index > 0) && albums[index - 1];
+    const nextAlbum = (index < albums.length - 1) && albums[index + 1];
+
+    return {group, previousAlbum, nextAlbum};
+  });
+}
+
+export default {
+  contentDependencies: [
+    'linkAlbum',
+    'linkExternal',
+    'linkGroup',
+    'linkTrack',
+  ],
+
+  extraDependencies: [
+    'getColors',
+    'html',
+    'language',
+    'transformMultiline',
+  ],
+
+  relations(relation, album, track) {
+    const relations = {};
+
+    relations.albumLink =
+      relation('linkAlbum', album);
+
+    relations.trackLinks =
+      album.trackSections.map(trackSection =>
+        trackSection.tracks.map(track =>
+          relation('linkTrack', track)));
+
+    relations.groupLinks =
+      groupRelationships(album)
+        .map(({group, previousAlbum, nextAlbum}) => ({
+          groupLink:
+            relation('linkGroup', group),
+
+          externalLinks:
+            group.urls.map(url =>
+              relation('linkExternal', url)),
+
+          previousAlbumLink:
+            previousAlbum &&
+              relation('linkAlbum', previousAlbum),
+
+          nextAlbumLink:
+            nextAlbum &&
+              relation('linkAlbum', nextAlbum),
+        }))
+
+    return relations;
+  },
+
+  data(album, track) {
+    const data = {};
+
+    data.isAlbumPage = !track;
+    data.isTrackPage = !!track;
+
+    data.hasTrackNumbers = album.hasTrackNumbers;
+
+    data.trackSectionInfo =
+      album.trackSections.map(trackSection => ({
+        name: trackSection.name,
+        color: trackSection.color,
+        isDefaultTrackSection: trackSection.isDefaultTrackSection,
+
+        firstTrackNumber: trackSection.startIndex + 1,
+        lastTrackNumber: trackSection.startIndex + trackSection.tracks.length,
+
+        includesCurrentTrack: track && trackSection.tracks.includes(track),
+        currentTrackIndex: trackSection.tracks.indexOf(track),
+      }));
+
+    data.groupInfo =
+      album.groups.map(group => ({
+        description: group.descriptionShort,
+      }));
+
+    return data;
+  },
+
+  generate(data, relations, {
+    getColors,
+    html,
+    language,
+    transformMultiline,
+  }) {
+    const {isTrackPage, isAlbumPage} = data;
+
+    const trackListPart = html.tags([
+      html.tag('h1', relations.albumLink),
+      data.trackSectionInfo.map(
+        ({
+          name,
+          color,
+          isDefaultTrackSection,
+
+          firstTrackNumber,
+          lastTrackNumber,
+
+          includesCurrentTrack,
+          currentTrackIndex,
+        }, index) => {
+          const trackLinks = relations.trackLinks[index];
+
+          const sectionName =
+            html.tag('span', {class: 'group-name'},
+              (isDefaultTrackSection
+                ? language.$('albumSidebar.trackList.fallbackSectionName')
+                : name));
+
+          let style;
+          if (color) {
+            const {primary} = getColors(color);
+            style = `--primary-color: ${primary}`;
+          }
+
+          const trackListItems =
+            trackLinks.map((trackLink, index) =>
+              html.tag('li',
+                {
+                  class:
+                    includesCurrentTrack &&
+                    index === currentTrackIndex &&
+                    'current',
+                },
+                language.$('albumSidebar.trackList.item', {
+                  track: trackLink,
+                })));
+
+          return html.tag('details',
+            {
+              class: includesCurrentTrack && 'current',
+
+              open: (
+                // Leave sidebar track sections collapsed on album info page,
+                // since there's already a view of the full track listing
+                // in the main content area.
+                isTrackPage &&
+
+                // Only expand the track section which includes the track
+                // currently being viewed by default.
+                includesCurrentTrack),
+            },
+            [
+              html.tag('summary', {style},
+                html.tag('span',
+                  (data.hasTrackNumbers
+                    ? language.$('albumSidebar.trackList.group.withRange', {
+                        group: sectionName,
+                        range: `${firstTrackNumber}&ndash;${lastTrackNumber}`
+                      })
+                    : language.$('albumSidebar.trackList.group', {
+                        group: sectionName,
+                      })))),
+
+              (data.hasTrackNumbers
+                ? html.tag('ol',
+                    {start: firstTrackNumber},
+                    trackListItems)
+                : html.tag('ul', trackListItems)),
+            ]);
+        }),
+    ]);
+
+    const groupParts = data.groupInfo.map(
+      ({description}, index) => {
+        const links = relations.groupLinks[index];
+
+        return html.tags([
+          html.tag('h1',
+            language.$('albumSidebar.groupBox.title', {
+              group: links.groupLink,
+            })),
+
+          isAlbumPage &&
+            transformMultiline(description),
+
+          !empty(links.externalLinks) &&
+            html.tag('p',
+              language.$('releaseInfo.visitOn', {
+                links: language.formatDisjunctionList(links.externalLinks),
+              })),
+
+          isAlbumPage &&
+          links.nextAlbumLink &&
+            html.tag('p', {class: 'group-chronology-link'},
+              language.$('albumSidebar.groupBox.next', {
+                album: links.nextAlbumLink,
+              })),
+
+          isAlbumPage &&
+          links.previousAlbumLink &&
+            html.tag('p', {class: 'group-chronology-link'},
+              language.$('albumSidebar.groupBox.previous', {
+                album: links.previousAlbumLink,
+              })),
+        ]);
+      });
+
+    if (isAlbumPage) {
+      return {
+        // leftSidebarStickyMode: 'last',
+        leftSidebarMultiple: [
+          ...groupParts.map(groupPart => ({content: groupPart})),
+          {content: trackListPart},
+        ],
+      };
+    } else {
+      return {
+        // leftSidebarStickyMode: 'column',
+        leftSidebarMultiple: [
+          {content: trackListPart},
+          // ...groupParts.map(groupPart => ({content: groupPart})),
+          {
+            content:
+              groupParts
+                .flatMap((part, i) => [
+                  part,
+                  i < groupParts.length - 1 &&
+                    html.tag('hr', {
+                      style: `border-color: var(--primary-color); border-style: none none dotted none`
+                    })
+                ])
+                .filter(Boolean),
+          },
+        ],
+      };
+    }
+  },
+};