How does this work?

I use Quartz v4 to compile Markdown notes, written in Obsidian with wikilinks and other niceties, into a static site which I host on a VPS. My setup was originally inspired by Ryan Murphy and Brandon Boswell but I’ve since upgraded to use the new, Node-backed version of Quartz.

Build

  • compile.sh
    • Delete any copied and compiled content in site directories
    • Copy over vault minus excluded files and dirs
    • Preprocess content
    • Build site with Quartz
#!/bin/bash
 
VAULT_LOCATION="$HOME/zettel"
SITE_LOCATION="$HOME/sites/quartz"
RSYNC_EXCLUDE="$VAULT_LOCATION/meta/rsync-exclude.md"
 
preprocess() {
    find "$SITE_LOCATION/content" -name "*.md" -print0 | while IFS= read -r -d '' f; do
        sed -i -r -e 's/(>\s\[\!.*)\|\w+(\])[+-]?/\1\2/g;' \
[\s]?[\n]?//g;' \
            -e 's/(>\s\[!.*\][+-]?.*$)/\1\n>/g' \
            -e 's/[^\S\r\n]?\^rw[0-9]{9}//g' \
            -e '/-\s[\*]?Anhang|Zotero[\*]?::.*/d' \
            "$f"
    done
}
 
echo "Deleting content in site location"
find "$SITE_LOCATION/public/" -mindepth 1 -delete
find "$SITE_LOCATION/content/" -mindepth 1 -delete
 
echo "Copying files from vault"
rsync -aq --exclude-from="$RSYNC_EXCLUDE" "$VAULT_LOCATION/" "$SITE_LOCATION/content"
 
echo "Running preprocessing script"
preprocess
 
echo "Building site"
cd "$SITE_LOCATION" && npx quartz build

Preview

  • serve.sh
    • Local dev environment
    • Rebuild site on change
#!/bin/bash
SITE_LOCATION="$HOME/sites/quartz"
cd "$SITE_LOCATION" && npx quartz build --serve

Alternatively, you can compile the site and preview changes using a local web server, e.g. Caddy. Just build the site with npx quartz build, then tell Caddy to serve from the public folder:

caddy file-server --root "$SITE_LOCATION/sites/quartz/public/" --listen :3000

Maintenance

  • no-title.py
    • Check for files that don’t have a title property, excluding anything in my “meta” folder
#!/usr/bin/python3
 
import frontmatter
from pathlib import Path
 
directory = Path("zettel")
pathlist = [f for f in directory.glob("**/*.md") if not str(f).startswith("zettel/meta")]
logfile = "zettel/meta/no-title.md"
 
files_without_title = []
 
for path in pathlist:
    try:
        content = frontmatter.load(str(path))
        
        if "title" not in content.keys():
            files_without_title.append(f"- [[{path.stem}]]\n")
    except:
        pass
        
with open(logfile, "w") as log:
    log.writelines(files_without_title)