« 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/generateTrackInfoPage.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/content/dependencies/generateTrackInfoPage.js')
-rw-r--r--src/content/dependencies/generateTrackInfoPage.js790
1 files changed, 298 insertions, 492 deletions
diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js
index a3ff07bd..e994aacf 100644
--- a/src/content/dependencies/generateTrackInfoPage.js
+++ b/src/content/dependencies/generateTrackInfoPage.js
@@ -1,613 +1,419 @@
-import {sortAlbumsTracksChronologically, sortFlashesChronologically}
-  from '#sort';
-import {empty, stitchArrays} from '#sugar';
-
-import getChronologyRelations from '../util/getChronologyRelations.js';
-
 export default {
   contentDependencies: [
-    'generateAbsoluteDatetimestamp',
-    'generateAdditionalFilesShortcut',
-    'generateAlbumAdditionalFilesList',
+    'generateAdditionalFilesList',
+    'generateAdditionalNamesBox',
     'generateAlbumNavAccent',
     'generateAlbumSecondaryNav',
     'generateAlbumSidebar',
-    'generateAlbumStyleRules',
-    'generateChronologyLinks',
-    'generateColorStyleAttribute',
-    'generateCommentarySection',
+    'generateAlbumStyleTags',
+    'generateCommentaryEntry',
+    'generateContentContentHeading',
     'generateContentHeading',
     'generateContributionList',
+    'generateLyricsSection',
     'generatePageLayout',
-    'generateRelativeDatetimestamp',
-    'generateTrackAdditionalNamesBox',
-    'generateTrackCoverArtwork',
+    'generateTrackArtistCommentarySection',
+    'generateTrackArtworkColumn',
+    'generateTrackInfoPageFeaturedByFlashesList',
+    'generateTrackInfoPageOtherReleasesList',
     'generateTrackList',
     'generateTrackListDividedByGroups',
+    'generateTrackNavLinks',
     'generateTrackReleaseInfo',
     'generateTrackSocialEmbed',
     'linkAlbum',
-    'linkArtist',
-    'linkFlash',
     'linkTrack',
     'transformContent',
   ],
 
-  extraDependencies: ['html', 'language', 'wikiData'],
-
-  sprawl({wikiInfo}) {
-    return {
-      divideTrackListsByGroups: wikiInfo.divideTrackListsByGroups,
-      enableFlashesAndGames: wikiInfo.enableFlashesAndGames,
-    };
-  },
-
-  relations(relation, sprawl, track) {
-    const relations = {};
-    const sections = relations.sections = {};
-    const {album} = track;
-
-    relations.layout =
-      relation('generatePageLayout');
-
-    relations.albumStyleRules =
-      relation('generateAlbumStyleRules', track.album, track);
-
-    relations.socialEmbed =
-      relation('generateTrackSocialEmbed', track);
-
-    relations.artistChronologyContributions =
-      getChronologyRelations(track, {
-        contributions: [
-          ...track.artistContribs ?? [],
-          ...track.contributorContribs ?? [],
-        ],
-
-        linkArtist: artist => relation('linkArtist', artist),
-        linkThing: track => relation('linkTrack', track),
-
-        getThings(artist) {
-          const getDate = thing => thing.date;
-
-          const things = [
-            ...artist.tracksAsArtist,
-            ...artist.tracksAsContributor,
-          ].filter(getDate);
-
-          return sortAlbumsTracksChronologically(things, {getDate});
-        },
-      });
-
-    relations.coverArtistChronologyContributions =
-      getChronologyRelations(track, {
-        contributions: track.coverArtistContribs ?? [],
-
-        linkArtist: artist => relation('linkArtist', artist),
-
-        linkThing: trackOrAlbum =>
-          (trackOrAlbum.album
-            ? relation('linkTrack', trackOrAlbum)
-            : relation('linkAlbum', trackOrAlbum)),
-
-        getThings(artist) {
-          const getDate = thing => thing.coverArtDate ?? thing.date;
-
-          const things = [
-            ...artist.albumsAsCoverArtist,
-            ...artist.tracksAsCoverArtist,
-          ].filter(getDate);
-
-          return sortAlbumsTracksChronologically(things, {getDate});
-        },
-      }),
-
-    relations.albumLink =
-      relation('linkAlbum', track.album);
-
-    relations.trackLink =
-      relation('linkTrack', track);
-
-    relations.albumNavAccent =
-      relation('generateAlbumNavAccent', track.album, track);
-
-    relations.chronologyLinks =
-      relation('generateChronologyLinks');
-
-    relations.secondaryNav =
-      relation('generateAlbumSecondaryNav', track.album);
+  extraDependencies: ['html', 'language'],
 
-    relations.sidebar =
-      relation('generateAlbumSidebar', track.album, track);
+  query: (track) => ({
+    mainReleaseTrack:
+      (track.isMainRelease
+        ? track
+        : track.mainReleaseTrack),
+  }),
 
-    const additionalFilesSection = additionalFiles => ({
-      heading: relation('generateContentHeading'),
-      list: relation('generateAlbumAdditionalFilesList', album, additionalFiles),
-    });
+  relations: (relation, query, track) => ({
+    layout:
+      relation('generatePageLayout'),
 
-    // This'll take care of itself being blank if there's nothing to show here.
-    relations.additionalNamesBox =
-      relation('generateTrackAdditionalNamesBox', track);
+    albumStyleTags:
+      relation('generateAlbumStyleTags', track.album, track),
 
-    if (track.hasUniqueCoverArt || album.hasCoverArt) {
-      relations.cover =
-        relation('generateTrackCoverArtwork', track);
-    }
+    socialEmbed:
+      relation('generateTrackSocialEmbed', track),
 
-    // Section: Release info
+    navLinks:
+      relation('generateTrackNavLinks', track),
 
-    relations.releaseInfo =
-      relation('generateTrackReleaseInfo', track);
+    albumNavLink:
+      relation('linkAlbum', track.album),
 
-    // Section: Extra links
+    albumNavAccent:
+      relation('generateAlbumNavAccent', track.album, track),
 
-    const extra = sections.extra = {};
+    secondaryNav:
+      relation('generateAlbumSecondaryNav', track.album),
 
-    if (!empty(track.additionalFiles)) {
-      extra.additionalFilesShortcut =
-        relation('generateAdditionalFilesShortcut', track.additionalFiles);
-    }
+    sidebar:
+      relation('generateAlbumSidebar', track.album, track),
 
-    // Section: Other releases
+    additionalNamesBox:
+      relation('generateAdditionalNamesBox', track.additionalNames),
 
-    if (!empty(track.otherReleases)) {
-      const otherReleases = sections.otherReleases = {};
+    artworkColumn:
+      relation('generateTrackArtworkColumn', track),
 
-      otherReleases.heading =
-        relation('generateContentHeading');
+    contentHeading:
+      relation('generateContentHeading'),
 
-      otherReleases.colorStyles =
-        track.otherReleases
-          .map(track => relation('generateColorStyleAttribute', track.color));
+    contentContentHeading:
+      relation('generateContentContentHeading', track),
 
-      otherReleases.trackLinks =
-        track.otherReleases
-          .map(track => relation('linkTrack', track));
+    releaseInfo:
+      relation('generateTrackReleaseInfo', track),
 
-      otherReleases.albumLinks =
-        track.otherReleases
-          .map(track => relation('linkAlbum', track.album));
+    otherReleasesList:
+      relation('generateTrackInfoPageOtherReleasesList', track),
 
-      otherReleases.datetimestamps =
-        track.otherReleases.map(track2 =>
-          (track2.date
-            ? (track.date
-                ? relation('generateRelativeDatetimestamp',
-                    track2.date,
-                    track.date)
-                : relation('generateAbsoluteDatetimestamp',
-                    track2.date))
-            : null));
+    contributorContributionList:
+      relation('generateContributionList', track.contributorContribs),
 
-      otherReleases.items =
-        track.otherReleases.map(track => ({
-          trackLink: relation('linkTrack', track),
-          albumLink: relation('linkAlbum', track.album),
-        }));
-    }
+    referencedTracksList:
+      relation('generateTrackList', track.referencedTracks),
 
-    // Section: Contributors
+    sampledTracksList:
+      relation('generateTrackList', track.sampledTracks),
 
-    if (!empty(track.contributorContribs)) {
-      const contributors = sections.contributors = {};
+    referencedByTracksList:
+      relation('generateTrackListDividedByGroups',
+        query.mainReleaseTrack.referencedByTracks),
 
-      contributors.heading =
-        relation('generateContentHeading');
+    sampledByTracksList:
+      relation('generateTrackListDividedByGroups',
+        query.mainReleaseTrack.sampledByTracks),
 
-      contributors.list =
-        relation('generateContributionList', track.contributorContribs);
-    }
+    flashesThatFeatureList:
+      relation('generateTrackInfoPageFeaturedByFlashesList', track),
 
-    // Section: Referenced tracks
+    lyricsSection:
+      relation('generateLyricsSection', track.lyrics),
 
-    if (!empty(track.referencedTracks)) {
-      const references = sections.references = {};
+    sheetMusicFilesList:
+      relation('generateAdditionalFilesList', track.sheetMusicFiles),
 
-      references.heading =
-        relation('generateContentHeading');
+    midiProjectFilesList:
+      relation('generateAdditionalFilesList', track.midiProjectFiles),
 
-      references.list =
-        relation('generateTrackList', track.referencedTracks);
-    }
+    additionalFilesList:
+      relation('generateAdditionalFilesList', track.additionalFiles),
 
-    // Section: Sampled tracks
+    artistCommentarySection:
+      relation('generateTrackArtistCommentarySection', track),
 
-    if (!empty(track.sampledTracks)) {
-      const samples = sections.samples = {};
+    creditingSourceEntries:
+      track.creditingSources
+        .map(entry => relation('generateCommentaryEntry', entry)),
 
-      samples.heading =
-        relation('generateContentHeading');
+    referencingSourceEntries:
+      track.referencingSources
+        .map(entry => relation('generateCommentaryEntry', entry)),
+  }),
 
-      samples.list =
-        relation('generateTrackList', track.sampledTracks);
-    }
+  data: (_query, track) => ({
+    name:
+      track.name,
 
-    // Section: Tracks that reference
+    color:
+      track.color,
 
-    if (!empty(track.referencedByTracks)) {
-      const referencedBy = sections.referencedBy = {};
+    singleTrackSingle:
+      track.album.style === 'single' &&
+      track.album.tracks.length === 1,
+  }),
 
-      referencedBy.heading =
-        relation('generateContentHeading');
-
-      referencedBy.list =
-        relation('generateTrackListDividedByGroups',
-          track.referencedByTracks,
-          sprawl.divideTrackListsByGroups);
-    }
-
-    // Section: Tracks that sample
-
-    if (!empty(track.sampledByTracks)) {
-      const sampledBy = sections.sampledBy = {};
-
-      sampledBy.heading =
-        relation('generateContentHeading');
-
-      sampledBy.list =
-        relation('generateTrackListDividedByGroups',
-          track.sampledByTracks,
-          sprawl.divideTrackListsByGroups);
-    }
-
-    // Section: Flashes that feature
+  generate: (data, relations, {html, language}) =>
+    language.encapsulate('trackPage', pageCapsule =>
+      relations.layout.slots({
+        title:
+          language.$(pageCapsule, 'title', {
+            track: data.name,
+          }),
 
-    if (sprawl.enableFlashesAndGames) {
-      const sortedFeatures =
-        sortFlashesChronologically(
-          [track, ...track.otherReleases].flatMap(track =>
-            track.featuredInFlashes.map(flash => ({
-              // These aren't going to be exposed directly, they're processed
-              // into the appropriate relations after this sort.
-              flash, track,
+        headingMode: 'sticky',
 
-              // These properties are only used for the sort.
-              act: flash.act,
-              date: flash.date,
-            }))));
+        additionalNames: relations.additionalNamesBox,
 
-      if (!empty(sortedFeatures)) {
-        const flashesThatFeature = sections.flashesThatFeature = {};
+        color: data.color,
+        styleTags: relations.albumStyleTags,
 
-        flashesThatFeature.heading =
-          relation('generateContentHeading');
+        artworkColumnContent:
+          relations.artworkColumn,
 
-        flashesThatFeature.entries =
-          sortedFeatures.map(({flash, track: directlyFeaturedTrack}) =>
-            (directlyFeaturedTrack === track
-              ? {
-                  flashLink: relation('linkFlash', flash),
-                }
-              : {
-                  flashLink: relation('linkFlash', flash),
-                  trackLink: relation('linkTrack', directlyFeaturedTrack),
-                }));
-      }
-    }
+        mainContent: [
+          relations.releaseInfo,
 
-    // Section: Lyrics
+          html.tag('p',
+            {[html.onlyIfContent]: true},
+            {[html.joinChildren]: html.tag('br')},
 
-    if (track.lyrics) {
-      const lyrics = sections.lyrics = {};
+            language.encapsulate('releaseInfo', capsule => [
+              !html.isBlank(relations.sheetMusicFilesList) &&
+                language.encapsulate(capsule, 'sheetMusicFiles.shortcut', capsule =>
+                  language.$(capsule, {
+                    link:
+                      html.tag('a',
+                        {href: '#sheet-music-files'},
+                        language.$(capsule, 'link')),
+                  })),
 
-      lyrics.heading =
-        relation('generateContentHeading');
+              !html.isBlank(relations.midiProjectFilesList) &&
+                language.encapsulate(capsule, 'midiProjectFiles.shortcut', capsule =>
+                  language.$(capsule, {
+                    link:
+                      html.tag('a',
+                        {href: '#midi-project-files'},
+                        language.$(capsule, 'link')),
+                  })),
 
-      lyrics.content =
-        relation('transformContent', track.lyrics);
-    }
+              !html.isBlank(relations.additionalFilesList) &&
+                language.encapsulate(capsule, 'additionalFiles.shortcut', capsule =>
+                  language.$(capsule, {
+                    link:
+                      html.tag('a',
+                        {href: '#midi-project-files'},
+                        language.$(capsule, 'link')),
+                  })),
 
-    // Sections: Sheet music files, MIDI/proejct files, additional files
+              !html.isBlank(relations.artistCommentarySection) &&
+                language.encapsulate(capsule, 'readCommentary', capsule =>
+                  language.$(capsule, {
+                    link:
+                      html.tag('a',
+                        {href: '#artist-commentary'},
+                        language.$(capsule, 'link')),
+                  })),
 
-    if (!empty(track.sheetMusicFiles)) {
-      sections.sheetMusicFiles = additionalFilesSection(track.sheetMusicFiles);
-    }
+              !html.isBlank(relations.creditingSourceEntries) &&
+                language.encapsulate(capsule, 'readCreditingSources', capsule =>
+                  language.$(capsule, {
+                    link:
+                      html.tag('a',
+                        {href: '#crediting-sources'},
+                        language.$(capsule, 'link')),
+                  })),
 
-    if (!empty(track.midiProjectFiles)) {
-      sections.midiProjectFiles = additionalFilesSection(track.midiProjectFiles);
-    }
+              !html.isBlank(relations.referencingSourceEntries) &&
+                language.encapsulate(capsule, 'readReferencingSources', capsule =>
+                  language.$(capsule, {
+                    link:
+                      html.tag('a',
+                        {href: '#referencing-sources'},
+                        language.$(capsule, 'link')),
+                  })),
+            ])),
 
-    if (!empty(track.additionalFiles)) {
-      sections.additionalFiles = additionalFilesSection(track.additionalFiles);
-    }
+          relations.otherReleasesList,
 
-    // Section: Artist commentary
+          html.tags([
+            relations.contentHeading.clone()
+              .slots({
+                attributes: {id: 'contributors'},
+                title: language.$('releaseInfo.contributors'),
+              }),
 
-    if (track.commentary) {
-      sections.artistCommentary =
-        relation('generateCommentarySection', track.commentary);
-    }
+            relations.contributorContributionList.slots({
+              chronologyKind: 'trackContribution',
+            }),
+          ]),
+
+          html.tags([
+            language.encapsulate('releaseInfo.tracksReferenced', capsule =>
+              relations.contentHeading.clone()
+                .slots({
+                  attributes: {id: 'references'},
+
+                  title:
+                    language.$(capsule, {
+                      track:
+                        html.tag('i', data.name),
+                    }),
+
+                  stickyTitle:
+                    language.$(capsule, 'sticky'),
+                })),
 
-    return relations;
-  },
+            relations.referencedTracksList,
+          ]),
 
-  data(sprawl, track) {
-    return {
-      name: track.name,
-      color: track.color,
+          html.tags([
+            language.encapsulate('releaseInfo.tracksSampled', capsule =>
+              relations.contentHeading.clone()
+                .slots({
+                  attributes: {id: 'samples'},
 
-      hasTrackNumbers: track.album.hasTrackNumbers,
-      trackNumber: track.album.tracks.indexOf(track) + 1,
+                  title:
+                    language.$(capsule, {
+                      track:
+                        html.tag('i', data.name),
+                    }),
 
-      numAdditionalFiles: track.additionalFiles.length,
-    };
-  },
+                  stickyTitle:
+                    language.$(capsule, 'sticky'),
+                })),
 
-  generate(data, relations, {html, language}) {
-    const {sections: sec} = relations;
+            relations.sampledTracksList,
+          ]),
 
-    return relations.layout
-      .slots({
-        title: language.$('trackPage.title', {track: data.name}),
-        headingMode: 'sticky',
+          language.encapsulate('releaseInfo.tracksThatReference', capsule =>
+            html.tags([
+              relations.contentHeading.clone()
+                .slots({
+                  attributes: {id: 'referenced-by'},
 
-        additionalNames: relations.additionalNamesBox,
+                  title:
+                    language.$(capsule, {
+                      track: html.tag('i', data.name),
+                    }),
 
-        color: data.color,
-        styleRules: [relations.albumStyleRules],
+                  stickyTitle:
+                    language.$(capsule, 'sticky'),
+                }),
 
-        cover:
-          (relations.cover
-            ? relations.cover.slots({
-                alt: language.$('misc.alt.trackCover'),
-              })
-            : null),
+              relations.referencedByTracksList
+                .slots({
+                  headingString: capsule,
+                }),
+            ])),
 
-        mainContent: [
-          relations.releaseInfo,
+          language.encapsulate('releaseInfo.tracksThatSample', capsule =>
+            html.tags([
+              relations.contentHeading.clone()
+                .slots({
+                  attributes: {id: 'sampled-by'},
 
-          html.tag('p',
-            {[html.onlyIfContent]: true},
-            {[html.joinChildren]: html.tag('br')},
+                  title:
+                    language.$(capsule, {
+                      track: html.tag('i', data.name),
+                    }),
 
-            [
-              sec.sheetMusicFiles &&
-                language.$('releaseInfo.sheetMusicFiles.shortcut', {
-                  link: html.tag('a',
-                    {href: '#sheet-music-files'},
-                    language.$('releaseInfo.sheetMusicFiles.shortcut.link')),
+                  stickyTitle:
+                    language.$(capsule, 'sticky'),
                 }),
 
-              sec.midiProjectFiles &&
-                language.$('releaseInfo.midiProjectFiles.shortcut', {
-                  link: html.tag('a',
-                    {href: '#midi-project-files'},
-                    language.$('releaseInfo.midiProjectFiles.shortcut.link')),
+              relations.sampledByTracksList
+                .slots({
+                  headingString: capsule,
                 }),
+            ])),
 
-              sec.additionalFiles &&
-                sec.extra.additionalFilesShortcut,
+          html.tags([
+            language.encapsulate('releaseInfo.flashesThatFeature', capsule =>
+              relations.contentHeading.clone()
+                .slots({
+                  attributes: {id: 'featured-in'},
 
-              sec.artistCommentary &&
-                language.$('releaseInfo.readCommentary', {
-                  link: html.tag('a',
-                    {href: '#artist-commentary'},
-                    language.$('releaseInfo.readCommentary.link')),
-                }),
-            ]),
-
-          sec.otherReleases && [
-            sec.otherReleases.heading
-              .slots({
-                id: 'also-released-as',
-                title: language.$('releaseInfo.alsoReleasedAs'),
-              }),
+                  title:
+                    language.$(capsule, {
+                      track: html.tag('i', data.name),
+                    }),
 
-            html.tag('ul',
-              stitchArrays({
-                trackLink: sec.otherReleases.trackLinks,
-                albumLink: sec.otherReleases.albumLinks,
-                datetimestamp: sec.otherReleases.datetimestamps,
-                colorStyle: sec.otherReleases.colorStyles,
-              }).map(({
-                  trackLink,
-                  albumLink,
-                  datetimestamp,
-                  colorStyle,
-                }) => {
-                  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',
-                      colorStyle,
-                      language.$(...parts, options)));
+                  stickyTitle:
+                    language.$(capsule, 'sticky'),
                 })),
-          ],
 
-          sec.contributors && [
-            sec.contributors.heading
-              .slots({
-                id: 'contributors',
-                title: language.$('releaseInfo.contributors'),
-              }),
+            relations.flashesThatFeatureList,
+          ]),
 
-            sec.contributors.list,
-          ],
+          relations.lyricsSection,
 
-          sec.references && [
-            sec.references.heading
+          html.tags([
+            relations.contentHeading.clone()
               .slots({
-                id: 'references',
-                title:
-                  language.$('releaseInfo.tracksReferenced', {
-                    track: html.tag('i', data.name),
-                  }),
-              }),
-
-            sec.references.list,
-          ],
-
-          sec.samples && [
-            sec.samples.heading
-              .slots({
-                id: 'samples',
-                title:
-                  language.$('releaseInfo.tracksSampled', {
-                    track: html.tag('i', data.name),
-                  }),
-              }),
-
-            sec.samples.list,
-          ],
-
-          sec.referencedBy && [
-            sec.referencedBy.heading
-              .slots({
-                id: 'referenced-by',
-                title:
-                  language.$('releaseInfo.tracksThatReference', {
-                    track: html.tag('i', data.name),
-                  }),
+                attributes: {id: 'sheet-music-files'},
+                title: language.$('releaseInfo.sheetMusicFiles.heading'),
               }),
 
-            sec.referencedBy.list,
-          ],
+            relations.sheetMusicFilesList,
+          ]),
 
-          sec.sampledBy && [
-            sec.sampledBy.heading
+          html.tags([
+            relations.contentHeading.clone()
               .slots({
-                id: 'referenced-by',
-                title:
-                  language.$('releaseInfo.tracksThatSample', {
-                    track: html.tag('i', data.name),
-                  }),
+                attributes: {id: 'midi-project-files'},
+                title: language.$('releaseInfo.midiProjectFiles.heading'),
               }),
 
-            sec.sampledBy.list,
-          ],
+            relations.midiProjectFilesList,
+          ]),
 
-          sec.flashesThatFeature && [
-            sec.flashesThatFeature.heading
+          html.tags([
+            relations.contentHeading.clone()
               .slots({
-                id: 'featured-in',
-                title:
-                  language.$('releaseInfo.flashesThatFeature', {
-                    track: html.tag('i', data.name),
-                  }),
+                attributes: {id: 'additional-files'},
+                title: language.$('releaseInfo.additionalFiles.heading'),
               }),
 
-            html.tag('ul', sec.flashesThatFeature.entries.map(({flashLink, trackLink}) =>
-              (trackLink
-                ? html.tag('li', {class: 'rerelease'},
-                    language.$('releaseInfo.flashesThatFeature.item.asDifferentRelease', {
-                      flash: flashLink,
-                      track: trackLink,
-                    }))
-                : html.tag('li',
-                    language.$('releaseInfo.flashesThatFeature.item', {
-                      flash: flashLink,
-                    }))))),
-          ],
-
-          sec.lyrics && [
-            sec.lyrics.heading
-              .slots({
-                id: 'lyrics',
-                title: language.$('releaseInfo.lyrics'),
-              }),
+            relations.additionalFilesList,
+          ]),
 
-            html.tag('blockquote',
-              sec.lyrics.content
-                .slot('mode', 'lyrics')),
-          ],
+          relations.artistCommentarySection,
 
-          sec.sheetMusicFiles && [
-            sec.sheetMusicFiles.heading
+          html.tags([
+            relations.contentContentHeading.clone()
               .slots({
-                id: 'sheet-music-files',
-                title: language.$('releaseInfo.sheetMusicFiles.heading'),
+                attributes: {id: 'crediting-sources'},
+                string: 'misc.creditingSources',
               }),
 
-            sec.sheetMusicFiles.list,
-          ],
+            relations.creditingSourceEntries,
+          ]),
 
-          sec.midiProjectFiles && [
-            sec.midiProjectFiles.heading
+          html.tags([
+            relations.contentContentHeading.clone()
               .slots({
-                id: 'midi-project-files',
-                title: language.$('releaseInfo.midiProjectFiles.heading'),
+                attributes: {id: 'referencing-sources'},
+                string: 'misc.referencingSources',
               }),
 
-            sec.midiProjectFiles.list,
-          ],
-
-          sec.additionalFiles && [
-            sec.additionalFiles.heading
-              .slots({
-                id: 'additional-files',
-                title:
-                  language.$('releaseInfo.additionalFiles.heading', {
-                    additionalFiles:
-                      language.countAdditionalFiles(data.numAdditionalFiles, {unit: true}),
-                  }),
-              }),
-
-            sec.additionalFiles.list,
-          ],
-
-          sec.artistCommentary,
+            relations.referencingSourceEntries,
+          ]),
         ],
 
         navLinkStyle: 'hierarchical',
-        navLinks: [
-          {auto: 'home'},
-          {html: relations.albumLink.slot('color', false)},
-          {
-            html:
-              (data.hasTrackNumbers
-                ? language.$('trackPage.nav.track.withNumber', {
-                    number: data.trackNumber,
-                    track: relations.trackLink
-                      .slot('attributes', {class: 'current'}),
-                  })
-                : language.$('trackPage.nav.track', {
-                    track: relations.trackLink
-                      .slot('attributes', {class: 'current'}),
-                  })),
-          },
-        ],
+        navLinks:
+          (data.singleTrackSingle
+            ? [
+                {auto: 'home'},
+                {
+                  html: relations.albumNavLink,
+                  accent:
+                    relations.albumNavAccent.slots({
+                      showTrackNavigation: false,
+                      showExtraLinks: true,
+                    }),
+                },
+              ]
+            : html.resolve(relations.navLinks)),
 
         navBottomRowContent:
-          relations.albumNavAccent.slots({
-            showTrackNavigation: true,
-            showExtraLinks: false,
-          }),
-
-        navContent:
-          relations.chronologyLinks.slots({
-            chronologyInfoSets: [
-              {
-                headingString: 'misc.chronology.heading.track',
-                contributions: relations.artistChronologyContributions,
-              },
-              {
-                headingString: 'misc.chronology.heading.coverArt',
-                contributions: relations.coverArtistChronologyContributions,
-              },
-            ],
-          }),
+          (data.singleTrackSingle
+            ? null
+            : relations.albumNavAccent.slots({
+                showTrackNavigation: true,
+                showExtraLinks: false,
+              })),
 
         secondaryNav:
           relations.secondaryNav
-            .slot('mode', 'track'),
+            .slot('mode', data.singleTrackSingle ? 'album' : 'track'),
 
         leftSidebar: relations.sidebar,
 
         socialEmbed: relations.socialEmbed,
-      });
-  },
+      })),
 };
 
 /*