Browse Source

Add Post: Creating a simple static blog

master
Hugo Thunnissen 8 months ago
parent
commit
6d331c6bf6
6 changed files with 492 additions and 3 deletions
  1. +8
    -1
      blog.html
  2. +8
    -2
      feed.xml
  3. +269
    -0
      generate-blog.bash.html
  4. +1
    -0
      posts.txt
  5. +205
    -0
      posts/simple-static-blog/index.html
  6. +1
    -0
      posts/simple-static-blog/publish_date.txt

+ 8
- 1
blog.html View File

@@ -39,7 +39,14 @@
</div>
<h1>Blog</h1>

<div><a href="posts/introduction/index.html"><h2 style="margin-bottom: 0.1em;"> Introduction </h2></a>
<div><a href="posts/simple-static-blog/index.html"><h2 style="margin-bottom: 0.1em;"> Creating a Simple Static Blog </h2></a>
<i style="font-size: 0.8em;">Sat 08 Feb 2020 12:14:16 PM CET</i><p style="margin-top: 0.5em;">I love personal websites. It&#39;s amazing that people can share content with the
entire world just by writing some text and throwing it on a web server. I
wanted to know what that is like, so I set out to create a personal website of
my own. As you can see I succeeded in the end. But getting here wasn&#39;t as
straight forward as I initially thought it would be. I thought that, being a ... <a href="posts/simple-static-blog/index.html">Continue reading</a></p>
</div>
<hr><div><a href="posts/introduction/index.html"><h2 style="margin-bottom: 0.1em;"> Introduction </h2></a>
<i style="font-size: 0.8em;">Sat 08 Feb 2020 09:30:06 AM CET</i><p style="margin-top: 0.5em;">Hello, welcome to my blog! My name is Hugo. I am a 22 year old Software
Engineering student from the Netherlands. Software development is a huge part
of my life, I write a lot of (weird) programs to scratch my own itch and most

+ 8
- 2
feed.xml View File

@@ -5,12 +5,18 @@
<link>https://hugot.nl/blog.html</link>
<description>Hugo's personal blog</description>
<language>en-us</language>
<pubDate>Sat 08 Feb 2020 10:41:46 AM CET</pubDate>
<lastBuildDate>Sat 08 Feb 2020 10:41:46 AM CET</lastBuildDate>
<pubDate>Sat 08 Feb 2020 05:04:18 PM CET</pubDate>
<lastBuildDate>Sat 08 Feb 2020 05:04:18 PM CET</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>Hugo's Custom Bash Script</generator>
<managingEditor>social@hugot.nl</managingEditor>
<webMaster>infra@hugot.nl</webMaster>
<item><title> Creating a Simple Static Blog </title><link>https://hugot.nl/posts/simple-static-blog/index.html</link><description>I love personal websites. It&#39;s amazing that people can share content with the
entire world just by writing some text and throwing it on a web server. I
wanted to know what that is like, so I set out to create a personal website of
my own. As you can see I succeeded in the end. But getting here wasn&#39;t as
straight forward as I initially thought it would be. I thought that, being a</description><pubDate>Sat 08 Feb 2020 12:14:16 PM CET</pubDate><guid isPermaLink="false"> Creating a Simple Static Blog Mzk2MDM4MTY0MCAyNjg0Cg==</guid>
</item>
<item><title> Introduction </title><link>https://hugot.nl/posts/introduction/index.html</link><description>Hello, welcome to my blog! My name is Hugo. I am a 22 year old Software
Engineering student from the Netherlands. Software development is a huge part
of my life, I write a lot of (weird) programs to scratch my own itch and most

+ 269
- 0
generate-blog.bash.html View File

