All posts

Publishing markdown to the web

Most static site generators ask you to learn a build system, install dependencies, and maintain config files. Glifo takes a different approach: you write markdown, hit publish, and get a live site. The entire pipeline lives inside the app.

How it works

The publishing system is built into Glifo's Rust backend. When you publish, it:

  1. Filters your notes using chip-based queries (same as sidebar search)
  2. Resolves [wikilinks](wikilinks.html) to proper HTML links between pages
  3. Converts markdown to HTML with syntax highlighting, tables, and task lists
  4. Exports any Excalidraw embeds as inline SVG
  5. Wraps everything in a template with navigation, metadata, and styling
  6. Pushes all files to GitHub Pages in a single commit

No CLI, no Node.js, no next.config.js. The repo is created automatically if it doesn't exist.

Here's the full pipeline:

Filter noteschip queriesResolve[wikilinks](wikilinks.html)Markdown → HTMLpulldown-cmarkExport drawings→ inline SVGWrap in templatenav + meta + CSSPush to GitHubGit Trees APIGitHub Pagesuser.github.io"Write""Website"

Templates

Two templates ship today:

Write — editorial, serif-forward design. EB Garamond body text on a warm parchment palette with burnt orange accents. Navigation says "Writing". Best for essays and personal blogs.

Website — modern, sans-serif design inspired by shadcn/ui. Geist on a zinc palette with flat post rows, crisp borders, and subtle opacity hover states. Navigation says "Posts". Best for product pages and dev blogs.

Both include responsive layout, dark mode toggle, frosted glass nav, meta/OG tags, and emoji favicon.

The template system

Templates are Rust modules — no external template engine, no runtime. Each template is a set of functions that take structured data and return HTML strings:

pub fn generate(
    notes: &[&NoteToPublish],
    site: &SiteConfig,
    repo_name: &str,
) -> Vec<(String, String)> {
    // Returns Vec of (filename, html_content)
}

CSS lives in standalone .css files next to the Rust code, compiled in at build time via include_str!(). This means real syntax highlighting in your editor and zero runtime overhead.

Site metadata

Each publish target stores metadata that flows into the generated HTML:

FieldWhere it appears
Site titleBrowser tab, nav bar, footer, OG tags
DescriptionMeta description, OG description
AuthorMeta author tag, footer
IconEmoji → SVG favicon, or URL
Language<html lang="..."> attribute
Home pageWhich note becomes index.html

Multiple targets

Create as many publish targets as you want. Your blog, your docs, and your project notes can each go to different sites with different templates and filters. Each target is an independent [publish](publish.html) entry in your config.