« get me outta code hell

Merge branch 'commentary-entries' into preview - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/content
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-11-24 15:05:03 -0400
committer(quasar) nebula <qznebula@protonmail.com>2023-11-24 15:05:03 -0400
commiteab0e06d148b5445feab453b8042d5e93e1fa1a2 (patch)
tree62dab7600a89ca73cd1bffc19092c97fe4d58450 /src/content
parentca30b07b9e116f6d42d6ea6a2623e1500c289383 (diff)
parent9f58ba688c8a6ac3acf7b4bc435e2ccaed20b011 (diff)
Merge branch 'commentary-entries' into preview
Diffstat (limited to 'src/content')
-rw-r--r--src/content/dependencies/generateAlbumCommentaryPage.js30
-rw-r--r--src/content/dependencies/generateAlbumInfoPage.js22
-rw-r--r--src/content/dependencies/generateCommentaryEntry.js99
-rw-r--r--src/content/dependencies/generateCommentarySection.js29
-rw-r--r--src/content/dependencies/generateTrackInfoPage.js22
-rw-r--r--src/content/dependencies/transformContent.js55
6 files changed, 185 insertions, 72 deletions
diff --git a/src/content/dependencies/generateAlbumCommentaryPage.js b/src/content/dependencies/generateAlbumCommentaryPage.js
index e2415516..001003ae 100644
--- a/src/content/dependencies/generateAlbumCommentaryPage.js
+++ b/src/content/dependencies/generateAlbumCommentaryPage.js
@@ -6,13 +6,12 @@ export default {
     'generateAlbumNavAccent',
     'generateAlbumSidebarTrackSection',
     'generateAlbumStyleRules',
-    'generateColorStyleVariables',
+    'generateCommentaryEntry',
     'generateContentHeading',
     'generateTrackCoverArtwork',
     'generatePageLayout',
     'linkAlbum',
     'linkTrack',
-    'transformContent',
   ],
 
   extraDependencies: ['html', 'language'],
@@ -38,8 +37,9 @@ export default {
           relation('generateAlbumCoverArtwork', album);
       }
 
-      relations.albumCommentaryContent =
-        relation('transformContent', album.commentary);
+      relations.albumCommentaryEntries =
+        album.commentary
+          .map(entry => relation('generateCommentaryEntry', entry));
     }
 
     const tracksWithCommentary =
@@ -61,16 +61,11 @@ export default {
             ? relation('generateTrackCoverArtwork', track)
             : null));
 
-    relations.trackCommentaryContent =
-      tracksWithCommentary
-        .map(track => relation('transformContent', track.commentary));
-
-    relations.trackCommentaryColorVariables =
+    relations.trackCommentaryEntries =
       tracksWithCommentary
         .map(track =>
-          (track.color === album.color
-            ? null
-            : relation('generateColorStyleVariables')));
+          track.commentary
+            .map(entry => relation('generateCommentaryEntry', entry)));
 
     relations.sidebarAlbumLink =
       relation('linkAlbum', album);
