« get me outta code hell

module-ify homepage - 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>2021-06-04 15:26:03 -0300
committer(quasar) nebula <towerofnix@gmail.com>2021-06-04 15:26:03 -0300
commita735545f1442d9aab870ce34c76d43487f7ed547 (patch)
treee4c62f3b92d26183863398c687b6075b458de007
parent635eea4460bb635766bcf9d0a666b7d5ddb2dba3 (diff)
module-ify homepage
-rw-r--r--src/page/homepage.js127
-rw-r--r--src/page/index.js1
-rwxr-xr-xsrc/upd8.js227
-rw-r--r--src/util/wiki-data.js116
4 files changed, 244 insertions, 227 deletions
diff --git a/src/page/homepage.js b/src/page/homepage.js
new file mode 100644
index 00000000..d1dcc680
--- /dev/null
+++ b/src/page/homepage.js
@@ -0,0 +1,127 @@
+// Homepage specification.
+
+// Imports
+
+import fixWS from 'fix-whitespace';
+
+import {
+    getLinkThemeString
+} from '../util/colors.js';
+
+import find from '../util/find.js';
+
+import * as html from '../util/html.js';
+
+import {
+    getNewAdditions,
+    getNewReleases
+} from '../util/wiki-data.js';
+
+// Page exports
+
+export function writeTargetless({wikiData}) {
+    const { newsData, staticPageData, homepageInfo, wikiInfo } = wikiData;
+
+    const page = {
+        type: 'page',
+        path: ['home'],
+        page: ({
+            getAlbumGridHTML,
+            link,
+            strings,
+            to,
+            transformInline,
+            transformMultiline
+        }) => ({
+            title: wikiInfo.name,
+
+            meta: {
+                description: wikiInfo.description
+            },
+
+            main: {
+                classes: ['top-index'],
+                content: fixWS`
+                    <h1>${wikiInfo.name}</h1>
+                    ${homepageInfo.rows.map((row, i) => fixWS`
+                        <section class="row" style="${getLinkThemeString(row.color)}">
+                            <h2>${row.name}</h2>
+                            ${row.type === 'albums' && fixWS`
+                                <div class="grid-listing">
+                                    ${getAlbumGridHTML({
+                                        entries: (
+                                            row.group === 'new-releases' ? getNewReleases(row.groupCount, {wikiData}) :
+                                            row.group === 'new-additions' ? getNewAdditions(row.groupCount, {wikiData}) :
+                                            ((find.group(row.group, {wikiData})?.albums || [])
+                                                .slice()
+                                                .reverse()
+                                                .slice(0, row.groupCount)
+                                                .map(album => ({item: album})))
+                                        ).concat(row.albums
+                                            .map(album => find.album(album, {wikiData}))
+                                            .map(album => ({item: album}))
+                                        ),
+                                        lazy: i > 0
+                                    })}
+                                    ${row.actions.length && fixWS`
+                                        <div class="grid-actions">
+                                            ${row.actions.map(action => transformInline(action)
+                                                .replace('<a', '<a class="box grid-item"')).join('\n')}
+                                        </div>
+                                    `}
+                                </div>
+                            `}
+                        </section>
+                    `).join('\n')}
+                `
+            },
+
+            sidebarLeft: homepageInfo.sidebar && {
+                wide: true,
+                collapse: false,
+                // This is a pretty filthy hack! 8ut otherwise, the [[news]] part
+                // gets treated like it's a reference to the track named "news",
+                // which o8viously isn't what we're going for. Gotta catch that
+                // 8efore we pass it to transformMultiline, 'cuz otherwise it'll
+                // get repl8ced with just the word "news" (or anything else that
+                // transformMultiline does with references it can't match) -- and
+                // we can't match that for replacing it with the news column!
+                //
+                // And no, I will not make [[news]] into part of transformMultiline
+                // (even though that would 8e hilarious).
+                content: (transformMultiline(homepageInfo.sidebar.replace('[[news]]', '__GENERATE_NEWS__'))
+                    .replace('<p>__GENERATE_NEWS__</p>', wikiInfo.features.news ? fixWS`
+                        <h1>${strings('homepage.news.title')}</h1>
+                        ${newsData.slice(0, 3).map((entry, i) => html.tag('article',
+                            {class: ['news-entry', i === 0 && 'first-news-entry']},
+                            fixWS`
+                                <h2><time>${strings.count.date(entry.date)}</time> ${link.newsEntry(entry)}</h2>
+                                ${transformMultiline(entry.bodyShort)}
+                                ${entry.bodyShort !== entry.body && link.newsEntry(entry, {
+                                    text: strings('homepage.news.entry.viewRest')
+                                })}
+                            `)).join('\n')}
+                    ` : `<p><i>News requested in content description but this feature isn't enabled</i></p>`))
+            },
+
+            nav: {
+                content: fixWS`
+                    <h2 class="dot-between-spans">
+                        ${[
+                            link.home('', {text: wikiInfo.shortName, class: 'current', to}),
+                            wikiInfo.features.listings &&
+                            link.listingIndex('', {text: strings('listingIndex.title'), to}),
+                            wikiInfo.features.news &&
+                            link.newsIndex('', {text: strings('newsIndex.title'), to}),
+                            wikiInfo.features.flashesAndGames &&
+                            link.flashIndex('', {text: strings('flashIndex.title'), to}),
+                            ...staticPageData.filter(page => page.listed).map(link.staticPage)
+                        ].filter(Boolean).map(link => `<span>${link}</span>`).join('\n')}
+                    </h2>
+                `
+            }
+        })
+    };
+
+    return [page];
+}
diff --git a/src/page/index.js b/src/page/index.js
index 42204947..c5e10631 100644
--- a/src/page/index.js
+++ b/src/page/index.js
@@ -43,6 +43,7 @@ export * as album from './album.js';
 export * as artist from './artist.js';
 export * as artistAlias from './artist-alias.js';
 export * as group from './group.js';
