« 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
diff options
context:
space:
mode:
Diffstat (limited to 'src/content/dependencies')
-rw-r--r--src/content/dependencies/generateAbsoluteDatetimestamp.js41
-rw-r--r--src/content/dependencies/generateColorStyleRules.js7
-rw-r--r--src/content/dependencies/generateColorStyleVariables.js51
-rw-r--r--src/content/dependencies/generateDatetimestampTemplate.js28
-rw-r--r--src/content/dependencies/generateGroupInfoPage.js112
-rw-r--r--src/content/dependencies/generateRelativeDatetimestamp.js58
-rw-r--r--src/content/dependencies/generateTrackInfoPage.js70
7 files changed, 311 insertions, 56 deletions
diff --git a/src/content/dependencies/generateAbsoluteDatetimestamp.js b/src/content/dependencies/generateAbsoluteDatetimestamp.js
new file mode 100644
index 00000000..63acecf2
--- /dev/null
+++ b/src/content/dependencies/generateAbsoluteDatetimestamp.js
@@ -0,0 +1,41 @@
+export default {
+  contentDependencies: ['generateDatetimestampTemplate'],
+  extraDependencies: ['html', 'language'],
+
+  data: (date) =>
+    ({date}),
+
+  relations: (relation) =>
+    ({template: relation('generateDatetimestampTemplate')}),
+
+  slots: {
+    style: {
+      validate: v => v.is('full', 'year'),
+      default: 'full',
+    },
+
+    // Only has an effect for 'year' style.
+    tooltip: {
+      type: 'boolean',
+      default: false,
+    },
+  },
+
+  generate: (data, relations, slots, {language}) =>
+    relations.template.slots({
+      mainContent:
+        (slots.style === 'full'
+          ? language.formatDate(data.date)
+       : slots.style === 'year'
+          ? data.date.getFullYear().toString()
+          : null),
+
+      tooltipContent:
+        slots.tooltip &&
+        slots.style === 'year' &&
+          language.formatDate(data.date),
+
+      datetime:
+        data.date.toISOString(),
+    }),
+};
diff --git a/src/content/dependencies/generateColorStyleRules.js b/src/content/dependencies/generateColorStyleRules.js
index 1b316a3c..3f1d0130 100644
--- a/src/content/dependencies/generateColorStyleRules.js
+++ b/src/content/dependencies/generateColorStyleRules.js
@@ -18,9 +18,12 @@ export default {
       `:root {`,
       ...(
         relations.variables
-          .slot('color', slots.color)
+          .slots({
+            color: slots.color,
+            context: 'page-root',
+            mode: 'property-list',
+          })
           .content
-          .split(';')
           .map(line => line + ';')),
       `}`,
     ].join('\n');
