From 60b6715b38d137f8d6d0ce3c537a546a507ecf1f Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 20 Aug 2023 21:22:15 -0300 Subject: content: listArtistsByName: divide by main groups --- src/content/dependencies/listArtistsByName.js | 123 ++++++++++++++++++++------ 1 file changed, 94 insertions(+), 29 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/listArtistsByName.js b/src/content/dependencies/listArtistsByName.js index 6c0ad836..d83150e8 100644 --- a/src/content/dependencies/listArtistsByName.js +++ b/src/content/dependencies/listArtistsByName.js @@ -1,51 +1,116 @@ -import {stitchArrays} from '#sugar'; +import {empty, stitchArrays, unique} from '#sugar'; import {getArtistNumContributions, sortAlphabetically} from '#wiki-data'; export default { - contentDependencies: ['generateListingPage', 'linkArtist'], + contentDependencies: ['generateListingPage', 'linkArtist', 'linkGroup'], extraDependencies: ['language', 'wikiData'], - sprawl({artistData}) { - return {artistData}; + sprawl({artistData, wikiInfo}) { + return {artistData, wikiInfo}; }, - query({artistData}, spec) { - return { - spec, + query(sprawl, spec) { + const artists = sortAlphabetically(sprawl.artistData.slice()); + const groups = sprawl.wikiInfo.divideTrackListsByGroups; - artists: sortAlphabetically(artistData.slice()), - }; + if (empty(groups)) { + return {spec, artists}; + } + + const artistGroups = + artists.map(artist => + unique( + unique([ + ...artist.albumsAsAny, + ...artist.tracksAsAny.map(track => track.album), + ]).flatMap(album => album.groups))) + + const artistsByGroup = + groups.map(group => + artists.filter((artist, index) => artistGroups[index].includes(group))); + + return {spec, groups, artistsByGroup}; }, relations(relation, query) { - return { - page: relation('generateListingPage', query.spec), + const relations = {}; - artistLinks: + relations.page = + relation('generateListingPage', query.spec); + + if (query.artists) { + relations.artistLinks = query.artists - .map(artist => relation('linkArtist', artist)), - }; + .map(artist => relation('linkArtist', artist)); + } + + if (query.artistsByGroup) { + relations.groupLinks = + query.groups + .map(group => relation('linkGroup', group)); + + relations.artistLinksByGroup = + query.artistsByGroup + .map(artists => artists + .map(artist => relation('linkArtist', artist))); + } + + return relations; }, data(query) { - return { - counts: + const data = {}; + + if (query.artists) { + data.counts = query.artists - .map(artist => getArtistNumContributions(artist)), - }; + .map(artist => getArtistNumContributions(artist)); + } + + if (query.artistsByGroup) { + data.countsByGroup = + query.artistsByGroup + .map(artists => artists + .map(artist => getArtistNumContributions(artist))); + } + + return data; }, generate(data, relations, {language}) { - return relations.page.slots({ - type: 'rows', - rows: - stitchArrays({ - link: relations.artistLinks, - count: data.counts, - }).map(({link, count}) => ({ - artist: link, - contributions: language.countContributions(count, {unit: true}), - })), - }); + return ( + (relations.artistLinksByGroup + ? relations.page.slots({ + type: 'chunks', + + chunkTitles: + relations.groupLinks.map(groupLink => ({ + group: groupLink, + })), + + chunkRows: + stitchArrays({ + artistLinks: relations.artistLinksByGroup, + counts: data.countsByGroup, + }).map(({artistLinks, counts}) => + stitchArrays({ + link: artistLinks, + count: counts, + }).map(({link, count}) => ({ + artist: link, + contributions: language.countContributions(count, {unit: true}), + }))), + }) + : relations.page.slots({ + type: 'rows', + rows: + stitchArrays({ + link: relations.artistLinks, + count: data.counts, + }).map(({link, count}) => ({ + artist: link, + contributions: language.countContributions(count, {unit: true}), + })), + }))); }, }; -- cgit 1.3.0-6-gf8a5 From e035dab576875bca12485f60a1aeb257c394c723 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 20 Aug 2023 22:07:05 -0300 Subject: content: generateListingPage: "skip to a section" --- src/content/dependencies/generateListingPage.js | 38 +++++++++++++++++++++++-- src/content/dependencies/listArtistsByName.js | 19 ++++++++++++- 2 files changed, 53 insertions(+), 4 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index 08eb40c6..4de2d006 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -7,6 +7,7 @@ export default { 'generatePageLayout', 'linkListing', 'linkListingIndex', + 'linkTemplate', ], extraDependencies: ['html', 'language', 'wikiData'], @@ -26,6 +27,9 @@ export default { relations.chunkHeading = relation('generateContentHeading'); + relations.showSkipToSectionLinkTemplate = + relation('linkTemplate'); + if (listing.target.listings.length > 1) { relations.sameTargetListingLinks = listing.target.listings @@ -65,6 +69,9 @@ export default { chunkTitles: {validate: v => v.strictArrayOf(v.isObject)}, chunkRows: {validate: v => v.strictArrayOf(v.isObject)}, + showSkipToSection: {type: 'boolean', default: false}, + chunkIDs: {validate: v => v.strictArrayOf(v.isString)}, + listStyle: { validate: v => v.is('ordered', 'unordered'), default: 'unordered', @@ -128,16 +135,40 @@ export default { formatListingString('item', row)))), slots.type === 'chunks' && - html.tag('dl', + html.tag('dl', [ + slots.showSkipToSection && [ + html.tag('dt', + language.$('listingPage.skipToSection')), + + html.tag('dd', + html.tag('ul', + stitchArrays({ + title: slots.chunkTitles, + id: slots.chunkIDs, + }).filter(({id}) => id) + .map(({title, id}) => + html.tag('li', + relations.showSkipToSectionLinkTemplate + .clone() + .slots({ + hash: id, + content: + formatListingString('chunk.title', title) + .replace(/:$/, ''), + }))))), + ], + stitchArrays({ title: slots.chunkTitles, rows: slots.chunkRows, - }).map(({title, rows}) => [ + id: slots.chunkIDs, + }).map(({title, rows, id}) => [ relations.chunkHeading .clone() .slots({ tag: 'dt', title: formatListingString('chunk.title', title), + id, }), html.tag('dd', @@ -146,7 +177,8 @@ export default { html.tag('li', {class: row.stringsKey === 'rerelease' && 'rerelease'}, formatListingString('chunk.item', row))))), - ])), + ]), + ]), slots.type === 'custom' && slots.content, diff --git a/src/content/dependencies/listArtistsByName.js b/src/content/dependencies/listArtistsByName.js index d83150e8..3778b9e3 100644 --- a/src/content/dependencies/listArtistsByName.js +++ b/src/content/dependencies/listArtistsByName.js @@ -1,5 +1,10 @@ import {empty, stitchArrays, unique} from '#sugar'; -import {getArtistNumContributions, sortAlphabetically} from '#wiki-data'; + +import { + filterMultipleArrays, + getArtistNumContributions, + sortAlphabetically, +} from '#wiki-data'; export default { contentDependencies: ['generateListingPage', 'linkArtist', 'linkGroup'], @@ -29,6 +34,9 @@ export default { groups.map(group => artists.filter((artist, index) => artistGroups[index].includes(group))); + filterMultipleArrays(groups, artistsByGroup, + (group, artists) => !empty(artists)); + return {spec, groups, artistsByGroup}; }, @@ -68,6 +76,10 @@ export default { } if (query.artistsByGroup) { + data.groupDirectories = + query.groups + .map(group => group.directory); + data.countsByGroup = query.artistsByGroup .map(artists => artists @@ -83,6 +95,11 @@ export default { ? relations.page.slots({ type: 'chunks', + showSkipToSection: true, + chunkIDs: + data.groupDirectories + .map(directory => `contributed-to-${directory}`), + chunkTitles: relations.groupLinks.map(groupLink => ({ group: groupLink, -- cgit 1.3.0-6-gf8a5 From f12605331f60796da178f3d4b7bbc096f02b0d48 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 28 Aug 2023 09:34:29 -0300 Subject: content: move new "Artists - by Name" implementation to "by Group" --- src/content/dependencies/listArtistsByGroup.js | 133 ++++++++++++++++++++++ src/content/dependencies/listArtistsByName.js | 151 ++++++------------------- 2 files changed, 165 insertions(+), 119 deletions(-) create mode 100644 src/content/dependencies/listArtistsByGroup.js (limited to 'src/content') diff --git a/src/content/dependencies/listArtistsByGroup.js b/src/content/dependencies/listArtistsByGroup.js new file mode 100644 index 00000000..3778b9e3 --- /dev/null +++ b/src/content/dependencies/listArtistsByGroup.js @@ -0,0 +1,133 @@ +import {empty, stitchArrays, unique} from '#sugar'; + +import { + filterMultipleArrays, + getArtistNumContributions, + sortAlphabetically, +} from '#wiki-data'; + +export default { + contentDependencies: ['generateListingPage', 'linkArtist', 'linkGroup'], + extraDependencies: ['language', 'wikiData'], + + sprawl({artistData, wikiInfo}) { + return {artistData, wikiInfo}; + }, + + query(sprawl, spec) { + const artists = sortAlphabetically(sprawl.artistData.slice()); + const groups = sprawl.wikiInfo.divideTrackListsByGroups; + + if (empty(groups)) { + return {spec, artists}; + } + + const artistGroups = + artists.map(artist => + unique( + unique([ + ...artist.albumsAsAny, + ...artist.tracksAsAny.map(track => track.album), + ]).flatMap(album => album.groups))) + + const artistsByGroup = + groups.map(group => + artists.filter((artist, index) => artistGroups[index].includes(group))); + + filterMultipleArrays(groups, artistsByGroup, + (group, artists) => !empty(artists)); + + return {spec, groups, artistsByGroup}; + }, + + relations(relation, query) { + const relations = {}; + + relations.page = + relation('generateListingPage', query.spec); + + if (query.artists) { + relations.artistLinks = + query.artists + .map(artist => relation('linkArtist', artist)); + } + + if (query.artistsByGroup) { + relations.groupLinks = + query.groups + .map(group => relation('linkGroup', group)); + + relations.artistLinksByGroup = + query.artistsByGroup + .map(artists => artists + .map(artist => relation('linkArtist', artist))); + } + + return relations; + }, + + data(query) { + const data = {}; + + if (query.artists) { + data.counts = + query.artists + .map(artist => getArtistNumContributions(artist)); + } + + if (query.artistsByGroup) { + data.groupDirectories = + query.groups + .map(group => group.directory); + + data.countsByGroup = + query.artistsByGroup + .map(artists => artists + .map(artist => getArtistNumContributions(artist))); + } + + return data; + }, + + generate(data, relations, {language}) { + return ( + (relations.artistLinksByGroup + ? relations.page.slots({ + type: 'chunks', + + showSkipToSection: true, + chunkIDs: + data.groupDirectories + .map(directory => `contributed-to-${directory}`), + + chunkTitles: + relations.groupLinks.map(groupLink => ({ + group: groupLink, + })), + + chunkRows: + stitchArrays({ + artistLinks: relations.artistLinksByGroup, + counts: data.countsByGroup, + }).map(({artistLinks, counts}) => + stitchArrays({ + link: artistLinks, + count: counts, + }).map(({link, count}) => ({ + artist: link, + contributions: language.countContributions(count, {unit: true}), + }))), + }) + : relations.page.slots({ + type: 'rows', + rows: + stitchArrays({ + link: relations.artistLinks, + count: data.counts, + }).map(({link, count}) => ({ + artist: link, + contributions: language.countContributions(count, {unit: true}), + })), + }))); + }, +}; diff --git a/src/content/dependencies/listArtistsByName.js b/src/content/dependencies/listArtistsByName.js index 3778b9e3..554b4587 100644 --- a/src/content/dependencies/listArtistsByName.js +++ b/src/content/dependencies/listArtistsByName.js @@ -1,133 +1,46 @@ -import {empty, stitchArrays, unique} from '#sugar'; - -import { - filterMultipleArrays, - getArtistNumContributions, - sortAlphabetically, -} from '#wiki-data'; +import {stitchArrays} from '#sugar'; +import {getArtistNumContributions, sortAlphabetically} from '#wiki-data'; export default { contentDependencies: ['generateListingPage', 'linkArtist', 'linkGroup'], extraDependencies: ['language', 'wikiData'], - sprawl({artistData, wikiInfo}) { - return {artistData, wikiInfo}; - }, - - query(sprawl, spec) { - const artists = sortAlphabetically(sprawl.artistData.slice()); - const groups = sprawl.wikiInfo.divideTrackListsByGroups; - - if (empty(groups)) { - return {spec, artists}; - } - - const artistGroups = - artists.map(artist => - unique( - unique([ - ...artist.albumsAsAny, - ...artist.tracksAsAny.map(track => track.album), - ]).flatMap(album => album.groups))) - - const artistsByGroup = - groups.map(group => - artists.filter((artist, index) => artistGroups[index].includes(group))); - - filterMultipleArrays(groups, artistsByGroup, - (group, artists) => !empty(artists)); - - return {spec, groups, artistsByGroup}; - }, - - relations(relation, query) { - const relations = {}; + sprawl: ({artistData, wikiInfo}) => + ({artistData, wikiInfo}), - relations.page = - relation('generateListingPage', query.spec); + query: (sprawl, spec) => ({ + spec, - if (query.artists) { - relations.artistLinks = - query.artists - .map(artist => relation('linkArtist', artist)); - } + artists: + sortAlphabetically(sprawl.artistData.slice()), + }), - if (query.artistsByGroup) { - relations.groupLinks = - query.groups - .map(group => relation('linkGroup', group)); + relations: (relation, query) => ({ + page: + relation('generateListingPage', query.spec), - relations.artistLinksByGroup = - query.artistsByGroup - .map(artists => artists - .map(artist => relation('linkArtist', artist))); - } + artistLinks: + query.artists + .map(artist => relation('linkArtist', artist)), + }), - return relations; - }, - - data(query) { - const data = {}; - - if (query.artists) { - data.counts = - query.artists - .map(artist => getArtistNumContributions(artist)); - } - - if (query.artistsByGroup) { - data.groupDirectories = - query.groups - .map(group => group.directory); - - data.countsByGroup = - query.artistsByGroup - .map(artists => artists - .map(artist => getArtistNumContributions(artist))); - } - - return data; - }, + data: (query) => ({ + counts: + query.artists + .map(artist => getArtistNumContributions(artist)), + }), generate(data, relations, {language}) { - return ( - (relations.artistLinksByGroup - ? relations.page.slots({ - type: 'chunks', - - showSkipToSection: true, - chunkIDs: - data.groupDirectories - .map(directory => `contributed-to-${directory}`), - - chunkTitles: - relations.groupLinks.map(groupLink => ({ - group: groupLink, - })), - - chunkRows: - stitchArrays({ - artistLinks: relations.artistLinksByGroup, - counts: data.countsByGroup, - }).map(({artistLinks, counts}) => - stitchArrays({ - link: artistLinks, - count: counts, - }).map(({link, count}) => ({ - artist: link, - contributions: language.countContributions(count, {unit: true}), - }))), - }) - : relations.page.slots({ - type: 'rows', - rows: - stitchArrays({ - link: relations.artistLinks, - count: data.counts, - }).map(({link, count}) => ({ - artist: link, - contributions: language.countContributions(count, {unit: true}), - })), - }))); + return relations.page.slots({ + type: 'rows', + rows: + stitchArrays({ + link: relations.artistLinks, + count: data.counts, + }).map(({link, count}) => ({ + artist: link, + contributions: language.countContributions(count, {unit: true}), + })), + }); }, }; -- cgit 1.3.0-6-gf8a5 From 168425e7a3dd3a268cfdbd2a395e11ac72eaa3b2 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 28 Aug 2023 09:57:50 -0300 Subject: content: generateListingPage: don't mutate options in slots --- src/content/dependencies/generateListingPage.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index 4de2d006..3c50bd59 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -91,12 +91,13 @@ export default { const parts = [baseStringsKey, contextStringsKey]; - if (options.stringsKey) { + const {stringsKey, ...passOptions} = options; + + if (stringsKey) { parts.push(options.stringsKey); - delete options.stringsKey; } - return language.formatString(parts.join('.'), options); + return language.formatString(parts.join('.'), passOptions); }; return relations.layout.slots({ -- cgit 1.3.0-6-gf8a5 From 6b76c7a0c852b87b3ff2e4f3a11fe15424618511 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 28 Aug 2023 09:58:22 -0300 Subject: content: listArtistsByContributions: use updated chunk layout --- .../dependencies/listArtistsByContributions.js | 116 ++++++++++----------- 1 file changed, 54 insertions(+), 62 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/listArtistsByContributions.js b/src/content/dependencies/listArtistsByContributions.js index 86c8cfa2..58c51a40 100644 --- a/src/content/dependencies/listArtistsByContributions.js +++ b/src/content/dependencies/listArtistsByContributions.js @@ -1,5 +1,11 @@ -import {stitchArrays, unique} from '#sugar'; -import {filterByCount, sortAlphabetically, sortByCount} from '#wiki-data'; +import {empty, stitchArrays, unique} from '#sugar'; + +import { + filterByCount, + filterMultipleArrays, + sortAlphabetically, + sortByCount, +} from '#wiki-data'; export default { contentDependencies: ['generateListingPage', 'linkArtist'], @@ -96,68 +102,54 @@ export default { return data; }, - generate(data, relations, {html, language}) { - const lists = Object.fromEntries( - ([ - ['tracks', [ - relations.artistLinksByTrackContributions, - data.countsByTrackContributions, - 'countTracks', - ]], - - ['artworks', [ - relations.artistLinksByArtworkContributions, - data.countsByArtworkContributions, - 'countArtworks', - ]], - - data.enableFlashesAndGames && - ['flashes', [ - relations.artistLinksByFlashContributions, - data.countsByFlashContributions, - 'countFlashes', - ]], - ]).filter(Boolean) - .map(([key, [artistLinks, counts, countFunction]]) => [ - key, - html.tag('ul', - stitchArrays({ - artistLink: artistLinks, - count: counts, - }).map(({artistLink, count}) => - html.tag('li', - language.$('listingPage.listArtists.byContribs.item', { - artist: artistLink, - contributions: language[countFunction](count, {unit: true}), - })))), - ])); + generate(data, relations, {language}) { + const listChunkIDs = ['tracks', 'artworks', 'flashes']; + const listTitleStringsKeys = ['trackContributors', 'artContributors', 'flashContributors']; + const listCountFunctions = ['countTracks', 'countArtworks', 'countFlashes']; + + const listArtistLinks = [ + relations.artistLinksByTrackContributions, + relations.artistLinksByArtworkContributions, + relations.artistLinksByFlashContributions, + ]; + + const listArtistCounts = [ + data.countsByTrackContributions, + data.countsByArtworkContributions, + data.countsByFlashContributions, + ]; + + filterMultipleArrays( + listChunkIDs, + listTitleStringsKeys, + listCountFunctions, + listArtistLinks, + listArtistCounts, + (_chunkID, _titleStringsKey, _countFunction, artistLinks, _artistCounts) => + !empty(artistLinks)); return relations.page.slots({ - type: 'custom', - content: - html.tag('div', {class: 'content-columns'}, [ - html.tag('div', {class: 'column'}, [ - html.tag('h2', - language.$('listingPage.misc.trackContributors')), - - lists.tracks, - ]), - - html.tag('div', {class: 'column'}, [ - html.tag('h2', - language.$( - 'listingPage.misc.artContributors')), - - lists.artworks, - - lists.flashes && [ - html.tag('h2', - language.$('listingPage.misc.flashContributors')), - - lists.flashes, - ], - ]), - ]), + type: 'chunks', + + showSkipToSection: true, + chunkIDs: listChunkIDs, + + chunkTitles: + listTitleStringsKeys.map(stringsKey => ({stringsKey})), + + chunkRows: + stitchArrays({ + artistLinks: listArtistLinks, + artistCounts: listArtistCounts, + countFunction: listCountFunctions, + }).map(({artistLinks, artistCounts, countFunction}) => + stitchArrays({ + artistLink: artistLinks, + artistCount: artistCounts, + }).map(({artistLink, artistCount}) => ({ + artist: artistLink, + contributions: language[countFunction](artistCount, {unit: true}), + }))), }); }, }; -- cgit 1.3.0-6-gf8a5 From 715bd8eff86c20b3773a66e96e9c9d6ae8602644 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 28 Aug 2023 19:19:39 -0300 Subject: content: listArtistsByLatestContribution: chunk-based rework --- .../listArtistsByLatestContribution.js | 594 ++++++++++----------- 1 file changed, 275 insertions(+), 319 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/listArtistsByLatestContribution.js b/src/content/dependencies/listArtistsByLatestContribution.js index b6ea8e96..edb02e0d 100644 --- a/src/content/dependencies/listArtistsByLatestContribution.js +++ b/src/content/dependencies/listArtistsByLatestContribution.js @@ -1,15 +1,16 @@ -import {transposeArrays, empty, stitchArrays} from '#sugar'; +import {empty, stitchArrays} from '#sugar'; +import T from '#things'; import { chunkMultipleArrays, - compareCaseLessSensitive, - compareDates, - filterMultipleArrays, - reduceMultipleArrays, sortAlphabetically, + sortAlbumsTracksChronologically, + sortFlashesChronologically, sortMultipleArrays, } from '#wiki-data'; +const {Album, Flash} = T; + export default { contentDependencies: [ 'generateListingPage', @@ -20,348 +21,303 @@ export default { extraDependencies: ['html', 'language', 'wikiData'], - sprawl({artistData, wikiInfo}) { - return { - artistData, - enableFlashesAndGames: wikiInfo.enableFlashesAndGames, - }; - }, + sprawl: ({albumData, artistData, flashData, trackData, wikiInfo}) => + ({albumData, artistData, flashData, trackData, + enableFlashesAndGames: wikiInfo.enableFlashesAndGames}), query(sprawl, spec) { - const query = { - spec, - enableFlashesAndGames: sprawl.enableFlashesAndGames, - }; - - const queryContributionInfo = ( - artistsKey, - chunkThingsKey, - datesKey, - datelessArtistsKey, - fn, - ) => { - const artists = sortAlphabetically(sprawl.artistData.slice()); - - // Each value stored in dateLists, corresponding to each artist, - // is going to be a list of dates and nulls. Any nulls represent - // a contribution which isn't associated with a particular date. - const [chunkThingLists, dateLists] = - transposeArrays(artists.map(artist => fn(artist))); - - // Scrap artists who don't even have any relevant contributions. - // These artists may still have other contributions across the wiki, but - // they weren't returned by the callback and so aren't relevant to this - // list. - filterMultipleArrays( - artists, - chunkThingLists, - dateLists, - (artists, chunkThings, dates) => !empty(dates)); - - // Also exclude artists whose remaining contributions are all dateless. - // But keep track of the artists removed here, since they'll be displayed - // in an additional list in the final listing page. - const {removed: [datelessArtists]} = - filterMultipleArrays( - artists, - chunkThingLists, - dateLists, - (artist, chunkThings, dates) => !empty(dates.filter(Boolean))); - - // Cut out dateless contributions. They're not relevant to finding the - // latest date. - for (const [chunkThings, dates] of transposeArrays([chunkThingLists, dateLists])) { - filterMultipleArrays(chunkThings, dates, (chunkThing, date) => date); + // + // First main step is to get the latest thing each artist has contributed + // to, and the date associated with that contribution! Some notes: + // + // * Album and track contributions are considered before flashes, so + // they'll take priority if an artist happens to have multiple contribs + // landing on the same date to both an album and a flash. + // + // * The final (album) contribution list is chunked by album, but also by + // date, because an individual album can cover a variety of dates. + // + // * If an artist has contributed both artworks and tracks to the album + // containing their latest contribution, then that will be indicated + // in an annotation, but *only if* those contributions were also on + // the same date. + // + // * If an artist made contributions to multiple albums on the same date, + // then the first of the *albums* sorted chronologically (latest first) + // is the one that will count. + // + // * Same for artists who've contributed to multiple flashes which were + // released on the same date. + // + // * The map may exclude artists none of whose contributions were dated. + // + + const artistLatestContribMap = new Map(); + + const considerDate = (artist, date, thing, contribution) => { + if (!date) { + return; } - const [chunkThings, dates] = - transposeArrays( - transposeArrays([chunkThingLists, dateLists]) - .map(([chunkThings, dates]) => - reduceMultipleArrays( - chunkThings, dates, - (accChunkThing, accDate, chunkThing, date) => - (date && date > accDate - ? [chunkThing, date] - : [accChunkThing, accDate])))); - - sortMultipleArrays(artists, dates, chunkThings, - (artistA, artistB, dateA, dateB, chunkThingA, chunkThingB) => { - const dateComparison = compareDates(dateA, dateB, {latestFirst: true}); - if (dateComparison !== 0) { - return dateComparison; - } - - // TODO: Compare alphabetically, not just by directory. - return compareCaseLessSensitive(chunkThingA.directory, chunkThingB.directory); - }); - - const chunks = - chunkMultipleArrays(artists, dates, chunkThings, - (artist, lastArtist, date, lastDate, chunkThing, lastChunkThing) => - +date !== +lastDate || chunkThing !== lastChunkThing); + if (artistLatestContribMap.has(artist)) { + const latest = artistLatestContribMap.get(artist); + if (latest.date > date) { + return; + } - query[chunkThingsKey] = - chunks.map(([artists, dates, chunkThings]) => chunkThings[0]); - - query[datesKey] = - chunks.map(([artists, dates, chunkThings]) => dates[0]); + if (latest.date === date) { + if (latest.thing === thing) { + // May combine differnt contributions to the same thing and date. + latest.contribution.add(contribution); + } - query[artistsKey] = - chunks.map(([artists, dates, chunkThings]) => artists); + // Earlier-processed things of same date take priority. + return; + } + } - query[datelessArtistsKey] = datelessArtists; + // First entry for artist or more recent contribution than latest date. + artistLatestContribMap.set(artist, { + date, + thing, + contribution: new Set([contribution]), + }); }; - queryContributionInfo( - 'artistsByTrackContributions', - 'albumsByTrackContributions', - 'datesByTrackContributions', - 'datelessArtistsByTrackContributions', - artist => { - const tracks = - [...artist.tracksAsArtist, ...artist.tracksAsContributor] - .filter(track => !track.originalReleaseTrack); - - const albums = tracks.map(track => track.album); - const dates = tracks.map(track => track.date); + const getArtists = (thing, key) => thing[key].map(({who}) => who); - return [albums, dates]; - }); + const albumsLatestFirst = sortAlbumsTracksChronologically(sprawl.albumData.slice()); + const tracksLatestFirst = sortAlbumsTracksChronologically(sprawl.trackData.slice()); + const flashesLatestFirst = sortFlashesChronologically(sprawl.flashData.slice()); - queryContributionInfo( - 'artistsByArtworkContributions', - 'albumsByArtworkContributions', - 'datesByArtworkContributions', - 'datelessArtistsByArtworkContributions', - artist => [ - [ - ...artist.tracksAsCoverArtist.map(track => track.album), - ...artist.albumsAsCoverArtist, - ...artist.albumsAsWallpaperArtist, - ...artist.albumsAsBannerArtist, - ], - [ - // TODO: Per-artwork dates, see #90. - ...artist.tracksAsCoverArtist.map(track => track.coverArtDate), - ...artist.albumsAsCoverArtist.map(album => album.coverArtDate), - ...artist.albumsAsWallpaperArtist.map(album => album.coverArtDate), - ...artist.albumsAsBannerArtist.map(album => album.coverArtDate), - ], - ]); - - if (sprawl.enableFlashesAndGames) { - queryContributionInfo( - 'artistsByFlashContributions', - 'flashesByFlashContributions', - 'datesByFlashContributions', - 'datelessArtistsByFlashContributions', - artist => [ - [ - ...artist.flashesAsContributor, - ], - [ - ...artist.flashesAsContributor.map(flash => flash.date), - ], - ]); + for (const album of albumsLatestFirst) { + for (const artist of new Set([ + ...getArtists(album, 'coverArtistContribs'), + ...getArtists(album, 'wallpaperArtistContribs'), + ...getArtists(album, 'bannerArtistContribs'), + ])) { + // Might combine later with 'track' of the same album and date. + considerDate(artist, album.coverArtDate, album, 'artwork'); + } } - return query; - }, - - relations(relation, query) { - const relations = {}; - - relations.page = - relation('generateListingPage', query.spec); - - // Track contributors - - relations.albumLinksByTrackContributions = - query.albumsByTrackContributions - .map(album => relation('linkAlbum', album)); - - relations.artistLinksByTrackContributions = - query.artistsByTrackContributions - .map(artists => - artists.map(artist => relation('linkArtist', artist))); - - relations.datelessArtistLinksByTrackContributions = - query.datelessArtistsByTrackContributions - .map(artist => relation('linkArtist', artist)); - - // Artwork contributors - - relations.albumLinksByArtworkContributions = - query.albumsByArtworkContributions - .map(album => relation('linkAlbum', album)); + 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.album, 'artwork'); + } - relations.artistLinksByArtworkContributions = - query.artistsByArtworkContributions - .map(artists => - artists.map(artist => relation('linkArtist', artist))); + for (const artist of new Set([ + ...getArtists(track, 'artistContribs'), + ...getArtists(track, 'contributorContribs'), + ])) { + // Might be combining with 'artwork' of the same album and date. + considerDate(artist, track.date, track.album, 'track'); + } + } - relations.datelessArtistLinksByArtworkContributions = - query.datelessArtistsByArtworkContributions - .map(artist => relation('linkArtist', artist)); + for (const flash of flashesLatestFirst) { + for (const artist of getArtists(flash, 'contributorContribs')) { + // Won't take priority above album contributions of the same date. + considerDate(artist, flash.date, flash, 'flash'); + } + } - // Flash contributors + // + // Next up is to sort all the processed artist information! + // + // Entries with the same album/flash and the same date go together first, + // with the following rules for sorting artists therein: + // + // * If the contributions are different, which can only happen for albums, + // then it's tracks-only first, tracks + artworks next, and artworks-only + // last. + // + // * If the contributions are the same, then sort alphabetically. + // + // Entries with different albums/flashes follow another set of rules: + // + // * Later dates come before earlier dates. + // + // * On the same date, albums come before flashes. + // + // * Things of the same type *and* date are sorted alphabetically. + // + + const artistsAlphabetically = + sortAlphabetically(sprawl.artistData.slice()); + + const artists = + Array.from(artistLatestContribMap.keys()); + + const artistContribEntries = + Array.from(artistLatestContribMap.values()); + + const artistThings = + artistContribEntries.map(({thing}) => thing); + + const artistDates = + artistContribEntries.map(({date}) => date); + + const artistContributions = + artistContribEntries.map(({contribution}) => contribution); + + sortMultipleArrays(artistThings, artistDates, artistContributions, artists, + (thing1, thing2, date1, date2, contrib1, contrib2, artist1, artist2) => { + if (date1 === date2 && thing1 === thing2) { + // Move artwork-only contribs after contribs with tracks. + if (!contrib1.has('track') && contrib2.has('track')) return 1; + if (!contrib2.has('track') && contrib1.has('track')) return -1; + + // Move track-only contribs before tracks with tracks and artwork. + if (!contrib1.has('artwork') && contrib2.has('artwork')) return -1; + if (!contrib2.has('artwork') && contrib1.has('artwork')) return 1; + + // Sort artists of the same type of contribution alphabetically, + // referring to a previous sort. + const index1 = artistsAlphabetically.indexOf(artist1); + const index2 = artistsAlphabetically.indexOf(artist2); + return index1 - index2; + } else { + // Move later dates before earlier ones. + if (date1 !== date2) return date2 - date1; + + // Move albums before flashes. + if (thing1 instanceof Album && thing2 instanceof Flash) return -1; + if (thing1 instanceof Flash && thing2 instanceof Album) return 1; + + // Sort two albums or two flashes alphabetically, referring to a + // previous sort (which was chronological but includes the correct + // ordering for things released on the same date). + const thingsLatestFirst = + (thing1 instanceof Album + ? albumsLatestFirst + : flashesLatestFirst); + const index1 = thingsLatestFirst.indexOf(thing1); + const index2 = thingsLatestFirst.indexOf(thing2); + return index2 - index1; + } + }); - if (query.enableFlashesAndGames) { - relations.flashLinksByFlashContributions = - query.flashesByFlashContributions - .map(flash => relation('linkFlash', flash)); + // Last off, turn the flat sorted list into a proper chunked list, now that + // entries going in the same chunk are sorted correctly next to each other. + // Then extract the parts that are useful for displaying on the listing! - relations.artistLinksByFlashContributions = - query.artistsByFlashContributions - .map(artists => - artists.map(artist => relation('linkArtist', artist))); + const chunks = + chunkMultipleArrays(artistThings, artistDates, artistContributions, artists, + (thing, lastThing, date, lastDate) => + thing !== lastThing || + +date !== +lastDate); - relations.datelessArtistLinksByFlashContributions = - query.datelessArtistsByFlashContributions - .map(artist => relation('linkArtist', artist)); - } + const chunkThings = + chunks.map(([artistThings, , , ]) => artistThings[0]); - return relations; - }, + const chunkDates = + chunks.map(([, artistDates, , ]) => artistDates[0]); - data(query) { - const data = {}; + const chunkArtistContributions = + chunks.map(([, , artistContributions, ]) => artistContributions); - data.enableFlashesAndGames = query.enableFlashesAndGames; + const chunkArtists = + chunks.map(([, , , artists]) => artists); - data.datesByTrackContributions = query.datesByTrackContributions; - data.datesByArtworkContributions = query.datesByArtworkContributions; + // And one bonus step - keep track of all the artists whose contributions + // were all without date. - if (query.enableFlashesAndGames) { - data.datesByFlashContributions = query.datesByFlashContributions; - } + const datelessArtists = + artistsAlphabetically + .filter(artist => !artists.includes(artist)); - return data; + return { + spec, + chunkThings, + chunkDates, + chunkArtistContributions, + chunkArtists, + datelessArtists, + }; }, - generate(data, relations, {html, language}) { - const chunkTitles = Object.fromEntries( - ([ - ['tracks', [ - 'album', - relations.albumLinksByTrackContributions, - data.datesByTrackContributions, - ]], - - ['artworks', [ - 'album', - relations.albumLinksByArtworkContributions, - data.datesByArtworkContributions, - ]], - - data.enableFlashesAndGames && - ['flashes', [ - 'flash', - relations.flashLinksByFlashContributions, - data.datesByFlashContributions, - ]], - ]).filter(Boolean) - .map(([key, [stringsKey, links, dates]]) => [ - key, - stitchArrays({link: links, date: dates}) - .map(({link, date}) => - html.tag('dt', - language.$(`listingPage.listArtists.byLatest.chunk.title.${stringsKey}`, { - [stringsKey]: link, - date: language.formatDate(date), - }))), - ])); - - const chunkItems = Object.fromEntries( - ([ - ['tracks', relations.artistLinksByTrackContributions], - ['artworks', relations.artistLinksByArtworkContributions], - data.enableFlashesAndGames && - ['flashes', relations.artistLinksByFlashContributions], - ]).filter(Boolean) - .map(([key, artistLinkLists]) => [ - key, - artistLinkLists.map(artistLinks => - html.tag('dd', - html.tag('ul', - artistLinks.map(artistLink => - html.tag('li', - language.$('listingPage.listArtists.byLatest.chunk.item', { - artist: artistLink, - })))))), - ])); - - const lists = Object.fromEntries( - ([ - ['tracks', [ - chunkTitles.tracks, - chunkItems.tracks, - relations.datelessArtistLinksByTrackContributions, - ]], - - ['artworks', [ - chunkTitles.artworks, - chunkItems.artworks, - relations.datelessArtistLinksByArtworkContributions, - ]], - - data.enableFlashesAndGames && - ['flashes', [ - chunkTitles.flashes, - chunkItems.flashes, - relations.datelessArtistLinksByFlashContributions, - ]], - ]).filter(Boolean) - .map(([key, [titles, items, datelessArtistLinks]]) => [ - key, - html.tags([ - html.tag('dl', - stitchArrays({ - title: titles, - items: items, - }).map(({title, items}) => [title, items])), - - !empty(datelessArtistLinks) && [ - html.tag('p', - language.$('listingPage.listArtists.byLatest.dateless.title')), - - html.tag('ul', - datelessArtistLinks.map(artistLink => - html.tag('li', - language.$('listingPage.listArtists.byLatest.dateless.item', { - artist: artistLink, - })))), - ], - ]), - ])); - + relations: (relation, query) => ({ + page: + relation('generateListingPage', query.spec), + + chunkAlbumLinks: + query.chunkThings + .map(thing => + (thing instanceof Album + ? relation('linkAlbum', thing) + : null)), + + chunkFlashLinks: + query.chunkThings + .map(thing => + (thing instanceof Flash + ? relation('linkFlash', thing) + : null)), + + chunkArtistLinks: + query.chunkArtists + .map(artists => artists + .map(artist => relation('linkArtist', artist))), + + datelessArtistLinks: + query.datelessArtists + .map(artist => relation('linkArtist', artist)), + }), + + data: (query) => ({ + chunkDates: query.chunkDates, + chunkArtistContributions: query.chunkArtistContributions, + }), + + generate(data, relations, {language}) { return relations.page.slots({ - type: 'custom', - content: - html.tag('div', {class: 'content-columns'}, [ - html.tag('div', {class: 'column'}, [ - html.tag('h2', - language.$('listingPage.misc.trackContributors')), - - lists.tracks, - ]), - - html.tag('div', {class: 'column'}, [ - html.tag('h2', - language.$( - 'listingPage.misc.artContributors')), - - lists.artworks, - - lists.flashes && [ - html.tag('h2', - language.$('listingPage.misc.flashContributors')), - - lists.flashes, - ], - ]), - ]), + type: 'chunks', + + chunkTitles: + stitchArrays({ + albumLink: relations.chunkAlbumLinks, + flashLink: relations.chunkFlashLinks, + date: data.chunkDates, + }).map(({albumLink, flashLink, date}) => ({ + date: language.formatDate(date), + ...(albumLink + ? {stringsKey: 'album', album: albumLink} + : {stringsKey: 'flash', flash: flashLink}), + })) + .concat( + (empty(relations.datelessArtistLinks) + ? [] + : [{stringsKey: 'dateless'}])), + + chunkRows: + stitchArrays({ + artistLinks: relations.chunkArtistLinks, + contributions: data.chunkArtistContributions, + }).map(({artistLinks, contributions}) => + stitchArrays({ + artistLink: artistLinks, + contribution: contributions, + }).map(({artistLink, contribution}) => ({ + artist: artistLink, + stringsKey: + (contribution.has('track') && contribution.has('artwork') + ? 'tracksAndArt' + : contribution.has('track') + ? 'tracks' + : contribution.has('artwork') + ? 'art' + : null), + }))) + .concat( + (empty(relations.datelessArtistLinks) + ? [] + : [ + relations.datelessArtistLinks.map(artistLink => ({ + artist: artistLink, + })), + ])), }); }, }; -- cgit 1.3.0-6-gf8a5 From c4ef4ced62d659d217873c6c48dd8038dbf765af Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 31 Aug 2023 10:49:03 -0300 Subject: content: generateListingPage: show custom content above auto content This is towards enabling custom controls and/or accents on listings which are otherwise represented by rows or chunks. --- src/content/dependencies/generateListingPage.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index 3c50bd59..f527f16f 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -129,6 +129,8 @@ export default { listings: language.formatUnitList(relations.seeAlsoLinks), })), + slots.content, + slots.type === 'rows' && html.tag(listTag, slots.rows.map(row => @@ -180,9 +182,6 @@ export default { formatListingString('chunk.item', row))))), ]), ]), - - slots.type === 'custom' && - slots.content, ], navLinkStyle: 'hierarchical', -- cgit 1.3.0-6-gf8a5 From c59545f5faafc826ff24ff779c20318ef14ae123 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 29 Oct 2023 09:27:23 -0300 Subject: content, client: generalize "random pages" listing to wiki dividing groups --- .../generateListRandomPageLinksGroupSection.js | 9 +++---- src/content/dependencies/listRandomPageLinks.js | 28 +++++++--------------- 2 files changed, 12 insertions(+), 25 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListRandomPageLinksGroupSection.js b/src/content/dependencies/generateListRandomPageLinksGroupSection.js index 2a684b19..74872724 100644 --- a/src/content/dependencies/generateListRandomPageLinksGroupSection.js +++ b/src/content/dependencies/generateListRandomPageLinksGroupSection.js @@ -23,10 +23,7 @@ export default { .map(() => relation('generateColorStyleVariables')), }), - data: (query, sprawl, group) => ({ - groupDirectory: - group.directory, - + data: (query) => ({ albumColors: query.albums .map(album => album.color), @@ -48,12 +45,12 @@ export default { randomAlbum: html.tag('a', - {href: '#', 'data-random': 'album-in-' + data.groupDirectory}, + {href: '#', 'data-random': 'album-in-group-dl'}, language.$('listingPage.other.randomPages.group.randomAlbum')), randomTrack: html.tag('a', - {href: '#', 'data-random': 'track-in-' + data.groupDirectory}, + {href: '#', 'data-random': 'track-in-group-dl'}, language.$('listingPage.other.randomPages.group.randomTrack')), })), diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index 43bf7dd5..57ecb044 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -6,19 +6,16 @@ export default { extraDependencies: ['html', 'language', 'wikiData'], - sprawl({groupData}) { - return {groupData}; + sprawl({wikiInfo}) { + return {wikiInfo}; }, query(sprawl, spec) { - const group = directory => - sprawl.groupData.find(group => group.directory === directory); - return { spec, - officialGroup: group('official'), - fandomGroup: group('fandom'), - beyondGroup: group('beyond'), + + groups: + sprawl.wikiInfo.divideTrackListsByGroups, }; }, @@ -26,14 +23,9 @@ export default { return { page: relation('generateListingPage', query.spec), - officialSection: - relation('generateListRandomPageLinksGroupSection', query.officialGroup), - - fandomSection: - relation('generateListRandomPageLinksGroupSection', query.fandomGroup), - - beyondSection: - relation('generateListRandomPageLinksGroupSection', query.beyondGroup), + groupSections: + query.groups + .map(group => relation('generateListRandomPageLinksGroupSection', group)), }; }, @@ -81,9 +73,7 @@ export default { language.$('listingPage.other.randomPages.misc.randomTrackWholeSite'))), ])), - relations.officialSection, - relations.fandomSection, - relations.beyondSection, + relations.groupSections, ]), ], }); -- cgit 1.3.0-6-gf8a5 From 777fbd3535f80fb8fb28d80a5dc53efe44c6cb82 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 29 Oct 2023 09:49:56 -0300 Subject: content: linkTemplate: append provided style to own style --- src/content/dependencies/linkTemplate.js | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/content') diff --git a/src/content/dependencies/linkTemplate.js b/src/content/dependencies/linkTemplate.js index d9af726c..a361a4e7 100644 --- a/src/content/dependencies/linkTemplate.js +++ b/src/content/dependencies/linkTemplate.js @@ -64,6 +64,14 @@ export default { style = `--primary-color: ${primary}; --dim-color: ${dim}`; } + if (slots.attributes?.style) { + if (style) { + style += '; ' + slots.attributes.style; + } else { + style = slots.attributes.style; + } + } + if (slots.tooltip) { title = slots.tooltip; } -- cgit 1.3.0-6-gf8a5 From d2903c800b6a005a447cc26f9431fe5fe4fb08b6 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 29 Oct 2023 09:51:01 -0300 Subject: content: adapt "random pages" to wikis without dividing groups --- .../generateListRandomPageLinksAlbumLink.js | 18 +++++++++ .../generateListRandomPageLinksAllAlbumsSection.js | 35 ++++++++++++++++ .../generateListRandomPageLinksGroupSection.js | 47 +++++----------------- src/content/dependencies/listRandomPageLinks.js | 40 +++++++++--------- 4 files changed, 85 insertions(+), 55 deletions(-) create mode 100644 src/content/dependencies/generateListRandomPageLinksAlbumLink.js create mode 100644 src/content/dependencies/generateListRandomPageLinksAllAlbumsSection.js (limited to 'src/content') diff --git a/src/content/dependencies/generateListRandomPageLinksAlbumLink.js b/src/content/dependencies/generateListRandomPageLinksAlbumLink.js new file mode 100644 index 00000000..b3560aca --- /dev/null +++ b/src/content/dependencies/generateListRandomPageLinksAlbumLink.js @@ -0,0 +1,18 @@ +export default { + contentDependencies: ['linkAlbum'], + + data: (album) => + ({directory: album.directory}), + + relations: (relation, album) => + ({albumLink: relation('linkAlbum', album)}), + + generate: (data, relations) => + relations.albumLink.slots({ + anchor: true, + attributes: { + 'data-random': 'track-in-album', + 'style': `--album-directory: ${data.directory}`, + }, + }), +}; diff --git a/src/content/dependencies/generateListRandomPageLinksAllAlbumsSection.js b/src/content/dependencies/generateListRandomPageLinksAllAlbumsSection.js new file mode 100644 index 00000000..e03252c9 --- /dev/null +++ b/src/content/dependencies/generateListRandomPageLinksAllAlbumsSection.js @@ -0,0 +1,35 @@ +import {sortChronologically} from '#wiki-data'; + +export default { + contentDependencies: ['generateListRandomPageLinksAlbumLink', 'linkGroup'], + extraDependencies: ['html', 'language', 'wikiData'], + + sprawl: ({albumData}) => ({albumData}), + + query: (sprawl) => ({ + albums: + sortChronologically(sprawl.albumData.slice()) + .filter(album => album.tracks.length > 1), + }), + + relations: (relation, query) => ({ + albumLinks: + query.albums + .map(album => relation('generateListRandomPageLinksAlbumLink', album)), + }), + + generate: (relations, {html, language}) => + html.tags([ + html.tag('dt', + language.$('listingPage.other.randomPages.fromAlbum')), + + html.tag('dd', + html.tag('ul', + relations.albumLinks + .map(albumLink => + html.tag('li', + language.$('listingPage.other.randomPages.album', { + album: albumLink, + }))))), + ]), +}; diff --git a/src/content/dependencies/generateListRandomPageLinksGroupSection.js b/src/content/dependencies/generateListRandomPageLinksGroupSection.js index 74872724..d05be8f7 100644 --- a/src/content/dependencies/generateListRandomPageLinksGroupSection.js +++ b/src/content/dependencies/generateListRandomPageLinksGroupSection.js @@ -1,8 +1,7 @@ -import {stitchArrays} from '#sugar'; import {sortChronologically} from '#wiki-data'; export default { - contentDependencies: ['generateColorStyleVariables', 'linkGroup'], + contentDependencies: ['generateListRandomPageLinksAlbumLink', 'linkGroup'], extraDependencies: ['html', 'language', 'wikiData'], sprawl: ({albumData}) => ({albumData}), @@ -18,61 +17,35 @@ export default { groupLink: relation('linkGroup', group), - albumColorVariables: + albumLinks: query.albums - .map(() => relation('generateColorStyleVariables')), + .map(album => relation('generateListRandomPageLinksAlbumLink', album)), }), - data: (query) => ({ - albumColors: - query.albums - .map(album => album.color), - - albumDirectories: - query.albums - .map(album => album.directory), - - albumNames: - query.albums - .map(album => album.name), - }), - - generate: (data, relations, {html, language}) => + generate: (relations, {html, language}) => html.tags([ html.tag('dt', - language.$('listingPage.other.randomPages.group', { + language.$('listingPage.other.randomPages.fromGroup', { group: relations.groupLink, randomAlbum: html.tag('a', {href: '#', 'data-random': 'album-in-group-dl'}, - language.$('listingPage.other.randomPages.group.randomAlbum')), + language.$('listingPage.other.randomPages.fromGroup.randomAlbum')), randomTrack: html.tag('a', {href: '#', 'data-random': 'track-in-group-dl'}, - language.$('listingPage.other.randomPages.group.randomTrack')), + language.$('listingPage.other.randomPages.fromGroup.randomTrack')), })), html.tag('dd', html.tag('ul', - stitchArrays({ - colorVariables: relations.albumColorVariables, - color: data.albumColors, - directory: data.albumDirectories, - name: data.albumNames, - }).map(({colorVariables, color, directory, name}) => + relations.albumLinks + .map(albumLink => html.tag('li', language.$('listingPage.other.randomPages.album', { - album: - html.tag('a', { - href: '#', - 'data-random': 'track-in-album', - style: - colorVariables.slot('color', color).content + - '; ' + - `--album-directory: ${directory}`, - }, name), + album: albumLink, }))))), ]), }; diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index 57ecb044..ce90a153 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -1,33 +1,36 @@ +import {empty} from '#sugar'; + export default { contentDependencies: [ 'generateListingPage', + 'generateListRandomPageLinksAllAlbumsSection', 'generateListRandomPageLinksGroupSection', ], extraDependencies: ['html', 'language', 'wikiData'], - sprawl({wikiInfo}) { - return {wikiInfo}; - }, + sprawl: ({wikiInfo}) => ({wikiInfo}), - query(sprawl, spec) { - return { - spec, + query: ({wikiInfo: {divideTrackListsByGroups: groups}}, spec) => ({ + spec, + groups, + divideByGroups: !empty(groups), + }), - groups: - sprawl.wikiInfo.divideTrackListsByGroups, - }; - }, + relations: (relation, query) => ({ + page: relation('generateListingPage', query.spec), - relations(relation, query) { - return { - page: relation('generateListingPage', query.spec), + allAlbumsSection: + (query.divideByGroups + ? null + : relation('generateListRandomPageLinksAllAlbumsSection')), - groupSections: - query.groups - .map(group => relation('generateListRandomPageLinksGroupSection', group)), - }; - }, + groupSections: + (query.divideByGroups + ? query.groups + .map(group => relation('generateListRandomPageLinksGroupSection', group)) + : null), + }), generate(relations, {html, language}) { return relations.page.slots({ @@ -73,6 +76,7 @@ export default { language.$('listingPage.other.randomPages.misc.randomTrackWholeSite'))), ])), + relations.allAlbumsSection, relations.groupSections, ]), ], -- cgit 1.3.0-6-gf8a5 From e71230340181a3b7b38ff05ba23504b264f5b26c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 29 Oct 2023 10:00:52 -0300 Subject: content: listRandomPageLinks: update chooseLinkLine wording --- src/content/dependencies/listRandomPageLinks.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index ce90a153..599a82d3 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -37,7 +37,15 @@ export default { type: 'custom', content: [ html.tag('p', - language.$('listingPage.other.randomPages.chooseLinkLine')), + language.$('listingPage.other.randomPages.chooseLinkLine', { + fromPart: + (empty(relations.groupSections) + ? language.$('listingPage.other.randomPages.chooseLinkLine.fromPart.notDividedByGroups') + : language.$('listingPage.other.randomPages.chooseLinkLine.fromPart.dividedByGroups')), + + browserSupportPart: + language.$('listingPage.other.randomPages.chooseLinkLine.browserSupportPart'), + })), html.tag('p', {class: 'js-hide-once-data'}, -- cgit 1.3.0-6-gf8a5 From 150c414044662134ddf785e7411560e3a6051a03 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 14:50:13 -0400 Subject: content: listRandomPageLinks: don't hard-code parentheses --- src/content/dependencies/listRandomPageLinks.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index 599a82d3..87e5f5aa 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -61,17 +61,18 @@ export default { html.tag('dd', html.tag('ul', [ - html.tag('li', [ - html.tag('a', - {href: '#', 'data-random': 'artist'}, - language.$('listingPage.other.randomPages.misc.randomArtist')), - - '(' + - html.tag('a', - {href: '#', 'data-random': 'artist-more-than-one-contrib'}, - language.$('listingPage.other.randomPages.misc.atLeastTwoContributions')) + - ')', - ]), + html.tag('li', + language.$('listingPage.other.randomPages.misc.randomArtist', { + mainLink: + html.tag('a', + {href: '#', 'data-random': 'artist'}, + language.$('listingPage.other.randomPages.misc.randomArtist.mainLink')), + + atLeastTwoContributions: + html.tag('a', + {href: '#', 'data-random': 'artist-more-than-one-contrib'}, + language.$('listingPage.other.randomPages.misc.randomArtist.atLeastTwoContributions')), + })), html.tag('li', html.tag('a', -- cgit 1.3.0-6-gf8a5 From 443c2e42ad2731e63f40c9575e2c27001ed55bae Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 15:48:36 -0400 Subject: content: generateListingPage: add chunkRowAttributes slot This refactors out the hard-coded 'rerelease' behavior. --- src/content/dependencies/generateListingPage.js | 24 ++++++++++++++++++------ src/content/dependencies/listTracksByDate.js | 9 ++++++++- 2 files changed, 26 insertions(+), 7 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index 45b7dc1b..403f891f 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -68,6 +68,7 @@ export default { chunkTitles: {validate: v => v.strictArrayOf(v.isObject)}, chunkRows: {validate: v => v.strictArrayOf(v.isObject)}, + chunkRowAttributes: {validate: v => v.strictArrayOf(v.optional(v.isObject))}, showSkipToSection: {type: 'boolean', default: false}, chunkIDs: {validate: v => v.strictArrayOf(v.isString)}, @@ -165,9 +166,17 @@ export default { stitchArrays({ title: slots.chunkTitles, - rows: slots.chunkRows, id: slots.chunkIDs, - }).map(({title, rows, id}) => [ + + rows: slots.chunkRows, + rowAttributes: slots.chunkRowAttributes, + }).map(({ + title, + id, + + rows, + rowAttributes, + }) => [ relations.chunkHeading .clone() .slots({ @@ -178,10 +187,13 @@ export default { html.tag('dd', html.tag(listTag, - rows.map(row => - html.tag('li', - {class: row.stringsKey === 'rerelease' && 'rerelease'}, - formatListingString('chunk.item', row))))), + stitchArrays({ + row: rows, + attributes: rowAttributes ?? rows.map(() => null), + }).map(({row, attributes}) => + html.tag('li', + attributes, + formatListingString('chunk.item', row))))), ]), ]), ], diff --git a/src/content/dependencies/listTracksByDate.js b/src/content/dependencies/listTracksByDate.js index d6546e67..25beb739 100644 --- a/src/content/dependencies/listTracksByDate.js +++ b/src/content/dependencies/listTracksByDate.js @@ -71,8 +71,15 @@ export default { rerelease: rereleases, }).map(({trackLink, rerelease}) => (rerelease - ? {track: trackLink, stringsKey: 'rerelease'} + ? {stringsKey: 'rerelease', track: trackLink} : {track: trackLink}))), + + chunkRowAttributes: + data.rereleases.map(rereleases => + rereleases.map(rerelease => + (rerelease + ? {class: 'rerelease'} + : null))), }); }, }; -- cgit 1.3.0-6-gf8a5 From 44cebe7bfaf8f69ff6806e98524d3b5955f2cef2 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 15:49:31 -0400 Subject: content: generateListingPage: specially handle 'href' row attribute But not that specially. --- src/content/dependencies/generateListingPage.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index 403f891f..4c86431d 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -191,9 +191,14 @@ export default { row: rows, attributes: rowAttributes ?? rows.map(() => null), }).map(({row, attributes}) => - html.tag('li', - attributes, - formatListingString('chunk.item', row))))), + (attributes?.href + ? html.tag('li', + html.tag('a', + attributes, + formatListingString('chunk.item', row))) + : html.tag('li', + attributes, + formatListingString('chunk.item', row)))))), ]), ]), ], -- cgit 1.3.0-6-gf8a5 From 2a7c3b90a8d66cea9b0f041a33f4c145628587eb Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 15:58:50 -0400 Subject: content: generateListingPage: code cleanup, add rowAttributes slot --- src/content/dependencies/generateListingPage.js | 90 +++++++++++++++---------- 1 file changed, 53 insertions(+), 37 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index 4c86431d..3878d0eb 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -62,16 +62,38 @@ export default { }, slots: { - type: {validate: v => v.is('rows', 'chunks', 'custom')}, + type: { + validate: v => v.is('rows', 'chunks', 'custom'), + }, + + rows: { + validate: v => v.strictArrayOf(v.isObject), + }, + + rowAttributes: { + validate: v => v.strictArrayOf(v.optional(v.isObject)) + }, + + chunkTitles: { + validate: v => v.strictArrayOf(v.isObject), + }, + + chunkRows: { + validate: v => v.strictArrayOf(v.isObject), + }, - rows: {validate: v => v.strictArrayOf(v.isObject)}, + chunkRowAttributes: { + validate: v => v.strictArrayOf(v.optional(v.isObject)), + }, - chunkTitles: {validate: v => v.strictArrayOf(v.isObject)}, - chunkRows: {validate: v => v.strictArrayOf(v.isObject)}, - chunkRowAttributes: {validate: v => v.strictArrayOf(v.optional(v.isObject))}, + showSkipToSection: { + type: 'boolean', + default: false, + }, - showSkipToSection: {type: 'boolean', default: false}, - chunkIDs: {validate: v => v.strictArrayOf(v.isString)}, + chunkIDs: { + validate: v => v.strictArrayOf(v.isString), + }, listStyle: { validate: v => v.is('ordered', 'unordered'), @@ -82,11 +104,6 @@ export default { }, generate(data, relations, slots, {html, language}) { - const listTag = - (slots.listStyle === 'ordered' - ? 'ol' - : 'ul'); - const formatListingString = (contextStringsKey, options = {}) => { const baseStringsKey = `listingPage.${data.stringsKey}`; @@ -101,6 +118,24 @@ export default { return language.formatString(parts.join('.'), passOptions); }; + const formatRow = ({row, attributes}) => + (attributes?.href + ? html.tag('li', + html.tag('a', + attributes, + formatListingString('chunk.item', row))) + : html.tag('li', + attributes, + formatListingString('chunk.item', row))); + + const formatRowList = ({rows, rowAttributes}) => + html.tag( + (slots.listStyle === 'ordered' ? 'ol' : 'ul'), + stitchArrays({ + row: rows, + attributes: rowAttributes ?? rows.map(() => null), + }).map(formatRow)); + return relations.layout.slots({ title: formatListingString('title'), headingMode: 'sticky', @@ -133,10 +168,10 @@ export default { slots.content, slots.type === 'rows' && - html.tag(listTag, - slots.rows.map(row => - html.tag('li', - formatListingString('item', row)))), + formatRowList({ + rows: slots.rows, + rowAttributes: slots.rowAttributes, + }), slots.type === 'chunks' && html.tag('dl', [ @@ -167,16 +202,9 @@ export default { stitchArrays({ title: slots.chunkTitles, id: slots.chunkIDs, - rows: slots.chunkRows, rowAttributes: slots.chunkRowAttributes, - }).map(({ - title, - id, - - rows, - rowAttributes, - }) => [ + }).map(({title, id, rows, rowAttributes}) => [ relations.chunkHeading .clone() .slots({ @@ -186,19 +214,7 @@ export default { }), html.tag('dd', - html.tag(listTag, - stitchArrays({ - row: rows, - attributes: rowAttributes ?? rows.map(() => null), - }).map(({row, attributes}) => - (attributes?.href - ? html.tag('li', - html.tag('a', - attributes, - formatListingString('chunk.item', row))) - : html.tag('li', - attributes, - formatListingString('chunk.item', row)))))), + formatRowList({rows, rowAttributes})), ]), ]), ], -- cgit 1.3.0-6-gf8a5 From 7166db580d57504b5ec42d9d07078ea24f0b1149 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 16:01:05 -0400 Subject: content: listRandomPageLinks: port to chunks layout --- .../generateListRandomPageLinksAllAlbumsSection.js | 35 ---- .../generateListRandomPageLinksGroupSection.js | 51 ------ src/content/dependencies/listRandomPageLinks.js | 181 ++++++++++++++------- 3 files changed, 125 insertions(+), 142 deletions(-) delete mode 100644 src/content/dependencies/generateListRandomPageLinksAllAlbumsSection.js delete mode 100644 src/content/dependencies/generateListRandomPageLinksGroupSection.js (limited to 'src/content') diff --git a/src/content/dependencies/generateListRandomPageLinksAllAlbumsSection.js b/src/content/dependencies/generateListRandomPageLinksAllAlbumsSection.js deleted file mode 100644 index e03252c9..00000000 --- a/src/content/dependencies/generateListRandomPageLinksAllAlbumsSection.js +++ /dev/null @@ -1,35 +0,0 @@ -import {sortChronologically} from '#wiki-data'; - -export default { - contentDependencies: ['generateListRandomPageLinksAlbumLink', 'linkGroup'], - extraDependencies: ['html', 'language', 'wikiData'], - - sprawl: ({albumData}) => ({albumData}), - - query: (sprawl) => ({ - albums: - sortChronologically(sprawl.albumData.slice()) - .filter(album => album.tracks.length > 1), - }), - - relations: (relation, query) => ({ - albumLinks: - query.albums - .map(album => relation('generateListRandomPageLinksAlbumLink', album)), - }), - - generate: (relations, {html, language}) => - html.tags([ - html.tag('dt', - language.$('listingPage.other.randomPages.fromAlbum')), - - html.tag('dd', - html.tag('ul', - relations.albumLinks - .map(albumLink => - html.tag('li', - language.$('listingPage.other.randomPages.album', { - album: albumLink, - }))))), - ]), -}; diff --git a/src/content/dependencies/generateListRandomPageLinksGroupSection.js b/src/content/dependencies/generateListRandomPageLinksGroupSection.js deleted file mode 100644 index d05be8f7..00000000 --- a/src/content/dependencies/generateListRandomPageLinksGroupSection.js +++ /dev/null @@ -1,51 +0,0 @@ -import {sortChronologically} from '#wiki-data'; - -export default { - contentDependencies: ['generateListRandomPageLinksAlbumLink', 'linkGroup'], - extraDependencies: ['html', 'language', 'wikiData'], - - sprawl: ({albumData}) => ({albumData}), - - query: (sprawl, group) => ({ - albums: - sortChronologically(sprawl.albumData.slice()) - .filter(album => album.groups.includes(group)) - .filter(album => album.tracks.length > 1), - }), - - relations: (relation, query, sprawl, group) => ({ - groupLink: - relation('linkGroup', group), - - albumLinks: - query.albums - .map(album => relation('generateListRandomPageLinksAlbumLink', album)), - }), - - generate: (relations, {html, language}) => - html.tags([ - html.tag('dt', - language.$('listingPage.other.randomPages.fromGroup', { - group: relations.groupLink, - - randomAlbum: - html.tag('a', - {href: '#', 'data-random': 'album-in-group-dl'}, - language.$('listingPage.other.randomPages.fromGroup.randomAlbum')), - - randomTrack: - html.tag('a', - {href: '#', 'data-random': 'track-in-group-dl'}, - language.$('listingPage.other.randomPages.fromGroup.randomTrack')), - })), - - html.tag('dd', - html.tag('ul', - relations.albumLinks - .map(albumLink => - html.tag('li', - language.$('listingPage.other.randomPages.album', { - album: albumLink, - }))))), - ]), -}; diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index 87e5f5aa..5e74b4ac 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -1,47 +1,102 @@ import {empty} from '#sugar'; +import {sortChronologically} from '#wiki-data'; export default { contentDependencies: [ 'generateListingPage', - 'generateListRandomPageLinksAllAlbumsSection', - 'generateListRandomPageLinksGroupSection', + 'generateListRandomPageLinksAlbumLink', + 'linkGroup', ], extraDependencies: ['html', 'language', 'wikiData'], sprawl: ({wikiInfo}) => ({wikiInfo}), - query: ({wikiInfo: {divideTrackListsByGroups: groups}}, spec) => ({ - spec, - groups, - divideByGroups: !empty(groups), - }), + query(sprawl, spec) { + const query = {spec}; - relations: (relation, query) => ({ - page: relation('generateListingPage', query.spec), + const groups = sprawl.wikiInfo.divideTrackListsByGroups; - allAlbumsSection: - (query.divideByGroups - ? null - : relation('generateListRandomPageLinksAllAlbumsSection')), + query.divideByGroups = !empty(groups); - groupSections: - (query.divideByGroups - ? query.groups - .map(group => relation('generateListRandomPageLinksGroupSection', group)) - : null), - }), + if (query.divideByGroups) { + query.groups = groups; + + query.groupAlbums = + groups + .map(group => + group.albums.filter(album => album.tracks.length > 1)); + } else { + query.undividedAlbums = + sortChronologically(sprawl.albumData.slice()) + .filter(album => album.tracks.length > 1); + } + + return query; + }, + + relations(relation, query) { + const relations = {}; + + relations.page = + relation('generateListingPage', query.spec); + + if (query.divideByGroups) { + relations.groupLinks = + query.groups + .map(group => relation('linkGroup', group)); + + relations.groupAlbumLinks = + query.groupAlbums + .map(albums => albums + .map(album => + relation('generateListRandomPageLinksAlbumLink', album))); + } else { + relations.undividedAlbumLinks = + query.undividedAlbums + .map(album => + relation('generateListRandomPageLinksAlbumLink', album)); + } + + return relations; + }, generate(relations, {html, language}) { + const miscellaneousChunkRows = [ + { + stringsKey: 'randomArtist', + + mainLink: + html.tag('a', + {href: '#', 'data-random': 'artist'}, + language.$('listingPage.other.randomPages.chunk.item.randomArtist.mainLink')), + + atLeastTwoContributions: + html.tag('a', + {href: '#', 'data-random': 'artist-more-than-one-contrib'}, + language.$('listingPage.other.randomPages.chunk.item.randomArtist.atLeastTwoContributions')), + }, + + {stringsKey: 'randomAlbumWholeSite'}, + {stringsKey: 'randomTrackWholeSite'}, + ]; + + const miscellaneousChunkRowAttributes = [ + null, + {href: '#', 'data-random': 'album'}, + {href: '#','data-random': 'track'}, + ]; + return relations.page.slots({ - type: 'custom', + type: 'chunks', + content: [ html.tag('p', language.$('listingPage.other.randomPages.chooseLinkLine', { fromPart: - (empty(relations.groupSections) - ? language.$('listingPage.other.randomPages.chooseLinkLine.fromPart.notDividedByGroups') - : language.$('listingPage.other.randomPages.chooseLinkLine.fromPart.dividedByGroups')), + (relations.groupLinks + ? language.$('listingPage.other.randomPages.chooseLinkLine.fromPart.dividedByGroups') + : language.$('listingPage.other.randomPages.chooseLinkLine.fromPart.notDividedByGroups')), browserSupportPart: language.$('listingPage.other.randomPages.chooseLinkLine.browserSupportPart'), @@ -54,40 +109,54 @@ export default { html.tag('p', {class: 'js-show-once-data'}, language.$('listingPage.other.randomPages.dataLoadedLine')), + ], + + chunkTitles: [ + {stringsKey: 'misc'}, + + ... + (relations.groupLinks + ? relations.groupLinks.map(groupLink => ({ + stringsKey: 'fromGroup', + + group: groupLink, + + randomAlbum: + html.tag('a', + {href: '#', 'data-random': 'album-in-group-dl'}, + language.$('listingPage.other.randomPages.chunk.title.fromGroup.randomAlbum')), + + randomTrack: + html.tag('a', + {href: '#', 'data-random': 'track-in-group-dl'}, + language.$('listingPage.other.randomPages.chunk.title.fromGroup.randomTrack')), + })) + : [{stringsKey: 'fromAlbum'}]), + ], + + chunkRows: [ + miscellaneousChunkRows, + + ... + (relations.groupAlbumLinks + ? relations.groupAlbumLinks.map(albumLinks => + albumLinks.map(albumLink => ({ + stringsKey: 'album', + album: albumLink, + }))) + : relations.albumLinks.map(albumLink => ({ + stringsKey: 'album', + album: albumLink, + }))), + ], - html.tag('dl', [ - html.tag('dt', - language.$('listingPage.other.randomPages.misc')), - - html.tag('dd', - html.tag('ul', [ - html.tag('li', - language.$('listingPage.other.randomPages.misc.randomArtist', { - mainLink: - html.tag('a', - {href: '#', 'data-random': 'artist'}, - language.$('listingPage.other.randomPages.misc.randomArtist.mainLink')), - - atLeastTwoContributions: - html.tag('a', - {href: '#', 'data-random': 'artist-more-than-one-contrib'}, - language.$('listingPage.other.randomPages.misc.randomArtist.atLeastTwoContributions')), - })), - - html.tag('li', - html.tag('a', - {href: '#', 'data-random': 'album'}, - language.$('listingPage.other.randomPages.misc.randomAlbumWholeSite'))), - - html.tag('li', - html.tag('a', - {href: '#', 'data-random': 'track'}, - language.$('listingPage.other.randomPages.misc.randomTrackWholeSite'))), - ])), - - relations.allAlbumsSection, - relations.groupSections, - ]), + chunkRowAttributes: [ + miscellaneousChunkRowAttributes, + ... + (relations.groupAlbumLinks + ? relations.groupAlbumLinks.map(albumLinks => + albumLinks.map(() => null)) + : [relations.albumLinks.map(() => null)]), ], }); }, -- cgit 1.3.0-6-gf8a5 From b8e612f9723ef1b890a1af8745e3f165220ce9d1 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 7 Nov 2023 20:31:57 -0400 Subject: content, client, css: accents in content headings --- src/content/dependencies/generateContentHeading.js | 26 +++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateContentHeading.js b/src/content/dependencies/generateContentHeading.js index ccaf1076..56f68cb3 100644 --- a/src/content/dependencies/generateContentHeading.js +++ b/src/content/dependencies/generateContentHeading.js @@ -1,19 +1,39 @@ export default { extraDependencies: ['html'], + contentDependencies: ['generateColorStyleVariables'], + + relations: (relation) => ({ + colorVariables: relation('generateColorStyleVariables'), + }), slots: { title: {type: 'html'}, + accent: {type: 'html'}, + + color: {validate: v => v.isColor}, + id: {type: 'string'}, tag: {type: 'string', default: 'p'}, }, - generate(slots, {html}) { + generate(relations, slots, {html}) { return html.tag(slots.tag, { class: 'content-heading', id: slots.id, tabindex: '0', - }, - slots.title); + + style: + slots.color && + relations.colorVariables + .slot('color', slots.color) + .content, + }, [ + slots.title, + + html.tag('span', + {[html.onlyIfContent]: true, class: 'content-heading-accent'}, + slots.accent), + ]); } } -- cgit 1.3.0-6-gf8a5 From 869548723002ebf2f3a501c4105cdf6db7ac8aa7 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 16:33:20 -0400 Subject: content: generateListingPage: formatListingString cleanup --- src/content/dependencies/generateListingPage.js | 54 +++++++++++++++++-------- 1 file changed, 38 insertions(+), 16 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index 3878d0eb..6eee45b8 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -104,29 +104,43 @@ export default { }, generate(data, relations, slots, {html, language}) { - const formatListingString = (contextStringsKey, options = {}) => { - const baseStringsKey = `listingPage.${data.stringsKey}`; - - const parts = [baseStringsKey, contextStringsKey]; - - const {stringsKey, ...passOptions} = options; + function formatListingString({ + context, + provided = {}, + }) { + const parts = ['listingPage', data.stringsKey]; + + if (Array.isArray(context)) { + parts.push(...context); + } else { + parts.push(context); + } - if (stringsKey) { - parts.push(options.stringsKey); + if (provided.stringsKey) { + parts.push(provided.stringsKey); } - return language.formatString(parts.join('.'), passOptions); - }; + const options = {...provided}; + delete options.stringsKey; + + return language.formatString(...parts, options); + } const formatRow = ({row, attributes}) => (attributes?.href ? html.tag('li', html.tag('a', attributes, - formatListingString('chunk.item', row))) + formatListingString({ + context: 'chunk.item', + provided: row, + }))) : html.tag('li', attributes, - formatListingString('chunk.item', row))); + formatListingString({ + context: 'chunk.item', + provided: row, + }))); const formatRowList = ({rows, rowAttributes}) => html.tag( @@ -137,7 +151,8 @@ export default { }).map(formatRow)); return relations.layout.slots({ - title: formatListingString('title'), + title: formatListingString({context: 'title'}), + headingMode: 'sticky', mainContent: [ @@ -193,8 +208,10 @@ export default { hash: id, content: html.normalize( - formatListingString('chunk.title', title) - .toString() + formatListingString({ + context: 'chunk.title', + provided: title, + }).toString() .replace(/:$/, '')), }))))), ], @@ -209,8 +226,13 @@ export default { .clone() .slots({ tag: 'dt', - title: formatListingString('chunk.title', title), id, + + title: + formatListingString({ + context: 'chunk.title', + provided: title, + }), }), html.tag('dd', -- cgit 1.3.0-6-gf8a5 From f187e32c858e46af9ee2717a20ae4095f0fef325 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 16:34:15 -0400 Subject: content: generateListingPage: add chunkTitleAccents slot --- src/content/dependencies/generateListingPage.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index 6eee45b8..b3d6899d 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -78,6 +78,10 @@ export default { validate: v => v.strictArrayOf(v.isObject), }, + chunkTitleAccents: { + validate: v => v.strictArrayOf(v.optional(v.isObject)), + }, + chunkRows: { validate: v => v.strictArrayOf(v.isObject), }, @@ -218,10 +222,11 @@ export default { stitchArrays({ title: slots.chunkTitles, + titleAccent: slots.chunkTitleAccents, id: slots.chunkIDs, rows: slots.chunkRows, rowAttributes: slots.chunkRowAttributes, - }).map(({title, id, rows, rowAttributes}) => [ + }).map(({title, titleAccent, id, rows, rowAttributes}) => [ relations.chunkHeading .clone() .slots({ @@ -233,6 +238,13 @@ export default { context: 'chunk.title', provided: title, }), + + accent: + titleAccent && + formatListingString({ + context: ['chunk.title', title.stringsKey, 'accent'], + provided: titleAccent, + }), }), html.tag('dd', -- cgit 1.3.0-6-gf8a5 From 082f693274a62c9f826fd84def417f243c21d612 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 16:35:10 -0400 Subject: content: listRandomPageLinks: use chunk title accents --- src/content/dependencies/listRandomPageLinks.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index 5e74b4ac..089289f7 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -118,20 +118,28 @@ export default { (relations.groupLinks ? relations.groupLinks.map(groupLink => ({ stringsKey: 'fromGroup', - group: groupLink, + })) + : [{stringsKey: 'fromAlbum'}]), + ], + chunkTitleAccents: [ + null, + + ... + (relations.groupLinks + ? relations.groupLinks.map(() => ({ randomAlbum: html.tag('a', {href: '#', 'data-random': 'album-in-group-dl'}, - language.$('listingPage.other.randomPages.chunk.title.fromGroup.randomAlbum')), + language.$('listingPage.other.randomPages.chunk.title.fromGroup.accent.randomAlbum')), randomTrack: html.tag('a', {href: '#', 'data-random': 'track-in-group-dl'}, - language.$('listingPage.other.randomPages.chunk.title.fromGroup.randomTrack')), + language.$('listingPage.other.randomPages.chunk.title.fromGroup.accent.randomTrack')), })) - : [{stringsKey: 'fromAlbum'}]), + : [null]), ], chunkRows: [ -- cgit 1.3.0-6-gf8a5 From f6a0bf1d7b4652a7dd04ed3340010ee2a6e47b7f Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 16:40:18 -0400 Subject: content: listRandomPageLinks: show skip to section --- src/content/dependencies/generateListingPage.js | 2 +- src/content/dependencies/listRandomPageLinks.js | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index b3d6899d..95c039eb 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -96,7 +96,7 @@ export default { }, chunkIDs: { - validate: v => v.strictArrayOf(v.isString), + validate: v => v.strictArrayOf(v.optional(v.isString)), }, listStyle: { diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index 089289f7..375a72d7 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -61,7 +61,19 @@ export default { return relations; }, - generate(relations, {html, language}) { + data(query) { + const data = {}; + + if (query.divideByGroups) { + data.groupDirectories = + query.groups + .map(group => group.directory); + } + + return data; + }, + + generate(data, relations, {html, language}) { const miscellaneousChunkRows = [ { stringsKey: 'randomArtist', @@ -111,6 +123,13 @@ export default { language.$('listingPage.other.randomPages.dataLoadedLine')), ], + showSkipToSection: true, + + chunkIDs: [ + null, + ...data.groupDirectories, + ], + chunkTitles: [ {stringsKey: 'misc'}, -- cgit 1.3.0-6-gf8a5 From 6f9d122f9d1ad5bb7e0aad917bbc1ff218e9b4df Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 10 Nov 2023 17:46:45 -0400 Subject: content: listRandomPageLinks: general syntax/slot fixes --- src/content/dependencies/listRandomPageLinks.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index 375a72d7..0b904019 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -10,7 +10,7 @@ export default { extraDependencies: ['html', 'language', 'wikiData'], - sprawl: ({wikiInfo}) => ({wikiInfo}), + sprawl: ({albumData, wikiInfo}) => ({albumData, wikiInfo}), query(sprawl, spec) { const query = {spec}; @@ -125,10 +125,10 @@ export default { showSkipToSection: true, - chunkIDs: [ - null, - ...data.groupDirectories, - ], + chunkIDs: + (data.groupDirectories + ? [null, ...data.groupDirectories] + : null), chunkTitles: [ {stringsKey: 'misc'}, @@ -171,10 +171,12 @@ export default { stringsKey: 'album', album: albumLink, }))) - : relations.albumLinks.map(albumLink => ({ - stringsKey: 'album', - album: albumLink, - }))), + : [ + relations.undividedAlbumLinks.map(albumLink => ({ + stringsKey: 'album', + album: albumLink, + })), + ]), ], chunkRowAttributes: [ @@ -183,7 +185,7 @@ export default { (relations.groupAlbumLinks ? relations.groupAlbumLinks.map(albumLinks => albumLinks.map(() => null)) - : [relations.albumLinks.map(() => null)]), + : [relations.undividedAlbumLinks.map(() => null)]), ], }); }, -- cgit 1.3.0-6-gf8a5 From 2de59682e52cd9121e53aec94a27ba78a09abb3e Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 10 Nov 2023 17:47:16 -0400 Subject: content: generateFlashActSidebar: try to behave without hsmusic data --- src/content/dependencies/generateFlashActSidebar.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateFlashActSidebar.js b/src/content/dependencies/generateFlashActSidebar.js index bd6063c9..80072483 100644 --- a/src/content/dependencies/generateFlashActSidebar.js +++ b/src/content/dependencies/generateFlashActSidebar.js @@ -1,5 +1,6 @@ import find from '#find'; import {stitchArrays} from '#sugar'; +import {filterMultipleArrays} from '#wiki-data'; export default { contentDependencies: ['linkFlash', 'linkFlashAct', 'linkFlashIndex'], @@ -11,10 +12,12 @@ export default { query(sprawl, act, flash) { const findFlashAct = directory => - find.flashAct(directory, sprawl.flashActData, {mode: 'error'}); + find.flashAct(directory, sprawl.flashActData, {mode: 'quiet'}); + + const homestuckSide1 = findFlashAct('flash-act:a1'); const sideFirstActs = [ - findFlashAct('flash-act:a1'), + sprawl.flashActData[0], findFlashAct('flash-act:a6a1'), findFlashAct('flash-act:hiveswap'), findFlashAct('flash-act:cool-and-new-web-comic'), @@ -22,7 +25,9 @@ export default { ]; const sideNames = [ - `Side 1 (Acts 1-5)`, + (homestuckSide1 + ? `Side 1 (Acts 1-5)` + : `All flashes & games`), `Side 2 (Acts 6-7)`, `Additional Canon`, `Fan Adventures`, @@ -30,13 +35,18 @@ export default { ]; const sideColors = [ - '#4ac925', + (homestuckSide1 + ? '#4ac925' + : null), '#3796c6', '#f2a400', '#c466ff', '#32c7fe', ]; + filterMultipleArrays(sideFirstActs, sideNames, sideColors, + firstAct => firstAct); + const sideFirstActIndexes = sideFirstActs .map(act => sprawl.flashActData.indexOf(act)); -- cgit 1.3.0-6-gf8a5 From ad943caefcacf62347199a73a90dc704cd8e369c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 10 Nov 2023 17:47:44 -0400 Subject: content: generateListingPage: fix row-based listings... oops... --- src/content/dependencies/generateListingPage.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateListingPage.js b/src/content/dependencies/generateListingPage.js index 95c039eb..2050d62d 100644 --- a/src/content/dependencies/generateListingPage.js +++ b/src/content/dependencies/generateListingPage.js @@ -1,4 +1,4 @@ -import {empty, stitchArrays} from '#sugar'; +import {bindOpts, empty, stitchArrays} from '#sugar'; export default { contentDependencies: [ @@ -130,29 +130,33 @@ export default { return language.formatString(...parts, options); } - const formatRow = ({row, attributes}) => + const formatRow = ({context, row, attributes}) => (attributes?.href ? html.tag('li', html.tag('a', attributes, formatListingString({ - context: 'chunk.item', + context, provided: row, }))) : html.tag('li', attributes, formatListingString({ - context: 'chunk.item', + context, provided: row, }))); - const formatRowList = ({rows, rowAttributes}) => + const formatRowList = ({context, rows, rowAttributes}) => html.tag( (slots.listStyle === 'ordered' ? 'ol' : 'ul'), stitchArrays({ row: rows, attributes: rowAttributes ?? rows.map(() => null), - }).map(formatRow)); + }).map( + bindOpts(formatRow, { + [bindOpts.bindIndex]: 0, + context, + }))); return relations.layout.slots({ title: formatListingString({context: 'title'}), @@ -188,6 +192,7 @@ export default { slots.type === 'rows' && formatRowList({ + context: 'item', rows: slots.rows, rowAttributes: slots.rowAttributes, }), @@ -248,7 +253,11 @@ export default { }), html.tag('dd', - formatRowList({rows, rowAttributes})), + formatRowList({ + context: 'chunk.item', + rows, + rowAttributes, + })), ]), ]), ], -- cgit 1.3.0-6-gf8a5 From f7007f0a090f22929b450ac816757c49e17b9ef1 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 10 Nov 2023 17:48:07 -0400 Subject: content: generatePageLayout: don't assume custom footer content --- src/content/dependencies/generatePageLayout.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js index 72dfbae5..5fa6e751 100644 --- a/src/content/dependencies/generatePageLayout.js +++ b/src/content/dependencies/generatePageLayout.js @@ -85,8 +85,10 @@ export default { relations.stickyHeadingContainer = relation('generateStickyHeadingContainer'); - relations.defaultFooterContent = - relation('transformContent', sprawl.footerContent); + if (sprawl.footerContent) { + relations.defaultFooterContent = + relation('transformContent', sprawl.footerContent); + } relations.colorStyleRules = relation('generateColorStyleRules'); @@ -231,7 +233,7 @@ export default { let footerContent = slots.footerContent; - if (html.isBlank(footerContent)) { + if (html.isBlank(footerContent) && relations.defaultFooterContent) { footerContent = relations.defaultFooterContent .slot('mode', 'multiline'); } -- cgit 1.3.0-6-gf8a5 From 3f236319355b093b336e70119a7127bd23693ec2 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 10 Nov 2023 17:48:26 -0400 Subject: content: generateWikiHomeAlbumsRow: support albums without covers --- src/content/dependencies/generateWikiHomeAlbumsRow.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateWikiHomeAlbumsRow.js b/src/content/dependencies/generateWikiHomeAlbumsRow.js index cb0860f5..2c6a147e 100644 --- a/src/content/dependencies/generateWikiHomeAlbumsRow.js +++ b/src/content/dependencies/generateWikiHomeAlbumsRow.js @@ -11,7 +11,7 @@ export default { 'transformContent', ], - extraDependencies: ['wikiData'], + extraDependencies: ['language', 'wikiData'], sprawl({albumData}, row) { const sprawl = {}; @@ -90,12 +90,14 @@ export default { data.paths = sprawl.albums .map(album => - ['media.albumCover', album.directory, album.coverArtFileExtension]); + (album.hasCoverArt + ? ['media.albumCover', album.directory, album.coverArtFileExtension] + : null)); return data; }, - generate(data, relations) { + generate(data, relations, {language}) { // Grids and carousels share some slots! Very convenient. const commonSlots = {}; @@ -106,8 +108,15 @@ export default { stitchArrays({ image: relations.images, path: data.paths, - }).map(({image, path}) => - image.slot('path', path)); + name: data.names, + }).map(({image, path, name}) => + image.slots({ + path, + missingSourceContent: + language.$('misc.albumGrid.noCoverArt', { + album: name, + }), + })); commonSlots.actionLinks = (relations.actionLinks -- cgit 1.3.0-6-gf8a5 From 95b1ed2f163c1a2be7b6582499cecb8963548155 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 12 Nov 2023 15:03:21 -0400 Subject: content: generateFlashIndexPage: don't show jump links if empty --- src/content/dependencies/generateFlashIndexPage.js | 38 ++++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateFlashIndexPage.js b/src/content/dependencies/generateFlashIndexPage.js index ad1dab94..5fc62ab3 100644 --- a/src/content/dependencies/generateFlashIndexPage.js +++ b/src/content/dependencies/generateFlashIndexPage.js @@ -1,4 +1,4 @@ -import {stitchArrays} from '#sugar'; +import {empty, stitchArrays} from '#sugar'; export default { contentDependencies: [ @@ -95,23 +95,25 @@ export default { mainClasses: ['flash-index'], mainContent: [ - html.tag('p', - {class: 'quick-info'}, - language.$('misc.jumpTo')), - - html.tag('ul', - {class: 'quick-info'}, - stitchArrays({ - colorVariables: relations.jumpLinkColorVariables, - anchor: data.jumpLinkAnchors, - color: data.jumpLinkColors, - label: data.jumpLinkLabels, - }).map(({colorVariables, anchor, color, label}) => - html.tag('li', - html.tag('a', { - href: '#' + anchor, - style: colorVariables.slot('color', color).content, - }, label)))), + !empty(data.jumpLinkLabels) && [ + html.tag('p', + {class: 'quick-info'}, + language.$('misc.jumpTo')), + + html.tag('ul', + {class: 'quick-info'}, + stitchArrays({ + colorVariables: relations.jumpLinkColorVariables, + anchor: data.jumpLinkAnchors, + color: data.jumpLinkColors, + label: data.jumpLinkLabels, + }).map(({colorVariables, anchor, color, label}) => + html.tag('li', + html.tag('a', { + href: '#' + anchor, + style: colorVariables.slot('color', color).content, + }, label)))), + ], stitchArrays({ colorVariables: relations.actColorVariables, -- cgit 1.3.0-6-gf8a5 From 51097802bd2f9d58d4062235858f588a4cf58d93 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 12 Nov 2023 15:16:19 -0400 Subject: content: generateFooterLocalizationLinks: refactor + hide if empty --- .../generateFooterLocalizationLinks.js | 53 ++++++++++++++-------- 1 file changed, 34 insertions(+), 19 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateFooterLocalizationLinks.js b/src/content/dependencies/generateFooterLocalizationLinks.js index 5df83566..86e6c61a 100644 --- a/src/content/dependencies/generateFooterLocalizationLinks.js +++ b/src/content/dependencies/generateFooterLocalizationLinks.js @@ -1,3 +1,6 @@ +import {stitchArrays} from '#sugar'; +import {sortByName} from '#wiki-data'; + export default { extraDependencies: [ 'defaultLanguage', @@ -16,25 +19,37 @@ export default { pagePath, to, }) { - const links = Object.entries(languages) - .filter(([code, language]) => code !== 'default' && !language.hidden) - .map(([code, language]) => language) - .sort(({name: a}, {name: b}) => (a < b ? -1 : a > b ? 1 : 0)) - .map((language) => - html.tag('span', - html.tag('a', - { - href: - language === defaultLanguage - ? to( - 'localizedDefaultLanguage.' + pagePath[0], - ...pagePath.slice(1)) - : to( - 'localizedWithBaseDirectory.' + pagePath[0], - language.code, - ...pagePath.slice(1)), - }, - language.name))); + const switchableLanguages = + Object.entries(languages) + .filter(([code, language]) => code !== 'default' && !language.hidden) + .map(([code, language]) => language); + + if (switchableLanguages.length <= 1) { + return html.blank(); + } + + sortByName(switchableLanguages); + + const [pagePathSubkey, ...pagePathArgs] = pagePath; + + const linkPaths = + switchableLanguages.map(language => + (language === defaultLanguage + ? (['localizedDefaultLanguage.' + pagePathSubkey, + ...pagePathArgs]) + : (['localizedWithBaseDirectory.' + pagePathSubkey, + language.code, + ...pagePathArgs]))); + + const links = + stitchArrays({ + language: switchableLanguages, + linkPath: linkPaths, + }).map(({language, linkPath}) => + html.tag('span', + html.tag('a', + {href: to(...linkPath)}, + language.name))); return html.tag('div', {class: 'footer-localization-links'}, language.$('misc.uiLanguage', { -- cgit 1.3.0-6-gf8a5 From 52cc83065f41472a4c32c2003b0a715a66d4739a Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 13 Nov 2023 16:36:36 -0400 Subject: content: generateWikiHomeAlbumsRow: handle no names in carousel --- src/content/dependencies/generateWikiHomeAlbumsRow.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateWikiHomeAlbumsRow.js b/src/content/dependencies/generateWikiHomeAlbumsRow.js index 2c6a147e..a19f104c 100644 --- a/src/content/dependencies/generateWikiHomeAlbumsRow.js +++ b/src/content/dependencies/generateWikiHomeAlbumsRow.js @@ -108,14 +108,15 @@ export default { stitchArrays({ image: relations.images, path: data.paths, - name: data.names, + name: data.names ?? data.paths.slice().fill(null), }).map(({image, path, name}) => image.slots({ path, missingSourceContent: - language.$('misc.albumGrid.noCoverArt', { - album: name, - }), + name && + language.$('misc.albumGrid.noCoverArt', { + album: name, + }), })); commonSlots.actionLinks = -- cgit 1.3.0-6-gf8a5 From d019852fc5dcfa2a7686c17ec1bc9c4877ad5832 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 15 Nov 2023 11:27:22 -0400 Subject: content, css: generateCommentarySection{Entry}? --- src/content/dependencies/generateAlbumInfoPage.js | 22 ++----- .../dependencies/generateCommentarySection.js | 29 ++++++++ .../dependencies/generateCommentarySectionEntry.js | 77 ++++++++++++++++++++++ src/content/dependencies/generateTrackInfoPage.js | 22 ++----- 4 files changed, 114 insertions(+), 36 deletions(-) create mode 100644 src/content/dependencies/generateCommentarySection.js create mode 100644 src/content/dependencies/generateCommentarySectionEntry.js (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumInfoPage.js b/src/content/dependencies/generateAlbumInfoPage.js index 5fe27caf..90a120ca 100644 --- a/src/content/dependencies/generateAlbumInfoPage.js +++ b/src/content/dependencies/generateAlbumInfoPage.js @@ -17,6 +17,7 @@ export default { 'generateAlbumStyleRules', 'generateAlbumTrackList', 'generateChronologyLinks', + 'generateCommentarySection', 'generateContentHeading', 'generatePageLayout', 'linkAlbum', @@ -126,13 +127,8 @@ export default { // Section: Artist commentary if (album.commentary) { - const artistCommentary = sections.artistCommentary = {}; - - artistCommentary.heading = - relation('generateContentHeading'); - - artistCommentary.content = - relation('transformContent', album.commentary); + sections.artistCommentary = + relation('generateCommentarySection', album.commentary); } return relations; @@ -235,17 +231,7 @@ export default { sec.additionalFiles.additionalFilesList, ], - sec.artistCommentary && [ - sec.artistCommentary.heading - .slots({ - id: 'artist-commentary', - title: language.$('releaseInfo.artistCommentary') - }), - - html.tag('blockquote', - sec.artistCommentary.content - .slot('mode', 'multiline')), - ], + sec.artistCommentary, ], navLinkStyle: 'hierarchical', diff --git a/src/content/dependencies/generateCommentarySection.js b/src/content/dependencies/generateCommentarySection.js new file mode 100644 index 00000000..d08c3c90 --- /dev/null +++ b/src/content/dependencies/generateCommentarySection.js @@ -0,0 +1,29 @@ +export default { + contentDependencies: [ + 'transformContent', + 'generateCommentarySectionEntry', + 'generateContentHeading', + ], + + extraDependencies: ['html', 'language'], + + relations: (relation, entries) => ({ + heading: + relation('generateContentHeading'), + + entries: + entries.map(entry => + relation('generateCommentarySectionEntry', entry)), + }), + + generate: (relations, {html, language}) => + html.tags([ + relations.heading + .slots({ + id: 'artist-commentary', + title: language.$('misc.artistCommentary') + }), + + relations.entries, + ]), +}; diff --git a/src/content/dependencies/generateCommentarySectionEntry.js b/src/content/dependencies/generateCommentarySectionEntry.js new file mode 100644 index 00000000..22e8fd1e --- /dev/null +++ b/src/content/dependencies/generateCommentarySectionEntry.js @@ -0,0 +1,77 @@ +export default { + contentDependencies: ['linkArtist', 'transformContent'], + extraDependencies: ['html', 'language'], + + relations: (relation, entry) => ({ + artistLink: + (entry.artist && !entry.artistDisplayText + ? relation('linkArtist', entry.artist) + : null), + + artistsContent: + (entry.artistDisplayText + ? relation('transformContent', entry.artistDisplayText) + : null), + + annotationContent: + (entry.annotation + ? relation('transformContent', entry.annotation) + : null), + + bodyContent: + (entry.body + ? relation('transformContent', entry.body) + : null), + }), + + data: (entry) => ({ + date: entry.date, + }), + + generate(data, relations, {html, language}) { + const artistsSpan = + html.tag('span', {class: 'commentary-entry-artists'}, + (relations.artistsContent + ? relations.artistsContent.slot('mode', 'inline') + : relations.artistLink + ? relations.artistLink + : language.$('misc.artistCommentary.noArtist'))); + + const accentParts = ['misc.artistCommentary.entry.title.accent']; + const accentOptions = {}; + + if (relations.annotationContent) { + accentParts.push('withAnnotation'); + accentOptions.annotation = + relations.annotationContent.slot('mode', 'inline'); + } + + if (data.date) { + accentParts.push('withDate'); + accentOptions.date = + language.formatDate(data.date); + } + + const accent = + (accentParts.length > 1 + ? html.tag('span', {class: 'commentary-entry-accent'}, + language.$(...accentParts, accentOptions)) + : null); + + const titleParts = ['misc.artistCommentary.entry.title']; + const titleOptions = {artists: artistsSpan}; + + if (accent) { + titleParts.push('withAccent'); + titleOptions.accent = accent; + } + + return html.tags([ + html.tag('p', {class: 'commentary-entry-heading'}, + language.$(...titleParts, titleOptions)), + + html.tag('blockquote', {class: 'commentary-entry-body'}, + relations.bodyContent.slot('mode', 'multiline')), + ]); + }, +}; diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js index 93334948..200cf054 100644 --- a/src/content/dependencies/generateTrackInfoPage.js +++ b/src/content/dependencies/generateTrackInfoPage.js @@ -11,6 +11,7 @@ export default { 'generateAlbumSidebar', 'generateAlbumStyleRules', 'generateChronologyLinks', + 'generateCommentarySection', 'generateContentHeading', 'generateContributionList', 'generatePageLayout', @@ -268,13 +269,8 @@ export default { // Section: Artist commentary if (track.commentary) { - const artistCommentary = sections.artistCommentary = {}; - - artistCommentary.heading = - relation('generateContentHeading'); - - artistCommentary.content = - relation('transformContent', track.commentary); + sections.artistCommentary = + relation('generateCommentarySection', track.commentary); } return relations; @@ -491,17 +487,7 @@ export default { sec.additionalFiles.list, ], - sec.artistCommentary && [ - sec.artistCommentary.heading - .slots({ - id: 'artist-commentary', - title: language.$('releaseInfo.artistCommentary') - }), - - html.tag('blockquote', - sec.artistCommentary.content - .slot('mode', 'multiline')), - ], + sec.artistCommentary, ], navLinkStyle: 'hierarchical', -- cgit 1.3.0-6-gf8a5 From ecc084546ca136bcab4bfce25e8291c3de565e67 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 15 Nov 2023 18:06:33 -0400 Subject: content: generatePageLayout: sidebar column & section class slots --- src/content/dependencies/generatePageLayout.js | 29 ++++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js index 5fa6e751..3bf0c9f0 100644 --- a/src/content/dependencies/generatePageLayout.js +++ b/src/content/dependencies/generatePageLayout.js @@ -6,12 +6,19 @@ function sidebarSlots(side) { // if specified. [side + 'Content']: {type: 'html'}, - // Multiple is an array of {content: (HTML)} objects. Each of these - // will generate one sidebar section. + // A single class to apply to the whole sidebar. If specifying multiple + // sections, this be added to the containing sidebar-column - specify a + // class on each section if that's more suitable. + [side + 'Class']: {type: 'string'}, + + // Multiple is an array of objects, each specifying content (HTML) and + // optionally class (a string). Each of these will generate one sidebar + // section. [side + 'Multiple']: { validate: v => v.sparseArrayOf( v.validateProperties({ + class: v.optional(v.isString), content: v.isHTML, })), }, @@ -27,6 +34,7 @@ function sidebarSlots(side) { // the whole section's containing box (or the sidebar column as a whole). [side + 'StickyMode']: { validate: v => v.is('last', 'column', 'static'), + default: 'static', }, // Collapsing sidebars disappear when the viewport is sufficiently @@ -354,6 +362,7 @@ export default { const generateSidebarHTML = (side, id) => { const content = slots[side + 'Content']; + const topClass = slots[side + 'Class']; const multiple = slots[side + 'Multiple']; const stickyMode = slots[side + 'StickyMode']; const wide = slots[side + 'Wide']; @@ -363,20 +372,18 @@ export default { let sidebarContent = html.blank(); if (!html.isBlank(content)) { - sidebarClasses = ['sidebar']; + sidebarClasses = ['sidebar', topClass]; sidebarContent = content; } else if (multiple) { - sidebarClasses = ['sidebar-multiple']; + sidebarClasses = ['sidebar-multiple', topClass]; sidebarContent = multiple .filter(Boolean) - .map(({content}) => - html.tag('div', - { - [html.onlyIfContent]: true, - class: 'sidebar', - }, - content)); + .map(box => + html.tag('div', { + [html.onlyIfContent]: true, + class: ['sidebar', box.class], + }, box.content)); } if (html.isBlank(sidebarContent)) { -- cgit 1.3.0-6-gf8a5 From e9d4cd7fb8bb9c55f3dd90b36eec7e246bc2589e Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 15 Nov 2023 18:15:37 -0400 Subject: content: add classes to various sidebar boxes --- .../dependencies/generateAlbumCommentaryPage.js | 1 + src/content/dependencies/generateAlbumSidebar.js | 8 ++++++-- .../dependencies/generateFlashActSidebar.js | 24 +++++++++++++--------- src/content/dependencies/generateGroupSidebar.js | 1 + src/content/dependencies/generateListingSidebar.js | 1 + .../dependencies/generateWikiHomeNewsBox.js | 1 + src/content/dependencies/generateWikiHomePage.js | 1 + 7 files changed, 25 insertions(+), 12 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumCommentaryPage.js b/src/content/dependencies/generateAlbumCommentaryPage.js index 3ad1549e..e2415516 100644 --- a/src/content/dependencies/generateAlbumCommentaryPage.js +++ b/src/content/dependencies/generateAlbumCommentaryPage.js @@ -201,6 +201,7 @@ export default { ], leftSidebarStickyMode: 'column', + leftSidebarClass: 'commentary-track-list-sidebar-box', leftSidebarContent: [ html.tag('h1', relations.sidebarAlbumLink), relations.sidebarTrackSections.map(section => diff --git a/src/content/dependencies/generateAlbumSidebar.js b/src/content/dependencies/generateAlbumSidebar.js index a84f4357..5ef4501b 100644 --- a/src/content/dependencies/generateAlbumSidebar.js +++ b/src/content/dependencies/generateAlbumSidebar.js @@ -30,6 +30,7 @@ export default { generate(data, relations, {html}) { const trackListBox = { + class: 'track-list-sidebar-box', content: html.tags([ html.tag('h1', relations.albumLink), @@ -40,8 +41,10 @@ export default { if (data.isAlbumPage) { const groupBoxes = relations.groupBoxes - .map(content => content.slot('mode', 'album')) - .map(content => ({content})); + .map(content => ({ + class: 'individual-group-sidebar-box', + content: content.slot('mode', 'album'), + })); return { leftSidebarMultiple: [ @@ -52,6 +55,7 @@ export default { } const conjoinedGroupBox = { + class: 'conjoined-group-sidebar-box', content: relations.groupBoxes .flatMap((content, i, {length}) => [ diff --git a/src/content/dependencies/generateFlashActSidebar.js b/src/content/dependencies/generateFlashActSidebar.js index 80072483..29379644 100644 --- a/src/content/dependencies/generateFlashActSidebar.js +++ b/src/content/dependencies/generateFlashActSidebar.js @@ -137,7 +137,7 @@ export default { }), generate(data, relations, {getColors, html, language}) { - const currentActBox = html.tags([ + const currentActBoxContent = html.tags([ html.tag('h1', relations.currentActLink), html.tag('details', @@ -160,7 +160,7 @@ export default { ]), ]); - const sideMapBox = html.tags([ + const sideMapBoxContent = html.tags([ html.tag('h1', relations.flashIndexLink), stitchArrays({ @@ -188,17 +188,21 @@ export default { ])), ]); + const sideMapBox = { + class: 'flash-act-map-sidebar-box', + content: sideMapBoxContent, + }; + + const currentActBox = { + class: 'flash-current-act-sidebar-box', + content: currentActBoxContent, + }; + return { leftSidebarMultiple: (data.isFlashActPage - ? [ - {content: sideMapBox}, - {content: currentActBox}, - ] - : [ - {content: currentActBox}, - {content: sideMapBox}, - ]), + ? [sideMapBox, currentActBox] + : [currentActBox, sideMapBox]), }; }, }; diff --git a/src/content/dependencies/generateGroupSidebar.js b/src/content/dependencies/generateGroupSidebar.js index 6baf37f4..98b288fa 100644 --- a/src/content/dependencies/generateGroupSidebar.js +++ b/src/content/dependencies/generateGroupSidebar.js @@ -22,6 +22,7 @@ export default { generate(relations, slots, {html, language}) { return { + leftSidebarClass: 'category-map-sidebar-box', leftSidebarContent: [ html.tag('h1', language.$('groupSidebar.title')), diff --git a/src/content/dependencies/generateListingSidebar.js b/src/content/dependencies/generateListingSidebar.js index fe2a08fa..1cdd236b 100644 --- a/src/content/dependencies/generateListingSidebar.js +++ b/src/content/dependencies/generateListingSidebar.js @@ -11,6 +11,7 @@ export default { generate(relations, {html}) { return { + leftSidebarClass: 'listing-map-sidebar-box', leftSidebarContent: [ html.tag('h1', relations.listingIndexLink), relations.listingIndexList.slot('mode', 'sidebar'), diff --git a/src/content/dependencies/generateWikiHomeNewsBox.js b/src/content/dependencies/generateWikiHomeNewsBox.js index 8acd426c..0d8303f1 100644 --- a/src/content/dependencies/generateWikiHomeNewsBox.js +++ b/src/content/dependencies/generateWikiHomeNewsBox.js @@ -42,6 +42,7 @@ export default { } return { + class: 'latest-news-sidebar-box', content: [ html.tag('h1', language.$('homepage.news.title')), diff --git a/src/content/dependencies/generateWikiHomePage.js b/src/content/dependencies/generateWikiHomePage.js index 40a6b1c5..36fcc6f2 100644 --- a/src/content/dependencies/generateWikiHomePage.js +++ b/src/content/dependencies/generateWikiHomePage.js @@ -75,6 +75,7 @@ export default { leftSidebarMultiple: [ (relations.customSidebarContent ? { + class: 'custom-content-sidebar-box', content: relations.customSidebarContent .slot('mode', 'multiline'), -- cgit 1.3.0-6-gf8a5 From c399b00ccea8280032e0576a99eab2d34a04355c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 15 Nov 2023 18:17:15 -0400 Subject: content, client: use 'track-in-sidebar' for random link in nav --- src/content/dependencies/generateAlbumNavAccent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumNavAccent.js b/src/content/dependencies/generateAlbumNavAccent.js index 7eb1dac0..01c88bf7 100644 --- a/src/content/dependencies/generateAlbumNavAccent.js +++ b/src/content/dependencies/generateAlbumNavAccent.js @@ -92,7 +92,7 @@ export default { html.tag('a', { href: '#', - 'data-random': 'track-in-album', + 'data-random': 'track-in-sidebar', id: 'random-button', }, (data.isTrackPage -- cgit 1.3.0-6-gf8a5 From 43141f1fc41768679b63e154ac21203e928b17c7 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 15 Nov 2023 18:19:00 -0400 Subject: client, content: client2.js -> client3.js --- src/content/dependencies/generatePageLayout.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js index 3bf0c9f0..95551f3e 100644 --- a/src/content/dependencies/generatePageLayout.js +++ b/src/content/dependencies/generatePageLayout.js @@ -655,7 +655,7 @@ export default { html.tag('script', { type: 'module', - src: to('shared.staticFile', 'client2.js', cachebust), + src: to('shared.staticFile', 'client3.js', cachebust), }), ]), ]) -- cgit 1.3.0-6-gf8a5 From 91f00a36b33d13630ea7a9ac6fcd03110b0f1a73 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 15 Nov 2023 18:55:22 -0400 Subject: client: tidy & better isolate random links code in client info --- src/content/dependencies/listRandomPageLinks.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index 0b904019..5e2972ad 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -114,12 +114,10 @@ export default { language.$('listingPage.other.randomPages.chooseLinkLine.browserSupportPart'), })), - html.tag('p', - {class: 'js-hide-once-data'}, + html.tag('p', {id: 'data-loading-line'}, language.$('listingPage.other.randomPages.dataLoadingLine')), - html.tag('p', - {class: 'js-show-once-data'}, + html.tag('p', {id: 'data-loaded-line'}, language.$('listingPage.other.randomPages.dataLoadedLine')), ], -- cgit 1.3.0-6-gf8a5 From 28371f6e029fb86ba536bf4c20e787dba44d202b Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 15 Nov 2023 18:56:10 -0400 Subject: content, client: handle random data failing to load --- src/content/dependencies/listRandomPageLinks.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/content') diff --git a/src/content/dependencies/listRandomPageLinks.js b/src/content/dependencies/listRandomPageLinks.js index 5e2972ad..18585696 100644 --- a/src/content/dependencies/listRandomPageLinks.js +++ b/src/content/dependencies/listRandomPageLinks.js @@ -119,6 +119,9 @@ export default { html.tag('p', {id: 'data-loaded-line'}, language.$('listingPage.other.randomPages.dataLoadedLine')), + + html.tag('p', {id: 'data-error-line'}, + language.$('listingPage.other.randomPages.dataErrorLine')), ], showSkipToSection: true, -- cgit 1.3.0-6-gf8a5 From 4b62389403ef84497d5855e8ef1359ebf5784881 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 16 Nov 2023 14:12:06 -0400 Subject: content: generateCommentarySectionEntry -> generateCommentaryEntry --- .../dependencies/generateCommentaryEntry.js | 77 ++++++++++++++++++++++ .../dependencies/generateCommentarySection.js | 4 +- .../dependencies/generateCommentarySectionEntry.js | 77 ---------------------- 3 files changed, 79 insertions(+), 79 deletions(-) create mode 100644 src/content/dependencies/generateCommentaryEntry.js delete mode 100644 src/content/dependencies/generateCommentarySectionEntry.js (limited to 'src/content') diff --git a/src/content/dependencies/generateCommentaryEntry.js b/src/content/dependencies/generateCommentaryEntry.js new file mode 100644 index 00000000..22e8fd1e --- /dev/null +++ b/src/content/dependencies/generateCommentaryEntry.js @@ -0,0 +1,77 @@ +export default { + contentDependencies: ['linkArtist', 'transformContent'], + extraDependencies: ['html', 'language'], + + relations: (relation, entry) => ({ + artistLink: + (entry.artist && !entry.artistDisplayText + ? relation('linkArtist', entry.artist) + : null), + + artistsContent: + (entry.artistDisplayText + ? relation('transformContent', entry.artistDisplayText) + : null), + + annotationContent: + (entry.annotation + ? relation('transformContent', entry.annotation) + : null), + + bodyContent: + (entry.body + ? relation('transformContent', entry.body) + : null), + }), + + data: (entry) => ({ + date: entry.date, + }), + + generate(data, relations, {html, language}) { + const artistsSpan = + html.tag('span', {class: 'commentary-entry-artists'}, + (relations.artistsContent + ? relations.artistsContent.slot('mode', 'inline') + : relations.artistLink + ? relations.artistLink + : language.$('misc.artistCommentary.noArtist'))); + + const accentParts = ['misc.artistCommentary.entry.title.accent']; + const accentOptions = {}; + + if (relations.annotationContent) { + accentParts.push('withAnnotation'); + accentOptions.annotation = + relations.annotationContent.slot('mode', 'inline'); + } + + if (data.date) { + accentParts.push('withDate'); + accentOptions.date = + language.formatDate(data.date); + } + + const accent = + (accentParts.length > 1 + ? html.tag('span', {class: 'commentary-entry-accent'}, + language.$(...accentParts, accentOptions)) + : null); + + const titleParts = ['misc.artistCommentary.entry.title']; + const titleOptions = {artists: artistsSpan}; + + if (accent) { + titleParts.push('withAccent'); + titleOptions.accent = accent; + } + + return html.tags([ + html.tag('p', {class: 'commentary-entry-heading'}, + language.$(...titleParts, titleOptions)), + + html.tag('blockquote', {class: 'commentary-entry-body'}, + relations.bodyContent.slot('mode', 'multiline')), + ]); + }, +}; diff --git a/src/content/dependencies/generateCommentarySection.js b/src/content/dependencies/generateCommentarySection.js index d08c3c90..8ae1b2d0 100644 --- a/src/content/dependencies/generateCommentarySection.js +++ b/src/content/dependencies/generateCommentarySection.js @@ -1,7 +1,7 @@ export default { contentDependencies: [ 'transformContent', - 'generateCommentarySectionEntry', + 'generateCommentaryEntry', 'generateContentHeading', ], @@ -13,7 +13,7 @@ export default { entries: entries.map(entry => - relation('generateCommentarySectionEntry', entry)), + relation('generateCommentaryEntry', entry)), }), generate: (relations, {html, language}) => diff --git a/src/content/dependencies/generateCommentarySectionEntry.js b/src/content/dependencies/generateCommentarySectionEntry.js deleted file mode 100644 index 22e8fd1e..00000000 --- a/src/content/dependencies/generateCommentarySectionEntry.js +++ /dev/null @@ -1,77 +0,0 @@ -export default { - contentDependencies: ['linkArtist', 'transformContent'], - extraDependencies: ['html', 'language'], - - relations: (relation, entry) => ({ - artistLink: - (entry.artist && !entry.artistDisplayText - ? relation('linkArtist', entry.artist) - : null), - - artistsContent: - (entry.artistDisplayText - ? relation('transformContent', entry.artistDisplayText) - : null), - - annotationContent: - (entry.annotation - ? relation('transformContent', entry.annotation) - : null), - - bodyContent: - (entry.body - ? relation('transformContent', entry.body) - : null), - }), - - data: (entry) => ({ - date: entry.date, - }), - - generate(data, relations, {html, language}) { - const artistsSpan = - html.tag('span', {class: 'commentary-entry-artists'}, - (relations.artistsContent - ? relations.artistsContent.slot('mode', 'inline') - : relations.artistLink - ? relations.artistLink - : language.$('misc.artistCommentary.noArtist'))); - - const accentParts = ['misc.artistCommentary.entry.title.accent']; - const accentOptions = {}; - - if (relations.annotationContent) { - accentParts.push('withAnnotation'); - accentOptions.annotation = - relations.annotationContent.slot('mode', 'inline'); - } - - if (data.date) { - accentParts.push('withDate'); - accentOptions.date = - language.formatDate(data.date); - } - - const accent = - (accentParts.length > 1 - ? html.tag('span', {class: 'commentary-entry-accent'}, - language.$(...accentParts, accentOptions)) - : null); - - const titleParts = ['misc.artistCommentary.entry.title']; - const titleOptions = {artists: artistsSpan}; - - if (accent) { - titleParts.push('withAccent'); - titleOptions.accent = accent; - } - - return html.tags([ - html.tag('p', {class: 'commentary-entry-heading'}, - language.$(...titleParts, titleOptions)), - - html.tag('blockquote', {class: 'commentary-entry-body'}, - relations.bodyContent.slot('mode', 'multiline')), - ]); - }, -}; -- cgit 1.3.0-6-gf8a5 From 233e46c8d9099b4f6d2174e12f2b287478c54f40 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 16 Nov 2023 14:25:08 -0400 Subject: content: generateAlbumCommentaryPage: use updated commentary entries --- .../dependencies/generateAlbumCommentaryPage.js | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumCommentaryPage.js b/src/content/dependencies/generateAlbumCommentaryPage.js index e2415516..5b00acf7 100644 --- a/src/content/dependencies/generateAlbumCommentaryPage.js +++ b/src/content/dependencies/generateAlbumCommentaryPage.js @@ -7,12 +7,12 @@ export default { 'generateAlbumSidebarTrackSection', 'generateAlbumStyleRules', 'generateColorStyleVariables', + 'generateCommentaryEntry', 'generateContentHeading', 'generateTrackCoverArtwork', 'generatePageLayout', 'linkAlbum', 'linkTrack', - 'transformContent', ], extraDependencies: ['html', 'language'], @@ -38,8 +38,9 @@ export default { relation('generateAlbumCoverArtwork', album); } - relations.albumCommentaryContent = - relation('transformContent', album.commentary); + relations.albumCommentaryEntries = + album.commentary + .map(entry => relation('generateCommentaryEntry', entry)); } const tracksWithCommentary = @@ -61,9 +62,11 @@ export default { ? relation('generateTrackCoverArtwork', track) : null)); - relations.trackCommentaryContent = + relations.trackCommentaryEntries = tracksWithCommentary - .map(track => relation('transformContent', track.commentary)); + .map(track => + track.commentary + .map(entry => relation('generateCommentaryEntry', entry))); relations.trackCommentaryColorVariables = tracksWithCommentary @@ -163,10 +166,10 @@ export default { link: relations.trackCommentaryLinks, directory: data.trackCommentaryDirectories, cover: relations.trackCommentaryCovers, - content: relations.trackCommentaryContent, + entries: relations.trackCommentaryEntries, colorVariables: relations.trackCommentaryColorVariables, color: data.trackCommentaryColors, - }).map(({heading, link, directory, cover, content, colorVariables, color}) => [ + }).map(({heading, link, directory, cover, entries, colorVariables, color}) => [ heading.slots({ tag: 'h3', id: directory, @@ -175,11 +178,7 @@ export default { cover?.slots({mode: 'commentary'}), - html.tag('blockquote', - (color - ? {style: colorVariables.slot('color', color).content} - : {}), - content), + entries, ]), ], -- cgit 1.3.0-6-gf8a5 From 7a5b4465069d594a90c8e783e646a3248408ddaf Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 16 Nov 2023 14:25:37 -0400 Subject: content: generateCommentaryEntry: add color slot --- .../dependencies/generateAlbumCommentaryPage.js | 13 ++--------- .../dependencies/generateCommentaryEntry.js | 27 ++++++++++++++++++---- 2 files changed, 25 insertions(+), 15 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumCommentaryPage.js b/src/content/dependencies/generateAlbumCommentaryPage.js index 5b00acf7..001003ae 100644 --- a/src/content/dependencies/generateAlbumCommentaryPage.js +++ b/src/content/dependencies/generateAlbumCommentaryPage.js @@ -6,7 +6,6 @@ export default { 'generateAlbumNavAccent', 'generateAlbumSidebarTrackSection', 'generateAlbumStyleRules', - 'generateColorStyleVariables', 'generateCommentaryEntry', 'generateContentHeading', 'generateTrackCoverArtwork', @@ -68,13 +67,6 @@ export default { track.commentary .map(entry => relation('generateCommentaryEntry', entry))); - relations.trackCommentaryColorVariables = - tracksWithCommentary - .map(track => - (track.color === album.color - ? null - : relation('generateColorStyleVariables'))); - relations.sidebarAlbumLink = relation('linkAlbum', album); @@ -167,9 +159,8 @@ export default { directory: data.trackCommentaryDirectories, cover: relations.trackCommentaryCovers, entries: relations.trackCommentaryEntries, - colorVariables: relations.trackCommentaryColorVariables, color: data.trackCommentaryColors, - }).map(({heading, link, directory, cover, entries, colorVariables, color}) => [ + }).map(({heading, link, directory, cover, entries, color}) => [ heading.slots({ tag: 'h3', id: directory, @@ -178,7 +169,7 @@ export default { cover?.slots({mode: 'commentary'}), - entries, + entries.map(entry => entry.slot('color', color)), ]), ], diff --git a/src/content/dependencies/generateCommentaryEntry.js b/src/content/dependencies/generateCommentaryEntry.js index 22e8fd1e..72e30657 100644 --- a/src/content/dependencies/generateCommentaryEntry.js +++ b/src/content/dependencies/generateCommentaryEntry.js @@ -1,5 +1,10 @@ export default { - contentDependencies: ['linkArtist', 'transformContent'], + contentDependencies: [ + 'generateColorStyleVariables', + 'linkArtist', + 'transformContent', + ], + extraDependencies: ['html', 'language'], relations: (relation, entry) => ({ @@ -22,13 +27,20 @@ export default { (entry.body ? relation('transformContent', entry.body) : null), + + colorVariables: + relation('generateColorStyleVariables'), }), data: (entry) => ({ date: entry.date, }), - generate(data, relations, {html, language}) { + slots: { + color: {validate: v => v.isColor}, + }, + + generate(data, relations, slots, {html, language}) { const artistsSpan = html.tag('span', {class: 'commentary-entry-artists'}, (relations.artistsContent @@ -66,11 +78,18 @@ export default { titleOptions.accent = accent; } + const style = + (slots.color + ? relations.colorVariables + .slot('color', slots.color) + .content + : null); + return html.tags([ - html.tag('p', {class: 'commentary-entry-heading'}, + html.tag('p', {class: 'commentary-entry-heading', style}, language.$(...titleParts, titleOptions)), - html.tag('blockquote', {class: 'commentary-entry-body'}, + html.tag('blockquote', {class: 'commentary-entry-body', style}, relations.bodyContent.slot('mode', 'multiline')), ]); }, -- cgit 1.3.0-6-gf8a5 From c9c8ccfbeb6a013131dee429da0f12192364a8d0 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 16 Nov 2023 14:27:15 -0400 Subject: content: generateCommentaryEntry: add missing noArtists string --- src/content/dependencies/generateCommentaryEntry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateCommentaryEntry.js b/src/content/dependencies/generateCommentaryEntry.js index 72e30657..b265ed41 100644 --- a/src/content/dependencies/generateCommentaryEntry.js +++ b/src/content/dependencies/generateCommentaryEntry.js @@ -47,7 +47,7 @@ export default { ? relations.artistsContent.slot('mode', 'inline') : relations.artistLink ? relations.artistLink - : language.$('misc.artistCommentary.noArtist'))); + : language.$('misc.artistCommentary.entry.title.noArtists'))); const accentParts = ['misc.artistCommentary.entry.title.accent']; const accentOptions = {}; -- cgit 1.3.0-6-gf8a5 From 2834bc41d1f141402f14a64f0c513997f43c4dc4 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 7 Nov 2023 20:30:26 -0400 Subject: content: linkExternal: add tab: 'separate' slot --- src/content/dependencies/linkExternal.js | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/content') diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js index 5de612e2..4a0959c0 100644 --- a/src/content/dependencies/linkExternal.js +++ b/src/content/dependencies/linkExternal.js @@ -24,6 +24,11 @@ export default { validate: v => v.is('generic', 'album', 'flash'), default: 'generic', }, + + tab: { + validate: v => v.is('default', 'separate'), + default: 'default', + }, }, generate(data, slots, {html, language}) { @@ -53,6 +58,10 @@ export default { { href: data.url, class: 'nowrap', + target: + (slots.tab === 'separate' + ? '_blank' + : null), }, // truly unhinged indentation here -- cgit 1.3.0-6-gf8a5 From 0936a1d377f45dbfcfe28ff0fd735b6faeb66cbf Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 7 Nov 2023 20:33:02 -0400 Subject: content: image: support specifying color on image --- src/content/dependencies/image.js | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/image.js b/src/content/dependencies/image.js index 8aa9753b..3c78abe3 100644 --- a/src/content/dependencies/image.js +++ b/src/content/dependencies/image.js @@ -14,6 +14,12 @@ export default { 'to', ], + contentDependencies: ['generateColorStyleVariables'], + + relations: (relation) => ({ + colorVariables: relation('generateColorStyleVariables'), + }), + data(artTags) { const data = {}; @@ -43,6 +49,10 @@ export default { default: false, }, + color: { + validate: v => v.isColor, + }, + reveal: {type: 'boolean', default: true}, lazy: {type: 'boolean', default: false}, square: {type: 'boolean', default: false}, @@ -56,7 +66,7 @@ export default { missingSourceContent: {type: 'html'}, }, - generate(data, slots, { + generate(data, relations, slots, { checkIfImagePathHasCachedThumbnails, getDimensionsOfImagePath, getSizeOfImagePath, @@ -110,6 +120,12 @@ export default { !isMissingImageFile && !empty(data.contentWarnings); + const colorStyle = + slots.color && + relations.colorVariables + .slot('color', slots.color) + .content; + const willSquare = slots.square; const idOnImg = willLink ? null : slots.id; @@ -118,6 +134,9 @@ export default { const classOnImg = willLink ? null : slots.class; const classOnLink = willLink ? slots.class : null; + const styleOnContainer = willLink ? null : colorStyle; + const styleOnLink = willLink ? colorStyle : null; + if (!originalSrc || isMissingImageFile) { return prepare( html.tag('div', {class: 'image-text-area'}, @@ -191,7 +210,7 @@ export default { imgAttributes['data-no-image-preview'] = true; } - // These attributes are only relevant when a thumbnail are available *and* + // These attributes are only relevant when a thumbnail is available *and* // being used. if (hasThumbnails && slots.thumb) { if (fileSize) { @@ -238,9 +257,13 @@ export default { let wrapped = content; wrapped = - html.tag('div', {class: ['image-container', !originalSrc && 'placeholder-image']}, + html.tag('div', { + class: ['image-container', !originalSrc && 'placeholder-image'], + style: styleOnContainer, + }, [ html.tag('div', {class: 'image-inner-area'}, - wrapped)); + wrapped), + ]); if (willReveal) { wrapped = @@ -270,6 +293,7 @@ export default { wrapped = html.tag('a', { id: idOnLink, + class: [ 'box', 'image-link', @@ -277,6 +301,8 @@ export default { classOnLink, ], + style: styleOnLink, + href: (typeof slots.link === 'string' ? slots.link -- cgit 1.3.0-6-gf8a5 From a328c845c0e8c89a9ca39a33c18016a1a88e023b Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 7 Nov 2023 20:33:37 -0400 Subject: content: generateAlbumCommentaryPage: track listening links --- .../dependencies/generateAlbumCommentaryPage.js | 32 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumCommentaryPage.js b/src/content/dependencies/generateAlbumCommentaryPage.js index 001003ae..3e97c379 100644 --- a/src/content/dependencies/generateAlbumCommentaryPage.js +++ b/src/content/dependencies/generateAlbumCommentaryPage.js @@ -11,6 +11,7 @@ export default { 'generateTrackCoverArtwork', 'generatePageLayout', 'linkAlbum', + 'linkExternal', 'linkTrack', ], @@ -54,6 +55,11 @@ export default { tracksWithCommentary .map(track => relation('linkTrack', track)); + relations.trackCommentaryListeningLinks = + tracksWithCommentary + .map(track => + track.urls.map(url => relation('linkExternal', url))); + relations.trackCommentaryCovers = tracksWithCommentary .map(track => @@ -156,15 +162,37 @@ export default { stitchArrays({ heading: relations.trackCommentaryHeadings, link: relations.trackCommentaryLinks, + listeningLinks: relations.trackCommentaryListeningLinks, directory: data.trackCommentaryDirectories, cover: relations.trackCommentaryCovers, entries: relations.trackCommentaryEntries, color: data.trackCommentaryColors, - }).map(({heading, link, directory, cover, entries, color}) => [ + }).map(({ + heading, + link, + listeningLinks, + directory, + cover, + entries, + color, + }) => [ heading.slots({ tag: 'h3', id: directory, - title: link, + color, + + title: + language.$('albumCommentaryPage.entry.title.trackCommentary', { + track: link, + }), + + accent: + language.$('albumCommentaryPage.entry.title.trackCommentary.accent', { + listeningLinks: + language.formatUnitList( + listeningLinks.map(link => + link.slot('tab', 'separate'))), + }), }), cover?.slots({mode: 'commentary'}), -- cgit 1.3.0-6-gf8a5 From 8e0a343d1ff83aa67083f5a67a9bd199f3f6ad9c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 7 Nov 2023 20:34:27 -0400 Subject: content: generate{Album,Track}CoverArtwork: provide thing color --- .../dependencies/generateAlbumCoverArtwork.js | 20 ++++++++++---- src/content/dependencies/generateCoverArtwork.js | 7 +++++ .../dependencies/generateTrackCoverArtwork.js | 32 ++++++++++++++-------- 3 files changed, 42 insertions(+), 17 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumCoverArtwork.js b/src/content/dependencies/generateAlbumCoverArtwork.js index cbec930e..ce8cde21 100644 --- a/src/content/dependencies/generateAlbumCoverArtwork.js +++ b/src/content/dependencies/generateAlbumCoverArtwork.js @@ -1,12 +1,22 @@ export default { contentDependencies: ['generateCoverArtwork'], - relations: (relation, album) => - ({coverArtwork: relation('generateCoverArtwork', album.artTags)}), + relations: (relation, album) => ({ + coverArtwork: + relation('generateCoverArtwork', album.artTags), + }), - data: (album) => - ({path: ['media.albumCover', album.directory, album.coverArtFileExtension]}), + data: (album) => ({ + path: + ['media.albumCover', album.directory, album.coverArtFileExtension], + + color: + album.color, + }), generate: (data, relations) => - relations.coverArtwork.slot('path', data.path), + relations.coverArtwork.slots({ + path: data.path, + color: data.color, + }), }; diff --git a/src/content/dependencies/generateCoverArtwork.js b/src/content/dependencies/generateCoverArtwork.js index aeba97de..e43963fb 100644 --- a/src/content/dependencies/generateCoverArtwork.js +++ b/src/content/dependencies/generateCoverArtwork.js @@ -31,6 +31,10 @@ export default { type: 'string', }, + color: { + validate: v => v.isColor, + }, + mode: { validate: v => v.is('primary', 'thumbnail', 'commentary'), default: 'primary', @@ -45,6 +49,7 @@ export default { .slots({ path: slots.path, alt: slots.alt, + color: slots.color, thumb: 'medium', id: 'cover-art', reveal: true, @@ -67,6 +72,7 @@ export default { .slots({ path: slots.path, alt: slots.alt, + color: slots.color, thumb: 'small', reveal: false, link: false, @@ -78,6 +84,7 @@ export default { .slots({ path: slots.path, alt: slots.alt, + color: slots.color, thumb: 'medium', class: 'commentary-art', reveal: true, diff --git a/src/content/dependencies/generateTrackCoverArtwork.js b/src/content/dependencies/generateTrackCoverArtwork.js index ec0488e2..6c056c9a 100644 --- a/src/content/dependencies/generateTrackCoverArtwork.js +++ b/src/content/dependencies/generateTrackCoverArtwork.js @@ -1,20 +1,28 @@ export default { contentDependencies: ['generateCoverArtwork'], - relations: (relation, track) => - ({coverArtwork: - relation('generateCoverArtwork', - (track.hasUniqueCoverArt - ? track.artTags - : track.album.artTags))}), - - data: (track) => - ({path: + relations: (relation, track) => ({ + coverArtwork: + relation('generateCoverArtwork', (track.hasUniqueCoverArt - ? ['media.trackCover', track.album.directory, track.directory, track.coverArtFileExtension] - : ['media.albumCover', track.album.directory, track.album.coverArtFileExtension])}), + ? track.artTags + : track.album.artTags)), + }), + + data: (track) => ({ + path: + (track.hasUniqueCoverArt + ? ['media.trackCover', track.album.directory, track.directory, track.coverArtFileExtension] + : ['media.albumCover', track.album.directory, track.album.coverArtFileExtension]), + + color: + track.color, + }), generate: (data, relations) => - relations.coverArtwork.slot('path', data.path), + relations.coverArtwork.slots({ + path: data.path, + color: data.color, + }), }; -- cgit 1.3.0-6-gf8a5 From 173ea7144c42e799dc08e1ba4e2a09410223840e Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 7 Nov 2023 20:47:22 -0400 Subject: content: linkTrackDynamically --- src/content/dependencies/linkTrackDynamically.js | 34 ++++++++++++++++++++++++ src/content/dependencies/transformContent.js | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/content/dependencies/linkTrackDynamically.js (limited to 'src/content') diff --git a/src/content/dependencies/linkTrackDynamically.js b/src/content/dependencies/linkTrackDynamically.js new file mode 100644 index 00000000..242cd4cb --- /dev/null +++ b/src/content/dependencies/linkTrackDynamically.js @@ -0,0 +1,34 @@ +export default { + contentDependencies: ['linkTrack'], + extraDependencies: ['pagePath'], + + relations: (relation, track) => ({ + infoLink: relation('linkTrack', track), + }), + + data: (track) => ({ + trackDirectory: + track.directory, + + albumDirectory: + track.album.directory, + + trackHasCommentary: + !!track.commentary, + }), + + generate(data, relations, {pagePath}) { + if ( + pagePath[0] === 'albumCommentary' && + pagePath[1] === data.albumDirectory && + data.trackHasCommentary + ) { + relations.infoLink.setSlots({ + anchor: true, + hash: data.trackDirectory, + }); + } + + return relations.infoLink; + }, +}; diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js index 3c2c3521..a60206c9 100644 --- a/src/content/dependencies/transformContent.js +++ b/src/content/dependencies/transformContent.js @@ -130,7 +130,7 @@ const linkThingRelationMap = { newsEntry: 'linkNewsEntry', staticPage: 'linkStaticPage', tag: 'linkArtTag', - track: 'linkTrack', + track: 'linkTrackDynamically', }; const linkValueRelationMap = { -- cgit 1.3.0-6-gf8a5 From 5c46ac058d7a09b6d129d612e6ea9d72df5d77cd Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 7 Nov 2023 21:17:02 -0400 Subject: content, css: generateAlbumCommentaryPage: album listening links, etc --- .../dependencies/generateAlbumCommentaryPage.js | 48 +++++++++++++++++----- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumCommentaryPage.js b/src/content/dependencies/generateAlbumCommentaryPage.js index 3e97c379..442d72a7 100644 --- a/src/content/dependencies/generateAlbumCommentaryPage.js +++ b/src/content/dependencies/generateAlbumCommentaryPage.js @@ -1,4 +1,4 @@ -import {stitchArrays} from '#sugar'; +import {empty, stitchArrays} from '#sugar'; export default { contentDependencies: [ @@ -33,6 +33,15 @@ export default { relation('generateAlbumNavAccent', album, null); if (album.commentary) { + relations.albumCommentaryHeading = + relation('generateContentHeading'); + + relations.albumCommentaryLink = + relation('linkAlbum', album); + + relations.albumCommentaryListeningLinks = + album.urls.map(url => relation('linkExternal', url)); + if (album.hasCoverArt) { relations.albumCommentaryCover = relation('generateAlbumCoverArtwork', album); @@ -148,9 +157,27 @@ export default { })), relations.albumCommentaryContent && [ - html.tag('h3', - {class: ['content-heading']}, - language.$('albumCommentaryPage.entry.title.albumCommentary')), + relations.albumCommentaryHeading.slots({ + tag: 'h3', + color: data.color, + + title: + language.$('albumCommentaryPage.entry.title.albumCommentary', { + album: relations.albumCommentaryLink, + }), + + accent: + !empty(relations.albumCommentaryListeningLinks) && + language.$('albumCommentaryPage.entry.title.albumCommentary.accent', { + listeningLinks: + language.formatUnitList( + relations.albumCommentaryListeningLinks + .map(link => link.slots({ + mode: 'album', + tab: 'separate', + }))), + }), + }), relations.albumCommentaryCover ?.slots({mode: 'commentary'}), @@ -187,12 +214,13 @@ export default { }), accent: - language.$('albumCommentaryPage.entry.title.trackCommentary.accent', { - listeningLinks: - language.formatUnitList( - listeningLinks.map(link => - link.slot('tab', 'separate'))), - }), + !empty(listeningLinks) && + language.$('albumCommentaryPage.entry.title.trackCommentary.accent', { + listeningLinks: + language.formatUnitList( + listeningLinks.map(link => + link.slot('tab', 'separate'))), + }), }), cover?.slots({mode: 'commentary'}), -- cgit 1.3.0-6-gf8a5 From 69385cc2ca5d4a7691d6cb3726de5741de153a7c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 9 Nov 2023 17:36:46 -0400 Subject: content, client: generateContentHeading: expose main title directly --- src/content/dependencies/generateContentHeading.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateContentHeading.js b/src/content/dependencies/generateContentHeading.js index 56f68cb3..0343409c 100644 --- a/src/content/dependencies/generateContentHeading.js +++ b/src/content/dependencies/generateContentHeading.js @@ -29,7 +29,9 @@ export default { .slot('color', slots.color) .content, }, [ - slots.title, + html.tag('span', + {[html.onlyIfContent]: true, class: 'content-heading-main-title'}, + slots.title), html.tag('span', {[html.onlyIfContent]: true, class: 'content-heading-accent'}, -- cgit 1.3.0-6-gf8a5 From fbcfb88ea407ab76d278c28f1f0711502ab2fbf9 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 16 Nov 2023 17:38:17 -0400 Subject: content, css: quick visual fixes for commentary entries --- src/content/dependencies/transformContent.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js index 3c2c3521..dab89630 100644 --- a/src/content/dependencies/transformContent.js +++ b/src/content/dependencies/transformContent.js @@ -450,7 +450,9 @@ export default { // In inline mode, no further processing is needed! if (slots.mode === 'inline') { - return html.tags(contentFromNodes.map(node => node.data)); + return html.tags( + contentFromNodes.map(node => node.data), + {[html.joinChildren]: ''}); } // Multiline mode has a secondary processing stage where it's passed... -- cgit 1.3.0-6-gf8a5 From a34b8d027866fbe858a4d2ff3543bc84c9d5983a Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 17 Nov 2023 06:53:34 -0400 Subject: data, yaml, content: support multiple artists per commentary entry --- src/content/dependencies/generateCommentaryEntry.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateCommentaryEntry.js b/src/content/dependencies/generateCommentaryEntry.js index b265ed41..0b2b2558 100644 --- a/src/content/dependencies/generateCommentaryEntry.js +++ b/src/content/dependencies/generateCommentaryEntry.js @@ -1,3 +1,5 @@ +import {empty} from '#sugar'; + export default { contentDependencies: [ 'generateColorStyleVariables', @@ -8,9 +10,10 @@ export default { extraDependencies: ['html', 'language'], relations: (relation, entry) => ({ - artistLink: - (entry.artist && !entry.artistDisplayText - ? relation('linkArtist', entry.artist) + artistLinks: + (!empty(entry.artists) && !entry.artistDisplayText + ? entry.artists + .map(artist => relation('linkArtist', artist)) : null), artistsContent: @@ -45,8 +48,8 @@ export default { html.tag('span', {class: 'commentary-entry-artists'}, (relations.artistsContent ? relations.artistsContent.slot('mode', 'inline') - : relations.artistLink - ? relations.artistLink + : relations.artistLinks + ? language.formatConjunctionList(relations.artistLinks) : language.$('misc.artistCommentary.entry.title.noArtists'))); const accentParts = ['misc.artistCommentary.entry.title.accent']; -- cgit 1.3.0-6-gf8a5 From 7da15227b8623a2fcef28c4f7988a2f89e5ab8b3 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sat, 18 Nov 2023 19:22:08 -0400 Subject: content: transformContent: use marked for inline + own instances There's obviously lots of room to do more here, but this is a simple way to get typical inline contents passing through marked. --- src/content/dependencies/transformContent.js | 57 +++++++++++++++++++--------- 1 file changed, 39 insertions(+), 18 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js index dab89630..7b2d0573 100644 --- a/src/content/dependencies/transformContent.js +++ b/src/content/dependencies/transformContent.js @@ -1,7 +1,7 @@ import {bindFind} from '#find'; import {parseInput} from '#replacer'; -import {marked} from 'marked'; +import {Marked} from 'marked'; export const replacerSpec = { album: { @@ -147,6 +147,29 @@ const linkIndexRelationMap = { newsIndex: 'linkNewsIndex', }; +const commonMarkedOptions = { + headerIds: false, + mangle: false, +}; + +const multilineMarked = new Marked({ + ...commonMarkedOptions, +}); + +const inlineMarked = new Marked({ + ...commonMarkedOptions, + + renderer: { + paragraph(text) { + return text; + }, + }, +}); + +const lyricsMarked = new Marked({ + ...commonMarkedOptions, +}); + function getPlaceholder(node, content) { return {type: 'text', data: content.slice(node.i, node.iEnd)}; } @@ -447,21 +470,9 @@ export default { return link.data; } - // In inline mode, no further processing is needed! - - if (slots.mode === 'inline') { - return html.tags( - contentFromNodes.map(node => node.data), - {[html.joinChildren]: ''}); - } - - // Multiline mode has a secondary processing stage where it's passed... - // through marked! Rolling your own Markdown only gets you so far :D - - const markedOptions = { - headerIds: false, - mangle: false, - }; + // Content always goes through marked (i.e. parsing as Markdown). + // This does require some attention to detail, mostly to do with line + // breaks (in multiline mode) and extracting/re-inserting non-text nodes. // The content of non-text nodes can end up getting mangled by marked. // To avoid this, we replace them with mundane placeholders, then @@ -536,6 +547,16 @@ export default { return html.tags(tags, {[html.joinChildren]: ''}); }; + if (slots.mode === 'inline') { + const markedInput = + extractNonTextNodes(); + + const markedOutput = + inlineMarked.parse(markedInput); + + return reinsertNonTextNodes(markedOutput); + } + // This is separated into its own function just since we're gonna reuse // it in a minute if everything goes to heck in lyrics mode. const transformMultiline = () => { @@ -552,7 +573,7 @@ export default { .replace(/(?<=^>.*)\n+(?!^>)/gm, '\n\n'); const markedOutput = - marked.parse(markedInput, markedOptions); + multilineMarked.parse(markedInput); return reinsertNonTextNodes(markedOutput); } @@ -602,7 +623,7 @@ export default { }); const markedOutput = - marked.parse(markedInput, markedOptions); + lyricsMarked.parse(markedInput); return reinsertNonTextNodes(markedOutput); } -- cgit 1.3.0-6-gf8a5 From bad238355e19c4fef5e5f3b41df88fa9b1b84aaa Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 21 Nov 2023 07:31:45 -0400 Subject: content, client, css: generateAdditionalNamesBox --- .../dependencies/generateAdditionalNamesBox.js | 48 ++++++++++++++++++++++ src/content/dependencies/generatePageLayout.js | 38 +++++++++-------- src/content/dependencies/generateTrackInfoPage.js | 8 ++++ 3 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 src/content/dependencies/generateAdditionalNamesBox.js (limited to 'src/content') diff --git a/src/content/dependencies/generateAdditionalNamesBox.js b/src/content/dependencies/generateAdditionalNamesBox.js new file mode 100644 index 00000000..f7fa3b00 --- /dev/null +++ b/src/content/dependencies/generateAdditionalNamesBox.js @@ -0,0 +1,48 @@ +import {stitchArrays} from '#sugar'; + +export default { + contentDependencies: ['transformContent'], + extraDependencies: ['html', 'language'], + + relations: (relation, additionalNames) => ({ + names: + additionalNames.map(({name}) => + relation('transformContent', name)), + + annotations: + additionalNames.map(({annotation}) => + (annotation + ? relation('transformContent', annotation) + : null)), + }), + + generate: (relations, {html, language}) => { + const names = + relations.names.map(name => + html.tag('span', {class: 'additional-name'}, + name.slot('mode', 'inline'))); + + const annotations = + relations.annotations.map(annotation => + (annotation + ? html.tag('span', {class: 'annotation'}, + language.$('misc.additionalNames.item.annotation', { + annotation: + annotation.slot('mode', 'inline'), + })) + : null)); + + return html.tag('div', {id: 'additional-names-box'}, [ + html.tag('p', + language.$('misc.additionalNames.title')), + + html.tag('ul', + stitchArrays({name: names, annotation: annotations}) + .map(({name, annotation}) => + html.tag('li', + (annotation + ? language.$('misc.additionalNames.item.withAnnotation', {name, annotation}) + : language.$('misc.additionalNames.item', {name}))))), + ]); + }, +}; diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js index 95551f3e..7dee8cc3 100644 --- a/src/content/dependencies/generatePageLayout.js +++ b/src/content/dependencies/generatePageLayout.js @@ -108,6 +108,8 @@ export default { title: {type: 'html'}, showWikiNameInTitle: {type: 'boolean', default: true}, + additionalNames: {type: 'html'}, + cover: {type: 'html'}, socialEmbed: {type: 'html'}, @@ -222,22 +224,25 @@ export default { const colors = getColors(slots.color ?? data.wikiColor); const hasSocialEmbed = !html.isBlank(slots.socialEmbed); - let titleHTML = null; - - if (!html.isBlank(slots.title)) { - switch (slots.headingMode) { - case 'sticky': - titleHTML = - relations.stickyHeadingContainer.slots({ - title: slots.title, - cover: slots.cover, - }); - break; - case 'static': - titleHTML = html.tag('h1', slots.title); - break; - } - } + const titleContentsHTML = + (html.isBlank(slots.title) + ? null + : html.isBlank(slots.additionalNames) + ? language.sanitize(slots.title) + : html.tag('a', { + href: '#additional-names-box', + title: language.$('misc.additionalNames.tooltip').toString(), + }, language.sanitize(slots.title))); + + const titleHTML = + (html.isBlank(slots.title) + ? null + : slots.headingMode === 'sticky' + ? relations.stickyHeadingContainer.slots({ + title: titleContentsHTML, + cover: slots.cover, + }) + : html.tag('h1', titleContentsHTML)); let footerContent = slots.footerContent; @@ -254,6 +259,7 @@ export default { titleHTML, slots.cover, + slots.additionalNames, html.tag('div', { diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js index 93334948..180e5c29 100644 --- a/src/content/dependencies/generateTrackInfoPage.js +++ b/src/content/dependencies/generateTrackInfoPage.js @@ -6,6 +6,7 @@ import getChronologyRelations from '../util/getChronologyRelations.js'; export default { contentDependencies: [ 'generateAdditionalFilesShortcut', + 'generateAdditionalNamesBox', 'generateAlbumAdditionalFilesList', 'generateAlbumNavAccent', 'generateAlbumSidebar', @@ -106,6 +107,11 @@ export default { list: relation('generateAlbumAdditionalFilesList', album, additionalFiles), }); + if (!empty(track.additionalNames)) { + relations.additionalNamesBox = + relation('generateAdditionalNamesBox', track.additionalNames); + } + if (track.hasUniqueCoverArt || album.hasCoverArt) { relations.cover = relation('generateTrackCoverArtwork', track); @@ -300,6 +306,8 @@ export default { title: language.$('trackPage.title', {track: data.name}), headingMode: 'sticky', + additionalNames: relations.additionalNamesBox ?? null, + color: data.color, styleRules: [relations.albumStyleRules], -- cgit 1.3.0-6-gf8a5 From c11edada828dc734cce6988e5819630a73326085 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 21 Jul 2023 20:06:32 -0300 Subject: content, test: linkContribution: tooltip icons --- .../generateReleaseInfoContributionsLine.js | 1 + src/content/dependencies/linkContribution.js | 79 ++++++++++++++++------ 2 files changed, 61 insertions(+), 19 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateReleaseInfoContributionsLine.js b/src/content/dependencies/generateReleaseInfoContributionsLine.js index 1fa8dcca..2e6c4709 100644 --- a/src/content/dependencies/generateReleaseInfoContributionsLine.js +++ b/src/content/dependencies/generateReleaseInfoContributionsLine.js @@ -35,6 +35,7 @@ export default { link.slots({ showContribution: slots.showContribution, showIcons: slots.showIcons, + iconMode: 'tooltip', }))), }); }, diff --git a/src/content/dependencies/linkContribution.js b/src/content/dependencies/linkContribution.js index 8e42f247..5bc398de 100644 --- a/src/content/dependencies/linkContribution.js +++ b/src/content/dependencies/linkContribution.js @@ -20,7 +20,6 @@ export default { if (!empty(contribution.who.urls)) { relations.artistIcons = contribution.who.urls - .slice(0, 4) .map(url => relation('linkExternalAsIcon', url)); } @@ -37,37 +36,79 @@ export default { showContribution: {type: 'boolean', default: false}, showIcons: {type: 'boolean', default: false}, preventWrapping: {type: 'boolean', default: true}, + + iconMode: { + validate: v => v.is('inline', 'tooltip'), + default: 'inline' + }, }, generate(data, relations, slots, {html, language}) { - const hasContributionPart = !!(slots.showContribution && data.what); - const hasExternalPart = !!(slots.showIcons && relations.artistIcons); - - const externalLinks = hasExternalPart && - html.tag('span', - {[html.noEdgeWhitespace]: true, class: 'icons'}, - language.formatUnitList(relations.artistIcons)); + const hasContribution = !!(slots.showContribution && data.what); + const hasExternalIcons = !!(slots.showIcons && relations.artistIcons); const parts = ['misc.artistLink']; const options = {artist: relations.artistLink}; - if (hasContributionPart) { + if (hasContribution) { parts.push('withContribution'); options.contrib = data.what; } - if (hasExternalPart) { + if (hasExternalIcons && slots.iconMode === 'inline') { parts.push('withExternalLinks'); - options.links = externalLinks; + options.links = + html.tag('span', + { + [html.noEdgeWhitespace]: true, + class: ['icons', 'icons-inline'], + }, + language.formatUnitList( + relations.artistIcons + .slice(0, 4))); } - const content = language.formatString(parts.join('.'), options); + let content = language.formatString(parts.join('.'), options); - return ( - (parts.length > 1 && slots.preventWrapping - ? html.tag('span', - {[html.noEdgeWhitespace]: true, class: 'nowrap'}, - content) - : content)); - }, + if (hasExternalIcons && slots.iconMode === 'tooltip') { + content = [ + content, + html.tag('span', + { + [html.noEdgeWhitespace]: true, + class: ['icons', 'icons-tooltip'], + inert: true, + }, + html.tag('span', + { + [html.noEdgeWhitespace]: true, + [html.joinChildren]: '', + class: 'icons-tooltip-content', + }, + relations.artistIcons)), + ]; + } + + if (hasContribution || hasExternalIcons) { + content = + html.tag('span', { + [html.noEdgeWhitespace]: true, + [html.joinChildren]: '', + + class: [ + 'contribution', + + hasExternalIcons && + slots.iconMode === 'tooltip' && + 'has-tooltip', + + parts.length > 1 && + slots.preventWrapping && + 'nowrap', + ], + }, content); + } + + return content; + } }; -- cgit 1.3.0-6-gf8a5 From a1d50400b858e40471bc1bb78408d69d39907c5f Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 14 Nov 2023 20:05:48 -0400 Subject: content: generateContributionList: use tooltip style contrib icons --- src/content/dependencies/generateContributionList.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/content') diff --git a/src/content/dependencies/generateContributionList.js b/src/content/dependencies/generateContributionList.js index 731cfba5..6401e65e 100644 --- a/src/content/dependencies/generateContributionList.js +++ b/src/content/dependencies/generateContributionList.js @@ -16,5 +16,6 @@ export default { showIcons: true, showContribution: true, preventWrapping: false, + iconMode: 'tooltip', })))), }; -- cgit 1.3.0-6-gf8a5 From 0202375db8ccd03d98ed6c2ffbb800b67c026639 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 23 Nov 2023 09:16:23 -0400 Subject: content, css: vertical tooltips + basic external parsing --- src/content/dependencies/linkContribution.js | 14 +- src/content/dependencies/linkExternalAsIcon.js | 265 +++++++++++++++++++++---- 2 files changed, 235 insertions(+), 44 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/linkContribution.js b/src/content/dependencies/linkContribution.js index 5bc398de..ef61c766 100644 --- a/src/content/dependencies/linkContribution.js +++ b/src/content/dependencies/linkContribution.js @@ -1,15 +1,8 @@ import {empty} from '#sugar'; export default { - contentDependencies: [ - 'linkArtist', - 'linkExternalAsIcon', - ], - - extraDependencies: [ - 'html', - 'language', - ], + contentDependencies: ['linkArtist', 'linkExternalAsIcon'], + extraDependencies: ['html', 'language'], relations(relation, contribution) { const relations = {}; @@ -85,7 +78,8 @@ export default { [html.joinChildren]: '', class: 'icons-tooltip-content', }, - relations.artistIcons)), + relations.artistIcons + .map(icon => icon.slot('withText', true)))), ]; } diff --git a/src/content/dependencies/linkExternalAsIcon.js b/src/content/dependencies/linkExternalAsIcon.js index cd168992..d3ed9122 100644 --- a/src/content/dependencies/linkExternalAsIcon.js +++ b/src/content/dependencies/linkExternalAsIcon.js @@ -1,6 +1,202 @@ -// TODO: Define these as extra dependencies and pass them somewhere -const BANDCAMP_DOMAINS = ['bc.s3m.us', 'music.solatrux.com']; -const MASTODON_DOMAINS = ['types.pl']; +import {stitchArrays} from '#sugar'; + +const fallbackDescriptor = { + icon: 'globe', + string: 'external', + + normal: 'domain', + compact: 'domain', +}; + +// TODO: Define all this stuff in data! +const externalSpec = [ + { + matchDomain: 'bandcamp.com', + + icon: 'bandcamp', + string: 'bandcamp', + + compact: 'handle', + + handle: {domain: /^[^.]*/}, + }, + + { + matchDomains: ['bc.s3m.us', 'music.solatrux.com'], + + icon: 'bandcamp', + string: 'bandcamp', + + normal: 'domain', + compact: 'domain', + }, + + { + matchDomains: ['types.pl'], + + icon: 'mastodon', + string: 'mastodon', + + compact: 'domain', + }, + + { + matchDomains: ['youtube.com', 'youtu.be'], + + icon: 'youtube', + string: 'youtube', + + compact: 'handle', + + handle: { + pathname: /^(@.*?)\/?$/, + }, + }, + + { + matchDomain: 'soundcloud.com', + + icon: 'soundcloud', + string: 'soundcloud', + + compact: 'handle', + + handle: /[^/]*\/?$/, + }, + + { + matchDomain: 'tumblr.com', + + icon: 'tumblr', + string: 'tumblr', + + compact: 'handle', + + handle: {domain: /^[^.]*/}, + }, + + { + matchDomain: 'twitter.com', + + icon: 'twitter', + string: 'twitter', + + compact: 'handle', + + handle: { + prefix: '@', + pathname: /^@?.*\/?$/, + }, + }, + + { + matchDomain: 'deviantart.com', + + icon: 'deviantart', + string: 'deviantart', + }, + + { + matchDomain: 'instagram.com', + + icon: 'instagram', + string: 'instagram', + }, + + { + matchDomain: 'newgrounds.com', + + icon: 'newgrounds', + string: 'newgrounds', + }, +]; + +function determineLinkText(url, descriptor, {language}) { + const prefix = 'misc.external'; + + const { + hostname: domain, + pathname, + } = new URL(url); + + let normal = null; + let compact = null; + + const place = language.$(prefix, descriptor.string); + + if (descriptor.normal === 'domain') { + normal = language.$(prefix, 'withDomain', {place, domain}); + } + + if (descriptor.compact === 'domain') { + compact = domain.replace(/^www\./, ''); + } + + let handle = null; + + if (descriptor.handle) { + let regexen = []; + let tests = []; + + let handlePrefix = ''; + + if (descriptor.handle instanceof RegExp) { + regexen.push(descriptor.handle); + tests.push(url); + } else { + for (const [key, value] of Object.entries(descriptor.handle)) { + switch (key) { + case 'prefix': + handlePrefix = value; + continue; + + case 'url': + tests.push(url); + break; + + case 'domain': + case 'hostname': + tests.push(domain); + break; + + case 'path': + case 'pathname': + tests.push(pathname.slice(1)); + break; + + default: + tests.push(''); + break; + } + + regexen.push(value); + } + } + + for (const {regex, test} of stitchArrays({ + regex: regexen, + test: tests, + })) { + const match = test.match(regex); + if (match) { + handle = handlePrefix + (match[1] ?? match[0]); + break; + } + } + } + + if (descriptor.compact === 'handle') { + compact = handle; + } + + if (normal === 'handle' && handle) { + normal = language.$(prefix, 'withHandle', {place, handle}); + } + + normal ??= language.$(prefix, descriptor.string); + + return {normal, compact}; +} export default { extraDependencies: ['html', 'language', 'to'], @@ -9,38 +205,39 @@ export default { return {url}; }, - generate(data, {html, language, to}) { - const domain = new URL(data.url).hostname; - const [id, msg] = ( - domain.includes('bandcamp.com') - ? ['bandcamp', language.$('misc.external.bandcamp')] - : BANDCAMP_DOMAINS.includes(domain) - ? ['bandcamp', language.$('misc.external.bandcamp.domain', {domain})] - : MASTODON_DOMAINS.includes(domain) - ? ['mastodon', language.$('misc.external.mastodon.domain', {domain})] - : domain.includes('youtu') - ? ['youtube', language.$('misc.external.youtube')] - : domain.includes('soundcloud') - ? ['soundcloud', language.$('misc.external.soundcloud')] - : domain.includes('tumblr.com') - ? ['tumblr', language.$('misc.external.tumblr')] - : domain.includes('twitter.com') - ? ['twitter', language.$('misc.external.twitter')] - : domain.includes('deviantart.com') - ? ['deviantart', language.$('misc.external.deviantart')] - : domain.includes('instagram.com') - ? ['instagram', language.$('misc.external.bandcamp')] - : domain.includes('newgrounds.com') - ? ['newgrounds', language.$('misc.external.newgrounds')] - : ['globe', language.$('misc.external.domain', {domain})]); + slots: { + withText: {type: 'boolean'}, + }, + + generate(data, slots, {html, language, to}) { + const {hostname: domain} = new URL(data.url); + + const descriptor = + externalSpec.find(({matchDomain, matchDomains}) => { + const compare = d => domain.includes(d); + if (matchDomain && compare(matchDomain)) return true; + if (matchDomains && matchDomains.some(compare)) return true; + return false; + }) ?? fallbackDescriptor; + + const {normal: normalText, compact: compactText} = + determineLinkText(data.url, descriptor, {language}); return html.tag('a', - {href: data.url, class: 'icon'}, - html.tag('svg', [ - html.tag('title', msg), - html.tag('use', { - href: to('shared.staticIcon', id), - }), - ])); + {href: data.url, class: ['icon', slots.withText && 'has-text']}, + [ + html.tag('svg', [ + !slots.withText && + html.tag('title', normalText), + + html.tag('use', { + href: to('shared.staticIcon', descriptor.icon), + }), + ]), + + slots.withText && + html.tag('span', {class: 'icon-text'}, + compactText ?? normalText), + ]); }, }; -- cgit 1.3.0-6-gf8a5 From 8f17782a5f2adbafd031b269195879eb7f79e05f Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 23 Nov 2023 11:16:48 -0400 Subject: data, content: extract external link parsing into nicer interface --- src/content/dependencies/linkExternalAsIcon.js | 223 +------------------------ 1 file changed, 7 insertions(+), 216 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/linkExternalAsIcon.js b/src/content/dependencies/linkExternalAsIcon.js index d3ed9122..58bd896d 100644 --- a/src/content/dependencies/linkExternalAsIcon.js +++ b/src/content/dependencies/linkExternalAsIcon.js @@ -1,237 +1,28 @@ -import {stitchArrays} from '#sugar'; - -const fallbackDescriptor = { - icon: 'globe', - string: 'external', - - normal: 'domain', - compact: 'domain', -}; - -// TODO: Define all this stuff in data! -const externalSpec = [ - { - matchDomain: 'bandcamp.com', - - icon: 'bandcamp', - string: 'bandcamp', - - compact: 'handle', - - handle: {domain: /^[^.]*/}, - }, - - { - matchDomains: ['bc.s3m.us', 'music.solatrux.com'], - - icon: 'bandcamp', - string: 'bandcamp', - - normal: 'domain', - compact: 'domain', - }, - - { - matchDomains: ['types.pl'], - - icon: 'mastodon', - string: 'mastodon', - - compact: 'domain', - }, - - { - matchDomains: ['youtube.com', 'youtu.be'], - - icon: 'youtube', - string: 'youtube', - - compact: 'handle', - - handle: { - pathname: /^(@.*?)\/?$/, - }, - }, - - { - matchDomain: 'soundcloud.com', - - icon: 'soundcloud', - string: 'soundcloud', - - compact: 'handle', - - handle: /[^/]*\/?$/, - }, - - { - matchDomain: 'tumblr.com', - - icon: 'tumblr', - string: 'tumblr', - - compact: 'handle', - - handle: {domain: /^[^.]*/}, - }, - - { - matchDomain: 'twitter.com', - - icon: 'twitter', - string: 'twitter', - - compact: 'handle', - - handle: { - prefix: '@', - pathname: /^@?.*\/?$/, - }, - }, - - { - matchDomain: 'deviantart.com', - - icon: 'deviantart', - string: 'deviantart', - }, - - { - matchDomain: 'instagram.com', - - icon: 'instagram', - string: 'instagram', - }, - - { - matchDomain: 'newgrounds.com', - - icon: 'newgrounds', - string: 'newgrounds', - }, -]; - -function determineLinkText(url, descriptor, {language}) { - const prefix = 'misc.external'; - - const { - hostname: domain, - pathname, - } = new URL(url); - - let normal = null; - let compact = null; - - const place = language.$(prefix, descriptor.string); - - if (descriptor.normal === 'domain') { - normal = language.$(prefix, 'withDomain', {place, domain}); - } - - if (descriptor.compact === 'domain') { - compact = domain.replace(/^www\./, ''); - } - - let handle = null; - - if (descriptor.handle) { - let regexen = []; - let tests = []; - - let handlePrefix = ''; - - if (descriptor.handle instanceof RegExp) { - regexen.push(descriptor.handle); - tests.push(url); - } else { - for (const [key, value] of Object.entries(descriptor.handle)) { - switch (key) { - case 'prefix': - handlePrefix = value; - continue; - - case 'url': - tests.push(url); - break; - - case 'domain': - case 'hostname': - tests.push(domain); - break; - - case 'path': - case 'pathname': - tests.push(pathname.slice(1)); - break; - - default: - tests.push(''); - break; - } - - regexen.push(value); - } - } - - for (const {regex, test} of stitchArrays({ - regex: regexen, - test: tests, - })) { - const match = test.match(regex); - if (match) { - handle = handlePrefix + (match[1] ?? match[0]); - break; - } - } - } - - if (descriptor.compact === 'handle') { - compact = handle; - } - - if (normal === 'handle' && handle) { - normal = language.$(prefix, 'withHandle', {place, handle}); - } - - normal ??= language.$(prefix, descriptor.string); - - return {normal, compact}; -} - export default { extraDependencies: ['html', 'language', 'to'], - data(url) { - return {url}; - }, + data: (url) => ({url}), slots: { withText: {type: 'boolean'}, }, generate(data, slots, {html, language, to}) { - const {hostname: domain} = new URL(data.url); - - const descriptor = - externalSpec.find(({matchDomain, matchDomains}) => { - const compare = d => domain.includes(d); - if (matchDomain && compare(matchDomain)) return true; - if (matchDomains && matchDomains.some(compare)) return true; - return false; - }) ?? fallbackDescriptor; + const {url} = data; - const {normal: normalText, compact: compactText} = - determineLinkText(data.url, descriptor, {language}); + const normalText = language.formatExternalLink(url, {style: 'normal'}); + const compactText = language.formatExternalLink(url, {style: 'compact'}); + const iconId = language.formatExternalLink(url, {style: 'icon-id'}); return html.tag('a', - {href: data.url, class: ['icon', slots.withText && 'has-text']}, + {href: url, class: ['icon', slots.withText && 'has-text']}, [ html.tag('svg', [ !slots.withText && html.tag('title', normalText), html.tag('use', { - href: to('shared.staticIcon', descriptor.icon), + href: to('shared.staticIcon', iconId), }), ]), -- cgit 1.3.0-6-gf8a5 From c5e02f9d314118a534fd0e942d87e74864674498 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 23 Nov 2023 17:42:49 -0400 Subject: content: *mostly* port linkExternal to language.formatExternalLink --- src/content/dependencies/linkExternal.js | 64 ++++---------------------------- 1 file changed, 8 insertions(+), 56 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js index 5de612e2..7f090084 100644 --- a/src/content/dependencies/linkExternal.js +++ b/src/content/dependencies/linkExternal.js @@ -1,7 +1,3 @@ -// TODO: Define these as extra dependencies and pass them somewhere -const BANDCAMP_DOMAINS = ['bc.s3m.us', 'music.solatrux.com']; -const MASTODON_DOMAINS = ['types.pl']; - export default { extraDependencies: ['html', 'language', 'wikiData'], @@ -27,6 +23,13 @@ export default { }, generate(data, slots, {html, language}) { + return ( + html.tag('a', + {href: data.url, class: 'nowrap'}, + language.formatExternalLink(data.url, {style: 'platform'}))); + }, + + /* let isLocal; let domain; let pathname; @@ -49,25 +52,6 @@ export default { isLocal = true; } - const link = html.tag('a', - { - href: data.url, - class: 'nowrap', - }, - - // truly unhinged indentation here - isLocal - ? language.$('misc.external.local') - - : domain.includes('bandcamp.com') - ? language.$('misc.external.bandcamp') - - : BANDCAMP_DOMAINS.includes(domain) - ? language.$('misc.external.bandcamp.domain', {domain}) - - : MASTODON_DOMAINS.includes(domain) - ? language.$('misc.external.mastodon.domain', {domain}) - : domain.includes('youtu') ? slots.mode === 'album' ? data.url.includes('list=') @@ -75,38 +59,6 @@ export default { : language.$('misc.external.youtube.fullAlbum') : language.$('misc.external.youtube') - : domain.includes('soundcloud') - ? language.$('misc.external.soundcloud') - - : domain.includes('tumblr.com') - ? language.$('misc.external.tumblr') - - : domain.includes('twitter.com') - ? language.$('misc.external.twitter') - - : domain.includes('deviantart.com') - ? language.$('misc.external.deviantart') - - : domain.includes('wikipedia.org') - ? language.$('misc.external.wikipedia') - - : domain.includes('poetryfoundation.org') - ? language.$('misc.external.poetryFoundation') - - : domain.includes('instagram.com') - ? language.$('misc.external.instagram') - - : domain.includes('patreon.com') - ? language.$('misc.external.patreon') - - : domain.includes('spotify.com') - ? language.$('misc.external.spotify') - - : domain.includes('newgrounds.com') - ? language.$('misc.external.newgrounds') - - : domain); - switch (slots.mode) { case 'flash': { const wrap = content => @@ -136,5 +88,5 @@ export default { default: return link; } - } + */ }; -- cgit 1.3.0-6-gf8a5 From 0ee5269cd196cd14f06aac6c586e7104159eac74 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 23 Nov 2023 17:47:18 -0400 Subject: content: implement "local" links much more rudimentarily --- src/content/dependencies/linkExternal.js | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js index 7f090084..1b81efcc 100644 --- a/src/content/dependencies/linkExternal.js +++ b/src/content/dependencies/linkExternal.js @@ -30,28 +30,6 @@ export default { }, /* - let isLocal; - let domain; - let pathname; - - try { - const url = new URL(data.url); - domain = url.hostname; - pathname = url.pathname; - } catch (error) { - // No support for relative local URLs yet, sorry! (I.e, local URLs must - // be absolute relative to the domain name in order to work.) - isLocal = true; - domain = null; - pathname = null; - } - - // isLocal also applies for URLs which match the 'Canonical Base' under - // wiki-info.yaml, if present. - if (data.canonicalDomain && domain === data.canonicalDomain) { - isLocal = true; - } - : domain.includes('youtu') ? slots.mode === 'album' ? data.url.includes('list=') -- cgit 1.3.0-6-gf8a5 From 8c69ef2b14c4719fa0cd0c7daca27c613167b7ca Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 23 Nov 2023 18:52:04 -0400 Subject: content: contextual external links --- .../dependencies/generateAlbumReleaseInfo.js | 2 +- .../dependencies/generateAlbumSidebarGroupBox.js | 5 ++++- src/content/dependencies/generateArtistInfoPage.js | 5 ++++- src/content/dependencies/generateFlashInfoPage.js | 2 +- src/content/dependencies/generateGroupInfoPage.js | 5 ++++- .../dependencies/generateTrackReleaseInfo.js | 5 ++++- src/content/dependencies/linkContribution.js | 5 +++-- src/content/dependencies/linkExternal.js | 14 +++++++++++--- src/content/dependencies/linkExternalAsIcon.js | 21 ++++++++++++++++----- src/content/dependencies/linkExternalFlash.js | 4 ++++ 10 files changed, 52 insertions(+), 16 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumReleaseInfo.js b/src/content/dependencies/generateAlbumReleaseInfo.js index d6405283..4b819091 100644 --- a/src/content/dependencies/generateAlbumReleaseInfo.js +++ b/src/content/dependencies/generateAlbumReleaseInfo.js @@ -94,7 +94,7 @@ export default { links: language.formatDisjunctionList( relations.externalLinks - .map(link => link.slot('mode', 'album'))), + .map(link => link.slot('context', 'album'))), })), ]); }, diff --git a/src/content/dependencies/generateAlbumSidebarGroupBox.js b/src/content/dependencies/generateAlbumSidebarGroupBox.js index 331ddaba..f3705450 100644 --- a/src/content/dependencies/generateAlbumSidebarGroupBox.js +++ b/src/content/dependencies/generateAlbumSidebarGroupBox.js @@ -66,7 +66,10 @@ export default { !empty(relations.externalLinks) && html.tag('p', language.$('releaseInfo.visitOn', { - links: language.formatDisjunctionList(relations.externalLinks), + links: + language.formatDisjunctionList( + relations.externalLinks + .map(link => link.slot('context', 'group'))), })), slots.mode === 'album' && diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js index 03bc0af5..ac9209a7 100644 --- a/src/content/dependencies/generateArtistInfoPage.js +++ b/src/content/dependencies/generateArtistInfoPage.js @@ -161,7 +161,10 @@ export default { sec.visit && html.tag('p', language.$('releaseInfo.visitOn', { - links: language.formatDisjunctionList(sec.visit.externalLinks), + links: + language.formatDisjunctionList( + sec.visit.externalLinks + .map(link => link.slot('context', 'artist'))), })), sec.artworks?.artistGalleryLink && diff --git a/src/content/dependencies/generateFlashInfoPage.js b/src/content/dependencies/generateFlashInfoPage.js index 09c6b37c..c60f9696 100644 --- a/src/content/dependencies/generateFlashInfoPage.js +++ b/src/content/dependencies/generateFlashInfoPage.js @@ -133,7 +133,7 @@ export default { links: language.formatDisjunctionList( relations.externalLinks - .map(link => link.slot('mode', 'flash'))), + .map(link => link.slot('context', 'flash'))), })), sec.featuredTracks && [ diff --git a/src/content/dependencies/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js index 0583755e..05df33fb 100644 --- a/src/content/dependencies/generateGroupInfoPage.js +++ b/src/content/dependencies/generateGroupInfoPage.js @@ -107,7 +107,10 @@ export default { sec.info.visitLinks && html.tag('p', language.$('releaseInfo.visitOn', { - links: language.formatDisjunctionList(sec.info.visitLinks), + links: + language.formatDisjunctionList( + sec.info.visitLinks + .map(link => link.slot('context', 'group'))), })), html.tag('blockquote', diff --git a/src/content/dependencies/generateTrackReleaseInfo.js b/src/content/dependencies/generateTrackReleaseInfo.js index 9a7478ca..c347dbce 100644 --- a/src/content/dependencies/generateTrackReleaseInfo.js +++ b/src/content/dependencies/generateTrackReleaseInfo.js @@ -77,7 +77,10 @@ export default { html.tag('p', (relations.externalLinks ? language.$('releaseInfo.listenOn', { - links: language.formatDisjunctionList(relations.externalLinks), + links: + language.formatDisjunctionList( + relations.externalLinks + .map(link => link.slot('context', 'track'))), }) : language.$('releaseInfo.listenOn.noLinks', { name: html.tag('i', data.name), diff --git a/src/content/dependencies/linkContribution.js b/src/content/dependencies/linkContribution.js index ef61c766..790afa4f 100644 --- a/src/content/dependencies/linkContribution.js +++ b/src/content/dependencies/linkContribution.js @@ -58,7 +58,8 @@ export default { }, language.formatUnitList( relations.artistIcons - .slice(0, 4))); + .slice(0, 4) + .map(icon => icon.slot('context', 'artist')))); } let content = language.formatString(parts.join('.'), options); @@ -79,7 +80,7 @@ export default { class: 'icons-tooltip-content', }, relations.artistIcons - .map(icon => icon.slot('withText', true)))), + .map(icon => icon.slots({context: 'artist', withText: true})))), ]; } diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js index 1b81efcc..e51ea89e 100644 --- a/src/content/dependencies/linkExternal.js +++ b/src/content/dependencies/linkExternal.js @@ -1,3 +1,5 @@ +import {isExternalLinkContext} from '#external-links'; + export default { extraDependencies: ['html', 'language', 'wikiData'], @@ -16,8 +18,11 @@ export default { }, slots: { - mode: { - validate: v => v.is('generic', 'album', 'flash'), + context: { + // This awkward syntax is because the slot descriptor validator can't + // differentiate between a function that returns a validator (the usual + // syntax) and a function that is itself a validator. + validate: () => isExternalLinkContext, default: 'generic', }, }, @@ -26,7 +31,10 @@ export default { return ( html.tag('a', {href: data.url, class: 'nowrap'}, - language.formatExternalLink(data.url, {style: 'platform'}))); + language.formatExternalLink(data.url, { + style: 'platform', + context: slots.context, + }))); }, /* diff --git a/src/content/dependencies/linkExternalAsIcon.js b/src/content/dependencies/linkExternalAsIcon.js index 58bd896d..357c835c 100644 --- a/src/content/dependencies/linkExternalAsIcon.js +++ b/src/content/dependencies/linkExternalAsIcon.js @@ -1,21 +1,32 @@ +import {isExternalLinkContext} from '#external-links'; + export default { extraDependencies: ['html', 'language', 'to'], data: (url) => ({url}), slots: { + context: { + // This awkward syntax is because the slot descriptor validator can't + // differentiate between a function that returns a validator (the usual + // syntax) and a function that is itself a validator. + validate: () => isExternalLinkContext, + default: 'generic', + }, + withText: {type: 'boolean'}, }, generate(data, slots, {html, language, to}) { - const {url} = data; + const format = style => + language.formatExternalLink(data.url, {style, context: slots.context}); - const normalText = language.formatExternalLink(url, {style: 'normal'}); - const compactText = language.formatExternalLink(url, {style: 'compact'}); - const iconId = language.formatExternalLink(url, {style: 'icon-id'}); + const normalText = format('normal'); + const compactText = format('compact'); + const iconId = format('icon-id'); return html.tag('a', - {href: url, class: ['icon', slots.withText && 'has-text']}, + {href: data.url, class: ['icon', slots.withText && 'has-text']}, [ html.tag('svg', [ !slots.withText && diff --git a/src/content/dependencies/linkExternalFlash.js b/src/content/dependencies/linkExternalFlash.js index 65158ff8..e2147da1 100644 --- a/src/content/dependencies/linkExternalFlash.js +++ b/src/content/dependencies/linkExternalFlash.js @@ -1,6 +1,8 @@ // Note: This function is seriously hard-coded for HSMusic, with custom // presentation of links to Homestuck flashes hosted various places. +// This also appears to be dead code, apart from a single snapshot test?? + export default { contentDependencies: ['linkExternal'], extraDependencies: ['html', 'language'], @@ -22,6 +24,8 @@ export default { const {link} = relations; const {url, page} = data; + link.setSlot('context', 'flash'); + return html.tag('span', {class: 'nowrap'}, -- cgit 1.3.0-6-gf8a5 From face11b98dbaa866055718b7731f61a21fcf9088 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 23 Nov 2023 21:01:27 -0400 Subject: content: linkExternal: make direct wrapper for formatExternalLink --- src/content/dependencies/linkExternal.js | 78 ++++++-------------------------- 1 file changed, 15 insertions(+), 63 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js index e51ea89e..4941e48a 100644 --- a/src/content/dependencies/linkExternal.js +++ b/src/content/dependencies/linkExternal.js @@ -1,78 +1,30 @@ -import {isExternalLinkContext} from '#external-links'; +import {isExternalLinkContext, isExternalLinkStyle} from '#external-links'; export default { extraDependencies: ['html', 'language', 'wikiData'], - sprawl: ({wikiInfo}) => ({wikiInfo}), - - data(sprawl, url) { - const data = {url}; - - const {canonicalBase} = sprawl.wikiInfo; - if (canonicalBase) { - const {hostname: canonicalDomain} = new URL(canonicalBase); - Object.assign(data, {canonicalDomain}); - } - - return data; - }, + data: (url) => ({url}), slots: { - context: { + style: { // This awkward syntax is because the slot descriptor validator can't // differentiate between a function that returns a validator (the usual // syntax) and a function that is itself a validator. + validate: () => isExternalLinkStyle, + default: 'platform', + }, + + context: { validate: () => isExternalLinkContext, default: 'generic', }, }, - generate(data, slots, {html, language}) { - return ( - html.tag('a', - {href: data.url, class: 'nowrap'}, - language.formatExternalLink(data.url, { - style: 'platform', - context: slots.context, - }))); - }, - - /* - : domain.includes('youtu') - ? slots.mode === 'album' - ? data.url.includes('list=') - ? language.$('misc.external.youtube.playlist') - : language.$('misc.external.youtube.fullAlbum') - : language.$('misc.external.youtube') - - switch (slots.mode) { - case 'flash': { - const wrap = content => - html.tag('span', {class: 'nowrap'}, content); - - if (domain.includes('homestuck.com')) { - const match = pathname.match(/\/story\/(.*)\/?/); - if (match) { - if (isNaN(Number(match[1]))) { - return wrap(language.$('misc.external.flash.homestuck.secret', {link})); - } else { - return wrap(language.$('misc.external.flash.homestuck.page', { - link, - page: match[1], - })); - } - } - } else if (domain.includes('bgreco.net')) { - return wrap(language.$('misc.external.flash.bgreco', {link})); - } else if (domain.includes('youtu')) { - return wrap(language.$('misc.external.flash.youtube', {link})); - } - - return link; - } - - default: - return link; - } - */ + generate: (data, slots, {html, language}) => + html.tag('a', + {href: data.url, class: 'nowrap'}, + language.formatExternalLink(data.url, { + style: slots.style, + context: slots.context, + })), }; -- cgit 1.3.0-6-gf8a5 From 370aab15cb6ba60c95b33f7c4a1ed9b6daf51d98 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 23 Nov 2023 21:02:07 -0400 Subject: content: generateFlashInfoPage: use 'normal' style links --- src/content/dependencies/generateFlashInfoPage.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateFlashInfoPage.js b/src/content/dependencies/generateFlashInfoPage.js index c60f9696..919996a2 100644 --- a/src/content/dependencies/generateFlashInfoPage.js +++ b/src/content/dependencies/generateFlashInfoPage.js @@ -132,8 +132,11 @@ export default { language.$('releaseInfo.playOn', { links: language.formatDisjunctionList( - relations.externalLinks - .map(link => link.slot('context', 'flash'))), + relations.externalLinks.map(link => + link.slots({ + context: 'flash', + style: 'normal', + }))), })), sec.featuredTracks && [ -- cgit 1.3.0-6-gf8a5 From db786c25a9fafc4cac37b108b4ea433019741c07 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 23 Nov 2023 21:33:15 -0400 Subject: content, external-links: minor fixes --- src/content/dependencies/generateAlbumReleaseInfo.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumReleaseInfo.js b/src/content/dependencies/generateAlbumReleaseInfo.js index 4b819091..dd5baab9 100644 --- a/src/content/dependencies/generateAlbumReleaseInfo.js +++ b/src/content/dependencies/generateAlbumReleaseInfo.js @@ -94,7 +94,11 @@ export default { links: language.formatDisjunctionList( relations.externalLinks - .map(link => link.slot('context', 'album'))), + .map(link => + link.slots({ + context: 'album', + style: 'normal', + }))), })), ]); }, -- cgit 1.3.0-6-gf8a5 From 3898fbe9380c7a8bc745eff548b112ad2e9c605b Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 24 Nov 2023 13:40:52 -0400 Subject: content, test: remove unused linkExternalFlash function --- src/content/dependencies/linkExternalFlash.js | 45 --------------------------- 1 file changed, 45 deletions(-) delete mode 100644 src/content/dependencies/linkExternalFlash.js (limited to 'src/content') diff --git a/src/content/dependencies/linkExternalFlash.js b/src/content/dependencies/linkExternalFlash.js deleted file mode 100644 index e2147da1..00000000 --- a/src/content/dependencies/linkExternalFlash.js +++ /dev/null @@ -1,45 +0,0 @@ -// Note: This function is seriously hard-coded for HSMusic, with custom -// presentation of links to Homestuck flashes hosted various places. - -// This also appears to be dead code, apart from a single snapshot test?? - -export default { - contentDependencies: ['linkExternal'], - extraDependencies: ['html', 'language'], - - relations(relation, url) { - return { - link: relation('linkExternal', url), - }; - }, - - data(url, flash) { - return { - url, - page: flash.page, - }; - }, - - generate(data, relations, {html, language}) { - const {link} = relations; - const {url, page} = data; - - link.setSlot('context', 'flash'); - - return html.tag('span', - {class: 'nowrap'}, - - url.includes('homestuck.com') - ? isNaN(Number(page)) - ? language.$('misc.external.flash.homestuck.secret', {link}) - : language.$('misc.external.flash.homestuck.page', {link, page}) - - : url.includes('bgreco.net') - ? language.$('misc.external.flash.bgreco', {link}) - - : url.includes('youtu') - ? language.$('misc.external.flash.youtube', {link}) - - : link); - }, -}; -- cgit 1.3.0-6-gf8a5 From 45fba07af02d4f161cce494b683918bc76453b82 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 24 Nov 2023 14:39:06 -0400 Subject: content: linkExternal: default to 'normal' style --- src/content/dependencies/generateArtistInfoPage.js | 7 +++++-- src/content/dependencies/generateFlashInfoPage.js | 7 ++----- src/content/dependencies/linkExternal.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js index ac9209a7..be9f9b86 100644 --- a/src/content/dependencies/generateArtistInfoPage.js +++ b/src/content/dependencies/generateArtistInfoPage.js @@ -163,8 +163,11 @@ export default { language.$('releaseInfo.visitOn', { links: language.formatDisjunctionList( - sec.visit.externalLinks - .map(link => link.slot('context', 'artist'))), + sec.visit.externalLinks.map(link => + link.slots({ + context: 'artist', + mode: 'platform', + }))), })), sec.artworks?.artistGalleryLink && diff --git a/src/content/dependencies/generateFlashInfoPage.js b/src/content/dependencies/generateFlashInfoPage.js index 919996a2..c60f9696 100644 --- a/src/content/dependencies/generateFlashInfoPage.js +++ b/src/content/dependencies/generateFlashInfoPage.js @@ -132,11 +132,8 @@ export default { language.$('releaseInfo.playOn', { links: language.formatDisjunctionList( - relations.externalLinks.map(link => - link.slots({ - context: 'flash', - style: 'normal', - }))), + relations.externalLinks + .map(link => link.slot('context', 'flash'))), })), sec.featuredTracks && [ diff --git a/src/content/dependencies/linkExternal.js b/src/content/dependencies/linkExternal.js index 4941e48a..0a079614 100644 --- a/src/content/dependencies/linkExternal.js +++ b/src/content/dependencies/linkExternal.js @@ -11,7 +11,7 @@ export default { // differentiate between a function that returns a validator (the usual // syntax) and a function that is itself a validator. validate: () => isExternalLinkStyle, - default: 'platform', + default: 'normal', }, context: { -- cgit 1.3.0-6-gf8a5 From 7b54aafa477ca8998f24d86e2b79e018bd93512d Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 24 Nov 2023 15:22:08 -0400 Subject: content: generateArtistInfoPage: quick slot fix --- src/content/dependencies/generateArtistInfoPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js index be9f9b86..1b85680f 100644 --- a/src/content/dependencies/generateArtistInfoPage.js +++ b/src/content/dependencies/generateArtistInfoPage.js @@ -166,7 +166,7 @@ export default { sec.visit.externalLinks.map(link => link.slots({ context: 'artist', - mode: 'platform', + style: 'platform', }))), })), -- cgit 1.3.0-6-gf8a5 From daf6f5b39ebaf8cf62b0dab72edac41ceff72989 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 24 Nov 2023 15:26:05 -0400 Subject: css: site5.css -> site6.css, just to be safe --- src/content/dependencies/generatePageLayout.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js index 7dee8cc3..1591223a 100644 --- a/src/content/dependencies/generatePageLayout.js +++ b/src/content/dependencies/generatePageLayout.js @@ -624,7 +624,7 @@ export default { html.tag('link', { rel: 'stylesheet', - href: to('shared.staticFile', 'site5.css', cachebust), + href: to('shared.staticFile', 'site6.css', cachebust), }), html.tag('style', [ -- cgit 1.3.0-6-gf8a5 From 692bd586495e5fcb6d7c5eae2af6a8c34b380b50 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 24 Nov 2023 15:40:00 -0400 Subject: content: generateCommentaryIndexPage: handle entries individually --- src/content/dependencies/generateCommentaryIndexPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateCommentaryIndexPage.js b/src/content/dependencies/generateCommentaryIndexPage.js index 1d381bff..5d38941a 100644 --- a/src/content/dependencies/generateCommentaryIndexPage.js +++ b/src/content/dependencies/generateCommentaryIndexPage.js @@ -19,13 +19,13 @@ export default { query.albums.map(album => [album, ...album.tracks] .filter(({commentary}) => commentary) - .map(({commentary}) => commentary)); + .flatMap(({commentary}) => commentary)); query.wordCounts = entries.map(entries => accumulateSum( entries, - entry => entry.split(' ').length)); + entry => entry.body.split(' ').length)); query.entryCounts = entries.map(entries => entries.length); -- cgit 1.3.0-6-gf8a5 From 09f67bdb9438618fe8632d0d8ceda8fee12b8cb7 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 26 Nov 2023 13:47:40 -0400 Subject: content: generateAlbumCommentaryPage: miscellaneous fixes/updates --- src/content/dependencies/generateAlbumCommentaryPage.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateAlbumCommentaryPage.js b/src/content/dependencies/generateAlbumCommentaryPage.js index 442d72a7..5a7142e5 100644 --- a/src/content/dependencies/generateAlbumCommentaryPage.js +++ b/src/content/dependencies/generateAlbumCommentaryPage.js @@ -107,11 +107,15 @@ export default { ? [album, ...tracksWithCommentary] : tracksWithCommentary); - data.entryCount = thingsWithCommentary.length; + data.entryCount = + thingsWithCommentary + .flatMap(({commentary}) => commentary) + .length; data.wordCount = thingsWithCommentary - .map(({commentary}) => commentary) + .flatMap(({commentary}) => commentary) + .map(({body}) => body) .join(' ') .split(' ') .length; @@ -156,7 +160,7 @@ export default { language.countCommentaryEntries(data.entryCount, {unit: true})), })), - relations.albumCommentaryContent && [ + relations.albumCommentaryEntries && [ relations.albumCommentaryHeading.slots({ tag: 'h3', color: data.color, @@ -173,7 +177,7 @@ export default { language.formatUnitList( relations.albumCommentaryListeningLinks .map(link => link.slots({ - mode: 'album', + context: 'album', tab: 'separate', }))), }), @@ -182,8 +186,7 @@ export default { relations.albumCommentaryCover ?.slots({mode: 'commentary'}), - html.tag('blockquote', - relations.albumCommentaryContent), + relations.albumCommentaryEntries, ], stitchArrays({ -- cgit 1.3.0-6-gf8a5 From a65693efe23b97da173463f207979f81767d791c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 27 Nov 2023 21:13:39 -0400 Subject: data, content: embed scripts on static pages --- src/content/dependencies/generateStaticPage.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateStaticPage.js b/src/content/dependencies/generateStaticPage.js index 3e27fd43..226152c7 100644 --- a/src/content/dependencies/generateStaticPage.js +++ b/src/content/dependencies/generateStaticPage.js @@ -1,5 +1,6 @@ export default { contentDependencies: ['generatePageLayout', 'transformContent'], + extraDependencies: ['html'], relations(relation, staticPage) { return { @@ -12,10 +13,11 @@ export default { return { name: staticPage.name, stylesheet: staticPage.stylesheet, + script: staticPage.script, }; }, - generate(data, relations) { + generate(data, relations, {html}) { return relations.layout .slots({ title: data.name, @@ -27,7 +29,12 @@ export default { : []), mainClasses: ['long-content'], - mainContent: relations.content, + mainContent: [ + relations.content, + + data.script && + html.tag('script', data.script), + ], navLinkStyle: 'hierarchical', navLinks: [ -- cgit 1.3.0-6-gf8a5 From 6844d1275f0b0025b09ca909a99d705447792e1f Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 27 Nov 2023 21:45:38 -0400 Subject: content, test: transformContent: handle indentation more carefully --- src/content/dependencies/transformContent.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js index b0a7796c..2002ebee 100644 --- a/src/content/dependencies/transformContent.js +++ b/src/content/dependencies/transformContent.js @@ -562,11 +562,14 @@ export default { const transformMultiline = () => { const markedInput = extractNonTextNodes() - // Compress multiple line breaks into single line breaks. - .replace(/\n{2,}/g, '\n') + // Compress multiple line breaks into single line breaks, + // except when they're preceding or following indented + // text (by at least two spaces). + .replace(/(? / " ". - .replace(/(?.*| $|
$)\n+/gm, '\n\n') /* eslint-disable-line no-regex-spaces */ + // or
/ " ", and which don't precede or follow + // indented text (by at least two spaces). + .replace(/(?.*|^ .*\n*| $|
$)\n+(?! |\n)/gm, '\n\n') /* eslint-disable-line no-regex-spaces */ // Expand line breaks which are at the end of a list. .replace(/(?<=^ *-.*)\n+(?!^ *-)/gm, '\n\n') // Expand line breaks which are at the end of a quote. -- cgit 1.3.0-6-gf8a5 From e156e337c29558b44e75e2d63494221823c5a9f9 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 16:53:31 -0400 Subject: content: generateGroupInfoPage: tidy album list implementation --- src/content/dependencies/generateGroupInfoPage.js | 89 +++++++++++------------ 1 file changed, 44 insertions(+), 45 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js index 05df33fb..04886fe2 100644 --- a/src/content/dependencies/generateGroupInfoPage.js +++ b/src/content/dependencies/generateGroupInfoPage.js @@ -1,4 +1,4 @@ -import {empty} from '#sugar'; +import {empty, stitchArrays} from '#sugar'; export default { contentDependencies: [ @@ -62,18 +62,17 @@ export default { sec.albums.galleryLink = relation('linkGroupGallery', group); - sec.albums.entries = - group.albums.map(album => { - const links = {}; - links.albumLink = relation('linkAlbum', album); - - const otherGroup = album.groups.find(g => g !== group); - if (otherGroup) { - links.groupLink = relation('linkGroup', otherGroup); - } + sec.albums.albumLinks = + group.albums + .map(album => relation('linkAlbum', album)); - return links; - }); + sec.albums.groupLinks = + group.albums + .map(album => album.groups.find(g => g !== group)) + .map(group => + (group + ? relation('linkGroup', group) + : null)); } return relations; @@ -85,11 +84,9 @@ export default { data.name = group.name; data.color = group.color; - if (!empty(group.albums)) { - data.albumYears = - group.albums - .map(album => album.date?.getFullYear()); - } + data.albumYears = + group.albums + .map(album => album.date?.getFullYear()); return data; }, @@ -133,34 +130,36 @@ export default { })), html.tag('ul', - sec.albums.entries.map(({albumLink, groupLink}, index) => { - // All these strings are really jank, and should probably - // be implemented with the same 'const parts = [], opts = {}' - // form used elsewhere... - const year = data.albumYears[index]; - const item = - (year - ? language.$('groupInfoPage.albumList.item', { - year, - album: albumLink, - }) - : language.$('groupInfoPage.albumList.item.withoutYear', { - album: albumLink, - })); - - return html.tag('li', - (groupLink - ? language.$('groupInfoPage.albumList.item.withAccent', { - item, - accent: - html.tag('span', {class: 'other-group-accent'}, - language.$('groupInfoPage.albumList.item.otherGroupAccent', { - group: - groupLink.slot('color', false), - })), - }) - : item)); - })), + stitchArrays({ + albumLink: sec.albums.albumLinks, + groupLink: sec.albums.groupLinks, + albumYear: data.albumYears, + }).map(({albumLink, groupLink, albumYear}) => { + const prefix = 'groupInfoPage.albumList.item'; + const parts = [prefix]; + const options = {album: albumLink}; + + if (albumYear) { + parts.push('withYear'); + options.yearAccent = + language.$(prefix, 'yearAccent', { + year: albumYear, + }); + } + + if (groupLink) { + parts.push('withOtherGroup'); + options.otherGroupAccent = + html.tag('span', {class: 'other-group-accent'}, + language.$(prefix, 'otherGroupAccent', { + group: + groupLink.slot('color', false), + })); + } + + return language.$(...parts, options); + }) + .map(content => html.tag('li', content))), ], ], -- cgit 1.3.0-6-gf8a5 From a0fa6520c77e46b7a2e55b87e9994df3af74f149 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 17:57:28 -0400 Subject: content, client, css: basic (absolute) datetimestamp tooltips --- .../dependencies/generateAbsoluteDatetimestamp.js | 41 ++++++++++++++++++++++ .../dependencies/generateDatetimestampTemplate.js | 28 +++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/content/dependencies/generateAbsoluteDatetimestamp.js create mode 100644 src/content/dependencies/generateDatetimestampTemplate.js (limited to 'src/content') diff --git a/src/content/dependencies/generateAbsoluteDatetimestamp.js b/src/content/dependencies/generateAbsoluteDatetimestamp.js new file mode 100644 index 00000000..63acecf2 --- /dev/null +++ b/src/content/dependencies/generateAbsoluteDatetimestamp.js @@ -0,0 +1,41 @@ +export default { + contentDependencies: ['generateDatetimestampTemplate'], + extraDependencies: ['html', 'language'], + + data: (date) => + ({date}), + + relations: (relation) => + ({template: relation('generateDatetimestampTemplate')}), + + slots: { + style: { + validate: v => v.is('full', 'year'), + default: 'full', + }, + + // Only has an effect for 'year' style. + tooltip: { + type: 'boolean', + default: false, + }, + }, + + generate: (data, relations, slots, {language}) => + relations.template.slots({ + mainContent: + (slots.style === 'full' + ? language.formatDate(data.date) + : slots.style === 'year' + ? data.date.getFullYear().toString() + : null), + + tooltipContent: + slots.tooltip && + slots.style === 'year' && + language.formatDate(data.date), + + datetime: + data.date.toISOString(), + }), +}; diff --git a/src/content/dependencies/generateDatetimestampTemplate.js b/src/content/dependencies/generateDatetimestampTemplate.js new file mode 100644 index 00000000..bfba647f --- /dev/null +++ b/src/content/dependencies/generateDatetimestampTemplate.js @@ -0,0 +1,28 @@ +export default { + extraDependencies: ['html'], + + slots: { + mainContent: {type: 'html'}, + tooltipContent: {type: 'html'}, + datetime: {type: 'string'}, + }, + + generate: (slots, {html}) => + html.tag('span', { + [html.joinChildren]: '', + + class: [ + 'datetimestamp', + slots.tooltipContent && 'has-tooltip', + ], + }, [ + html.tag('time', + {datetime: slots.datetime}, + slots.mainContent), + + slots.tooltipContent && + html.tag('span', {class: 'datetimestamp-tooltip'}, + html.tag('span', {class: 'datetimestamp-tooltip-content'}, + slots.tooltipContent)), + ]), +}; -- cgit 1.3.0-6-gf8a5 From 301ae482ee60897db13d5fd76b9ce7c9df5790f2 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 17:58:07 -0400 Subject: content: generateGroupInfoPage: use datetimestamps --- src/content/dependencies/generateGroupInfoPage.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js index 04886fe2..5bf2b1bf 100644 --- a/src/content/dependencies/generateGroupInfoPage.js +++ b/src/content/dependencies/generateGroupInfoPage.js @@ -2,6 +2,7 @@ import {empty, stitchArrays} from '#sugar'; export default { contentDependencies: [ + 'generateAbsoluteDatetimestamp', 'generateContentHeading', 'generateGroupNavLinks', 'generateGroupSecondaryNav', @@ -73,6 +74,12 @@ export default { (group ? relation('linkGroup', group) : null)); + + sec.albums.datetimestamps = + group.albums.map(album => + (album.date + ? relation('generateAbsoluteDatetimestamp', album.date) + : null)); } return relations; @@ -84,10 +91,6 @@ export default { data.name = group.name; data.color = group.color; - data.albumYears = - group.albums - .map(album => album.date?.getFullYear()); - return data; }, @@ -133,17 +136,18 @@ export default { stitchArrays({ albumLink: sec.albums.albumLinks, groupLink: sec.albums.groupLinks, - albumYear: data.albumYears, - }).map(({albumLink, groupLink, albumYear}) => { + datetimestamp: sec.albums.datetimestamps, + }).map(({albumLink, groupLink, datetimestamp}) => { const prefix = 'groupInfoPage.albumList.item'; const parts = [prefix]; const options = {album: albumLink}; - if (albumYear) { + if (datetimestamp) { parts.push('withYear'); options.yearAccent = language.$(prefix, 'yearAccent', { - year: albumYear, + year: + datetimestamp.slots({style: 'year', tooltip: true}), }); } -- cgit 1.3.0-6-gf8a5 From 253ee49496ff785eb0d9ca909ce13d7b2fd2a2e6 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 18:21:12 -0400 Subject: content: generateColorStyleVariables: misc dynamics + extensibility --- .../dependencies/generateColorStyleRules.js | 7 ++- .../dependencies/generateColorStyleVariables.js | 51 ++++++++++++++++++++-- 2 files changed, 53 insertions(+), 5 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateColorStyleRules.js b/src/content/dependencies/generateColorStyleRules.js index 1b316a3c..3f1d0130 100644 --- a/src/content/dependencies/generateColorStyleRules.js +++ b/src/content/dependencies/generateColorStyleRules.js @@ -18,9 +18,12 @@ export default { `:root {`, ...( relations.variables - .slot('color', slots.color) + .slots({ + color: slots.color, + context: 'page-root', + mode: 'property-list', + }) .content - .split(';') .map(line => line + ';')), `}`, ].join('\n'); diff --git a/src/content/dependencies/generateColorStyleVariables.js b/src/content/dependencies/generateColorStyleVariables.js index f30d786b..7cd04bd1 100644 --- a/src/content/dependencies/generateColorStyleVariables.js +++ b/src/content/dependencies/generateColorStyleVariables.js @@ -2,7 +2,23 @@ export default { extraDependencies: ['html', 'getColors'], slots: { - color: {validate: v => v.isColor}, + color: { + validate: v => v.isColor, + }, + + context: { + validate: v => v.is( + 'any-content', + 'page-root', + 'primary-only'), + + default: 'any-content', + }, + + mode: { + validate: v => v.is('style', 'property-list'), + default: 'style', + }, }, generate(slots, {getColors}) { @@ -18,7 +34,7 @@ export default { shadow, } = getColors(slots.color); - return [ + let anyContent = [ `--primary-color: ${primary}`, `--dark-color: ${dark}`, `--dim-color: ${dim}`, @@ -26,6 +42,35 @@ export default { `--bg-color: ${bg}`, `--bg-black-color: ${bgBlack}`, `--shadow-color: ${shadow}`, - ].join('; '); + ]; + + let selectedProperties; + + switch (slots.context) { + case 'any-content': + selectedProperties = anyContent; + break; + + case 'page-root': + selectedProperties = [ + ...anyContent, + `--page-primary-color: ${primary}`, + ]; + break; + + case 'primary-only': + selectedProperties = [ + `--primary-color: ${primary}`, + ]; + break; + } + + switch (slots.mode) { + case 'style': + return selectedProperties.join('; '); + + case 'property-list': + return selectedProperties; + } }, }; -- cgit 1.3.0-6-gf8a5 From ad823614a22807321d28ad25fa5440d439d84975 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 18:22:05 -0400 Subject: content: generateGroupInfoPage: colorize tooltips --- src/content/dependencies/generateGroupInfoPage.js | 31 +++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js index 5bf2b1bf..0e5d645b 100644 --- a/src/content/dependencies/generateGroupInfoPage.js +++ b/src/content/dependencies/generateGroupInfoPage.js @@ -3,6 +3,7 @@ import {empty, stitchArrays} from '#sugar'; export default { contentDependencies: [ 'generateAbsoluteDatetimestamp', + 'generateColorStyleVariables', 'generateContentHeading', 'generateGroupNavLinks', 'generateGroupSecondaryNav', @@ -63,6 +64,10 @@ export default { sec.albums.galleryLink = relation('linkGroupGallery', group); + sec.albums.colorVariables = + group.albums + .map(() => relation('generateColorStyleVariables')); + sec.albums.albumLinks = group.albums .map(album => relation('linkAlbum', album)); @@ -91,6 +96,9 @@ export default { data.name = group.name; data.color = group.color; + data.albumColors = + group.albums.map(album => album.color); + return data; }, @@ -137,10 +145,21 @@ export default { albumLink: sec.albums.albumLinks, groupLink: sec.albums.groupLinks, datetimestamp: sec.albums.datetimestamps, - }).map(({albumLink, groupLink, datetimestamp}) => { + colorVariables: sec.albums.colorVariables, + albumColor: data.albumColors, + }).map(({ + albumLink, + groupLink, + datetimestamp, + colorVariables, + albumColor, + }) => { const prefix = 'groupInfoPage.albumList.item'; const parts = [prefix]; - const options = {album: albumLink}; + const options = {}; + + options.album = + albumLink.slot('color', false); if (datetimestamp) { parts.push('withYear'); @@ -161,9 +180,11 @@ export default { })); } - return language.$(...parts, options); - }) - .map(content => html.tag('li', content))), + return ( + html.tag('li', + {style: colorVariables.slot('color', albumColor).content}, + language.$(...parts, options))); + })), ], ], -- cgit 1.3.0-6-gf8a5 From 2c6d88908591a0f9d734d634f3f2ab4aca575be5 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 21:46:46 -0400 Subject: content: generateRelativeDatetimestamp --- .../dependencies/generateRelativeDatetimestamp.js | 58 ++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/content/dependencies/generateRelativeDatetimestamp.js (limited to 'src/content') diff --git a/src/content/dependencies/generateRelativeDatetimestamp.js b/src/content/dependencies/generateRelativeDatetimestamp.js new file mode 100644 index 00000000..f0417594 --- /dev/null +++ b/src/content/dependencies/generateRelativeDatetimestamp.js @@ -0,0 +1,58 @@ +export default { + contentDependencies: [ + 'generateAbsoluteDatetimestamp', + 'generateDatetimestampTemplate', + ], + + extraDependencies: ['html', 'language'], + + data: (currentDate, referenceDate) => + (currentDate.getTime() === referenceDate.getTime() + ? {equal: true, date: currentDate} + : {equal: false, currentDate, referenceDate}), + + relations: (relation, currentDate) => + ({template: relation('generateDatetimestampTemplate'), + fallback: relation('generateAbsoluteDatetimestamp', currentDate)}), + + slots: { + style: { + validate: v => v.is('full', 'year'), + default: 'full', + }, + + tooltip: { + type: 'boolean', + default: false, + }, + }, + + generate(data, relations, slots, {language}) { + if (data.comparison === 'equal') { + return relations.fallback.slots({ + style: slots.style, + tooltip: slots.tooltip, + }); + } + + return relations.template.slots({ + mainContent: + (slots.style === 'full' + ? language.formatDate(data.currentDate) + : slots.style === 'year' + ? data.currentDate.getFullYear().toString() + : null), + + tooltipContent: + slots.tooltip && + language.formatRelativeDate(data.currentDate, data.referenceDate, { + considerRoundingDays: true, + approximate: true, + absolute: true, + }), + + datetime: + data.currentDate.toISOString(), + }); + }, +}; -- cgit 1.3.0-6-gf8a5 From 628a608833f938d79d10c250fb1bf780ec133276 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 21:48:05 -0400 Subject: content: generateTrackInfoPage: embed year next to other releases --- src/content/dependencies/generateTrackInfoPage.js | 50 +++++++++++++++++++---- 1 file changed, 43 insertions(+), 7 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js index 2848b15c..099b889b 100644 --- a/src/content/dependencies/generateTrackInfoPage.js +++ b/src/content/dependencies/generateTrackInfoPage.js @@ -1,10 +1,11 @@ -import {empty} from '#sugar'; +import {empty, stitchArrays} from '#sugar'; import {sortAlbumsTracksChronologically, sortFlashesChronologically} from '#wiki-data'; import getChronologyRelations from '../util/getChronologyRelations.js'; export default { contentDependencies: [ + 'generateAbsoluteDatetimestamp', 'generateAdditionalFilesShortcut', 'generateAdditionalNamesBox', 'generateAlbumAdditionalFilesList', @@ -16,6 +17,7 @@ export default { 'generateContentHeading', 'generateContributionList', 'generatePageLayout', + 'generateRelativeDatetimestamp', 'generateTrackCoverArtwork', 'generateTrackList', 'generateTrackListDividedByGroups', @@ -140,6 +142,25 @@ export default { otherReleases.heading = relation('generateContentHeading'); + otherReleases.trackLinks = + track.otherReleases + .map(track => relation('linkTrack', track)); + + otherReleases.albumLinks = + track.otherReleases + .map(track => relation('linkAlbum', track.album)); + + otherReleases.datetimestamps = + track.otherReleases.map(track2 => + (track2.date + ? (track.date + ? relation('generateRelativeDatetimestamp', + track2.date, + track.date) + : relation('generateAbsoluteDatetimestamp', + track2.date)) + : null)); + otherReleases.items = track.otherReleases.map(track => ({ trackLink: relation('linkTrack', track), @@ -356,12 +377,27 @@ export default { }), html.tag('ul', - sec.otherReleases.items.map(({trackLink, albumLink}) => - html.tag('li', - language.$('releaseInfo.alsoReleasedAs.item', { - track: trackLink, - album: albumLink, - })))), + stitchArrays({ + trackLink: sec.otherReleases.trackLinks, + albumLink: sec.otherReleases.albumLinks, + datetimestamp: sec.otherReleases.datetimestamps, + }).map(({trackLink, albumLink, datetimestamp}) => { + const parts = ['releaseInfo.alsoReleasedAs.item']; + const options = {track: trackLink, album: albumLink}; + + if (datetimestamp) { + parts.push('withYear'); + options.year = + datetimestamp.slots({ + style: 'year', + tooltip: true, + }); + } + + return ( + html.tag('li', + language.$(...parts, options))); + })), ], sec.contributors && [ -- cgit 1.3.0-6-gf8a5 From 7d2f0dab8a21a4282f1ee5bcbe418765782eb9b6 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 22:02:41 -0400 Subject: content: generateTrackInfoPage: colorize tooltips --- src/content/dependencies/generateTrackInfoPage.js | 24 +++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js index 099b889b..11fb2b9c 100644 --- a/src/content/dependencies/generateTrackInfoPage.js +++ b/src/content/dependencies/generateTrackInfoPage.js @@ -13,6 +13,7 @@ export default { 'generateAlbumSidebar', 'generateAlbumStyleRules', 'generateChronologyLinks', + 'generateColorStyleVariables', 'generateCommentarySection', 'generateContentHeading', 'generateContributionList', @@ -142,6 +143,10 @@ export default { otherReleases.heading = relation('generateContentHeading'); + otherReleases.colorVariables = + track.otherReleases + .map(() => relation('generateColorStyleVariables')); + otherReleases.trackLinks = track.otherReleases .map(track => relation('linkTrack', track)); @@ -311,6 +316,9 @@ export default { hasTrackNumbers: track.album.hasTrackNumbers, trackNumber: track.album.tracks.indexOf(track) + 1, + otherReleaseColors: + track.otherReleases.map(track => track.color), + numAdditionalFiles: track.additionalFiles.length, }; }, @@ -381,9 +389,20 @@ export default { trackLink: sec.otherReleases.trackLinks, albumLink: sec.otherReleases.albumLinks, datetimestamp: sec.otherReleases.datetimestamps, - }).map(({trackLink, albumLink, datetimestamp}) => { + colorVariables: sec.otherReleases.colorVariables, + color: data.otherReleaseColors, + }).map(({ + trackLink, + albumLink, + datetimestamp, + colorVariables, + color, + }) => { const parts = ['releaseInfo.alsoReleasedAs.item']; - const options = {track: trackLink, album: albumLink}; + const options = {}; + + options.track = trackLink.slot('color', false); + options.album = albumLink; if (datetimestamp) { parts.push('withYear'); @@ -396,6 +415,7 @@ export default { return ( html.tag('li', + {style: colorVariables.slot('color', color).content}, language.$(...parts, options))); })), ], -- cgit 1.3.0-6-gf8a5 From 67b5ad5f64b5a75a727decd732119343b34c7cdc Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 22:11:02 -0400 Subject: content: generateRelativeDatetimestamp: don't double full date in tooltip --- src/content/dependencies/generateRelativeDatetimestamp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/content') diff --git a/src/content/dependencies/generateRelativeDatetimestamp.js b/src/content/dependencies/generateRelativeDatetimestamp.js index f0417594..bbe33188 100644 --- a/src/content/dependencies/generateRelativeDatetimestamp.js +++ b/src/content/dependencies/generateRelativeDatetimestamp.js @@ -48,7 +48,7 @@ export default { language.formatRelativeDate(data.currentDate, data.referenceDate, { considerRoundingDays: true, approximate: true, - absolute: true, + absolute: slots.style === 'year', }), datetime: -- cgit 1.3.0-6-gf8a5 From 38e048838eae945a1b0ed8cffd747c0534e46af2 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 3 Dec 2023 13:28:26 -0400 Subject: content: generateAdditionalNamesBoxItem + "from" support --- .../dependencies/generateAdditionalNamesBox.js | 46 +++------------ .../dependencies/generateAdditionalNamesBoxItem.js | 68 ++++++++++++++++++++++ 2 files changed, 77 insertions(+), 37 deletions(-) create mode 100644 src/content/dependencies/generateAdditionalNamesBoxItem.js (limited to 'src/content') diff --git a/src/content/dependencies/generateAdditionalNamesBox.js b/src/content/dependencies/generateAdditionalNamesBox.js index f7fa3b00..63427c58 100644 --- a/src/content/dependencies/generateAdditionalNamesBox.js +++ b/src/content/dependencies/generateAdditionalNamesBox.js @@ -1,48 +1,20 @@ -import {stitchArrays} from '#sugar'; - export default { - contentDependencies: ['transformContent'], + contentDependencies: ['generateAdditionalNamesBoxItem'], extraDependencies: ['html', 'language'], relations: (relation, additionalNames) => ({ - names: - additionalNames.map(({name}) => - relation('transformContent', name)), - - annotations: - additionalNames.map(({annotation}) => - (annotation - ? relation('transformContent', annotation) - : null)), + items: + additionalNames + .map(entry => relation('generateAdditionalNamesBoxItem', entry)), }), - generate: (relations, {html, language}) => { - const names = - relations.names.map(name => - html.tag('span', {class: 'additional-name'}, - name.slot('mode', 'inline'))); - - const annotations = - relations.annotations.map(annotation => - (annotation - ? html.tag('span', {class: 'annotation'}, - language.$('misc.additionalNames.item.annotation', { - annotation: - annotation.slot('mode', 'inline'), - })) - : null)); - - return html.tag('div', {id: 'additional-names-box'}, [ + generate: (relations, {html, language}) => + html.tag('div', {id: 'additional-names-box'}, [ html.tag('p', language.$('misc.additionalNames.title')), html.tag('ul', - stitchArrays({name: names, annotation: annotations}) - .map(({name, annotation}) => - html.tag('li', - (annotation - ? language.$('misc.additionalNames.item.withAnnotation', {name, annotation}) - : language.$('misc.additionalNames.item', {name}))))), - ]); - }, + relations.items + .map(item => html.tag('li', item))), + ]), }; diff --git a/src/content/dependencies/generateAdditionalNamesBoxItem.js b/src/content/dependencies/generateAdditionalNamesBoxItem.js new file mode 100644 index 00000000..bb4c8477 --- /dev/null +++ b/src/content/dependencies/generateAdditionalNamesBoxItem.js @@ -0,0 +1,68 @@ +import {stitchArrays} from '#sugar'; + +export default { + contentDependencies: ['linkTrack', 'transformContent'], + extraDependencies: ['html', 'language'], + + relations: (relation, entry) => ({ + nameContent: + relation('transformContent', entry.name), + + annotationContent: + (entry.annotation + ? relation('transformContent', entry.annotation) + : null), + + trackLinks: + (entry.from + ? entry.from.map(track => relation('linkTrack', track)) + : null), + }), + + data: (entry) => ({ + albumNames: + (entry.from + ? entry.from.map(track => track.album.name) + : null), + }), + + generate: (data, relations, {html, language}) => { + const prefix = 'misc.additionalNames.item'; + + const itemParts = [prefix]; + const itemOptions = {}; + + itemOptions.name = + html.tag('span', {class: 'additional-name'}, + relations.nameContent.slot('mode', 'inline')); + + const accentParts = [prefix, 'accent']; + const accentOptions = {}; + + if (relations.annotationContent) { + accentParts.push('withAnnotation'); + accentOptions.annotation = + relations.annotationContent.slot('mode', 'inline'); + } + + if (relations.trackLinks) { + accentParts.push('withAlbums'); + accentOptions.albums = + language.formatConjunctionList( + stitchArrays({ + trackLink: relations.trackLinks, + albumName: data.albumNames, + }).map(({trackLink, albumName}) => + trackLink.slot('content', albumName))); + } + + if (accentParts.length > 2) { + itemParts.push('withAccent'); + itemOptions.accent = + html.tag('span', {class: 'accent'}, + language.$(...accentParts, accentOptions)); + } + + return language.$(...itemParts, itemOptions); + }, +}; -- cgit 1.3.0-6-gf8a5 From 2f0ff9ced6c8a29b098a51f751522ebe11704063 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 3 Dec 2023 13:28:59 -0400 Subject: content: generateTrackAdditionalNamesBox --- .../generateTrackAdditionalNamesBox.js | 53 ++++++++++++++++++++++ src/content/dependencies/generateTrackInfoPage.js | 11 ++--- 2 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 src/content/dependencies/generateTrackAdditionalNamesBox.js (limited to 'src/content') diff --git a/src/content/dependencies/generateTrackAdditionalNamesBox.js b/src/content/dependencies/generateTrackAdditionalNamesBox.js new file mode 100644 index 00000000..bad04b74 --- /dev/null +++ b/src/content/dependencies/generateTrackAdditionalNamesBox.js @@ -0,0 +1,53 @@ +import {empty} from '#sugar'; + +export default { + contentDependencies: ['generateAdditionalNamesBox'], + extraDependencies: ['html'], + + query: (track) => { + const { + additionalNames: own, + sharedAdditionalNames: shared, + inferredAdditionalNames: inferred, + } = track; + + if (empty(own) && empty(shared) && empty(inferred)) { + return {combinedList: []}; + } + + const firstFilter = + (empty(own) + ? new Set() + : new Set(own.map(({name}) => name))); + + const sharedFiltered = + shared.filter(({name}) => !firstFilter.has(name)) + + const secondFilter = + new Set([ + ...firstFilter, + ...sharedFiltered.map(({name}) => name), + ]); + + const inferredFiltered = + inferred.filter(({name}) => !secondFilter.has(name)); + + return { + combinedList: [ + ...own, + ...sharedFiltered, + ...inferredFiltered, + ], + }; + }, + + relations: (relation, query) => ({ + box: + (empty(query.combinedList) + ? null + : relation('generateAdditionalNamesBox', query.combinedList)), + }), + + generate: (relations, {html}) => + relations.box ?? html.blank(), +}; diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js index 2848b15c..d8908ade 100644 --- a/src/content/dependencies/generateTrackInfoPage.js +++ b/src/content/dependencies/generateTrackInfoPage.js @@ -6,7 +6,6 @@ import getChronologyRelations from '../util/getChronologyRelations.js'; export default { contentDependencies: [ 'generateAdditionalFilesShortcut', - 'generateAdditionalNamesBox', 'generateAlbumAdditionalFilesList', 'generateAlbumNavAccent', 'generateAlbumSidebar', @@ -16,6 +15,7 @@ export default { 'generateContentHeading', 'generateContributionList', 'generatePageLayout', + 'generateTrackAdditionalNamesBox', 'generateTrackCoverArtwork', 'generateTrackList', 'generateTrackListDividedByGroups', @@ -108,10 +108,9 @@ export default { list: relation('generateAlbumAdditionalFilesList', album, additionalFiles), }); - if (!empty(track.additionalNames)) { - relations.additionalNamesBox = - relation('generateAdditionalNamesBox', track.additionalNames); - } + // This'll take care of itself being blank if there's nothing to show here. + relations.additionalNamesBox = + relation('generateTrackAdditionalNamesBox', track); if (track.hasUniqueCoverArt || album.hasCoverArt) { relations.cover = @@ -302,7 +301,7 @@ export default { title: language.$('trackPage.title', {track: data.name}), headingMode: 'sticky', - additionalNames: relations.additionalNamesBox ?? null, + additionalNames: relations.additionalNamesBox, color: data.color, styleRules: [relations.albumStyleRules], -- cgit 1.3.0-6-gf8a5