+export * as homepage from './homepage.js';
 export * as static from './static.js';
 export * as news from './news.js';
 export * as track from './track.js';
diff --git a/src/upd8.js b/src/upd8.js
index a1fafb27..586afe95 100755
--- a/src/upd8.js
+++ b/src/upd8.js
@@ -2151,120 +2151,6 @@ function getFlashGridHTML({
     });
 }
 
-function getNewReleases(numReleases, {wikiData}) {
-    const { albumData } = wikiData;
-
-    const latestFirst = albumData.filter(album => album.isListedOnHomepage).reverse();
-    const majorReleases = latestFirst.filter(album => album.isMajorRelease);
-    majorReleases.splice(1);
-
-    const otherReleases = latestFirst
-        .filter(album => !majorReleases.includes(album))
-        .slice(0, numReleases - majorReleases.length);
-
-    return [
-        ...majorReleases.map(album => ({large: true, item: album})),
-        ...otherReleases.map(album => ({large: false, item: album}))
-    ];
-}
-
-function getNewAdditions(numAlbums, {wikiData}) {
-    const { albumData } = wikiData;
-
-    // Sort al8ums, in descending order of priority, 8y...
-    //
-    // * D8te of addition to the wiki (descending).
-    // * Major releases first.
-    // * D8te of release (descending).
-    //
-    // Major releases go first to 8etter ensure they show up in the list (and
-    // are usually at the start of the final output for a given d8 of release
-    // too).
-    const sortedAlbums = albumData.filter(album => album.isListedOnHomepage).sort((a, b) => {
-        if (a.dateAdded > b.dateAdded) return -1;
-        if (a.dateAdded < b.dateAdded) return 1;
-        if (a.isMajorRelease && !b.isMajorRelease) return -1;
-        if (!a.isMajorRelease && b.isMajorRelease) return 1;
-        if (a.date > b.date) return -1;
-        if (a.date < b.date) return 1;
-    });
-
-    // When multiple al8ums are added to the wiki at a time, we want to show
-    // all of them 8efore pulling al8ums from the next (earlier) date. We also
-    // want to show a diverse selection of al8ums - with limited space, we'd
-    // rather not show only the latest al8ums, if those happen to all 8e
-    // closely rel8ted!
-    //
-    // Specifically, we're concerned with avoiding too much overlap amongst
-    // the primary (first/top-most) group. We do this 8y collecting every
-    // primary group present amongst the al8ums for a given d8 into one
-    // (ordered) array, initially sorted (inherently) 8y latest al8um from
-    // the group. Then we cycle over the array, adding one al8um from each
-    // group until all the al8ums from that release d8 have 8een added (or
-    // we've met the total target num8er of al8ums). Once we've added all the
-    // al8ums for a given group, it's struck from the array (so the groups
-    // with the most additions on one d8 will have their oldest releases
-    // collected more towards the end of the list).
-
-    const albums = [];
-
-    let i = 0;
-    outerLoop: while (i < sortedAlbums.length) {
-        // 8uild up a list of groups and their al8ums 8y order of decending
-        // release, iter8ting until we're on a different d8. (We use a map for
-        // indexing so we don't have to iter8te through the entire array each
-        // time we access one of its entries. This is 8asically unnecessary
-        // since this will never 8e an expensive enough task for that to
-        // matter.... 8ut it's nicer code. BBBB) )
-        const currentDate = sortedAlbums[i].dateAdded;
-        const groupMap = new Map();
-        const groupArray = [];
-        for (let album; (album = sortedAlbums[i]) && +album.dateAdded === +currentDate; i++) {
-            const primaryGroup = album.groups[0];
-            if (groupMap.has(primaryGroup)) {
-                groupMap.get(primaryGroup).push(album);
-            } else {
-                const entry = [album]
-                groupMap.set(primaryGroup, entry);
-                groupArray.push(entry);
-            }
-        }
-
-        // Then cycle over that sorted array, adding one al8um from each to
-        // the main array until we've run out or have met the target num8er
-        // of al8ums.
-        while (groupArray.length) {
-            let j = 0;
-            while (j < groupArray.length) {
-                const entry = groupArray[j];
-                const album = entry.shift();
-                albums.push(album);
-
-
-                // This is the only time we ever add anything to the main al8um
-                // list, so it's also the only place we need to check if we've
-                // met the target length.
-                if (albums.length === numAlbums) {
-                    // If we've met it, 8r8k out of the outer loop - we're done
-                    // here!
-                    break outerLoop;
-                }
-
-                if (entry.length) {
-                    j++;
-                } else {
-                    groupArray.splice(j, 1);
-                }
-            }
-        }
-    }
-
-    // Finally, do some quick mapping shenanigans to 8etter display the result
-    // in a grid. (This should pro8a8ly 8e a separ8te, shared function, 8ut
-    // whatevs.)
-    return albums.map(album => ({large: album.isMajorRelease, item: album}));
-}
-
 function writeSymlinks() {
     return progressPromiseAll('Writing site symlinks.', [
         link(path.join(__dirname, UTILITY_DIRECTORY), 'shared.utilityRoot'),
@@ -2316,119 +2202,6 @@ function writeSharedFilesAndPages({strings, wikiData}) {
     ].filter(Boolean));
 }
 
-function writeHomepage({wikiData}) {
-    const { newsData, staticPageData, homepageInfo, wikiInfo } = wikiData;
-
-    const page = {
-        type: 'page',
-        path: ['home'],
-        page: ({
-            getAlbumGridHTML,
-            link,
-            strings,
-            to,
-            transformInline,
-            transformMultiline,
-        }) => ({
-            title: wikiInfo.name,
-
-            meta: {
-                description: wikiInfo.description
-            },
-
-            main: {
-                classes: ['top-index'],
-                content: fixWS`
-                    <h1>${wikiInfo.name}</h1>
-                    ${homepageInfo.rows.map((row, i) => fixWS`
-                        <section class="row" style="${getLinkThemeString(row.color)}">
-                            <h2>${row.name}</h2>
-                            ${row.type === 'albums' && fixWS`
-                                <div class="grid-listing">
-                                    ${getAlbumGridHTML({
-                                        entries: (
-                                            row.group === 'new-releases' ? getNewReleases(row.groupCount, {wikiData}) :
-                                            row.group === 'new-additions' ? getNewAdditions(row.groupCount, {wikiData}) :
-                                            ((find.group(row.group, {wikiData})?.albums || [])
-                                                .slice()
-                                                .reverse()
-                                                .slice(0, row.groupCount)
-                                                .map(album => ({item: album})))
-                                        ).concat(row.albums
-                                            .map(album => find.album(album, {wikiData}))
-                                            .map(album => ({item: album}))
-                                        ),
-                                        lazy: i > 0
-                                    })}
-                                    ${row.actions.length && fixWS`
-                                        <div class="grid-actions">
-                                            ${row.actions.map(action => transformInline(action)
-                                                .replace('<a', '<a class="box grid-item"')).join('\n')}
-                                        </div>
-                                    `}
-                                </div>
-                            `}
-                        </section>
-                    `).join('\n')}
-                `
-            },
-
-            sidebarLeft: homepageInfo.sidebar && {
-                wide: true,
-                collapse: false,
-                // This is a pretty filthy hack! 8ut otherwise, the [[news]] part
-                // gets treated like it's a reference to the track named "news",
-                // which o8viously isn't what we're going for. Gotta catch that
-                // 8efore we pass it to transformMultiline, 'cuz otherwise it'll
-                // get repl8ced with just the word "news" (or anything else that
-                // transformMultiline does with references it can't match) -- and
-                // we can't match that for replacing it with the news column!
-                //
-                // And no, I will not make [[news]] into part of transformMultiline
-                // (even though that would 8e hilarious).
-                content: (transformMultiline(homepageInfo.sidebar.replace('[[news]]', '__GENERATE_NEWS__'))
-                    .replace('<p>__GENERATE_NEWS__</p>', wikiInfo.features.news ? fixWS`
-                        <h1>${strings('homepage.news.title')}</h1>
-                        ${newsData.slice(0, 3).map((entry, i) => fixWS`
-                            <article ${classes('news-entry', i === 0 && 'first-news-entry')}>
-                                <h2><time>${strings.count.date(entry.date)}</time> ${link.newsEntry(entry)}</h2>
-                                ${transformMultiline(entry.bodyShort)}
-                                ${entry.bodyShort !== entry.body && link.newsEntry(entry, {
-                                    text: strings('homepage.news.entry.viewRest')
-                                })}
-                            </article>
-                        `).join('\n')}
-                    ` : `<p><i>News requested in content description but this feature isn't enabled</i></p>`))
-            },
-
-            nav: {
-                content: fixWS`
-                    <h2 class="dot-between-spans">
-                        ${[
-                            link.home('', {text: wikiInfo.shortName, class: 'current', to}),
-                            wikiInfo.features.listings &&
-                            link.listingIndex('', {text: strings('listingIndex.title'), to}),
-                            wikiInfo.features.news &&
-                            link.newsIndex('', {text: strings('newsIndex.title'), to}),
-                            wikiInfo.features.flashesAndGames &&
-                            link.flashIndex('', {text: strings('flashIndex.title'), to}),
-                            ...staticPageData.filter(page => page.listed).map(link.staticPage)
-                        ].filter(Boolean).map(link => `<span>${link}</span>`).join('\n')}
-                    </h2>
-                `
-            }
-        })
-    };
-
-    return [page];
-}
-
-function writeMiscellaneousPages({wikiData}) {
-    return [
-        writeHomepage({wikiData})
-    ];
-}
-
 function getRevealStringFromWarnings(warnings, {strings}) {
     return strings('misc.contentWarnings', {warnings}) + `<br><span class="reveal-interaction">${strings('misc.contentWarnings.reveal')}</span>`
 }
diff --git a/src/util/wiki-data.js b/src/util/wiki-data.js
index e4142c85..2527a4b3 100644
--- a/src/util/wiki-data.js
+++ b/src/util/wiki-data.js
@@ -159,3 +159,119 @@ export function getTrackCover(track, {to}) {
         return to('media.trackCover', track.album.directory, track.directory);
     }
 }
