diff options
Diffstat (limited to 'src/content')
| -rw-r--r-- | src/content/dependencies/generateAlbumReleaseInfo.js | 88 | ||||
| -rw-r--r-- | src/content/dependencies/generateArtistInfoPage.js | 21 | ||||
| -rw-r--r-- | src/content/dependencies/generateExternalLinksLineOrList.js | 99 | ||||
| -rw-r--r-- | src/content/dependencies/generateListenLineOrList.js (renamed from src/content/dependencies/generateReleaseInfoListenLine.js) | 40 | ||||
| -rw-r--r-- | src/content/dependencies/generateReleaseInfoBlock.js | 64 | ||||
| -rw-r--r-- | src/content/dependencies/generateTrackReleaseInfo.js | 92 |
6 files changed, 267 insertions, 137 deletions
diff --git a/src/content/dependencies/generateAlbumReleaseInfo.js b/src/content/dependencies/generateAlbumReleaseInfo.js index 4cec4120..38cd1c05 100644 --- a/src/content/dependencies/generateAlbumReleaseInfo.js +++ b/src/content/dependencies/generateAlbumReleaseInfo.js @@ -1,17 +1,16 @@ import {accumulateSum, empty} from '#sugar'; export default { - relations(relation, album) { - const relations = {}; + relations: (relation, album) => ({ + block: + relation('generateReleaseInfoBlock'), - relations.artistContributionsLine = - relation('generateReleaseInfoContributionsLine', album.artistContribs); + artistContributionsLine: + relation('generateReleaseInfoContributionsLine', album.artistContribs), - relations.listenLine = - relation('generateReleaseInfoListenLine', album); - - return relations; - }, + listenLineOrList: + relation('generateListenLineOrList', album), + }), data(album) { const data = {}; @@ -45,44 +44,37 @@ export default { generate: (data, relations, {html, language}) => language.encapsulate('releaseInfo', capsule => html.tags([ - html.tag('p', - {[html.onlyIfContent]: true}, - {[html.joinChildren]: html.tag('br')}, - - [ - relations.artistContributionsLine.slots({ - stringKey: capsule + '.by', - featuringStringKey: capsule + '.by.featuring', - chronologyKind: 'album', - }), - - language.$(capsule, 'released', { - [language.onlyIfOptions]: ['date'], - date: language.formatDate(data.date), - }), - - language.$(capsule, 'duration', { - [language.onlyIfOptions]: ['duration'], - duration: - language.formatDuration(data.duration, { - approximate: data.durationApproximate, - }), - }), - ]), - - html.tag('p', - {[html.onlyIfContent]: true}, - - relations.listenLine.slots({ - context: [ - 'album', - - (data.numTracks === 0 - ? 'albumNoTracks' - : data.numTracks === 1 - ? 'albumOneTrack' - : 'albumMultipleTracks'), - ], - })), + relations.block.slot('items', [ + relations.artistContributionsLine.slots({ + stringKey: capsule + '.by', + featuringStringKey: capsule + '.by.featuring', + chronologyKind: 'album', + }), + + language.$(capsule, 'released', { + [language.onlyIfOptions]: ['date'], + date: language.formatDate(data.date), + }), + + language.$(capsule, 'duration', { + [language.onlyIfOptions]: ['duration'], + duration: + language.formatDuration(data.duration, { + approximate: data.durationApproximate, + }), + }), + ]), + + relations.listenLineOrList.slots({ + context: [ + 'album', + + (data.numTracks === 0 + ? 'albumNoTracks' + : data.numTracks === 1 + ? 'albumOneTrack' + : 'albumMultipleTracks'), + ], + }), ])), }; diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js index 45b111ed..ae21b361 100644 --- a/src/content/dependencies/generateArtistInfoPage.js +++ b/src/content/dependencies/generateArtistInfoPage.js @@ -60,9 +60,8 @@ export default { query.aliasLinkedGroups .map(({group}) => relation('linkGroup', group)), - visitLinks: - artist.urls - .map(entry => relation('linkExternal', entry)), + externalLinksLineOrList: + relation('generateExternalLinksLineOrList', artist.urls), tracksChunkedList: relation('generateArtistInfoPageTracksChunkedList', artist), @@ -182,17 +181,11 @@ export default { }), ])), - html.tag('p', - {[html.onlyIfContent]: true}, - - language.$('releaseInfo.visitOn', { - [language.onlyIfOptions]: ['links'], - - links: - language.formatDisjunctionList( - relations.visitLinks - .map(link => link.slot('context', 'artist'))), - })), + relations.externalLinksLineOrList.slots({ + string: 'releaseInfo.visitOn', + maximumTotalEntriesInLine: 5, + maximumAnnotatedEntriesInLine: 3, + }), html.tag('p', {[html.onlyIfContent]: true}, diff --git a/src/content/dependencies/generateExternalLinksLineOrList.js b/src/content/dependencies/generateExternalLinksLineOrList.js new file mode 100644 index 00000000..18922db6 --- /dev/null +++ b/src/content/dependencies/generateExternalLinksLineOrList.js @@ -0,0 +1,99 @@ +import {isExternalLinkContext} from '#external-links'; +import {empty, stitchArrays} from '#sugar'; + +export default { + relations: (relation, urlEntries) => ({ + externalLinks: + urlEntries.map(entry => relation('linkExternal', entry)), + }), + + data: (urlEntries) => ({ + totalEntries: + urlEntries.length, + + annotatedEntries: + urlEntries.filter(entry => entry.annotation).length, + }), + + slots: { + string: {type: 'string'}, + + context: { + validate: () => isExternalLinkContext, + default: 'generic', + }, + + contexts: { + validate: v => v.strictArrayOf(isExternalLinkContext), + default: [], + }, + + maximumTotalEntriesInLine: {type: 'number', default: 4}, + maximumAnnotatedEntriesInLine: {type: 'number', default: 1}, + maximumParenthesizedEntriesInLine: {type: 'number', default: 3}, + }, + + generate(data, relations, slots, {html, language}) { + const {externalLinks} = relations; + + if (empty(externalLinks)) { + return html.blank(); + } + + if (!html.isBlank(slots.contexts)) { + stitchArrays({ + link: externalLinks, + linkContext: slots.contexts, + }).forEach(({link, linkContext}) => { + link.setSlot('context', [slots.context, linkContext].flat(Infinity)); + }); + } else { + externalLinks.forEach(link => { + link.setSlot('context', slots.context); + }); + } + + let style = 'line'; + + if (data.totalEntries > slots.maximumTotalEntriesInLine) { + style = 'list'; + } + + if (data.annotatedEntries > slots.maximumAnnotatedEntriesInLine) { + style = 'list'; + } + + let parenthesizedEntries = 0; + for (const item of externalLinks) { + const plainText = html.resolve(item, {normalize: 'plain'}); + if (plainText.endsWith(')')) { + parenthesizedEntries++; + } + } + + if (parenthesizedEntries > slots.maximumParenthesizedEntriesInLine) { + style = 'list'; + } + + switch (style) { + case 'line': return ( + html.tag('p', + language.$(slots.string, { + links: + language.formatDisjunctionList(externalLinks), + })) + ); + + case 'list': return ( + html.tags([ + html.tag('p', language.$(slots.string, 'title')), + html.tag('ul', + externalLinks.map(link => html.tag('li', link))), + ]) + ); + + default: + return html.blank(); + } + }, +}; diff --git a/src/content/dependencies/generateReleaseInfoListenLine.js b/src/content/dependencies/generateListenLineOrList.js index 54e7985f..f0d8dae9 100644 --- a/src/content/dependencies/generateReleaseInfoListenLine.js +++ b/src/content/dependencies/generateListenLineOrList.js @@ -1,5 +1,5 @@ import {isExternalLinkContext} from '#external-links'; -import {empty, stitchArrays, unique} from '#sugar'; +import {empty, unique} from '#sugar'; function getReleaseContext(urlString, { _artistURLs, @@ -13,14 +13,14 @@ function getReleaseContext(urlString, { const url = new URL(urlString); if (url.hostname === 'homestuck.bandcamp.com') { - return 'officialRelease'; + return ['officialRelease']; } if (composerBandcampDomains.includes(url.hostname)) { - return 'composerRelease'; + return ['composerRelease']; } - return null; + return []; } export default { @@ -63,9 +63,8 @@ export default { }, relations: (relation, query, _thing) => ({ - links: - query.urls - .map(entry => relation('linkExternal', entry)), + externalLinksLineOrList: + relation('generateExternalLinksLineOrList', query.urls), }), data(query, thing) { @@ -73,6 +72,8 @@ export default { data.name = thing.name; + data.noLinks = empty(query.urls); + const artistURLs = unique([ ...query.artists.flatMap(artist => artist.urls), @@ -108,7 +109,7 @@ export default { presentAlbumReleaseContexts.length <= 1 ) { releaseContexts = - query.urls.map(() => null); + query.urls.map(() => []); } data.releaseContexts = releaseContexts; @@ -130,28 +131,15 @@ export default { generate: (data, relations, slots, {html, language}) => language.encapsulate('releaseInfo.listenOn', capsule => - (empty(relations.links) && slots.visibleWithoutLinks + (data.noLinks && slots.visibleWithoutLinks ? language.$(capsule, 'noLinks', { name: html.tag('i', data.name), }) - : language.$('releaseInfo.listenOn', { - [language.onlyIfOptions]: ['links'], - - links: - language.formatDisjunctionList( - stitchArrays({ - link: relations.links, - releaseContext: data.releaseContexts, - }).map(({link, releaseContext}) => - link.slot('context', [ - ... - (Array.isArray(slots.context) - ? slots.context - : [slots.context]), - - releaseContext, - ]))), + : relations.externalLinksLineOrList.slots({ + string: capsule, + context: slots.context, + contexts: data.releaseContexts, }))), }; diff --git a/src/content/dependencies/generateReleaseInfoBlock.js b/src/content/dependencies/generateReleaseInfoBlock.js new file mode 100644 index 00000000..93d889ab --- /dev/null +++ b/src/content/dependencies/generateReleaseInfoBlock.js @@ -0,0 +1,64 @@ +import {empty} from '#sugar'; + +export default { + slots: { + // This isn't mutable, but we will be inspecting items' contents. + items: {validate: v => v.looseArrayOf(v.isHTML)}, + }, + + generate(slots, {html}) { + const tags = []; + + let paragraphLines = []; + const closeParagraph = () => { + if (empty(paragraphLines)) return; + + const paragraph = + html.tag('p', + {[html.joinChildren]: html.tag('br')}, + {[html.onlyIfContent]: true}, + paragraphLines); + + tags.push(paragraph); + paragraphLines = []; + }; + + for (let item of slots.items) { + item = html.Template.resolve(item); + + if (typeof item === 'string' && item.length) { + paragraphLines.push(item); + continue; + } + + if (html.isBlank(item)) { + continue; + } + + if (item.contentOnly) { + paragraphLines.push(item); + continue; + } + + if (item.tagName === 'br') { + continue; + } + + if (item.tagName === 'p') { + paragraphLines.push(item.content); + continue; + } + + closeParagraph(); + tags.push(item); + } + + closeParagraph(); + + if (empty(tags)) { + return html.blank(); + } else { + return html.tags(tags); + } + } +}; diff --git a/src/content/dependencies/generateTrackReleaseInfo.js b/src/content/dependencies/generateTrackReleaseInfo.js index 0207e574..001f5a54 100644 --- a/src/content/dependencies/generateTrackReleaseInfo.js +++ b/src/content/dependencies/generateTrackReleaseInfo.js @@ -1,22 +1,21 @@ import {compareArrays} from '#sugar'; export default { - relations(relation, track) { - const relations = {}; + relations: (relation, track) => ({ + block: + relation('generateReleaseInfoBlock'), - relations.artistContributionsLine = + artistContributionsLine: relation('generateReleaseInfoContributionsLine', track.artistContribs, - track.artistText); + track.artistText), - relations.listenLine = - relation('generateReleaseInfoListenLine', track); + listenLineOrList: + relation('generateListenLineOrList', track), - relations.albumLink = - relation('linkAlbum', track.album); - - return relations; - }, + albumLink: + relation('linkAlbum', track.album), + }), data(track) { const data = {}; @@ -48,43 +47,38 @@ export default { generate: (data, relations, {html, language}) => language.encapsulate('releaseInfo', capsule => html.tags([ - html.tag('p', - {[html.onlyIfContent]: true}, - {[html.joinChildren]: html.tag('br')}, - - [ - language.encapsulate(capsule, 'by', capsule => { - const withAlbum = - (data.showAlbum ? '.withAlbum' : ''); - - const albumOptions = - (data.showAlbum ? {album: relations.albumLink} : {}); - - return relations.artistContributionsLine.slots({ - stringKey: capsule + withAlbum, - featuringStringKey: capsule + '.featuring' + withAlbum, - - additionalStringOptions: albumOptions, - - chronologyKind: 'track', - }); - }), - - language.$(capsule, 'released', { - [language.onlyIfOptions]: ['date'], - date: language.formatDate(data.date), - }), - - language.$(capsule, 'duration', { - [language.onlyIfOptions]: ['duration'], - duration: language.formatDuration(data.duration), - }), - ]), - - html.tag('p', - relations.listenLine.slots({ - visibleWithoutLinks: true, - context: ['track'], - })), + relations.block.slot('items', [ + language.encapsulate(capsule, 'by', capsule => { + const withAlbum = + (data.showAlbum ? '.withAlbum' : ''); + + const albumOptions = + (data.showAlbum ? {album: relations.albumLink} : {}); + + return relations.artistContributionsLine.slots({ + stringKey: capsule + withAlbum, + featuringStringKey: capsule + '.featuring' + withAlbum, + + additionalStringOptions: albumOptions, + + chronologyKind: 'track', + }); + }), + + language.$(capsule, 'released', { + [language.onlyIfOptions]: ['date'], + date: language.formatDate(data.date), + }), + + language.$(capsule, 'duration', { + [language.onlyIfOptions]: ['duration'], + duration: language.formatDuration(data.duration), + }), + ]), + + relations.listenLineOrList.slots({ + visibleWithoutLinks: true, + context: 'track', + }), ])), }; |