@@ -0,0 +1,269 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<!-- Created by htmlize-1.56 in css mode. -->
<html>
<head>
<title>generate-blog.bash</title>
<style type="text/css">
<!--
body {
color: #f6f3e8;
background-color: #242424;
}
.builtin {
/* font-lock-builtin-face */
color: #e5786d;
}
.comment {
/* font-lock-comment-face */
color: #99968b;
}
.comment-delimiter {
/* font-lock-comment-delimiter-face */
color: #99968b;
}
.function-name {
/* font-lock-function-name-face */
color: #cae682;
}
.keyword {
/* font-lock-keyword-face */
color: #8ac6f2;
font-weight: bold;
}
.negation-char {
}
.sh-heredoc {
/* sh-heredoc */
color: #ffff00;
font-weight: bold;
}
.sh-quoted-exec {
/* sh-quoted-exec */
color: #fa8072;
}
.string {
/* font-lock-string-face */
color: #95e454;
}
.variable-name {
/* font-lock-variable-name-face */
color: #cae682;
}

a {
color: inherit;
background-color: inherit;
font: inherit;
text-decoration: inherit;
}
a:hover {
text-decoration: underline;
}
-->
</style>
</head>
<body>
<pre>
<span class="comment-delimiter">#</span><span class="comment">!/bin/</span><span class="keyword">bash</span><span class="comment">
</span><span class="comment-delimiter">##</span><span class="comment">
</span><span class="comment-delimiter"># </span><span class="comment">Generate html page with blog article excerpts from ./posts.txt. Post file names should
</span><span class="comment-delimiter"># </span><span class="comment">be added to ./posts.txt in the exact order that they are supposed to appear on the blog
</span><span class="comment-delimiter"># </span><span class="comment">page.
</span>
<span class="comment-delimiter"># </span><span class="comment">Check if required executables can be found
</span><span class="keyword">if ! </span><span class="builtin">type</span> readlink dirname html2text mv cat cksum base64; <span class="keyword">then</span>
<span class="builtin">echo</span> <span class="string">'One or more required executables are not present. Generation cancelled'</span> &gt;&amp;2
<span class="keyword">exit</span> 1
<span class="keyword">fi</span>

<span class="comment-delimiter"># </span><span class="comment">Determine script directory (requires GNU readlink)
</span><span class="variable-name">here</span>=<span class="string">"$(</span><span class="sh-quoted-exec">dirname</span><span class="string"> "$(</span><span class="sh-quoted-exec">readlink</span><span class="string"> -f "${BASH_SOURCE[0]}")")"</span>

<span class="builtin">printf</span> <span class="string">'Changing directory: '</span>
<span class="builtin">pushd</span> <span class="string">"$here"</span> || <span class="keyword">exit</span> $<span class="variable-name">?</span>

<span class="variable-name">posts_file</span>=<span class="string">"$here/posts.txt"</span>

<span class="keyword">if</span> <span class="negation-char">!</span> [[ -f <span class="string">"$posts_file"</span> ]]; <span class="keyword">then</span>
<span class="builtin">printf</span> <span class="string">'Posts file "%s" not found. Generation cancelled.\n'</span> <span class="string">"$posts_file"</span> &gt;&amp;2
<span class="keyword">exit</span> 1
<span class="keyword">fi</span>

<span class="function-name">escape-html</span>() {
sed <span class="string">'s/&amp;/\&amp;amp;/g; s/&lt;/\&amp;lt;/g; s/&gt;/\&amp;gt;/g; s/"/\&amp;quot;/g; s/'"'"'/\&amp;#39;/g'</span>
}

<span class="function-name">html-to-text</span>() {
html2text -nobs -style compact <span class="string">"$@"</span>
}

<span class="function-name">print-blog-html-top</span>() {
<span class="builtin">echo</span> <span class="string">'&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Blog&lt;/title&gt;
&lt;meta charset="UTF-8"&gt;
&lt;/head&gt;

&lt;style type="text/css"&gt;
html {
font-family: Helvetica, Arial, sans-serif;
color: #5b4636;
background-color: #f4ecd8;
}

body {
padding: 1em;
margin: auto;
}

@media only all and (pointer: coarse), (pointer: none) {
body {
font-size: 5.5vmin;
}
}

@media only all and (pointer: fine) {
body {
font-size: calc(16px + 0.6vmin);
min-width: 500px;
max-width: 50em;
}
}
&lt;/style&gt;

&lt;body&gt;
&lt;div style="display: flex; flex-direction: horizontal;"&gt;
&lt;a href="index.html"&gt;Home&lt;/a&gt;
&lt;span style="margin-left: 1em; margin-right: 1em;"&gt;|&lt;/span&gt;
&lt;a href="feed.xml"&gt;RSS Feed&lt;/a&gt;
&lt;/div&gt;
&lt;h1&gt;Blog&lt;/h1&gt;
'</span>
}

