From 89e79008b02331b69660bb16b6ca737e37483e61 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 23 Jun 2023 19:41:15 -0300 Subject: content: generateCoverCarousel This also introduces a handy stitchArrays() utility, which probably has some uses not caught in this commit. --- src/content/dependencies/generateCoverCarousel.js | 54 +++++++++++ src/content/dependencies/generateCoverGrid.js | 45 +++++----- .../dependencies/generateGroupGalleryPage.js | 100 ++++++++++++++------- 3 files changed, 145 insertions(+), 54 deletions(-) create mode 100644 src/content/dependencies/generateCoverCarousel.js (limited to 'src/content') diff --git a/src/content/dependencies/generateCoverCarousel.js b/src/content/dependencies/generateCoverCarousel.js new file mode 100644 index 00000000..2a2503ac --- /dev/null +++ b/src/content/dependencies/generateCoverCarousel.js @@ -0,0 +1,54 @@ +import {empty, repeat, stitchArrays} from '../../util/sugar.js'; +import {getCarouselLayoutForNumberOfItems} from '../../util/wiki-data.js'; + +export default { + extraDependencies: ['html'], + + slots: { + images: {validate: v => v.arrayOf(v.isHTML)}, + links: {validate: v => v.arrayOf(v.isHTML)}, + + lazy: {validate: v => v.oneOf(v.isWholeNumber, v.isBoolean)}, + }, + + generate(slots, {html}) { + const stitched = + stitchArrays({ + image: slots.images, + link: slots.links, + }); + + if (empty(stitched)) { + return; + } + + const layout = getCarouselLayoutForNumberOfItems(stitched.length); + + return html.tag('div', + { + class: 'carousel-container', + 'data-carousel-rows': layout.rows, + 'data-carousel-columns': layout.columns, + }, + repeat(3, [ + html.tag('div', + {class: 'carousel-grid', 'aria-hidden': 'true'}, + stitched.map(({image, link}, index) => + html.tag('div', {class: 'carousel-item'}, + link.slots({ + attributes: {tabindex: '-1'}, + content: + image.slots({ + thumb: 'small', + square: true, + lazy: + (typeof slots.lazy === 'number' + ? index >= slots.lazy + : typeof slots.lazy === 'boolean' + ? slots.lazy + : false), + }), + })))), + ])); + }, +}; diff --git a/src/content/dependencies/generateCoverGrid.js b/src/content/dependencies/generateCoverGrid.js index a024ae25..970aa05c 100644 --- a/src/content/dependencies/generateCoverGrid.js +++ b/src/content/dependencies/generateCoverGrid.js @@ -1,3 +1,5 @@ +import {stitchArrays} from '../../util/sugar.js'; + export default { extraDependencies: ['html'], @@ -12,27 +14,26 @@ export default { generate(slots, {html}) { return ( html.tag('div', {class: 'grid-listing'}, - slots.images.map((image, i) => { - const link = slots.links[i]; - const name = slots.names[i]; - return link.slots({ - content: [ - image.slots({ - thumb: 'medium', - lazy: - (typeof slots.lazy === 'number' - ? i >= slots.lazy - : typeof slots.lazy === 'boolean' - ? slots.lazy - : false), - square: true, - }), - html.tag('span', name), - ], - attributes: { - class: ['grid-item', 'box', /* large && 'large-grid-item' */], - }, - }); - }))); + stitchArrays({ + image: slots.images, + link: slots.links, + name: slots.names, + }).map(({image, link, name}, index) => + link.slots({ + attributes: {class: ['grid-item', 'box']}, + content: [ + image.slots({ + thumb: 'medium', + square: true, + lazy: + (typeof slots.lazy === 'number' + ? index >= slots.lazy + : typeof slots.lazy === 'boolean' + ? slots.lazy + : false), + }), + html.tag('span', name), + ], + })))); }, }; diff --git a/src/content/dependencies/generateGroupGalleryPage.js b/src/content/dependencies/generateGroupGalleryPage.js index 1ec53a0a..168bf799 100644 --- a/src/content/dependencies/generateGroupGalleryPage.js +++ b/src/content/dependencies/generateGroupGalleryPage.js @@ -1,4 +1,7 @@ +import {empty, stitchArrays} from '../../util/sugar.js'; + import { + filterItemsForCarousel, getTotalDuration, sortChronologically, } from '../../util/wiki-data.js'; @@ -6,6 +9,7 @@ import { export default { contentDependencies: [ 'generateColorStyleRules', + 'generateCoverCarousel', 'generateCoverGrid', 'generateGroupNavLinks', 'generateGroupSidebar', @@ -55,14 +59,29 @@ export default { relation('linkListing', sprawl.groupsByCategoryListing); } + const carouselAlbums = filterItemsForCarousel(group.featuredAlbums); + + if (!empty(carouselAlbums)) { + relations.coverCarousel = + relation('generateCoverCarousel'); + + relations.carouselLinks = + carouselAlbums + .map(album => relation('linkAlbum', album)); + + relations.carouselImages = + carouselAlbums + .map(album => relation('image', album.artTags)); + } + relations.coverGrid = relation('generateCoverGrid'); - relations.links = + relations.gridLinks = albums .map(album => relation('linkAlbum', album)); - relations.images = + relations.gridImages = albums.map(album => (album.hasCoverArt ? relation('image', album.artTags) @@ -72,25 +91,35 @@ export default { }, data(sprawl, group) { - const albums = - sortChronologically(group.albums.slice(), {latestFirst: true}); + const data = {}; - const tracks = albums.flatMap((album) => album.tracks); - const totalDuration = getTotalDuration(tracks, {originalReleasesOnly: true}); + data.name = group.name; - return { - name: group.name, + const albums = sortChronologically(group.albums.slice(), {latestFirst: true}); + const tracks = albums.flatMap((album) => album.tracks); - numAlbums: albums.length, - numTracks: tracks.length, - totalDuration, + data.numAlbums = albums.length; + data.numTracks = tracks.length; + data.totalDuration = getTotalDuration(tracks, {originalReleasesOnly: true}); - names: albums.map(album => album.name), - paths: albums.map(album => + data.gridNames = albums.map(album => album.name); + data.gridPaths = + albums.map(album => (album.hasCoverArt ? ['media.albumCover', album.directory, album.coverArtFileExtension] - : null)), - }; + : 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; }, generate(data, relations, {html, language}) { @@ -103,13 +132,16 @@ export default { mainClasses: ['top-index'], mainContent: [ - /* - getCarouselHTML({ - items: group.featuredAlbums.slice(0, 12 + 1), - srcFn: getAlbumCover, - linkFn: link.album, - }), - */ + relations.coverCarousel + ?.slots({ + links: relations.carouselLinks, + images: + stitchArrays({ + image: relations.carouselImages, + path: data.carouselPaths, + }).map(({image, path}) => + image.slot('path', path)), + }), html.tag('p', {class: 'quick-info'}, @@ -139,17 +171,21 @@ export default { relations.coverGrid .slots({ - links: relations.links, - names: data.names, + links: relations.gridLinks, + names: data.gridNames, images: - relations.images.map((image, i) => - image.slots({ - path: data.paths[i], - missingSourceContent: - language.$('misc.albumGrid.noCoverArt', { - album: data.names[i], - }), - })), + stitchArrays({ + image: relations.gridImages, + path: data.gridPaths, + name: data.gridNames, + }).map(({image, path, name}) => + image.slots({ + path, + missingSourceContent: + language.$('misc.albumGrid.noCoverArt', { + album: name, + }), + })), }), ], -- cgit 1.3.0-6-gf8a5