๐Ÿ“ Blog Publishing

Load markdown posts with frontmatter and render to SEO-friendly HTML.

๐ŸŽฏ Overview

Class Purpose
PostLoader Load markdown posts from filesystem
MarkdownEngine Render markdown to SEO-friendly HTML

๐Ÿ“‚ PostLoader

Method Purpose
.load_posts() Load all posts sorted by date
.get_post() Get single post by slug

source

PostLoader


def PostLoader(
    posts_dir:str, # Directory containing .md files
):

Load and parse markdown blog posts from filesystem


source

PostLoader.load_posts


def load_posts(
    
)->List[Dict]:

Load all markdown posts from directory.

Returns list of post dicts sorted by date (newest first). Each post contains: title, date, slug, body, categories, author, series.

Example: ```python loader = PostLoader(โ€˜blog/postsโ€™) posts = loader.load_posts()

for post in posts:
    print(f"{post['title']} - {post['slug']}")
```

source

PostLoader.get_post


def get_post(
    slug:str
)->Optional[Dict]: # URL slug (e.g., 'my-post')

Get single post by slug.

Example: python post = loader.get_post('bg0010') if post: print(post['title'])

๐ŸŽจ MarkdownEngine

Method Purpose
.render() Convert markdown to HTML

source

MarkdownEngine


def MarkdownEngine(
    
):

Render markdown to HTML with SEO extensions


source

MarkdownEngine.render


def render(
    content:str
)->str: # Markdown content

Convert markdown to HTML.

    Returns HTML string with proper semantic tags for SEO.

    Example:
        ```python
        engine = MarkdownEngine()
        html = engine.render('# Hello
This is bold.โ€™) print(html) #

Hello

This is bold.

        ```

source

MarkdownEngine.get_toc


def get_toc(
    
)->str:

Get table of contents HTML from last render.

    Must call render() first. Returns empty string if no headings.

    Example:
        ```python
        engine = MarkdownEngine()
        html = engine.render('# Title

Section 1

Section 2โ€™)

        toc = engine.get_toc()
        print(toc)  # <ul><li><a href="#section-1">Section 1</a>...</li></ul>
        ```

FastHTML Integration Example

Basic pattern for server-side rendering with FastHTML:

from fasthtml.common import *
from fh_saas.utils_blog import PostLoader, MarkdownEngine

app = FastHTML()
loader = PostLoader('blog/posts')
engine = MarkdownEngine()

@app.get('/blog')
def blog_index():
    posts = loader.load_posts()
    return Titled('Blog',
        *[Article(
            H2(A(p['title'], href=f"/blog/{p['slug']}")),
            P(p['description']),
            Small(p['date'].strftime('%Y-%m-%d') if p['date'] else '')
        ) for p in posts]
    )

@app.get('/blog/{slug}')
def blog_post(slug: str):
    post = loader.get_post(slug)
    if not post:
        return 'Post not found', 404
    
    html_content = engine.render(post['body'])
    toc = engine.get_toc()
    
    return Titled(post['title'],
        Article(
            NotStr(toc),  # Table of contents
            NotStr(html_content)  # Rendered markdown
        )
    )