diff options
Diffstat (limited to 'src/page/track.js')
-rw-r--r-- | src/page/track.js | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/src/page/track.js b/src/page/track.js new file mode 100644 index 00000000..2dec9bd3 --- /dev/null +++ b/src/page/track.js @@ -0,0 +1,331 @@ +// Track page specification. + +// Imports + +import fixWS from 'fix-whitespace'; + +import { + generateAlbumChronologyLinks, + generateAlbumNavLinks, + generateAlbumSidebar +} from './album.js'; + +import { + getThemeString +} from '../util/colors.js'; + +import * as html from '../util/html.js'; + +import { + OFFICIAL_GROUP_DIRECTORY, + UNRELEASED_TRACKS_DIRECTORY +} from '../util/magic-constants.js'; + +import { + bindOpts +} from '../util/sugar.js'; + +import { + getTrackCover, + getAlbumListTag, + sortByDate +} from '../util/wiki-data.js'; + +// Page exports + +export function targets({wikiData}) { + return wikiData.trackData; +} + +export function write(track, {wikiData}) { + const { groupData, wikiInfo } = wikiData; + const { album } = track; + + const tracksThatReference = track.referencedBy; + const useDividedReferences = groupData.some(group => group.directory === OFFICIAL_GROUP_DIRECTORY); + const ttrFanon = (useDividedReferences && + tracksThatReference.filter(t => t.album.groups.every(group => group.directory !== OFFICIAL_GROUP_DIRECTORY))); + const ttrOfficial = (useDividedReferences && + tracksThatReference.filter(t => t.album.groups.some(group => group.directory === OFFICIAL_GROUP_DIRECTORY))); + + const tracksReferenced = track.references; + const otherReleases = track.otherReleases; + const listTag = getAlbumListTag(album); + + let flashesThatFeature; + if (wikiInfo.features.flashesAndGames) { + flashesThatFeature = sortByDate([track, ...otherReleases] + .flatMap(track => track.flashes.map(flash => ({flash, as: track})))); + } + + const unbound_generateTrackList = (tracks, {getArtistString, link, strings}) => html.tag('ul', + tracks.map(track => { + const line = strings('trackList.item.withArtists', { + track: link.track(track), + by: `<span class="by">${strings('trackList.item.withArtists.by', { + artists: getArtistString(track.artists) + })}</span>` + }); + return (track.aka + ? `<li class="rerelease">${strings('trackList.item.rerelease', {track: line})}</li>` + : `<li>${line}</li>`); + }) + ); + + const hasCommentary = track.commentary || otherReleases.some(t => t.commentary); + const generateCommentary = ({ + link, + strings, + transformMultiline + }) => transformMultiline([ + track.commentary, + ...otherReleases.map(track => + (track.commentary?.split('\n') + .filter(line => line.replace(/<\/b>/g, '').includes(':</i>')) + .map(line => fixWS` + ${line} + ${strings('releaseInfo.artistCommentary.seeOriginalRelease', { + original: link.track(track) + })} + `) + .join('\n'))) + ].filter(Boolean).join('\n')); + + const data = { + type: 'data', + path: ['track', track.directory], + data: ({ + serializeContribs, + serializeCover, + serializeGroupsForTrack, + serializeLink + }) => ({ + name: track.name, + directory: track.directory, + dates: { + released: track.date, + originallyReleased: track.originalDate, + coverArtAdded: track.coverArtDate + }, + duration: track.duration, + color: track.color, + cover: serializeCover(track, getTrackCover), + artists: serializeContribs(track.artists), + contributors: serializeContribs(track.contributors), + coverArtists: serializeContribs(track.coverArtists || []), + album: serializeLink(track.album), + groups: serializeGroupsForTrack(track), + references: track.references.map(serializeLink), + referencedBy: track.referencedBy.map(serializeLink), + alsoReleasedAs: otherReleases.map(track => ({ + track: serializeLink(track), + album: serializeLink(track.album) + })) + }) + }; + + const page = { + type: 'page', + path: ['track', track.directory], + page: ({ + fancifyURL, + generateChronologyLinks, + generateCoverLink, + generatePreviousNextLinks, + getAlbumStylesheet, + getArtistString, + getTrackCover, + link, + strings, + transformInline, + transformLyrics, + transformMultiline, + to + }) => { + const generateTrackList = bindOpts(unbound_generateTrackList, {getArtistString, link, strings}); + + return { + title: strings('trackPage.title', {track: track.name}), + stylesheet: getAlbumStylesheet(album, {to}), + theme: getThemeString(track.color, [ + `--album-directory: ${album.directory}`, + `--track-directory: ${track.directory}` + ]), + + // disabled for now! shifting banner position per height of page is disorienting + /* + banner: album.bannerArtists && { + classes: ['dim'], + dimensions: album.bannerDimensions, + path: ['media.albumBanner', album.directory], + alt: strings('misc.alt.albumBanner'), + position: 'bottom' + }, + */ + + main: { + content: fixWS` + ${generateCoverLink({ + src: getTrackCover(track), + alt: strings('misc.alt.trackCover'), + tags: track.artTags + })} + <h1>${strings('trackPage.title', {track: track.name})}</h1> + <p> + ${[ + strings('releaseInfo.by', { + artists: getArtistString(track.artists, { + showContrib: true, + showIcons: true + }) + }), + track.coverArtists && strings('releaseInfo.coverArtBy', { + artists: getArtistString(track.coverArtists, { + showContrib: true, + showIcons: true + }) + }), + album.directory !== UNRELEASED_TRACKS_DIRECTORY && strings('releaseInfo.released', { + date: strings.count.date(track.date) + }), + +track.coverArtDate !== +track.date && strings('releaseInfo.artReleased', { + date: strings.count.date(track.coverArtDate) + }), + track.duration && strings('releaseInfo.duration', { + duration: strings.count.duration(track.duration) + }) + ].filter(Boolean).join('<br>\n')} + </p> + <p>${ + (track.urls.length + ? strings('releaseInfo.listenOn', { + links: strings.list.or(track.urls.map(url => fancifyURL(url, {strings}))) + }) + : strings('releaseInfo.listenOn.noLinks')) + }</p> + ${otherReleases.length && fixWS` + <p>${strings('releaseInfo.alsoReleasedAs')}</p> + <ul> + ${otherReleases.map(track => fixWS` + <li>${strings('releaseInfo.alsoReleasedAs.item', { + track: link.track(track), + album: link.album(track.album) + })}</li> + `).join('\n')} + </ul> + `} + ${track.contributors.textContent && fixWS` + <p> + ${strings('releaseInfo.contributors')} + <br> + ${transformInline(track.contributors.textContent)} + </p> + `} + ${track.contributors.length && fixWS` + <p>${strings('releaseInfo.contributors')}</p> + <ul> + ${(track.contributors + .map(contrib => `<li>${getArtistString([contrib], { + showContrib: true, + showIcons: true + })}</li>`) + .join('\n'))} + </ul> + `} + ${tracksReferenced.length && fixWS` + <p>${strings('releaseInfo.tracksReferenced', {track: `<i>${track.name}</i>`})}</p> + ${generateTrackList(tracksReferenced)} + `} + ${tracksThatReference.length && fixWS` + <p>${strings('releaseInfo.tracksThatReference', {track: `<i>${track.name}</i>`})}</p> + ${useDividedReferences && fixWS` + <dl> + ${ttrOfficial.length && fixWS` + <dt>${strings('trackPage.referenceList.official')}</dt> + <dd>${generateTrackList(ttrOfficial)}</dd> + `} + ${ttrFanon.length && fixWS` + <dt>${strings('trackPage.referenceList.fandom')}</dt> + <dd>${generateTrackList(ttrFanon)}</dd> + `} + </dl> + `} + ${!useDividedReferences && generateTrackList(tracksThatReference)} + `} + ${wikiInfo.features.flashesAndGames && flashesThatFeature.length && fixWS` + <p>${strings('releaseInfo.flashesThatFeature', {track: `<i>${track.name}</i>`})}</p> + <ul> + ${flashesThatFeature.map(({ flash, as }) => html.tag('li', + {class: as !== track && 'rerelease'}, + (as === track + ? strings('releaseInfo.flashesThatFeature.item', { + flash: link.flash(flash) + }) + : strings('releaseInfo.flashesThatFeature.item.asDifferentRelease', { + flash: link.flash(flash), + track: link.track(as) + })))).join('\n')} + </ul> + `} + ${track.lyrics && fixWS` + <p>${strings('releaseInfo.lyrics')}</p> + <blockquote> + ${transformLyrics(track.lyrics)} + </blockquote> + `} + ${hasCommentary && fixWS` + <p>${strings('releaseInfo.artistCommentary')}</p> + <blockquote> + ${generateCommentary({link, strings, transformMultiline})} + </blockquote> + `} + ` + }, + + sidebarLeft: generateAlbumSidebar(album, track, { + fancifyURL, + link, + strings, + transformMultiline, + wikiData + }), + + nav: { + links: [ + {toHome: true}, + { + path: ['localized.album', album.directory], + title: album.name + }, + listTag === 'ol' ? { + html: strings('trackPage.nav.track.withNumber', { + number: album.tracks.indexOf(track) + 1, + track: link.track(track, {class: 'current', to}) + }) + } : { + html: strings('trackPage.nav.track', { + track: link.track(track, {class: 'current', to}) + }) + }, + album.tracks.length > 1 && + { + divider: false, + html: generateAlbumNavLinks(album, track, { + generatePreviousNextLinks, + strings + }) + } + ].filter(Boolean), + content: fixWS` + <div> + ${generateAlbumChronologyLinks(album, track, {generateChronologyLinks})} + </div> + ` + } + }; + } + }; + + return [data, page]; +} + |