« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/static
diff options
context:
space:
mode:
Diffstat (limited to 'src/static')
-rw-r--r--src/static/css/site.css102
-rw-r--r--src/static/js/client-util.js22
-rw-r--r--src/static/js/client/expandable-gallery-section.js77
-rw-r--r--src/static/js/client/expandable-grid-section.js85
-rw-r--r--src/static/js/client/index.js4
-rw-r--r--src/static/js/client/quick-description.js2
-rw-r--r--src/static/js/client/sidebar-search.js56
-rw-r--r--src/static/js/search-worker.js3
8 files changed, 227 insertions, 124 deletions
diff --git a/src/static/css/site.css b/src/static/css/site.css
index 8872bde8..e584f918 100644
--- a/src/static/css/site.css
+++ b/src/static/css/site.css
@@ -918,6 +918,11 @@ summary.underline-white > span:hover a:not(:hover) {
   display: inline-block;
 }
 
+.wiki-search-result-disambiguator {
+  opacity: 0.9;
+  display: inline-block;
+}
+
 .wiki-search-result-image-container {
   align-self: flex-start;
   flex-shrink: 0;
@@ -1232,7 +1237,12 @@ label > input[type=checkbox]:not(:checked) + span {
   white-space: nowrap;
 }
 
-.isolate-tooltip-z-indexing > * {
+:where(.isolate-tooltip-z-indexing) {
+  position: relative;
+  z-index: 1;
+}
+
+:where(.isolate-tooltip-z-indexing > *) {
   position: relative;
   z-index: -1;
 }
@@ -1640,9 +1650,11 @@ hr.cute,
 }
 
 #artwork-column .cover-artwork {
+  --normal-shadow: 0 0 12px 12px #00000080;
+
   box-shadow:
     0 2px 14px -6px var(--primary-color),
-    0 0 12px 12px #00000080;
+    var(--normal-shadow);
 }
 
 #artwork-column .cover-artwork:not(:first-child),
@@ -1651,6 +1663,10 @@ hr.cute,
   margin-right: 5px;
 }
 
+#artwork-column .cover-artwork:not(:first-child) {
+  --normal-shadow: 0 0 9px 9px #00000068;
+}
+
 #artwork-column .cover-artwork:first-child + .cover-artwork-joiner,
 #artwork-column .cover-artwork.attached-artwork-is-main-artwork,
 #artwork-column .cover-artwork.attached-artwork-is-main-artwork + .cover-artwork-joiner {
@@ -1870,11 +1886,11 @@ p.image-details.origin-details .origin-details {
   margin-top: 0.25em;
 }
 
