diff options
-rw-r--r-- | common/common.js | 1 | ||||
-rw-r--r-- | static/site.css | 31 | ||||
-rw-r--r-- | upd8.js | 92 |
3 files changed, 118 insertions, 6 deletions
diff --git a/common/common.js b/common/common.js index 8fd16129..b8eae480 100644 --- a/common/common.js +++ b/common/common.js @@ -77,6 +77,7 @@ const C = { FEEDBACK_DIRECTORY: 'feedback', CHANGELOG_DIRECTORY: 'changelog', FLASH_DIRECTORY: 'flash', + NEWS_DIRECTORY: 'news', JS_DISABLED_DIRECTORY: 'js-disabled', UNRELEASED_TRACKS_DIRECTORY: 'unreleased-tracks', diff --git a/static/site.css b/static/site.css index f9e26a7c..abde862c 100644 --- a/static/site.css +++ b/static/site.css @@ -153,28 +153,31 @@ a:hover { flex-grow: 1; } +#sidebar > h1, +#sidebar > h2, +#sidebar > h3, +#sidebar > p { + text-align: center; +} + #sidebar h1 { font-size: 1.25em; - text-align: center; } #sidebar h2 { font-size: 1.1em; - text-align: center; margin: 0; } #sidebar h3 { font-size: 1.1em; - text-align: center; font-style: oblique; font-variant: small-caps; margin-top: 0.3em; margin-bottom: 0em; } -#sidebar p { - text-align: center; +#sidebar > p { margin: 0.5em 0; } @@ -227,6 +230,24 @@ a:hover { overflow-wrap: break-word; } +#sidebar article { + text-align: left; + margin: 5px 5px 15px 5px; +} + +#sidebar article:last-child { + margin-bottom: 5px; +} + +#sidebar article h2 { + border-bottom: 1px dotted white; +} + +#sidebar article h2 time { + float: right; + font-weight: normal; +} + #cover-art { float: right; width: 40%; diff --git a/upd8.js b/upd8.js index 36d948f8..1258c5e6 100644 --- a/upd8.js +++ b/upd8.js @@ -129,6 +129,7 @@ const ARTIST_AVATAR_DIRECTORY = 'artist-avatar'; const ARTIST_DATA_FILE = 'artists.txt'; const FLASH_DATA_FILE = 'flashes.txt'; +const NEWS_DATA_FILE = 'news.txt'; const CSS_FILE = 'site.css'; @@ -141,6 +142,7 @@ const CSS_FILE = 'site.css'; let albumData; let allTracks; let flashData; +let newsData; let artistNames; let artistData; @@ -743,6 +745,59 @@ async function processFlashDataFile(file) { }); } +async function processNewsDataFile(file) { + let contents; + try { + contents = await readFile(file, 'utf-8'); + } catch (error) { + return {error: `Could not read ${file} (${error.code}).`}; + } + + const contentLines = contents.split('\n'); + const sections = Array.from(getSections(contentLines)); + + return sections.map(section => { + const name = getBasicField(section, 'Name'); + if (!name) { + return {error: 'Expected "Name" field!'}; + } + + const id = getBasicField(section, 'ID'); + if (!id) { + return {error: 'Expected "ID" field!'}; + } + + let body = getMultilineField(section, 'Body'); + if (!body) { + return {error: 'Expected "Body" field!'}; + } + + let date = getBasicField(section, 'Date'); + if (!date) { + return {error: 'Expected "Date" field!'}; + } + + if (isNaN(Date.parse(date))) { + return {error: `Invalid date field: "${date}"`}; + } + + date = new Date(date); + + let bodyShort = body.split('\n')[0]; + + body = transformMultiline(body); + bodyShort = transformMultiline(bodyShort); + + return { + name, + body, + bodyShort, + date, + id + }; + }); +} + function getDateString({ date }) { /* const pad = val => val.toString().padStart(2, '0'); @@ -1170,7 +1225,12 @@ function writeMiscellaneousPages() { </ul> <hr> <h1>News</h1> - <p>Todo.</p> + ${newsData.slice(0, 3).map(entry => fixWS` + <article> + <h2><time>${getDateString(entry)}</time> <a href="${C.NEWS_DIRECTORY}/#${entry.id}">${entry.name}</a></h2> + ${entry.body} + </article> + `).join('\n')} ` }, nav: { @@ -1308,6 +1368,22 @@ function writeMiscellaneousPages() { nav: {simple: true} }), + writePage([C.NEWS_DIRECTORY], { + title: 'News', + main: { + content: fixWS` + <h1>News</h1> + ${newsData.map(entry => fixWS` + <article id="${entry.id}"> + <h2><a href="#${entry.id}">${getDateString(entry)} - ${entry.name}</a></h2> + ${entry.body} + </article> + `).join('\n')} + ` + }, + nav: {simple: true} + }), + writeFile(path.join(C.SITE_DIRECTORY, 'data.js'), fixWS` // Yo, this file is gener8ted. Don't mess around with it! window.albumData = ${stringifyAlbumData()}; @@ -2639,6 +2715,20 @@ async function main() { return; } + newsData = await processNewsDataFile(path.join(C.DATA_DIRECTORY, NEWS_DATA_FILE)); + if (newsData.error) { + console.log(`\x1b[31;1m${newsData.error}\x1b[0m`); + return; + } + + const newsErrors = newsData.filter(obj => obj.error); + if (newsErrors.length) { + for (const error of newsErrors) { + console.log(`\x1b[31;1m${error.error}\x1b[0m`); + } + return; + } + allTracks = C.getAllTracks(albumData); artistNames = Array.from(new Set([ ...artistData.filter(artist => !artist.alias).map(artist => artist.name), |