<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Hyperlink Your Heart - pelican</title><link href="https://blog.hyperlinkyourheart.com/" rel="alternate"></link><link href="https://blog.hyperlinkyourheart.com/feeds/tag.pelican.atom.xml" rel="self"></link><id>https://blog.hyperlinkyourheart.com/</id><updated>2021-06-26T14:59:00+02:00</updated><subtitle>Until there's nothing left.</subtitle><entry><title>Gemini Launch!</title><link href="https://blog.hyperlinkyourheart.com/gemini-launch.html" rel="alternate"></link><published>2021-06-26T14:59:00+02:00</published><updated>2021-06-26T14:59:00+02:00</updated><author><name>Kevin Houlihan</name></author><id>tag:blog.hyperlinkyourheart.com,2021-06-26:/gemini-launch.html</id><summary type="html">&lt;p&gt;All about the launch of my Gemini capsule, and how it is generated and&amp;nbsp;hosted.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In the olden-times, before the Web became basically synonymous with the Internet itself in many people&amp;#8217;s minds, there was another, competing hypertext protocol: &lt;a href="https://en.wikipedia.org/wiki/Gopher_(protocol)" title="Gopher entry on Wikipedia"&gt;Gopher&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I say &amp;#8220;was&amp;#8221;, but of course Gopher never really went away - it was kept alive by enthusiasts, and in recent years there has been a resurgence of interest in it as a sort of haven from the ubiquitous surveillance and relentless commercialisation of the&amp;nbsp;Web.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve long been interested in Gopher (I even &lt;a href="https://hyperlinkyourheart.itch.io/gophers" title="Gophers on itch.io"&gt;made a game about it&lt;/a&gt;), and have intended to start a phlog for a while without ever going ahead with it. Something about it always just seemed a little bit awkward and off-putting. I was torn between using Gophermap (i.e. menu) files for everything, or using plain text for posts and sacrificing any hypertextuality. I was torn between finding the need to wrap text to be cool and retro, or a hassle that results in an inferior experience for both creating and consuming&amp;nbsp;content.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gemini.circumlunar.space/docs/faq.gmi" title="Gemini FAQ"&gt;Gemini&lt;/a&gt; is a new protocol which takes inspiration from both Gopher and the Web, and from a certain perspective, improves on&amp;nbsp;both.&lt;/p&gt;
&lt;p&gt;When I heard about Gemini I didn&amp;#8217;t really get it at first. I thought it was just Gopher with &lt;span class="caps"&gt;SSL&lt;/span&gt;, which is nice, but I figured I&amp;#8217;d get set up on Gopher first and then consider a Gemini mirror. A few days ago I saw a screenshot of the Lagrange browser on Mastodon and started to look into it a bit more. When I realised just how many issues of both Gopher and the web it addresses, I was hooked! I spent several days after that setting up &lt;a href="gemini://gemini.hyperlinkyourheart.com/" title="My capsule"&gt;a capsule&lt;/a&gt; (the Gemini equivalent of a&amp;nbsp;&amp;#8220;site&amp;#8221;).&lt;/p&gt;
&lt;p&gt;&lt;a href="gemini://gemini.hyperlinkyourheart.com/" title="My capsule"&gt;&lt;img alt="My Gemlog in Lagrange" src="https://blog.hyperlinkyourheart.com/images/gemini-launch/gemlog.png" title="My Gemlog in Lagrange"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Static&amp;nbsp;Generation&lt;/h2&gt;
&lt;p&gt;After experimenting with a Gemini server for a bit and creating a few static &lt;code&gt;text/gemini&lt;/code&gt; files, I decided that I wanted to statically generate my gemlog the same way that I do my blog. I expected to have to write something from scratch to do this, but after some experimentation I was able to get the &lt;a href="https://blog.getpelican.com/" title="Pelican static site generator"&gt;Pelican static site generator&lt;/a&gt; (which I also use for my blog) to both read and output &lt;code&gt;.gmi&lt;/code&gt; files. It does take a bit of configuration however, and I had to monkeypatch a couple of methods in&amp;nbsp;Pelican.&lt;/p&gt;
&lt;p&gt;Unfortunately this means that it is only guaranteed to work with the current version of Pelican, 4.6.0, and could break at any time. Nonetheless, the plugin is &lt;a href="https://github.com/khoulihan/pelican-gemini" title="pelican-gemini plugin"&gt;available on GitHub&lt;/a&gt; if you want to try it&amp;nbsp;out.&lt;/p&gt;
&lt;h3&gt;Gemini&amp;nbsp;Reader&lt;/h3&gt;
&lt;p&gt;The first thing required was a custom &amp;#8220;Reader&amp;#8221; that can handle &lt;code&gt;.gmi&lt;/code&gt; files instead of the usual Markdown or reStructuredText files. It&amp;#8217;s simple enough - it just parses the file up to the first blank line as metadata, and the rest of the content is returned unmodified, since we are also going to output the same&amp;nbsp;format.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;GeminiReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseReader&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;

    &lt;span class="n"&gt;file_extensions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gmi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gemini&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;end_of_meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;end_of_meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;end_of_meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;
                &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="c1"&gt;# After the first blank line, the rest is content.&lt;/span&gt;
            &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Handling Internal&amp;nbsp;Links&lt;/h3&gt;
