« 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
diff options
context:
space:
mode:
Diffstat (limited to 'src/content')
-rw-r--r--src/content/dependencies/generateAlbumReleaseInfo.js6
-rw-r--r--src/content/dependencies/generateAlbumSidebarGroupBox.js5
-rw-r--r--src/content/dependencies/generateArtistInfoPage.js8
-rw-r--r--src/content/dependencies/generateContributionList.js1
-rw-r--r--src/content/dependencies/generateFlashInfoPage.js2
-rw-r--r--src/content/dependencies/generateGroupInfoPage.js5
-rw-r--r--src/content/dependencies/generateReleaseInfoContributionsLine.js1
-rw-r--r--src/content/dependencies/generateTrackReleaseInfo.js5
-rw-r--r--src/content/dependencies/linkContribution.js92
-rw-r--r--src/content/dependencies/linkExternal.js148
-rw-r--r--src/content/dependencies/linkExternalAsIcon.js71
-rw-r--r--src/content/dependencies/linkExternalFlash.js41
12 files changed, 145 insertions, 240 deletions
diff --git a/src/content/dependencies/generateAlbumReleaseInfo.js b/src/content/dependencies/generateAlbumReleaseInfo.js
index d6405283..dd5baab9 100644
--- a/src/content/dependencies/generateAlbumReleaseInfo.js
+++ b/src/content/dependencies/generateAlbumReleaseInfo.js
@@ -94,7 +94,11 @@ export default {
             links:
               language.formatDisjunctionList(
                 relations.externalLinks
-                  .map(link => link.slot('mode', 'album'))),
+                  .map(link =>
+                    link.slots({
+                      context: 'album',
+                      style: 'normal',
+                    }))),
           })),
     ]);
   },
diff --git a/src/content/dependencies/generateAlbumSidebarGroupBox.js b/src/content/dependencies/generateAlbumSidebarGroupBox.js
index 331ddaba..f3705450 100644
--- a/src/content/dependencies/generateAlbumSidebarGroupBox.js
+++ b/src/content/dependencies/generateAlbumSidebarGroupBox.js
@@ -66,7 +66,10 @@ export default {
       !empty(relations.externalLinks) &&
         html.tag('p',
           language.$('releaseInfo.visitOn', {
-            links: language.formatDisjunctionList(relations.externalLinks),
+            links:
+              language.formatDisjunctionList(
+                relations.externalLinks
+                  .map(link => link.slot('context', 'group'))),
           })),
 
       slots.mode === 'album' &&
diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js
index 03bc0af5..be9f9b86 100644
--- a/src/content/dependencies/generateArtistInfoPage.js
+++ b/src/content/dependencies/generateArtistInfoPage.js
@@ -161,7 +161,13 @@ export default {
           sec.visit &&
             html.tag('p',
               language.$('releaseInfo.visitOn', {
-                links: language.formatDisjunctionList(sec.visit.externalLinks),
+                links:
+                  language.formatDisjunctionList(
+                    sec.visit.externalLinks.map(link =>
+                      link.slots({
+                        context: 'artist',
+                        mode: 'platform',
+                      }))),
               })),
 
           sec.artworks?.artistGalleryLink &&
diff --git a/src/content/dependencies/generateContributionList.js b/src/content/dependencies/generateContributionList.js
index 731cfba5..6401e65e 100644
--- a/src/content/dependencies/generateContributionList.js
+++ b/src/content/dependencies/generateContributionList.js
@@ -16,5 +16,6 @@ export default {
               showIcons: true,
               showContribution: true,
               preventWrapping: false,
+              iconMode: 'tooltip',
             })))),
 };
