« get me outta code hell

data, content: singles - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2025-07-02 17:43:34 -0300
committer(quasar) nebula <qznebula@protonmail.com>2025-07-02 17:43:34 -0300
commit112a840bdf69bfba5aae893e92b0b20c4a4884fd (patch)
treef82c3244a2f743d69e45556138b4ecd06b5369af /src
parentda8d9d616eb4d002126a89e6cba7f26053c6e4c3 (diff)
data, content: singles
Diffstat (limited to 'src')
-rw-r--r--src/content/dependencies/generateAlbumSidebar.js15
-rw-r--r--src/content/dependencies/generateAlbumSidebarTrackListBox.js10
-rw-r--r--src/content/dependencies/generateAlbumSidebarTrackSection.js23
-rw-r--r--src/content/dependencies/generateTrackInfoPage.js30
-rw-r--r--src/content/dependencies/linkAlbum.js10
-rw-r--r--src/data/things/album.js25
-rw-r--r--src/page/album.js25
7 files changed, 105 insertions, 33 deletions
diff --git a/src/content/dependencies/generateAlbumSidebar.js b/src/content/dependencies/generateAlbumSidebar.js
index 7cf689cc..464274e3 100644
--- a/src/content/dependencies/generateAlbumSidebar.js
+++ b/src/content/dependencies/generateAlbumSidebar.js
@@ -108,24 +108,29 @@ export default {
         : null),
   }),
 
