diff options
| author | Ben Beltran <ben@nsovocal.com> | 2017-07-03 00:26:08 -0500 |
|---|---|---|
| committer | Ben Beltran <ben@nsovocal.com> | 2017-07-03 00:26:08 -0500 |
| commit | cf6302904d61ead65e6294e7f1be406eb68ef5f9 (patch) | |
| tree | 2d034809bbf8db2db79e413ace9cab44a7044ae6 | |
| parent | 7a5a585ead8c4e967980adc2ab9c7502e47694fd (diff) | |
✨📝🔧 Add generator bin and files
Includes config for eslint, and jsdoc, plus the executable
Squashed commit of the following:
commit 7726a2743994800f5c0afbc23e5b529107b79450
Author: Ben Beltran <ben@nsovocal.com>
Date: Mon Jul 3 00:25:43 2017 -0500
Update changelog
commit 78ad8ab788020c09848a852e48827781aa17341a
Author: Ben Beltran <ben@nsovocal.com>
Date: Mon Jul 3 00:25:38 2017 -0500
Remove unused image
commit 1cd659307a39669cf0fc8d0f676b25625fd16ba2
Author: Ben Beltran <ben@nsovocal.com>
Date: Mon Jul 3 00:23:53 2017 -0500
Remove trailing slash on index
commit 944160fcbc364e4a829be91e6ad32521b4f94987
Author: Ben Beltran <ben@nsovocal.com>
Date: Mon Jul 3 00:21:50 2017 -0500
Add example blog post
commit 70645d0214d5d363accfedc3e2583e97232c930e
Author: Ben Beltran <ben@nsovocal.com>
Date: Mon Jul 3 00:20:44 2017 -0500
✨ Add binary / generator to lib
commit bb8f8bb6e12c89bc4b9b3766fd2ef8e924422005
Author: Ben Beltran <ben@nsovocal.com>
Date: Mon Jul 3 00:20:29 2017 -0500
🔧 Add package.json
commit 7e9b6f52c1c91bf963319ddeb1696bfac4130b95
Author: Ben Beltran <ben@nsovocal.com>
Date: Mon Jul 3 00:19:57 2017 -0500
🔧 Add eslint config
commit 26ee06bbf1c2f20620c81fa94c4a9b40460bd401
Author: Ben Beltran <ben@nsovocal.com>
Date: Mon Jul 3 00:19:31 2017 -0500
Move static files to template / static
commit db84351cbb8e8c4729123650d1cb3a6150da0502
Author: Ben Beltran <ben@nsovocal.com>
Date: Sun Jul 2 21:39:20 2017 -0500
Use a hidden name for posts directory
| -rw-r--r-- | .eslintrc | 14 | ||||
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | CHANGELOG.md | 4 | ||||
| -rwxr-xr-x | bin/blog.js | 92 | ||||
| -rw-r--r-- | config/config.js | 31 | ||||
| -rw-r--r-- | config/env.dist | 0 | ||||
| -rw-r--r-- | config/jsdoc.json | 9 | ||||
| -rw-r--r-- | example/test-blog-post/assets/example_image.png (renamed from images/example_image.png) | bin | 51624 -> 51624 bytes | |||
| -rw-r--r-- | example/test-blog-post/assets/ok/ok.txt | 0 | ||||
| -rw-r--r-- | example/test-blog-post/test-blog-post.md | 57 | ||||
| -rw-r--r-- | index.html | 197 | ||||
| -rw-r--r-- | lib/blog.js | 220 | ||||
| -rw-r--r-- | package.json | 42 | ||||
| -rw-r--r-- | static/css/style.css (renamed from css/style.css) | 0 | ||||
| -rw-r--r-- | static/images/header_background.png (renamed from images/header_background.png) | bin | 5247 -> 5247 bytes | |||
| -rw-r--r-- | static/images/header_foreground.png (renamed from images/header_foreground.png) | bin | 5273 -> 5273 bytes | |||
| -rw-r--r-- | templates/index.html | 32 |
17 files changed, 501 insertions, 199 deletions
diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..0a1dc80 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,14 @@ +{ + "extends": "eslint-config-hapi", + "parserOptions": { + "ecmaVersion": 2017 + }, + "rules": { + "indent": [ + 2, + 2 + ], + "no-undef": 2, + "require-yield": 0 + } +} @@ -61,7 +61,7 @@ typings/ .DS_Store # Data store -_posts +.posts # Generated files static/assets diff --git a/CHANGELOG.md b/CHANGELOG.md index a695952..728047b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added -- Static HTML / CSS +- Binary to add and update blog posts +- Template for index +- Static Files - Simple contributing guidelines - This CHANGELOG - A Readme diff --git a/bin/blog.js b/bin/blog.js new file mode 100755 index 0000000..c88a8aa --- /dev/null +++ b/bin/blog.js @@ -0,0 +1,92 @@ +#!/usr/bin/env node +'use strict'; + +const Config = require('../config/config'); +const Blog = require('..'); +const Minimist = require('minimist'); + +const internals = { + blog: new Blog(Config), + expectedKeys: ['add', 'update', 'publish'], + + // Application entry point. Reads arguments and calls the + // corresponding method from the blog lib + + async main() { + + try { + const parsedArguments = this._parseArguments(); + + for (const argument in parsedArguments) { + if (parsedArguments.hasOwnProperty(argument)) { + + const value = parsedArguments[argument]; + + if (argument === 'add') { + await internals.blog.add(value); + return; + } + + if (argument === 'update') { + await internals.blog.update(value); + return; + } + + if (argument === 'publish') { + await internals.blog.update(value); + return; + } + } + } + console.log('Not yet implemented'); + } + catch (err) { + console.error(err.message || err); + this._printUsage(); + process.exit(1); + } + }, + + // Parses arguments and returns them if valid. otherwise Throws + + _parseArguments() { + + const parsedArguments = Minimist(process.argv.slice(2)); + + if (!this._areArgumentsValid(parsedArguments)) { + throw new Error(internals.strings.invalidArguments); + } + + return parsedArguments; + }, + + // Checks if the arguments are valid, returns a boolean value. + + _areArgumentsValid(parsedArguments) { + + const argumentKeys = Object.keys(parsedArguments); + + return argumentKeys.some((key) => internals.expectedKeys.indexOf(key) >= 0); + }, + + // Prints the usage to stderr + + _printUsage() { + + console.error('\nUsage:\n'); + console.error('blog --add path/to/blog_post\t\t(creates new blog post)'); + console.error('blog --update path/to/blog_post\t(updates latest blog post)'); + console.error('blog --publish \t\t\t(publishes the blog)'); + } +}; + +// Add the strings, added after declaration so they can consume the +// internals object. + +internals.strings = { + invalidArguments: `Invalid Arguments, expecting one of: ${internals.expectedKeys.join(', ')}` +}; + + + +internals.main(); diff --git a/config/config.js b/config/config.js new file mode 100644 index 0000000..d16ff2d --- /dev/null +++ b/config/config.js @@ -0,0 +1,31 @@ +'use strict'; + +const Path = require('path'); +const Getenv = require('getenv'); + +const internals = {}; + +/** + * The main configuration object for Blog. It will be used to + * initialize all of the sub-components. It can extend any property of + * the blog object. + * + * @memberof Blog + * @typedef {object} tConfiguration + * @property {number} maxPosts=3 the max number of posts that can exist + * at one time + * @property {string} postsDirectory=<project_root>/.posts the location of + * the directory where the posts will be stored. + * @property {string} staticDirectory=<project_root>/static the location of + * the directory where the generated files will be placed. NOTE: There + * are some pre-built style files in the default directory, if you + * select another one, make sure you include them manually. + * @property {string} templatesDirectory=<project_root>/templates the + * location of the templates we'll use to generate the index.html + */ +module.exports = internals.Config = { + maxPosts: Getenv.int('BLOG_MAX_POSTS', 3), + postsDirectory: Getenv('BLOG_POSTS_DIRECTORY', Path.resolve(Path.join(__dirname, '../.posts'))), + staticDirectory: Getenv('BLOG_STATIC_DIRECTORY', Path.resolve(Path.join(__dirname, '../static'))), + templatesDirectory: Getenv('BLOG_TEMPLATES_DIRECTORY', Path.resolve(Path.join(__dirname, '../templates'))) +}; diff --git a/config/env.dist b/config/env.dist new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/config/env.dist diff --git a/config/jsdoc.json b/config/jsdoc.json new file mode 100644 index 0000000..9e05753 --- /dev/null +++ b/config/jsdoc.json @@ -0,0 +1,9 @@ +{ + "plugins": ["plugins/markdown"], + "opts": { + "destination": "doc", + "readme": "README.md", + "template": "node_modules/docdash", + "recurse": true + } +} diff --git a/images/example_image.png b/example/test-blog-post/assets/example_image.png Binary files differindex 672e3a1..672e3a1 100644 --- a/images/example_image.png +++ b/example/test-blog-post/assets/example_image.png diff --git a/example/test-blog-post/assets/ok/ok.txt b/example/test-blog-post/assets/ok/ok.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/example/test-blog-post/assets/ok/ok.txt diff --git a/example/test-blog-post/test-blog-post.md b/example/test-blog-post/test-blog-post.md new file mode 100644 index 0000000..88209ea --- /dev/null +++ b/example/test-blog-post/test-blog-post.md @@ -0,0 +1,57 @@ +# This is the title of another entry + +An entry will have paragraphs, these paragraphs will contain text. The +text should be formatted correctly: visitors will want to read whatever +is in the blog, so it should be readable. It should account for several +types of tags, like **strong**, or *emphasised*. It should even support +[links](/) + +An entry will have paragraphs, these paragraphs will contain text. The +text should be formatted correctly: visitors will want to read whatever +is in the blog, so it should be readable. It should account for several +types of tags, like **strong**, or *emphasised*. It +should even support [links](/) + +An entry will have paragraphs, these paragraphs will contain text. The +text should be formatted correctly: visitors will want to read whatever +is in the blog, so it should be readable. It should account for several +types of tags, like **strong**, or *emphasised*. It +should even support [links](/) + +## Subheading 1 (h2) + +An entry will have paragraphs, these paragraphs will contain text. The +text should be formatted correctly: visitors will want to read whatever +is in the blog, so it should be readable. It should account for several +types of tags, like **strong**, or *emphasised*. It +should even support [links](/) + +* There will be **lists** +* Lists will have *tags* +* And everything else [in the world](/) + +An entry will have paragraphs, these paragraphs will contain text. The +text should be formatted correctly: visitors will want to read whatever +is in the blog, so it should be readable. It should account for several +types of tags, like **strong**, or *emphasised*. It +should even support [links](/) + +![Picture: two persons in a ceremony][example-image] + +### Other types of subheadings, other types of lists (h3) + +1. There will be **lists** +2. Lists will have *tags* +3. And everything else [in the world](/) + +An entry will have paragraphs, these paragraphs will contain text. The +text should be formatted correctly: visitors will want to read whatever +is in the blog, so it should be readable. It should account for several +types of tags, like **strong**, or *emphasised*. It +should even support [links](/) + +#### Finally there are hfours (h4) + +And that's about it! + +[example-image]: /assets/example_image.png diff --git a/index.html b/index.html deleted file mode 100644 index 10d4919..0000000 --- a/index.html +++ /dev/null @@ -1,197 +0,0 @@ -<!doctype html> -<html> - <head> - <meta charset="utf-8"> - <meta name="description" content="This is the blog at unlimited.pizza"> - - <title>blog 🍕</title> - - <link href="css/style.css" rel="stylesheet"> - - </head> - <body> - <header class="main-header"> - <a href="/">Blog</a> - </header> - <main> - <article id="1"> - <h1>This is the title of an entry</h1> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <h2>Subheading 1 (h2)</h2> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <ul> - <li>There will be <strong>lists</strong></li> - <li>Lists will have <em>tags</em></li> - <li>And everything else <a href="/">in the world</a></li> - </ul> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <h3>Other types of subheadings, other types of lists (h3)</h3> - <ol> - <li>There will be <strong>lists</strong></li> - <li>Lists will have <em>tags</em></li> - <li>And everything else <a href="/">in the world</a></li> - </ol> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - </article> - <hr> - <article id="2"> - <h1>This is the title of another entry</h1> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <h2>Subheading 1 (h2)</h2> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <ul> - <li>There will be <strong>lists</strong></li> - <li>Lists will have <em>tags</em></li> - <li>And everything else <a href="/">in the world</a></li> - </ul> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <img src="/images/example_image.png" alt="Picture: two persons in a ceremony"> - <h3>Other types of subheadings, other types of lists (h3)</h3> - <ol> - <li>There will be <strong>lists</strong></li> - <li>Lists will have <em>tags</em></li> - <li>And everything else <a href="/">in the world</a></li> - </ol> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - </article> - <hr> - <article id="3"> - <h1>This is the title of the last entry</h1> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <h2>Subheading 1 (h2)</h2> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <ul> - <li>There will be <strong>lists</strong></li> - <li>Lists will have <em>tags</em></li> - <li>And everything else <a href="/">in the world</a></li> - </ul> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - <h3>Other types of subheadings, other types of lists (h3)</h3> - <ol> - <li>There will be <strong>lists</strong></li> - <li>Lists will have <em>tags</em></li> - <li>And everything else <a href="/">in the world</a></li> - </ol> - <p> - An entry will have paragraphs, these paragraphs will contain text. The - text should be formatted correctly: visitors will want to read whatever - is in the blog, so it should be readable. It should account for several - types of tags, like <strong>strong</strong>, or <em>emphasised</em>. It - should even support <a href="/">links</a> - </p> - </article> - </main> - <footer> - <p>Only 3 entries kept at any time. Press 1, 2, and 3 to switch. <a href="https://unlimited.pizza">unlimited.pizza</a></p> - </footer> - </body> -</html> - diff --git a/lib/blog.js b/lib/blog.js new file mode 100644 index 0000000..483577f --- /dev/null +++ b/lib/blog.js @@ -0,0 +1,220 @@ +'use strict'; + +const Fs = require('fs'); +const Markdown = require('markdown'); +const Mustache = require('mustache'); +const Ncp = require('ncp'); +const Path = require('path'); +const Rimraf = require('rimraf'); +const Util = require('util'); + +const internals = { + + // Promisified functions + + fs: { + access: Util.promisify(Fs.access), + mkdir: Util.promisify(Fs.mkdir), + readdir: Util.promisify(Fs.readdir), + readFile: Util.promisify(Fs.readFile), + writeFile: Util.promisify(Fs.writeFile) + }, + ncp: Util.promisify(Ncp.ncp), + rimraf: Util.promisify(Rimraf), + debuglog: Util.debuglog('blog'), + + // constants + + kAssetsDirectoryName: 'assets', + kIndexName: 'index.html', + kFileNotFoundError: 'ENOENT', + kMarkdownRe: /\.md$/i, + + // Strings + + strings: { + markdownNotFound: 'Markdown file was not found in blog directory. Please update.' + } +}; + +/** + * The Blog class is the blog generator, it's in charge of adding and + * updating posts, and handling the publishing. + * + * @class Blog + * @param {Potluck.tConfiguration} config the initialization options to + * extend the instance + */ +module.exports = class Blog { + + constructor(config) { + + Object.assign(this, config); + } + + /** + * Shifts the blog posts, adds the passed path to slot 0, and + * generates files. + * + * @function add + * @memberof Blog + * @param {string} postLocation the path to the directory containing + * the post structure + * @return {Promise<undefined>} empty promise, returns no value + * @instance + */ + async add(postLocation) { + + await this._shift(); + await this.update(postLocation); + } + + /** + * Adds the passed path to slot 0, and generates files. + * + * @function update + * @memberof Blog + * @param {string} postLocation the path to the directory containing + * the post structure + * @return {Promise<undefined>} empty promise, returns no value + * @instance + */ + async update(postLocation) { + + await this._copyPost(postLocation); + await this._generate(); + } + + /** + * Publishes the files to a static host. + * + * @function publish + * @memberof Blog + * @return {Promise<undefined>} empty promise, returns no value + * @instance + */ + async publish() { + + console.error('Publishing not yet implemented'); + } + + // Parses markdown for each page, copies assets and generates index. + + async _generate() { + + const assetsTarget = Path.join(this.staticDirectory, internals.kAssetsDirectoryName); + const indexTarget = Path.join(this.staticDirectory, internals.kIndexName); + const indexLocation = Path.join(this.templatesDirectory, internals.kIndexName); + const posts = []; + + internals.debuglog(`Removing ${assetsTarget}`); + await internals.rimraf(assetsTarget); + + for (let i = 0; i < this.maxPosts; ++i) { + const sourcePath = Path.join(this.postsDirectory, `${i}`); + const assetsSource = Path.join(sourcePath, internals.kAssetsDirectoryName); + const postContentPath = await this._findBlogContent(sourcePath); + + internals.debuglog(`Copying ${assetsSource} to ${assetsTarget}`); + await internals.ncp(assetsSource, assetsTarget); + + internals.debuglog(`Reading ${postContentPath}`); + const postContent = await internals.fs.readFile(postContentPath, { encoding: 'utf8' }); + + internals.debuglog('Parsing markdown'); + posts.push({ + html: Markdown.markdown.toHTML(postContent), + id: i + 1 + }); + } + + internals.debuglog(`Reading ${indexLocation}`); + const indexTemplate = await internals.fs.readFile(indexLocation, { encoding: 'utf8' }); + + internals.debuglog('Generating HTML'); + const indexHtml = Mustache.render(indexTemplate, { posts }); + await internals.fs.writeFile(indexTarget, indexHtml); + } + + // Shift the posts, delete any remainder. + + async _shift() { + + await this._ensurePostsDirectoryExists(); + + for (let i = this.maxPosts - 1; i > 0; --i) { + const targetPath = Path.join(this.postsDirectory, `${i}`); + const sourcePath = Path.join(this.postsDirectory, `${i - 1}`); + + try { + await internals.fs.access(sourcePath); + + internals.debuglog(`Removing ${targetPath}`); + await internals.rimraf(targetPath); + + internals.debuglog(`Shifting blog post ${sourcePath} to ${targetPath}`); + await internals.ncp(sourcePath, targetPath); + } + catch (error) { + if (error.code === internals.kFileNotFoundError) { + internals.debuglog(`Skipping ${sourcePath}: Does not exist.`); + continue; + } + + throw error; + } + } + } + + // Copies a post directory to the latest slot. + + async _copyPost(postLocation) { + + await this._ensurePostsDirectoryExists(); + + const targetPath = Path.join(this.postsDirectory, '0'); + + internals.debuglog(`Removing ${targetPath}`); + await internals.rimraf(targetPath); + + internals.debuglog(`Adding ${postLocation} to ${targetPath}`); + await internals.ncp(postLocation, targetPath); + } + + // Ensures the posts directory exists. + + async _ensurePostsDirectoryExists() { + + internals.debuglog(`Checking if ${this.postsDirectory} exists.`); + try { + await internals.fs.access(this.postsDirectory); + } + catch (error) { + if (error.code === internals.kFileNotFoundError) { + internals.debuglog('Creating posts directory'); + await internals.fs.mkdir(this.postsDirectory); + return; + } + + throw error; + } + } + + // Looks for a `.md` file in the blog directory, and returns the path + + async _findBlogContent(directory) { + + const entries = await internals.fs.readdir(directory); + + const markdownEntries = entries + .filter((entry) => internals.kMarkdownRe.test(entry)) + .map((entry) => Path.join(directory, entry)); + + if (markdownEntries.length > 0) { + internals.debuglog(`Found markdown file: ${markdownEntries[0]}`); + return markdownEntries[0]; + } + + throw new Error(internals.strings.markdownNotFound); + } +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..e5303b1 --- /dev/null +++ b/package.json @@ -0,0 +1,42 @@ +{ + "name": "blog", + "version": "1.0.0", + "description": "An ephemeral blog", + "main": "lib/blog.js", + "bin": { + "blog": "./bin/blog.js" + }, + "scripts": { + "document": "jsdoc -c ./config/jsdoc.json lib config", + "lint": "eslint .", + "test": "echo \":(\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/rbdr/blog.git" + }, + "author": "Ben Beltran <ben@nsovocal.com>", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/rbdr/blog/issues" + }, + "homepage": "https://github.com/rbdr/blog#readme", + "dependencies": { + "getenv": "0.7.x", + "markdown": "0.5.x", + "minimist": "1.2.x", + "mustache": "2.3.x", + "ncp": "2.0.x", + "rimraf": "2.6.x" + }, + "devDependencies": { + "docdash": "0.4.x", + "eslint": "4.1.x", + "eslint-config-hapi": "10.0.x", + "eslint-plugin-hapi": "4.0.x", + "jsdoc": "3.4.x" + }, + "engines": { + "node": ">=8.0.0" + } +} diff --git a/css/style.css b/static/css/style.css index aeda780..aeda780 100644 --- a/css/style.css +++ b/static/css/style.css diff --git a/images/header_background.png b/static/images/header_background.png Binary files differindex 8352b5e..8352b5e 100644 --- a/images/header_background.png +++ b/static/images/header_background.png diff --git a/images/header_foreground.png b/static/images/header_foreground.png Binary files differindex eb9b34d..eb9b34d 100644 --- a/images/header_foreground.png +++ b/static/images/header_foreground.png diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..858396b --- /dev/null +++ b/templates/index.html @@ -0,0 +1,32 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <meta name="description" content="This is the blog at unlimited.pizza"> + + <title>blog 🍕</title> + + <link href="css/style.css" rel="stylesheet"> + + </head> + <body> + <header class="main-header"> + <a href="/">Blog</a> + </header> + <main> + {{#posts}} + <article id="{{id}}"> + {{{html}}} + </article> + <hr> + {{/posts}} + {{^posts}} + <h1>This is a fresh blog!</h1> + <p>There are no posts yet.</p> + {{/posts}} + </main> + <footer> + <p>Only 3 entries kept at any time. Press 1, 2, and 3 to switch. <a href="https://unlimited.pizza">unlimited.pizza</a></p> + </footer> + </body> +</html> |