From b2469c03bd4bdb29c5e80752f812203a6755c159 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 4 Jun 2021 17:30:16 -0300 Subject: move around a bunch of utility functions --- src/misc-templates.js | 369 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 src/misc-templates.js (limited to 'src/misc-templates.js') diff --git a/src/misc-templates.js b/src/misc-templates.js new file mode 100644 index 0000000..d4e4af3 --- /dev/null +++ b/src/misc-templates.js @@ -0,0 +1,369 @@ +// Miscellaneous utility functions which are useful across page specifications. +// These are made available right on a page spec's ({wikiData, strings, ...}) +// args object! + +import fixWS from 'fix-whitespace'; + +import * as html from './util/html.js'; + +import { + getColors +} from './util/colors.js'; + +import { + UNRELEASED_TRACKS_DIRECTORY +} from './util/magic-constants.js'; + +import { + unique +} from './util/sugar.js'; + +import { + getTotalDuration, + sortByDate +} from './util/wiki-data.js'; + +// Artist strings + +export function getArtistString(artists, { + iconifyURL, link, strings, + showIcons = false, + showContrib = false +}) { + return strings.list.and(artists.map(({ who, what }) => { + const { urls, directory, name } = who; + return [ + link.artist(who), + showContrib && what && `(${what})`, + showIcons && urls.length && `(${ + strings.list.unit(urls.map(url => iconifyURL(url, {strings}))) + })` + ].filter(Boolean).join(' '); + })); +} + +// Chronology links + +export function generateChronologyLinks(currentThing, { + contribKey, + getThings, + headingString, + link, + linkAnythingMan, + strings, + wikiData +}) { + const { albumData } = wikiData; + + const contributions = currentThing[contribKey]; + if (!contributions) { + return ''; + } + + if (contributions.length > 8) { + return `
${strings('misc.chronology.seeArtistPages')}
`; + } + + return contributions.map(({ who: artist }) => { + const things = sortByDate(unique(getThings(artist))); + const releasedThings = things.filter(thing => { + const album = albumData.includes(thing) ? thing : thing.album; + return !(album && album.directory === UNRELEASED_TRACKS_DIRECTORY); + }); + const index = releasedThings.indexOf(currentThing); + + if (index === -1) return ''; + + // TODO: This can pro8a8ly 8e made to use generatePreviousNextLinks? + // We'd need to make generatePreviousNextLinks use toAnythingMan tho. + const previous = releasedThings[index - 1]; + const next = releasedThings[index + 1]; + const parts = [ + previous && linkAnythingMan(previous, { + color: false, + text: strings('misc.nav.previous') + }), + next && linkAnythingMan(next, { + color: false, + text: strings('misc.nav.next') + }) + ].filter(Boolean); + + const stringOpts = { + index: strings.count.index(index + 1, {strings}), + artist: link.artist(artist) + }; + + return fixWS` +
+ ${strings(headingString, stringOpts)} + ${parts.length && `(${parts.join(', ')})`} +
+ `; + }).filter(Boolean).join('\n'); +} + +// Content warning tags + +export function getRevealStringFromWarnings(warnings, {strings}) { + return strings('misc.contentWarnings', {warnings}) + `
${strings('misc.contentWarnings.reveal')}` +} + +export function getRevealStringFromTags(tags, {strings}) { + return tags && tags.some(tag => tag.isCW) && ( + getRevealStringFromWarnings(strings.list.unit(tags.filter(tag => tag.isCW).map(tag => tag.name)), {strings})); +} + +// Cover art links + +export function generateCoverLink({ + img, link, strings, to, wikiData, + src, + path, + alt, + tags = [] +}) { + const { wikiInfo } = wikiData; + + if (!src && path) { + src = to(...path); + } + + if (!src) { + throw new Error(`Expected src or path`); + } + + return fixWS` +
+ ${img({ + src, + alt, + thumb: 'medium', + id: 'cover-art', + link: true, + square: true, + reveal: getRevealStringFromTags(tags, {strings}) + })} + ${wikiInfo.features.artTagUI && tags.filter(tag => !tag.isCW).length && fixWS` +

+ ${strings('releaseInfo.artTags')} + ${(tags + .filter(tag => !tag.isCW) + .map(link.tag) + .join(',\n'))} +

+ `} +
+ `; +} + +// CSS & color shenanigans + +export function getThemeString(color, additionalVariables = []) { + if (!color) return ''; + + const { primary, dim, bg } = getColors(color); + + const variables = [ + `--primary-color: ${primary}`, + `--dim-color: ${dim}`, + `--bg-color: ${bg}`, + ...additionalVariables + ].filter(Boolean); + + if (!variables.length) return ''; + + return ( + `:root {\n` + + variables.map(line => ` ` + line + ';\n').join('') + + `}` + ); +} +export function getAlbumStylesheet(album, {to}) { + return [ + album.wallpaperArtists && fixWS` + body::before { + background-image: url("${to('media.albumWallpaper', album.directory)}"); + ${album.wallpaperStyle} + } + `, + album.bannerStyle && fixWS` + #banner img { + ${album.bannerStyle} + } + ` + ].filter(Boolean).join('\n'); +} + +// Fancy lookin' links + +export function fancifyURL(url, {strings, album = false} = {}) { + const domain = new URL(url).hostname; + return fixWS`${ + domain.includes('bandcamp.com') ? strings('misc.external.bandcamp') : + [ + 'music.solatrux.com' + ].includes(domain) ? strings('misc.external.bandcamp.domain', {domain}) : + [ + 'types.pl' + ].includes(domain) ? strings('misc.external.mastodon.domain', {domain}) : + domain.includes('youtu') ? (album + ? (url.includes('list=') + ? strings('misc.external.youtube.playlist') + : strings('misc.external.youtube.fullAlbum')) + : strings('misc.external.youtube')) : + domain.includes('soundcloud') ? strings('misc.external.soundcloud') : + domain.includes('tumblr.com') ? strings('misc.external.tumblr') : + domain.includes('twitter.com') ? strings('misc.external.twitter') : + domain.includes('deviantart.com') ? strings('misc.external.deviantart') : + domain.includes('wikipedia.org') ? strings('misc.external.wikipedia') : + domain.includes('poetryfoundation.org') ? strings('misc.external.poetryFoundation') : + domain.includes('instagram.com') ? strings('misc.external.instagram') : + domain.includes('patreon.com') ? strings('misc.external.patreon') : + domain + }`; +} + +export function fancifyFlashURL(url, flash, {strings}) { + const link = fancifyURL(url, {strings}); + return `${ + url.includes('homestuck.com') ? (isNaN(Number(flash.page)) + ? strings('misc.external.flash.homestuck.secret', {link}) + : strings('misc.external.flash.homestuck.page', {link, page: flash.page})) : + url.includes('bgreco.net') ? strings('misc.external.flash.bgreco', {link}) : + url.includes('youtu') ? strings('misc.external.flash.youtube', {link}) : + link + }`; +} + +export function iconifyURL(url, {strings, to}) { + const domain = new URL(url).hostname; + const [ id, msg ] = ( + domain.includes('bandcamp.com') ? ['bandcamp', strings('misc.external.bandcamp')] : + ( + domain.includes('music.solatrus.com') + ) ? ['bandcamp', strings('misc.external.bandcamp.domain', {domain})] : + ( + domain.includes('types.pl') + ) ? ['mastodon', strings('misc.external.mastodon.domain', {domain})] : + domain.includes('youtu') ? ['youtube', strings('misc.external.youtube')] : + domain.includes('soundcloud') ? ['soundcloud', strings('misc.external.soundcloud')] : + domain.includes('tumblr.com') ? ['tumblr', strings('misc.external.tumblr')] : + domain.includes('twitter.com') ? ['twitter', strings('misc.external.twitter')] : + domain.includes('deviantart.com') ? ['deviantart', strings('misc.external.deviantart')] : + domain.includes('instagram.com') ? ['instagram', strings('misc.external.bandcamp')] : + ['globe', strings('misc.external.domain', {domain})] + ); + return fixWS`${msg}`; +} + +// Grids + +export function getGridHTML({ + getLinkThemeString, + img, + strings, + + entries, + srcFn, + hrefFn, + altFn = () => '', + detailsFn = null, + lazy = true +}) { + return entries.map(({ large, item }, i) => html.tag('a', + { + class: ['grid-item', 'box', large && 'large-grid-item'], + href: hrefFn(item), + style: getLinkThemeString(item.color) + }, + fixWS` + ${img({ + src: srcFn(item), + alt: altFn(item), + thumb: 'small', + lazy: (typeof lazy === 'number' ? i >= lazy : lazy), + square: true, + reveal: getRevealStringFromTags(item.artTags, {strings}) + })} + ${item.name} + ${detailsFn && `${detailsFn(item)}`} + `)).join('\n'); +} + +export function getAlbumGridHTML({ + getAlbumCover, getGridHTML, strings, to, + details = false, + ...props +}) { + return getGridHTML({ + srcFn: getAlbumCover, + hrefFn: album => to('localized.album', album.directory), + detailsFn: details && (album => strings('misc.albumGridDetails', { + tracks: strings.count.tracks(album.tracks.length, {unit: true}), + time: strings.count.duration(getTotalDuration(album.tracks)) + })), + ...props + }); +} + +export function getFlashGridHTML({ + getFlashCover, getGridHTML, to, + ...props +}) { + return getGridHTML({ + srcFn: getFlashCover, + hrefFn: flash => to('localized.flash', flash.directory), + ...props + }); +} +// Nav-bar links + +export function generateInfoGalleryLinks(currentThing, isGallery, { + link, strings, + linkKeyGallery, + linkKeyInfo +}) { + return [ + link[linkKeyInfo](currentThing, { + class: isGallery ? '' : 'current', + text: strings('misc.nav.info') + }), + link[linkKeyGallery](currentThing, { + class: isGallery ? 'current' : '', + text: strings('misc.nav.gallery') + }) + ].join(', '); +} + +export function generatePreviousNextLinks(current, { + data, + link, + linkKey, + strings +}) { + const linkFn = link[linkKey]; + + const index = data.indexOf(current); + const previous = data[index - 1]; + const next = data[index + 1]; + + return [ + previous && linkFn(previous, { + attributes: { + id: 'previous-button', + title: previous.name + }, + text: strings('misc.nav.previous'), + color: false + }), + next && linkFn(next, { + attributes: { + id: 'next-button', + title: next.name + }, + text: strings('misc.nav.next'), + color: false + }) + ].filter(Boolean).join(', '); +} -- cgit 1.3.0-6-gf8a5