<span class="function-name">print-blog-html-bottom</span>() {
<span class="builtin">echo</span> <span class="string">' &lt;/body&gt;
&lt;/html&gt;'</span>
}

<span class="comment-delimiter"># </span><span class="comment">Note: pubDate and lastBuildDate are both set to the current time.
</span><span class="function-name">print-blog-rss-top</span>() {
cat &lt;&lt;EOF<span class="sh-heredoc">
&lt;?xml version="1.0"?&gt;
&lt;rss version="2.0"&gt;
&lt;channel&gt;
&lt;title&gt;Hugot Blog&lt;/title&gt;
&lt;link&gt;https://hugot.nl/blog.html&lt;/link&gt;
&lt;description&gt;Hugo's personal blog&lt;/description&gt;
&lt;language&gt;en-us&lt;/language&gt;
&lt;pubDate&gt;$(</span><span class="sh-quoted-exec">date</span><span class="sh-heredoc">)&lt;/pubDate&gt;
&lt;lastBuildDate&gt;$(</span><span class="sh-quoted-exec">date</span><span class="sh-heredoc">)&lt;/lastBuildDate&gt;
&lt;docs&gt;http://blogs.law.harvard.edu/tech/rss&lt;/docs&gt;
&lt;generator&gt;Hugo's Custom Bash Script&lt;/generator&gt;
&lt;managingEditor&gt;social@hugot.nl&lt;/managingEditor&gt;
&lt;webMaster&gt;infra@hugot.nl&lt;/webMaster&gt;
EOF
</span>}

<span class="function-name">print-blog-rss-bottom</span>() {
<span class="builtin">echo</span> <span class="string">'&lt;/channel&gt;
&lt;/rss&gt;'</span>
}

<span class="function-name">el</span>() {
<span class="variable-name">format_string</span>=<span class="string">"$1"</span>
<span class="builtin">shift</span>

<span class="builtin">printf</span> <span class="string">"&lt;$format_string&gt;"</span> <span class="string">"$@"</span>
}

<span class="function-name">el-close</span>() {
<span class="builtin">echo</span> <span class="string">"&lt;/$1&gt;"</span>
}

<span class="function-name">el-enclose</span>() {
<span class="variable-name">element_name</span>=<span class="string">"$1"</span>
<span class="builtin">shift</span>

<span class="builtin">printf</span> <span class="string">'%s'</span> <span class="string">"&lt;$element_name&gt;"</span>
<span class="builtin">printf</span> <span class="string">'%s'</span> <span class="string">"$@"</span>
<span class="builtin">printf</span> <span class="string">'%s'</span> <span class="string">"&lt;/$element_name&gt;"</span>
}

<span class="variable-name">site_url</span>=<span class="string">"https://hugot.nl"</span>

<span class="variable-name">blog_html</span>=<span class="string">"$here/blog.html"</span>
<span class="variable-name">new_html</span>=<span class="string">"$blog_html.new"</span>

<span class="variable-name">blog_rss</span>=<span class="string">"$here/feed.xml"</span>
<span class="variable-name">new_rss</span>=<span class="string">"$blog_rss.new"</span>

print-blog-html-top &gt; <span class="string">"$new_html"</span>
print-blog-rss-top &gt; <span class="string">"$new_rss"</span>

<span class="keyword">while </span><span class="builtin">read</span> -r post_html; <span class="keyword">do</span>
<span class="comment-delimiter"># </span><span class="comment">Convert the post's html to text to make it easier to use the blog's text
</span> <span class="variable-name">text</span>=<span class="string">"$(</span><span class="sh-quoted-exec">html-to-text</span><span class="string"> "$post_html" | escape-html)"</span> || <span class="keyword">exit</span> $<span class="variable-name">?</span>

