Add Post: Creating a simple static blog
parent
62c74d974c
commit
6d331c6bf6
@ -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> >&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> >&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;/g; s/</\&lt;/g; s/>/\&gt;/g; s/"/\&quot;/g; s/'"'"'/\&#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">'<html>
|
||||
<head>
|
||||
<title>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>
|
||||
<div style="display: flex; flex-direction: horizontal;">
|
||||
<a href="index.html">Home</a>
|
||||
<span style="margin-left: 1em; margin-right: 1em;">|</span>
|
||||
<a href="feed.xml">RSS Feed</a>
|
||||
</div>
|
||||
<h1>Blog</h1>
|
||||
'</span>
|
||||
}
|
||||
|
||||
<span class="function-name">print-blog-html-bottom</span>() {
|
||||
<span class="builtin">echo</span> <span class="string">' </body>
|
||||
</html>'</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 <<EOF<span class="sh-heredoc">
|
||||
<?xml version="1.0"?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>Hugot Blog</title>
|
||||
<link>https://hugot.nl/blog.html</link>
|
||||
<description>Hugo's personal blog</description>
|
||||
<language>en-us</language>
|
||||
<pubDate>$(</span><span class="sh-quoted-exec">date</span><span class="sh-heredoc">)</pubDate>
|
||||
<lastBuildDate>$(</span><span class="sh-quoted-exec">date</span><span class="sh-heredoc">)</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>
|
||||
EOF
|
||||
</span>}
|
||||
|
||||
<span class="function-name">print-blog-rss-bottom</span>() {
|
||||
<span class="builtin">echo</span> <span class="string">'</channel>
|
||||
</rss>'</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">"<$format_string>"</span> <span class="string">"$@"</span>
|
||||
}
|
||||
|
||||
<span class="function-name">el-close</span>() {
|
||||
<span class="builtin">echo</span> <span class="string">"</$1>"</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">"<$element_name>"</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">"</$element_name>"</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 > <span class="string">"$new_html"</span>
|
||||
print-blog-rss-top > <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 <<<"$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 <<<"$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"> <<<"$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 < <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> > <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">'<h2 style="margin-bottom: 0.1em;">%s</h2>'</span> <span class="string">"$title"</span>
|
||||
el-close a
|
||||
|
||||
<span class="builtin">printf</span> <span class="string">'<i style="font-size: 0.8em;">%s</i>'</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 ... <a href="%s">Continue reading</a>'</span> <span class="string">"$excerpt"</span> <span class="string">"$href"</span>
|
||||
el-close p
|
||||
|
||||
el-close div
|
||||
|
||||
el hr
|
||||
} >> <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">"<guid isPermaLink=\"false\">$title$(</span><span class="sh-quoted-exec">base64</span><span class="string"> <(cksum <<<"$text"))</guid>"</span>
|
||||
|
||||
el-close item
|
||||
} >> <span class="string">"$new_rss"</span>
|
||||
<span class="keyword"> done</span> < <span class="string">"$posts_file"</span>
|
||||
|
||||
print-blog-html-bottom >> <span class="string">"$new_html"</span>
|
||||
print-blog-rss-bottom >> <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 +1,2 @@
|
||||
posts/simple-static-blog/index.html
|
||||
posts/introduction/index.html
|
||||
|
@ -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 "scale", support "modern
|
||||
workflows" or be "easy to use with integrated WYSIWYG
|
||||
editors". 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>
|
@ -0,0 +1 @@
|
||||
Sat 08 Feb 2020 12:14:16 PM CET
|
Loading…
Reference in New Issue