« 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/generatePageLayout.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/content/dependencies/generatePageLayout.js')
-rw-r--r--src/content/dependencies/generatePageLayout.js193
1 files changed, 126 insertions, 67 deletions
diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js
index a45f7415..23d5932d 100644
--- a/src/content/dependencies/generatePageLayout.js
+++ b/src/content/dependencies/generatePageLayout.js
@@ -1,27 +1,9 @@
+import striptags from 'striptags';
+
 import {openAggregate} from '#aggregate';
-import {empty, repeat} from '#sugar';
+import {atOffset, empty, repeat} from '#sugar';
 
 export default {
-  contentDependencies: [
-    'generateColorStyleRules',
-    'generateFooterLocalizationLinks',
-    'generateImageOverlay',
-    'generatePageSidebar',
-    'generateSearchSidebarBox',
-    'generateStickyHeadingContainer',
-    'transformContent',
-  ],
-
-  extraDependencies: [
-    'getColors',
-    'html',
-    'language',
-    'pagePath',
-    'pagePathStringFromRoot',
-    'to',
-    'wikiData',
-  ],
-
   sprawl: ({wikiInfo}) => ({
     enableSearch: wikiInfo.enableSearch,
     footerContent: wikiInfo.footerContent,
@@ -58,8 +40,14 @@ export default {
         relation('transformContent', sprawl.footerContent);
     }
 
-    relations.colorStyleRules =
-      relation('generateColorStyleRules');
+    relations.colorStyleTag =
+      relation('generateColorStyleTag');
+
+    relations.staticURLStyleTag =
+      relation('generateStaticURLStyleTag');
+
+    relations.wikiWallpaperStyleTag =
+      relation('generateWikiWallpaperStyleTag');
 
     relations.imageOverlay =
       relation('generateImageOverlay');
@@ -93,7 +81,7 @@ export default {
       mutable: false,
     },
 
-    cover: {
+    artworkColumnContent: {
       type: 'html',
       mutable: false,
     },
@@ -107,9 +95,9 @@ export default {
 
     color: {validate: v => v.isColor},
 
-    styleRules: {
-      validate: v => v.sparseArrayOf(v.isHTML),
-      default: [],
+    styleTags: {
+      type: 'html',
+      mutable: false,
     },
 
     mainClasses: {
@@ -262,24 +250,58 @@ export default {
         ? data.canonicalBase + pagePathStringFromRoot
         : null);
 
+    const primaryCover = (() => {
+      const apparentFirst = tag => html.smooth(tag).content[0];
+
+      const maybeTemplate =
+        apparentFirst(slots.artworkColumnContent);
+
+      if (!maybeTemplate) return null;
+
+      const maybeTemplateContent =
+        html.resolve(maybeTemplate, {normalize: 'tag'});
+
+      const maybeCoverArtwork =
+        apparentFirst(maybeTemplateContent);
+
+      if (!maybeCoverArtwork) return null;
+
+      if (maybeCoverArtwork.attributes.has('class', 'cover-artwork')) {
+        return maybeTemplate;
+      } else {
+        return null;
+      }
+    })();
+
     const titleContentsHTML =
       (html.isBlank(slots.title)
         ? null
-     : html.isBlank(slots.additionalNames)
-        ? language.sanitize(slots.title)
-        : html.tag('a', {
+
+     : (!html.isBlank(slots.additionalNames) &&
+        !html.resolve(slots.additionalNames, {slots: ['alwaysVisible']})
+          .getSlotValue('alwaysVisible'))
+
+        ? html.tag('a', {
             href: '#additional-names-box',
             title: language.$('misc.additionalNames.tooltip').toString(),
-          }, language.sanitize(slots.title)));
+          }, language.sanitize(slots.title))
+
+        : language.sanitize(slots.title));
 
     const titleHTML =
       (html.isBlank(slots.title)
         ? null
      : slots.headingMode === 'sticky'
-        ? relations.stickyHeadingContainer.slots({
-            title: titleContentsHTML,
-            cover: slots.cover,
-          })
+        ? [
+            relations.stickyHeadingContainer.slots({
+              title: titleContentsHTML,
+              cover: primaryCover,
+            }),
+
+            relations.stickyHeadingContainer.clone().slots({
+              rootAttributes: {inert: true},
+            }),
+          ]
         : html.tag('h1', titleContentsHTML));
 
     // TODO: There could be neat interactions with the sticky heading here,
@@ -310,9 +332,11 @@ export default {
         [
           titleHTML,
 
-          html.tag('div', {id: 'cover-art-container'},
+          html.tag('div', {id: 'artwork-column'},
             {[html.onlyIfContent]: true},
-            slots.cover),
+            {class: 'isolate-tooltip-z-indexing'},
+
+            slots.artworkColumnContent),
 
           subtitleHTML,
 
@@ -355,7 +379,7 @@ export default {
 
             slots.navLinks
               ?.filter(Boolean)
-              ?.map((cur, i) => {
+              ?.map((cur, i, entries) => {
                 let content;
 
                 if (cur.html) {
@@ -389,20 +413,13 @@ export default {
                   (slots.navLinkStyle === 'hierarchical' &&
                     i === slots.navLinks.length - 1);
 
-                return (
+                const navLink =
                   html.tag('span', {class: 'nav-link'},
                     showAsCurrent &&
                       {class: 'current'},
 
                     [
                       html.tag('span', {class: 'nav-link-content'},
-                        // Use inline-block styling on the content span,
-                        // rather than wrapping the whole nav-link in a proper
-                        // blockwrap, so that if the content spans multiple
-                        // lines, it'll kick the accent down beneath it.
-                        i > 0 &&
-                          {class: 'blockwrap'},
-
                         content),
 
                       html.tag('span', {class: 'nav-link-accent'},
@@ -413,7 +430,25 @@ export default {
                           [language.onlyIfOptions]: ['links'],
                           links: cur.accent,
                         })),
-                    ]));
+                    ]);
+
+                if (slots.navLinkStyle === 'index') {
+                  return navLink;
+                }
+
+                const prev =
+                  atOffset(entries, i, -1);
+
+                if (
+                  prev &&
+                  prev.releaseRestToWrapTogether !== true &&
+                  (prev.releaseRestToWrapTogether === false ||
+                   prev.auto === 'home')
+                ) {
+                  return navLink;
+                } else {
+                  return html.metatag('blockwrap', navLink);
+                }
               })),
 
           html.tag('div', {class: 'nav-bottom-row'},
@@ -539,24 +574,33 @@ export default {
               {id: 'additional-files', string: 'additionalFiles'},
               {id: 'commentary', string: 'commentary'},
               {id: 'artist-commentary', string: 'artistCommentary'},
-              {id: 'credit-sources', string: 'creditSources'},
+              {id: 'crediting-sources', string: 'creditingSources'},
+              {id: 'referencing-sources', string: 'referencingSources'},
             ])),
         ]);
 
-    const styleRulesCSS =
-      html.resolve(slots.styleRules, {normalize: 'string'});
+    const slottedStyleTags =
+      html.smush(slots.styleTags);
+
+    const slottedWallpaperStyleTag =
+      slottedStyleTags.content
+        .find(tag => tag.attributes.has('class', 'wallpaper-style'));
 
-    const fallbackBackgroundStyleRule =
-      (styleRulesCSS.match(/body::before[^}]*background-image:/)
-        ? ''
-        : `body::before {\n` +
-          `    background-image: url("${to('media.path', 'bg.jpg')}");\n` +
-          `}`);
+    const fallbackWallpaperStyleTag =
+      (slottedWallpaperStyleTag
+        ? html.blank()
+        : relations.wikiWallpaperStyleTag);
+
+    const usingWallpaperStyleTag =
+      (slottedWallpaperStyleTag
+        ? slottedWallpaperStyleTag
+        : html.resolve(fallbackWallpaperStyleTag, {normalize: 'tag'}));
 
     const numWallpaperParts =
-      html.resolve(slots.styleRules, {normalize: 'string'})
-        .match(/\.wallpaper-part:nth-child/g)
-        ?.length ?? 0;
+      (usingWallpaperStyleTag &&
+       usingWallpaperStyleTag.attributes.has('data-wallpaper-mode', 'parts')
+        ? parseInt(usingWallpaperStyleTag.attributes.get('data-num-wallpaper-parts'))
+        : 0);
 
     const wallpaperPartsHTML =
       html.tag('div', {class: 'wallpaper-parts'},
@@ -612,11 +656,25 @@ export default {
               language.encapsulate('misc.pageTitle', workingCapsule => {
                 const workingOptions = {};
 
-                workingOptions.title = slots.title;
+                // Slightly jank: The output of striptags is, of course, a string,
+                // and as far as language.formatString() is concerned, that means
+                // it needs to be sanitized - including turning ampersands into
+                // &'s. But the title is already HTML that has implicitly been
+                // sanitized, however it got here, and includes HTML entities that
+                // are properly escaped. Those need to get included as they are,
+                // so we wrap the title in a tag and pass it off as good to go.
+                workingOptions.title =
+                  html.tags([
+                    striptags(slots.title.toString()),
+                  ]);
 
                 if (!html.isBlank(slots.subtitle)) {
+                  // Same shenanigans here, as far as wrapping striptags goes.
                   workingCapsule += '.withSubtitle';
-                  workingOptions.subtitle = slots.subtitle;
+                  workingOptions.subtitle =
+                    html.tags([
+                      striptags(slots.subtitle.toString()),
+                    ]);
                 }
 
                 const showWikiName =
@@ -698,13 +756,14 @@ export default {
               href: to('staticCSS.path', 'site.css'),
             }),
 
-            html.tag('style', [
-              relations.colorStyleRules
-                .slot('color', slots.color ?? data.wikiColor),
+            relations.colorStyleTag
+              .slot('color', slots.color ?? data.wikiColor),
 
-              fallbackBackgroundStyleRule,
-              slots.styleRules,
-            ]),
+            relations.staticURLStyleTag,
+
+            fallbackWallpaperStyleTag,
+
+            slottedStyleTags,
 
             html.tag('script', {
               src: to('staticLib.path', 'chroma-js/chroma.min.js'),