<span class="comment-delimiter"># </span><span class="comment">The title should be on the 2nd line of text, right after the link to the
</span> <span class="comment-delimiter"># </span><span class="comment">homepage. This is a bit inflexible but it will do for now.
</span> <span class="variable-name">title</span>=<span class="string">"$(</span><span class="sh-quoted-exec">tail</span><span class="string"> -n +2 &lt;&lt;&lt;"$text" | head -n 1 | tr -d '*')"</span> || <span class="keyword">exit</span> $<span class="variable-name">?</span>

<span class="comment-delimiter"># </span><span class="comment">Use the first 5 lines after the title as post excerpt.
</span> <span class="variable-name">excerpt</span>=<span class="string">"$(</span><span class="sh-quoted-exec">tail</span><span class="string"> -n +3 &lt;&lt;&lt;"$text" | head -n 5)"</span> || <span class="keyword">exit</span> $<span class="variable-name">?</span>
<span class="comment-delimiter"># </span><span class="comment">Escape the post html file name to safely use it in the generated html.
</span> <span class="variable-name">href</span>=<span class="string">"$(</span><span class="sh-quoted-exec">escape-html</span><span class="string"> &lt;&lt;&lt;"$post_html")"</span> || <span class="keyword">exit</span> $<span class="variable-name">?</span>
<span class="variable-name">post_dir</span>=<span class="string">"$(</span><span class="sh-quoted-exec">dirname</span><span class="string"> "$post_html")"</span> || <span class="keyword">exit</span> $<span class="variable-name">?</span>
<span class="variable-name">pubdate_file</span>=<span class="string">"$post_dir/publish_date.txt"</span>
<span class="comment-delimiter"># </span><span class="comment">Determine a publishing date for the post
</span> <span class="keyword">if</span> [[ -f <span class="string">"$pubdate_file"</span> ]]; <span class="keyword">then</span>
<span class="builtin">read</span> -r pubdate &lt; <span class="string">"$pubdate_file"</span>
<span class="keyword">else</span>
<span class="variable-name">pubdate</span>=<span class="string">"$(</span><span class="sh-quoted-exec">date</span><span class="string">)"</span>
<span class="builtin">echo</span> <span class="string">"$pubdate"</span> &gt; <span class="string">"$pubdate_file"</span>
<span class="keyword">fi</span>
{
el div
el <span class="string">'a href="%s"'</span> <span class="string">"$href"</span>
<span class="builtin">printf</span> <span class="string">'&lt;h2 style="margin-bottom: 0.1em;"&gt;%s&lt;/h2&gt;'</span> <span class="string">"$title"</span>
el-close a
<span class="builtin">printf</span> <span class="string">'&lt;i style="font-size: 0.8em;"&gt;%s&lt;/i&gt;'</span> <span class="string">"$pubdate"</span>
el <span class="string">'p style="margin-top: 0.5em;"'</span>
<span class="builtin">printf</span> <span class="string">'%s ... &lt;a href="%s"&gt;Continue reading&lt;/a&gt;'</span> <span class="string">"$excerpt"</span> <span class="string">"$href"</span>
el-close p
el-close div
el hr
} &gt;&gt; <span class="string">"$new_html"</span>
{
el item
el-enclose title <span class="string">"$title"</span>
el-enclose link <span class="string">"$site_url/$href"</span>
el-enclose description <span class="string">"$excerpt"</span>
el-enclose pubDate <span class="string">"$pubdate"</span>
<span class="builtin">echo</span> <span class="string">"&lt;guid isPermaLink=\"false\"&gt;$title$(</span><span class="sh-quoted-exec">base64</span><span class="string"> &lt;(cksum &lt;&lt;&lt;"$text"))&lt;/guid&gt;"</span>
el-close item
} &gt;&gt; <span class="string">"$new_rss"</span>
<span class="keyword"> done</span> &lt; <span class="string">"$posts_file"</span>
print-blog-html-bottom &gt;&gt; <span class="string">"$new_html"</span>
print-blog-rss-bottom &gt;&gt; <span class="string">"$new_rss"</span>
mv -v <span class="string">"$new_html"</span> <span class="string">"$blog_html"</span> || <span class="keyword">exit</span> $<span class="variable-name">?</span>
mv -v <span class="string">"$new_rss"</span> <span class="string">"$blog_rss"</span> || <span class="keyword">exit</span> $<span class="variable-name">?</span>
<span class="builtin"> echo</span> <span class="string">'SUCCESS!'</span>
</pre>
</body>
</html>