diff --git a/src/content/dependencies/generateFlashInfoPage.js b/src/content/dependencies/generateFlashInfoPage.js
index 09c6b37c..c60f9696 100644
--- a/src/content/dependencies/generateFlashInfoPage.js
+++ b/src/content/dependencies/generateFlashInfoPage.js
@@ -133,7 +133,7 @@ export default {
               links:
                 language.formatDisjunctionList(
                   relations.externalLinks
-                    .map(link => link.slot('mode', 'flash'))),
+                    .map(link => link.slot('context', 'flash'))),
             })),
 
         sec.featuredTracks && [
diff --git a/src/content/dependencies/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js
index 0583755e..05df33fb 100644
--- a/src/content/dependencies/generateGroupInfoPage.js
+++ b/src/content/dependencies/generateGroupInfoPage.js
@@ -107,7 +107,10 @@ export default {
           sec.info.visitLinks &&
             html.tag('p',
               language.$('releaseInfo.visitOn', {
-                links: language.formatDisjunctionList(sec.info.visitLinks),
+                links:
+                  language.formatDisjunctionList(
+                    sec.info.visitLinks
+                      .map(link => link.slot('context', 'group'))),
               })),
 
           html.tag('blockquote',
diff --git a/src/content/dependencies/generateReleaseInfoContributionsLine.js b/src/content/dependencies/generateReleaseInfoContributionsLine.js
index 1fa8dcca..2e6c4709 100644
--- a/src/content/dependencies/generateReleaseInfoContributionsLine.js
+++ b/src/content/dependencies/generateReleaseInfoContributionsLine.js
@@ -35,6 +35,7 @@ export default {
             link.slots({
               showContribution: slots.showContribution,
               showIcons: slots.showIcons,
+              iconMode: 'tooltip',
             }))),
     });
   },
