Skip to content

Dotnet core static blog generator based on markdown, YAML front matter and Handlebars.NET

License

Notifications You must be signed in to change notification settings

codernr/bloggen-net

Repository files navigation

Bloggen.Net .NET Core Codacy Badge

Dotnet core cross platform static blog generator based on markdown, YAML front matter and Handlebars.NET

A working example of a blog generated by this is my own: https://codernr.github.io/

To read more about this project, see this blog post: https://codernr.github.io/posts/this-post-is-generated-by-the-subject-of-this-post

Features

  • Uses YAML front matter for metadata and markdown
  • Generates posts and static pages
  • Handles tags
  • Supports pagination of posts
  • Uses Handlebars language for templates

Usage

  1. Download the latest release
  2. Extract the tar file
  3. Go to the extracted directory
  4. Run dotnet ./Bloggen.Net.dll -s <source directory path> -o <output directory path>

Source directory structure

The source directory has to follow a well defined structure (see details in next sections):

source/
├── assets/
│   ├── img/
│   │   ├── some_image.jpg
│   │   └── ...
│   ├── js/
│   └── ...
├── pages
│   ├── some-page.md
│   ├── other-page.md
│   └── ...
├── posts
│   ├── my-first-post.md
│   ├── my-second-post.md
│   └── ...
├── templates
│   ├── my-template-name/
│   │   ├── assets/
│   │   │   ├── img/
│   │   │   │   ├── template_img.jpg
│   │   │   │   └── ...
│   │   │   ├── css/
│   │   │   │   ├── template_style.css
│   │   │   │   └── ...
│   │   │   ├── js/
│   │   │   │   ├── template_scripts.js
│   │   │   │   └── ...
│   │   │   └── ...
│   │   ├── layouts/
│   │   │   ├── list.hbs
│   │   │   ├── page.hbs
│   │   │   ├── post.hbs
│   │   │   └── tag.hbs
│   │   ├── partials/
│   │   │   ├── any_partial.hbs
│   │   │   └── ...
│   │   └── index.hbs
│   └── ...
└── config.yml

Config

The source root directory contains a config.yml file that represents the site configuration. Example:

# The title of the site; default: empty string
title: 'Site title'

# A subheading/slogan; default: empty string
subHeading: 'A secondary heading'

# source/templates directory can contain multiple templates,
# the one with this name is rendered; default: empty string
template: 'my-template-name'

# Number of posts that is displayed on one page; default: 10
postsPerPage: 10

# Root url of site; default: '/'
url: 'https://my-page.com'

# Date format string on the site; default: 'yyyy-MM-dd'
dateFormat: 'yyyy-MM-dd'

# Site-wide meta properties, e.g. 'og:title', etc.
metaProperties:
  - property: 'og:image'
    content: '/assets/my-facebook-share-image.jpg'

# Google analytics tracker code, could be used in template for rendering google analytics script
# optional
gTag: 'UA-12345678-1'

# Disqus identifier, could be used in template for rendering disqus script
disqusId: 'my-disqus-id'

Pages

Files in the pages directory are rendered in the output root directory directly so they can be reached on the /pagename path. SReserved therefore are not allowed for pages:

  • assets
  • pages
  • posts
  • tags
  • index

Page metadata is passed in the file's front matter header and content is parsed as markdown. Currently pages only have title metadata:

---
# Front matter header is between --- marks
title: 'About'
---

# Here comes the markdown content

...

Posts

Posts are generated based on their filename and available on /posts/post-file-name path so it is recommended to name the original file seo-friendly. The format is the same front matter + markdown as with pages. Example:

---
# Front matter header is between --- marks

# Title of the post
title: 'My first blog post'

# Excerpt that can be used on list page for example
excerpt: 'A longer description of my post'

# Date of creation (list page orders by this)
createdAt: '2020-04-01'

# Author
postedBy: 'codernr'

# Tags
tags: [ 'blog', 'C#', 'Github' ]

# Post specific meta properties, these are merged with site meta properties
# Properties defined here take precedence over site properties so an 'og:image' defined here overrides the default one
metaProperties:
  - property: 'og:image'
    content: '/assets/img/my-custom-share-image.jpg'
---

# Here comes the markdown content

...

Tags

Tags are collected from posts' metadata and grouped by slug. Special characters are stripped and hyphens are added when generating slugs so C# and C becomes the same, this should be kept in mind when tagging posts. Tag pages are generated under /tag/tagname path where a list of posts using that tag is passed to the template.

Post pagination

Posts are ordered descending by creation date and paginated as defined in config. The first page is always rendered as index.html and the other pages are rendered under /pages/{page-number} path.

Assets

There are two sources of assets:

  • site-wide assets in source/assets directory
  • template specific assets in source/templates/<selected-template>/assets

These folders are merged during generation to the /assets path which means that a template asset with the same name as a site asset overwrites it.

Templates

There is an example template that is used by my blog, forked from Start bootstrap, see it here.

Bloggen.Net uses Handlebars.Net as a templating engine. The pages are rendered from a main template file index.hbs and embedded layout files that are specific for the type of content.

There is a site variable that is available within all the templates called site with the following structure:

{
  config: {
    title: '...',
    subheading: '...',
    template: '...',
    postsperpage: '...'
    // ... and al the config values
  },
  tags: [ // all the tags ordered by name
    { /* see details at tag layout description */ }
  ],
  pages: [
    { /* see details at list layout description */ }
  ]
}

List layout (layouts/list.hbs)

This template is rendered with the paginated post objects. Pagination objects are available in {{site.pages}} array in the template. Structure:

{
  pageNumber: 2,
  items: [ { /* see structure at post layout */ }]
  url: '/pages/2' // or '/' if on the first page that is index.html
  totalcount: 3 // number of pages
  previous: { /* the previous pagination object */ }
  next: { /* the next pagination object */ }
}

Page layout (layouts/page.hbs)

Pages are rendered with this template. Page data is available in the {{data}} variable in the template. Structure is the same as described in posts section.

Page content is available in the {{content}} variable. To render markdown as html see helpers.

Post layout (layouts/post.hbs)

The same as pages. Metadata is in the {{data}} variable, content is in {{content}}. See metadata in posts section.

Tag layout (layouts/tag.hbs)

This template is used to render one specific tag's post list. Tag metadata is available in {{data}} variable:

{
  name: 'tag name',
  postreferences: [ { /* see details at posts description */ } ]
  url: '/tags/tag-name'
}

Template helpers

There are two registered helpers in Bloggen.Net by default:

  • Date helper that renders date objects with the format string from config; usage: {{date datevariable}}
  • Html helper that renders markdown content as html; usage: {{html content}}

Automation

Since this is a command line tool, it can be used in an automated setup. My own blog is generated this way; a source repository is set up to trigger the generation of files and a git push to my user site repository. For details, see the workflow file.