(w) smolweb

A smolweb bash generator

I publish this ugly code just to show that it is very easy to build and regenerate a smolwebsite with a few lines of bash script.

It uses discount markdown converter to generate html code from .md files.

All files

The source directory contains the converter, favicons, a page template and markdown content of each page. Two folder would be used to store image (/img) and documents (/doc).

.
├── convert.sh
├── doc
│   └── index.html
├── favicon-32x32.png
├── favicon-64x64.png
├── favicon.ico
├── guidelines.md
├── img
│   └── index.html
├── index.md
├── news.md
├── page.tpl
├── posts
│   ├── 2023-10-09-1st-post.md
│   ├── 2023-10-09-an-other-smallweb-definition.md
│   └── 2023-10-11-smolweb-bash-generator.md
├── style.css
└── subset.md

The bash script

This script (called convert.sh) uses files put in the same directory to generate the content of smolweb.org

#!/bin/bash

cd "$(dirname "$0")"
export docroot="../smolweb.org"
export urlroot="https://smolweb.org"
cp -vu *.{ico,png,css} $docroot
cp -vu img/* $docroot/img/
cp -vu doc/* $docroot/doc/


echo "# News" > news.md
echo '<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
    xmlns:thr="http://purl.org/syndication/thread/1.0"
    xml:lang="en">
    <title type="text">smolweb.org</title>
    <subtitle type="text">Smolweb news</subtitle>
    <updated>'"$(date -u -Isecond)"'</updated>
    <link rel="alternate" type="text/html" href="'"$urlroot"'/" />
    <id>'"$urlroot"'/</id>
    <link rel="self" type="application/atom+xml" href="'"$urlroot"'/atom.xml" />' > $docroot/atom.xml
# posts
for f in `ls -1r posts/*.md`;
do
    head -n 3 "$f" | grep "^# " | sed -e "s/^# //" > /tmp/title.tmp
    cat "$f" |  markdown -f fencedcode > /tmp/content.tmp
    cat "$f" |  markdown -f fencedcode -f cdata > /tmp/cdata.tmp
    cat page.tpl | sed -e "/PAGE_TITLE/r /tmp/title.tmp" -e '//d' -e "/PAGE_CONTENT/r /tmp/content.tmp" -e '//d' > $docroot/${f%.*}.html
    echo "* $(echo $f | grep -oP "[0-9]{4}-[0-9]{2}-[0-9]{2}") [$(cat /tmp/title.tmp)](${f%.*}.html)" >> news.md
    
    echo '  <entry xml:lang="en">
        <author><name>Adële</name><uri>'"$urlroot"'/</uri></author>
        <title type="html">'"$(cat /tmp/title.tmp)"'</title>
        <link rel="alternate" type="text/html" href="'"$urlroot"'/'"${f%.*}.html"'" />
        <id>'"$urlroot"'/'"${f%.*}.html"'</id>
        <published>'"$(echo $f | grep -oP "[0-9]{4}-[0-9]{2}-[0-9]{2}")"'T00:00:00+00:00</published>
        <updated>'"$(date -u -Isecond --date=$(stat -c '@%Y' $f))"'</updated>
        <content type="html">' >> $docroot/atom.xml
    cat /tmp/cdata.tmp >> $docroot/atom.xml
    echo '      </content>
    </entry>'>> $docroot/atom.xml
done
echo '</feed>' >> $docroot/atom.xml

# pages
for f in *.md
do
    head -n 3 "$f" | grep "^# " | sed -e "s/^# //" > /tmp/title.tmp
    cat "$f" |  markdown -f fencedcode > /tmp/content.tmp
    cat page.tpl | sed -e "/PAGE_TITLE/r /tmp/title.tmp" -e '//d' -e "/PAGE_CONTENT/r /tmp/content.tmp" -e '//d' > $docroot/${f%.*}.html
done

The markdown files

The files with .md extension contain text in markdown format. The first line begining with with a # and a space is the H1 and the title of the page.

Example index.md:

# About smolweb

_Promoting a simple unbloated web!_

Nowadays, hardware resources of our personal devices are essentially
oversized to manage bloated websites. If we incite web designers to
return to a lighter web, small devices such as old PC, old smartphones,
retro-machines and small boards could be usable.

...

The site template

The file page.tpl contains the template of a page for the site. the line PAGE_TITLE and PAGE_CONTENT are replaced dynamically to generate each page of the site.

<!DOCTYPE html>
<html lang="en">
        <head>
                <meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
                <meta name="viewport" content="width=device-width, initial-scale=1.0" >
                <meta name="description" content="smolweb.org promotes simple unbloated web. It provides resources to actors who want to participate." >
                <link href="/style.css" rel="stylesheet" type="text/css" >
                <link href="/atom.xml" rel="alternate" type="application/atom+xml" title="Smolweb news" >
                <link rel="icon" href="/favicon.ico" type="image/x-icon" >
                <link rel="icon" href="/favicon-64x64.png" type="image/png" >
                <title>
                        PAGE_TITLE
                </title>
        </head>
        <body>
                <header>
                <p>
                        <small><code>(w)</code></small> smolweb
                </p>
                <nav><ul>
                        <li><a href="/index.html">Home</a></li>
                        <li><a href="/guidelines.html">Guidelines</a></li>
                        <li><a href="/subset.html">HTML subset</a></li>
                        <li><a href="/news.html">News</a></li>
                        <li><a href="/atom.xml">RSS feed</a></li>
                </ul></nav> 
                </header>
                <main>
                        <article>
                                PAGE_CONTENT
                        </article>
                </main>
                <footer>
                         <p><a property="dct:title" rel="cc:attributionURL" href="https://smolweb.org/">Smolweb</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://mastodon.tetaneutral.net/@adele">Adële</a> is licensed under <a href="http://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="license noopener noreferrer">CC BY-SA 4.0</a></p> 
                </footer>
        </body>
</html>

The stylesheet

The file style.css is the stylesheet for the whole site.

body {
    margin: 0 auto;
    padding: 0;
    max-width: 1024px;
    font-family: Verdana, Sans-Serif;
} 
main {
    margin: 0 1em;
}
header {
    color: #a0a;
    background-color: #ddf;
    padding: 0.2em;
    border-bottom: 1px solid black;
}
header p {
    line-height: 2em;
    font-size: 2em;
    margin: 0;
    padding-left: 1em;
    font-weight: bold;
}
header p small {
    font-size: 0.5em;
}
nav ul {
    list-style-type: none;
    border-left: 1px solid black;
    margin: 0;
    padding: 0;
}
nav ul li {
    display: inline-block;
    border-right: 1px solid black;
    padding: 2px 10px;
    margin: 0;
}
nav ul li a.active {
    font-weight: bold;
}
img#logo {
    vertical-align: middle;
    max-width: 80px;
    max-height: 80px;
} 
pre, code {
    font-family: Monaco, Courier, monospace;
    tab-size: 1em;
}
pre {
    padding: 1em;
    margin: 1em 0;
    overflow-x: auto;
    background-color: #111;
    color: #6f6;
    border-radius: 0.5em;
}
li {
    margin-left: 1em;
}
p {
    margin: 1em 0;
    line-height: 1.5em;
}
a {
    color: #009;
    text-decoration: none;
}
blockquote {
    background: #eee;
    padding: 0.5em 1em;
    margin: 0 0 0 0.5em;
    border-radius: 0.5em;
}
div.inline-img img {
    max-width: 100%;
}
footer {
    margin-top: 20px;
    border-top: 1px solid black;
}
footer img {
    height:22px!important;
    margin-left:3px;
    vertical-align:text-bottom;
}

@media (prefers-color-scheme: dark) {
    body {
        color: #eee;
        background: #444;
    }
    a {
        color: #99f;
    }
    blockquote {
        color: #fff;
        background: #333;
    }
}