« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/page
diff options
context:
space:
mode:
Diffstat (limited to 'src/page')
-rw-r--r--src/page/index.js33
-rw-r--r--src/page/news.js129
2 files changed, 153 insertions, 9 deletions
diff --git a/src/page/index.js b/src/page/index.js
index d74dad57..384b4193 100644
--- a/src/page/index.js
+++ b/src/page/index.js
@@ -3,7 +3,14 @@
 // homepage.js for that.
 //
 // Each module published in this list should follow a particular format,
-// including the following exports:
+// including any of the following exports:
+//
+// condition({wikiData})
+//     Returns a boolean indicating whether to process targets/writes (true) or
+//     skip this page spec altogether (false). This is usually used for
+//     selectively toggling pages according to site feature flags, though it may
+//     also be used to e.g. skip out if no targets would be found (preventing
+//     writeTargetless from generating an empty index page).
 //
 // targets({wikiData})
 //     Gets the objects which this page's write() function should be called on.
@@ -11,14 +18,21 @@
 //     but it may also apply filter/map/etc if useful.
 //
 // write(thing, {wikiData})
-//     Gets descriptors for any page and data writes associated with the given
-//     thing (which will be a value from the targets() array). This includes
-//     page (HTML) writes, data (JSON) writes, etc. Notably, this function does
-//     not perform any file operations itself; it only describes the operations
-//     which will be processed elsewhere, once for each translation language.
-//     The write function also immediately transforms any data which will be
-//     reused across writes of the same page, so that this data is effectively
-//     cached (rather than recalculated for each language/write).
+//     Provides descriptors for any page and data writes associated with the
+//     given thing (which will be a value from the targets() array). This
+//     includes page (HTML) writes, data (JSON) writes, etc. Notably, this
+//     function does not perform any file operations itself; it only describes
+//     the operations which will be processed elsewhere, once for each
+//     translation language.  The write function also immediately transforms
+//     any data which will be reused across writes of the same page, so that
+//     this data is effectively cached (rather than recalculated for each
+//     language/write).
+//
+// writeTargetless({wikiData})
+//     Provides descriptors for page/data/etc writes which will be used
+//     without concern for targets. This is usually used for writing index pages
+//     which should be generated just once (rather than corresponding to
+//     targets).
 //
 // As these modules are effectively the HTML templates for all site layout,
 // common patterns may also be exported alongside the special exports above.
@@ -29,4 +43,5 @@ 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 news from './news.js';
 export * as track from './track.js';
diff --git a/src/page/news.js b/src/page/news.js
new file mode 100644
index 00000000..99cbe8d5
--- /dev/null
+++ b/src/page/news.js
@@ -0,0 +1,129 @@
+// News entry & index page specifications.
+
+// Imports
+
+import fixWS from 'fix-whitespace';
+
+// Page exports
+
+export function condition({wikiData}) {
+    return wikiData.wikiInfo.features.news;
+}
+
+export function targets({wikiData}) {
+    return wikiData.newsData;
+}
+
+export function write(entry, {wikiData}) {
+    const page = {
+        type: 'page',
+        path: ['newsEntry', entry.directory],
+        page: ({
+            generatePreviousNextLinks,
+            link,
+            strings,
+            transformMultiline,
+        }) => ({
+            title: strings('newsEntryPage.title', {entry: entry.name}),
+
+            main: {
+                content: fixWS`
+                    <div class="long-content">
+                        <h1>${strings('newsEntryPage.title', {entry: entry.name})}</h1>
+                        <p>${strings('newsEntryPage.published', {date: strings.count.date(entry.date)})}</p>
+                        ${transformMultiline(entry.body)}
+                    </div>
+                `
+            },
+
+            nav: generateNewsEntryNav(entry, {
+                generatePreviousNextLinks,
+                link,
+                strings,
+                wikiData
+            })
+        })
+    };
+
+    return [page];
+}
+
+export function writeTargetless({wikiData}) {
+    const { newsData } = wikiData;
+
+    const page = {
+        type: 'page',
+        path: ['newsIndex'],
+        page: ({
+            link,
+            strings,
+            transformMultiline
+        }) => ({
+            title: strings('newsIndex.title'),
+
+            main: {
+                content: fixWS`
+                    <div class="long-content news-index">
+                        <h1>${strings('newsIndex.title')}</h1>
+                        ${newsData.map(entry => fixWS`
+                            <article id="${entry.directory}">
+                                <h2><time>${strings.count.date(entry.date)}</time> ${link.newsEntry(entry)}</h2>
+                                ${transformMultiline(entry.bodyShort)}
+                                ${entry.bodyShort !== entry.body && `<p>${link.newsEntry(entry, {
+                                    text: strings('newsIndex.entry.viewRest')
+                                })}</p>`}
+                            </article>
+                        `).join('\n')}
+                    </div>
+                `
+            },
+
+            nav: {simple: true}
+        })
+    };
+
+    return [page];
+}
+
+// Utility functions
+
+function generateNewsEntryNav(entry, {
+    generatePreviousNextLinks,
+    link,
+    strings,
+    wikiData
+}) {
+    const { wikiInfo, newsData } = wikiData;
+
+    // The newsData list is sorted reverse chronologically (newest ones first),
+    // so the way we find next/previous entries is flipped from normal.
+    const previousNextLinks = generatePreviousNextLinks(entry, {
+        link, strings,
+        data: newsData.slice().reverse(),
+        linkKey: 'newsEntry'
+    });
+
+    return {
+        links: [
+            {
+                path: ['localized.home'],
+                title: wikiInfo.shortName
+            },
+            {
+                path: ['localized.newsIndex'],
+                title: strings('newsEntryPage.nav.news')
+            },
+            {
+                html: strings('newsEntryPage.nav.entry', {
+                    date: strings.count.date(entry.date),
+                    entry: link.newsEntry(entry, {class: 'current'})
+                })
+            },
+            previousNextLinks &&
+            {
+                divider: false,
+                html: `(${previousNextLinks})`
+            }
+        ]
+    };
+}