@@ -163,10 +158,9 @@ export default {
             link: relations.trackCommentaryLinks,
             directory: data.trackCommentaryDirectories,
             cover: relations.trackCommentaryCovers,
-            content: relations.trackCommentaryContent,
-            colorVariables: relations.trackCommentaryColorVariables,
+            entries: relations.trackCommentaryEntries,
             color: data.trackCommentaryColors,
-          }).map(({heading, link, directory, cover, content, colorVariables, color}) => [
+          }).map(({heading, link, directory, cover, entries, color}) => [
               heading.slots({
                 tag: 'h3',
                 id: directory,
@@ -175,11 +169,7 @@ export default {
 
               cover?.slots({mode: 'commentary'}),
 
-              html.tag('blockquote',
-                (color
-                  ? {style: colorVariables.slot('color', color).content}
-                  : {}),
-                content),
+              entries.map(entry => entry.slot('color', color)),
             ]),
         ],
 
diff --git a/src/content/dependencies/generateAlbumInfoPage.js b/src/content/dependencies/generateAlbumInfoPage.js
index 5fe27caf..90a120ca 100644
--- a/src/content/dependencies/generateAlbumInfoPage.js
+++ b/src/content/dependencies/generateAlbumInfoPage.js
@@ -17,6 +17,7 @@ export default {
     'generateAlbumStyleRules',
     'generateAlbumTrackList',
     'generateChronologyLinks',
+    'generateCommentarySection',
     'generateContentHeading',
     'generatePageLayout',
     'linkAlbum',
@@ -126,13 +127,8 @@ export default {
     // Section: Artist commentary
 
     if (album.commentary) {
-      const artistCommentary = sections.artistCommentary = {};
-
-      artistCommentary.heading =
-        relation('generateContentHeading');
-
-      artistCommentary.content =
-        relation('transformContent', album.commentary);
+      sections.artistCommentary =
+        relation('generateCommentarySection', album.commentary);
     }
 
     return relations;
@@ -235,17 +231,7 @@ export default {
             sec.additionalFiles.additionalFilesList,
           ],
 
-          sec.artistCommentary && [
-            sec.artistCommentary.heading
-              .slots({
-                id: 'artist-commentary',
-                title: language.$('releaseInfo.artistCommentary')
-              }),
-
-            html.tag('blockquote',
-              sec.artistCommentary.content
-                .slot('mode', 'multiline')),
-          ],
+          sec.artistCommentary,
         ],
 
         navLinkStyle: 'hierarchical',
diff --git a/src/content/dependencies/generateCommentaryEntry.js b/src/content/dependencies/generateCommentaryEntry.js
new file mode 100644
index 00000000..0b2b2558
--- /dev/null
+++ b/src/content/dependencies/generateCommentaryEntry.js
@@ -0,0 +1,99 @@
+import {empty} from '#sugar';
+
+export default {
+  contentDependencies: [
+    'generateColorStyleVariables',
+    'linkArtist',
+    'transformContent',
+  ],
+
+  extraDependencies: ['html', 'language'],
+
+  relations: (relation, entry) => ({
+    artistLinks:
+      (!empty(entry.artists) && !entry.artistDisplayText
+        ? entry.artists
+            .map(artist => relation('linkArtist', artist))
+        : null),
+
+    artistsContent:
+      (entry.artistDisplayText
+        ? relation('transformContent', entry.artistDisplayText)
+        : null),
+
+    annotationContent:
+      (entry.annotation
+        ? relation('transformContent', entry.annotation)
+        : null),
+
+    bodyContent:
+      (entry.body
+        ? relation('transformContent', entry.body)
+        : null),
+
+    colorVariables:
+      relation('generateColorStyleVariables'),
+  }),
+
+  data: (entry) => ({
+    date: entry.date,
+  }),
+
+  slots: {
+    color: {validate: v => v.isColor},
+  },
+
+  generate(data, relations, slots, {html, language}) {
+    const artistsSpan =
+      html.tag('span', {class: 'commentary-entry-artists'},
+        (relations.artistsContent
+          ? relations.artistsContent.slot('mode', 'inline')
+       : relations.artistLinks
+          ? language.formatConjunctionList(relations.artistLinks)
+          : language.$('misc.artistCommentary.entry.title.noArtists')));
+
+    const accentParts = ['misc.artistCommentary.entry.title.accent'];
+    const accentOptions = {};
+
+    if (relations.annotationContent) {
+      accentParts.push('withAnnotation');
+      accentOptions.annotation =
+        relations.annotationContent.slot('mode', 'inline');
+    }
+
+    if (data.date) {
+      accentParts.push('withDate');
+      accentOptions.date =
+        language.formatDate(data.date);
+    }
+
+    const accent =
+      (accentParts.length > 1
+        ? html.tag('span', {class: 'commentary-entry-accent'},
+            language.$(...accentParts, accentOptions))
+        : null);
+
+    const titleParts = ['misc.artistCommentary.entry.title'];
+    const titleOptions = {artists: artistsSpan};
+
+    if (accent) {
+      titleParts.push('withAccent');
+      titleOptions.accent = accent;
+    }
+
+    const style =
+      (slots.color
+        ? relations.colorVariables
+            .slot('color', slots.color)
+            .content
+        : null);
+
+    return html.tags([
+      html.tag('p', {class: 'commentary-entry-heading', style},
+        language.$(...titleParts, titleOptions)),
+
+      html.tag('blockquote', {class: 'commentary-entry-body', style},
+        relations.bodyContent.slot('mode', 'multiline')),
+    ]);
+  },
+};
diff --git a/src/content/dependencies/generateCommentarySection.js b/src/content/dependencies/generateCommentarySection.js
new file mode 100644
index 00000000..8ae1b2d0
--- /dev/null
+++ b/src/content/dependencies/generateCommentarySection.js
@@ -0,0 +1,29 @@
+export default {
+  contentDependencies: [
+    'transformContent',
+    'generateCommentaryEntry',
+    'generateContentHeading',
+  ],
+
+  extraDependencies: ['html', 'language'],
+
+  relations: (relation, entries) => ({
+    heading:
+      relation('generateContentHeading'),
+
+    entries:
+      entries.map(entry =>
+        relation('generateCommentaryEntry', entry)),
+  }),
+
+  generate: (relations, {html, language}) =>
+    html.tags([
+      relations.heading
+        .slots({
+          id: 'artist-commentary',
+          title: language.$('misc.artistCommentary')
+        }),
+
+      relations.entries,
+    ]),
+};
diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js
index 180e5c29..2848b15c 100644
--- a/src/content/dependencies/generateTrackInfoPage.js
+++ b/src/content/dependencies/generateTrackInfoPage.js
@@ -12,6 +12,7 @@ export default {
     'generateAlbumSidebar',
     'generateAlbumStyleRules',
     'generateChronologyLinks',
+    'generateCommentarySection',
     'generateContentHeading',
     'generateContributionList',
     'generatePageLayout',
@@ -274,13 +275,8 @@ export default {
     // Section: Artist commentary
 
     if (track.commentary) {
-      const artistCommentary = sections.artistCommentary = {};
-
-      artistCommentary.heading =
-        relation('generateContentHeading');
-
-      artistCommentary.content =
-        relation('transformContent', track.commentary);
+      sections.artistCommentary =
+        relation('generateCommentarySection', track.commentary);
     }
 
     return relations;
@@ -499,17 +495,7 @@ export default {
             sec.additionalFiles.list,
           ],
 
-          sec.artistCommentary && [
-            sec.artistCommentary.heading
-              .slots({
-                id: 'artist-commentary',
-                title: language.$('releaseInfo.artistCommentary')
-              }),
-
-            html.tag('blockquote',
-              sec.artistCommentary.content
-                .slot('mode', 'multiline')),
-          ],
+          sec.artistCommentary,
         ],
 
         navLinkStyle: 'hierarchical',
diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js
index 3c2c3521..7b2d0573 100644
--- a/src/content/dependencies/transformContent.js
+++ b/src/content/dependencies/transformContent.js
@@ -1,7 +1,7 @@
 import {bindFind} from '#find';
 import {parseInput} from '#replacer';
 
-import {marked} from 'marked';
+import {Marked} from 'marked';
 
 export const replacerSpec = {
   album: {
@@ -147,6 +147,29 @@ const linkIndexRelationMap = {
   newsIndex: 'linkNewsIndex',
 };
 
+const commonMarkedOptions = {
+  headerIds: false,
+  mangle: false,
+};
+
+const multilineMarked = new Marked({
+  ...commonMarkedOptions,
+});
+
+const inlineMarked = new Marked({
+  ...commonMarkedOptions,
+
+  renderer: {
+    paragraph(text) {
+      return text;
+    },
+  },
+});
+
+const lyricsMarked = new Marked({
+  ...commonMarkedOptions,
+});
+
 function getPlaceholder(node, content) {
   return {type: 'text', data: content.slice(node.i, node.iEnd)};
 }
@@ -447,19 +470,9 @@ export default {
       return link.data;
     }
 
-    // In inline mode, no further processing is needed!
-
-    if (slots.mode === 'inline') {
-      return html.tags(contentFromNodes.map(node => node.data));
-    }
-
-    // Multiline mode has a secondary processing stage where it's passed...
-    // through marked! Rolling your own Markdown only gets you so far :D
-
-    const markedOptions = {
-      headerIds: false,
-      mangle: false,
-    };
+    // Content always goes through marked (i.e. parsing as Markdown).
+    // This does require some attention to detail, mostly to do with line
+    // breaks (in multiline mode) and extracting/re-inserting non-text nodes.
 
     // The content of non-text nodes can end up getting mangled by marked.
     // To avoid this, we replace them with mundane placeholders, then
@@ -534,6 +547,16 @@ export default {
       return html.tags(tags, {[html.joinChildren]: ''});
     };
 
+    if (slots.mode === 'inline') {
+      const markedInput =
+        extractNonTextNodes();
+
+      const markedOutput =
+        inlineMarked.parse(markedInput);
+
+      return reinsertNonTextNodes(markedOutput);
+    }
+
     // This is separated into its own function just since we're gonna reuse
     // it in a minute if everything goes to heck in lyrics mode.
     const transformMultiline = () => {
@@ -550,7 +573,7 @@ export default {
           .replace(/(?<=^>.*)\n+(?!^>)/gm, '\n\n');
 
       const markedOutput =
-        marked.parse(markedInput, markedOptions);
+        multilineMarked.parse(markedInput);
 
       return reinsertNonTextNodes(markedOutput);
     }
@@ -600,7 +623,7 @@ export default {
         });
 
       const markedOutput =
-        marked.parse(markedInput, markedOptions);
+        lyricsMarked.parse(markedInput);
 
       return reinsertNonTextNodes(markedOutput);
     }