This documentation is also published as Markdown for efficient machine reading: the whole site is indexed at /llms.txt, and every page has a clean Markdown copy at the same URL with .md appended. These are generated from the same source and cost far fewer tokens to read than this rendered HTML.

Skip to main content Skip to navigation
Getting Started

Add a hero, projects, and social links

Populate the four BlogSite homepage surfaces — hero block, My Work card, social-icon row, and top-nav links — on BlogSiteOptions.

By the end of this tutorial, the BlogSite host displays a hero headline on the home page, a "My Work" sidebar card listing three projects, a row of four social-media icons beneath it, and a top-nav bar populated from MainSiteLinks — all driven by BlogSiteOptions without a line of Razor.

Prerequisites

The finished code for this tutorial lives in examples/BlogSiteHeroProjectsSocialsExample.


1. Populate the hero block

The BlogSite home page renders a headline block at the very top, driven entirely by BlogSiteOptions.HeroContent. HeroContent is a two-field positional record — Title and Description — so a single constructor call is all it takes.

1

Add HeroContent to the AddBlogSite call

Open the AddBlogSite call from the previous tutorial and add one property. The HeroContent = new HeroContent(Title: …, Description: …) assignment is the only addition — no new DI registrations, no new Razor files, no front matter changes. The rest of the options block carries forward unchanged from the scaffold tutorial.

csharp
var builder = WebApplication.CreateBuilder(args);
  
builder.Services.AddBlogSite(() => new BlogSiteOptions
{
    SiteTitle = "Hero Blog",
    SiteDescription = "A BlogSite tutorial app demonstrating hero, projects, and social links.",
    CanonicalBaseUrl = "https://example.com",
  
    AuthorName = "Author Name",
    AuthorBio = "Writing about software, tools, and the occasional side project.",
  
    HeroContent = new HeroContent( 
        Title: "Field notes from a weekend content engine", 
        Description: "I build small tools for small problems. This is where I write about them."), 
});
  
var app = builder.Build();
app.UseBlogSite();
app.RunBlogSiteAsync(args).GetAwaiter().GetResult();

Checkpoint

  • Run dotnet run and visit http://localhost:5000/
  • The hero title "Field notes from a weekend content engine" and the description paragraph stack above the recent-posts list from the first-post tutorial

2. Add a "My Work" projects section

BlogSiteOptions.MyWork accepts a Project[] that the home page renders as a sidebar card titled "My Work". Project is a three-field positional record — Title, Description, Url. The Url becomes the <a href> around each rendered entry, so it can point at a GitHub repo, a product page, or any other URL.

1

Populate MyWork with a Project[] collection expression

Add the MyWork property right below HeroContent, populated with a C# collection expression. The property is typed as Project[] on BlogSiteOptions; its default is an empty list, so the "My Work" card stays invisible in the UI until populated here.

csharp
var builder = WebApplication.CreateBuilder(args);
  
builder.Services.AddBlogSite(() => new BlogSiteOptions
{
    SiteTitle = "Hero Blog",
    SiteDescription = "A BlogSite tutorial app demonstrating hero, projects, and social links.",
    CanonicalBaseUrl = "https://example.com",
  
    AuthorName = "Author Name",
    AuthorBio = "Writing about software, tools, and the occasional side project.",
  
    HeroContent = new HeroContent(
        Title: "Field notes from a weekend content engine",
        Description: "I build small tools for small problems. This is where I write about them."),
  
    MyWork = 
    [ 
        new Project( 
            Title: "Pennington", 
            Description: "A tiny .NET content engine for docs and blogs.", 
            Url: "https://github.com/example/pennington"), 
        new Project( 
            Title: "MonorailCSS", 
            Description: "Utility-first CSS generation for Razor.", 
            Url: "https://github.com/example/monorailcss"), 
        new Project( 
            Title: "Mdazor", 
            Description: "Inline Razor components inside Markdown.", 
            Url: "https://github.com/example/mdazor"), 
    ], 
});
  
var app = builder.Build();
app.UseBlogSite();
app.RunBlogSiteAsync(args).GetAwaiter().GetResult();

