'use strict' const Koa = require('koa') const app = new Koa() const fs = require('fs') const streamify = require('stream-array') const send = require('koa-send') const config = require('./modules/config.js') const PORT = process.env.PORT || config.server.port const Router = require('koa-router') const router = new Router() const rheo = require('rheo') const Posts = require('./modules/posts.js') const posts = Posts.getFolder(config.posts.folder) const templateReader = template => () => fs.createReadStream(`${__dirname}/templates/${template}.html`) const templates = { layout: templateReader('layout'), home: templateReader('home'), post: templateReader('post'), taxon: templateReader('taxon') } function setTitle (pageTitle) { return rheo.template(function (s) { return s .inner('title', rheo((pageTitle ? ' · ' : '') + config.site.title)) .inner('body header h1', rheo(config.site.title)) }) } function renderPostListItem (template, [, post]) { return template .attribute('a', 'href', () => router.url('post', post.basename)) .inner('a', () => rheo(post.data.get('title'))) } function toArrayStream (iterator) { return streamify(Array.from(iterator.entries())) } function showPage (name) { return function (els) { return rheo(templates[name]()) } } const postsStream = toArrayStream(posts) router.get('home', '/', async function (ctx, next) { ctx.set('Content-Type', 'text/html') ctx.body = templates .layout() .pipe(rheo()) .outer('main', showPage('home')) .inner('.posts', function (postsTemplate) { return postsStream.pipe(postsTemplate.map(renderPostListItem)) }) .pipe(setTitle()) .render() }) router.get('post', '/post/:filename', async function (ctx, next) { ctx.assert(posts.has(ctx.params.filename), 404, 'Post not found') const post = posts.get(ctx.params.filename) post.body = Posts.render(post) ctx.set('Content-Type', 'text/html') ctx.body = templates .layout() .pipe(rheo()) .inner('main', showPage('post')) .inner('article h1', rheo(post.data.get('title'))) .inner('article main', rheo(post.body)) .pipe(setTitle()) .render() }) const taxonomies = Posts.taxonomise(config.taxonomies, posts) for (let [term, items] of taxonomies) { router.get(`taxon-${term}`, `/${term}/:value`, async function (ctx, next) { const value = ctx.params.value ctx.assert( items.has(ctx.params.value), 404, `Could not find ${term} ${value}` ) ctx.set('Content-Type', 'text/html') ctx.body = templates .layout() .pipe(rheo()) .inner('main', showPage('taxon')) .inner('h1', rheo(config.site.title)) .inner('.posts', function (postsTemplate) { return toArrayStream(items.get(value)).pipe( postsTemplate.map(renderPostListItem) ) }) .pipe(setTitle()) .render() }) } app.use(router.routes()).use(router.allowedMethods()) const prefix = /^\/static\// app.use(async function (ctx) { if (prefix.test(ctx.path)) { await send(ctx, ctx.path.replace(prefix, ''), { root: './static' }) } }) module.exports = app if (require.main === module) { app.listen(PORT, () => { console.log(`App listening on port ${PORT}`) }) }