-  data: (_query, _sprawl, _album, track) => ({
+  data: (_query, _sprawl, album, track) => ({
     isAlbumPage: !track,
     isTrackPage: !!track,
+
+    albumStyle: album.style,
   }),
 
   generate(data, relations, {html}) {
+    const presentGroupsLikeAlbum =
+      data.isAlbumPage ||
+      data.albumStyle === 'single';
+
     for (const box of [
       ...relations.groupBoxes,
       ...relations.seriesBoxes.flat(),
       ...relations.disconnectedSeriesBoxes,
     ]) {
-      box.setSlot('mode',
-        data.isAlbumPage ? 'album' : 'track');
+      box.setSlot('mode', presentGroupsLikeAlbum ? 'album' : 'track');
     }
 
     return relations.sidebar.slots({
       boxes: [
-        data.isAlbumPage && [
+        presentGroupsLikeAlbum && [
           relations.disconnectedSeriesBoxes,
 
           stitchArrays({
@@ -150,7 +155,7 @@ export default {
         data.isTrackPage &&
           relations.laterTrackReleaseBoxes,
 
-        data.isTrackPage &&
+        !presentGroupsLikeAlbum &&
           relations.conjoinedBox.slots({
             attributes: {class: 'conjoined-group-sidebar-box'},
             boxes:
diff --git a/src/content/dependencies/generateAlbumSidebarTrackListBox.js b/src/content/dependencies/generateAlbumSidebarTrackListBox.js
index 3a244e3a..36d1e6b6 100644
--- a/src/content/dependencies/generateAlbumSidebarTrackListBox.js
+++ b/src/content/dependencies/generateAlbumSidebarTrackListBox.js
@@ -19,12 +19,18 @@ export default {
         relation('generateAlbumSidebarTrackSection', album, track, trackSection)),
   }),
 
-  generate: (relations, {html}) =>
+  data: (album) => ({
+    albumStyle: album.style,
+  }),
+
+  generate: (data, relations, {html}) =>
     relations.box.slots({
       attributes: {class: 'track-list-sidebar-box'},
 
       content: [
-        html.tag('h1', relations.albumLink),
+        html.tag('h1', {[html.onlyIfSiblings]: true},
+          relations.albumLink),
+
         relations.trackSections,
       ],
     })
diff --git a/src/content/dependencies/generateAlbumSidebarTrackSection.js b/src/content/dependencies/generateAlbumSidebarTrackSection.js
index dae5fa03..a158d2d4 100644
--- a/src/content/dependencies/generateAlbumSidebarTrackSection.js
+++ b/src/content/dependencies/generateAlbumSidebarTrackSection.js
@@ -22,10 +22,12 @@ export default {
       !empty(trackSection.tracks);
 
     data.isTrackPage = !!track;
+    data.albumStyle = album.style;
 
     data.name = trackSection.name;
     data.color = trackSection.color;
     data.isDefaultTrackSection = trackSection.isDefaultTrackSection;
+    data.hasSiblingSections = album.trackSections.length > 1;
 
     data.firstTrackNumber =
       (data.hasTrackNumbers
@@ -115,6 +117,21 @@ export default {
                   : trackLink),
             })));
 
+    const list =
+      (data.hasTrackNumbers
+        ? html.tag('ol',
+            {start: data.firstTrackNumber},
+            trackListItems)
+        : html.tag('ul', trackListItems));
+
+    if (data.albumStyle === 'single' && !data.hasSiblingSections) {
+      if (trackListItems.length <= 1) {
+        return html.blank();
+      } else {
+        return list;
+      }
+    }
+
     return html.tag('details',
       data.includesCurrentTrack &&
         {class: 'current'},
@@ -157,11 +174,7 @@ export default {
                 return language.$(workingCapsule, workingOptions);
               })))),
 
-        (data.hasTrackNumbers
-          ? html.tag('ol',
-              {start: data.firstTrackNumber},
-              trackListItems)
-          : html.tag('ul', trackListItems)),
+        list,
       ]);
   },
 };
diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js
index 6c16ce27..1a5f84be 100644
--- a/src/content/dependencies/generateTrackInfoPage.js
+++ b/src/content/dependencies/generateTrackInfoPage.js
@@ -48,6 +48,9 @@ export default {
     navLinks:
       relation('generateTrackNavLinks', track),
 
+    albumNavLink:
+      relation('linkAlbum', track.album),
+
     albumNavAccent:
       relation('generateAlbumNavAccent', track.album, track),
 
@@ -125,6 +128,10 @@ export default {
 
     color:
       track.color,
+
+    singleTrackSingle:
+      track.album.style === 'single' &&
+      track.album.tracks.length === 1,
   }),
 
   generate: (data, relations, {html, language}) =>
@@ -376,17 +383,28 @@ export default {
         ],
 
         navLinkStyle: 'hierarchical',
-        navLinks: html.resolve(relations.navLinks),
+        navLinks:
+          (data.singleTrackSingle
+            ? [
+                {auto: 'home'},
+                {html: relations.albumNavLink},
+              ]
+            : html.resolve(relations.navLinks)),
 
         navBottomRowContent:
-          relations.albumNavAccent.slots({
-            showTrackNavigation: true,
-            showExtraLinks: false,
-          }),
+          (data.singleTrackSingle
+            ? relations.albumNavAccent.slots({
+                showTrackNavigation: false,
+                showExtraLinks: true,
+              })
+            : relations.albumNavAccent.slots({
+                showTrackNavigation: true,
+                showExtraLinks: false,
+              })),
 
         secondaryNav:
           relations.secondaryNav
-            .slot('mode', 'track'),
+            .slot('mode', data.singleTrackSingle ? 'album' : 'track'),
 
         leftSidebar: relations.sidebar,
 
diff --git a/src/content/dependencies/linkAlbum.js b/src/content/dependencies/linkAlbum.js
index 36b0d13a..cdfe65d3 100644
--- a/src/content/dependencies/linkAlbum.js
+++ b/src/content/dependencies/linkAlbum.js
@@ -1,8 +1,12 @@
 export default {
-  contentDependencies: ['linkThing'],
+  contentDependencies: ['linkThing', 'linkTrack'],
 
-  relations: (relation, album) =>
-    ({link: relation('linkThing', 'localized.album', album)}),
+  relations: (relation, album) => ({
+    link:
+      (album.style === 'single'
+        ? relation('linkTrack', album.tracks[0])
+        : relation('linkThing', 'localized.album', album)),
+  }),
 
   generate: (relations) => relations.link,
 };
diff --git a/src/data/things/album.js b/src/data/things/album.js
index 51698148..a922e565 100644
--- a/src/data/things/album.js
+++ b/src/data/things/album.js
@@ -10,7 +10,7 @@ import {traverse} from '#node-utils';
 import {sortAlbumsTracksChronologically, sortChronologically} from '#sort';
 import {empty} from '#sugar';
 import Thing from '#thing';
-import {isColor, isDate, isDirectory, isNumber} from '#validators';
+import {is, isColor, isDate, isDirectory, isNumber} from '#validators';
 
 import {
   parseAdditionalFiles,
@@ -25,13 +25,18 @@ import {
   parseWallpaperParts,
 } from '#yaml';
 
-import {exitWithoutDependency, exposeDependency, exposeUpdateValueOrContinue}
-  from '#composite/control-flow';
 import {withPropertyFromObject} from '#composite/data';
 import {exitWithoutArtwork, withDirectory, withHasArtwork}
   from '#composite/wiki-data';
 
 import {
+  exitWithoutDependency,
+  exposeConstant,
+  exposeDependency,
+  exposeUpdateValueOrContinue,
+} from '#composite/control-flow';
+
+import {
   color,
   commentatorArtists,
   constitutibleArtwork,
@@ -102,6 +107,19 @@ export class Album extends Thing {
     alwaysReferenceTracksByDirectory: flag(false),
     suffixTrackDirectories: flag(false),
 
+    style: [
+      exposeUpdateValueOrContinue({
+        validate: input.value(is(...[
+          'album',
+          'single',
+        ])),
+      }),
+
+      exposeConstant({
+        value: input.value('album'),
+      }),
+    ],
+
     bandcampAlbumIdentifier: simpleString(),
     bandcampArtworkIdentifier: simpleString(),
 
@@ -541,6 +559,7 @@ export class Album extends Thing {
       'Suffix Track Directories': {property: 'suffixTrackDirectories'},
       'Always Reference By Directory': {property: 'alwaysReferenceByDirectory'},
       'Always Reference Tracks By Directory': {property: 'alwaysReferenceTracksByDirectory'},
+      'Style': {property: 'style'},
 
       'Bandcamp Album ID': {
         property: 'bandcampAlbumIdentifier',
diff --git a/src/page/album.js b/src/page/album.js
index 696e2854..e585618c 100644
--- a/src/page/album.js
+++ b/src/page/album.js
@@ -8,15 +8,22 @@ export function targets({wikiData}) {
 
 export function pathsForTarget(album) {
   return [
-    {
-      type: 'page',
-      path: ['album', album.directory],
-
-      contentFunction: {
-        name: 'generateAlbumInfoPage',
-        args: [album],
-      },
-    },
+    (album.style === 'single'
+      ? {
+          type: 'redirect',
+          fromPath: ['album', album.directory],
+          toPath: ['track', album.tracks[0].directory],
+          title: album.name,
+        }
+      : {
+          type: 'page',
+          path: ['album', album.directory],
+
+          contentFunction: {
+            name: 'generateAlbumInfoPage',
+            args: [album],
+          },
+        }),
 
     {
       type: 'page',