+ 1
- 0
posts.txt View File

@@ -1 +1,2 @@
posts/simple-static-blog/index.html
posts/introduction/index.html

+ 205
- 0
posts/simple-static-blog/index.html View File

@@ -0,0 +1,205 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Creating a Simple Static Blog</title>
<meta charset="UTF-8">
</head>

<style type="text/css">
html {
font-family: Helvetica, Arial, sans-serif;
color: #5b4636;
background-color: #f4ecd8;
}

body {
padding: 1em;
margin: auto;
}

@media only all and (pointer: coarse), (pointer: none) {
body {
font-size: 5.5vmin;
}
}

@media only all and (pointer: fine) {
body {
font-size: calc(16px + 0.6vmin);
min-width: 500px;
max-width: 50em;
}
}
</style>

<body>
<a href="../../blog.html">Home</a>
<h1>Creating a Simple Static Blog</h1>

<p>
I love personal websites. It's amazing that people can share content with the
entire world just by writing some text and throwing it behind a web server. I
wanted to know what that is like, so I set out to create a personal website of
my own. As you can see I succeeded in the end. But getting here wasn't as
straight forward as I initially thought it would be. I thought that, being a
programmer and knowing a thing or two about web servers, setting up my own
website was going to be easy: How complicated can it be to throw some text
behind a web server, right?! I was wrong. Throwing text behind a web server can be
very complicated (and wasteful). But it doesn't have to be!
</p>

<h2>The search for a CMS</h2>
<p>
The first thought that popped into my head when I got started was: <em>I need to
find myself a CMS</em>. I had a few requirements: my site should be
self-hosted, be lightweight, have no JavaScript in it and it should look
pretty. I also wanted to be able to write blog posts in markdown using my
trusty text editor. The first CMSes that came to mind were WordPress, Ghost,
Jekyll and Hugo. I don't want to get into too much detail, so I'll summarize
my judgments here without any nuance: Wordpress is the devil, Ghost is great
but too bulky and both Jekyll and Hugo required me to learn about theming and
project structure which I deemed too much effort. I just wanted to write some
text and throw it behind a web server, but all solutions I saw were sophisticated
programs that were designed to &quot;scale&quot;, support &quot;modern
workflows&quot; or be &quot;easy to use with integrated WYSIWYG
editors&quot;. I didn't feel like exploring the idea further and gave up on
having a website for a while.
</p>

<p>
Then, a few months back, I learned about writefreely. Writefreely is an open
source web application from write.as that lets users create blogs that
federate through the fediverse. I had just started to become acquainted with
the fediverse and it seemed like a cool idea to me at the time, so me and a
friend decided to set up our own instance. It wasn't too hard to set up and
once it was running I only needed a couple of hours to add some custom
style sheets. I finally had a fully functioning blog that satisfied all of my
needs!
</p>

<p>
After that the holiday season came along and I turned my back on blogging for
a while. When I checked on our instance three or four weeks later I was
displeased to discover that spammers had created accounts on the instance and
were posting spammy garbage. Sure, we could just close registrations. But this
event reminded me that hosting any dynamic web application on the public
internet is a big responsibility that involves keeping software up to date,
monitoring and doing other configuration/maintenance work. Not to mention
having to do regular database backups. I didn't feel like having to do any of
that, I already have by hands full with self-hosting a bunch of other
services. Once again I had found a complicated solution for a simple problem:
I just wanted to throw some text behind a web server, remember? Why did I need to use a CMS
again?
</p>