-.lyrics-entry {
+.lyrics-entry.long-lyrics {
   clip-path: inset(-15px -20px);
 }
 
-.lyrics-entry::after {
+.lyrics-entry.long-lyrics::after {
   content: "";
   pointer-events: none;
   display: block;
@@ -2076,39 +2092,6 @@ ul.quick-info li:not(:last-child)::after {
   margin-bottom: 1.5em;
 }
 
-.expandable-gallery-section .section-expando {
-  margin-top: 1em;
-  margin-bottom: 2em;
-
-  display: flex;
-  flex-direction: row;
-  justify-content: space-around;
-}
-
-.expandable-gallery-section .section-expando-content {
-  text-align: center;
-  line-height: 1.5;
-}
-
-.expandable-gallery-section .section-expando-toggle {
-  text-decoration: underline;
-  text-decoration-style: dotted;
-}
-
-.expandable-gallery-section.expanded .section-content-below-cut {
-  animation: expand-gallery-section 0.8s forwards;
-}
-
-@keyframes expand-gallery-section {
-  from {
-    opacity: 0;
-  }
-
-  to {
-    opacity: 1;
-  }
-}
-
 .quick-description:not(.has-external-links-only) {
   --clamped-padding-ratio: max(var(--responsive-padding-ratio), 0.06);
   margin-left: auto;
@@ -3251,6 +3234,47 @@ video.pixelate, .pixelate video {
   --dim-color: inherit !important;
 }
 
+.grid-caption {
+  flex-basis: 100%;
+  text-align: center;
+  line-height: 1.5;
+}
+
+.grid-expando {
+  margin-top: 1em;
+  margin-bottom: 2em;
+  flex-basis: 100%;
+
+  display: flex;
+  flex-direction: row;
+  justify-content: space-around;
+}
+
+.grid-expando-content {
+  margin: 0;
+  text-align: center;
+  line-height: 1.5;
+}
+
+.grid-expando-toggle {
+  text-decoration: underline;
+  text-decoration-style: dotted;
+}
+
+.grid-item.shown-by-expandable-cut {
+  animation: expand-cover-grid 0.8s forwards;
+}
+
+@keyframes expand-cover-grid {
+  from {
+    opacity: 0;
+  }
+
+  to {
+    opacity: 1;
+  }
+}
+
 /* Carousel */
 
 .carousel-container {
@@ -4193,6 +4217,10 @@ main.long-content .content-sticky-heading-container .content-sticky-subheading-r
     max-width: unset;
   }
 
+  #artwork-column .cover-artwork {
+    --normal-shadow: 0 0 transparent;
+  }
+
   #artwork-column .cover-artwork:not(:first-child),
   #artwork-column .cover-artwork-joiner {
     margin-left: 30px;
diff --git a/src/static/js/client-util.js b/src/static/js/client-util.js
index 5a35bcf2..396c4889 100644
--- a/src/static/js/client-util.js
+++ b/src/static/js/client-util.js
@@ -37,7 +37,7 @@ export function cssProp(el, ...args) {
   }
 }
 
-export function templateContent(el) {
+export function templateContent(el, slots = {}) {
   if (el === null) {
     return null;
   }
@@ -46,7 +46,25 @@ export function templateContent(el) {
     throw new Error(`Expected a <template> element`);
   }
 
-  return el.content.cloneNode(true);
+  const content = el.content.cloneNode(true);
+
+  for (const [key, value] of Object.entries(slots)) {
+    const slot = content.querySelector(`slot[name="${key}"]`);
+
+    if (!slot) {
+      console.warn(`Slot ${key} missing in template:`, el);
+      continue;
+    }
+
+    if (value === null || value === undefined) {
+      console.warn(`Valueless slot ${key} in template:`, el);
+      continue;
+    }
+
+    slot.replaceWith(value);
+  }
+
+  return content;
 }
 
 // Curry-style, so multiple points can more conveniently be tested at once.
diff --git a/src/static/js/client/expandable-gallery-section.js b/src/static/js/client/expandable-gallery-section.js
deleted file mode 100644
index dc83e8b7..00000000
--- a/src/static/js/client/expandable-gallery-section.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/* eslint-env browser */
-
-// TODO: Combine this and quick-description.js
-
-import {cssProp} from '../client-util.js';
-
-import {stitchArrays} from '../../shared-util/sugar.js';
-
-export const info = {
-  id: 'expandableGallerySectionInfo',
-
-  sections: null,
-
-  sectionContentBelowCut: null,
-
-  sectionExpandoToggles: null,
-
-  sectionExpandCues: null,
-  sectionCollapseCues: null,
-};
-
-export function getPageReferences() {
-  info.sections =
-    Array.from(document.querySelectorAll('.expandable-gallery-section'))
-      .filter(section => section.querySelector('.section-expando-toggle'));
-
-  info.sectionContentBelowCut =
-    info.sections
-      .map(section => section.querySelector('.section-content-below-cut'));
-
-  info.sectionExpandoToggles =
-    info.sections
-      .map(section => section.querySelector('.section-expando-toggle'));
-
-  info.sectionExpandCues =
-    info.sections
-      .map(section => section.querySelector('.section-expand-cue'));
-
-  info.sectionCollapseCues =
-    info.sections
-      .map(section => section.querySelector('.section-collapse-cue'));
-}
-
-export function addPageListeners() {
-  for (const {
-    section,
-    contentBelowCut,
-    expandoToggle,
-    expandCue,
-    collapseCue,
-  } of stitchArrays({
-    section: info.sections,
-    contentBelowCut: info.sectionContentBelowCut,
-    expandoToggle: info.sectionExpandoToggles,
-    expandCue: info.sectionExpandCues,
-    collapseCue: info.sectionCollapseCues,
-  })) {
-    expandoToggle.addEventListener('click', domEvent => {
-      domEvent.preventDefault();
-
-      const collapsed =
-        cssProp(contentBelowCut, 'display') === 'none';
-
-      if (collapsed) {
-        section.classList.add('expanded');
-        cssProp(contentBelowCut, 'display', null);
-        cssProp(expandCue, 'display', 'none');
-        cssProp(collapseCue, 'display', null);
-      } else {
-        section.classList.remove('expanded');
-        cssProp(contentBelowCut, 'display', 'none');
-        cssProp(expandCue, 'display', null);
-        cssProp(collapseCue, 'display', 'none');
-      }
-    });
-  }
-}
diff --git a/src/static/js/client/expandable-grid-section.js b/src/static/js/client/expandable-grid-section.js
new file mode 100644
index 00000000..ce9a4c06
--- /dev/null
+++ b/src/static/js/client/expandable-grid-section.js
@@ -0,0 +1,85 @@
+/* eslint-env browser */
+
+import {cssProp} from '../client-util.js';
+
+import {stitchArrays} from '../../shared-util/sugar.js';
+
+export const info = {
+  id: 'expandableGallerySectionInfo',
+
+  items: null,
+  toggles: null,
+  expandCues: null,
+  collapseCues: null,
+};
+
+export function getPageReferences() {
+  const expandos =
+    Array.from(document.querySelectorAll('.grid-expando'));
+
+  const grids =
+    expandos
+      .map(expando => expando.closest('.grid-listing'));
+
+  info.items =
+    grids
+      .map(grid => grid.querySelectorAll('.grid-item'))
+      .map(items => Array.from(items));
+
+  info.toggles =
+    expandos
+      .map(expando => expando.querySelector('.grid-expando-toggle'));
+
+  info.expandCues =
+    info.toggles
+      .map(toggle => toggle.querySelector('.grid-expand-cue'));
+
+  info.collapseCues =
+    info.toggles
+      .map(toggle => toggle.querySelector('.grid-collapse-cue'));
+}
+
+export function addPageListeners() {
+  stitchArrays({
+    items: info.items,
+    toggle: info.toggles,
+    expandCue: info.expandCues,
+    collapseCue: info.collapseCues,
+  }).forEach(({
+      items,
+      toggle,
+      expandCue,
+      collapseCue,
+    }) => {
+      toggle.addEventListener('click', domEvent => {
+        domEvent.preventDefault();
+
+        const collapsed =
+          items.some(item =>
+            item.classList.contains('hidden-by-expandable-cut'));
+
+        for (const item of items) {
+          if (
+            !item.classList.contains('hidden-by-expandable-cut') &&
+            !item.classList.contains('shown-by-expandable-cut')
+          ) continue;
+
+          if (collapsed) {
+            item.classList.remove('hidden-by-expandable-cut');
+            item.classList.add('shown-by-expandable-cut');
+          } else {
+            item.classList.add('hidden-by-expandable-cut');
+            item.classList.remove('shown-by-expandable-cut');
+          }
+        }
+
+        if (collapsed) {
+          cssProp(expandCue, 'display', 'none');
+          cssProp(collapseCue, 'display', null);
+        } else {
+          cssProp(expandCue, 'display', null);
+          cssProp(collapseCue, 'display', 'none');
+        }
+      });
+    });
+}
diff --git a/src/static/js/client/index.js b/src/static/js/client/index.js
index 016ce9ad..86081b5d 100644
--- a/src/static/js/client/index.js
+++ b/src/static/js/client/index.js
@@ -11,7 +11,7 @@ import * as artistRollingWindowModule from './artist-rolling-window.js';
 import * as cssCompatibilityAssistantModule from './css-compatibility-assistant.js';
 import * as datetimestampTooltipModule from './datetimestamp-tooltip.js';
 import * as draggedLinkModule from './dragged-link.js';
-import * as expandableGallerySectionModule from './expandable-gallery-section.js';
+import * as expandableGridSectionModule from './expandable-grid-section.js';
 import * as galleryStyleSelectorModule from './gallery-style-selector.js';
 import * as hashLinkModule from './hash-link.js';
 import * as hoverableTooltipModule from './hoverable-tooltip.js';
@@ -37,7 +37,7 @@ export const modules = [
   cssCompatibilityAssistantModule,
   datetimestampTooltipModule,
   draggedLinkModule,
-  expandableGallerySectionModule,
+  expandableGridSectionModule,
   galleryStyleSelectorModule,
   hashLinkModule,
   hoverableTooltipModule,
diff --git a/src/static/js/client/quick-description.js b/src/static/js/client/quick-description.js
index 6a7a6023..cff82252 100644
--- a/src/static/js/client/quick-description.js
+++ b/src/static/js/client/quick-description.js
@@ -1,7 +1,5 @@
 /* eslint-env browser */
 
-// TODO: Combine this and expandable-gallery-section.js
-
 import {stitchArrays} from '../../shared-util/sugar.js';
 
 export const info = {
diff --git a/src/static/js/client/sidebar-search.js b/src/static/js/client/sidebar-search.js
index eae1e74e..4467766c 100644
--- a/src/static/js/client/sidebar-search.js
+++ b/src/static/js/client/sidebar-search.js
@@ -73,6 +73,10 @@ export const info = {
   groupResultKindString: null,
   tagResultKindString: null,
 
+  groupResultDisambiguatorString: null,
+  flashResultDisambiguatorString: null,
+  trackResultDisambiguatorString: null,
+
   albumResultFilterString: null,
   artistResultFilterString: null,
   flashResultFilterString: null,
@@ -196,6 +200,15 @@ export function getPageReferences() {
   info.tagResultKindString =
     findString('tag-result-kind');
 
+  info.groupResultDisambiguatorString =
+    findString('group-result-disambiguator');
+
+  info.flashResultDisambiguatorString =
+    findString('flash-result-disambiguator');
+
+  info.trackResultDisambiguatorString =
+    findString('track-result-disambiguator');
+
   info.albumResultFilterString =
     findString('album-result-filter');
 
@@ -841,7 +854,7 @@ function fillResultElements(results, {
   }
 
   for (const result of filteredResults) {
-    const el = generateSidebarSearchResult(result);
+    const el = generateSidebarSearchResult(result, filteredResults);
     if (!el) continue;
 
     info.results.appendChild(el);
@@ -890,13 +903,13 @@ function showFilterElements(results) {
   }
 }
 
-function generateSidebarSearchResult(result) {
+function generateSidebarSearchResult(result, results) {
   const preparedSlots = {
     color:
       result.data.color ?? null,
 
     name:
-      result.data.name ?? result.data.primaryName ?? null,
+      getSearchResultName(result),
 
     imageSource:
       getSearchResultImageSource(result),
@@ -961,9 +974,37 @@ function generateSidebarSearchResult(result) {
       return null;
   }
 
+  const compareReferenceType = otherResult =>
+    otherResult.referenceType === result.referenceType;
+
+  const compareName = otherResult =>
+    getSearchResultName(otherResult) === getSearchResultName(result);
+
+  const ambiguous =
+    results.some(otherResult =>
+      otherResult !== result &&
+      compareReferenceType(otherResult) &&
+      compareName(otherResult));
+
+  if (ambiguous) {
+    preparedSlots.disambiguate =
+      result.data.disambiguator;
+
+    preparedSlots.disambiguatorString =
+      info[result.referenceType + 'ResultDisambiguatorString'];
+  }
+
   return generateSidebarSearchResultTemplate(preparedSlots);
 }
 
+function getSearchResultName(result) {
+  return (
+    result.data.name ??
+    result.data.primaryName ??
+    null
+  );
+}
+
 function getSearchResultImageSource(result) {
   const {artwork} = result.data;
   if (!artwork) return null;
@@ -1039,6 +1080,15 @@ function generateSidebarSearchResultTemplate(slots) {
     }
   }
 
+  if (!accentSpan && slots.disambiguate) {
+    accentSpan = document.createElement('span');
+    accentSpan.classList.add('wiki-search-result-disambiguator');
+    accentSpan.appendChild(
+      templateContent(slots.disambiguatorString, {
+        disambiguator: slots.disambiguate,
+      }));
+  }
+
   if (!accentSpan && slots.kindString) {
     accentSpan = document.createElement('span');
     accentSpan.classList.add('wiki-search-result-kind');
diff --git a/src/static/js/search-worker.js b/src/static/js/search-worker.js
index e32b4ad5..3e9fbfca 100644
--- a/src/static/js/search-worker.js
+++ b/src/static/js/search-worker.js
@@ -391,6 +391,8 @@ function performSearchAction({query, options}) {
 }
 
 const interestingFieldCombinations = [
+  ['primaryName'],
+
   ['primaryName', 'parentName', 'groups'],
   ['primaryName', 'parentName'],
   ['primaryName', 'groups', 'contributors'],
@@ -412,7 +414,6 @@ const interestingFieldCombinations = [
   ['contributors', 'parentName'],
   ['contributors', 'groups'],
   ['primaryName', 'contributors'],
-  ['primaryName'],
 ];
 
 function queryGenericIndex(query, options) {