&lt;p&gt;Pelican has a mechanism for linking to content internal to the site where you start the &lt;span class="caps"&gt;URL&lt;/span&gt; as &lt;code&gt;{static}&lt;/code&gt; or &lt;code&gt;{filename}&lt;/code&gt; and it replaces those with the appropriate paths during generation. However, this didn&amp;#8217;t work with the Gemini link syntax - the replacement is based on a regular expression that assumes the placeholder will be found in an attribute of a &lt;span class="caps"&gt;HTML&lt;/span&gt;&amp;nbsp;element.&lt;/p&gt;
&lt;p&gt;I couldn&amp;#8217;t find any setting or hook in the plugin system to alter this regular expression. There is a setting to customise the part that specifies the braces, so you could change the placeholders to &lt;code&gt;¿¿static??&lt;/code&gt; or something if you like, as long as it is still found in &lt;span class="caps"&gt;HTML&lt;/span&gt;. It seemed like my only option was to replace the method where the problem regex pattern is defined, and use something that matches Gemini links&amp;nbsp;instead.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_get_intrasite_link_regex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;intrasite_link_regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;INTRASITE_LINK_REGEX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;(?P&amp;lt;markup&amp;gt;=&amp;gt; )(?P&amp;lt;quote&amp;gt;)(?P&amp;lt;path&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s2"&gt;(?P&amp;lt;value&amp;gt;[\S]*))&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intrasite_link_regex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You&amp;#8217;ll notice this also has to include a &amp;#8220;quote&amp;#8221; group because that was present in the &lt;span class="caps"&gt;HTML&lt;/span&gt; version and was expected elsewhere - here it will always be an empty&amp;nbsp;string.&lt;/p&gt;
&lt;p&gt;Unfortunately, the problems didn&amp;#8217;t end there. I found that the placeholders were removed, but not replaced with the absolute &lt;span class="caps"&gt;URL&lt;/span&gt; of the capsule. This turned out to be because urllib is used to join the &lt;span class="caps"&gt;URL&lt;/span&gt; components, and it doesn&amp;#8217;t recognise the gemini protocol. To get around this I had to replace another method, and make a call to a wrapper around &lt;code&gt;urllib.urljoin&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_urljoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;is_gemini&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gemini://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_gemini&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gemini://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urljoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_gemini&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gemini://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Gemini&amp;nbsp;Output&lt;/h3&gt;
&lt;p&gt;Pelican uses Jinja2 for its templating, which is happy to work with any type of text file, so creating &lt;code&gt;.gmi&lt;/code&gt; templates wasn&amp;#8217;t an issue. Handily, there is a setting to look for templates with extensions other than &lt;code&gt;.html&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;THEME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;themes/hypergem&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;TEMPLATE_EXTENSIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.gmi&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.gemini&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To get Pelican to output files with a &lt;code&gt;.gmi&lt;/code&gt; extension instead of &lt;code&gt;.html&lt;/code&gt;, there are a bunch of settings for the different parts of the site. A single &amp;#8220;extension&amp;#8221; setting like for the templates would be nice, but whatchagonnado? I took the opportunity to customise the article location and file names as&amp;nbsp;well.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# These settings are required to output files as .gmi instead of .html&lt;/span&gt;
&lt;span class="n"&gt;ARTICLE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;articles/{date:%Y}-{date:%m}-{date:&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s1"&gt;}-&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;ARTICLE_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ARTICLE_URL&lt;/span&gt;

&lt;span class="n"&gt;DRAFT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;drafts/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;DRAFT_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DRAFT_URL&lt;/span&gt;

&lt;span class="n"&gt;PAGE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;pages/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;PAGE_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PAGE_URL&lt;/span&gt;

&lt;span class="n"&gt;DRAFT_PAGE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;drafts/pages/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;DRAFT_PAGE_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DRAFT_PAGE_URL&lt;/span&gt;

&lt;span class="n"&gt;AUTHOR_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;author/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;AUTHOR_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AUTHOR_URL&lt;/span&gt;

&lt;span class="n"&gt;CATEGORY_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;category/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;CATEGORY_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CATEGORY_URL&lt;/span&gt;

&lt;span class="n"&gt;TAG_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tag/&lt;/span&gt;&lt;span class="si"&gt;{slug}&lt;/span&gt;&lt;span class="s1"&gt;.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;TAG_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TAG_URL&lt;/span&gt;

&lt;span class="n"&gt;ARCHIVES_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;archives.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;AUTHORS_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;authors.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;CATEGORIES_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;categories.gmi&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;TAGS_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tags.gmi&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Theme&lt;/h3&gt;
&lt;p&gt;I haven&amp;#8217;t got much to say about this. I wanted the article links to be a bit more descriptive than just the date and title, so I did something similar to what medusae.space does and included the article summary, the category, and the&amp;nbsp;tags.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s close to general purpose but not quite - I added a custom &lt;code&gt;SITELOGO&lt;/code&gt; setting that is used on the index page with an &lt;span class="caps"&gt;ASCII&lt;/span&gt; art version of my logo generated using &lt;a href="https://ascii-generator.site/" title="ASCII Generator"&gt;ascii-generator.site&lt;/a&gt;, and there is also a custom template for the custom landing page. The index is renamed using a setting, and another page is renamed to index.gmi to take its place. This is so if I want to add content that isn&amp;#8217;t generated by Pelican, I have the scope to do&amp;nbsp;so.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;INDEX_SAVE_AS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gemlog.gmi&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Hyperlink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Heart&lt;/span&gt;
&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;06&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;
&lt;span class="n"&gt;Slug&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;
&lt;span class="n"&gt;Authors&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Kevin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Houlihan&lt;/span&gt;
&lt;span class="n"&gt;Summary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Capsule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;
&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gmi&lt;/span&gt;
&lt;span class="n"&gt;save_as&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gmi&lt;/span&gt;
&lt;span class="n"&gt;Template&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capsule_intro&lt;/span&gt;
&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hidden&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Hosting&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;m serving the capsule using &lt;a href="https://github.com/michael-lazar/jetforce" title="Jetforce github"&gt;Jetforce&lt;/a&gt; from a first generation Raspberry Pi which I had lying around and haven&amp;#8217;t done anything with in a while. There was nothing really involved in setting it up beyond what is described in the documentation, except that I installed it in a&amp;nbsp;virtualenv.&lt;/p&gt;
&lt;p&gt;I also took steps to make sure it is running as a dedicated user with no permissions to anything else on the&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Real professional operation" src="https://blog.hyperlinkyourheart.com/images/gemini-launch/hosting.jpg" title="Real professional operation"&gt;&lt;/p&gt;
&lt;h2&gt;Future&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;m not sure what&amp;#8217;s next, but I&amp;#8217;m excited! I might discuss with the Pelican crew if there are any ways around the issues I encountered that I might have overlooked, or if it could be adapted to be more suited to non-&lt;span class="caps"&gt;HTML&lt;/span&gt; output. If not, maybe a Gemini fork is in order. I have no idea if there are further issues with it beyond the functionality that I&amp;#8217;ve&amp;nbsp;used.&lt;/p&gt;
&lt;p&gt;I have quite a few posts to port over from my blog yet, and I need to get some image optimisation happening there like I have here. Besides that, I guess all I have to do is get to know the&amp;nbsp;community!&lt;/p&gt;
&lt;h2&gt;Visit My Capsule (and&amp;nbsp;Beyond)&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;re already familiar with Gemini please &lt;a href="gemini://gemini.hyperlinkyourheart.com/" title="My capsule"&gt;check out my capsule&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not, well, I still encourage you to visit, but I should probably give you some guidance on getting&amp;nbsp;started.&lt;/p&gt;
&lt;p&gt;If you just want to dip your toes you can browse the Gemini network using a &lt;span class="caps"&gt;HTTP&lt;/span&gt; proxy (&lt;a href="https://proxy.vulpes.one/gemini/gemini.hyperlinkyourheart.com" title="Vulpes.one proxy"&gt;here&amp;#8217;s one&lt;/a&gt;, and &lt;a href="https://portal.mozz.us/gemini/gemini.hyperlinkyourheart.com" title="Mozz.us proxy"&gt;another&lt;/a&gt;). For what I would consider the &amp;#8220;full experience&amp;#8221; you will need a dedicated browser. I&amp;#8217;ve been using &lt;a href="https://github.com/skyjake/lagrange" title="Lagrange browser GitHub"&gt;Lagrange&lt;/a&gt;, and highly recommend it, but there are a &lt;a href="https://gemini.circumlunar.space/software/" title="Gemini software list"&gt;whole bunch of others&lt;/a&gt; if that doesn&amp;#8217;t suit you. Many of them also support Gopher, which makes browsing both into a seamless experience outside of the modern&amp;nbsp;Web.&lt;/p&gt;
&lt;p&gt;When you want to move beyond my capsule, here are some others I&amp;nbsp;recommend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Medusae.space, a content directory: &lt;a href="gemini://medusae.space" title="Medusae.space content directory"&gt;gemini://medusae.space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Station, a social network with user accounts: &lt;a href="gemini://station.martinrue.com/" title="Station - where capsuleers hang out"&gt;gemini://station.martinrue.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Geddit, an anonymous link aggregator: &lt;a href="gemini://geddit.glv.one/" title="Geddit?"&gt;gemini://geddit.glv.one/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Astrobotany, a community garden game: &lt;a href="gemini://astrobotany.mozz.us/" title="Astrobotany"&gt;gemini://astrobotany.mozz.us/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A gemlog post about the &amp;#8220;smolnet&amp;#8221;, which explains the appeal far better than I ever could: &lt;a href="gemini://republic.circumlunar.space/users/maugre/200701-smolnet.gmi" title="The smolnet of smol things"&gt;gemini://republic.circumlunar.space/users/maugre/200701-smolnet.gmi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I leave you with my anxious young poppy, Jennifer, on&amp;nbsp;AstroBotany:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;            O
            |
           \o
            |o
           \/
.  , &lt;span class="ge"&gt;_ . ., l, _&lt;/span&gt; ., _ .  
^      &amp;#39;        `    &amp;#39;

name  : &amp;quot;Jennifer&amp;quot;
stage : anxious young poppy
age   : 2 days
rate  : 1st generation (x1.0)
score : 326788
water : |██████████| 100%
bonus : |          | 2%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Gemini"></category><category term="python"></category><category term="pelican"></category><category term="blogging"></category><category term="smolnet"></category></entry><entry><title>Embedding SVGs in Pelican</title><link href="https://blog.hyperlinkyourheart.com/embedding-svgs.html" rel="alternate"></link><published>2020-04-04T00:10:00+02:00</published><updated>2020-04-04T00:10:00+02:00</updated><author><name>Kevin Houlihan</name></author><id>tag:blog.hyperlinkyourheart.com,2020-04-04:/embedding-svgs.html</id><summary type="html">&lt;p&gt;A static alternative to Font Awesome&amp;#8217;s dynamic icon&amp;nbsp;embedding.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In my &lt;a href="https://blog.hyperlinkyourheart.com/remember-blogs.html"&gt;inaugural post&lt;/a&gt; I mentioned that one problem I had encountered while designing this blog was styling the &lt;span class="caps"&gt;SVG&lt;/span&gt; icons. I had grabbed a bunch of the individual icon files from &lt;a href="https://fontawesome.com/"&gt;Font Awesome&lt;/a&gt;, but because of the way SVGs, &lt;span class="caps"&gt;CSS&lt;/span&gt; and &lt;span class="caps"&gt;HTML&lt;/span&gt; interact, I wasn&amp;#8217;t able to colour them directly using &lt;span class="caps"&gt;CSS&lt;/span&gt; &lt;code&gt;color&lt;/code&gt; or &lt;code&gt;fill&lt;/code&gt; properties, and instead had to use &lt;code&gt;filter&lt;/code&gt; properties (which I calculated using &lt;a href="https://codepen.io/sosuke/pen/Pjoqqp"&gt;this tool&lt;/a&gt;, so it wasn&amp;#8217;t too much of a&amp;nbsp;hardship).&lt;/p&gt;
&lt;p&gt;I also didn&amp;#8217;t particularly like that retrieving the icons involved numerous separate requests, nor the visible &amp;#8220;pop-in&amp;#8221; in Firefox that resulted from having them referenced as external files. The files are tiny, with the request overhead often as large or larger than the files&amp;nbsp;themselves.&lt;/p&gt;
&lt;p&gt;A further advantage that I was missing out on by not using Font Awesome as intended was that I couldn&amp;#8217;t use their handy &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag shortcuts for specifying the icons to&amp;nbsp;use.&lt;/p&gt;
&lt;p&gt;Now, I have taken steps towards solving all of these many&amp;nbsp;problems!&lt;/p&gt;
&lt;h2&gt;Just use Font Awesome normally you&amp;nbsp;weirdo&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s back up a sec and talk about why I didn&amp;#8217;t just use Font Awesome as intended in the first place (yes tldr; it is probably because I&amp;#8217;m a&amp;nbsp;weirdo).&lt;/p&gt;
&lt;p&gt;Font Awesome has two ways that it can work: Web Fonts + &lt;span class="caps"&gt;CSS&lt;/span&gt;, or &lt;span class="caps"&gt;SVG&lt;/span&gt; + JavaScript. The former would involve retrieving an additional &lt;span class="caps"&gt;CSS&lt;/span&gt; file or two, as well as a couple of web fonts. The web font for the solid collection alone is 79.&lt;span class="caps"&gt;4KB&lt;/span&gt; - larger than anything else on this website. The JavaScript that would be required for the other method would likely be approaching &lt;span class="caps"&gt;1MB&lt;/span&gt; in size - larger than this &lt;em&gt;entire&lt;/em&gt; website so far! I want a lean, fast-loading, low-power website, and these approaches seem entirely at odds with those&amp;nbsp;goals.&lt;/p&gt;
&lt;p&gt;It also struck me as odd to be statically generating a site, yet also having the client browser swapping in &lt;span class="caps"&gt;SVG&lt;/span&gt; images. I&amp;#8217;ve nothing against JavaScript, but clearly this is work that can be done in&amp;nbsp;advance!&lt;/p&gt;
&lt;h2&gt;Doesn&amp;#8217;t caching solve this&amp;nbsp;problem?&lt;/h2&gt;
&lt;p&gt;Well&amp;#8230; maybe? In same cases? But not&amp;nbsp;necessarily.&lt;/p&gt;
&lt;p&gt;The average size of an icon in Font Awesome&amp;#8217;s &amp;#8220;solid&amp;#8221; collection is 660B. A visitor would have to encounter over 1500 such embedded icons before downloading the JavaScript and caching it would be cheaper. The Web Fonts are much better, with caching the separate files becoming worthwhile after only 214 icons. That&amp;#8217;s about 5 views of this blog&amp;#8217;s index page, or 15 individual&amp;nbsp;posts.&lt;/p&gt;
&lt;p&gt;As such, if somebody reads 16 posts on this blog, they will have transferred more data than they would have if I&amp;#8217;d used the Font Awesome web fonts. However, if 15 people read one post each and never visit again, the embedded approach comes out way ahead. So it very much depends on the traffic profile of the site, and I don&amp;#8217;t think this site is one that people will be checking in on&amp;nbsp;daily.&lt;/p&gt;
&lt;p&gt;Embedding also offers other advantages, such as reducing initial load&amp;nbsp;times.&lt;/p&gt;
&lt;h2&gt;Solutions&lt;/h2&gt;
&lt;p&gt;My solution is a &lt;a href="https://github.com/khoulihan/pelican-embed-svg"&gt;pelican plugin&lt;/a&gt; that post-processes the generated &lt;span class="caps"&gt;HTML&lt;/span&gt; files and embeds any SVGs it finds, whether specified as &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags or &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
&lt;p&gt;It also, crucially, sets the &lt;code&gt;fill&lt;/code&gt; attribute of any &lt;span class="caps"&gt;SVG&lt;/span&gt; paths to &lt;code&gt;currentColor&lt;/code&gt;, which causes the fill colour to be taken from the current &lt;span class="caps"&gt;CSS&lt;/span&gt; text&amp;nbsp;colour.&lt;/p&gt;
&lt;p&gt;Taking the plugin beyond being merely a static implementation of Font Awesome, it also supports embedding of arbitrary &lt;span class="caps"&gt;SVG&lt;/span&gt; files. This can be achieved either by using &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tags with the class &lt;code&gt;pi&lt;/code&gt; to search a custom icon set, or through &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags where the &lt;span class="caps"&gt;SVG&lt;/span&gt; file is referenced by &lt;span class="caps"&gt;URL&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Future&lt;/h2&gt;
&lt;p&gt;The plugin probably has loads of rough edges at the moment. I haven&amp;#8217;t at all tested if it supports Font Awesome&amp;#8217;s more advanced behaviour, or even investigated how those features work, so there is a lot to be done&amp;nbsp;there.&lt;/p&gt;
&lt;p&gt;I may explore an approach that would combine the advantages of static generation with the advantages of a separate, cacheable &lt;span class="caps"&gt;SVG&lt;/span&gt; file. My initial thoughts on how to approach this plugin were to combine any referenced SVGs into a single file, and then reference them in the &lt;span class="caps"&gt;HTML&lt;/span&gt; using an &lt;span class="caps"&gt;SVG&lt;/span&gt; &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; tag. I need to learn a lot more about SVGs to know if that&amp;#8217;s even&amp;nbsp;feasible.&lt;/p&gt;
&lt;p&gt;I also want to try to support other icon frameworks that support a similar &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag shortcut, such as &lt;a href="https://forkaweso.me/Fork-Awesome/"&gt;Fork Awesome&lt;/a&gt; and &lt;a href="https://friconix.com"&gt;Friconix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the meantime, it&amp;#8217;s serving my purposes already on this&amp;nbsp;site.&lt;/p&gt;
&lt;p&gt;&lt;i class="fas fa-thumbs-up body-icon"&gt;&lt;/i&gt; &lt;i class="fas fa-bomb body-icon"&gt;&lt;/i&gt; &lt;i class="fas fa-cat body-icon"&gt;&lt;/i&gt; &lt;i class="fas fa-leaf body-icon"&gt;&lt;/i&gt; &lt;i class="fas fa-file body-icon"&gt;&lt;/i&gt; &lt;i class="fas fa-fist-raised body-icon"&gt;&lt;/i&gt;&lt;/p&gt;</content><category term="Programming"></category><category term="python"></category><category term="blogging"></category><category term="pelican"></category></entry><entry><title>Remember Blogs?</title><link href="https://blog.hyperlinkyourheart.com/remember-blogs.html" rel="alternate"></link><published>2020-01-02T20:05:00+01:00</published><updated>2020-01-02T20:05:00+01:00</updated><author><name>Kevin Houlihan</name></author><id>tag:blog.hyperlinkyourheart.com,2020-01-02:/remember-blogs.html</id><summary type="html">&lt;p&gt;The how and the why of this very blog right&amp;nbsp;here.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve read a lot of articles recently (&lt;a href="https://omarabid.com/the-modern-web"&gt;here&amp;#8217;s one&lt;/a&gt;) lamenting the state of the web. Once distributed, egalitarian, ungovernable, and fast, now centralised, intentionally manipulative, and bloated both technically and conceptually. Even when you manage to fight your way through the popups demanding your attention or personal information, often what is underneath is not worth the effort - more likely a vehicle for advertising than for&amp;nbsp;insight.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s also incredibly power-hungry. It&amp;#8217;s hard to tie down an exact figure for exactly &lt;em&gt;how&lt;/em&gt; power-hungry, but the internet as a whole &lt;a href="https://newrepublic.com/article/155993/can-internet-survive-climate-change"&gt;could account for up to 10% of global energy use&lt;/a&gt;. A good chunk of that is streaming video and music, which is a topic for another day, but of the power consumed in serving the web, some of it is related to actual valuable content that people want to see, and some of it is related to the trends described above. The latter is waste. At least bloated JavaScript and &lt;span class="caps"&gt;CSS&lt;/span&gt; frameworks can be cached, but advertising has to be constantly served&amp;nbsp;anew.&lt;/p&gt;
&lt;p&gt;So, anyway, all this to say&amp;#8230; I&amp;#8217;ve decided to start a&amp;nbsp;blog.&lt;/p&gt;
&lt;h2&gt;The&amp;nbsp;Tech&lt;/h2&gt;
&lt;p&gt;My technical goals for this website are for it to&amp;nbsp;be&amp;#8230;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lightweight &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; fast to load&lt;/strong&gt; - I set up a WordPress site recently, on the best hosting I can afford. It is not lightweight or fast to&amp;nbsp;load.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content focused&lt;/strong&gt; - Read one thing or read them all, but I&amp;#8217;m sure you can only read one article at a&amp;nbsp;time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nice to look at&lt;/strong&gt; - Apparently it &lt;a href="https://perfectmotherfuckingwebsite.com/"&gt;doesn&amp;#8217;t take much&lt;/a&gt;. Also going for consistent &lt;em&gt;branding&lt;/em&gt; between all my sites and&amp;nbsp;profiles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Responsive&lt;/strong&gt; - Readable on phones as well as&amp;nbsp;desktops!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy to deploy&lt;/strong&gt; - I don&amp;#8217;t have time to configure and maintain a teetering stack of back-end technology, and if I have to move to different hosting at some point, I want it to be a simple&amp;nbsp;task.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy to update&lt;/strong&gt; - If writing posts is a chore, I won&amp;#8217;t ever do&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hackable&lt;/strong&gt; - Created using technologies that I&amp;#8217;m somewhat familiar with, so that it is feasible for me to modify or extend if I want/need&amp;nbsp;to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I decided almost immediately that a statically-generated site was going to be the best way to achieve most of those goals. I&amp;#8217;m a big fan of Python, so although &lt;em&gt;hackability&lt;/em&gt; could be achieved by a JavaScript or C# based generator, I checked out the Python ones first, and found plenty of viable options. I settled on &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt; because&amp;nbsp;it&amp;#8217;s&amp;#8230;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Popular&lt;/strong&gt; - It seems to be one of the more popular Python&amp;nbsp;generators.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blog-oriented&lt;/strong&gt; - Some generators are geared towards documentation or are intended as replacements for content management systems, but that&amp;#8217;s not what I&amp;#8217;m&amp;nbsp;doing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Supports Markdown&lt;/strong&gt; - I&amp;#8217;m sure reST is fine, but I already have to use Markdown elsewhere so I&amp;#8217;d rather stick with&amp;nbsp;that.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy to update&lt;/strong&gt; - Just create a new Markdown file and run a command to&amp;nbsp;rebuild.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensible&lt;/strong&gt; - It includes a plugin system to modify the&amp;nbsp;output.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also decided to hand-craft my own theme, and to avoid a &lt;span class="caps"&gt;CSS&lt;/span&gt; framework. I love the look of Bootstrap, and how quick it is to get started with, but it&amp;#8217;s over 200kb and a lot of that is undoubtedly unnecessary for my needs. The spirit of the exercise is bare-bones and &lt;span class="caps"&gt;DIY&lt;/span&gt;!&lt;/p&gt;
&lt;h3&gt;The&amp;nbsp;Theme&lt;/h3&gt;
&lt;p&gt;The first step in hand-crafting a theme was&amp;#8230; to find an existing theme to copy! &lt;a href="https://github.com/arulrajnet/attila"&gt;Atilla&lt;/a&gt; was the closest to the style I was after, so I took a copy of that and gutted it of &lt;span class="caps"&gt;CSS&lt;/span&gt; and JavaScript and other elements that didn&amp;#8217;t meet my needs. Then I started building the &lt;span class="caps"&gt;CSS&lt;/span&gt; back up while trying to keep it as minimal as possible. It may not implement every feature supported by Pelican, but you can find it &lt;a href="https://github.com/khoulihan/hyh-blog/tree/master/themes/hyper"&gt;on my Github&lt;/a&gt; if it seems like something you could adapt for your own&amp;nbsp;needs.&lt;/p&gt;
&lt;p&gt;One departure that I made from the standard Pelican configuration was to have the social media links be taken from a collection of tuples with three elements, so that I could specify both an icon and a title to&amp;nbsp;use.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Custom social list that includes icons&lt;/span&gt;
&lt;span class="n"&gt;SOCIAL_ICONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Twitter&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;twitter.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://twitter.com/http_your_heart&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Mastodon&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;mastodon.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://mastodon.art/@hyperlinkyourheart&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Instagram&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;instagram.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://www.instagram.com/hyperlinkyourheart/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;YouTube&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;youtube.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://www.youtube.com/channel/UCc_O9Hp5UfQ-IHswi1H54Zg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Twitch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;twitch.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://www.twitch.tv/hyperlinkyourheart&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Itch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;itchio.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://hyperlinkyourheart.itch.io/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;GitHub&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;github.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://github.com/khoulihan&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Atom Feed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rss.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/feeds/all.atom.xml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I like that I can just throw custom configuration into the config file and then make use of it in the templates. However, it probably makes the theme less generally&amp;nbsp;useful.&lt;/p&gt;
&lt;p&gt;As it stands currently, loading this post requires less than 30kb to be&amp;nbsp;transferred.&lt;/p&gt;
&lt;h3&gt;Plugins&lt;/h3&gt;
&lt;p&gt;Currently, the only plugin I&amp;#8217;m using is the &lt;a href="https://github.com/getpelican/pelican-plugins/tree/master/css-html-js-minify"&gt;css-html-js-minify&lt;/a&gt; plugin that is available in the pelican-plugins repository. I haven&amp;#8217;t found anything I need to write my own plugin to handle yet, but I&amp;#8217;m sure I will get to&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;One problem that needs solving is that the &lt;span class="caps"&gt;SVG&lt;/span&gt; icons are a big nuisance, because it doesn&amp;#8217;t seem to be possible to change their colour without using the &lt;span class="caps"&gt;CSS&lt;/span&gt; &lt;code&gt;filter&lt;/code&gt; property, which is not nearly as convenient as just setting the colour directly. In order to do that, using the &lt;code&gt;fill&lt;/code&gt; property, I would have to embed the SVGs, or reference them as symbols in a &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; tag within an &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; tag. The individual icon files (from &lt;a href="https://fontawesome.com/"&gt;FontAwesome&lt;/a&gt;) aren&amp;#8217;t set up like that, and I didn&amp;#8217;t want to use their spritesheet because it is rather&amp;nbsp;large.&lt;/p&gt;
&lt;p&gt;What I might do in the future is write a plugin to compile the individual files into a single spritesheet of symbols, then find and replace any references to them with appropriate &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; tags. Essentially this will be doing the job that the FontAwesome toolkit usually does in the&amp;nbsp;browser.&lt;/p&gt;
&lt;h2&gt;The&amp;nbsp;Content&lt;/h2&gt;
&lt;p&gt;Uuuh&amp;#8230; I&amp;#8217;ll get back to you on that. Things I like, things I do, that sort of&amp;nbsp;thing.&lt;/p&gt;
&lt;h2&gt;Feedback&lt;/h2&gt;
&lt;p&gt;There&amp;#8217;s a couple of different strategies for allowing comments on a static site - I&amp;#8217;m not going to attempt them for now, and perhaps never will! If you have any feedback or thoughts there are many ways to reach me, such as &lt;a href="https://mastodon.art/@hyperlinkyourheart"&gt;Mastodon&lt;/a&gt; or &lt;a href="https://twitter.com/http_your_heart"&gt;Twitter&lt;/a&gt;, and I think that&amp;#8217;s just&amp;nbsp;fine.&lt;/p&gt;</content><category term="Meta"></category><category term="indieweb"></category><category term="blogging"></category><category term="pelican"></category></entry></feed>