diff --git a/src/content/dependencies/generateColorStyleVariables.js b/src/content/dependencies/generateColorStyleVariables.js
index f30d786b..7cd04bd1 100644
--- a/src/content/dependencies/generateColorStyleVariables.js
+++ b/src/content/dependencies/generateColorStyleVariables.js
@@ -2,7 +2,23 @@ export default {
   extraDependencies: ['html', 'getColors'],
 
   slots: {
-    color: {validate: v => v.isColor},
+    color: {
+      validate: v => v.isColor,
+    },
+
+    context: {
+      validate: v => v.is(
+        'any-content',
+        'page-root',
+        'primary-only'),
+
+      default: 'any-content',
+    },
+
+    mode: {
+      validate: v => v.is('style', 'property-list'),
+      default: 'style',
+    },
   },
 
   generate(slots, {getColors}) {
@@ -18,7 +34,7 @@ export default {
       shadow,
     } = getColors(slots.color);
 
-    return [
+    let anyContent = [
       `--primary-color: ${primary}`,
       `--dark-color: ${dark}`,
       `--dim-color: ${dim}`,
@@ -26,6 +42,35 @@ export default {
       `--bg-color: ${bg}`,
       `--bg-black-color: ${bgBlack}`,
       `--shadow-color: ${shadow}`,
-    ].join('; ');
+    ];
+
+    let selectedProperties;
+
+    switch (slots.context) {
+      case 'any-content':
+        selectedProperties = anyContent;
+        break;
+
+      case 'page-root':
+        selectedProperties = [
+          ...anyContent,
+          `--page-primary-color: ${primary}`,
+        ];
+        break;
+
+      case 'primary-only':
+        selectedProperties = [
+          `--primary-color: ${primary}`,
+        ];
+        break;
+    }
+
+    switch (slots.mode) {
+      case 'style':
+        return selectedProperties.join('; ');
+
+      case 'property-list':
+        return selectedProperties;
+    }
   },
 };
diff --git a/src/content/dependencies/generateDatetimestampTemplate.js b/src/content/dependencies/generateDatetimestampTemplate.js
new file mode 100644
index 00000000..bfba647f
--- /dev/null
+++ b/src/content/dependencies/generateDatetimestampTemplate.js
@@ -0,0 +1,28 @@
+export default {
+  extraDependencies: ['html'],
+
+  slots: {
+    mainContent: {type: 'html'},
+    tooltipContent: {type: 'html'},
+    datetime: {type: 'string'},
+  },
+
+  generate: (slots, {html}) =>
+    html.tag('span', {
+      [html.joinChildren]: '',
+
+      class: [
+        'datetimestamp',
+        slots.tooltipContent && 'has-tooltip',
+      ],
+    }, [
+      html.tag('time',
+        {datetime: slots.datetime},
+        slots.mainContent),
+
+      slots.tooltipContent &&
+        html.tag('span', {class: 'datetimestamp-tooltip'},
+          html.tag('span', {class: 'datetimestamp-tooltip-content'},
+            slots.tooltipContent)),
+    ]),
+};
diff --git a/src/content/dependencies/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js
index 05df33fb..0e5d645b 100644
--- a/src/content/dependencies/generateGroupInfoPage.js
+++ b/src/content/dependencies/generateGroupInfoPage.js
@@ -1,7 +1,9 @@
-import {empty} from '#sugar';
+import {empty, stitchArrays} from '#sugar';
 
 export default {
   contentDependencies: [
+    'generateAbsoluteDatetimestamp',
+    'generateColorStyleVariables',
     'generateContentHeading',
     'generateGroupNavLinks',
     'generateGroupSecondaryNav',
@@ -62,18 +64,27 @@ export default {
       sec.albums.galleryLink =
         relation('linkGroupGallery', group);
 
-      sec.albums.entries =
-        group.albums.map(album => {
-          const links = {};
-          links.albumLink = relation('linkAlbum', album);
+      sec.albums.colorVariables =
+        group.albums
+          .map(() => relation('generateColorStyleVariables'));
 
-          const otherGroup = album.groups.find(g => g !== group);
-          if (otherGroup) {
-            links.groupLink = relation('linkGroup', otherGroup);
-          }
+      sec.albums.albumLinks =
+        group.albums
+          .map(album => relation('linkAlbum', album));
 
-          return links;
-        });
+      sec.albums.groupLinks =
+        group.albums
+          .map(album => album.groups.find(g => g !== group))
+          .map(group =>
+            (group
+              ? relation('linkGroup', group)
+              : null));
+
+      sec.albums.datetimestamps =
+        group.albums.map(album =>
+          (album.date
+            ? relation('generateAbsoluteDatetimestamp', album.date)
+            : null));
     }
 
     return relations;
@@ -85,11 +96,8 @@ export default {
     data.name = group.name;
     data.color = group.color;
 
-    if (!empty(group.albums)) {
-      data.albumYears =
-        group.albums
-          .map(album => album.date?.getFullYear());
-    }
+    data.albumColors =
+      group.albums.map(album => album.color);
 
     return data;
   },
@@ -133,34 +141,50 @@ export default {
               })),
 
             html.tag('ul',
-              sec.albums.entries.map(({albumLink, groupLink}, index) => {
-                // All these strings are really jank, and should probably
-                // be implemented with the same 'const parts = [], opts = {}'
-                // form used elsewhere...
-                const year = data.albumYears[index];
-                const item =
-                  (year
-                    ? language.$('groupInfoPage.albumList.item', {
-                        year,
-                        album: albumLink,
-                      })
-                    : language.$('groupInfoPage.albumList.item.withoutYear', {
-                        album: albumLink,
-                      }));
-
-                return html.tag('li',
-                  (groupLink
-                    ? language.$('groupInfoPage.albumList.item.withAccent', {
-                        item,
-                        accent:
-                          html.tag('span', {class: 'other-group-accent'},
-                            language.$('groupInfoPage.albumList.item.otherGroupAccent', {
-                              group:
-                                groupLink.slot('color', false),
-                            })),
-                      })
-                    : item));
-              })),
+              stitchArrays({
+                albumLink: sec.albums.albumLinks,
+                groupLink: sec.albums.groupLinks,
+                datetimestamp: sec.albums.datetimestamps,
+                colorVariables: sec.albums.colorVariables,
+                albumColor: data.albumColors,
+              }).map(({
+                  albumLink,
+                  groupLink,
+                  datetimestamp,
+                  colorVariables,
+                  albumColor,
+                }) => {
+                  const prefix = 'groupInfoPage.albumList.item';
+                  const parts = [prefix];
+                  const options = {};
+
+                  options.album =
+                    albumLink.slot('color', false);
+
+                  if (datetimestamp) {
+                    parts.push('withYear');
+                    options.yearAccent =
+                      language.$(prefix, 'yearAccent', {
+                        year:
+                          datetimestamp.slots({style: 'year', tooltip: true}),
+                      });
+                  }
+
+                  if (groupLink) {
+                    parts.push('withOtherGroup');
+                    options.otherGroupAccent =
+                      html.tag('span', {class: 'other-group-accent'},
+                        language.$(prefix, 'otherGroupAccent', {
+                          group:
+                            groupLink.slot('color', false),
+                        }));
+                  }
+
+                  return (
+                    html.tag('li',
+                      {style: colorVariables.slot('color', albumColor).content},
+                      language.$(...parts, options)));
+                })),
           ],
         ],
 