Checkpoint

  • Run dotnet run and visit http://localhost:5000/
  • A "My Work" sidebar card appears with three linked entries — Pennington, MonorailCSS, Mdazor — each clickable

The final two surfaces land in the same AddBlogSite call. Socials is a SocialLink(RenderFragment Icon, string Url)[]; MainSiteLinks is a HeaderLink(string Title, string Url)[] that BlogSite renders in both the top-nav of MainLayout.razor and the footer. The listing below adds both.

1

Reference the built-in social icons

The four built-in icons ship as static readonly RenderFragment fields on SocialIcons — pass the field directly, not as a component tag (SocialIcons.GithubIcon, not <SocialIcons.GithubIcon />). Add a using Pennington.BlogSite.Components; directive at the top of Program.cs so SocialIcons.GithubIcon resolves.

2

Add the Socials and MainSiteLinks blocks

Add a Socials = [...] block with four entries covering all four built-ins, then a MainSiteLinks = [...] block with three entries — Home pointing to /, Archive to /archive, and Tags to /tags. Those URLs match the routes BlogSite includes, so the top-nav populates with no additional code.

csharp
var builder = WebApplication.CreateBuilder(args);
  
builder.Services.AddBlogSite(() => new BlogSiteOptions
{
    SiteTitle = "Hero Blog",
    SiteDescription = "A BlogSite tutorial app demonstrating hero, projects, and social links.",
    CanonicalBaseUrl = "https://example.com",
  
    AuthorName = "Author Name",
    AuthorBio = "Writing about software, tools, and the occasional side project.",
  
    HeroContent = new HeroContent(
        Title: "Field notes from a weekend content engine",
        Description: "I build small tools for small problems. This is where I write about them."),
  
    MyWork =
    [
        new Project(
            Title: "Pennington",
            Description: "A tiny .NET content engine for docs and blogs.",
            Url: "https://github.com/example/pennington"),
        new Project(
            Title: "MonorailCSS",
            Description: "Utility-first CSS generation for Razor.",
            Url: "https://github.com/example/monorailcss"),
        new Project(
            Title: "Mdazor",
            Description: "Inline Razor components inside Markdown.",
            Url: "https://github.com/example/mdazor"),
    ],
  
    Socials = 
    [ 
        new SocialLink(SocialIcons.GithubIcon, "https://github.com/example"), 
        new SocialLink(SocialIcons.BlueskyIcon, "https://bsky.app/profile/example.bsky.social"), 
        new SocialLink(SocialIcons.LinkedInIcon, "https://www.linkedin.com/in/example"), 
        new SocialLink(SocialIcons.MastodonIcon, "https://hachyderm.io/@example"), 
    ], 
  
    MainSiteLinks = 
    [ 
        new HeaderLink("Home", "/"), 
        new HeaderLink("Archive", "/archive"), 
        new HeaderLink("Tags", "/tags"), 
    ], 
});
  
var app = builder.Build();
app.UseBlogSite();
app.RunBlogSiteAsync(args).GetAwaiter().GetResult();

Checkpoint

  • Run dotnet run and visit http://localhost:5000/
  • A horizontal row of four SVG icons — GitHub, Bluesky, LinkedIn, Mastodon — sits below the "My Work" sidebar card, each linking out to its Url
  • A "Home / Archive / Tags" link row appears in the site header, and the same three links repeat in the footer nav
  • Click Archive — the archive page lists the first post from the previous tutorial

Summary

  • HeroContent now drives the home-page headline block.
  • A Project[] on MyWork brought the "My Work" sidebar card to life with three linked entries.
  • Four SocialLink entries wire the built-in SocialIcons.GithubIcon, BlueskyIcon, LinkedInIcon, and MastodonIcon RenderFragment fields — no Razor required.
  • MainSiteLinks holds three HeaderLink entries, and they render in both the top-nav and the footer.
  • All four homepage surfaces on BlogSiteOptions (hero, work, socials, header links) populate from one options block.

That completes the BlogSite getting-started arc — you have a scaffolded host, a fully-populated post, and a configured home page. From here, populate the blog homepage is the how-to that revisits these same options when you need them on their own, generate social card images adds OpenGraph cards to every post, and Built-in BlogSite routes catalogs the full route surface the template serves.