diff options
| -rw-r--r-- | src/content/dependencies/generateArtistInfoPageArtworksChunk.js | 11 | ||||
| -rw-r--r-- | src/content/dependencies/generateArtistInfoPageChunk.js | 85 | ||||
| -rw-r--r-- | src/content/dependencies/generateArtistInfoPageCommentaryChunkedList.js | 91 | ||||
| -rw-r--r-- | src/content/dependencies/generateArtistInfoPageFlashesChunk.js | 8 | ||||
| -rw-r--r-- | src/content/dependencies/generateArtistInfoPageTracksChunk.js | 41 | ||||
| -rw-r--r-- | src/content/dependencies/generateContributionList.js | 6 | ||||
| -rw-r--r-- | src/content/dependencies/generateGroupInfoPageAlbumsListByDate.js | 6 | ||||
| -rw-r--r-- | src/content/dependencies/generateGroupInfoPageAlbumsListBySeries.js | 19 | ||||
| -rw-r--r-- | src/content/dependencies/generateNewsEntryReadAnotherLinks.js | 4 | ||||
| -rw-r--r-- | src/data/things/language.js | 58 | ||||
| -rw-r--r-- | src/search-select.js | 91 | ||||
| -rw-r--r-- | src/search.js | 3 | ||||
| -rw-r--r-- | src/static/css/site.css | 15 | ||||
| -rw-r--r-- | src/static/js/search-worker.js | 2 |
14 files changed, 291 insertions, 149 deletions
diff --git a/src/content/dependencies/generateArtistInfoPageArtworksChunk.js b/src/content/dependencies/generateArtistInfoPageArtworksChunk.js index f4c9439a..eb15d54b 100644 --- a/src/content/dependencies/generateArtistInfoPageArtworksChunk.js +++ b/src/content/dependencies/generateArtistInfoPageArtworksChunk.js @@ -25,18 +25,19 @@ export default { }, }, - generate: (data, relations, slots) => + generate: (data, relations, slots, {html}) => relations.template.slots({ mode: 'album', - albumLink: relations.albumLink, + link: relations.albumLink, dates: (slots.filterEditsForWiki ? Array.from({length: data.dates}, () => null) : data.dates), - items: - relations.items.map(item => - item.slot('filterEditsForWiki', slots.filterEditsForWiki)), + list: + html.tag('ul', + relations.items.map(item => + item.slot('filterEditsForWiki', slots.filterEditsForWiki))), }), }; diff --git a/src/content/dependencies/generateArtistInfoPageChunk.js b/src/content/dependencies/generateArtistInfoPageChunk.js index 80429912..3fa46c61 100644 --- a/src/content/dependencies/generateArtistInfoPageChunk.js +++ b/src/content/dependencies/generateArtistInfoPageChunk.js @@ -8,17 +8,12 @@ export default { id: {type: 'string'}, - albumLink: { + link: { type: 'html', mutable: false, }, - flashActLink: { - type: 'html', - mutable: false, - }, - - items: { + list: { type: 'html', mutable: false, }, @@ -51,50 +46,43 @@ export default { } let accentedLink; - - accent: { - switch (slots.mode) { - case 'album': { - accentedLink = slots.albumLink; - - const options = {album: accentedLink}; - const parts = ['artistPage.creditList.album']; - - if (onlyDate) { - parts.push('withDate'); - options.date = language.formatDate(onlyDate); - } - - if (slots.duration) { - parts.push('withDuration'); - options.duration = - language.formatDuration(slots.duration, { - approximate: slots.durationApproximate, - }); - } - - accentedLink = language.formatString(...parts, options); - break; + switch (slots.mode) { + case 'album': { + const options = {album: slots.link}; + const parts = ['artistPage.creditList.album']; + + if (onlyDate) { + parts.push('withDate'); + options.date = language.formatDate(onlyDate); } - case 'flash': { - accentedLink = slots.flashActLink; - - const options = {act: accentedLink}; - const parts = ['artistPage.creditList.flashAct']; + if (slots.duration) { + parts.push('withDuration'); + options.duration = + language.formatDuration(slots.duration, { + approximate: slots.durationApproximate, + }); + } - if (onlyDate) { - parts.push('withDate'); - options.date = language.formatDate(onlyDate); - } else if (earliestDate && latestDate) { - parts.push('withDateRange'); - options.dateRange = - language.formatDateRange(earliestDate, latestDate); - } + accentedLink = language.formatString(...parts, options); + break; + } - accentedLink = language.formatString(...parts, options); - break; + case 'flash': { + const options = {act: slots.link}; + const parts = ['artistPage.creditList.flashAct']; + + if (onlyDate) { + parts.push('withDate'); + options.date = language.formatDate(onlyDate); + } else if (earliestDate && latestDate) { + parts.push('withDateRange'); + options.dateRange = + language.formatDateRange(earliestDate, latestDate); } + + accentedLink = language.formatString(...parts, options); + break; } } @@ -103,10 +91,7 @@ export default { slots.id && {id: slots.id}, accentedLink), - html.tag('dd', - html.tag('ul', - {class: 'offset-tooltips'}, - slots.items)), + html.tag('dd', slots.list), ]); }, }; diff --git a/src/content/dependencies/generateArtistInfoPageCommentaryChunkedList.js b/src/content/dependencies/generateArtistInfoPageCommentaryChunkedList.js index caec58d6..08446a2e 100644 --- a/src/content/dependencies/generateArtistInfoPageCommentaryChunkedList.js +++ b/src/content/dependencies/generateArtistInfoPageCommentaryChunkedList.js @@ -220,52 +220,57 @@ export default { (chunkType === 'album' ? chunk.slots({ mode: 'album', - albumLink: chunkLink, - items: - stitchArrays({ - item: items, - link: itemLinks, - annotation: itemAnnotations, - type: itemTypes, - }).map(({item, link, annotation, type}) => - item.slots({ - annotation: - annotation.slots({ - mode: 'inline', - absorbPunctuationFollowingExternalLinks: false, - }), - - content: - (type === 'album' - ? html.tag('i', - language.$(capsule, 'album.commentary')) - : language.$(capsule, 'track', {track: link})), - })), + link: chunkLink, + + list: + html.tag('ul', + stitchArrays({ + item: items, + link: itemLinks, + annotation: itemAnnotations, + type: itemTypes, + }).map(({item, link, annotation, type}) => + item.slots({ + annotation: + annotation.slots({ + mode: 'inline', + absorbPunctuationFollowingExternalLinks: false, + }), + + content: + (type === 'album' + ? html.tag('i', + language.$(capsule, 'album.commentary')) + : language.$(capsule, 'track', {track: link})), + }))), }) - : chunkType === 'flash-act' + + : chunkType === 'flash-act' ? chunk.slots({ mode: 'flash', - flashActLink: chunkLink, - items: - stitchArrays({ - item: items, - link: itemLinks, - annotation: itemAnnotations, - }).map(({item, link, annotation}) => - item.slots({ - annotation: - (annotation - ? annotation.slots({ - mode: 'inline', - absorbPunctuationFollowingExternalLinks: false, - }) - : null), - - content: - language.$(capsule, 'flash', { - flash: link, - }), - })), + link: chunkLink, + + list: + html.tag('ul', + stitchArrays({ + item: items, + link: itemLinks, + annotation: itemAnnotations, + }).map(({item, link, annotation}) => + item.slots({ + annotation: + (annotation + ? annotation.slots({ + mode: 'inline', + absorbPunctuationFollowingExternalLinks: false, + }) + : null), + + content: + language.$(capsule, 'flash', { + flash: link, + }), + }))), }) : null)))), }; diff --git a/src/content/dependencies/generateArtistInfoPageFlashesChunk.js b/src/content/dependencies/generateArtistInfoPageFlashesChunk.js index acdb9897..ce89d80c 100644 --- a/src/content/dependencies/generateArtistInfoPageFlashesChunk.js +++ b/src/content/dependencies/generateArtistInfoPageFlashesChunk.js @@ -18,11 +18,13 @@ export default { .map(contrib => contrib.date), }), - generate: (data, relations) => + generate: (data, relations, {html}) => relations.template.slots({ mode: 'flash', - flashActLink: relations.flashActLink, + link: relations.flashActLink, dates: data.dates, - items: relations.items, + + list: + html.tag('ul', relations.items), }), }; diff --git a/src/content/dependencies/generateArtistInfoPageTracksChunk.js b/src/content/dependencies/generateArtistInfoPageTracksChunk.js index 3e4cc4e9..7d00fdd6 100644 --- a/src/content/dependencies/generateArtistInfoPageTracksChunk.js +++ b/src/content/dependencies/generateArtistInfoPageTracksChunk.js @@ -1,4 +1,5 @@ -import {unique} from '#sugar'; +import {sortAlbumsTracksChronologically} from '#sort'; +import {empty, unique} from '#sugar'; import {getTotalDuration} from '#wiki-data'; export default { @@ -18,7 +19,7 @@ export default { trackContribs)), }), - data(_artist, album, trackContribLists) { + data(artist, album, trackContribLists) { const data = {}; const contribs = @@ -43,19 +44,47 @@ export default { data.durationApproximate = durationTerms.length > 1; + const tracks = + trackContribLists.map(contribs => contribs[0].thing); + + data.numLinkingOtherReleases = + tracks.filter(track => { + if (empty(track.otherReleases)) return false; + + const releases = + sortAlbumsTracksChronologically(track.allReleases.slice()); + + // later releases always link to first release + if (track !== releases[0]) return true; + + // first releases only link to later credited releases + return tracks.slice(1).some(track => { + const contribs = [ + ...track.artistContribs, + ...track.contributorContribs, + ]; + + return contribs.some(contrib => contrib.artist === artist); + }); + }).length; + return data; }, - generate: (data, relations) => + generate: (data, relations, {html}) => relations.template.slots({ mode: 'album', - - albumLink: relations.albumLink, + link: relations.albumLink, dates: data.dates, duration: data.duration, durationApproximate: data.durationApproximate, - items: relations.items, + list: + html.tag('ul', + data.numLinkingOtherReleases > 1 && + {class: 'offset-tooltips'}, + + relations.items), }), }; diff --git a/src/content/dependencies/generateContributionList.js b/src/content/dependencies/generateContributionList.js index 3716bcd6..4f68321f 100644 --- a/src/content/dependencies/generateContributionList.js +++ b/src/content/dependencies/generateContributionList.js @@ -9,10 +9,14 @@ export default { chronologyKind: {type: 'string'}, }, - generate: (relations, slots, {html}) => + generate: (relations, slots, {html, language}) => html.tag('ul', {[html.onlyIfContent]: true}, + relations.contributionLinks.length > 1 && + language.$order('misc.artistLink.withContribution', 0) === 'ARTIST' && + {class: 'offset-tooltips'}, + relations.contributionLinks .map(contributionLink => html.tag('li', diff --git a/src/content/dependencies/generateGroupInfoPageAlbumsListByDate.js b/src/content/dependencies/generateGroupInfoPageAlbumsListByDate.js index de55f33a..bd3f5dd5 100644 --- a/src/content/dependencies/generateGroupInfoPageAlbumsListByDate.js +++ b/src/content/dependencies/generateGroupInfoPageAlbumsListByDate.js @@ -29,12 +29,16 @@ export default { }, }, - generate: (relations, slots, {html}) => + generate: (relations, slots, {html, language}) => html.tag('ul', {id: 'group-album-list-by-date'}, slots.hidden && {style: 'display: none'}, + relations.items.length > 1&& + language.$order('groupInfoPage.albumList.item.withYear', 0) === 'YEAR_ACCENT' && + {class: 'offset-tooltips'}, + {[html.onlyIfContent]: true}, relations.items diff --git a/src/content/dependencies/generateGroupInfoPageAlbumsListBySeries.js b/src/content/dependencies/generateGroupInfoPageAlbumsListBySeries.js index f8314d71..ddba0aec 100644 --- a/src/content/dependencies/generateGroupInfoPageAlbumsListBySeries.js +++ b/src/content/dependencies/generateGroupInfoPageAlbumsListBySeries.js @@ -12,6 +12,10 @@ export default { group.serieses .map(() => relation('generateContentHeading')), + seriesDescriptions: + group.serieses + .map(series => relation('transformContent', series.description)), + seriesItems: group.serieses .map(series => series.albums @@ -44,17 +48,23 @@ export default { {id: 'group-album-list-by-series'}, {class: 'group-series-list'}, + relations.seriesItems.flat().length > 1 && + language.$order(listCapsule, 'item.withYear', 0) === 'YEAR_ACCENT' && + {class: 'offset-tooltips'}, + {[html.onlyIfContent]: true}, stitchArrays({ name: data.seriesNames, itemsShowArtists: data.seriesItemsShowArtists, heading: relations.seriesHeadings, + description: relations.seriesDescriptions, items: relations.seriesItems, }).map(({ name, itemsShowArtists, heading, + description, items, }) => html.tags([ @@ -66,7 +76,11 @@ export default { }), }), - html.tag('dd', + html.tag('dd', [ + html.tag('blockquote', + {[html.onlyIfContent]: true}, + description), + html.tag('ul', stitchArrays({ item: items, @@ -75,6 +89,7 @@ export default { item.slots({ accentMode: (showArtists ? 'artists' : null), - })))), + }))), + ]), ])))), }; diff --git a/src/content/dependencies/generateNewsEntryReadAnotherLinks.js b/src/content/dependencies/generateNewsEntryReadAnotherLinks.js index 1f6ee6d4..50c23513 100644 --- a/src/content/dependencies/generateNewsEntryReadAnotherLinks.js +++ b/src/content/dependencies/generateNewsEntryReadAnotherLinks.js @@ -70,12 +70,16 @@ export default { entryLines.push(language.$(...parts, options)); } + console.log(language.$order(prefix, 'previous.withDate', 0)); + return ( html.tag('p', {class: 'read-another-links'}, {[html.onlyIfContent]: true}, {[html.joinChildren]: html.tag('br')}, entryLines.length > 1 && + language.$order(prefix, 'previous.withDate', 0) === 'DATE' && + language.$order(prefix, 'next.withDate', 0) === 'DATE' && {class: 'offset-tooltips'}, entryLines)); diff --git a/src/data/things/language.js b/src/data/things/language.js index 43f69f3d..5866027d 100644 --- a/src/data/things/language.js +++ b/src/data/things/language.js @@ -158,6 +158,10 @@ export class Language extends Thing { return this.formatString(...args); } + $order(...args) { + return this.orderStringOptions(...args); + } + assertIntlAvailable(property) { if (!this[property]) { throw new Error(`Intl API ${property} unavailable`); @@ -190,19 +194,14 @@ export class Language extends Thing { const key = this.#joinKeyParts(hasOptions ? args.slice(0, -1) : args); + const template = + this.#getStringTemplateFromFormedKey(key); + const options = (hasOptions ? args.at(-1) : {}); - if (!this.strings) { - throw new Error(`Strings unavailable`); - } - - if (!this.validKeys.includes(key)) { - throw new Error(`Invalid key ${key} accessed`); - } - const constantCasify = name => name .replace(/[A-Z]/g, '_$&') @@ -243,8 +242,7 @@ export class Language extends Thing { ])); const output = this.#iterateOverTemplate({ - template: this.strings[key], - + template, match: languageOptionRegex, insert: ({name: optionName}, canceledForming) => { @@ -324,6 +322,46 @@ export class Language extends Thing { return output; } + orderStringOptions(...args) { + let slice = null, at = null, parts = null; + if (args.length >= 2 && typeof args.at(-1) === 'number') { + if (args.length >= 3 && typeof args.at(-2) === 'number') { + slice = [args.at(-2), args.at(-1)]; + parts = args.slice(0, -2); + } else { + at = args.at(-1); + parts = args.slice(0, -1); + } + } else { + parts = args; + } + + const template = this.getStringTemplate(...parts); + const matches = Array.from(template.matchAll(languageOptionRegex)); + const options = matches.map(({groups}) => groups.name); + + if (slice !== null) return options.slice(...slice); + if (at !== null) return options.at(at); + return options; + } + + getStringTemplate(...args) { + const key = this.#joinKeyParts(args); + return this.#getStringTemplateFromFormedKey(key); + } + + #getStringTemplateFromFormedKey(key) { + if (!this.strings) { + throw new Error(`Strings unavailable`); + } + + if (!this.validKeys.includes(key)) { + throw new Error(`Invalid key ${key} accessed`); + } + + return this.strings[key]; + } + #iterateOverTemplate({ template, match: regexp, diff --git a/src/search-select.js b/src/search-select.js index 24532cbb..36b9e98a 100644 --- a/src/search-select.js +++ b/src/search-select.js @@ -3,6 +3,7 @@ // These files totally go together, so read them side by side, okay? import baseSearchSpec from '#search-shape'; +import {unique} from '#sugar'; import {getKebabCase} from '#wiki-data'; function prepareArtwork(artwork, thing, { @@ -52,6 +53,58 @@ function prepareArtwork(artwork, thing, { return serializeSrc; } +function determineArtistGroups(artist, opts) { + const contributions = [ + artist.musicContributions, + artist.artworkContributions + .filter(contrib => !contrib.annotation?.includes('edits for wiki')), + ].flat(); + + const contributionGroups = + contributions.flatMap(contrib => contrib.groups); + + const scores = + new Map( + unique(contributionGroups).map(group => [group, 0])); + + const artistNamesish = + unique( + [artist.name, ...artist.artistAliases.map(alias => alias.name)] + .map(name => getKebabCase(name))); + + for (const group of scores.keys()) { + if (artistNamesish.includes(getKebabCase(group.name))) { + scores.delete(group); + } + } + + for (const group of contributionGroups) { + scores.set(group, scores.get(group) + 1 / contributions.length); + } + + const dividingGroups = + opts.wikiInfo.divideTrackListsByGroups; + + const dividingGroupThreshold = + (contributions.length < 50 ? 0.08 : 0.16); + + const generalGroupThreshold = + (contributions.length < 50 ? 0.00 : 0.12); + + for (const group of scores.keys()) { + const threshold = + (dividingGroups.includes(group) + ? dividingGroupThreshold + : generalGroupThreshold); + + if (scores.get(group) < threshold) { + scores.delete(group); + } + } + + return Array.from(scores.keys()); +} + function baselineProcess(thing, _opts) { const fields = {}; @@ -116,30 +169,24 @@ function genericSelect(wikiData) { function genericProcess(thing, opts) { const fields = baselineProcess(thing, opts); - const kind = - thing.constructor[Symbol.for('Thing.referenceType')]; - const boundPrepareArtwork = artwork => prepareArtwork(artwork, thing, opts); fields.artwork = - (kind === 'track' && thing.hasUniqueCoverArt + (thing.isTrack && thing.hasUniqueCoverArt ? boundPrepareArtwork(thing.trackArtworks[0]) - : kind === 'track' + : thing.isTrack ? boundPrepareArtwork(thing.album.coverArtworks[0]) - : kind === 'album' + : thing.isAlbum ? boundPrepareArtwork(thing.coverArtworks[0]) - : kind === 'flash' + : thing.isFlash ? boundPrepareArtwork(thing.coverArtwork) : null); fields.parentName = - (kind === 'track' - ? thing.album.name - : kind === 'group' - ? thing.category.name - : kind === 'flash' - ? thing.act.name + (thing.isTrack ? thing.album.name + : thing.isGroup ? thing.category.name + : thing.isFlash ? thing.act.name : null); fields.disambiguator = @@ -147,9 +194,9 @@ function genericProcess(thing, opts) { fields.artTags = (Array.from(new Set( - (kind === 'track' + (thing.isTrack ? thing.trackArtworks.flatMap(artwork => artwork.artTags) - : kind === 'album' + : thing.isAlbum ? thing.coverArtworks.flatMap(artwork => artwork.artTags) : [])))) @@ -169,22 +216,20 @@ function genericProcess(thing, opts) { const contributions = contribKeys - .filter(key => Object.hasOwn(thing, key)) - .flatMap(key => thing[key]); + .flatMap(key => thing[key] ?? []); fields.contributors = contributions .flatMap(({artist}) => [ artist.name, - ...artist.aliasNames, + ...artist.artistAliases.map(alias => alias.name), ]); const groups = - (Object.hasOwn(thing, 'groups') - ? thing.groups - : Object.hasOwn(thing, 'album') - ? thing.album.groups - : []); + (thing.isAlbum ? thing.groups + : thing.isTrack ? thing.album.groups + : thing.isArtist ? determineArtistGroups(thing, opts) + : []); const mainContributorNames = contributions diff --git a/src/search.js b/src/search.js index 138a2d2c..bef8107f 100644 --- a/src/search.js +++ b/src/search.js @@ -23,9 +23,12 @@ function bindSearchUtilities({ getThumbnailEqualOrSmaller, thumbsCache, urls, + wikiData, }) { const bound = { urls, + wikiData, + wikiInfo: wikiData.wikiInfo, }; bound.checkIfImagePathHasCachedThumbnails = diff --git a/src/static/css/site.css b/src/static/css/site.css index a78a31fb..e1654e6d 100644 --- a/src/static/css/site.css +++ b/src/static/css/site.css @@ -1261,8 +1261,7 @@ label > input[type=checkbox]:not(:checked) + span { font-size: 0.9rem; } -li:not(:first-child:last-child) .tooltip:where(:not(.cover-artwork .tooltip)), -.offset-tooltips > :not(:first-child:last-child) .tooltip { +.offset-tooltips .tooltip { left: 14px; } @@ -2353,17 +2352,23 @@ li .origin-details { text-indent: 0; } -.album-group-list blockquote { +blockquote:is( + .album-group-list *, .group-series-list * +) { max-width: 540px; margin-bottom: 9px; margin-top: 3px; } -.album-group-list blockquote p:first-child { +blockquote p:first-child:is( + .album-group-list *, .group-series-list * +) { margin-top: 0; } -.album-group-list blockquote p:last-child { +blockquote p:last-child:is( + .album-group-list *, .group-series-list * +) { margin-bottom: 0; } diff --git a/src/static/js/search-worker.js b/src/static/js/search-worker.js index 96ad8a0b..92ba1f0d 100644 --- a/src/static/js/search-worker.js +++ b/src/static/js/search-worker.js @@ -391,12 +391,14 @@ function performSearchAction({query, options}) { const interestingFieldCombinations = [ ['primaryName'], + ['additionalNames'], ['primaryName', 'parentName', 'groups'], ['primaryName', 'parentName'], ['primaryName', 'groups', 'contributors'], ['primaryName', 'groups', 'artTags'], ['primaryName', 'groups'], + ['additionalNames', 'groups'], ['primaryName', 'contributors'], ['primaryName', 'artTags'], ['parentName', 'groups', 'artTags'], |