diff --git a/src/content/dependencies/generateTrackReleaseInfo.js b/src/content/dependencies/generateTrackReleaseInfo.js
index 9a7478ca..c347dbce 100644
--- a/src/content/dependencies/generateTrackReleaseInfo.js
+++ b/src/content/dependencies/generateTrackReleaseInfo.js
@@ -77,7 +77,10 @@ export default {
       html.tag('p',
         (relations.externalLinks
           ? language.$('releaseInfo.listenOn', {
-              links: language.formatDisjunctionList(relations.externalLinks),
+              links:
+                language.formatDisjunctionList(
+                  relations.externalLinks
+                    .map(link => link.slot('context', 'track'))),
             })
           : language.$('releaseInfo.listenOn.noLinks', {
               name: html.tag('i', data.name),
diff --git a/src/content/dependencies/linkContribution.js b/src/content/dependencies/linkContribution.js
index 8e42f247..790afa4f 100644
--- a/src/content/dependencies/linkContribution.js
+++ b/src/content/dependencies/linkContribution.js
@@ -1,15 +1,8 @@
 import {empty} from '#sugar';
 
 export default {
-  contentDependencies: [
-    'linkArtist',
-    'linkExternalAsIcon',
-  ],
-
-  extraDependencies: [
-    'html',
-    'language',
-  ],
+  contentDependencies: ['linkArtist', 'linkExternalAsIcon'],
+  extraDependencies: ['html', 'language'],
 
   relations(relation, contribution) {
     const relations = {};
@@ -20,7 +13,6 @@ export default {
     if (!empty(contribution.who.urls)) {
       relations.artistIcons =
         contribution.who.urls
-          .slice(0, 4)
           .map(url => relation('linkExternalAsIcon', url));
     }
 
@@ -37,37 +29,81 @@ export default {
     showContribution: {type: 'boolean', default: false},
     showIcons: {type: 'boolean', default: false},
     preventWrapping: {type: 'boolean', default: true},
+
+    iconMode: {
+      validate: v => v.is('inline', 'tooltip'),
+      default: 'inline'
+    },
   },
 
   generate(data, relations, slots, {html, language}) {
-    const hasContributionPart = !!(slots.showContribution && data.what);
-    const hasExternalPart = !!(slots.showIcons && relations.artistIcons);
-
-    const externalLinks = hasExternalPart &&
-      html.tag('span',
-        {[html.noEdgeWhitespace]: true, class: 'icons'},
-        language.formatUnitList(relations.artistIcons));
+    const hasContribution = !!(slots.showContribution && data.what);
+    const hasExternalIcons = !!(slots.showIcons && relations.artistIcons);
 
     const parts = ['misc.artistLink'];
     const options = {artist: relations.artistLink};
 
-    if (hasContributionPart) {
+    if (hasContribution) {
       parts.push('withContribution');
       options.contrib = data.what;
     }
 
-    if (hasExternalPart) {
+    if (hasExternalIcons && slots.iconMode === 'inline') {
       parts.push('withExternalLinks');
-      options.links = externalLinks;
+      options.links =
+        html.tag('span',
+          {
+            [html.noEdgeWhitespace]: true,
+            class: ['icons', 'icons-inline'],
+          },
+          language.formatUnitList(
+            relations.artistIcons
+              .slice(0, 4)
+              .map(icon => icon.slot('context', 'artist'))));
     }
 
-    const content = language.formatString(parts.join('.'), options);
+    let content = language.formatString(parts.join('.'), options);
 
-    return (
-      (parts.length > 1 && slots.preventWrapping
-        ? html.tag('span',
-            {[html.noEdgeWhitespace]: true, class: 'nowrap'},
-            content)
-        : content));
-    },
+    if (hasExternalIcons && slots.iconMode === 'tooltip') {
+      content = [
+        content,
+        html.tag('span',
+          {
+            [html.noEdgeWhitespace]: true,
+            class: ['icons', 'icons-tooltip'],
+            inert: true,
+          },
+          html.tag('span',
+            {
+              [html.noEdgeWhitespace]: true,
+              [html.joinChildren]: '',
+              class: 'icons-tooltip-content',
+            },
+            relations.artistIcons
+              .map(icon => icon.slots({context: 'artist', withText: true})))),
+      ];
+    }
+
+    if (hasContribution || hasExternalIcons) {
+      content =
+        html.tag('span', {
+          [html.noEdgeWhitespace]: true,
+          [html.joinChildren]: '',
+
+          class: [
+            'contribution',
+
+            hasExternalIcons &&
+            slots.iconMode === 'tooltip' &&
+              'has-tooltip',
+
+            parts.length > 1 &&
+            slots.preventWrapping &&
+              'nowrap',
+          ],
+        }, content);
+    }
+
+    return content;
+  }
 };
diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js
index 5de612e2..0a079614 100644
--- a/src/content/dependencies/linkExternal.js
+++ b/src/content/dependencies/linkExternal.js
@@ -1,140 +1,30 @@
-// TODO: Define these as extra dependencies and pass them somewhere
-const BANDCAMP_DOMAINS = ['bc.s3m.us', 'music.solatrux.com'];
-const MASTODON_DOMAINS = ['types.pl'];
+import {isExternalLinkContext, isExternalLinkStyle} from '#external-links';
 
 export default {
   extraDependencies: ['html', 'language', 'wikiData'],
 
-  sprawl: ({wikiInfo}) => ({wikiInfo}),
-
-  data(sprawl, url) {
-    const data = {url};
-
-    const {canonicalBase} = sprawl.wikiInfo;
-    if (canonicalBase) {
-      const {hostname: canonicalDomain} = new URL(canonicalBase);
-      Object.assign(data, {canonicalDomain});
-    }
-
-    return data;
-  },
+  data: (url) => ({url}),
 
   slots: {
-    mode: {
-      validate: v => v.is('generic', 'album', 'flash'),
+    style: {
+      // This awkward syntax is because the slot descriptor validator can't
+      // differentiate between a function that returns a validator (the usual
+      // syntax) and a function that is itself a validator.
+      validate: () => isExternalLinkStyle,
+      default: 'normal',
+    },
+
+    context: {
+      validate: () => isExternalLinkContext,
       default: 'generic',
     },
   },
 
-  generate(data, slots, {html, language}) {
-    let isLocal;
-    let domain;
-    let pathname;
-
-    try {
-      const url = new URL(data.url);
-      domain = url.hostname;
-      pathname = url.pathname;
-    } catch (error) {
-      // No support for relative local URLs yet, sorry! (I.e, local URLs must
-      // be absolute relative to the domain name in order to work.)
-      isLocal = true;
-      domain = null;
-      pathname = null;
-    }
-
-    // isLocal also applies for URLs which match the 'Canonical Base' under
-    // wiki-info.yaml, if present.
-    if (data.canonicalDomain && domain === data.canonicalDomain) {
-      isLocal = true;
-    }
-
-    const link = html.tag('a',
-      {
-        href: data.url,
-        class: 'nowrap',
-      },
-
-      // truly unhinged indentation here
-      isLocal
-        ? language.$('misc.external.local')
-
-    : domain.includes('bandcamp.com')
-        ? language.$('misc.external.bandcamp')
-
-    : BANDCAMP_DOMAINS.includes(domain)
-        ? language.$('misc.external.bandcamp.domain', {domain})
-
-    : MASTODON_DOMAINS.includes(domain)
-        ? language.$('misc.external.mastodon.domain', {domain})
-
-    : domain.includes('youtu')
-        ? slots.mode === 'album'
-          ? data.url.includes('list=')
-            ? language.$('misc.external.youtube.playlist')
-            : language.$('misc.external.youtube.fullAlbum')
-          : language.$('misc.external.youtube')
-
-    : domain.includes('soundcloud')
-        ? language.$('misc.external.soundcloud')
-
-    : domain.includes('tumblr.com')
-        ? language.$('misc.external.tumblr')
-
-    : domain.includes('twitter.com')
-        ? language.$('misc.external.twitter')
-
-    : domain.includes('deviantart.com')
-        ? language.$('misc.external.deviantart')
-
-    : domain.includes('wikipedia.org')
-        ? language.$('misc.external.wikipedia')
-
-    : domain.includes('poetryfoundation.org')
-        ? language.$('misc.external.poetryFoundation')
-
-    : domain.includes('instagram.com')
-        ? language.$('misc.external.instagram')
-
-    : domain.includes('patreon.com')
-        ? language.$('misc.external.patreon')
-
-    : domain.includes('spotify.com')
-        ? language.$('misc.external.spotify')
-
-    : domain.includes('newgrounds.com')
-        ? language.$('misc.external.newgrounds')
-
-        : domain);
-
-    switch (slots.mode) {
-      case 'flash': {
-        const wrap = content =>
-          html.tag('span', {class: 'nowrap'}, content);
-
-        if (domain.includes('homestuck.com')) {
-          const match = pathname.match(/\/story\/(.*)\/?/);
-          if (match) {
-            if (isNaN(Number(match[1]))) {
-              return wrap(language.$('misc.external.flash.homestuck.secret', {link}));
-            } else {
-              return wrap(language.$('misc.external.flash.homestuck.page', {
-                link,
-                page: match[1],
-              }));
-            }
-          }
-        } else if (domain.includes('bgreco.net')) {
-          return wrap(language.$('misc.external.flash.bgreco', {link}));
-        } else if (domain.includes('youtu')) {
-          return wrap(language.$('misc.external.flash.youtube', {link}));
-        }
-
-        return link;
-      }
-
-      default:
-        return link;
-    }
-  }
+  generate: (data, slots, {html, language}) =>
+    html.tag('a',
+      {href: data.url, class: 'nowrap'},
+      language.formatExternalLink(data.url, {
+        style: slots.style,
+        context: slots.context,
+      })),
 };
diff --git a/src/content/dependencies/linkExternalAsIcon.js b/src/content/dependencies/linkExternalAsIcon.js
index cd168992..357c835c 100644
--- a/src/content/dependencies/linkExternalAsIcon.js
+++ b/src/content/dependencies/linkExternalAsIcon.js
@@ -1,46 +1,45 @@
-// TODO: Define these as extra dependencies and pass them somewhere
-const BANDCAMP_DOMAINS = ['bc.s3m.us', 'music.solatrux.com'];
-const MASTODON_DOMAINS = ['types.pl'];
+import {isExternalLinkContext} from '#external-links';
 
 export default {
   extraDependencies: ['html', 'language', 'to'],
 
-  data(url) {
-    return {url};
+  data: (url) => ({url}),
+
+  slots: {
+    context: {
+      // This awkward syntax is because the slot descriptor validator can't
+      // differentiate between a function that returns a validator (the usual
+      // syntax) and a function that is itself a validator.
+      validate: () => isExternalLinkContext,
+      default: 'generic',
+    },
+
+    withText: {type: 'boolean'},
   },
 
-  generate(data, {html, language, to}) {
-    const domain = new URL(data.url).hostname;
-    const [id, msg] = (
-      domain.includes('bandcamp.com')
-        ? ['bandcamp', language.$('misc.external.bandcamp')]
-      : BANDCAMP_DOMAINS.includes(domain)
-        ? ['bandcamp', language.$('misc.external.bandcamp.domain', {domain})]
-      : MASTODON_DOMAINS.includes(domain)
-        ? ['mastodon', language.$('misc.external.mastodon.domain', {domain})]
-      : domain.includes('youtu')
-        ? ['youtube', language.$('misc.external.youtube')]
-      : domain.includes('soundcloud')
-        ? ['soundcloud', language.$('misc.external.soundcloud')]
-      : domain.includes('tumblr.com')
-        ? ['tumblr', language.$('misc.external.tumblr')]
-      : domain.includes('twitter.com')
-        ? ['twitter', language.$('misc.external.twitter')]
-      : domain.includes('deviantart.com')
-        ? ['deviantart', language.$('misc.external.deviantart')]
-      : domain.includes('instagram.com')
-        ? ['instagram', language.$('misc.external.bandcamp')]
-      : domain.includes('newgrounds.com')
-        ? ['newgrounds', language.$('misc.external.newgrounds')]
-        : ['globe', language.$('misc.external.domain', {domain})]);
+  generate(data, slots, {html, language, to}) {
+    const format = style =>
+      language.formatExternalLink(data.url, {style, context: slots.context});
+
+    const normalText = format('normal');
+    const compactText = format('compact');
+    const iconId = format('icon-id');
 
     return html.tag('a',
-      {href: data.url, class: 'icon'},
-      html.tag('svg', [
-        html.tag('title', msg),
-        html.tag('use', {
-          href: to('shared.staticIcon', id),
-        }),
-      ]));
+      {href: data.url, class: ['icon', slots.withText && 'has-text']},
+      [
+        html.tag('svg', [
+          !slots.withText &&
+            html.tag('title', normalText),
+
+          html.tag('use', {
+            href: to('shared.staticIcon', iconId),
+          }),
+        ]),
+
+        slots.withText &&
+          html.tag('span', {class: 'icon-text'},
+            compactText ?? normalText),
+      ]);
   },
 };
diff --git a/src/content/dependencies/linkExternalFlash.js b/src/content/dependencies/linkExternalFlash.js
deleted file mode 100644
index 65158ff8..00000000
--- a/src/content/dependencies/linkExternalFlash.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// Note: This function is seriously hard-coded for HSMusic, with custom
-// presentation of links to Homestuck flashes hosted various places.
-
-export default {
-  contentDependencies: ['linkExternal'],
-  extraDependencies: ['html', 'language'],
-
-  relations(relation, url) {
-    return {
-      link: relation('linkExternal', url),
-    };
-  },
-
-  data(url, flash) {
-    return {
-      url,
-      page: flash.page,
-    };
-  },
-
-  generate(data, relations, {html, language}) {
-    const {link} = relations;
-    const {url, page} = data;
-
-    return html.tag('span',
-      {class: 'nowrap'},
-
-      url.includes('homestuck.com')
-        ? isNaN(Number(page))
-          ? language.$('misc.external.flash.homestuck.secret', {link})
-          : language.$('misc.external.flash.homestuck.page', {link, page})
-
-    : url.includes('bgreco.net')
-        ? language.$('misc.external.flash.bgreco', {link})
-
-    : url.includes('youtu')
-        ? language.$('misc.external.flash.youtube', {link})
-
-        : link);
-  },
-};