From 9c11308ace82c024ddb0223d9ffeb742d86ad927 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sat, 2 Jul 2022 15:21:24 -0300 Subject: htmlify album pages --- src/page/album.js | 621 ++++++++++++++++++++++++---------------------------- src/page/track.js | 116 +++++----- src/static/site.css | 3 +- src/upd8.js | 80 +++---- src/util/html.js | 19 +- 5 files changed, 400 insertions(+), 439 deletions(-) diff --git a/src/page/album.js b/src/page/album.js index 12755ae..1cadde0 100644 --- a/src/page/album.js +++ b/src/page/album.js @@ -4,8 +4,6 @@ // Imports -import fixWS from 'fix-whitespace'; - import * as html from '../util/html.js'; import {bindOpts, compareArrays} from '../util/sugar.js'; @@ -31,7 +29,8 @@ export function write(album, {wikiData}) { duration: language.formatDuration(track.duration ?? 0), track: link.track(track), }; - return `
  • ${ + return html.tag('li', + {style: getLinkThemeString(track.color)}, compareArrays( track.artistContribs.map((c) => c.who), album.artistContribs.map((c) => c.who), @@ -40,14 +39,12 @@ export function write(album, {wikiData}) { ? language.$('trackList.item.withDuration', itemOpts) : language.$('trackList.item.withDuration.withArtists', { ...itemOpts, - by: `${language.$( - 'trackList.item.withArtists.by', - { + by: html.tag('span', + {class: 'by'}, + language.$('trackList.item.withArtists.by', { artists: getArtistString(track.artistContribs), - } - )}`, - }) - }
  • `; + })), + })); }; const hasCommentaryEntries = @@ -55,6 +52,11 @@ export function write(album, {wikiData}) { const hasAdditionalFiles = album.additionalFiles?.length > 0; const albumDuration = getTotalDuration(album.tracks); + const displayTrackGroups = + album.trackGroups && + (album.trackGroups.length > 1 || + !album.trackGroups[0].isDefaultTrackGroup); + const listTag = getAlbumListTag(album); const data = { @@ -142,203 +144,158 @@ export function write(album, {wikiData}) { }, main: { - content: fixWS` - ${ - cover && - generateCoverLink({ - src: cover, - alt: language.$('misc.alt.albumCover'), - tags: album.artTags, - }) - } -

    ${language.$('albumPage.title', { - album: album.name, - })}

    -

    - ${[ - album.artistContribs.length && - language.$('releaseInfo.by', { - artists: getArtistString( - album.artistContribs, - { - showContrib: true, - showIcons: true, - } - ), - }), - album.coverArtistContribs.length && - language.$('releaseInfo.coverArtBy', { - artists: getArtistString( - album.coverArtistContribs, - { - showContrib: true, - showIcons: true, - } - ), - }), - album.wallpaperArtistContribs.length && - language.$('releaseInfo.wallpaperArtBy', { - artists: getArtistString( - album.wallpaperArtistContribs, - { - showContrib: true, - showIcons: true, - } - ), - }), - album.bannerArtistContribs.length && - language.$('releaseInfo.bannerArtBy', { - artists: getArtistString( - album.bannerArtistContribs, - { - showContrib: true, - showIcons: true, - } - ), - }), - album.date && - language.$('releaseInfo.released', { - date: language.formatDate(album.date), - }), - album.coverArtDate && - +album.coverArtDate !== +album.date && - language.$('releaseInfo.artReleased', { - date: language.formatDate(album.coverArtDate), - }), - language.$('releaseInfo.duration', { - duration: language.formatDuration( - albumDuration, - { - approximate: album.tracks.length > 1, - } - ), - }), - ] - .filter(Boolean) - .join('
    \n')} -

    - ${ - (hasAdditionalFiles || hasCommentaryEntries) && - fixWS`

    - ${[ - hasAdditionalFiles && - generateAdditionalFilesShortcut( - album.additionalFiles, - { - language, - } - ), - hasCommentaryEntries && - language.$('releaseInfo.viewCommentary', { - link: link.albumCommentary(album, { - text: language.$( - 'releaseInfo.viewCommentary.link' - ), - }), - }), - ] - .filter(Boolean) - .join('
    \n')}

    ` - } - ${ - album.urls?.length && - `

    ${language.$('releaseInfo.listenOn', { - links: language.formatDisjunctionList( - album.urls.map((url) => - fancifyURL(url, {album: true}) - ) - ), - })}

    ` - } - ${ - album.trackGroups && - (album.trackGroups.length > 1 || - !album.trackGroups[0].isDefaultTrackGroup) - ? fixWS` -
    - ${album.trackGroups - .map( - ({ - name, - startIndex, - tracks, - }) => fixWS` -
    ${language.$( - 'trackList.section.withDuration', - { - duration: language.formatDuration( - getTotalDuration(tracks), - { - approximate: tracks.length > 1, - } - ), - section: name, - } - )}
    -
    <${ - listTag === 'ol' - ? `ol start="${startIndex + 1}"` - : listTag - }> - ${tracks - .map(trackToListItem) - .join('\n')} -
    - ` - ) - .join('\n')} -
    - ` - : fixWS` - <${listTag}> - ${album.tracks.map(trackToListItem).join('\n')} - - ` - } - ${ - album.dateAddedToWiki && - fixWS` -

    - ${[ - language.$('releaseInfo.addedToWiki', { - date: language.formatDate( - album.dateAddedToWiki - ), - }), - ] - .filter(Boolean) - .join('
    \n')} -

    - ` - } - ${ - hasAdditionalFiles && - generateAdditionalFilesList(album.additionalFiles, { - // TODO: Kinda near the metal here... - getFileSize: (file) => - getSizeOfAdditionalFile( - urls - .from('media.root') - .to( - 'media.albumAdditionalFile', - album.directory, - file - ) - ), - linkFile: (file) => - link.albumAdditionalFile({album, file}), - }) - } - ${ - album.commentary && - fixWS` -

    ${language.$('releaseInfo.artistCommentary')}

    -
    - ${transformMultiline(album.commentary)} -
    - ` - } - `, + content: [ + cover && generateCoverLink({ + src: cover, + alt: language.$('misc.alt.albumCover'), + tags: album.artTags, + }), + + html.tag('h1', language.$('albumPage.title', { + album: album.name, + })), + + html.tag('p', + { + [html.onlyIfContent]: true, + [html.joinChildren]: '
    ', + }, + [ + album.artistContribs.length && + language.$('releaseInfo.by', { + artists: getArtistString(album.artistContribs, { + showContrib: true, + showIcons: true, + }), + }), + + album.coverArtistContribs.length && + language.$('releaseInfo.coverArtBy', { + artists: getArtistString(album.coverArtistContribs, { + showContrib: true, + showIcons: true, + }), + }), + + album.wallpaperArtistContribs.length && + language.$('releaseInfo.wallpaperArtBy', { + artists: getArtistString(album.wallpaperArtistContribs, { + showContrib: true, + showIcons: true, + }), + }), + + album.bannerArtistContribs.length && + language.$('releaseInfo.bannerArtBy', { + artists: getArtistString(album.bannerArtistContribs, { + showContrib: true, + showIcons: true, + }), + }), + + album.date && + language.$('releaseInfo.released', { + date: language.formatDate(album.date), + }), + + album.coverArtDate && + +album.coverArtDate !== +album.date && + language.$('releaseInfo.artReleased', { + date: language.formatDate(album.coverArtDate), + }), + + album.duration && + language.$('releaseInfo.duration', { + duration: language.formatDuration(albumDuration, { + approximate: album.tracks.length > 1, + }), + }), + ]), + + html.tag('p', + { + [html.onlyIfContent]: true, + [html.joinChildren]: '
    ', + }, + [ + hasAdditionalFiles && + generateAdditionalFilesShortcut(album.additionalFiles, { + language, + }), + + hasCommentaryEntries && + language.$('releaseInfo.viewCommentary', { + link: link.albumCommentary(album, { + text: language.$('releaseInfo.viewCommentary.link'), + }), + }), + ]), + + album.urls?.length && + html.tag('p', + language.$('releaseInfo.listenOn', { + links: language.formatDisjunctionList( + album.urls.map(url => fancifyURL(url, {album: true})) + ), + })), + + displayTrackGroups && + html.tag('dl', + {class: 'album-group-list'}, + album.trackGroups.flatMap(({ + name, + startIndex, + tracks, + }) => [ + html.tag('dt', + language.$('trackList.section.withDuration', { + duration: language.formatDuration(getTotalDuration(tracks), { + approximate: tracks.length > 1, + }), + section: name, + })), + html.tag('dd', + html.tag(listTag, + listTag === 'ol' ? {start: startIndex + 1} : {}, + tracks.map(trackToListItem))), + ])), + + !displayTrackGroups && + html.tag(listTag, + album.tracks.map(trackToListItem)), + + html.tag('p', + { + [html.onlyIfContent]: true, + [html.joinChildren]: '
    ', + }, + [ + album.dateAddedToWiki && + language.$('releaseInfo.addedToWiki', { + date: language.formatDate( + album.dateAddedToWiki + ), + }) + ]), + + hasAdditionalFiles && + generateAdditionalFilesList(album.additionalFiles, { + // TODO: Kinda near the metal here... + getFileSize: (file) => + getSizeOfAdditionalFile( + urls.from('media.root').to( + 'media.albumAdditionalFile', + album.directory, + file)), + linkFile: (file) => + link.albumAdditionalFile({album, file}), + }), + + ...album.commentary ? [ + html.tag('p', language.$('releaseInfo.artistCommentary')), + html.tag('blockquote', transformMultiline(album.commentary)), + ] : [], + ], }, sidebarLeft: generateAlbumSidebar(album, null, { @@ -387,81 +344,66 @@ export function generateAlbumSidebar(album, currentTrack, { language, transformMultiline, }) { - const listTag = getAlbumListTag(album); + const isAlbumPage = !currentTrack; + const isTrackPage = !!currentTrack; - /* - const trackGroups = album.trackGroups || [{ - name: language.$('albumSidebar.trackList.fallbackGroupName'), - color: album.color, - startIndex: 0, - tracks: album.tracks - }]; - */ + const listTag = getAlbumListTag(album); const {trackGroups} = album; const trackToListItem = (track) => - html.tag( - 'li', + html.tag('li', {class: track === currentTrack && 'current'}, language.$('albumSidebar.trackList.item', { track: link.track(track), - }) - ); + })); const nameOrDefault = (isDefaultTrackGroup, name) => isDefaultTrackGroup ? language.$('albumSidebar.trackList.fallbackGroupName') : name; - const trackListPart = fixWS` -

    ${link.album(album)}

    - ${trackGroups - .map(({name, color, startIndex, tracks, isDefaultTrackGroup}) => - html.tag( - 'details', - { - // Leave side8ar track groups collapsed on al8um homepage, - // since there's already a view of all the groups expanded - // in the main content area. - open: currentTrack && tracks.includes(currentTrack), - class: tracks.includes(currentTrack) && 'current', - }, - [ - html.tag( - 'summary', - {style: getLinkThemeString(color)}, - listTag === 'ol' - ? language.$('albumSidebar.trackList.group.withRange', { - group: `${nameOrDefault( - isDefaultTrackGroup, - name - )}`, - range: `${startIndex + 1}–${ - startIndex + tracks.length - }`, - }) - : language.$('albumSidebar.trackList.group', { - group: `${nameOrDefault( - isDefaultTrackGroup, - name - )}`, - }) - ), - fixWS` - <${ - listTag === 'ol' - ? `ol start="${startIndex + 1}"` - : listTag - }> - ${tracks.map(trackToListItem).join('\n')} - - `, - ] - ) - ) - .join('\n')} - `; + const trackListPart = [ + html.tag('h1', link.album(album)), + ...trackGroups.map(({name, color, startIndex, tracks, isDefaultTrackGroup}) => { + const groupName = + html.tag('span', + {class: 'group-name'}, + nameOrDefault( + isDefaultTrackGroup, + name + )); + return html.tag('details', + { + // Leave side8ar track groups collapsed on al8um homepage, + // since there's already a view of all the groups expanded + // in the main content area. + open: isTrackPage && tracks.includes(currentTrack), + class: tracks.includes(currentTrack) && 'current', + }, + [ + html.tag( + 'summary', + {style: getLinkThemeString(color)}, + [ + listTag === 'ol' && + language.$('albumSidebar.trackList.group.withRange', { + group: groupName, + range: `${startIndex + 1}–${ + startIndex + tracks.length + }`, + }), + listTag === 'ul' && + language.$('albumSidebar.trackList.group', { + group: groupName, + }), + ]), + html.tag(listTag, + listTag === 'ol' ? {start: startIndex + 1} : {}, + tracks.map(trackToListItem)), + ]); + }), + ]; const {groups} = album; @@ -473,49 +415,47 @@ export function generateAlbumSidebar(album, currentTrack, { const previous = index > 0 && albums[index - 1]; return {group, next, previous}; }) - .map( - ({group, next, previous}) => fixWS` -

    ${language.$('albumSidebar.groupBox.title', { - group: link.groupInfo(group), - })}

    - ${!currentTrack && transformMultiline(group.descriptionShort)} - ${ - group.urls?.length && - `

    ${language.$('releaseInfo.visitOn', { - links: language.formatDisjunctionList( - group.urls.map((url) => fancifyURL(url)) - ), - })}

    ` - } - ${ - !currentTrack && - fixWS` - ${ - next && - `` - } - ${ - previous && - `` - } - ` - } - ` - ); + // This is a map and not a flatMap because the distinction between which + // group sets of elements belong to matters. That means this variable is an + // array of arrays, and we'll need to treat it as such later! + .map(({group, next, previous}) => [ + html.tag('h1', language.$('albumSidebar.groupBox.title', { + group: link.groupInfo(group), + })), + + isAlbumPage && + transformMultiline(group.descriptionShort), + + group.urls?.length && + html.tag('p', language.$('releaseInfo.visitOn', { + links: language.formatDisjunctionList( + group.urls.map((url) => fancifyURL(url)) + ), + })), + + ...isAlbumPage ? [ + next && + html.tag('p', + {class: 'group-chronology-link'}, + language.$('albumSidebar.groupBox.next', { + album: link.album(next), + })), + + previous && + html.tag('p', + {class: 'group-chronology-link'}, + language.$('albumSidebar.groupBox.previous', { + album: link.album(previous), + })), + ] : [], + ]); if (groupParts.length) { - if (currentTrack) { - const combinedGroupPart = groupParts.join('\n
    \n'); + if (isTrackPage) { + const combinedGroupPart = + groupParts + .map(groupPart => groupPart.filter(Boolean).join('\n')) + .join('\n
    \n'); return { multiple: [trackListPart, combinedGroupPart], }; @@ -536,6 +476,8 @@ export function generateAlbumSecondaryNav( currentTrack, {link, language, getLinkThemeString} ) { + const isAlbumPage = !currentTrack; + const {groups} = album; if (!groups.length) { @@ -552,20 +494,21 @@ export function generateAlbumSecondaryNav( }) .map(({group, next, previous}) => { const previousNext = - !currentTrack && - [ - previous && - link.album(previous, { - color: false, - text: language.$('misc.nav.previous'), - }), - next && - link.album(next, { - color: false, - text: language.$('misc.nav.next'), - }), - ].filter(Boolean); - return html.tag('span', {style: getLinkThemeString(group.color)}, [ + isAlbumPage && + [ + previous && + link.album(previous, { + color: false, + text: language.$('misc.nav.previous'), + }), + next && + link.album(next, { + color: false, + text: language.$('misc.nav.next'), + }), + ].filter(Boolean); + return html.tag('span', + {style: getLinkThemeString(group.color)}, [ language.$('albumSidebar.groupBox.title', { group: link.groupInfo(group), }), @@ -574,8 +517,8 @@ export function generateAlbumSecondaryNav( }); return { - classes: ['dot-between-spans'], - content: groupParts.join('\n'), + classes: ['nav-links-groups'], + content: groupParts, }; } @@ -584,18 +527,21 @@ export function generateAlbumNavLinks( currentTrack, {generatePreviousNextLinks, language} ) { + const isTrackPage = !!currentTrack; + if (album.tracks.length <= 1) { return ''; } const previousNextLinks = - currentTrack && - generatePreviousNextLinks(currentTrack, { - data: album.tracks, - linkKey: 'track', - }); + isTrackPage && + generatePreviousNextLinks(currentTrack, { + data: album.tracks, + linkKey: 'track', + }); + const randomLink = `${ - currentTrack + isTrackPage ? language.$('trackPage.nav.random') : language.$('albumPage.nav.randomTrack') }`; @@ -610,6 +556,8 @@ export function generateAlbumChronologyLinks( currentTrack, {generateChronologyLinks} ) { + const isTrackPage = !!currentTrack; + return html.tag( 'div', { @@ -617,7 +565,7 @@ export function generateAlbumChronologyLinks( class: 'nav-chronology-links', }, [ - currentTrack && + isTrackPage && generateChronologyLinks(currentTrack, { contribKey: 'artistContribs', getThings: (artist) => [ @@ -626,7 +574,8 @@ export function generateAlbumChronologyLinks( ], headingString: 'misc.chronology.heading.track', }), - currentTrack && + + isTrackPage && generateChronologyLinks(currentTrack, { contribKey: 'contributorContribs', getThings: (artist) => [ @@ -635,6 +584,7 @@ export function generateAlbumChronologyLinks( ], headingString: 'misc.chronology.heading.track', }), + generateChronologyLinks(currentTrack || album, { contribKey: 'coverArtistContribs', dateKey: 'coverArtDate', @@ -644,8 +594,5 @@ export function generateAlbumChronologyLinks( ], headingString: 'misc.chronology.heading.coverArt', }), - ] - .filter(Boolean) - .join('\n') - ); + ]); } diff --git a/src/page/track.js b/src/page/track.js index edc8c20..436205b 100644 --- a/src/page/track.js +++ b/src/page/track.js @@ -4,8 +4,6 @@ // Imports -import fixWS from 'fix-whitespace'; - import { generateAlbumChronologyLinks, generateAlbumNavLinks, @@ -217,44 +215,55 @@ export function write(track, {wikiData}) { html.tag('h1', language.$('trackPage.title', {track: track.name})), - html.tag('p', [ - language.$('releaseInfo.by', { - artists: getArtistString(track.artistContribs, { - showContrib: true, - showIcons: true, - }), - }), - track.coverArtistContribs.length && language.$('releaseInfo.coverArtBy', { - artists: getArtistString( - track.coverArtistContribs, - { - showContrib: true, - showIcons: true, - } - ), - }), - track.date && language.$('releaseInfo.released', { - date: language.formatDate(track.date), - }), - track.coverArtDate && +track.coverArtDate !== +track.date && - language.$('releaseInfo.artReleased', { - date: language.formatDate(track.coverArtDate), - }), - track.duration && language.$('releaseInfo.duration', { - duration: language.formatDuration( - track.duration - ), - }), - ].filter(Boolean).join('
    \n')), + html.tag('p', + { + [html.onlyIfContent]: true, + [html.joinChildren]: '
    ', + }, + [ + track.artistContribs.length && + language.$('releaseInfo.by', { + artists: getArtistString(track.artistContribs, { + showContrib: true, + showIcons: true, + }), + }), + + track.coverArtistContribs.length && + language.$('releaseInfo.coverArtBy', { + artists: getArtistString( + track.coverArtistContribs, + { + showContrib: true, + showIcons: true, + } + ), + }), + + track.date && + language.$('releaseInfo.released', { + date: language.formatDate(track.date), + }), + + track.coverArtDate && + +track.coverArtDate !== +track.date && + language.$('releaseInfo.artReleased', { + date: language.formatDate(track.coverArtDate), + }), + + track.duration && + language.$('releaseInfo.duration', { + duration: language.formatDuration( + track.duration + ), + }), + ]), html.tag('p', (track.urls?.length ? language.$('releaseInfo.listenOn', { links: language.formatDisjunctionList( - track.urls.map((url) => - fancifyURL(url, {language}) - ) - ), + track.urls.map(url => fancifyURL(url, {language}))), }) : language.$('releaseInfo.listenOn.noLinks'))), @@ -323,7 +332,7 @@ export function write(track, {wikiData}) { transformMultiline, })), ] : [], - ].filter(Boolean).join('\n'), + ], }, sidebarLeft: generateAlbumSidebar(album, track, { @@ -343,28 +352,31 @@ export function write(track, {wikiData}) { path: ['localized.album', album.directory], title: album.name, }, - listTag === 'ol' - ? { - html: language.$('trackPage.nav.track.withNumber', { - number: album.tracks.indexOf(track) + 1, - track: link.track(track, {class: 'current', to}), - }), - } - : { - html: language.$('trackPage.nav.track', { - track: link.track(track, {class: 'current', to}), - }), - }, + listTag === 'ol' && + { + html: language.$('trackPage.nav.track.withNumber', { + number: album.tracks.indexOf(track) + 1, + track: link.track(track, {class: 'current', to}), + }), + }, + listTag === 'ul' && + { + html: language.$('trackPage.nav.track', { + track: link.track(track, {class: 'current', to}), + }), + }, ].filter(Boolean), + content: generateAlbumChronologyLinks(album, track, { generateChronologyLinks, }), + bottomRowContent: album.tracks.length > 1 && - generateAlbumNavLinks(album, track, { - generatePreviousNextLinks, - language, - }), + generateAlbumNavLinks(album, track, { + generatePreviousNextLinks, + language, + }), }, secondaryNav: generateAlbumSecondaryNav(album, track, { diff --git a/src/static/site.css b/src/static/site.css index d80c57c..328ef7d 100644 --- a/src/static/site.css +++ b/src/static/site.css @@ -165,7 +165,8 @@ a:hover { font-weight: 800; } -.nav-links-index > span:not(:first-child):not(.no-divider)::before { +.nav-links-index > span:not(:first-child):not(.no-divider)::before, +.nav-links-groups > span:not(:first-child):not(.no-divider)::before { content: "\0020\00b7\0020"; font-weight: 800; } diff --git a/src/upd8.js b/src/upd8.js index 0399b29..83eecb4 100755 --- a/src/upd8.js +++ b/src/upd8.js @@ -149,7 +149,7 @@ import FileSizePreloader from './file-size-preloader.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const CACHEBUST = 10; +const CACHEBUST = 11; const DEFAULT_STRINGS_FILE = 'strings-default.json'; @@ -951,33 +951,28 @@ writePage.html = ( const mainHTML = main.content && - html.tag( - 'main', + html.tag('main', { id: 'content', class: main.classes, }, - main.content - ); + main.content); const footerHTML = footer.content && - html.tag( - 'footer', + html.tag('footer', { id: 'footer', class: footer.classes, }, - footer.content - ); + footer.content); const generateSidebarHTML = ( id, {content, multiple, classes, collapse = true, wide = false} ) => content - ? html.tag( - 'div', + ? html.tag('div', { id, class: [ @@ -988,11 +983,9 @@ writePage.html = ( ...classes, ], }, - content - ) + content) : multiple - ? html.tag( - 'div', + ? html.tag('div', { id, class: [ @@ -1003,9 +996,7 @@ writePage.html = ( ], }, multiple.map((content) => - html.tag('div', {class: ['sidebar', ...classes]}, content) - ) - ) + html.tag('div', {class: ['sidebar', ...classes]}, content))) : ''; const sidebarLeftHTML = generateSidebarHTML('sidebar-left', sidebarLeft); @@ -1064,17 +1055,14 @@ writePage.html = ( partContent = html.tag('a', attributes, linkTitle); } - const part = html.tag( - 'span', + const part = html.tag('span', {class: cur.divider === false && 'no-divider'}, - partContent - ); + partContent); navLinkParts.push(part); } - const navHTML = html.tag( - 'nav', + const navHTML = html.tag('nav', { [html.onlyIfContent]: true, id: 'header', @@ -1095,18 +1083,15 @@ writePage.html = ( nav.content && html.tag('div', {class: 'nav-content'}, nav.content), nav.bottomRowContent && html.tag('div', {class: 'nav-bottom-row'}, nav.bottomRowContent), - ] - ); + ]); - const secondaryNavHTML = html.tag( - 'nav', + const secondaryNavHTML = html.tag('nav', { [html.onlyIfContent]: true, id: 'secondary-nav', class: secondaryNav.classes, }, - [secondaryNav.content] - ); + secondaryNav.content); const bannerSrc = banner.src ? banner.src @@ -1117,8 +1102,7 @@ writePage.html = ( const bannerHTML = banner.position && bannerSrc && - html.tag( - 'div', + html.tag('div', { id: 'banner', class: banner.classes, @@ -1128,23 +1112,27 @@ writePage.html = ( alt: banner.alt, width: banner.dimensions[0] || 1100, height: banner.dimensions[1] || 200, - }) - ); + })); const layoutHTML = [ navHTML, banner.position === 'top' && bannerHTML, secondaryNavHTML, - html.tag( - 'div', - {class: ['layout-columns', !collapseSidebars && 'vertical-when-thin']}, - [sidebarLeftHTML, mainHTML, sidebarRightHTML] - ), + html.tag('div', + { + class: [ + 'layout-columns', + !collapseSidebars && 'vertical-when-thin', + ], + }, + [ + sidebarLeftHTML, + mainHTML, + sidebarRightHTML, + ]), banner.position === 'bottom' && bannerHTML, footerHTML, - ] - .filter(Boolean) - .join('\n'); + ].filter(Boolean).join('\n'); const infoCardHTML = fixWS`
    @@ -1197,23 +1185,25 @@ writePage.html = ( const socialEmbedHTML = [ socialEmbed.title && html.tag('meta', {property: 'og:title', content: socialEmbed.title}), + socialEmbed.description && html.tag('meta', { property: 'og:description', content: socialEmbed.description, }), + socialEmbed.image && html.tag('meta', {property: 'og:image', content: socialEmbed.image}), + socialEmbed.color && html.tag('meta', {name: 'theme-color', content: socialEmbed.color}), + oEmbedJSONHref && html.tag('link', { type: 'application/json+oembed', href: oEmbedJSONHref, }), - ] - .filter(Boolean) - .join('\n'); + ].filter(Boolean).join('\n'); return filterEmptyLines(fixWS` diff --git a/src/util/html.js b/src/util/html.js index 0ba923b..338df71 100644 --- a/src/util/html.js +++ b/src/util/html.js @@ -20,11 +20,18 @@ export const selfClosingTags = [ 'wbr', ]; -// Pass to tag() as an attri8utes key to make tag() return a 8lank string -// if the provided content is empty. Useful for when you'll only 8e showing -// an element according to the presence of content that would 8elong there. +// Pass to tag() as an attributes key to make tag() return a 8lank string if the +// provided content is empty. Useful for when you'll only 8e showing an element +// according to the presence of content that would 8elong there. export const onlyIfContent = Symbol(); +// Pass to tag() as an attributes key to make children be joined together by the +// provided string. This is handy, for example, for joining lines by
    tags, +// or putting some other divider between each child. Note this will only have an +// effect if the tag content is passed as an array of children and not a single +// string. +export const joinChildren = Symbol(); + export function tag(tagName, ...args) { const selfClosing = selfClosingTags.includes(tagName); @@ -59,7 +66,11 @@ export function tag(tagName, ...args) { } if (Array.isArray(content)) { - content = content.filter(Boolean).join('\n'); + const joiner = attrs?.[joinChildren]; + content = content.filter(Boolean).join( + (joiner + ? `\n${joiner}\n` + : '\n')); } if (content) { -- cgit 1.3.0-6-gf8a5