diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2024-11-19 13:25:22 -0400 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2024-11-19 13:25:22 -0400 |
commit | 7cb88275fd3c813114271c0a136b12c72c5a172a (patch) | |
tree | b3b007e73c4681e206162362f5d9a8b99b6762d7 /src | |
parent | 943cb8d05f5ef8572edfa081fb9912107769241a (diff) |
content: decompose generateCoverArtwork
No visual/site changes yet. This involves introducing an unfortunate mega-hack in generateStickyHeadingContainer, which sets slots on cover artworks. Very scary. Oooooo Otherwise, all cover artwork code is much more compositional. Pass-through slots (`image`) are removed in generateCoverArtwork and a partially-formed `image` slot is accepted instead.
Diffstat (limited to 'src')
9 files changed, 257 insertions, 160 deletions
diff --git a/src/content/dependencies/generateAlbumCoverArtwork.js b/src/content/dependencies/generateAlbumCoverArtwork.js index 99003034..f6583882 100644 --- a/src/content/dependencies/generateAlbumCoverArtwork.js +++ b/src/content/dependencies/generateAlbumCoverArtwork.js @@ -1,10 +1,25 @@ export default { - contentDependencies: ['generateCoverArtwork'], - extraDependencies: ['language'], + contentDependencies: [ + 'generateCoverArtwork', + 'generateCoverArtworkArtTagDetails', + 'generateCoverArtworkArtistDetails', + 'image', + ], + + extraDependencies: ['html', 'language'], relations: (relation, album) => ({ coverArtwork: - relation('generateCoverArtwork', album.artTags, album.coverArtistContribs), + relation('generateCoverArtwork'), + + image: + relation('image'), + + artTagDetails: + relation('generateCoverArtworkArtTagDetails', album.artTags), + + artistDetails: + relation('generateCoverArtworkArtistDetails', album.coverArtistContribs), }), data: (album) => ({ @@ -18,11 +33,29 @@ export default { album.coverArtDimensions, }), - generate: (data, relations, {language}) => + slots: { + details: { + validate: v => v.is('tags', 'artists'), + default: 'tags', + }, + }, + + generate: (data, relations, slots, {language}) => relations.coverArtwork.slots({ - path: data.path, - color: data.color, + image: + relations.image.slots({ + path: data.path, + color: data.color, + alt: language.$('misc.alt.albumCover'), + }), + dimensions: data.dimensions, - alt: language.$('misc.alt.albumCover'), + + details: + (slots.details === 'tags' + ? relations.artTagDetails + : slots.details === 'artists' + ? relations.artistDetails + : null), }), }; diff --git a/src/content/dependencies/generateCoverArtwork.js b/src/content/dependencies/generateCoverArtwork.js index 70d71bc6..50089f69 100644 --- a/src/content/dependencies/generateCoverArtwork.js +++ b/src/content/dependencies/generateCoverArtwork.js @@ -1,83 +1,29 @@ -import {stitchArrays} from '#sugar'; - export default { - contentDependencies: ['image', 'linkArtTag', 'linkArtistGallery'], - extraDependencies: ['html', 'language'], - - query: (artTags, _coverArtistContribs) => ({ - linkableArtTags: - (artTags - ? artTags.filter(tag => !tag.isContentWarning) - : []), - }), - - relations: (relation, query, artTags, coverArtistContribs) => ({ - image: - relation('image', artTags), - - tagLinks: - query.linkableArtTags - .map(tag => relation('linkArtTag', tag)), - - artistLinks: - coverArtistContribs - .map(contrib => contrib.artist) - .map(artist => - relation('linkArtistGallery', artist)), - }), - - data: (query, _artTags, _coverArtistContribs) => { - const data = {}; - - const seenShortNames = new Set(); - const duplicateShortNames = new Set(); - - for (const {nameShort: shortName} of query.linkableArtTags) { - if (seenShortNames.has(shortName)) { - duplicateShortNames.add(shortName); - } else { - seenShortNames.add(shortName); - } - } - - data.preferShortName = - query.linkableArtTags - .map(artTag => !duplicateShortNames.has(artTag.nameShort)); - - return data; - }, + contentDependencies: ['image', 'linkArtistGallery'], + extraDependencies: ['html'], slots: { - path: { - validate: v => v.validateArrayItems(v.isString), - }, - - alt: { - type: 'string', - }, - - color: { - validate: v => v.isColor, + image: { + type: 'html', + mutable: true, }, mode: { - validate: v => - v.is(...[ - 'primary-tags', - 'primary-artists', - 'thumbnail', - 'commentary', - ]), - - default: 'primary-tags', + validate: v => v.is('primary', 'thumbnail', 'commentary'), + default: 'primary', }, dimensions: { validate: v => v.isDimensions, }, + + details: { + type: 'html', + mutable: false, + }, }, - generate(data, relations, slots, {html, language}) { + generate(slots, {html}) { const square = (slots.dimensions ? slots.dimensions[0] === slots.dimensions[1] @@ -88,83 +34,38 @@ export default { ? {square: true} : {dimensions: slots.dimensions}); - switch (slots.mode) { - case 'primary-tags': - return html.tags([ - relations.image.slots({ - path: slots.path, - alt: slots.alt, - color: slots.color, + return html.tags([ + (slots.mode === 'primary' + ? slots.image.slots({ thumb: 'medium', reveal: true, link: true, ...sizeSlots, - }), - - html.tag('ul', {class: 'image-details'}, - {[html.onlyIfContent]: true}, + }) - {class: 'art-tag-details'}, - - stitchArrays({ - tagLink: relations.tagLinks, - preferShortName: data.preferShortName, - }).map(({tagLink, preferShortName}) => - html.tag('li', - tagLink.slot('preferShortName', preferShortName)))), - ]); + : slots.mode === 'thumbnail' + ? slots.image.slots({ + thumb: 'small', + reveal: false, + link: false, + ...sizeSlots, + }) - case 'primary-artists': - return html.tags([ - relations.image.slots({ - path: slots.path, - alt: slots.alt, - color: slots.color, + : slots.mode === 'commentary' + ? slots.image.slots({ thumb: 'medium', reveal: true, link: true, + lazy: true, ...sizeSlots, - }), - - html.tag('p', {class: 'image-details'}, - {[html.onlyIfContent]: true}, - - {class: 'illustrator-details'}, - - language.$('misc.coverGrid.details.coverArtists', { - artists: - language.formatConjunctionList(relations.artistLinks), - })), - ]); - - case 'thumbnail': - return relations.image.slots({ - path: slots.path, - alt: slots.alt, - color: slots.color, - thumb: 'small', - reveal: false, - link: false, - ...sizeSlots, - }); - case 'commentary': - return relations.image.slots({ - path: slots.path, - alt: slots.alt, - color: slots.color, - thumb: 'medium', - reveal: true, - link: true, - lazy: true, - ...sizeSlots, + attributes: + {class: 'commentary-art'}, + }) - attributes: - {class: 'commentary-art'}, - }); + : html.blank()), - default: - return html.blank(); - } + html.tags([slots.details], {[html.onlyIfSiblings]: true}), + ]); }, }; diff --git a/src/content/dependencies/generateCoverArtworkArtTagDetails.js b/src/content/dependencies/generateCoverArtworkArtTagDetails.js new file mode 100644 index 00000000..81ead8a9 --- /dev/null +++ b/src/content/dependencies/generateCoverArtworkArtTagDetails.js @@ -0,0 +1,50 @@ +import {stitchArrays} from '#sugar'; + +export default { + contentDependencies: ['linkArtTag'], + extraDependencies: ['html'], + + query: (artTags) => ({ + linkableArtTags: + artTags + .filter(tag => !tag.isContentWarning), + }), + + relations: (relation, query, _artTags) => ({ + tagLinks: + query.linkableArtTags + .map(tag => relation('linkArtTag', tag)), + }), + + data: (query, _artTags) => { + const seenShortNames = new Set(); + const duplicateShortNames = new Set(); + + for (const {nameShort: shortName} of query.linkableArtTags) { + if (seenShortNames.has(shortName)) { + duplicateShortNames.add(shortName); + } else { + seenShortNames.add(shortName); + } + } + + const preferShortName = + query.linkableArtTags + .map(artTag => !duplicateShortNames.has(artTag.nameShort)); + + return {preferShortName}; + }, + + generate: (data, relations, {html}) => + html.tag('ul', {class: 'image-details'}, + {[html.onlyIfContent]: true}, + + {class: 'art-tag-details'}, + + stitchArrays({ + tagLink: relations.tagLinks, + preferShortName: data.preferShortName, + }).map(({tagLink, preferShortName}) => + html.tag('li', + tagLink.slot('preferShortName', preferShortName)))), +}; diff --git a/src/content/dependencies/generateCoverArtworkArtistDetails.js b/src/content/dependencies/generateCoverArtworkArtistDetails.js new file mode 100644 index 00000000..5b235353 --- /dev/null +++ b/src/content/dependencies/generateCoverArtworkArtistDetails.js @@ -0,0 +1,23 @@ +export default { + contentDependencies: ['linkArtistGallery'], + extraDependencies: ['html', 'language'], + + relations: (relation, contributions) => ({ + artistLinks: + contributions + .map(contrib => contrib.artist) + .map(artist => + relation('linkArtistGallery', artist)), + }), + + generate: (relations, {html, language}) => + html.tag('p', {class: 'image-details'}, + {[html.onlyIfContent]: true}, + + {class: 'illustrator-details'}, + + language.$('misc.coverGrid.details.coverArtists', { + artists: + language.formatConjunctionList(relations.artistLinks), + })), +}; diff --git a/src/content/dependencies/generateFlashCoverArtwork.js b/src/content/dependencies/generateFlashCoverArtwork.js index bcf2a55c..02590a09 100644 --- a/src/content/dependencies/generateFlashCoverArtwork.js +++ b/src/content/dependencies/generateFlashCoverArtwork.js @@ -4,7 +4,10 @@ export default { relations: (relation) => ({ coverArtwork: - relation('generateCoverArtwork', [], []), + relation('generateCoverArtwork'), + + image: + relation('image'), }), data: (flash) => ({ @@ -20,9 +23,13 @@ export default { generate: (data, relations, {language}) => relations.coverArtwork.slots({ - path: data.path, - color: data.color, + image: + relations.image.slots({ + data: data.path, + color: data.color, + alt: language.$('misc.alt.flashArt'), + }), + dimensions: data.dimensions, - alt: language.$('misc.alt.flashArt'), }), }; diff --git a/src/content/dependencies/generateReferencedArtworksPage.js b/src/content/dependencies/generateReferencedArtworksPage.js index fa65a245..3d21b15d 100644 --- a/src/content/dependencies/generateReferencedArtworksPage.js +++ b/src/content/dependencies/generateReferencedArtworksPage.js @@ -77,8 +77,7 @@ export default { styleRules: slots.styleRules, cover: - slots.cover - .slot('mode', 'primary-artists'), + slots.cover.slot('details', 'artists'), mainClasses: ['top-index'], mainContent: [ diff --git a/src/content/dependencies/generateReferencingArtworksPage.js b/src/content/dependencies/generateReferencingArtworksPage.js index 468d5f78..78dae5b0 100644 --- a/src/content/dependencies/generateReferencingArtworksPage.js +++ b/src/content/dependencies/generateReferencingArtworksPage.js @@ -77,8 +77,7 @@ export default { styleRules: slots.styleRules, cover: - slots.cover - .slot('mode', 'primary-artists'), + slots.cover.slot('details', 'artists'), mainClasses: ['top-index'], mainContent: [ diff --git a/src/content/dependencies/generateStickyHeadingContainer.js b/src/content/dependencies/generateStickyHeadingContainer.js index 7f271715..ab607a4f 100644 --- a/src/content/dependencies/generateStickyHeadingContainer.js +++ b/src/content/dependencies/generateStickyHeadingContainer.js @@ -28,11 +28,63 @@ export default { html.tag('div', {class: 'content-sticky-heading-cover'}, {[html.onlyIfContent]: true}, - // TODO: We shouldn't need to do an isBlank check here, - // but a live blank value doesn't have a slot functions, so. - (html.isBlank(slots.cover) - ? html.blank() - : slots.cover.slot('mode', 'thumbnail')))), + (() => { + if (html.isBlank(slots.cover)) { + return html.blank(); + } + + // Try very hard to set the cover's 'mode' slot to 'thumbnail' + // and its 'details' slot to html.blank(). + let setMode = false; + let setDetails = false; + let cover = slots.cover; + while (true) { + if (!cover) { + return html.blank(); + } + + if (!(cover instanceof html.Template)) { + return cover; + } + + // The cover from `slots` is already cloned (since it's + // mutable), but later ones are not, and for extremely scary + // content function infrastructure reasons, it is possible + // for the identity of the content of the clone-template + // to be the same as the cloned template. + if (cover !== slots.cover) { + cover = cover.clone(); + } + + if (!setMode) { + try { + cover.setSlot('mode', 'thumbnail'); + setMode = true; + } catch { + // No mode slot, or it doesn't allow 'thumbnail'. + } + } + + if (!setDetails) { + try { + cover.setSlot('details', html.blank()); + setDetails = true; + } catch { + // No details slot, or it doesn't allow html.blank(). + // We're setting a blank instead of null because null is + // always allowed, and can carry a different semantic + // meaning, like "put something else here by default + // instead please". + } + } + + if (setMode && setDetails) { + return cover; + } + + cover = cover.content; + } + })())), ]), html.tag('div', {class: 'content-sticky-subheading-row'}, diff --git a/src/content/dependencies/generateTrackCoverArtwork.js b/src/content/dependencies/generateTrackCoverArtwork.js index 64690c71..f75bf00b 100644 --- a/src/content/dependencies/generateTrackCoverArtwork.js +++ b/src/content/dependencies/generateTrackCoverArtwork.js @@ -1,13 +1,28 @@ export default { - contentDependencies: ['generateCoverArtwork'], - extraDependencies: ['language'], + contentDependencies: [ + 'generateCoverArtwork', + 'generateCoverArtworkArtTagDetails', + 'generateCoverArtworkArtistDetails', + 'image', + ], + + extraDependencies: ['html', 'language'], relations: (relation, track) => ({ coverArtwork: - relation('generateCoverArtwork', + relation('generateCoverArtwork'), + + image: + relation('image'), + + artTagDetails: + relation('generateCoverArtworkArtTagDetails', (track.hasUniqueCoverArt ? track.artTags - : track.album.artTags), + : track.album.artTags)), + + artistDetails: + relation('generateCoverArtworkArtistDetails', (track.hasUniqueCoverArt ? track.coverArtistContribs : track.album.coverArtistContribs)), @@ -28,12 +43,30 @@ export default { : track.album.coverArtDimensions), }), - generate: (data, relations, {language}) => + slots: { + details: { + validate: v => v.is('tags', 'artists'), + default: 'tags', + }, + }, + + generate: (data, relations, slots, {language}) => relations.coverArtwork.slots({ - path: data.path, - color: data.color, + image: + relations.image.slots({ + path: data.path, + color: data.color, + alt: language.$('misc.alt.trackCover'), + }), + dimensions: data.dimensions, - alt: language.$('misc.alt.trackCover'), + + details: + (slots.details === 'tags' + ? relations.artTagDetails + : slots.details === 'artists' + ? relations.artistDetails + : null), }), }; |