~will-clarke/super-simple-static-site-generator

e485bc6d43c8d3fe3986bd744f927ad83c16cdc1 — William Clarke 2 years ago
Add ssssg shell script and a README
2 files changed, 138 insertions(+), 0 deletions(-)

A README.md
A ssssg
A  => README.md +23 -0
@@ 1,23 @@
# Super Simple Static Site Generator (`ssssg`)

I took heavy inspiration for this script from [ssg](https://www.romanzolotarev.com/ssg.html), written by Roman Zolotarev and an updated version of this, [ssg5](https://github.com/fmash16/ssg5) by u/fmash16.

## Features:

- 115 lines of fabulous shell script!
- Home page with a description of all posts
- Post feed, archived by date
- RSS Feed
- A comprehensive tagging system (tags page, pages per tag, tag links)
- Pandoc

## How to:

## Dependencies

`ssssg` uses [pandoc](https://pandoc.org/) to generate `html` from `markdown`.

## Some stuff that I could probably improve upon

- It's not very SEO-friendly. No sitemap. No opengraph tags.
- It's kind of slow. We delete and regenerate all pages and tags each time.

A  => ssssg +115 -0
@@ 1,115 @@
#!/bin/sh

main() {
    # Some housekeeping...
    rm -rf dst tmp && mkdir -p src dst/posts dst/tags tmp/tags tmp/posts
    touch src/config.yaml

    # Generate tmp/posts/*.md, tmp/index.md, tmp/posts.md, tmp/tags.md,
    # tmp/tags/example-tag.md files, using our posts as a source
    find src/posts -type f -name "*.md" | sort -r | generate_tmp_files

    # Generate tags.md file. Grab the list of tags from our tmp/tags directory,
    # then chuck them all into a tmp directory, which we then sort & pandoc-ise.
    tags=$(find tmp/tags -type f -print0 | xargs -0 -I {} basename {} ".md")
    echo "$tags" | while read -r tag; do
        tag_count="$(wc -l < tmp/tags/"$tag".md | xargs)"
        echo "- [$tag](tags/$tag.html) ($tag_count)" >> tmp/tags-unsorted.md
        tags_file=$(cat "tmp/tags/$tag.md")
        printf -- "---\ntitle: %s tags\n---\n\n%s" "$tag" "$tags_file" > "tmp/tags/$tag.md"
    done
    sort tmp/tags-unsorted.md >> tmp/tags.md && rm tmp/tags-unsorted.md

    # Find all markdown files in out tmp directory and then turn them into
    # corresponding html in the dst path.
    find tmp -type f -name "*.md" | while read -r file; do
        html_dst_path="$(echo "$file" | sed -e 's/tmp/dst/' -e's/\.md$/\.html/')"
        md_file_to_html_file "$file" > "$html_dst_path"
    done

    md_file_to_html_file src/about.md > dst/about.html

    generate_rss_feed > dst/index.xml

    cp -r src/css dst/css

    echo "Generated $(find dst | wc -l) files"
}

md_file_to_html_file() {
    input_file="$1"
    pandoc \
        --css="/css/style.css" \
        --include-before-body src/_top.html \
        --include-after-body src/_bottom.html \
        --title "$(config_for title)" \
        --to=html5  \
        "$input_file"
}

# Generate tmp/posts/*.md, tmp/index.md, tmp/posts.md, tmp/tags.md,
# tmp/tags/example-tag.md files, using our posts as a source
generate_tmp_files() {
    # We initially load up some sane front-matter defaults for pandoc.
    printf -- "---\ntitle: Home\n---\n\n%b\n\n---\n\n" "$(config_for index_md)" > tmp/index.md
    printf -- "---\ntitle: Posts\n---\n" > tmp/posts.md
    printf -- "---\ntitle: Tags\n---\n" > tmp/tags.md
    # For every post, we want to:
    while read -r post_file_path; do
        # Assigning variables from the front-matter of the markdown post
        post_md_file=$(cat "$post_file_path")
        title=$(echo "$post_md_file" | grep -iE '^title: ' | cut -d' ' -f 2-)
        description=$(echo "$post_md_file" | grep -iE '^description: ' | cut -d' ' -f 2-)
        post_date=$(echo "$post_md_file" | grep -iE '^date: ' | cut -d' ' -f 2-)
        tags=$(echo "$post_md_file" | grep -iE '^tags: ' | cut -d' ' -f 2-)

        # Calculate the ultimate root paths for the generated html files
        dst_path=$(echo "$post_file_path" | sed -e's#src/##' -e's/\.md$/\.html/' -e's#tags/##')

        # A list of tags converted to a list of markdown links
        linked_tags=$(echo "$tags" | xargs -n1 -I {} echo "[{}](/tags/{}.html)")

        # Add a heading from every post into the index.md / posts.md
        # and generate all our tags
        printf "# [%s](%s)\n%s\n%s\n\n" "$title" "$dst_path" "$description" "$linked_tags" >> tmp/index.md
        printf -- "- *%s* [%s](%s)\n\n" "$post_date" "$title" "$dst_path" >> tmp/posts.md
        echo "$tags" | xargs -n1 -I "{tag}" sh -c "echo \"- *[$title](/$dst_path)* $post_date\" >> tmp/tags/{tag}.md"
        if [ -n "$linked_tags" ]; then
            tmp_path="$(echo "$post_file_path" | sed 's#src/#tmp/#')"
            cat "$post_file_path" > "$tmp_path"
            printf "\n\n---\n\n## Tags\n\n%s" "$linked_tags" >> "$tmp_path"
        fi
        # Add an RSS element for the page
        post_html_fragment="$(echo "$post_md_file" | tail -n +7 | pandoc --from markdown --to=html5)"
        echo "<item>
<title>$(echo "$title" | xml_encode)</title>
<link>$(config_for base_url)/$(echo "$dst_path" | xml_encode)</link>
<pubDate>$(gdate -d "$post_date" -R)</pubDate>
<guid>$(config_for base_url)/$(echo "$dst_path" | xml_encode)</guid>
<description><![CDATA[$post_html_fragment]]></description>
</item>" >> tmp/index.xml
    done
}

xml_encode() {
    sed "s/\&/\&amp;/g;s/>/\&gt;/g;s/</\&lt;/g;s/'/\&apos;/g"
}

config_for() {
    grep "^$1: " src/config.yaml | cut -d' ' -f2-
}

generate_rss_feed() {
    echo "<rss xmlns:atom=\"http://www.w3.org/2005/Atom\" version=\"2.0\">
<channel>
<title>$(config_for rss_title)</title>
<link>$(config_for base_url)</link>
<description>$(config_for rss_description)</description>
<generator>ssssg</generator>
<lastBuildDate>$(date -R)</lastBuildDate>
<atom:link href=\"$(config_for base_url)/index.xml\" rel=\"self\" type=\"application/rss+xml\"/>"
    cat tmp/index.xml
    echo "</channel></rss>"
}

main