diff options
Diffstat (limited to 'src/content/dependencies')
67 files changed, 1328 insertions, 1180 deletions
diff --git a/src/content/dependencies/generateAlbumArtInfoBox.js b/src/content/dependencies/generateAlbumArtInfoBox.js new file mode 100644 index 00000000..8c44c930 --- /dev/null +++ b/src/content/dependencies/generateAlbumArtInfoBox.js @@ -0,0 +1,39 @@ +export default { + contentDependencies: ['generateReleaseInfoContributionsLine'], + extraDependencies: ['html', 'language'], + + relations: (relation, album) => ({ + wallpaperArtistContributionsLine: + (album.wallpaperArtwork + ? relation('generateReleaseInfoContributionsLine', + album.wallpaperArtwork.artistContribs) + : null), + + bannerArtistContributionsLine: + (album.bannerArtwork + ? relation('generateReleaseInfoContributionsLine', + album.bannerArtwork.artistContribs) + : null), + }), + + generate: (relations, {html, language}) => + language.encapsulate('releaseInfo', capsule => + html.tag('div', {class: 'album-art-info'}, + {[html.onlyIfContent]: true}, + + html.tag('p', + {[html.onlyIfContent]: true}, + {[html.joinChildren]: html.tag('br')}, + + [ + relations.wallpaperArtistContributionsLine?.slots({ + stringKey: capsule + '.wallpaperArtBy', + chronologyKind: 'wallpaperArt', + }), + + relations.bannerArtistContributionsLine?.slots({ + stringKey: capsule + '.bannerArtBy', + chronologyKind: 'bannerArt', + }), + ]))), +}; diff --git a/src/content/dependencies/generateAlbumArtworkColumn.js b/src/content/dependencies/generateAlbumArtworkColumn.js new file mode 100644 index 00000000..e6762463 --- /dev/null +++ b/src/content/dependencies/generateAlbumArtworkColumn.js @@ -0,0 +1,38 @@ +export default { + contentDependencies: ['generateAlbumArtInfoBox', 'generateCoverArtwork'], + extraDependencies: ['html'], + + relations: (relation, album) => ({ + firstCover: + (album.hasCoverArt + ? relation('generateCoverArtwork', album.coverArtworks[0]) + : null), + + restCovers: + (album.hasCoverArt + ? album.coverArtworks.slice(1).map(artwork => + relation('generateCoverArtwork', artwork)) + : []), + + albumArtInfoBox: + relation('generateAlbumArtInfoBox', album), + }), + + generate: (relations, {html}) => + html.tags([ + relations.firstCover?.slots({ + showOriginDetails: true, + showArtTagDetails: true, + showReferenceDetails: true, + }), + + relations.albumArtInfoBox, + + relations.restCovers.map(cover => + cover.slots({ + showOriginDetails: true, + showArtTagDetails: true, + showReferenceDetails: true, + })), + ]), +}; diff --git a/src/content/dependencies/generateAlbumCommentaryPage.js b/src/content/dependencies/generateAlbumCommentaryPage.js index f5df7c3d..1e39b47d 100644 --- a/src/content/dependencies/generateAlbumCommentaryPage.js +++ b/src/content/dependencies/generateAlbumCommentaryPage.js @@ -3,13 +3,12 @@ import {empty, stitchArrays} from '#sugar'; export default { contentDependencies: [ 'generateAlbumCommentarySidebar', - 'generateAlbumCoverArtwork', 'generateAlbumNavAccent', 'generateAlbumSecondaryNav', 'generateAlbumStyleRules', 'generateCommentaryEntry', 'generateContentHeading', - 'generateTrackCoverArtwork', + 'generateCoverArtwork', 'generatePageLayout', 'linkAlbum', 'linkExternal', @@ -66,7 +65,7 @@ export default { if (album.hasCoverArt) { relations.albumCommentaryCover = - relation('generateAlbumCoverArtwork', album); + relation('generateCoverArtwork', album.coverArtworks[0]); } relations.albumCommentaryEntries = @@ -91,7 +90,7 @@ export default { query.tracksWithCommentary .map(track => (track.hasUniqueCoverArt - ? relation('generateTrackCoverArtwork', track) + ? relation('generateCoverArtwork', track.trackArtworks[0]) : null)); relations.trackCommentaryEntries = diff --git a/src/content/dependencies/generateAlbumCoverArtwork.js b/src/content/dependencies/generateAlbumCoverArtwork.js deleted file mode 100644 index ff7d2b85..00000000 --- a/src/content/dependencies/generateAlbumCoverArtwork.js +++ /dev/null @@ -1,100 +0,0 @@ -export default { - contentDependencies: [ - 'generateCoverArtwork', - 'generateCoverArtworkArtTagDetails', - 'generateCoverArtworkArtistDetails', - 'generateCoverArtworkReferenceDetails', - 'image', - 'linkAlbumReferencedArtworks', - 'linkAlbumReferencingArtworks', - ], - - extraDependencies: ['html', 'language'], - - relations: (relation, album) => ({ - coverArtwork: - relation('generateCoverArtwork'), - - image: - relation('image'), - - artTagDetails: - relation('generateCoverArtworkArtTagDetails', album.artTags), - - artistDetails: - relation('generateCoverArtworkArtistDetails', album.coverArtistContribs), - - referenceDetails: - relation('generateCoverArtworkReferenceDetails', - album.referencedArtworks, - album.referencedByArtworks), - - referencedArtworksLink: - relation('linkAlbumReferencedArtworks', album), - - referencingArtworksLink: - relation('linkAlbumReferencingArtworks', album), - }), - - data: (album) => ({ - path: - ['media.albumCover', album.directory, album.coverArtFileExtension], - - color: - album.color, - - dimensions: - album.coverArtDimensions, - - warnings: - album.artTags - .filter(tag => tag.isContentWarning) - .map(tag => tag.name), - }), - - slots: { - mode: {type: 'string'}, - - details: { - validate: v => v.is('tags', 'artists'), - default: 'tags', - }, - - showReferenceLinks: { - type: 'boolean', - default: false, - }, - }, - - generate: (data, relations, slots, {language}) => - relations.coverArtwork.slots({ - mode: slots.mode, - - image: - relations.image.slots({ - path: data.path, - color: data.color, - alt: language.$('misc.alt.albumCover'), - }), - - dimensions: data.dimensions, - warnings: data.warnings, - - details: [ - slots.details === 'tags' && - relations.artTagDetails, - - slots.details === 'artists' && - relations.artistDetails, - - slots.showReferenceLinks && - relations.referenceDetails.slots({ - referencedLink: - relations.referencedArtworksLink, - - referencingLink: - relations.referencingArtworksLink, - }), - ], - }), -}; diff --git a/src/content/dependencies/generateAlbumGalleryAlbumGrid.js b/src/content/dependencies/generateAlbumGalleryAlbumGrid.js new file mode 100644 index 00000000..7f152871 --- /dev/null +++ b/src/content/dependencies/generateAlbumGalleryAlbumGrid.js @@ -0,0 +1,90 @@ +import {stitchArrays} from '#sugar'; + +export default { + contentDependencies: [ + 'generateCoverGrid', + 'image', + 'linkAlbum', + ], + + extraDependencies: ['html', 'language'], + + query: (album) => ({ + artworks: + (album.hasCoverArt + ? album.coverArtworks + : []), + }), + + relations: (relation, query, album) => ({ + coverGrid: + relation('generateCoverGrid'), + + albumLinks: + query.artworks.map(_artwork => + relation('linkAlbum', album)), + + images: + query.artworks + .map(artwork => relation('image', artwork)), + }), + + data: (query, album) => ({ + albumName: + album.name, + + artworkLabels: + query.artworks + .map(artwork => artwork.label), + + artworkArtists: + query.artworks + .map(artwork => artwork.artistContribs + .map(contrib => contrib.artist.name)), + }), + + slots: { + attributes: {type: 'attributes', mutable: false}, + }, + + generate: (data, relations, slots, {html, language}) => + html.tag('div', + {[html.onlyIfContent]: true}, + + slots.attributes, + + [ + relations.coverArtistsLine, + + relations.coverGrid.slots({ + links: + relations.albumLinks, + + names: + data.artworkLabels + .map(label => label ?? data.albumName), + + images: + stitchArrays({ + image: relations.images, + label: data.artworkLabels, + }).map(({image, label}) => + image.slots({ + missingSourceContent: + language.$('misc.albumGalleryGrid.noCoverArt', { + name: + label ?? data.albumName, + }), + })), + + info: + data.artworkArtists.map(artists => + language.$('misc.coverGrid.details.coverArtists', { + [language.onlyIfOptions]: ['artists'], + + artists: + language.formatUnitList(artists), + })), + }), + ]), +}; diff --git a/src/content/dependencies/generateAlbumGalleryPage.js b/src/content/dependencies/generateAlbumGalleryPage.js index b48d92af..2ba3b272 100644 --- a/src/content/dependencies/generateAlbumGalleryPage.js +++ b/src/content/dependencies/generateAlbumGalleryPage.js @@ -1,18 +1,18 @@ -import {compareArrays, stitchArrays} from '#sugar'; +import {stitchArrays, unique} from '#sugar'; +import {getKebabCase} from '#wiki-data'; export default { contentDependencies: [ - 'generateAlbumGalleryCoverArtistsLine', + 'generateAlbumGalleryAlbumGrid', 'generateAlbumGalleryNoTrackArtworksLine', 'generateAlbumGalleryStatsLine', + 'generateAlbumGalleryTrackGrid', 'generateAlbumNavAccent', 'generateAlbumSecondaryNav', 'generateAlbumStyleRules', - 'generateCoverGrid', + 'generateIntrapageDotSwitcher', 'generatePageLayout', - 'image', 'linkAlbum', - 'linkTrack', ], extraDependencies: ['html', 'language'], @@ -20,147 +20,82 @@ export default { query(album) { const query = {}; - const tracksWithUniqueCoverArt = + const trackArtworkLabels = album.tracks - .filter(track => track.hasUniqueCoverArt); - - // Don't display "all artwork by..." for albums where there's - // only one unique artwork in the first place. - if (tracksWithUniqueCoverArt.length > 1) { - const allCoverArtistArrays = - tracksWithUniqueCoverArt - .map(track => track.coverArtistContribs) - .map(contribs => contribs.map(contrib => contrib.artist)); - - const allSameCoverArtists = - allCoverArtistArrays - .slice(1) - .every(artists => compareArrays(artists, allCoverArtistArrays[0])); - - if (allSameCoverArtists) { - query.coverArtistsForAllTracks = - allCoverArtistArrays[0]; - } - } + .map(track => track.trackArtworks + .map(artwork => artwork.label)); + + const recurranceThreshold = 2; + + // This list may include null, if some artworks are not labelled! + // That's expected. + query.recurringTrackArtworkLabels = + unique(trackArtworkLabels.flat()) + .filter(label => + trackArtworkLabels + .filter(labels => labels.includes(label)) + .length >= + (label === null + ? 1 + : recurranceThreshold)); return query; }, - relations(relation, query, album) { - const relations = {}; + relations: (relation, query, album) => ({ + layout: + relation('generatePageLayout'), - relations.layout = - relation('generatePageLayout'); + albumStyleRules: + relation('generateAlbumStyleRules', album, null), - relations.albumStyleRules = - relation('generateAlbumStyleRules', album, null); - - relations.albumLink = - relation('linkAlbum', album); - - relations.albumNavAccent = - relation('generateAlbumNavAccent', album, null); - - relations.secondaryNav = - relation('generateAlbumSecondaryNav', album); - - relations.statsLine = - relation('generateAlbumGalleryStatsLine', album); - - if (album.tracks.every(track => !track.hasUniqueCoverArt)) { - relations.noTrackArtworksLine = - relation('generateAlbumGalleryNoTrackArtworksLine'); - } - - if (query.coverArtistsForAllTracks) { - relations.coverArtistsLine = - relation('generateAlbumGalleryCoverArtistsLine', query.coverArtistsForAllTracks); - } - - relations.coverGrid = - relation('generateCoverGrid'); - - relations.links = [ + albumLink: relation('linkAlbum', album), - ... - album.tracks - .map(track => relation('linkTrack', track)), - ]; - - relations.images = [ - (album.hasCoverArt - ? relation('image', album.artTags) - : relation('image')), + albumNavAccent: + relation('generateAlbumNavAccent', album, null), - ... - album.tracks.map(track => - (track.hasUniqueCoverArt - ? relation('image', track.artTags) - : relation('image'))), - ]; - - return relations; - }, + secondaryNav: + relation('generateAlbumSecondaryNav', album), - data(query, album) { - const data = {}; + statsLine: + relation('generateAlbumGalleryStatsLine', album), - data.name = album.name; - data.color = album.color; - - data.names = [ - album.name, - ...album.tracks.map(track => track.name), - ]; - - data.coverArtists = [ - (album.hasCoverArt - ? album.coverArtistContribs.map(({artist}) => artist.name) + noTrackArtworksLine: + (album.tracks.every(track => !track.hasUniqueCoverArt) + ? relation('generateAlbumGalleryNoTrackArtworksLine') : null), - ... - album.tracks.map(track => { - if (query.coverArtistsForAllTracks) { - return null; - } + setSwitcher: + relation('generateIntrapageDotSwitcher'), - if (track.hasUniqueCoverArt) { - return track.coverArtistContribs.map(({artist}) => artist.name); - } + albumGrid: + relation('generateAlbumGalleryAlbumGrid', album), - return null; - }), - ]; - - data.paths = [ - (album.hasCoverArt - ? ['media.albumCover', album.directory, album.coverArtFileExtension] - : null), + trackGrids: + query.recurringTrackArtworkLabels.map(label => + relation('generateAlbumGalleryTrackGrid', album, label)), + }), - ... - album.tracks.map(track => - (track.hasUniqueCoverArt - ? ['media.trackCover', track.album.directory, track.directory, track.coverArtFileExtension] - : null)), - ]; + data: (query, album) => ({ + trackGridLabels: + query.recurringTrackArtworkLabels, - data.dimensions = [ - (album.hasCoverArt - ? album.coverArtDimensions - : null), + trackGridIDs: + query.recurringTrackArtworkLabels.map(label => + 'track-grid-' + + (label + ? getKebabCase(label) + : 'no-label')), - ... - album.tracks.map(track => - (track.hasUniqueCoverArt - ? track.coverArtDimensions - : null)), - ]; + name: + album.name, - return data; - }, + color: + album.color, + }), - generate: (data, relations, {language}) => + generate: (data, relations, {html, language}) => language.encapsulate('albumGalleryPage', pageCapsule => relations.layout.slots({ title: @@ -176,34 +111,39 @@ export default { mainClasses: ['top-index'], mainContent: [ relations.statsLine, - relations.coverArtistsLine, + + relations.albumGrid, + relations.noTrackArtworksLine, - relations.coverGrid - .slots({ - links: relations.links, - names: data.names, - images: - stitchArrays({ - image: relations.images, - path: data.paths, - dimensions: data.dimensions, - name: data.names, - }).map(({image, path, dimensions, name}) => - image.slots({ - path, - dimensions, - missingSourceContent: - language.$('misc.albumGalleryGrid.noCoverArt', {name}), - })), - info: - data.coverArtists.map(names => - (names === null - ? null - : language.$('misc.coverGrid.details.coverArtists', { - artists: language.formatUnitList(names), - }))), - }), + data.trackGridLabels.some(value => value !== null) && + html.tag('p', {class: 'gallery-set-switcher'}, + language.encapsulate(pageCapsule, 'setSwitcher', switcherCapsule => + language.$(switcherCapsule, { + sets: + relations.setSwitcher.slots({ + initialOptionIndex: 0, + + titles: + data.trackGridLabels.map(label => + label ?? + language.$(switcherCapsule, 'unlabeledSet')), + + targetIDs: + data.trackGridIDs, + }), + }))), + + stitchArrays({ + grid: relations.trackGrids, + id: data.trackGridIDs, + }).map(({grid, id}, index) => + grid.slots({ + attributes: [ + {id}, + index >= 1 && {style: 'display: none'}, + ], + })), ], navLinkStyle: 'hierarchical', diff --git a/src/content/dependencies/generateAlbumGalleryTrackGrid.js b/src/content/dependencies/generateAlbumGalleryTrackGrid.js new file mode 100644 index 00000000..85e7576c --- /dev/null +++ b/src/content/dependencies/generateAlbumGalleryTrackGrid.js @@ -0,0 +1,122 @@ +import {compareArrays, stitchArrays} from '#sugar'; + +export default { + contentDependencies: [ + 'generateAlbumGalleryCoverArtistsLine', + 'generateCoverGrid', + 'image', + 'linkAlbum', + 'linkTrack', + ], + + extraDependencies: ['html', 'language'], + + query(album, label) { + const query = {}; + + query.artworks = + album.tracks.map(track => + track.trackArtworks.find(artwork => artwork.label === label) ?? + null); + + const presentArtworks = + query.artworks.filter(Boolean); + + if (presentArtworks.length > 1) { + const allArtistArrays = + presentArtworks + .map(artwork => artwork.artistContribs + .map(contrib => contrib.artist)); + + const allSameArtists = + allArtistArrays + .slice(1) + .every(artists => compareArrays(artists, allArtistArrays[0])); + + if (allSameArtists) { + query.artistsForAllTrackArtworks = + allArtistArrays[0]; + } + } + + return query; + }, + + relations: (relation, query, album, _label) => ({ + coverArtistsLine: + (query.artistsForAllTrackArtworks + ? relation('generateAlbumGalleryCoverArtistsLine', + query.artistsForAllTrackArtworks) + : null), + + coverGrid: + relation('generateCoverGrid'), + + albumLink: + relation('linkAlbum', album), + + trackLinks: + album.tracks + .map(track => relation('linkTrack', track)), + + images: + query.artworks + .map(artwork => relation('image', artwork)), + }), + + data: (query, album, _label) => ({ + trackNames: + album.tracks + .map(track => track.name), + + trackArtworkArtists: + query.artworks.map(artwork => + (query.artistsForAllTrackArtworks + ? null + : artwork + ? artwork.artistContribs + .map(contrib => contrib.artist.name) + : null)), + }), + + slots: { + attributes: {type: 'attributes', mutable: false}, + }, + + generate: (data, relations, slots, {html, language}) => + html.tag('div', + {[html.onlyIfContent]: true}, + + slots.attributes, + + [ + relations.coverArtistsLine, + + relations.coverGrid.slots({ + links: + relations.trackLinks, + + names: + data.trackNames, + + images: + stitchArrays({ + image: relations.images, + name: data.trackNames, + }).map(({image, name}) => + image.slots({ + missingSourceContent: + language.$('misc.albumGalleryGrid.noCoverArt', {name}), + })), + + info: + data.trackArtworkArtists.map(artists => + language.$('misc.coverGrid.details.coverArtists', { + [language.onlyIfOptions]: ['artists'], + + artists: + language.formatUnitList(artists), + })), + }), + ]), +}; diff --git a/src/content/dependencies/generateAlbumInfoPage.js b/src/content/dependencies/generateAlbumInfoPage.js index aae56637..d0788523 100644 --- a/src/content/dependencies/generateAlbumInfoPage.js +++ b/src/content/dependencies/generateAlbumInfoPage.js @@ -4,8 +4,8 @@ export default { contentDependencies: [ 'generateAdditionalNamesBox', 'generateAlbumAdditionalFilesList', + 'generateAlbumArtworkColumn', 'generateAlbumBanner', - 'generateAlbumCoverArtwork', 'generateAlbumNavAccent', 'generateAlbumReleaseInfo', 'generateAlbumSecondaryNav', @@ -44,10 +44,8 @@ export default { additionalNamesBox: relation('generateAdditionalNamesBox', album.additionalNames), - cover: - (album.hasCoverArt - ? relation('generateAlbumCoverArtwork', album) - : null), + artworkColumn: + relation('generateAlbumArtworkColumn', album), banner: (album.hasBannerArt @@ -112,12 +110,8 @@ export default { additionalNames: relations.additionalNamesBox, - cover: - (relations.cover - ? relations.cover.slots({ - showReferenceLinks: true, - }) - : null), + artworkColumnContent: + relations.artworkColumn, mainContent: [ relations.releaseInfo, diff --git a/src/content/dependencies/generateAlbumReferencedArtworksPage.js b/src/content/dependencies/generateAlbumReferencedArtworksPage.js index 3f3d77b3..7586393c 100644 --- a/src/content/dependencies/generateAlbumReferencedArtworksPage.js +++ b/src/content/dependencies/generateAlbumReferencedArtworksPage.js @@ -1,6 +1,5 @@ export default { contentDependencies: [ - 'generateAlbumCoverArtwork', 'generateAlbumStyleRules', 'generateBackToAlbumLink', 'generateReferencedArtworksPage', @@ -11,7 +10,7 @@ export default { relations: (relation, album) => ({ page: - relation('generateReferencedArtworksPage', album.referencedArtworks), + relation('generateReferencedArtworksPage', album.coverArtworks[0]), albumStyleRules: relation('generateAlbumStyleRules', album, null), @@ -21,17 +20,11 @@ export default { backToAlbumLink: relation('generateBackToAlbumLink', album), - - cover: - relation('generateAlbumCoverArtwork', album), }), data: (album) => ({ name: album.name, - - color: - album.color, }), generate: (data, relations, {html, language}) => @@ -42,11 +35,8 @@ export default { data.name, }), - color: data.color, styleRules: [relations.albumStyleRules], - cover: relations.cover, - navLinks: [ {auto: 'home'}, diff --git a/src/content/dependencies/generateAlbumReferencingArtworksPage.js b/src/content/dependencies/generateAlbumReferencingArtworksPage.js index 8f2349f9..d072d2f6 100644 --- a/src/content/dependencies/generateAlbumReferencingArtworksPage.js +++ b/src/content/dependencies/generateAlbumReferencingArtworksPage.js @@ -1,6 +1,5 @@ export default { contentDependencies: [ - 'generateAlbumCoverArtwork', 'generateAlbumStyleRules', 'generateBackToAlbumLink', 'generateReferencingArtworksPage', @@ -11,7 +10,7 @@ export default { relations: (relation, album) => ({ page: - relation('generateReferencingArtworksPage', album.referencedByArtworks), + relation('generateReferencingArtworksPage', album.coverArtworks[0]), albumStyleRules: relation('generateAlbumStyleRules', album, null), @@ -21,17 +20,11 @@ export default { backToAlbumLink: relation('generateBackToAlbumLink', album), - - cover: - relation('generateAlbumCoverArtwork', album), }), data: (album) => ({ name: album.name, - - color: - album.color, }), generate: (data, relations, {html, language}) => @@ -42,11 +35,8 @@ export default { data.name, }), - color: data.color, styleRules: [relations.albumStyleRules], - cover: relations.cover, - navLinks: [ {auto: 'home'}, diff --git a/src/content/dependencies/generateAlbumReleaseInfo.js b/src/content/dependencies/generateAlbumReleaseInfo.js index 217282c0..0abb412c 100644 --- a/src/content/dependencies/generateAlbumReleaseInfo.js +++ b/src/content/dependencies/generateAlbumReleaseInfo.js @@ -14,9 +14,6 @@ export default { relations.artistContributionsLine = relation('generateReleaseInfoContributionsLine', album.artistContribs); - relations.coverArtistContributionsLine = - relation('generateReleaseInfoContributionsLine', album.coverArtistContribs); - relations.wallpaperArtistContributionsLine = relation('generateReleaseInfoContributionsLine', album.wallpaperArtistContribs); @@ -73,31 +70,11 @@ export default { chronologyKind: 'album', }), - relations.coverArtistContributionsLine.slots({ - stringKey: capsule + '.coverArtBy', - chronologyKind: 'coverArt', - }), - - relations.wallpaperArtistContributionsLine.slots({ - stringKey: capsule + '.wallpaperArtBy', - chronologyKind: 'wallpaperArt', - }), - - relations.bannerArtistContributionsLine.slots({ - stringKey: capsule + '.bannerArtBy', - chronologyKind: 'bannerArt', - }), - language.$(capsule, 'released', { [language.onlyIfOptions]: ['date'], date: language.formatDate(data.date), }), - language.$(capsule, 'artReleased', { - [language.onlyIfOptions]: ['date'], - date: language.formatDate(data.coverArtDate), - }), - language.$(capsule, 'duration', { [language.onlyIfOptions]: ['duration'], duration: diff --git a/src/content/dependencies/generateAlbumSecondaryNavGroupPart.js b/src/content/dependencies/generateAlbumSecondaryNavGroupPart.js index 9f9aaf23..22dfa51c 100644 --- a/src/content/dependencies/generateAlbumSecondaryNavGroupPart.js +++ b/src/content/dependencies/generateAlbumSecondaryNavGroupPart.js @@ -67,6 +67,8 @@ export default { generate: (relations, slots) => relations.parentSiblingsPart.slots({ + attributes: {class: 'group-nav-links'}, + showPreviousNext: slots.mode === 'album', colorStyle: relations.colorStyle, diff --git a/src/content/dependencies/generateAlbumSecondaryNavSeriesPart.js b/src/content/dependencies/generateAlbumSecondaryNavSeriesPart.js index f579cdc9..16f205e3 100644 --- a/src/content/dependencies/generateAlbumSecondaryNavSeriesPart.js +++ b/src/content/dependencies/generateAlbumSecondaryNavSeriesPart.js @@ -62,7 +62,7 @@ export default { generate: (data, relations, slots, {language}) => relations.parentSiblingsPart.slots({ - attributes: {class: 'series-nav-link'}, + attributes: {class: 'series-nav-links'}, showPreviousNext: slots.mode === 'album', diff --git a/src/content/dependencies/generateAlbumSidebarTrackSection.js b/src/content/dependencies/generateAlbumSidebarTrackSection.js index 88aea409..dae5fa03 100644 --- a/src/content/dependencies/generateAlbumSidebarTrackSection.js +++ b/src/content/dependencies/generateAlbumSidebarTrackSection.js @@ -1,4 +1,4 @@ -import {empty} from '#sugar'; +import {empty, stitchArrays} from '#sugar'; export default { contentDependencies: ['linkTrack'], @@ -17,23 +17,25 @@ export default { data(album, track, trackSection) { const data = {}; - data.hasTrackNumbers = album.hasTrackNumbers; + data.hasTrackNumbers = + album.hasTrackNumbers && + !empty(trackSection.tracks); + data.isTrackPage = !!track; data.name = trackSection.name; data.color = trackSection.color; data.isDefaultTrackSection = trackSection.isDefaultTrackSection; - data.firstTrackNumber = trackSection.startIndex + 1; - data.lastTrackNumber = trackSection.startIndex + trackSection.tracks.length; + data.firstTrackNumber = + (data.hasTrackNumbers + ? trackSection.tracks.at(0).trackNumber + : null); - if (track) { - const index = trackSection.tracks.indexOf(track); - if (index !== -1) { - data.includesCurrentTrack = true; - data.currentTrackIndex = index; - } - } + data.lastTrackNumber = + (data.hasTrackNumbers + ? trackSection.tracks.at(-1).trackNumber + : null); data.trackDirectories = trackSection.tracks @@ -43,6 +45,13 @@ export default { trackSection.tracks .map(track => empty(track.commentary)); + data.tracksAreCurrentTrack = + trackSection.tracks + .map(traaaaaaaack => traaaaaaaack === track); + + data.includesCurrentTrack = + data.tracksAreCurrentTrack.includes(true); + return data; }, @@ -72,29 +81,39 @@ export default { } const trackListItems = - relations.trackLinks.map((trackLink, index) => - html.tag('li', - data.includesCurrentTrack && - index === data.currentTrackIndex && - {class: 'current'}, - - slots.mode === 'commentary' && - data.tracksAreMissingCommentary[index] && - {class: 'no-commentary'}, - - language.$(capsule, 'item', { - track: - (slots.mode === 'commentary' && data.tracksAreMissingCommentary[index] - ? trackLink.slots({ - linkless: true, - }) - : slots.anchor - ? trackLink.slots({ - anchor: true, - hash: data.trackDirectories[index], - }) - : trackLink), - }))); + stitchArrays({ + trackLink: relations.trackLinks, + directory: data.trackDirectories, + isCurrentTrack: data.tracksAreCurrentTrack, + missingCommentary: data.tracksAreMissingCommentary, + }).map(({ + trackLink, + directory, + isCurrentTrack, + missingCommentary, + }) => + html.tag('li', + data.includesCurrentTrack && + isCurrentTrack && + {class: 'current'}, + + slots.mode === 'commentary' && + missingCommentary && + {class: 'no-commentary'}, + + language.$(capsule, 'item', { + track: + (slots.mode === 'commentary' && missingCommentary + ? trackLink.slots({ + linkless: true, + }) + : slots.anchor + ? trackLink.slots({ + anchor: true, + hash: directory, + }) + : trackLink), + }))); return html.tag('details', data.includesCurrentTrack && @@ -121,17 +140,22 @@ export default { colorStyle, html.tag('span', - language.encapsulate(capsule, 'group', workingCapsule => { - const workingOptions = {group: sectionName}; - - if (data.hasTrackNumbers) { - workingCapsule += '.withRange'; - workingOptions.range = - `${data.firstTrackNumber}–${data.lastTrackNumber}`; - } - - return language.$(workingCapsule, workingOptions); - }))), + language.encapsulate(capsule, 'group', groupCapsule => + language.encapsulate(groupCapsule, workingCapsule => { + const workingOptions = {group: sectionName}; + + if (data.hasTrackNumbers) { + workingCapsule += '.withRange'; + workingOptions.rangePart = + html.tag('span', {class: 'track-section-range'}, + language.$(groupCapsule, 'withRange.rangePart', { + range: + `${data.firstTrackNumber}–${data.lastTrackNumber}`, + })); + } + + return language.$(workingCapsule, workingOptions); + })))), (data.hasTrackNumbers ? html.tag('ol', diff --git a/src/content/dependencies/generateAlbumSocialEmbed.js b/src/content/dependencies/generateAlbumSocialEmbed.js index ad02e180..e28a3fd0 100644 --- a/src/content/dependencies/generateAlbumSocialEmbed.js +++ b/src/content/dependencies/generateAlbumSocialEmbed.js @@ -32,8 +32,7 @@ export default { data.hasImage = album.hasCoverArt; if (data.hasImage) { - data.coverArtDirectory = album.directory; - data.coverArtFileExtension = album.coverArtFileExtension; + data.imagePath = album.coverArtworks[0].path; } data.albumName = album.name; @@ -65,7 +64,7 @@ export default { imagePath: (data.hasImage - ? ['media.albumCover', data.coverArtDirectory, data.coverArtFileExtension] + ? data.imagePath : null), })), }; diff --git a/src/content/dependencies/generateAlbumTrackList.js b/src/content/dependencies/generateAlbumTrackList.js index 9743c750..0a949ded 100644 --- a/src/content/dependencies/generateAlbumTrackList.js +++ b/src/content/dependencies/generateAlbumTrackList.js @@ -102,11 +102,11 @@ export default { .map(section => section.tracks.length > 1); if (album.hasTrackNumbers) { - data.trackSectionStartIndices = + data.trackSectionsStartCountingFrom = album.trackSections - .map(section => section.startIndex); + .map(section => section.startCountingFrom); } else { - data.trackSectionStartIndices = + data.trackSectionsStartCountingFrom = album.trackSections .map(() => null); } @@ -147,7 +147,7 @@ export default { name: data.trackSectionNames, duration: data.trackSectionDurations, durationApproximate: data.trackSectionDurationsApproximate, - startIndex: data.trackSectionStartIndices, + startCountingFrom: data.trackSectionsStartCountingFrom, }).map(({ heading, description, @@ -156,7 +156,7 @@ export default { name, duration, durationApproximate, - startIndex, + startCountingFrom, }) => [ language.encapsulate('trackList.section', capsule => heading.slots({ @@ -190,7 +190,7 @@ export default { html.tag(listTag, data.hasTrackNumbers && - {start: startIndex + 1}, + {start: startCountingFrom}, slotItems(items)), ]), diff --git a/src/content/dependencies/generateArtTagAncestorDescendantMapList.js b/src/content/dependencies/generateArtTagAncestorDescendantMapList.js index 89150615..80d19b5a 100644 --- a/src/content/dependencies/generateArtTagAncestorDescendantMapList.js +++ b/src/content/dependencies/generateArtTagAncestorDescendantMapList.js @@ -33,8 +33,8 @@ export default { const artTagsTimesFeaturedTotal = artTags.map(artTag => unique([ - ...artTag.directlyTaggedInThings, - ...artTag.indirectlyTaggedInThings, + ...artTag.directlyFeaturedInArtworks, + ...artTag.indirectlyFeaturedInArtworks, ]).length); const sublists = diff --git a/src/content/dependencies/generateArtTagGalleryPage.js b/src/content/dependencies/generateArtTagGalleryPage.js index b633e58f..344e7bda 100644 --- a/src/content/dependencies/generateArtTagGalleryPage.js +++ b/src/content/dependencies/generateArtTagGalleryPage.js @@ -1,5 +1,5 @@ -import {sortAlbumsTracksChronologically} from '#sort'; -import {empty, stitchArrays, unique} from '#sugar'; +import {sortArtworksChronologically} from '#sort'; +import {empty, unique} from '#sugar'; export default { contentDependencies: [ @@ -11,10 +11,9 @@ export default { 'generatePageLayout', 'generateQuickDescription', 'image', - 'linkAlbum', + 'linkAnythingMan', 'linkArtTagGallery', 'linkExternal', - 'linkTrack', ], extraDependencies: ['html', 'language', 'wikiData'], @@ -26,16 +25,13 @@ export default { }, query(sprawl, artTag) { - const directThings = artTag.directlyTaggedInThings; - const indirectThings = artTag.indirectlyTaggedInThings; - const allThings = unique([...directThings, ...indirectThings]); + const directArtworks = artTag.directlyFeaturedInArtworks; + const indirectArtworks = artTag.indirectlyFeaturedInArtworks; + const allArtworks = unique([...directArtworks, ...indirectArtworks]); - sortAlbumsTracksChronologically(allThings, { - getDate: thing => thing.coverArtDate ?? thing.date, - latestFirst: true, - }); + sortArtworksChronologically(allArtworks, {latestFirst: true}); - return {directThings, indirectThings, allThings}; + return {directArtworks, indirectArtworks, allArtworks}; }, relations(relation, query, sprawl, artTag) { @@ -81,15 +77,12 @@ export default { relation('generateCoverGrid'); relations.links = - query.allThings - .map(thing => - (thing.album - ? relation('linkTrack', thing) - : relation('linkAlbum', thing))); + query.allArtworks + .map(artwork => relation('linkAnythingMan', artwork.thing)); relations.images = - query.allThings - .map(thing => relation('image', thing.artTags)); + query.allArtworks + .map(artwork => relation('image', artwork)); return relations; }, @@ -102,30 +95,22 @@ export default { data.name = artTag.name; data.color = artTag.color; - data.numArtworksIndirectly = query.indirectThings.length; - data.numArtworksDirectly = query.directThings.length; - data.numArtworksTotal = query.allThings.length; + data.numArtworksIndirectly = query.indirectArtworks.length; + data.numArtworksDirectly = query.directArtworks.length; + data.numArtworksTotal = query.allArtworks.length; data.names = - query.allThings.map(thing => thing.name); - - data.paths = - query.allThings.map(thing => - (thing.album - ? ['media.trackCover', thing.album.directory, thing.directory, thing.coverArtFileExtension] - : ['media.albumCover', thing.directory, thing.coverArtFileExtension])); - - data.dimensions = - query.allThings.map(thing => thing.coverArtDimensions); + query.allArtworks + .map(artwork => artwork.thing.name); data.coverArtists = - query.allThings.map(thing => - thing.coverArtistContribs - .map(({artist}) => artist.name)); + query.allArtworks + .map(artwork => artwork.artistContribs + .map(contrib => contrib.artist.name)); data.onlyFeaturedIndirectly = - query.allThings.map(thing => - !query.directThings.includes(thing)); + query.allArtworks.map(artwork => + !query.directArtworks.includes(artwork)); data.hasMixedDirectIndirect = data.onlyFeaturedIndirectly.includes(true) && @@ -210,6 +195,7 @@ export default { relations.coverGrid .slots({ links: relations.links, + images: relations.images, names: data.names, lazy: 12, @@ -217,17 +203,6 @@ export default { data.onlyFeaturedIndirectly.map(onlyFeaturedIndirectly => (onlyFeaturedIndirectly ? 'featured-indirectly' : '')), - images: - stitchArrays({ - image: relations.images, - path: data.paths, - dimensions: data.dimensions, - }).map(({image, path, dimensions}) => - image.slots({ - path, - dimensions, - })), - info: data.coverArtists.map(names => (names === null diff --git a/src/content/dependencies/generateArtTagInfoPage.js b/src/content/dependencies/generateArtTagInfoPage.js index 7765f159..9df51b77 100644 --- a/src/content/dependencies/generateArtTagInfoPage.js +++ b/src/content/dependencies/generateArtTagInfoPage.js @@ -23,10 +23,10 @@ export default { const query = {}; query.directThings = - artTag.directlyTaggedInThings; + artTag.directlyFeaturedInArtworks; query.indirectThings = - artTag.indirectlyTaggedInThings; + artTag.indirectlyFeaturedInArtworks; query.allThings = unique([...query.directThings, ...query.indirectThings]); @@ -111,8 +111,8 @@ export default { directDescendantTimesFeaturedTotal: artTag.directDescendantArtTags.map(artTag => unique([ - ...artTag.directlyTaggedInThings, - ...artTag.indirectlyTaggedInThings, + ...artTag.directlyFeaturedInArtworks, + ...artTag.indirectlyFeaturedInArtworks, ]).length), }), diff --git a/src/content/dependencies/generateArtTagSidebar.js b/src/content/dependencies/generateArtTagSidebar.js index c281b93d..9e2f813c 100644 --- a/src/content/dependencies/generateArtTagSidebar.js +++ b/src/content/dependencies/generateArtTagSidebar.js @@ -54,8 +54,8 @@ export default { directDescendantTimesFeaturedTotal: artTag.directDescendantArtTags.map(artTag => unique([ - ...artTag.directlyTaggedInThings, - ...artTag.indirectlyTaggedInThings, + ...artTag.directlyFeaturedInArtworks, + ...artTag.indirectlyFeaturedInArtworks, ]).length), furthestAncestorArtTagNames: diff --git a/src/content/dependencies/generateArtistArtworkColumn.js b/src/content/dependencies/generateArtistArtworkColumn.js new file mode 100644 index 00000000..a4135489 --- /dev/null +++ b/src/content/dependencies/generateArtistArtworkColumn.js @@ -0,0 +1,13 @@ +export default { + contentDependencies: ['generateCoverArtwork'], + + relations: (relation, artist) => ({ + coverArtwork: + (artist.hasAvatar + ? relation('generateCoverArtwork', artist.avatarArtwork) + : null), + }), + + generate: (relations) => + relations.coverArtwork, +}; diff --git a/src/content/dependencies/generateArtistCredit.js b/src/content/dependencies/generateArtistCredit.js index 72d55854..6bdbeb23 100644 --- a/src/content/dependencies/generateArtistCredit.js +++ b/src/content/dependencies/generateArtistCredit.js @@ -80,6 +80,8 @@ export default { // It won't be used if contextContributions isn't provided. featuringStringKey: {type: 'string'}, + additionalStringOptions: {validate: v => v.isObject}, + showAnnotation: {type: 'boolean', default: false}, showExternalLinks: {type: 'boolean', default: false}, showChronology: {type: 'boolean', default: false}, @@ -148,7 +150,10 @@ export default { if (empty(relations.featuringContributionLinks)) { if (data.normalContributionsDifferFromContext) { - return language.$(slots.normalStringKey, {artists: artistsList}); + return language.$(slots.normalStringKey, { + ...slots.additionalStringOptions, + artists: artistsList, + }); } else { return html.blank(); } @@ -156,13 +161,20 @@ export default { if (data.normalContributionsDifferFromContext && slots.normalFeaturingStringKey) { return language.$(slots.normalFeaturingStringKey, { + ...slots.additionalStringOptions, artists: artistsList, featuring: featuringList, }); } else if (slots.featuringStringKey) { - return language.$(slots.featuringStringKey, {artists: featuringList}); + return language.$(slots.featuringStringKey, { + ...slots.additionalStringOptions, + artists: featuringList, + }); } else { - return language.$(slots.normalStringKey, {artists: everyoneList}); + return language.$(slots.normalStringKey, { + ...slots.additionalStringOptions, + artists: everyoneList, + }); } }, }; diff --git a/src/content/dependencies/generateArtistGalleryPage.js b/src/content/dependencies/generateArtistGalleryPage.js index 7a76188a..6a24275e 100644 --- a/src/content/dependencies/generateArtistGalleryPage.js +++ b/src/content/dependencies/generateArtistGalleryPage.js @@ -1,5 +1,4 @@ -import {sortAlbumsTracksChronologically} from '#sort'; -import {stitchArrays} from '#sugar'; +import {sortArtworksChronologically} from '#sort'; export default { contentDependencies: [ @@ -7,83 +6,59 @@ export default { 'generateCoverGrid', 'generatePageLayout', 'image', - 'linkAlbum', - 'linkTrack', + 'linkAnythingMan', ], extraDependencies: ['html', 'language'], - query(artist) { - const things = - ([ - artist.albumCoverArtistContributions, - artist.trackCoverArtistContributions, - ]).flat() - .filter(({annotation}) => !annotation?.startsWith(`edits for wiki`)) - .map(({thing}) => thing); - - sortAlbumsTracksChronologically(things, { - latestFirst: true, - getDate: thing => thing.coverArtDate ?? thing.date, - }); - - return {things}; - }, - - relations(relation, query, artist) { - const relations = {}; - - relations.layout = - relation('generatePageLayout'); - - relations.artistNavLinks = - relation('generateArtistNavLinks', artist); - - relations.coverGrid = - relation('generateCoverGrid'); - - relations.links = - query.things.map(thing => - (thing.album - ? relation('linkTrack', thing) - : relation('linkAlbum', thing))); - - relations.images = - query.things.map(thing => - relation('image', thing.artTags)); - - return relations; - }, - - data(query, artist) { - const data = {}; - - data.name = artist.name; - - data.numArtworks = query.things.length; - - data.names = - query.things.map(thing => thing.name); - - data.paths = - query.things.map(thing => - (thing.album - ? ['media.trackCover', thing.album.directory, thing.directory, thing.coverArtFileExtension] - : ['media.albumCover', thing.directory, thing.coverArtFileExtension])); - - data.dimensions = - query.things.map(thing => thing.coverArtDimensions); - - data.otherCoverArtists = - query.things.map(thing => - (thing.coverArtistContribs.length > 1 - ? thing.coverArtistContribs - .filter(({artist: otherArtist}) => otherArtist !== artist) - .map(({artist: otherArtist}) => otherArtist.name) - : null)); - - return data; - }, + query: (artist) => ({ + artworks: + sortArtworksChronologically( + ([ + artist.albumCoverArtistContributions, + artist.trackCoverArtistContributions, + ]).flat() + .filter(contrib => !contrib.annotation?.startsWith(`edits for wiki`)) + .map(contrib => contrib.thing), + {latestFirst: true}), + }), + + relations: (relation, query, artist) => ({ + layout: + relation('generatePageLayout'), + + artistNavLinks: + relation('generateArtistNavLinks', artist), + + coverGrid: + relation('generateCoverGrid'), + + links: + query.artworks + .map(artwork => relation('linkAnythingMan', artwork.thing)), + + images: + query.artworks + .map(artwork => relation('image', artwork)), + }), + + data: (query, artist) => ({ + name: + artist.name, + + numArtworks: + query.artworks.length, + + names: + query.artworks + .map(artwork => artwork.thing.name), + + otherCoverArtists: + query.artworks + .map(artwork => artwork.artistContribs + .filter(contrib => contrib.artist !== artist) + .map(contrib => contrib.artist.name)), + }), generate: (data, relations, {html, language}) => language.encapsulate('artistGalleryPage', pageCapsule => @@ -100,7 +75,7 @@ export default { html.tag('p', {class: 'quick-info'}, language.$(pageCapsule, 'infoLine', { coverArts: - language.countCoverArts(data.numArtworks, { + language.countArtworks(data.numArtworks, { unit: true, }), })), @@ -108,27 +83,16 @@ export default { relations.coverGrid .slots({ links: relations.links, + images: relations.images, names: data.names, - images: - stitchArrays({ - image: relations.images, - path: data.paths, - dimensions: data.dimensions, - }).map(({image, path, dimensions}) => - image.slots({ - path, - dimensions, - })), - - // TODO: Can this be [language.onlyIfOptions]? info: data.otherCoverArtists.map(names => - (names === null - ? null - : language.$('misc.coverGrid.details.otherCoverArtists', { - artists: language.formatUnitList(names), - }))), + language.$('misc.coverGrid.details.otherCoverArtists', { + [language.onlyIfOptions]: ['artists'], + + artists: language.formatUnitList(names), + })), }), ], diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js index 0c4e4189..3a3cf8b7 100644 --- a/src/content/dependencies/generateArtistInfoPage.js +++ b/src/content/dependencies/generateArtistInfoPage.js @@ -2,6 +2,7 @@ import {empty, stitchArrays, unique} from '#sugar'; export default { contentDependencies: [ + 'generateArtistArtworkColumn', 'generateArtistGroupContributionsInfo', 'generateArtistInfoPageArtworksChunkedList', 'generateArtistInfoPageCommentaryChunkedList', @@ -9,9 +10,7 @@ export default { 'generateArtistInfoPageTracksChunkedList', 'generateArtistNavLinks', 'generateContentHeading', - 'generateCoverArtwork', 'generatePageLayout', - 'image', 'linkArtistGallery', 'linkExternal', 'linkGroup', @@ -35,7 +34,7 @@ export default { // Artworks are different, though. We intentionally duplicate album data // objects when the artist has contributed some combination of cover art, // wallpaper, and banner - these each count as a unique contribution. - allArtworks: + allArtworkThings: ([ artist.albumCoverArtistContributions, artist.albumWallpaperArtistContributions, @@ -43,7 +42,7 @@ export default { artist.trackCoverArtistContributions, ]).flat() .filter(({annotation}) => !annotation?.startsWith('edits for wiki')) - .map(({thing}) => thing), + .map(({thing}) => thing.thing), // Banners and wallpapers don't show up in the artist gallery page, only // cover art. @@ -69,15 +68,8 @@ export default { artistNavLinks: relation('generateArtistNavLinks', artist), - cover: - (artist.hasAvatar - ? relation('generateCoverArtwork', [], []) - : null), - - image: - (artist.hasAvatar - ? relation('image') - : null), + artworkColumn: + relation('generateArtistArtworkColumn', artist), contentHeading: relation('generateContentHeading'), @@ -110,7 +102,7 @@ export default { relation('generateArtistInfoPageArtworksChunkedList', artist, true), artworksGroupInfo: - relation('generateArtistGroupContributionsInfo', query.allArtworks), + relation('generateArtistGroupContributionsInfo', query.allArtworkThings), artistGalleryLink: (query.hasGallery @@ -131,14 +123,6 @@ export default { name: artist.name, - directory: - artist.directory, - - avatarFileExtension: - (artist.hasAvatar - ? artist.avatarFileExtension - : null), - closeGroupAnnotations: query.generalLinkedGroups .map(({annotation}) => annotation), @@ -156,19 +140,8 @@ export default { title: data.name, headingMode: 'sticky', - cover: - (relations.cover - ? relations.cover.slots({ - image: - relations.image.slots({ - path: [ - 'media.artistAvatar', - data.directory, - data.avatarFileExtension, - ], - }), - }) - : null), + artworkColumnContent: + relations.artworkColumn, mainContent: [ html.tags([ diff --git a/src/content/dependencies/generateArtistInfoPageArtworksChunkItem.js b/src/content/dependencies/generateArtistInfoPageArtworksChunkItem.js index 089cfb8d..2f2fe0c5 100644 --- a/src/content/dependencies/generateArtistInfoPageArtworksChunkItem.js +++ b/src/content/dependencies/generateArtistInfoPageArtworksChunkItem.js @@ -24,7 +24,7 @@ export default { trackLink: (query.kind === 'track-cover' - ? relation('linkTrack', contrib.thing) + ? relation('linkTrack', contrib.thing.thing) : null), otherArtistLinks: diff --git a/src/content/dependencies/generateArtistInfoPageArtworksChunkedList.js b/src/content/dependencies/generateArtistInfoPageArtworksChunkedList.js index 8b024147..75a4aa5a 100644 --- a/src/content/dependencies/generateArtistInfoPageArtworksChunkedList.js +++ b/src/content/dependencies/generateArtistInfoPageArtworksChunkedList.js @@ -27,20 +27,21 @@ export default { sortContributionsChronologically( filteredContributions, - sortAlbumsTracksChronologically); + sortAlbumsTracksChronologically, + {getThing: contrib => contrib.thing.thing}); query.contribs = chunkByConditions(filteredContributions, [ ({date: date1}, {date: date2}) => +date1 !== +date2, - ({thing: thing1}, {thing: thing2}) => + ({thing: {thing: thing1}}, {thing: {thing: thing2}}) => (thing1.album ?? thing1) !== (thing2.album ?? thing2), ]); query.albums = query.contribs - .map(contribs => contribs[0].thing) + .map(contribs => contribs[0].thing.thing) .map(thing => thing.album ?? thing); return query; diff --git a/src/content/dependencies/generateCommentaryEntry.js b/src/content/dependencies/generateCommentaryEntry.js index c93020f3..4cb618e3 100644 --- a/src/content/dependencies/generateCommentaryEntry.js +++ b/src/content/dependencies/generateCommentaryEntry.js @@ -98,8 +98,6 @@ export default { return language.$(workingCapsule, workingOptions); })), - - relations.date, ])), html.tag('blockquote', {class: 'commentary-entry-body'}, @@ -107,6 +105,10 @@ export default { relations.colorStyle.clone() .slot('color', slots.color), - relations.bodyContent.slot('mode', 'multiline')), + [ + relations.date, + + relations.bodyContent.slot('mode', 'multiline'), + ]), ])), }; diff --git a/src/content/dependencies/generateContributionTooltipChronologySection.js b/src/content/dependencies/generateContributionTooltipChronologySection.js index 78c9051c..378c0e1c 100644 --- a/src/content/dependencies/generateContributionTooltipChronologySection.js +++ b/src/content/dependencies/generateContributionTooltipChronologySection.js @@ -1,3 +1,19 @@ +import Thing from '#thing'; + +function getName(thing) { + if (!thing) { + return null; + } + + const referenceType = thing.constructor[Thing.referenceType]; + + if (referenceType === 'artwork') { + return thing.thing.name; + } + + return thing.name; +} + export default { contentDependencies: ['linkAnythingMan'], extraDependencies: ['html', 'language'], @@ -30,14 +46,10 @@ export default { data: (query, _contribution) => ({ previousName: - (query.previous - ? query.previous.thing.name - : null), + getName(query.previous?.thing), nextName: - (query.next - ? query.next.thing.name - : null), + getName(query.next?.thing), }), slots: { diff --git a/src/content/dependencies/generateCoverArtwork.js b/src/content/dependencies/generateCoverArtwork.js index 06972d6b..3a10ab20 100644 --- a/src/content/dependencies/generateCoverArtwork.js +++ b/src/content/dependencies/generateCoverArtwork.js @@ -1,11 +1,44 @@ export default { - contentDependencies: ['image'], + contentDependencies: [ + 'generateCoverArtworkArtTagDetails', + 'generateCoverArtworkArtistDetails', + 'generateCoverArtworkOriginDetails', + 'generateCoverArtworkReferenceDetails', + 'image', + ], + extraDependencies: ['html'], + relations: (relation, artwork) => ({ + image: + relation('image', artwork), + + originDetails: + relation('generateCoverArtworkOriginDetails', artwork), + + artTagDetails: + relation('generateCoverArtworkArtTagDetails', artwork), + + artistDetails: + relation('generateCoverArtworkArtistDetails', artwork), + + referenceDetails: + relation('generateCoverArtworkReferenceDetails', artwork), + }), + + data: (artwork) => ({ + color: + artwork.thing.color ?? null, + + dimensions: + artwork.dimensions, + }), + slots: { - image: { - type: 'html', - mutable: true, + alt: {type: 'string'}, + + color: { + validate: v => v.isColor, }, mode: { @@ -13,13 +46,10 @@ export default { default: 'primary', }, - dimensions: { - validate: v => v.isDimensions, - }, - - warnings: { - validate: v => v.looseArrayOf(v.isString), - }, + showOriginDetails: {type: 'boolean', default: false}, + showArtTagDetails: {type: 'boolean', default: false}, + showArtistDetails: {type: 'boolean', default: false}, + showReferenceDetails: {type: 'boolean', default: false}, details: { type: 'html', @@ -27,60 +57,65 @@ export default { }, }, - generate(slots, {html}) { + generate(data, relations, slots, {html}) { + const {image} = relations; + + image.setSlots({ + color: slots.color ?? data.color, + alt: slots.alt, + }); + const square = - (slots.dimensions - ? slots.dimensions[0] === slots.dimensions[1] + (data.dimensions + ? data.dimensions[0] === data.dimensions[1] : true); - const sizeSlots = - (square - ? {square: true} - : {dimensions: slots.dimensions}); - - switch (slots.mode) { - case 'primary': - return html.tags([ - slots.image.slots({ - thumb: 'medium', - reveal: true, - link: true, - - warnings: slots.warnings, - ...sizeSlots, - }), - - slots.details, - ]); - - case 'thumbnail': - return ( - slots.image.slots({ - thumb: 'small', - reveal: false, - link: false, - - warnings: slots.warnings, - ...sizeSlots, - })); - - case 'commentary': - return ( - slots.image.slots({ - thumb: 'medium', - reveal: true, - link: true, - lazy: true, - - warnings: slots.warnings, - ...sizeSlots, - - attributes: - {class: 'commentary-art'}, - })); - - default: - return html.blank(); + if (square) { + image.setSlot('square', true); + } else { + image.setSlot('dimensions', data.dimensions); } + + return ( + html.tag('div', {class: 'cover-artwork'}, + slots.mode === 'commentary' && + {class: 'commentary-art'}, + + (slots.mode === 'primary' + ? [ + relations.image.slots({ + thumb: 'medium', + reveal: true, + link: true, + }), + + slots.showOriginDetails && + relations.originDetails, + + slots.showArtTagDetails && + relations.artTagDetails, + + slots.showArtistDetails && + relations.artistDetails, + + slots.showReferenceDetails && + relations.referenceDetails, + + slots.details, + ] + : slots.mode === 'thumbnail' + ? relations.image.slots({ + thumb: 'small', + reveal: false, + link: false, + }) + : slots.mode === 'commentary' + ? relations.image.slots({ + thumb: 'medium', + reveal: true, + link: true, + lazy: true, + }) + : html.blank()))); }, }; diff --git a/src/content/dependencies/generateCoverArtworkArtTagDetails.js b/src/content/dependencies/generateCoverArtworkArtTagDetails.js index b4edbbdd..b20f599b 100644 --- a/src/content/dependencies/generateCoverArtworkArtTagDetails.js +++ b/src/content/dependencies/generateCoverArtworkArtTagDetails.js @@ -4,19 +4,19 @@ export default { contentDependencies: ['linkArtTagGallery'], extraDependencies: ['html'], - query: (artTags) => ({ + query: (artwork) => ({ linkableArtTags: - artTags + artwork.artTags .filter(tag => !tag.isContentWarning), }), - relations: (relation, query, _artTags) => ({ + relations: (relation, query, _artwork) => ({ artTagLinks: query.linkableArtTags .map(tag => relation('linkArtTagGallery', tag)), }), - data: (query, _artTags) => { + data: (query, _artwork) => { const seenShortNames = new Set(); const duplicateShortNames = new Set(); diff --git a/src/content/dependencies/generateCoverArtworkArtistDetails.js b/src/content/dependencies/generateCoverArtworkArtistDetails.js index 5b235353..3ead80ab 100644 --- a/src/content/dependencies/generateCoverArtworkArtistDetails.js +++ b/src/content/dependencies/generateCoverArtworkArtistDetails.js @@ -2,9 +2,9 @@ export default { contentDependencies: ['linkArtistGallery'], extraDependencies: ['html', 'language'], - relations: (relation, contributions) => ({ + relations: (relation, artwork) => ({ artistLinks: - contributions + artwork.artistContribs .map(contrib => contrib.artist) .map(artist => relation('linkArtistGallery', artist)), @@ -17,6 +17,8 @@ export default { {class: 'illustrator-details'}, language.$('misc.coverGrid.details.coverArtists', { + [language.onlyIfOptions]: ['artists'], + artists: language.formatConjunctionList(relations.artistLinks), })), diff --git a/src/content/dependencies/generateCoverArtworkOriginDetails.js b/src/content/dependencies/generateCoverArtworkOriginDetails.js new file mode 100644 index 00000000..08a01cfe --- /dev/null +++ b/src/content/dependencies/generateCoverArtworkOriginDetails.js @@ -0,0 +1,98 @@ +import Thing from '#thing'; + +export default { + contentDependencies: [ + 'generateArtistCredit', + 'generateAbsoluteDatetimestamp', + 'linkAlbum', + 'transformContent', + ], + + extraDependencies: ['html', 'language', 'pagePath'], + + query: (artwork) => ({ + artworkThingType: + artwork.thing.constructor[Thing.referenceType], + }), + + relations: (relation, query, artwork) => ({ + credit: + relation('generateArtistCredit', artwork.artistContribs, []), + + source: + relation('transformContent', artwork.source), + + albumLink: + (query.artworkThingType === 'album' + ? relation('linkAlbum', artwork.thing) + : null), + + datetimestamp: + (artwork.date && artwork.date !== artwork.thing.date + ? relation('generateAbsoluteDatetimestamp', artwork.date) + : null), + }), + + + data: (query, artwork) => ({ + label: + artwork.label, + + artworkThingType: + query.artworkThingType, + }), + + generate: (data, relations, {html, language, pagePath}) => + language.encapsulate('misc.coverArtwork', capsule => + html.tag('p', {class: 'image-details'}, + {[html.onlyIfContent]: true}, + {[html.joinChildren]: html.tag('br')}, + + {class: 'origin-details'}, + + [ + language.encapsulate(capsule, 'artworkBy', workingCapsule => { + const workingOptions = {}; + + if (data.label) { + workingCapsule += '.customLabel'; + workingOptions.label = data.label; + } + + if (relations.datetimestamp) { + workingCapsule += '.withYear'; + workingOptions.year = + relations.datetimestamp.slots({ + style: 'year', + tooltip: true, + }); + } + + return relations.credit.slots({ + showAnnotation: true, + showExternalLinks: true, + showChronology: true, + showWikiEdits: true, + + trimAnnotation: false, + + chronologyKind: 'coverArt', + + normalStringKey: workingCapsule, + additionalStringOptions: workingOptions, + }); + }), + + pagePath[0] === 'track' && + data.artworkThingType === 'album' && + language.$(capsule, 'trackArtFromAlbum', { + album: + relations.albumLink.slot('color', false), + }), + + language.$(capsule, 'source', { + [language.onlyIfOptions]: ['source'], + source: relations.source.slot('mode', 'inline'), + }), + ])), +}; diff --git a/src/content/dependencies/generateCoverArtworkReferenceDetails.js b/src/content/dependencies/generateCoverArtworkReferenceDetails.js index 006b2b4b..035ab586 100644 --- a/src/content/dependencies/generateCoverArtworkReferenceDetails.js +++ b/src/content/dependencies/generateCoverArtworkReferenceDetails.js @@ -1,20 +1,24 @@ export default { + contentDependencies: ['linkReferencedArtworks', 'linkReferencingArtworks'], extraDependencies: ['html', 'language'], - data: (referenced, referencedBy) => ({ + relations: (relation, artwork) => ({ + referencedArtworksLink: + relation('linkReferencedArtworks', artwork), + + referencingArtworksLink: + relation('linkReferencingArtworks', artwork), + }), + + data: (artwork) => ({ referenced: - referenced.length, + artwork.referencedArtworks.length, referencedBy: - referencedBy.length, + artwork.referencedByArtworks.length, }), - slots: { - referencedLink: {type: 'html', mutable: true}, - referencingLink: {type: 'html', mutable: true}, - }, - - generate: (data, slots, {html, language}) => + generate: (data, relations, {html, language}) => language.encapsulate('releaseInfo', capsule => { const referencedText = language.$(capsule, 'referencesArtworks', { @@ -47,10 +51,10 @@ export default { [ !html.isBlank(referencedText) && - slots.referencedLink.slot('content', referencedText), + relations.referencedArtworksLink.slot('content', referencedText), !html.isBlank(referencingText) && - slots.referencingLink.slot('content', referencingText), + relations.referencingArtworksLink.slot('content', referencingText), ])); }), } diff --git a/src/content/dependencies/generateCoverGrid.js b/src/content/dependencies/generateCoverGrid.js index 1898832f..29ac08b7 100644 --- a/src/content/dependencies/generateCoverGrid.js +++ b/src/content/dependencies/generateCoverGrid.js @@ -33,9 +33,11 @@ export default { actionLinks: {validate: v => v.sparseArrayOf(v.isHTML)}, }, - generate(relations, slots, {html, language}) { - return ( - html.tag('div', {class: 'grid-listing'}, [ + generate: (relations, slots, {html, language}) => + html.tag('div', {class: 'grid-listing'}, + {[html.onlyIfContent]: true}, + + [ stitchArrays({ classes: slots.classes, image: slots.images, @@ -84,6 +86,5 @@ export default { relations.actionLinks .slot('actionLinks', slots.actionLinks), - ])); - }, + ]), }; diff --git a/src/content/dependencies/generateFlashActGalleryPage.js b/src/content/dependencies/generateFlashActGalleryPage.js index 8f174b21..84ab549d 100644 --- a/src/content/dependencies/generateFlashActGalleryPage.js +++ b/src/content/dependencies/generateFlashActGalleryPage.js @@ -1,5 +1,3 @@ -import {stitchArrays} from '#sugar'; - import striptags from 'striptags'; export default { @@ -37,7 +35,7 @@ export default { coverGridImages: act.flashes - .map(_flash => relation('image')), + .map(flash => relation('image', flash.coverArtwork)), flashLinks: act.flashes @@ -50,10 +48,6 @@ export default { flashNames: act.flashes.map(flash => flash.name), - - flashCoverPaths: - act.flashes.map(flash => - ['media.flashArt', flash.directory, flash.coverArtFileExtension]) }), generate: (data, relations, {language}) => @@ -71,15 +65,9 @@ export default { mainContent: [ relations.coverGrid.slots({ links: relations.flashLinks, + images: relations.coverGridImages, names: data.flashNames, lazy: 6, - - images: - stitchArrays({ - image: relations.coverGridImages, - path: data.flashCoverPaths, - }).map(({image, path}) => - image.slot('path', path)), }), ], diff --git a/src/content/dependencies/generateFlashArtworkColumn.js b/src/content/dependencies/generateFlashArtworkColumn.js new file mode 100644 index 00000000..5987df9e --- /dev/null +++ b/src/content/dependencies/generateFlashArtworkColumn.js @@ -0,0 +1,11 @@ +export default { + contentDependencies: ['generateCoverArtwork'], + + relations: (relation, flash) => ({ + coverArtwork: + relation('generateCoverArtwork', flash.coverArtwork), + }), + + generate: (relations) => + relations.coverArtwork, +}; diff --git a/src/content/dependencies/generateFlashCoverArtwork.js b/src/content/dependencies/generateFlashCoverArtwork.js deleted file mode 100644 index 4b0e5242..00000000 --- a/src/content/dependencies/generateFlashCoverArtwork.js +++ /dev/null @@ -1,41 +0,0 @@ -export default { - contentDependencies: ['generateCoverArtwork', 'image'], - extraDependencies: ['html', 'language'], - - relations: (relation) => ({ - coverArtwork: - relation('generateCoverArtwork'), - - image: - relation('image'), - }), - - data: (flash) => ({ - path: - ['media.flashArt', flash.directory, flash.coverArtFileExtension], - - color: - flash.color, - - dimensions: - flash.coverArtDimensions, - }), - - slots: { - mode: {type: 'string'}, - }, - - generate: (data, relations, slots, {language}) => - relations.coverArtwork.slots({ - mode: slots.mode, - - image: - relations.image.slots({ - path: data.path, - color: data.color, - alt: language.$('misc.alt.flashArt'), - }), - - dimensions: data.dimensions, - }), -}; diff --git a/src/content/dependencies/generateFlashIndexPage.js b/src/content/dependencies/generateFlashIndexPage.js index a21bb49e..2788406c 100644 --- a/src/content/dependencies/generateFlashIndexPage.js +++ b/src/content/dependencies/generateFlashIndexPage.js @@ -53,7 +53,7 @@ export default { actCoverGridImages: query.flashActs .map(act => act.flashes - .map(() => relation('image'))), + .map(flash => relation('image', flash.coverArtwork))), }), data: (query) => ({ @@ -73,11 +73,6 @@ export default { query.flashActs .map(act => act.flashes .map(flash => flash.name)), - - actCoverGridPaths: - query.flashActs - .map(act => act.flashes - .map(flash => ['media.flashArt', flash.directory, flash.coverArtFileExtension])), }), generate: (data, relations, {html, language}) => @@ -116,7 +111,6 @@ export default { coverGridImages: relations.actCoverGridImages, coverGridLinks: relations.actCoverGridLinks, coverGridNames: data.actCoverGridNames, - coverGridPaths: data.actCoverGridPaths, }).map(({ colorStyle, actLink, @@ -126,7 +120,6 @@ export default { coverGridImages, coverGridLinks, coverGridNames, - coverGridPaths, }, index) => [ html.tag('h2', {id: anchor}, @@ -135,15 +128,9 @@ export default { coverGrid.slots({ links: coverGridLinks, + images: coverGridImages, names: coverGridNames, lazy: index === 0 ? 4 : true, - - images: - stitchArrays({ - image: coverGridImages, - path: coverGridPaths, - }).map(({image, path}) => - image.slot('path', path)), }), ]), ], diff --git a/src/content/dependencies/generateFlashInfoPage.js b/src/content/dependencies/generateFlashInfoPage.js index 350a0fc5..095e43c4 100644 --- a/src/content/dependencies/generateFlashInfoPage.js +++ b/src/content/dependencies/generateFlashInfoPage.js @@ -7,7 +7,7 @@ export default { 'generateContentHeading', 'generateContributionList', 'generateFlashActSidebar', - 'generateFlashCoverArtwork', + 'generateFlashArtworkColumn', 'generateFlashNavAccent', 'generatePageLayout', 'generateTrackList', @@ -47,8 +47,8 @@ export default { query.urls .map(url => relation('linkExternal', url)), - cover: - relation('generateFlashCoverArtwork', flash), + artworkColumn: + relation('generateFlashArtworkColumn', flash), contentHeading: relation('generateContentHeading'), @@ -98,7 +98,7 @@ export default { additionalNames: relations.additionalNamesBox, - cover: relations.cover, + artworkColumnContent: relations.artworkColumn, mainContent: [ html.tag('p', diff --git a/src/content/dependencies/generateGroupGalleryPage.js b/src/content/dependencies/generateGroupGalleryPage.js index 206c495d..d51366ca 100644 --- a/src/content/dependencies/generateGroupGalleryPage.js +++ b/src/content/dependencies/generateGroupGalleryPage.js @@ -53,7 +53,7 @@ export default { relations.carouselImages = carouselAlbums - .map(album => relation('image', album.artTags)); + .map(album => relation('image', album.coverArtworks[0])); } relations.quickDescription = @@ -69,7 +69,7 @@ export default { relations.gridImages = albums.map(album => (album.hasCoverArt - ? relation('image', album.artTags) + ? relation('image', album.coverArtworks[0]) : relation('image'))); return relations; @@ -92,22 +92,6 @@ export default { data.gridDurations = albums.map(album => getTotalDuration(album.tracks)); data.gridNumTracks = albums.map(album => album.tracks.length); - data.gridPaths = - albums.map(album => - (album.hasCoverArt - ? ['media.albumCover', album.directory, album.coverArtFileExtension] - : null)); - - const carouselAlbums = filterItemsForCarousel(group.featuredAlbums); - - if (!empty(group.featuredAlbums)) { - data.carouselPaths = - carouselAlbums.map(album => - (album.hasCoverArt - ? ['media.albumCover', album.directory, album.coverArtFileExtension] - : null)); - } - return data; }, @@ -124,12 +108,7 @@ export default { relations.coverCarousel ?.slots({ links: relations.carouselLinks, - images: - stitchArrays({ - image: relations.carouselImages, - path: data.carouselPaths, - }).map(({image, path}) => - image.slot('path', path)), + images: relations.carouselImages, }), relations.quickDescription, @@ -159,19 +138,19 @@ export default { .slots({ links: relations.gridLinks, names: data.gridNames, + images: stitchArrays({ image: relations.gridImages, - path: data.gridPaths, name: data.gridNames, - }).map(({image, path, name}) => + }).map(({image, name}) => image.slots({ - path, missingSourceContent: language.$('misc.coverGrid.noCoverArt', { album: name, }), })), + info: stitchArrays({ numTracks: data.gridNumTracks, diff --git a/src/content/dependencies/generateIntrapageDotSwitcher.js b/src/content/dependencies/generateIntrapageDotSwitcher.js index 3f300676..1d58367d 100644 --- a/src/content/dependencies/generateIntrapageDotSwitcher.js +++ b/src/content/dependencies/generateIntrapageDotSwitcher.js @@ -42,6 +42,8 @@ export default { }).map(({title, targetID}) => html.tag('a', {href: '#'}, {'data-target-id': targetID}, + {[html.onlyIfContent]: true}, + language.sanitize(title))), }), }; diff --git a/src/content/dependencies/generateLyricsEntry.js b/src/content/dependencies/generateLyricsEntry.js new file mode 100644 index 00000000..4f9c22f1 --- /dev/null +++ b/src/content/dependencies/generateLyricsEntry.js @@ -0,0 +1,25 @@ +export default { + contentDependencies: [ + 'transformContent', + ], + + extraDependencies: ['html', 'language'], + + relations: (relation, entry) => ({ + content: + relation('transformContent', entry.body), + }), + + slots: { + attributes: { + type: 'attributes', + mutable: false, + }, + }, + + generate: (relations, slots, {html}) => + html.tag('div', {class: 'lyrics-entry'}, + slots.attributes, + + relations.content.slot('mode', 'lyrics')), +}; diff --git a/src/content/dependencies/generateLyricsSection.js b/src/content/dependencies/generateLyricsSection.js new file mode 100644 index 00000000..f6b719a9 --- /dev/null +++ b/src/content/dependencies/generateLyricsSection.js @@ -0,0 +1,81 @@ +import {stitchArrays} from '#sugar'; + +export default { + contentDependencies: [ + 'generateContentHeading', + 'generateIntrapageDotSwitcher', + 'generateLyricsEntry', + 'transformContent', + ], + + extraDependencies: ['html', 'language'], + + relations: (relation, entries) => ({ + heading: + relation('generateContentHeading'), + + switcher: + relation('generateIntrapageDotSwitcher'), + + entries: + entries + .map(entry => relation('generateLyricsEntry', entry)), + + annotations: + entries + .map(entry => entry.annotation) + .map(annotation => relation('transformContent', annotation)), + }), + + data: (entries) => ({ + ids: + Array.from( + {length: entries.length}, + (_, index) => 'lyrics-entry-' + index), + }), + + generate: (data, relations, {html, language}) => + language.encapsulate('releaseInfo.lyrics', capsule => + html.tags([ + relations.heading + .slots({ + attributes: {id: 'lyrics'}, + title: language.$(capsule), + }), + + html.tag('p', {class: 'lyrics-switcher'}, + {[html.onlyIfContent]: true}, + + language.$(capsule, 'switcher', { + [language.onlyIfOptions]: ['entries'], + + entries: + relations.switcher.slots({ + initialOptionIndex: 0, + + titles: + relations.annotations.map(annotation => + annotation.slots({ + mode: 'inline', + textOnly: true, + })), + + targetIDs: + data.ids, + }), + })), + + stitchArrays({ + entry: relations.entries, + id: data.ids, + }).map(({entry, id}, index) => + entry.slots({ + attributes: [ + {id}, + + index >= 1 && + {style: 'display: none'}, + ], + })), + ])), +}; diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js index d667a6f4..0acf401c 100644 --- a/src/content/dependencies/generatePageLayout.js +++ b/src/content/dependencies/generatePageLayout.js @@ -1,5 +1,5 @@ import {openAggregate} from '#aggregate'; -import {empty, repeat} from '#sugar'; +import {atOffset, empty, repeat} from '#sugar'; export default { contentDependencies: [ @@ -93,7 +93,7 @@ export default { mutable: false, }, - cover: { + artworkColumnContent: { type: 'html', mutable: false, }, @@ -262,6 +262,17 @@ export default { ? data.canonicalBase + pagePathStringFromRoot : null); + const firstItemInArtworkColumn = + html.smooth(slots.artworkColumnContent) + .content[0]; + + const primaryCover = + (firstItemInArtworkColumn && + html.resolve(firstItemInArtworkColumn, {normalize: 'tag'}) + .attributes.has('class', 'cover-artwork') + ? firstItemInArtworkColumn + : null); + const titleContentsHTML = (html.isBlank(slots.title) ? null @@ -279,7 +290,7 @@ export default { ? [ relations.stickyHeadingContainer.slots({ title: titleContentsHTML, - cover: slots.cover, + cover: primaryCover, }), relations.stickyHeadingContainer.clone().slots({ @@ -316,9 +327,11 @@ export default { [ titleHTML, - html.tag('div', {id: 'cover-art-container'}, + html.tag('div', {id: 'artwork-column'}, {[html.onlyIfContent]: true}, - slots.cover), + {class: 'isolate-tooltip-z-indexing'}, + + slots.artworkColumnContent), subtitleHTML, @@ -361,7 +374,7 @@ export default { slots.navLinks ?.filter(Boolean) - ?.map((cur, i) => { + ?.map((cur, i, entries) => { let content; if (cur.html) { @@ -395,20 +408,13 @@ export default { (slots.navLinkStyle === 'hierarchical' && i === slots.navLinks.length - 1); - return ( + const navLink = html.tag('span', {class: 'nav-link'}, showAsCurrent && {class: 'current'}, [ html.tag('span', {class: 'nav-link-content'}, - // Use inline-block styling on the content span, - // rather than wrapping the whole nav-link in a proper - // blockwrap, so that if the content spans multiple - // lines, it'll kick the accent down beneath it. - i > 0 && - {class: 'blockwrap'}, - content), html.tag('span', {class: 'nav-link-accent'}, @@ -419,7 +425,25 @@ export default { [language.onlyIfOptions]: ['links'], links: cur.accent, })), - ])); + ]); + + if (slots.navLinkStyle === 'index') { + return navLink; + } + + const prev = + atOffset(entries, i, -1); + + if ( + prev && + prev.releaseRestToWrapTogether !== true && + (prev.releaseRestToWrapTogether === false || + prev.auto === 'home') + ) { + return navLink; + } else { + return html.metatag('blockwrap', navLink); + } })), html.tag('div', {class: 'nav-bottom-row'}, @@ -559,6 +583,11 @@ export default { ` background-image: url("${to('media.path', 'bg.jpg')}");\n` + `}`); + const goshFrigginDarnitStyleRule = + `.image-media-link::after {\n` + + ` mask-image: url("${to('staticMisc.path', 'image.svg')}");\n` + + `}`; + const numWallpaperParts = html.resolve(slots.styleRules, {normalize: 'string'}) .match(/\.wallpaper-part:nth-child/g) @@ -709,6 +738,7 @@ export default { .slot('color', slots.color ?? data.wikiColor), fallbackBackgroundStyleRule, + goshFrigginDarnitStyleRule, slots.styleRules, ]), diff --git a/src/content/dependencies/generateReferencedArtworksPage.js b/src/content/dependencies/generateReferencedArtworksPage.js index 3d21b15d..154b4762 100644 --- a/src/content/dependencies/generateReferencedArtworksPage.js +++ b/src/content/dependencies/generateReferencedArtworksPage.js @@ -1,67 +1,55 @@ -import {stitchArrays} from '#sugar'; - export default { contentDependencies: [ + 'generateCoverArtwork', 'generateCoverGrid', 'generatePageLayout', 'image', - 'linkAlbum', - 'linkTrack', + 'linkAnythingMan', ], extraDependencies: ['html', 'language'], - relations: (relation, referencedArtworks) => ({ + relations: (relation, artwork) => ({ layout: relation('generatePageLayout'), + cover: + relation('generateCoverArtwork', artwork), + coverGrid: relation('generateCoverGrid'), links: - referencedArtworks.map(({thing}) => - (thing.album - ? relation('linkTrack', thing) - : relation('linkAlbum', thing))), + artwork.referencedArtworks.map(({artwork}) => + relation('linkAnythingMan', artwork.thing)), images: - referencedArtworks.map(({thing}) => - relation('image', thing.artTags)), + artwork.referencedArtworks.map(({artwork}) => + relation('image', artwork)), }), - data: (referencedArtworks) => ({ + data: (artwork) => ({ + color: + artwork.thing.color, + count: - referencedArtworks.length, + artwork.referencedArtworks.length, names: - referencedArtworks - .map(({thing}) => thing.name), - - paths: - referencedArtworks - .map(({thing}) => - (thing.album - ? ['media.trackCover', thing.album.directory, thing.directory, thing.coverArtFileExtension] - : ['media.albumCover', thing.directory, thing.coverArtFileExtension])), - - dimensions: - referencedArtworks - .map(({thing}) => thing.coverArtDimensions), + artwork.referencedArtworks + .map(({artwork}) => artwork.thing.name), coverArtistNames: - referencedArtworks - .map(({thing}) => - thing.coverArtistContribs + artwork.referencedArtworks + .map(({artwork}) => + artwork.artistContribs .map(contrib => contrib.artist.name)), }), slots: { - color: {validate: v => v.isColor}, - styleRules: {type: 'html', mutable: false}, title: {type: 'html', mutable: false}, - cover: {type: 'html', mutable: true}, navLinks: {validate: v => v.isArray}, navBottomRowContent: {type: 'html', mutable: false}, @@ -73,11 +61,13 @@ export default { title: slots.title, subtitle: language.$(pageCapsule, 'subtitle'), - color: slots.color, + color: data.color, styleRules: slots.styleRules, - cover: - slots.cover.slot('details', 'artists'), + artworkColumnContent: + relations.cover.slots({ + showArtistDetails: true, + }), mainClasses: ['top-index'], mainContent: [ @@ -91,19 +81,9 @@ export default { relations.coverGrid.slots({ links: relations.links, + images: relations.images, names: data.names, - images: - stitchArrays({ - image: relations.images, - path: data.paths, - dimensions: data.dimensions, - }).map(({image, path, dimensions}) => - image.slots({ - path, - dimensions, - })), - info: data.coverArtistNames.map(names => language.$('misc.coverGrid.details.coverArtists', { diff --git a/src/content/dependencies/generateReferencingArtworksPage.js b/src/content/dependencies/generateReferencingArtworksPage.js index 2fe2e93d..55977b37 100644 --- a/src/content/dependencies/generateReferencingArtworksPage.js +++ b/src/content/dependencies/generateReferencingArtworksPage.js @@ -1,67 +1,55 @@ -import {stitchArrays} from '#sugar'; - export default { contentDependencies: [ + 'generateCoverArtwork', 'generateCoverGrid', 'generatePageLayout', 'image', - 'linkAlbum', - 'linkTrack', + 'linkAnythingMan', ], extraDependencies: ['html', 'language'], - relations: (relation, referencingArtworks) => ({ + relations: (relation, artwork) => ({ layout: relation('generatePageLayout'), + cover: + relation('generateCoverArtwork', artwork), + coverGrid: relation('generateCoverGrid'), links: - referencingArtworks.map(({thing}) => - (thing.album - ? relation('linkTrack', thing) - : relation('linkAlbum', thing))), + artwork.referencedByArtworks.map(({artwork}) => + relation('linkAnythingMan', artwork.thing)), images: - referencingArtworks.map(({thing}) => - relation('image', thing.artTags)), + artwork.referencedByArtworks.map(({artwork}) => + relation('image', artwork)), }), - data: (referencingArtworks) => ({ + data: (artwork) => ({ + color: + artwork.thing.color, + count: - referencingArtworks.length, + artwork.referencedByArtworks.length, names: - referencingArtworks - .map(({thing}) => thing.name), - - paths: - referencingArtworks - .map(({thing}) => - (thing.album - ? ['media.trackCover', thing.album.directory, thing.directory, thing.coverArtFileExtension] - : ['media.albumCover', thing.directory, thing.coverArtFileExtension])), - - dimensions: - referencingArtworks - .map(({thing}) => thing.coverArtDimensions), + artwork.referencedByArtworks + .map(({artwork}) => artwork.thing.name), coverArtistNames: - referencingArtworks - .map(({thing}) => - thing.coverArtistContribs + artwork.referencedByArtworks + .map(({artwork}) => + artwork.artistContribs .map(contrib => contrib.artist.name)), }), slots: { - color: {validate: v => v.isColor}, - styleRules: {type: 'html', mutable: false}, title: {type: 'html', mutable: false}, - cover: {type: 'html', mutable: true}, navLinks: {validate: v => v.isArray}, navBottomRowContent: {type: 'html', mutable: false}, @@ -73,11 +61,13 @@ export default { title: slots.title, subtitle: language.$(pageCapsule, 'subtitle'), - color: slots.color, + color: data.color, styleRules: slots.styleRules, - cover: - slots.cover.slot('details', 'artists'), + artworkColumnContent: + relations.cover.slots({ + showArtistDetails: true, + }), mainClasses: ['top-index'], mainContent: [ @@ -91,19 +81,9 @@ export default { relations.coverGrid.slots({ links: relations.links, + images: relations.images, names: data.names, - images: - stitchArrays({ - image: relations.images, - path: data.paths, - dimensions: data.dimensions, - }).map(({image, path, dimensions}) => - image.slots({ - path, - dimensions, - })), - info: data.coverArtistNames.map(names => language.$('misc.coverGrid.details.coverArtists', { diff --git a/src/content/dependencies/generateTrackArtworkColumn.js b/src/content/dependencies/generateTrackArtworkColumn.js new file mode 100644 index 00000000..f06d735b --- /dev/null +++ b/src/content/dependencies/generateTrackArtworkColumn.js @@ -0,0 +1,33 @@ +export default { + contentDependencies: ['generateCoverArtwork'], + extraDependencies: ['html'], + + relations: (relation, track) => ({ + albumCover: + (!track.hasUniqueCoverArt && track.album.hasCoverArt + ? relation('generateCoverArtwork', track.album.coverArtworks[0]) + : null), + + trackCovers: + (track.hasUniqueCoverArt + ? track.trackArtworks.map(artwork => + relation('generateCoverArtwork', artwork)) + : []), + }), + + generate: (relations, {html}) => + html.tags([ + relations.albumCover?.slots({ + showOriginDetails: true, + showArtTagDetails: true, + showReferenceDetails: true, + }), + + relations.trackCovers.map(cover => + cover.slots({ + showOriginDetails: true, + showArtTagDetails: true, + showReferenceDetails: true, + })), + ]), +}; diff --git a/src/content/dependencies/generateTrackCoverArtwork.js b/src/content/dependencies/generateTrackCoverArtwork.js deleted file mode 100644 index 9153e2fc..00000000 --- a/src/content/dependencies/generateTrackCoverArtwork.js +++ /dev/null @@ -1,143 +0,0 @@ -export default { - contentDependencies: [ - 'generateCoverArtwork', - 'generateCoverArtworkArtTagDetails', - 'generateCoverArtworkArtistDetails', - 'generateCoverArtworkReferenceDetails', - 'image', - 'linkAlbum', - 'linkTrackReferencedArtworks', - 'linkTrackReferencingArtworks', - ], - - extraDependencies: ['html', 'language'], - - query: (track) => ({ - artTags: - (track.hasUniqueCoverArt - ? track.artTags - : track.album.artTags), - - coverArtistContribs: - (track.hasUniqueCoverArt - ? track.coverArtistContribs - : track.album.coverArtistContribs), - }), - - relations: (relation, query, track) => ({ - coverArtwork: - relation('generateCoverArtwork'), - - image: - relation('image'), - - artTagDetails: - relation('generateCoverArtworkArtTagDetails', - query.artTags), - - artistDetails: - relation('generateCoverArtworkArtistDetails', - query.coverArtistContribs), - - referenceDetails: - relation('generateCoverArtworkReferenceDetails', - track.referencedArtworks, - track.referencedByArtworks), - - referencedArtworksLink: - relation('linkTrackReferencedArtworks', track), - - referencingArtworksLink: - relation('linkTrackReferencingArtworks', track), - - albumLink: - relation('linkAlbum', track.album), - }), - - data: (query, track) => ({ - path: - (track.hasUniqueCoverArt - ? ['media.trackCover', track.album.directory, track.directory, track.coverArtFileExtension] - : ['media.albumCover', track.album.directory, track.album.coverArtFileExtension]), - - color: - track.color, - - dimensions: - (track.hasUniqueCoverArt - ? track.coverArtDimensions - : track.album.coverArtDimensions), - - nonUnique: - !track.hasUniqueCoverArt, - - warnings: - query.artTags - .filter(tag => tag.isContentWarning) - .map(tag => tag.name), - }), - - slots: { - mode: {type: 'string'}, - - details: { - validate: v => v.is('tags', 'artists'), - default: 'tags', - }, - - showReferenceLinks: { - type: 'boolean', - default: false, - }, - - showNonUniqueLine: { - type: 'boolean', - default: false, - }, - }, - - generate: (data, relations, slots, {html, language}) => - relations.coverArtwork.slots({ - mode: slots.mode, - - image: - relations.image.slots({ - path: data.path, - color: data.color, - alt: language.$('misc.alt.trackCover'), - }), - - dimensions: data.dimensions, - warnings: data.warnings, - - details: [ - slots.details === 'tags' && - relations.artTagDetails, - - slots.details === 'artists'&& - relations.artistDetails, - - slots.showReferenceLinks && - relations.referenceDetails.slots({ - referencedLink: - relations.referencedArtworksLink, - - referencingLink: - relations.referencingArtworksLink, - }), - - slots.showNonUniqueLine && - data.nonUnique && - html.tag('p', {class: 'image-details'}, - {class: 'non-unique-details'}, - - language.$('misc.trackArtFromAlbum', { - album: - relations.albumLink.slots({ - color: false, - }), - })), - ], - }), -}; - diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js index 1c349c2e..11d179ad 100644 --- a/src/content/dependencies/generateTrackInfoPage.js +++ b/src/content/dependencies/generateTrackInfoPage.js @@ -9,9 +9,10 @@ export default { 'generateCommentaryEntry', 'generateContentHeading', 'generateContributionList', + 'generateLyricsSection', 'generatePageLayout', 'generateTrackArtistCommentarySection', - 'generateTrackCoverArtwork', + 'generateTrackArtworkColumn', 'generateTrackInfoPageFeaturedByFlashesList', 'generateTrackInfoPageOtherReleasesList', 'generateTrackList', @@ -58,10 +59,8 @@ export default { additionalNamesBox: relation('generateAdditionalNamesBox', track.additionalNames), - cover: - (track.hasUniqueCoverArt || track.album.hasCoverArt - ? relation('generateTrackCoverArtwork', track) - : null), + artworkColumn: + relation('generateTrackArtworkColumn', track), contentHeading: relation('generateContentHeading'), @@ -92,8 +91,8 @@ export default { flashesThatFeatureList: relation('generateTrackInfoPageFeaturedByFlashesList', track), - lyrics: - relation('transformContent', track.lyrics), + lyricsSection: + relation('generateLyricsSection', track.lyrics), sheetMusicFilesList: relation('generateAlbumAdditionalFilesList', @@ -141,13 +140,8 @@ export default { color: data.color, styleRules: [relations.albumStyleRules], - cover: - (relations.cover - ? relations.cover.slots({ - showReferenceLinks: true, - showNonUniqueLine: true, - }) - : null), + artworkColumnContent: + relations.artworkColumn, mainContent: [ relations.releaseInfo, @@ -315,17 +309,7 @@ export default { relations.flashesThatFeatureList, ]), - html.tags([ - relations.contentHeading.clone() - .slots({ - attributes: {id: 'lyrics'}, - title: language.$('releaseInfo.lyrics'), - }), - - html.tag('blockquote', - {[html.onlyIfContent]: true}, - relations.lyrics.slot('mode', 'lyrics')), - ]), + relations.lyricsSection, html.tags([ relations.contentHeading.clone() diff --git a/src/content/dependencies/generateTrackNavLinks.js b/src/content/dependencies/generateTrackNavLinks.js index e01653f0..6a8b7c64 100644 --- a/src/content/dependencies/generateTrackNavLinks.js +++ b/src/content/dependencies/generateTrackNavLinks.js @@ -15,7 +15,7 @@ export default { track.album.hasTrackNumbers, trackNumber: - track.album.tracks.indexOf(track) + 1, + track.trackNumber, }), slots: { diff --git a/src/content/dependencies/generateTrackReferencedArtworksPage.js b/src/content/dependencies/generateTrackReferencedArtworksPage.js index ac81e525..93438c5b 100644 --- a/src/content/dependencies/generateTrackReferencedArtworksPage.js +++ b/src/content/dependencies/generateTrackReferencedArtworksPage.js @@ -3,7 +3,6 @@ export default { 'generateAlbumStyleRules', 'generateBackToTrackLink', 'generateReferencedArtworksPage', - 'generateTrackCoverArtwork', 'generateTrackNavLinks', ], @@ -11,7 +10,7 @@ export default { relations: (relation, track) => ({ page: - relation('generateReferencedArtworksPage', track.referencedArtworks), + relation('generateReferencedArtworksPage', track.trackArtworks[0]), albumStyleRules: relation('generateAlbumStyleRules', track.album, track), @@ -21,17 +20,11 @@ export default { backToTrackLink: relation('generateBackToTrackLink', track), - - cover: - relation('generateTrackCoverArtwork', track), }), data: (track) => ({ name: track.name, - - color: - track.color, }), generate: (data, relations, {html, language}) => @@ -42,11 +35,8 @@ export default { data.name, }), - color: data.color, styleRules: [relations.albumStyleRules], - cover: relations.cover, - navLinks: html.resolve( relations.navLinks diff --git a/src/content/dependencies/generateTrackReferencingArtworksPage.js b/src/content/dependencies/generateTrackReferencingArtworksPage.js index 097ee929..e9818bad 100644 --- a/src/content/dependencies/generateTrackReferencingArtworksPage.js +++ b/src/content/dependencies/generateTrackReferencingArtworksPage.js @@ -3,7 +3,6 @@ export default { 'generateAlbumStyleRules', 'generateBackToTrackLink', 'generateReferencingArtworksPage', - 'generateTrackCoverArtwork', 'generateTrackNavLinks', ], @@ -11,7 +10,7 @@ export default { relations: (relation, track) => ({ page: - relation('generateReferencingArtworksPage', track.referencedByArtworks), + relation('generateReferencingArtworksPage', track.trackArtworks[0]), albumStyleRules: relation('generateAlbumStyleRules', track.album, track), @@ -21,17 +20,11 @@ export default { backToTrackLink: relation('generateBackToTrackLink', track), - - cover: - relation('generateTrackCoverArtwork', track), }), data: (track) => ({ name: track.name, - - color: - track.color, }), generate: (data, relations, {html, language}) => @@ -42,11 +35,8 @@ export default { data.name, }), - color: data.color, styleRules: [relations.albumStyleRules], - cover: relations.cover, - navLinks: html.resolve( relations.navLinks diff --git a/src/content/dependencies/generateTrackReleaseInfo.js b/src/content/dependencies/generateTrackReleaseInfo.js index 38b8383f..54e462c7 100644 --- a/src/content/dependencies/generateTrackReleaseInfo.js +++ b/src/content/dependencies/generateTrackReleaseInfo.js @@ -14,11 +14,6 @@ export default { relations.artistContributionLinks = relation('generateReleaseInfoContributionsLine', track.artistContribs); - if (track.hasUniqueCoverArt) { - relations.coverArtistContributionsLine = - relation('generateReleaseInfoContributionsLine', track.coverArtistContribs); - } - if (!empty(track.urls)) { relations.externalLinks = track.urls.map(url => @@ -37,7 +32,6 @@ export default { if ( track.hasUniqueCoverArt && - track.coverArtDate && +track.coverArtDate !== +track.date ) { data.coverArtDate = track.coverArtDate; @@ -60,21 +54,11 @@ export default { chronologyKind: 'track', }), - relations.coverArtistContributionsLine?.slots({ - stringKey: capsule + '.coverArtBy', - chronologyKind: 'trackArt', - }), - language.$(capsule, 'released', { [language.onlyIfOptions]: ['date'], date: language.formatDate(data.date), }), - language.$(capsule, 'artReleased', { - [language.onlyIfOptions]: ['date'], - date: language.formatDate(data.coverArtDate), - }), - language.$(capsule, 'duration', { [language.onlyIfOptions]: ['duration'], duration: language.formatDuration(data.duration), diff --git a/src/content/dependencies/generateWikiHomepageAlbumCarouselRow.js b/src/content/dependencies/generateWikiHomepageAlbumCarouselRow.js index 3068d951..b45bfc19 100644 --- a/src/content/dependencies/generateWikiHomepageAlbumCarouselRow.js +++ b/src/content/dependencies/generateWikiHomepageAlbumCarouselRow.js @@ -1,5 +1,3 @@ -import {stitchArrays} from '#sugar'; - export default { contentDependencies: ['generateCoverCarousel', 'image', 'linkAlbum'], @@ -13,27 +11,12 @@ export default { images: row.albums - .map(album => relation('image', album.artTags)), - }), - - data: (row) => ({ - paths: - row.albums.map(album => - (album.hasCoverArt - ? ['media.albumCover', album.directory, album.coverArtFileExtension] - : null)), + .map(album => relation('image', album.coverArtworks[0])), }), - generate: (data, relations) => + generate: (relations) => relations.coverCarousel.slots({ - links: - relations.links, - - images: - stitchArrays({ - image: relations.images, - path: data.paths, - }).map(({image, path}) => - image.slot('path', path)), + links: relations.links, + images: relations.images, }), }; diff --git a/src/content/dependencies/generateWikiHomepageAlbumGridRow.js b/src/content/dependencies/generateWikiHomepageAlbumGridRow.js index c1d2c79d..a00136ba 100644 --- a/src/content/dependencies/generateWikiHomepageAlbumGridRow.js +++ b/src/content/dependencies/generateWikiHomepageAlbumGridRow.js @@ -45,20 +45,17 @@ export default { images: sprawl.albums - .map(album => relation('image', album.artTags)), + .map(album => + relation('image', + (album.hasCoverArt + ? album.coverArtworks[0] + : null))), }), data: (sprawl, _row) => ({ names: sprawl.albums .map(album => album.name), - - paths: - sprawl.albums - .map(album => - (album.hasCoverArt - ? ['media.albumCover', album.directory, album.coverArtFileExtension] - : null)), }), generate: (data, relations, {language}) => @@ -69,11 +66,9 @@ export default { images: stitchArrays({ image: relations.images, - path: data.paths, name: data.names, - }).map(({image, path, name}) => + }).map(({image, name}) => image.slots({ - path, missingSourceContent: language.$('misc.coverGrid.noCoverArt', { album: name, diff --git a/src/content/dependencies/image.js b/src/content/dependencies/image.js index bc268ec1..bf47b14f 100644 --- a/src/content/dependencies/image.js +++ b/src/content/dependencies/image.js @@ -16,68 +16,77 @@ export default { contentDependencies: ['generateColorStyleAttribute'], - relations: (relation) => ({ + relations: (relation, _artwork) => ({ colorStyle: relation('generateColorStyleAttribute'), }), - data(artTags) { - const data = {}; - - if (artTags) { - data.contentWarnings = - artTags - .filter(artTag => artTag.isContentWarning) - .map(artTag => artTag.name); - } else { - data.contentWarnings = null; - } - - return data; - }, + data: (artwork) => ({ + path: + (artwork + ? artwork.path + : null), + + warnings: + (artwork + ? artwork.artTags + .filter(artTag => artTag.isContentWarning) + .map(artTag => artTag.name) + : null), + + dimensions: + (artwork + ? artwork.dimensions + : null), + }), slots: { - src: {type: 'string'}, - - path: { - validate: v => v.validateArrayItems(v.isString), - }, - thumb: {type: 'string'}, + reveal: {type: 'boolean', default: true}, + lazy: {type: 'boolean', default: false}, + square: {type: 'boolean', default: false}, + link: { validate: v => v.anyOf(v.isBoolean, v.isString), default: false, }, - color: { - validate: v => v.isColor, - }, + color: {validate: v => v.isColor}, - warnings: { - validate: v => v.looseArrayOf(v.isString), + // Added to the .image-container. + attributes: { + type: 'attributes', + mutable: false, }, - reveal: {type: 'boolean', default: true}, - lazy: {type: 'boolean', default: false}, - - square: {type: 'boolean', default: false}, + // Added to the <img> itself. + alt: {type: 'string'}, - dimensions: { - validate: v => v.isDimensions, - }, + // Specify 'src' or 'path', or the path will be used from the artwork. + // If none of the above is present, the message in missingSourceContent + // will be displayed instead. - alt: {type: 'string'}, + src: {type: 'string'}, - attributes: { - type: 'attributes', - mutable: false, + path: { + validate: v => v.validateArrayItems(v.isString), }, missingSourceContent: { type: 'html', mutable: false, }, + + // These will also be used from the artwork if not specified as slots. + + warnings: { + validate: v => v.looseArrayOf(v.isString), + }, + + dimensions: { + validate: v => v.isDimensions, + }, }, generate(data, relations, slots, { @@ -91,15 +100,14 @@ export default { missingImagePaths, to, }) { - let originalSrc; - - if (slots.src) { - originalSrc = slots.src; - } else if (!empty(slots.path)) { - originalSrc = to(...slots.path); - } else { - originalSrc = ''; - } + const originalSrc = + (slots.src + ? slots.src + : slots.path + ? to(...slots.path) + : data.path + ? to(...data.path) + : ''); // TODO: This feels janky. It's necessary to deal with static content that // includes strings like <img src="media/misc/foo.png">, but processing the @@ -121,29 +129,27 @@ export default { !isMissingImageFile && (typeof slots.link === 'string' || slots.link); - const contentWarnings = - slots.warnings ?? - data.contentWarnings; + const warnings = slots.warnings ?? data.warnings; + const dimensions = slots.dimensions ?? data.dimensions; const willReveal = slots.reveal && originalSrc && !isMissingImageFile && - !empty(contentWarnings); - - const willSquare = - slots.square; + !empty(warnings); const imgAttributes = html.attributes([ {class: 'image'}, slots.alt && {alt: slots.alt}, - slots.dimensions?.[0] && - {width: slots.dimensions[0]}, + dimensions && + dimensions[0] && + {width: dimensions[0]}, - slots.dimensions?.[1] && - {height: slots.dimensions[1]}, + dimensions && + dimensions[1] && + {height: dimensions[1]}, ]); const isPlaceholder = @@ -169,7 +175,7 @@ export default { html.tag('span', {class: 'reveal-warnings'}, language.$('misc.contentWarnings.warnings', { - warnings: language.formatUnitList(contentWarnings), + warnings: language.formatUnitList(warnings), })), html.tag('br'), @@ -323,14 +329,14 @@ export default { wrapped = html.tag('div', {class: 'image-outer-area'}, - willSquare && + slots.square && {class: 'square-content'}, wrapped); wrapped = html.tag('div', {class: 'image-container'}, - willSquare && + slots.square && {class: 'square'}, typeof slots.link === 'string' && diff --git a/src/content/dependencies/linkAnythingMan.js b/src/content/dependencies/linkAnythingMan.js index d4697403..e408c1b2 100644 --- a/src/content/dependencies/linkAnythingMan.js +++ b/src/content/dependencies/linkAnythingMan.js @@ -1,6 +1,7 @@ export default { contentDependencies: [ 'linkAlbum', + 'linkArtwork', 'linkFlash', 'linkTrack', ], @@ -13,6 +14,8 @@ export default { link: (query.referenceType === 'album' ? relation('linkAlbum', thing) + : query.referenceType === 'artwork' + ? relation('linkArtwork', thing) : query.referenceType === 'flash' ? relation('linkFlash', thing) : query.referenceType === 'track' diff --git a/src/content/dependencies/linkArtwork.js b/src/content/dependencies/linkArtwork.js new file mode 100644 index 00000000..8cd6f359 --- /dev/null +++ b/src/content/dependencies/linkArtwork.js @@ -0,0 +1,20 @@ +export default { + contentDependencies: ['linkAlbum', 'linkTrack'], + + query: (artwork) => ({ + referenceType: + artwork.thing.constructor[Symbol.for('Thing.referenceType')], + }), + + relations: (relation, query, artwork) => ({ + link: + (query.referenceType === 'album' + ? relation('linkAlbum', artwork.thing) + : query.referenceType === 'track' + ? relation('linkTrack', artwork.thing) + : null), + }), + + generate: (relations) => + relations.link, +}; diff --git a/src/content/dependencies/linkReferencedArtworks.js b/src/content/dependencies/linkReferencedArtworks.js new file mode 100644 index 00000000..c456b808 --- /dev/null +++ b/src/content/dependencies/linkReferencedArtworks.js @@ -0,0 +1,24 @@ +import Thing from '#thing'; + +export default { + contentDependencies: [ + 'linkAlbumReferencedArtworks', + 'linkTrackReferencedArtworks', + ], + + query: (artwork) => ({ + referenceType: + artwork.thing.constructor[Thing.referenceType], + }), + + relations: (relation, query, artwork) => ({ + link: + (query.referenceType === 'album' + ? relation('linkAlbumReferencedArtworks', artwork.thing) + : query.referenceType === 'track' + ? relation('linkTrackReferencedArtworks', artwork.thing) + : null), + }), + + generate: (relations) => relations.link, +}; diff --git a/src/content/dependencies/linkReferencingArtworks.js b/src/content/dependencies/linkReferencingArtworks.js new file mode 100644 index 00000000..0cfca4db --- /dev/null +++ b/src/content/dependencies/linkReferencingArtworks.js @@ -0,0 +1,24 @@ +import Thing from '#thing'; + +export default { + contentDependencies: [ + 'linkAlbumReferencingArtworks', + 'linkTrackReferencingArtworks', + ], + + query: (artwork) => ({ + referenceType: + artwork.thing.constructor[Thing.referenceType], + }), + + relations: (relation, query, artwork) => ({ + link: + (query.referenceType === 'album' + ? relation('linkAlbumReferencingArtworks', artwork.thing) + : query.referenceType === 'track' + ? relation('linkTrackReferencingArtworks', artwork.thing) + : null), + }), + + generate: (relations) => relations.link, +}; diff --git a/src/content/dependencies/listArtTagNetwork.js b/src/content/dependencies/listArtTagNetwork.js index 5386dcdc..93dd4ce8 100644 --- a/src/content/dependencies/listArtTagNetwork.js +++ b/src/content/dependencies/listArtTagNetwork.js @@ -29,21 +29,21 @@ export default { const getStats = (artTag) => ({ directUses: - artTag.directlyTaggedInThings.length, + artTag.directlyFeaturedInArtworks.length, // Not currently displayed directAndIndirectUses: unique([ - ...artTag.indirectlyTaggedInThings, - ...artTag.directlyTaggedInThings, + ...artTag.indirectlyFeaturedInArtworks, + ...artTag.directlyFeaturedInArtworks, ]).length, totalUses: [ - ...artTag.directlyTaggedInThings, + ...artTag.directlyFeaturedInArtworks, ... artTag.allDescendantArtTags - .flatMap(artTag => artTag.directlyTaggedInThings), + .flatMap(artTag => artTag.directlyFeaturedInArtworks), ].length, descendants: diff --git a/src/content/dependencies/listArtTagsByName.js b/src/content/dependencies/listArtTagsByName.js index 31856478..1df9dfff 100644 --- a/src/content/dependencies/listArtTagsByName.js +++ b/src/content/dependencies/listArtTagsByName.js @@ -35,8 +35,8 @@ export default { counts: query.artTags.map(artTag => unique([ - ...artTag.indirectlyTaggedInThings, - ...artTag.directlyTaggedInThings, + ...artTag.indirectlyFeaturedInArtworks, + ...artTag.directlyFeaturedInArtworks, ]).length), }; }, diff --git a/src/content/dependencies/listArtTagsByUses.js b/src/content/dependencies/listArtTagsByUses.js index fcd324f7..eca7f1c6 100644 --- a/src/content/dependencies/listArtTagsByUses.js +++ b/src/content/dependencies/listArtTagsByUses.js @@ -17,8 +17,8 @@ export default { const counts = artTags.map(artTag => unique([ - ...artTag.directlyTaggedInThings, - ...artTag.indirectlyTaggedInThings, + ...artTag.directlyFeaturedInArtworks, + ...artTag.indirectlyFeaturedInArtworks, ]).length); filterByCount(artTags, counts); diff --git a/src/content/dependencies/listArtistsByGroup.js b/src/content/dependencies/listArtistsByGroup.js index 0bf9dd2d..17096cfc 100644 --- a/src/content/dependencies/listArtistsByGroup.js +++ b/src/content/dependencies/listArtistsByGroup.js @@ -37,20 +37,25 @@ export default { ([ (unique( ([ - artist.albumArtistContributions, - artist.albumCoverArtistContributions, - artist.albumWallpaperArtistContributions, - artist.albumBannerArtistContributions, + artist.albumArtistContributions + .map(contrib => contrib.thing), + artist.albumCoverArtistContributions + .map(contrib => contrib.thing.thing), + artist.albumWallpaperArtistContributions + .map(contrib => contrib.thing.thing), + artist.albumBannerArtistContributions + .map(contrib => contrib.thing.thing), ]).flat() - .map(({thing}) => thing) )).map(album => album.groups), (unique( ([ - artist.trackArtistContributions, - artist.trackContributorContributions, - artist.trackCoverArtistContributions, + artist.trackArtistContributions + .map(contrib => contrib.thing), + artist.trackContributorContributions + .map(contrib => contrib.thing), + artist.trackCoverArtistContributions + .map(contrib => contrib.thing.thing), ]).flat() - .map(({thing}) => thing) )).map(track => track.album.groups), ]).flat() .map(groups => groups diff --git a/src/content/dependencies/listArtistsByLatestContribution.js b/src/content/dependencies/listArtistsByLatestContribution.js index 27a2faa3..2a8d1b4c 100644 --- a/src/content/dependencies/listArtistsByLatestContribution.js +++ b/src/content/dependencies/listArtistsByLatestContribution.js @@ -98,13 +98,16 @@ export default { ])) { // Might combine later with 'track' of the same album and date. considerDate(artist, album.coverArtDate ?? album.date, album, 'artwork'); + // '?? album.date' is kept here because wallpaper and banner may + // technically be present for an album w/o cover art, therefore + // also no cover art date. } } for (const track of tracksLatestFirst) { for (const artist of getArtists(track, 'coverArtistContribs')) { // No special effect if artist already has 'artwork' for the same album and date. - considerDate(artist, track.coverArtDate ?? track.date, track.album, 'artwork'); + considerDate(artist, track.coverArtDate, track.album, 'artwork'); } for (const artist of new Set([ diff --git a/src/content/dependencies/listTracksWithLyrics.js b/src/content/dependencies/listTracksWithLyrics.js index a13a76f0..e6ab9d7d 100644 --- a/src/content/dependencies/listTracksWithLyrics.js +++ b/src/content/dependencies/listTracksWithLyrics.js @@ -2,7 +2,7 @@ export default { contentDependencies: ['listTracksWithExtra'], relations: (relation, spec) => - ({page: relation('listTracksWithExtra', spec, 'lyrics', 'truthy')}), + ({page: relation('listTracksWithExtra', spec, 'lyrics', 'array')}), generate: (relations) => relations.page, diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js index f56a1da9..1bbd45e2 100644 --- a/src/content/dependencies/transformContent.js +++ b/src/content/dependencies/transformContent.js @@ -2,6 +2,7 @@ import {bindFind} from '#find'; import {replacerSpec, parseInput} from '#replacer'; import {Marked} from 'marked'; +import striptags from 'striptags'; const commonMarkedOptions = { headerIds: false, @@ -184,6 +185,8 @@ export default { link: relation(name, arg), label: node.data.label, hash: node.data.hash, + name: arg?.name, + shortName: arg?.shortName ?? arg?.nameShort, } : getPlaceholder(node, content)); @@ -241,6 +244,11 @@ export default { default: true, }, + textOnly: { + type: 'boolean', + default: false, + }, + thumb: { validate: v => v.is('small', 'medium', 'large'), default: 'large', @@ -452,7 +460,17 @@ export default { nodeFromRelations.link, {slots: ['content', 'hash']}); - const {label, hash} = nodeFromRelations; + const {label, hash, shortName, name} = nodeFromRelations; + + if (slots.textOnly) { + if (label) { + return {type: 'text', data: label}; + } else if (slots.preferShortLinkNames) { + return {type: 'text', data: shortName ?? name}; + } else { + return {type: 'text', data: name}; + } + } // These are removed from the typical combined slots({})-style // because we don't want to override slots that were already set @@ -506,6 +524,10 @@ export default { const {label} = node.data; const externalLink = relations.externalLinks[externalLinkIndex++]; + if (slots.textOnly) { + return {type: 'text', data: label}; + } + externalLink.setSlots({ content: label, fromContent: true, @@ -542,12 +564,19 @@ export default { ? valueFn(replacerValue) : replacerValue); - const contents = + const content = (htmlFn ? htmlFn(value, {html, language}) : value); - return {type: 'text', data: contents.toString()}; + const contentText = + html.resolve(content, {normalize: 'string'}); + + if (slots.textOnly) { + return {type: 'text', data: striptags(contentText)}; + } else { + return {type: 'text', data: contentText}; + } } default: |