+
+// Big-ass homepage row functions
+
+export function getNewAdditions(numAlbums, {wikiData}) {
+    const { albumData } = wikiData;
+
+    // Sort al8ums, in descending order of priority, 8y...
+    //
+    // * D8te of addition to the wiki (descending).
+    // * Major releases first.
+    // * D8te of release (descending).
+    //
+    // Major releases go first to 8etter ensure they show up in the list (and
+    // are usually at the start of the final output for a given d8 of release
+    // too).
+    const sortedAlbums = albumData.filter(album => album.isListedOnHomepage).sort((a, b) => {
+        if (a.dateAdded > b.dateAdded) return -1;
+        if (a.dateAdded < b.dateAdded) return 1;
+        if (a.isMajorRelease && !b.isMajorRelease) return -1;
+        if (!a.isMajorRelease && b.isMajorRelease) return 1;
+        if (a.date > b.date) return -1;
+        if (a.date < b.date) return 1;
+    });
+
+    // When multiple al8ums are added to the wiki at a time, we want to show
+    // all of them 8efore pulling al8ums from the next (earlier) date. We also
+    // want to show a diverse selection of al8ums - with limited space, we'd
+    // rather not show only the latest al8ums, if those happen to all 8e
+    // closely rel8ted!
+    //
+    // Specifically, we're concerned with avoiding too much overlap amongst
+    // the primary (first/top-most) group. We do this 8y collecting every
+    // primary group present amongst the al8ums for a given d8 into one
+    // (ordered) array, initially sorted (inherently) 8y latest al8um from
+    // the group. Then we cycle over the array, adding one al8um from each
+    // group until all the al8ums from that release d8 have 8een added (or
+    // we've met the total target num8er of al8ums). Once we've added all the
+    // al8ums for a given group, it's struck from the array (so the groups
+    // with the most additions on one d8 will have their oldest releases
+    // collected more towards the end of the list).
+
+    const albums = [];
+
+    let i = 0;
+    outerLoop: while (i < sortedAlbums.length) {
+        // 8uild up a list of groups and their al8ums 8y order of decending
+        // release, iter8ting until we're on a different d8. (We use a map for
+        // indexing so we don't have to iter8te through the entire array each
+        // time we access one of its entries. This is 8asically unnecessary
+        // since this will never 8e an expensive enough task for that to
+        // matter.... 8ut it's nicer code. BBBB) )
+        const currentDate = sortedAlbums[i].dateAdded;
+        const groupMap = new Map();
+        const groupArray = [];
+        for (let album; (album = sortedAlbums[i]) && +album.dateAdded === +currentDate; i++) {
+            const primaryGroup = album.groups[0];
+            if (groupMap.has(primaryGroup)) {
+                groupMap.get(primaryGroup).push(album);
+            } else {
+                const entry = [album]
+                groupMap.set(primaryGroup, entry);
+                groupArray.push(entry);
+            }
+        }
+
+        // Then cycle over that sorted array, adding one al8um from each to
+        // the main array until we've run out or have met the target num8er
+        // of al8ums.
+        while (groupArray.length) {
+            let j = 0;
+            while (j < groupArray.length) {
+                const entry = groupArray[j];
+                const album = entry.shift();
+                albums.push(album);
+
+
+                // This is the only time we ever add anything to the main al8um
+                // list, so it's also the only place we need to check if we've
+                // met the target length.
+                if (albums.length === numAlbums) {
+                    // If we've met it, 8r8k out of the outer loop - we're done
+                    // here!
+                    break outerLoop;
+                }
+
+                if (entry.length) {
+                    j++;
+                } else {
+                    groupArray.splice(j, 1);
+                }
+            }
+        }
+    }
+
+    // Finally, do some quick mapping shenanigans to 8etter display the result
+    // in a grid. (This should pro8a8ly 8e a separ8te, shared function, 8ut
+    // whatevs.)
+    return albums.map(album => ({large: album.isMajorRelease, item: album}));
+}
+
+export function getNewReleases(numReleases, {wikiData}) {
+    const { albumData } = wikiData;
+
+    const latestFirst = albumData.filter(album => album.isListedOnHomepage).reverse();
+    const majorReleases = latestFirst.filter(album => album.isMajorRelease);
+    majorReleases.splice(1);
+
+    const otherReleases = latestFirst
+        .filter(album => !majorReleases.includes(album))
+        .slice(0, numReleases - majorReleases.length);
+
+    return [
+        ...majorReleases.map(album => ({large: true, item: album})),
+        ...otherReleases.map(album => ({large: false, item: album}))
+    ];
+}