diff --git a/src/content/dependencies/generateRelativeDatetimestamp.js b/src/content/dependencies/generateRelativeDatetimestamp.js
new file mode 100644
index 00000000..bbe33188
--- /dev/null
+++ b/src/content/dependencies/generateRelativeDatetimestamp.js
@@ -0,0 +1,58 @@
+export default {
+  contentDependencies: [
+    'generateAbsoluteDatetimestamp',
+    'generateDatetimestampTemplate',
+  ],
+
+  extraDependencies: ['html', 'language'],
+
+  data: (currentDate, referenceDate) =>
+    (currentDate.getTime() === referenceDate.getTime()
+      ? {equal: true, date: currentDate}
+      : {equal: false, currentDate, referenceDate}),
+
+  relations: (relation, currentDate) =>
+    ({template: relation('generateDatetimestampTemplate'),
+      fallback: relation('generateAbsoluteDatetimestamp', currentDate)}),
+
+  slots: {
+    style: {
+      validate: v => v.is('full', 'year'),
+      default: 'full',
+    },
+
+    tooltip: {
+      type: 'boolean',
+      default: false,
+    },
+  },
+
+  generate(data, relations, slots, {language}) {
+    if (data.comparison === 'equal') {
+      return relations.fallback.slots({
+        style: slots.style,
+        tooltip: slots.tooltip,
+      });
+    }
+
+    return relations.template.slots({
+      mainContent:
+        (slots.style === 'full'
+          ? language.formatDate(data.currentDate)
+       : slots.style === 'year'
+          ? data.currentDate.getFullYear().toString()
+          : null),
+
+      tooltipContent:
+        slots.tooltip &&
+          language.formatRelativeDate(data.currentDate, data.referenceDate, {
+            considerRoundingDays: true,
+            approximate: true,
+            absolute: slots.style === 'year',
+          }),
+
+      datetime:
+        data.currentDate.toISOString(),
+    });
+  },
+};
diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js
index d8908ade..041f6bbc 100644
--- a/src/content/dependencies/generateTrackInfoPage.js
+++ b/src/content/dependencies/generateTrackInfoPage.js
@@ -1,20 +1,23 @@
-import {empty} from '#sugar';
+import {empty, stitchArrays} from '#sugar';
 import {sortAlbumsTracksChronologically, sortFlashesChronologically} from '#wiki-data';
 
 import getChronologyRelations from '../util/getChronologyRelations.js';
 
 export default {
   contentDependencies: [
+    'generateAbsoluteDatetimestamp',
     'generateAdditionalFilesShortcut',
     'generateAlbumAdditionalFilesList',
     'generateAlbumNavAccent',
     'generateAlbumSidebar',
     'generateAlbumStyleRules',
     'generateChronologyLinks',
+    'generateColorStyleVariables',
     'generateCommentarySection',
     'generateContentHeading',
     'generateContributionList',
     'generatePageLayout',
+    'generateRelativeDatetimestamp',
     'generateTrackAdditionalNamesBox',
     'generateTrackCoverArtwork',
     'generateTrackList',
@@ -139,6 +142,29 @@ export default {
       otherReleases.heading =
         relation('generateContentHeading');
 
+      otherReleases.colorVariables =
+        track.otherReleases
+          .map(() => relation('generateColorStyleVariables'));
+
+      otherReleases.trackLinks =
+        track.otherReleases
+          .map(track => relation('linkTrack', track));
+
+      otherReleases.albumLinks =
+        track.otherReleases
+          .map(track => relation('linkAlbum', track.album));
+
+      otherReleases.datetimestamps =
+        track.otherReleases.map(track2 =>
+          (track2.date
+            ? (track.date
+                ? relation('generateRelativeDatetimestamp',
+                    track2.date,
+                    track.date)
+                : relation('generateAbsoluteDatetimestamp',
+                    track2.date))
+            : null));
+
       otherReleases.items =
         track.otherReleases.map(track => ({
           trackLink: relation('linkTrack', track),
@@ -289,6 +315,9 @@ export default {
       hasTrackNumbers: track.album.hasTrackNumbers,
       trackNumber: track.album.tracks.indexOf(track) + 1,
 
+      otherReleaseColors:
+        track.otherReleases.map(track => track.color),
+
       numAdditionalFiles: track.additionalFiles.length,
     };
   },
@@ -355,12 +384,39 @@ export default {
               }),
 
             html.tag('ul',
-              sec.otherReleases.items.map(({trackLink, albumLink}) =>
-                html.tag('li',
-                  language.$('releaseInfo.alsoReleasedAs.item', {
-                    track: trackLink,
-                    album: albumLink,
-                  })))),
+              stitchArrays({
+                trackLink: sec.otherReleases.trackLinks,
+                albumLink: sec.otherReleases.albumLinks,
+                datetimestamp: sec.otherReleases.datetimestamps,
+                colorVariables: sec.otherReleases.colorVariables,
+                color: data.otherReleaseColors,
+              }).map(({
+                  trackLink,
+                  albumLink,
+                  datetimestamp,
+                  colorVariables,
+                  color,
+                }) => {
+                  const parts = ['releaseInfo.alsoReleasedAs.item'];
+                  const options = {};
+
+                  options.track = trackLink.slot('color', false);
+                  options.album = albumLink;
+
+                  if (datetimestamp) {
+                    parts.push('withYear');
+                    options.year =
+                      datetimestamp.slots({
+                        style: 'year',
+                        tooltip: true,
+                      });
+                  }
+
+                  return (
+                    html.tag('li',
+                      {style: colorVariables.slot('color', color).content},
+                      language.$(...parts, options)));
+                })),
           ],
 
           sec.contributors && [