« get me outta code hell

implement news entries data file and page! - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
author(quasar) nebula <towerofnix@gmail.com>2020-11-10 14:11:16 -0400
committer(quasar) nebula <towerofnix@gmail.com>2020-11-10 14:11:16 -0400
commit157ffb24a57e04ddd19f93c9dfff64df5a6208fd (patch)
treeefeb70f0391b1bfcd70674c75ef718102e46017e
parentc42861023bd97b355e59bc35e517ee76304df5a9 (diff)
implement news entries data file and page!
-rw-r--r--common/common.js1
-rw-r--r--static/site.css31
-rw-r--r--upd8.js92
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),