« get me outta code hell

client, content, css: simple group contributions table filter - 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>2026-06-10 07:02:20 -0300
committer(quasar) nebula <qznebula@protonmail.com>2026-06-10 07:20:35 -0300
commit9c946df709fbeca15bc6e76435cbe30269a2bd3a (patch)
tree2e2b465fc089aa56d40dc608d0004a409f1b541e /src
parent7710949c13b149d40195b4203b8a8234039ef5d6 (diff)
client, content, css: simple group contributions table filter
Diffstat (limited to 'src')
-rw-r--r--src/content/dependencies/generateArtistGroupContributionsInfo.js11
-rw-r--r--src/content/dependencies/generateArtistInfoPageAdditionalFilesChunk.js2
-rw-r--r--src/content/dependencies/generateArtistInfoPageArtworksChunk.js2
-rw-r--r--src/content/dependencies/generateArtistInfoPageChunk.js13
-rw-r--r--src/content/dependencies/generateArtistInfoPageFlashesChunk.js2
-rw-r--r--src/content/dependencies/generateArtistInfoPageMusicVideosChunk.js2
-rw-r--r--src/content/dependencies/generateArtistInfoPageTracksChunk.js2
-rw-r--r--src/static/css/features.css37
-rw-r--r--src/static/js/client-util.js8
-rw-r--r--src/static/js/client/group-contributions-table.js123
-rw-r--r--src/static/js/client/index.js2
11 files changed, 195 insertions, 9 deletions
diff --git a/src/content/dependencies/generateArtistGroupContributionsInfo.js b/src/content/dependencies/generateArtistGroupContributionsInfo.js
index 3c6187f9..f9a06d4a 100644
--- a/src/content/dependencies/generateArtistGroupContributionsInfo.js
+++ b/src/content/dependencies/generateArtistGroupContributionsInfo.js
@@ -66,6 +66,10 @@ export default {
   }),
 
   data: (query) => ({
+    groupDirectories:
+      query.groups
+        .map(group => group.directory),
+
     hasCountColumn:
       true,
 
@@ -117,13 +121,16 @@ export default {
 
             stitchArrays({
               link: relations.groupLinks,
+              directory: data.groupDirectories,
               changesCategory: data.groupsChangeCategory,
               count: data.groupCounts,
               duration: data.groupDurations,
-            }).map(({link, changesCategory, count, duration}) =>
+            }).map(({link, directory, changesCategory, count, duration}) =>
                 html.tag('tr', changesCategory && {class: 'split'}, [
                   html.tag('td', {class: 'group'},
-                    link),
+                    link.slots({
+                      attributes: {'data-directory': directory},
+                    })),
 
                   data.hasCountColumn &&
                     html.tag('td', {class: 'count'},
diff --git a/src/content/dependencies/generateArtistInfoPageAdditionalFilesChunk.js b/src/content/dependencies/generateArtistInfoPageAdditionalFilesChunk.js
index 53bc103f..2159c5e9 100644
--- a/src/content/dependencies/generateArtistInfoPageAdditionalFilesChunk.js
+++ b/src/content/dependencies/generateArtistInfoPageAdditionalFilesChunk.js
@@ -1,7 +1,7 @@
 export default {
   relations: (relation, artist, album, contribs) => ({
     template:
-      relation('generateArtistInfoPageChunk'),
+      relation('generateArtistInfoPageChunk', album),
 
     albumLink:
       relation('linkAlbum', album),
diff --git a/src/content/dependencies/generateArtistInfoPageArtworksChunk.js b/src/content/dependencies/generateArtistInfoPageArtworksChunk.js
index f98b1e85..2519a0c7 100644
--- a/src/content/dependencies/generateArtistInfoPageArtworksChunk.js
+++ b/src/content/dependencies/generateArtistInfoPageArtworksChunk.js
@@ -1,7 +1,7 @@
 export default {
   relations: (relation, album, contribs) => ({
     template:
-      relation('generateArtistInfoPageChunk'),
+      relation('generateArtistInfoPageChunk', album),
 
     albumLink:
       relation('linkAlbum', album),
diff --git a/src/content/dependencies/generateArtistInfoPageChunk.js b/src/content/dependencies/generateArtistInfoPageChunk.js
index e19030c9..aadafb08 100644
--- a/src/content/dependencies/generateArtistInfoPageChunk.js
+++ b/src/content/dependencies/generateArtistInfoPageChunk.js
@@ -1,6 +1,13 @@
 import {empty} from '#sugar';
 
 export default {
+  data: (thing) => ({
+    groupDirectories:
+      (thing && thing.groups
+        ? thing.groups.map(group => group.directory)
+        : null),
+  }),
+
   slots: {
     mode: {
       validate: v => v.is('flash', 'album'),
@@ -26,7 +33,7 @@ export default {
     durationApproximate: {type: 'boolean'},
   },
 
-  generate(slots, {html, language}) {
+  generate(data, slots, {html, language}) {
     let earliestItemDate = null;
     let latestItemDate = null;
     let onlyItemDate = null;
@@ -96,6 +103,10 @@ export default {
     return html.tags([
       html.tag('dt',
         slots.id && {id: slots.id},
+
+        data.groupDirectories &&
+          {'data-groups': data.groupDirectories.join(' ')},
+
         accentedLink),
 
       html.tag('dd', slots.list),
diff --git a/src/content/dependencies/generateArtistInfoPageFlashesChunk.js b/src/content/dependencies/generateArtistInfoPageFlashesChunk.js
index 733c8fa4..7e98ee06 100644
--- a/src/content/dependencies/generateArtistInfoPageFlashesChunk.js
+++ b/src/content/dependencies/generateArtistInfoPageFlashesChunk.js
@@ -1,7 +1,7 @@
 export default {
   relations: (relation, flashAct, contribs) => ({
     template:
-      relation('generateArtistInfoPageChunk'),
+      relation('generateArtistInfoPageChunk', flashAct),
 
     flashActLink:
       relation('linkFlashAct', flashAct),
diff --git a/src/content/dependencies/generateArtistInfoPageMusicVideosChunk.js b/src/content/dependencies/generateArtistInfoPageMusicVideosChunk.js
index 9ac7debf..2733dbcf 100644
--- a/src/content/dependencies/generateArtistInfoPageMusicVideosChunk.js
+++ b/src/content/dependencies/generateArtistInfoPageMusicVideosChunk.js
@@ -1,7 +1,7 @@
 export default {
   relations: (relation, artist, album, contribs) => ({
     template:
-      relation('generateArtistInfoPageChunk'),
+      relation('generateArtistInfoPageChunk', album),
 
     albumLink:
       relation('linkAlbum', album),
diff --git a/src/content/dependencies/generateArtistInfoPageTracksChunk.js b/src/content/dependencies/generateArtistInfoPageTracksChunk.js
index 607f1f53..f2cc7456 100644
--- a/src/content/dependencies/generateArtistInfoPageTracksChunk.js
+++ b/src/content/dependencies/generateArtistInfoPageTracksChunk.js
@@ -63,7 +63,7 @@ export default {
 
   relations: (relation, query, artist, album, trackContribLists) => ({
     template:
-      relation('generateArtistInfoPageChunk'),
+      relation('generateArtistInfoPageChunk', album),
 
     albumLink:
       relation('linkAlbum', album),
diff --git a/src/static/css/features.css b/src/static/css/features.css
index 2d54fe7a..f0bd1425 100644
--- a/src/static/css/features.css
+++ b/src/static/css/features.css
@@ -1260,12 +1260,49 @@
       padding-right: 1.5ch;
     }
 
+    th:nth-child(1) { text-align: left; }
     td.group { padding-left: 3ch; }
     td.count { text-align: center; }
     td.duration { text-align: right; }
   }
 }
 
+@layer interaction {
+  .group-contributions-table {
+    .group a {
+      position: relative;
+      text-decoration: underline;
+      text-decoration-style: dotted;
+    }
+  }
+
+  .group-contributions-table:has(.group a.selected) {
+    tr:has(.group a:not(.selected)) {
+      td { opacity: 0.65; }
+      td.group { opacity: 0.8; }
+    }
+
+    .group a.selected {
+      text-decoration-style: solid;
+    }
+
+    .group a.selected::before {
+      content: "";
+
+      position: absolute;
+      display: inline-block;
+      top: 50%; transform: translateY(-50%);
+      left: -1.75ch;
+
+      width: 0.4em;
+      height: 0.4em;
+      border-radius: 100000cm;
+
+      background: var(--primary-color);
+    }
+  }
+}
+
 /* Image and media containers */
 
 @layer layout {
diff --git a/src/static/js/client-util.js b/src/static/js/client-util.js
index de54945c..8ad31b90 100644
--- a/src/static/js/client-util.js
+++ b/src/static/js/client-util.js
@@ -16,9 +16,15 @@ export function rebase(href, rebaseKey = 'rebaseLocalized') {
 
 export function cssProp(el, ...args) {
   if (typeof args[0] === 'string' && args.length === 1) {
-    return getComputedStyle(el).getPropertyValue(args[0]).trim();
+    if (el) {
+      return getComputedStyle(el).getPropertyValue(args[0]).trim();
+    } else {
+      return '';
+    }
   }
 
+  if (!el) return;
+
   if (typeof args[0] === 'string' && args.length === 2) {
     if (args[1] === null) {
       el.style.removeProperty(args[0]);
diff --git a/src/static/js/client/group-contributions-table.js b/src/static/js/client/group-contributions-table.js
new file mode 100644
index 00000000..3b79f84d
--- /dev/null
+++ b/src/static/js/client/group-contributions-table.js
@@ -0,0 +1,123 @@
+import {cssProp} from '../client-util.js';
+import {stitchArrays} from '../../shared-util/sugar.js';
+
+export const info = {
+  id: 'groupContributionsInfo',
+
+  tables: null,
+  lists: null,
+
+  groupLinks: null,
+  groupLinkDirectories: null,
+
+  chunkDTs: null,
+  chunkDDs: null,
+  chunkGroupDirectories: null,
+};
+
+export function getPageReferences() {
+  if (document.documentElement.dataset.urlKey !== 'localized.artist') {
+    return;
+  }
+
+  info.tables =
+    Array.from(document.querySelectorAll('.group-contributions-table'));
+
+  info.lists =
+    info.tables
+      .map(table => table.closest('dl'));
+
+  info.groupLinks =
+    info.tables
+      .map(table => Array.from(table.querySelectorAll('td.group a')));
+
+  info.groupLinkDirectories =
+    info.groupLinks
+      .map(links => links
+        .map(link => link.dataset.directory));
+
+  info.chunkDTs =
+    info.lists
+      .map(list => Array.from(list.querySelectorAll('dt')));
+
+  info.chunkDDs =
+    info.chunkDTs
+      .map(dts => dts
+        .map(dt => dt.nextElementSibling)
+        .map(el => el.tagName === 'DD' ? el : null));
+
+  info.chunkGroupDirectories =
+    info.chunkDTs
+      .map(dts => dts
+        .map(dt => dt.dataset.groups)
+        .map(string => string ? string.split(' ') : []));
+}
+
+export function addPageListeners() {
+  if (!info.tables) return;
+
+  stitchArrays({
+    table: info.tables,
+    groupLinks: info.groupLinks,
+  }).forEach(({table, groupLinks}) => {
+      groupLinks.forEach(groupLink => {
+        groupLink.addEventListener('click', domEvent => {
+          domEvent.preventDefault();
+          handleGroupLinkClicked(table, groupLink);
+        });
+      });
+    });
+}
+
+function handleGroupLinkClicked(table, groupLink) {
+  const i = info.tables.indexOf(table);
+
+  groupLink.classList.toggle('selected');
+
+  // For now, just disable having more than one link selected at a time.
+  for (const link of info.groupLinks[i]) {
+    if (link !== groupLink) {
+      link.classList.remove('selected');
+    }
+  }
+
+  updateVisibleChunks(table);
+}
+
+function updateVisibleChunks(table) {
+  const i = info.tables.indexOf(table);
+
+  const selectedGroupDirectories =
+    stitchArrays({
+      link: info.groupLinks[i],
+      directory: info.groupLinkDirectories[i],
+    }).filter(({link}) => link.classList.contains('selected'))
+      .map(({directory}) => directory);
+
+  stitchArrays({
+    chunkDT: info.chunkDTs[i],
+    chunkDD: info.chunkDDs[i],
+    chunkGroupDirectories: info.chunkGroupDirectories[i],
+  }).forEach(({
+      chunkDT,
+      chunkDD,
+      chunkGroupDirectories,
+    }) => {
+      if (selectedGroupDirectories.length >= 1) {
+        const included =
+          chunkGroupDirectories
+            .some(d => selectedGroupDirectories.includes(d));
+
+        if (included) {
+          cssProp(chunkDT, 'display', null);
+          cssProp(chunkDD, 'display', null);
+        } else {
+          cssProp(chunkDT, 'display', 'none');
+          cssProp(chunkDD, 'display', 'none');
+        }
+      } else {
+        cssProp(chunkDT, 'display', null);
+        cssProp(chunkDD, 'display', null);
+      }
+    });
+}
diff --git a/src/static/js/client/index.js b/src/static/js/client/index.js
index a17f7dab..a438d6d8 100644
--- a/src/static/js/client/index.js
+++ b/src/static/js/client/index.js
@@ -8,6 +8,7 @@ import * as datetimestampTooltipModule from './datetimestamp-tooltip.js';
 import * as draggedLinkModule from './dragged-link.js';
 import * as expandableGridSectionModule from './expandable-grid-section.js';
 import * as galleryStyleSelectorModule from './gallery-style-selector.js';
+import * as groupContributionsTableModule from './group-contributions-table.js';
 import * as hashLinkModule from './hash-link.js';
 import * as hoverableTooltipModule from './hoverable-tooltip.js';
 import * as imageOverlayModule from './image-overlay.js';
@@ -33,6 +34,7 @@ export const modules = [
   draggedLinkModule,
   expandableGridSectionModule,
   galleryStyleSelectorModule,
+  groupContributionsTableModule,
   hashLinkModule,
   hoverableTooltipModule,
   imageOverlayModule,