diff options
| -rw-r--r-- | src/common-util/wiki-data.js | 5 | ||||
| -rw-r--r-- | src/content/dependencies/generateArtistInfoPageChunk.js | 47 | ||||
| -rw-r--r-- | src/content/dependencies/generateArtistInfoPageTracksChunk.js | 17 | ||||
| -rw-r--r-- | src/content/dependencies/generateArtistInfoPageTracksChunkItem.js | 17 | ||||
| -rw-r--r-- | src/content/dependencies/generateTrackListItem.js | 115 | ||||
| -rw-r--r-- | src/content/dependencies/generateTrackListMissingDuration.js | 37 | ||||
| -rw-r--r-- | src/strings-default.yaml | 34 |
7 files changed, 173 insertions, 99 deletions
diff --git a/src/common-util/wiki-data.js b/src/common-util/wiki-data.js index 21e15725..54f8b7ed 100644 --- a/src/common-util/wiki-data.js +++ b/src/common-util/wiki-data.js @@ -262,17 +262,14 @@ export function getArtistAvatar(artist, {to}) { // Used in multiple content functions for the artist info page, // because shared logic is torture oooooooooooooooo. export function chunkArtistTrackContributions(contributions) { - const date = contrib => contrib.date; - const album = contrib => (contrib.thing.isTrack ? contrib.thing.album : contrib.thing); return ( - // First chunk by (contribution) date and album. + // First chunk by (contribution) album. chunkByConditions(contributions, [ - (a, b) => +date(a) !== +date(b), (a, b) => album(a) !== album(b), ]).map(contribs => // Then, *within* the boundaries of the existing chunks, diff --git a/src/content/dependencies/generateArtistInfoPageChunk.js b/src/content/dependencies/generateArtistInfoPageChunk.js index 3fa46c61..e19030c9 100644 --- a/src/content/dependencies/generateArtistInfoPageChunk.js +++ b/src/content/dependencies/generateArtistInfoPageChunk.js @@ -18,30 +18,30 @@ export default { mutable: false, }, - dates: { - validate: v => v.sparseArrayOf(v.isDate), - }, + // Container and items, respectively. + date: {validate: v => v.isDate}, + dates: {validate: v => v.sparseArrayOf(v.isDate)}, duration: {validate: v => v.isDuration}, durationApproximate: {type: 'boolean'}, }, generate(slots, {html, language}) { - let earliestDate = null; - let latestDate = null; - let onlyDate = null; + let earliestItemDate = null; + let latestItemDate = null; + let onlyItemDate = null; if (!empty(slots.dates)) { - earliestDate = - slots.dates - .reduce((a, b) => a <= b ? a : b); + earliestItemDate = slots.dates[0]; + latestItemDate = slots.dates[1]; - latestDate = - slots.dates - .reduce((a, b) => a <= b ? b : a); + for (const date of slots.dates.slice(1)) { + if (date < earliestItemDate) earliestItemDate = date; + if (date > latestItemDate) latestItemDate = date; + } - if (+earliestDate === +latestDate) { - onlyDate = earliestDate; + if (+earliestItemDate === +latestItemDate) { + onlyItemDate = earliestItemDate; } } @@ -51,9 +51,16 @@ export default { const options = {album: slots.link}; const parts = ['artistPage.creditList.album']; - if (onlyDate) { + if (slots.date) { + parts.push('withDate'); + options.date = language.formatDate(slots.date); + } else if (onlyItemDate) { parts.push('withDate'); - options.date = language.formatDate(onlyDate); + options.date = language.formatDate(onlyItemDate); + } else if (earliestItemDate && latestItemDate) { + parts.push('withDateRange'); + options.dateRange = + language.formatDateRange(earliestItemDate, latestItemDate); } if (slots.duration) { @@ -72,13 +79,13 @@ export default { const options = {act: slots.link}; const parts = ['artistPage.creditList.flashAct']; - if (onlyDate) { + if (onlyItemDate) { parts.push('withDate'); - options.date = language.formatDate(onlyDate); - } else if (earliestDate && latestDate) { + options.date = language.formatDate(onlyItemDate); + } else if (earliestItemDate && latestItemDate) { parts.push('withDateRange'); options.dateRange = - language.formatDateRange(earliestDate, latestDate); + language.formatDateRange(earliestItemDate, latestItemDate); } accentedLink = language.formatString(...parts, options); diff --git a/src/content/dependencies/generateArtistInfoPageTracksChunk.js b/src/content/dependencies/generateArtistInfoPageTracksChunk.js index b3727756..7a7fc6a9 100644 --- a/src/content/dependencies/generateArtistInfoPageTracksChunk.js +++ b/src/content/dependencies/generateArtistInfoPageTracksChunk.js @@ -61,7 +61,7 @@ export default { .filter(contribs => countTowardTrackTotals(contribs) === false), }), - relations: (relation, query, artist, album, _trackContribLists) => ({ + relations: (relation, query, artist, album, trackContribLists) => ({ template: relation('generateArtistInfoPageChunk'), @@ -82,13 +82,15 @@ export default { query.contribListsCountingTowardTotals.map(trackContribs => relation('generateArtistInfoPageTracksChunkItem', artist, - trackContribs)), + trackContribs, + trackContribLists)), itemsNotCountingTowardTotals: query.contribListsNotCountingTowardTotals.map(trackContribs => relation('generateArtistInfoPageTracksChunkItem', artist, - trackContribs)), + trackContribs, + trackContribLists)), }), data(artist, _query, album, trackContribLists) { @@ -97,7 +99,10 @@ export default { const contribs = trackContribLists.flat(); - data.dates = + data.albumDate = + album.date; + + data.contribDates = contribs .map(contrib => contrib.date); @@ -168,7 +173,9 @@ export default { return language.$(workingCapsule, workingOptions); }), - dates: data.dates, + date: data.albumDate, + dates: data.contribDates, + duration: data.duration, durationApproximate: data.durationApproximate, diff --git a/src/content/dependencies/generateArtistInfoPageTracksChunkItem.js b/src/content/dependencies/generateArtistInfoPageTracksChunkItem.js index 3d6e274b..69d8eebd 100644 --- a/src/content/dependencies/generateArtistInfoPageTracksChunkItem.js +++ b/src/content/dependencies/generateArtistInfoPageTracksChunkItem.js @@ -2,14 +2,19 @@ import {sortAlbumsTracksChronologically} from '#sort'; import {empty} from '#sugar'; export default { - query(artist, contribs) { + query(artist, contribs, chunkContribs) { const query = {}; - // TODO: Very mysterious what to do if the set of contributions is, - // in total, associated with more than one thing. No design yet. query.track = contribs[0].thing; + query.date = + contribs[0].date; + + query.anyItemsExpresslyDated = + chunkContribs.flat() + .some(contrib => +contrib.date !== +query.track.album.date); + const creditedAsNormalArtist = contribs .some(contrib => @@ -112,6 +117,11 @@ export default { }), data: (query) => ({ + date: + (query.anyItemsExpresslyDated + ? query.date + : null), + duration: query.track.duration, @@ -146,6 +156,7 @@ export default { relations.trackListItem.slots({ showArtists: 'auto', showDuration: slots.showDuration, + showDate: data.date, })), }), }), diff --git a/src/content/dependencies/generateTrackListItem.js b/src/content/dependencies/generateTrackListItem.js index c8c57534..383f0025 100644 --- a/src/content/dependencies/generateTrackListItem.js +++ b/src/content/dependencies/generateTrackListItem.js @@ -25,6 +25,9 @@ export default { }), data: (track, _contextContributions) => ({ + date: + track.date, + duration: track.duration ?? 0, @@ -47,6 +50,11 @@ export default { default: false, }, + showDate: { + validate: v => v.anyOf(v.isBoolean, v.isDate), + default: false, + }, + colorMode: { validate: v => v.is('none', 'track', 'line'), default: 'track', @@ -62,48 +70,83 @@ export default { language.encapsulate(itemCapsule, workingCapsule => { const workingOptions = {}; - workingOptions.track = - relations.trackLink - .slot('color', slots.colorMode === 'track'); + const accent = + language.encapsulate(itemCapsule, 'accent', accentCapsule => { + let workingCapsule = accentCapsule; + let workingOptions = {}; + let any = false; + + if (slots.showDate) { + any = true; + workingCapsule += '.withDate'; + workingOptions.date = + language.$(accentCapsule, 'date', { + date: + (slots.showDate === true + ? language.formatDate(data.date) + : language.formatDate(slots.showDate)), + }); + } + + if (slots.showDuration) { + any = true; + workingCapsule += '.withDuration'; + workingOptions.duration = + (data.trackHasDuration + ? language.$(accentCapsule, 'duration', { + duration: + language.formatDuration(data.duration), + }) + : relations.missingDuration); + } + + if (any) { + return language.$(workingCapsule, workingOptions); + } else { + return html.blank(); + } + }); - if (slots.showDuration) { - workingCapsule += '.withDuration'; - workingOptions.duration = - (data.trackHasDuration - ? language.$(itemCapsule, 'withDuration.duration', { - duration: - language.formatDuration(data.duration), - }) - : relations.missingDuration); + if (!html.isBlank(accent)) { + workingCapsule += '.withAccent'; + workingOptions.accent = accent; } - const chosenCredit = - (slots.showArtists === true - ? relations.acontextualCredit - : slots.showArtists === 'auto' - ? relations.contextualCredit - : null); - - if (chosenCredit) { - const artistCapsule = language.encapsulate(itemCapsule, 'withArtists'); - - chosenCredit.setSlots({ - normalStringKey: - artistCapsule + '.by', - - featuringStringKey: - artistCapsule + '.featuring', + workingOptions.track = + relations.trackLink + .slot('color', slots.colorMode === 'track'); - normalFeaturingStringKey: - artistCapsule + '.by.featuring', + const artists = + language.encapsulate(itemCapsule, 'artists', artistsCapsule => { + const chosenCredit = + (slots.showArtists === true + ? relations.acontextualCredit + : slots.showArtists === 'auto' + ? relations.contextualCredit + : null); + + if (!chosenCredit) { + return html.blank(); + } + + // This might still be blank, if the contextual credit is chosen + // and it matches its context credit. + return chosenCredit.slots({ + normalStringKey: + artistsCapsule + '.by', + + featuringStringKey: + artistsCapsule + '.featuring', + + normalFeaturingStringKey: + artistsCapsule + '.by.featuring', + }); }); - if (!html.isBlank(chosenCredit)) { - workingCapsule += '.withArtists'; - workingOptions.by = - html.tag('span', {class: 'by'}, - chosenCredit); - } + if (!html.isBlank(artists)) { + workingCapsule += '.withArtists'; + workingOptions.artists = + html.tag('span', {class: 'by'}, artists); } return language.$(workingCapsule, workingOptions); diff --git a/src/content/dependencies/generateTrackListMissingDuration.js b/src/content/dependencies/generateTrackListMissingDuration.js index 70db23c2..f3c5c6ce 100644 --- a/src/content/dependencies/generateTrackListMissingDuration.js +++ b/src/content/dependencies/generateTrackListMissingDuration.js @@ -8,27 +8,26 @@ export default { }), generate: (relations, {html, language}) => - language.encapsulate('trackList.item.withDuration', itemCapsule => - language.encapsulate(itemCapsule, 'duration', durationCapsule => - relations.textWithTooltip.slots({ - attributes: {class: 'missing-duration'}, - customInteractionCue: true, + language.encapsulate('trackList.item.accent.duration', capsule => + relations.textWithTooltip.slots({ + attributes: {class: 'missing-duration'}, + customInteractionCue: true, - text: - language.$(durationCapsule, { - duration: - html.tag('span', {class: 'text-with-tooltip-interaction-cue'}, - {tabindex: '0'}, + text: + language.$(capsule, { + duration: + html.tag('span', {class: 'text-with-tooltip-interaction-cue'}, + {tabindex: '0'}, - language.$(durationCapsule, 'missing')), - }), + language.$(capsule, 'missing')), + }), - tooltip: - relations.tooltip.slots({ - attributes: {class: 'missing-duration-tooltip'}, + tooltip: + relations.tooltip.slots({ + attributes: {class: 'missing-duration-tooltip'}, - content: - language.$(durationCapsule, 'missing.info'), - }), - }))), + content: + language.$(capsule, 'missing.info'), + }), + })), }; diff --git a/src/strings-default.yaml b/src/strings-default.yaml index daca8347..e8bda92f 100644 --- a/src/strings-default.yaml +++ b/src/strings-default.yaml @@ -447,25 +447,35 @@ trackList: item: _: "{TRACK}" - withDuration: - _: >- - {DURATION} {TRACK} + withAccent: >- + {ACCENT} {TRACK} - duration: - _: "({DURATION})" - missing: "_:__" - missing.info: "no duration provided; treated as zero seconds long" + accent.withDate: >- + ({DATE}) - withArtists: - _: >- - {TRACK} {BY} + accent.withDate.withDuration: >- + ({DURATION}; {DATE}) + + accent.withDuration: >- + ({DURATION}) + + accent.date: "{DATE}" + + accent.duration: + _: "{DURATION}" + missing: "_:__" + missing.info: "no duration provided; treated as zero seconds long" + + withArtists: >- + {TRACK} {ARTISTS} + artists: by: "by {ARTISTS}" featuring: "feat. {ARTISTS}" by.featuring: "by {ARTISTS} feat. {FEATURING}" - withDuration.withArtists: >- - {DURATION} {TRACK} {BY} + withAccent.withArtists: >- + {ACCENT} {TRACK} {ARTISTS} rerelease: >- {TRACK} (rerelease) |