diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2023-06-30 20:45:00 -0300 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2023-06-30 20:45:00 -0300 |
commit | da5ba89f4171c395f5e7fa2c764272e7d2de93f3 (patch) | |
tree | 51252bb8e85fc6e2867c40393798ef8b9304734e /src/content | |
parent | 84e1f947c9ac17ab075348ea386d43c17af66435 (diff) |
content: generateArtistGroupContributionsInfo: table layout 👻
Diffstat (limited to 'src/content')
5 files changed, 301 insertions, 163 deletions
diff --git a/src/content/dependencies/generateArtistGroupContributionsInfo.js b/src/content/dependencies/generateArtistGroupContributionsInfo.js index 0ecfaa34..1e7086ed 100644 --- a/src/content/dependencies/generateArtistGroupContributionsInfo.js +++ b/src/content/dependencies/generateArtistGroupContributionsInfo.js @@ -1,4 +1,9 @@ -import {stitchArrays, unique} from '../../util/sugar.js'; +import { + empty, + filterProperties, + stitchArrays, + unique, +} from '../../util/sugar.js'; export default { contentDependencies: ['linkGroup'], @@ -47,29 +52,48 @@ export default { allGroupsOrdered .sort((a, b) => groupToCountMap.get(b) - groupToCountMap.get(a)); + // The filter here ensures all displayed groups have at least some duration + // when sorting by duration. const groupsSortedByDuration = allGroupsOrdered .filter(group => groupToDurationMap.get(group) > 0) .sort((a, b) => groupToDurationMap.get(b) - groupToDurationMap.get(a)); - const groupCounts = + const groupCountsSortedByCount = groupsSortedByCount .map(group => groupToCountMap.get(group)); - const groupDurations = + const groupDurationsSortedByCount = + groupsSortedByCount + .map(group => groupToDurationMap.get(group)); + + const groupDurationsApproximateSortedByCount = + groupsSortedByCount + .map(group => groupToDurationCountMap.get(group) > 1); + + const groupCountsSortedByDuration = + groupsSortedByDuration + .map(group => groupToCountMap.get(group)); + + const groupDurationsSortedByDuration = groupsSortedByDuration .map(group => groupToDurationMap.get(group)); - const groupDurationsApproximate = + const groupDurationsApproximateSortedByDuration = groupsSortedByDuration .map(group => groupToDurationCountMap.get(group) > 1); return { groupsSortedByCount, groupsSortedByDuration, - groupCounts, - groupDurations, - groupDurationsApproximate, + + groupCountsSortedByCount, + groupDurationsSortedByCount, + groupDurationsApproximateSortedByCount, + + groupCountsSortedByDuration, + groupDurationsSortedByDuration, + groupDurationsApproximateSortedByDuration, }; }, @@ -86,39 +110,104 @@ export default { }, data(query) { - return { - groupCounts: query.groupCounts, - groupDurations: query.groupDurations, - groupDurationsApproximate: query.groupDurationsApproximate, - }; + return filterProperties(query, [ + 'groupCountsSortedByCount', + 'groupDurationsSortedByCount', + 'groupDurationsApproximateSortedByCount', + + 'groupCountsSortedByDuration', + 'groupDurationsSortedByDuration', + 'groupDurationsApproximateSortedByDuration', + ]); }, slots: { - mode: { - validate: v => v.is('count', 'duration'), - }, + title: {type: 'html'}, + showBothColumns: {type: 'boolean'}, + showSortButton: {type: 'boolean'}, + visible: {type: 'boolean', default: true}, + + sort: {validate: v => v.is('count', 'duration')}, + countUnit: {validate: v => v.is('tracks', 'artworks')}, }, - generate(data, relations, slots, {language}) { - return ( - language.formatUnitList( - (slots.mode === 'count' - ? stitchArrays({ - groupLink: relations.groupLinksSortedByCount, - count: data.groupCounts, - }).map(({groupLink, count}) => - language.$('artistPage.groupsLine.item.withCount', { - group: groupLink, - count, - })) - : stitchArrays({ - groupLink: relations.groupLinksSortedByDuration, - duration: data.groupDurations, - approximate: data.groupDurationsApproximate, - }).map(({groupLink, duration, approximate}) => - language.$('artistPage.groupsLine.item.withDuration', { - group: groupLink, - duration: language.formatDuration(duration, {approximate}), - }))))); + generate(data, relations, slots, {html, language}) { + if (slots.sort === 'count' && empty(relations.groupLinksSortedByCount)) { + return html.blank(); + } else if (slots.sort === 'duration' && empty(relations.groupLinksSortedByDuration)) { + return html.blank(); + } + + const getCounts = counts => + counts.map(count => { + switch (slots.countUnit) { + case 'tracks': return language.countTracks(count, {unit: true}); + case 'artworks': return language.countArtworks(count, {unit: true}); + } + }); + + // We aren't displaying the "~" approximate symbol here for now. + // The general notion that these sums aren't going to be 100% accurate + // is made clear by the "XYZ has contributed ~1:23:45 hours of music..." + // line that's always displayed above this table. + const getDurations = (durations, approximate) => + stitchArrays({ + duration: durations, + approximate: approximate, + }).map(({duration}) => language.formatDuration(duration)); + + const topLevelClasses = [ + 'group-contributions-sorted-by-' + slots.sort, + slots.visible && 'visible', + ]; + + return html.tags([ + html.tag('dt', {class: topLevelClasses}, + (slots.showSortButton + ? language.$('artistPage.groupContributions.title.withSortButton', { + title: slots.title, + sort: + html.tag('a', {href: '#', class: 'group-contributions-sort-button'}, + (slots.sort === 'count' + ? language.$('artistPage.groupContributions.title.sorting.count') + : language.$('artistPage.groupContributions.title.sorting.duration'))), + }) + : slots.title)), + + html.tag('dd', {class: topLevelClasses}, + html.tag('ul', {class: 'group-contributions-table', role: 'list'}, + (slots.sort === 'count' + ? stitchArrays({ + group: relations.groupLinksSortedByCount, + count: getCounts(data.groupCountsSortedByCount), + duration: getDurations(data.groupDurationsSortedByCount, data.groupDurationsApproximateSortedByCount), + }).map(({group, count, duration}) => + html.tag('li', + html.tag('div', {class: 'group-contributions-row'}, [ + group, + html.tag('span', {class: 'group-contributions-metrics'}, + // When sorting by count, duration details aren't necessarily + // available for all items. + (slots.showBothColumns && duration + ? language.$('artistPage.groupContributions.item.countDurationAccent', {count, duration}) + : language.$('artistPage.groupContributions.item.countAccent', {count}))), + ]))) + : stitchArrays({ + group: relations.groupLinksSortedByDuration, + count: getCounts(data.groupCountsSortedByDuration), + duration: getDurations(data.groupDurationsSortedByDuration, data.groupDurationsApproximateSortedByCount), + }).map(({group, count, duration}) => + html.tag('li', + html.tag('div', {class: 'group-contributions-row'}, [ + group, + html.tag('span', {class: 'group-contributions-metrics'}, + // Count details are always available, since they're just the + // number of contributions directly. And duration details are + // guaranteed for every item when sorting by duration. + (slots.showBothColumns + ? language.$('artistPage.groupContributions.item.durationCountAccent', {duration, count}) + : language.$('artistPage.groupContributions.item.durationAccent', {duration}))), + ])))))), + ]); }, }; diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js index 1f6c66fc..7f79a609 100644 --- a/src/content/dependencies/generateArtistInfoPage.js +++ b/src/content/dependencies/generateArtistInfoPage.js @@ -218,14 +218,30 @@ export default { }), })), - // TODO: How to check if a template is blank!? - // !html.isBlank(sec.tracks.groupInfo.content) && - html.tag('p', - language.$('artistPage.musicGroupsLine', { - groups: sec.tracks.groupInfo.slot('mode', 'duration'), - })), + sec.tracks.list + .slots({ + groupInfo: [ + sec.tracks.groupInfo + .clone() + .slots({ + title: language.$('artistPage.groupContributions.title.music'), + showSortButton: true, + sort: 'count', + countUnit: 'tracks', + visible: true, + }), - sec.tracks.list, + sec.tracks.groupInfo + .clone() + .slots({ + title: language.$('artistPage.groupContributions.title.music'), + showSortButton: true, + sort: 'duration', + countUnit: 'tracks', + visible: false, + }), + ], + }), ], sec.artworks && [ @@ -236,11 +252,6 @@ export default { title: language.$('artistPage.artList.title'), }), - html.tag('p', - language.$('artistPage.artGroupsLine', { - groups: sec.artworks.groupInfo.slot('mode', 'count'), - })), - sec.artworks.artistGalleryLink && html.tag('p', language.$('artistPage.viewArtGallery.orBrowseList', { @@ -249,7 +260,17 @@ export default { }), })), - sec.artworks.list, + sec.artworks.list + .slots({ + groupInfo: + sec.artworks.groupInfo + .slots({ + title: language.$('artistPage.groupContributions.title.artworks'), + showBothColumns: false, + sort: 'count', + countUnit: 'artworks', + }), + }), ], sec.flashes && [ diff --git a/src/content/dependencies/generateArtistInfoPageArtworksChunkedList.js b/src/content/dependencies/generateArtistInfoPageArtworksChunkedList.js index 86548598..656121c6 100644 --- a/src/content/dependencies/generateArtistInfoPageArtworksChunkedList.js +++ b/src/content/dependencies/generateArtistInfoPageArtworksChunkedList.js @@ -9,6 +9,7 @@ import { export default { contentDependencies: [ 'generateArtistInfoPageChunk', + 'generateArtistInfoPageChunkedList', 'generateArtistInfoPageChunkItem', 'generateArtistInfoPageOtherArtistLinks', 'linkAlbum', @@ -81,6 +82,9 @@ export default { relations(relation, query, artist) { return { + chunkedList: + relation('generateArtistInfoPageChunkedList'), + chunks: query.chunks.map(() => relation('generateArtistInfoPageChunk')), @@ -120,63 +124,65 @@ export default { }, generate(data, relations, {html, language}) { - return html.tag('dl', - stitchArrays({ - chunk: relations.chunks, - albumLink: relations.albumLinks, - date: data.chunkDates, - - items: relations.items, - itemTrackLinks: relations.itemTrackLinks, - itemOtherArtistLinks: relations.itemOtherArtistLinks, - itemTypes: data.itemTypes, - itemContributions: data.itemContributions, - }).map(({ - chunk, - albumLink, - date, - - items, - itemTrackLinks, - itemOtherArtistLinks, - itemTypes, - itemContributions, - }) => - chunk.slots({ - mode: 'album', + return relations.chunkedList.slots({ + chunks: + stitchArrays({ + chunk: relations.chunks, + albumLink: relations.albumLinks, + date: data.chunkDates, + + items: relations.items, + itemTrackLinks: relations.itemTrackLinks, + itemOtherArtistLinks: relations.itemOtherArtistLinks, + itemTypes: data.itemTypes, + itemContributions: data.itemContributions, + }).map(({ + chunk, albumLink, date, - items: - stitchArrays({ - item: items, - trackLink: itemTrackLinks, - otherArtistLinks: itemOtherArtistLinks, - type: itemTypes, - contribution: itemContributions, - }).map(({ - item, - trackLink, - otherArtistLinks, - type, - contribution, - }) => - item.slots({ + items, + itemTrackLinks, + itemOtherArtistLinks, + itemTypes, + itemContributions, + }) => + chunk.slots({ + mode: 'album', + albumLink, + date, + + items: + stitchArrays({ + item: items, + trackLink: itemTrackLinks, + otherArtistLinks: itemOtherArtistLinks, + type: itemTypes, + contribution: itemContributions, + }).map(({ + item, + trackLink, otherArtistLinks, + type, contribution, - - content: - (type === 'trackCover' - ? language.$('artistPage.creditList.entry.track', { - track: trackLink, - }) - : html.tag('i', - language.$('artistPage.creditList.entry.album.' + { - albumWallpaper: 'wallpaperArt', - albumBanner: 'bannerArt', - albumCover: 'coverArt', - }[type]))), - })), - }))); + }) => + item.slots({ + otherArtistLinks, + contribution, + + content: + (type === 'trackCover' + ? language.$('artistPage.creditList.entry.track', { + track: trackLink, + }) + : html.tag('i', + language.$('artistPage.creditList.entry.album.' + { + albumWallpaper: 'wallpaperArt', + albumBanner: 'bannerArt', + albumCover: 'coverArt', + }[type]))), + })), + })), + }); }, }; diff --git a/src/content/dependencies/generateArtistInfoPageChunkedList.js b/src/content/dependencies/generateArtistInfoPageChunkedList.js new file mode 100644 index 00000000..a0334cbc --- /dev/null +++ b/src/content/dependencies/generateArtistInfoPageChunkedList.js @@ -0,0 +1,16 @@ +export default { + extraDependencies: ['html'], + + slots: { + groupInfo: {type: 'html'}, + chunks: {type: 'html'}, + }, + + generate(slots, {html}) { + return ( + html.tag('dl', [ + slots.groupInfo, + slots.chunks, + ])); + }, +}; diff --git a/src/content/dependencies/generateArtistInfoPageTracksChunkedList.js b/src/content/dependencies/generateArtistInfoPageTracksChunkedList.js index 4dd4d468..d6ae9ae8 100644 --- a/src/content/dependencies/generateArtistInfoPageTracksChunkedList.js +++ b/src/content/dependencies/generateArtistInfoPageTracksChunkedList.js @@ -9,13 +9,14 @@ import { export default { contentDependencies: [ 'generateArtistInfoPageChunk', + 'generateArtistInfoPageChunkedList', 'generateArtistInfoPageChunkItem', 'generateArtistInfoPageOtherArtistLinks', 'linkAlbum', 'linkTrack', ], - extraDependencies: ['html', 'language'], + extraDependencies: ['language'], query(artist) { const entries = [ @@ -52,6 +53,9 @@ export default { relations(relation, query, artist) { return { + chunkedList: + relation('generateArtistInfoPageChunkedList'), + chunks: query.chunks.map(() => relation('generateArtistInfoPageChunk')), @@ -107,73 +111,75 @@ export default { }; }, - generate(data, relations, {html, language}) { - return html.tag('dl', - stitchArrays({ - chunk: relations.chunks, - albumLink: relations.albumLinks, - date: data.chunkDates, - duration: data.chunkDurations, - durationApproximate: data.chunkDurationsApproximate, - - items: relations.items, - trackLinks: relations.trackLinks, - trackOtherArtistLinks: relations.trackOtherArtistLinks, - trackDurations: data.trackDurations, - trackContributions: data.trackContributions, - trackRereleases: data.trackRereleases, - }).map(({ - chunk, - albumLink, - date, - duration, - durationApproximate, - - items, - trackLinks, - trackOtherArtistLinks, - trackDurations, - trackContributions, - trackRereleases, - }) => - chunk.slots({ - mode: 'album', + generate(data, relations, {language}) { + return relations.chunkedList.slots({ + chunks: + stitchArrays({ + chunk: relations.chunks, + albumLink: relations.albumLinks, + date: data.chunkDates, + duration: data.chunkDurations, + durationApproximate: data.chunkDurationsApproximate, + + items: relations.items, + trackLinks: relations.trackLinks, + trackOtherArtistLinks: relations.trackOtherArtistLinks, + trackDurations: data.trackDurations, + trackContributions: data.trackContributions, + trackRereleases: data.trackRereleases, + }).map(({ + chunk, albumLink, date, duration, durationApproximate, - items: - stitchArrays({ - item: items, - trackLink: trackLinks, - otherArtistLinks: trackOtherArtistLinks, - duration: trackDurations, - contribution: trackContributions, - rerelease: trackRereleases, - }).map(({ - item, - trackLink, - otherArtistLinks, - duration, - contribution, - rerelease, - }) => - item.slots({ + items, + trackLinks, + trackOtherArtistLinks, + trackDurations, + trackContributions, + trackRereleases, + }) => + chunk.slots({ + mode: 'album', + albumLink, + date, + duration, + durationApproximate, + + items: + stitchArrays({ + item: items, + trackLink: trackLinks, + otherArtistLinks: trackOtherArtistLinks, + duration: trackDurations, + contribution: trackContributions, + rerelease: trackRereleases, + }).map(({ + item, + trackLink, otherArtistLinks, + duration, contribution, rerelease, - - content: - (duration - ? language.$('artistPage.creditList.entry.track.withDuration', { - track: trackLink, - duration: language.formatDuration(duration), - }) - : language.$('artistPage.creditList.entry.track', { - track: trackLink, - })), - })), - }))); + }) => + item.slots({ + otherArtistLinks, + contribution, + rerelease, + + content: + (duration + ? language.$('artistPage.creditList.entry.track.withDuration', { + track: trackLink, + duration: language.formatDuration(duration), + }) + : language.$('artistPage.creditList.entry.track', { + track: trackLink, + })), + })), + })), + }); }, }; |