<p>
CMSes seem to offer solutions to a problem that I don't have: I don't mind
writing plain html and I most certainly don't need a WISYWIG editor. I also
don't need plugins, dynamic code for analytics, pretty yaml or toml
configuration files, templates, extensive theming, admin panels, markdown,
mailing lists, comment threads or any other common CMS features. I just want
to throw some text behind a web server, so why not just write some HTML and do
exactly that?
</p>

<h2>A CMS in ~200 lines</h2>
<p>
It was decided: I was going to blog in plain HTML. Having figured out what I
actually wanted, I went to work. The first order of business was creating a
style sheet to make things look good. I made it my goal to use as little CSS
as possible and I managed to limit myself to just these 23 lines:
</p>

<style type="text/css">
.code {
color: #f6f3e8;
background-color: #242424;
}
.builtin {
color: #e5786d;
}
.css-property {
color: #8ac6f2;
font-weight: bold;
}
.css-selector {
color: #cae682;
}
.custom {
color: #000000;
background-color: #f4ecd8;
}
.custom-1 {
color: #ffffff;
background-color: #5b4636;
}
</style>

<div class="code">
<pre>
<span class="css-selector">html </span>{
<span class="css-property">font-family</span>: Helvetica, Arial, sans-serif;
<span class="css-property">color</span>: <span class="custom-1">#5b4636</span>;
<span class="css-property">background-color</span>: <span class="custom">#f4ecd8</span>;
}
<span class="css-selector">body </span>{
<span class="css-property">padding</span>: 1em;
<span class="css-property">margin</span>: auto;
}
<span class="builtin">@media</span> only all and (pointer: coarse), (pointer: none) {
<span class="css-selector">body </span>{
<span class="css-property">font-size</span>: 5.5vmin;
}
}
<span class="builtin">@media</span> only all and (pointer: fine) {
<span class="css-selector">body </span>{
<span class="css-property">font-size</span>: calc(16px + 0.6vmin);
<span class="css-property">min-width</span>: 500px;
<span class="css-property">max-width</span>: 50em;
}
}
</pre>
</div>

<p>
This is all the CSS I need to have a responsive website that looks pretty (I
stole the colors from firefox's reader mode btw). It's such a small amount
that I don't mind copy-pasting it at the top of all new HTML pages that I add
to my website. This might make it harder to change the styling later, but it
has the added benefit that each page is a standalone document. So for example <code>wget PAGE_URL</code>
will download a HTML page that looks exactly the same locally as it does on
the web without having to download any extra assets.
</p>

<p>
The next challenge was creating and maintaining the article listing page and
the RSS feed for the blog. I don't mind typing HTML pages, but typing out a
page and an RSS feed containing excerpts/titles from other files gets old soon
and I'd be bound to forget updating its content every once in a while. This
seemed like a perfect occasion to write a little bash script, so I did. You
can find the script <a href="../../generate-blog.bash">here (raw)</a> and
<a href="../../generate-blog.bash.html">here (pretty)</a>. What it basically
does is read in a file called posts.txt that has html filenames in it,
separated by newlines. Using those filenames and the contents of the files it
then generates a HTML page (called <a href="../../blog.html">blog.html</a>)
and an RSS feed (called <a href="../../feed.xml">feed.xml</a>).
</p>

<p>
I keep all of this neatly stored under version control
<a href="https://snorba.art/hugo/website">here</a>, so deploying a new version
is as easy as running <code>git pull</code> on my web server. I can honestly say that
this is the simplest, most user-friendly CMS that I have ever used, and it
only took me several months to figure out that this is exactly what I needed 🤓.
</p>

<p>
So, to conclude this story: websites are just HTML. You don't need fancy
programs or WYSIWYG editors to create a website. Just a text editor, a web
server and some spare time.
</p>
</body>
</html>

+ 1
- 0
posts/simple-static-blog/publish_date.txt View File

@@ -0,0 +1 @@
Sat 08 Feb 2020 12:14:16 PM CET

Loading…
Cancel
Save