Metalsharp.SimpleBlog 1.0.0

dotnet add package Metalsharp.SimpleBlog --version 1.0.0
                    
NuGet\Install-Package Metalsharp.SimpleBlog -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Metalsharp.SimpleBlog" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Metalsharp.SimpleBlog" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Metalsharp.SimpleBlog" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Metalsharp.SimpleBlog --version 1.0.0
                    
#r "nuget: Metalsharp.SimpleBlog, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Metalsharp.SimpleBlog@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Metalsharp.SimpleBlog&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Metalsharp.SimpleBlog&version=1.0.0
                    
Install as a Cake Tool

<div align="center">

Metalsharp.SimpleBlog

NuGet

A barebones blog plugin for Metalsharp

</div>


Metalsharp.SimpleBlog doesn't render anything itself. It walks the posts you've already generated, collects their metadata into an ordered list, and attaches that list to a new output file for a templating plugin (or your own code) to turn into an actual blog index page:

new MetalsharpProject()
    .AddInput("Posts")
    .UseFrontmatter()
    .UseMarkdown()
    .UseSimpleBlog(new SimpleBlogOptions
    {
        PostsDirectory = "Posts",
        PostsOrderQuery = file => DateTime.Parse((string)file.Metadata["date"])
    })
    .Build();

What SimpleBlog Does

  1. Gathers posts — filters project.OutputFiles down to whatever sits in SimpleBlogOptions.PostsDirectory, optionally sorted by a key you supply (e.g. publish date).
  2. Annotates each post — optionally runs your PostMetadata function against each file to inject extra fields, adds a fileName entry, then snapshots that file's metadata into a posts list.
  3. Emits an index file — adds a new output file (blog.html by default, empty content) whose metadata is your BlogMetadata merged with that posts list.

Nothing gets rendered to HTML for you — the plugin's whole job is handing a posts collection to whatever runs after it in the pipeline.

Tutorial

This walks through building a minimal blog with a listing page. It assumes you're already comfortable with the basics of Metalsharp itself — if not, its quickstart is a good five-minute primer.

Lay out the project

MyBlog
├── Posts
│   ├── hello-world.md
│   └── a-second-post.md
└── Program.cs

Each post is a Markdown file with frontmatter:

---
title: Hello, World!
date: 2026-01-15
---

This is my first post.
---
title: A Second Post
date: 2026-02-01
---

And here's another one.

Build the pipeline

using Metalsharp;
using Metalsharp.SimpleBlog;

new MetalsharpProject()
    .AddInput("Posts")
    .UseFrontmatter()
    .UseMarkdown()
    .UseSimpleBlog(new SimpleBlogOptions
    {
        PostsDirectory = "Posts",
        PostsOrderQuery = file => DateTime.Parse((string)file.Metadata["date"])
    })
    .Build();

UseFrontmatter reads the title/date block into each file's Metadata, and UseMarkdown turns the Markdown body into HTML — so by the time UseSimpleBlog runs, project.OutputFiles already contains Posts/hello-world.html and Posts/a-second-post.html, each carrying its own frontmatter.

SimpleBlog picks those two files out (their virtual Directory matches PostsDirectory), sorts them newest-first by the parsed date (PostsOrderedDescending defaults to true), and adds a third output file, blog.html, whose metadata looks like:

Metadata["posts"] = [
    { title = "A Second Post", date = "2026-02-01", fileName = "a-second-post" },
    { title = "Hello, World!", date = "2026-01-15", fileName = "hello-world" }
]

Note that frontmatter values arrive as plain strings — that's why PostsOrderQuery parses date with DateTime.Parse rather than casting it directly.

Render the listing page

blog.html is added with empty content — SimpleBlog only prepares the metadata. Render it with whatever templating plugin you're already using, or do it by hand with a plugin of your own. MetalsharpFile.Text is read-only, so write to Contents instead:

using System.Text;

new MetalsharpProject()
    .AddInput("Posts")
    .UseFrontmatter()
    .UseMarkdown()
    .UseSimpleBlog(new SimpleBlogOptions
    {
        PostsDirectory = "Posts",
        PostsOrderQuery = file => DateTime.Parse((string)file.Metadata["date"])
    })
    .Use(project =>
    {
        var blog = project.OutputFiles.First(f => f.FilePath == "blog.html");
        var posts = (List<Dictionary<string, object>>)blog.Metadata["posts"];

        var html = string.Join('\n', posts.Select(post =>
            $"<article><h2>{post["title"]}</h2><p>{post["date"]}</p></article>"
        ));

        blog.Contents = Encoding.UTF8.GetBytes($"<main>{html}</main>");
    })
    .Build();

Running this produces blog.html listing both posts, newest first, alongside the two rendered post pages.

Configuring SimpleBlogOptions

Property Type Default Description
PostsDirectory string "" The virtual directory (as set by AddInput/AddOutput) that posts live in. Only output files whose Directory matches exactly are treated as posts.
PostsOrderedDescending bool true Whether PostsOrderQuery sorts newest/highest first. Ignored if PostsOrderQuery isn't set.
PostsOrderQuery Func<MetalsharpFile, DateTime>? null Selects the sort key for each post (typically a publish date parsed from metadata). If null, posts keep whatever order they're found in.
PostMetadata Func<MetalsharpFile, Dictionary<string, object>>? null Runs against each post file; anything it returns is merged into that file's metadata before it's copied into the posts list.
BlogFilePath string "blog.html" The virtual path of the output file SimpleBlog creates.
BlogMetadata Dictionary<string, object>? null Extra metadata to merge onto the blog output file, alongside the generated posts list.

Usage

project.UseSimpleBlog(options);

is shorthand for:

project.Use(new SimpleBlog(options));

options is optional in both forms — omit it to use every default in the table above.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 97 8/15/2026
0.9.0-rc.2 920 8/21/2022
0.9.0-rc.1 269 8/15/2022