<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Parker Jones Dev Blog - neofetch</title>
    <subtitle>Dev Blog of Parker Jones</subtitle>
    <link rel="self" type="application/atom+xml" href="https://parkerjones.dev/tags/neofetch/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://parkerjones.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-06-26T00:00:00+00:00</updated>
    <id>https://parkerjones.dev/tags/neofetch/atom.xml</id>
    <entry xml:lang="en">
        <title>Consoler Dark: A Terminal-Themed Zola Blog with Neofetch Logos and In-Browser SurrealDB</title>
        <published>2026-06-26T00:00:00+00:00</published>
        <updated>2026-06-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://parkerjones.dev/posts/consoler-dark-theme/"/>
        <id>https://parkerjones.dev/posts/consoler-dark-theme/</id>
        
        <content type="html" xml:base="https://parkerjones.dev/posts/consoler-dark-theme/">&lt;p&gt;I wanted my blog to feel like a terminal — not in the lazy &quot;monospace font and a green-on-black palette&quot; way, but structurally. The model I kept coming back to was &lt;code&gt;neofetch&lt;&#x2F;code&gt;: an ASCII distro logo on the left, a tidy key&#x2F;value table of system info on the right. That layout &lt;em&gt;is&lt;&#x2F;em&gt; a homepage. So I built one.&lt;&#x2F;p&gt;
&lt;p&gt;The result is &lt;strong&gt;Consoler Dark&lt;&#x2F;strong&gt;, the Zola theme this site runs on. This is how it works, including the two parts I&#x27;m fondest of: a script that generates logos by scraping neofetch itself, and a database that runs entirely in your browser.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;starting-from-after-dark&quot;&gt;Starting from after-dark&lt;&#x2F;h2&gt;
&lt;p&gt;I didn&#x27;t start from scratch. Consoler Dark is a fork of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git.habd.as&#x2F;comfusion&#x2F;after-dark&#x2F;&quot;&gt;comfusion&#x27;s after-dark&lt;&#x2F;a&gt;, a minimal Zola theme built on top of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hackcss.egoist.dev&#x2F;&quot;&gt;hack.css&lt;&#x2F;a&gt;. You can still see hack.css&#x27;s fingerprints in the SCSS — the &lt;code&gt;.hack&lt;&#x2F;code&gt; utility classes, the no-nonsense defaults. After-dark gave me a clean skeleton; I layered the terminal identity on top.&lt;&#x2F;p&gt;
&lt;p&gt;The taxonomy setup is where I diverged most. Beyond the usual &lt;code&gt;categories&lt;&#x2F;code&gt; and &lt;code&gt;tags&lt;&#x2F;code&gt;, the site indexes &lt;code&gt;series&lt;&#x2F;code&gt;, &lt;code&gt;projects&lt;&#x2F;code&gt;, and &lt;code&gt;authors&lt;&#x2F;code&gt; — that last one so I can credit the AI models I draft alongside as co-authors (this post included).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-neofetch-metaphor-in-templates&quot;&gt;The neofetch metaphor, in templates&lt;&#x2F;h2&gt;
&lt;p&gt;The homepage and section headers render a &lt;code&gt;.neofetch-header&lt;&#x2F;code&gt;: a logo block next to a &lt;code&gt;tech_info&lt;&#x2F;code&gt; table driven straight from config.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;toml&quot;&gt;[extra.tech_info]
Title = &amp;quot;parkerjones.dev&amp;quot;
Framework = &amp;quot;Zola&amp;quot;
Theme = &amp;quot;Consoler Dark&amp;quot;
Hosting = &amp;quot;Github Pages&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The template loops over those key&#x2F;value pairs the way neofetch prints &lt;code&gt;OS&lt;&#x2F;code&gt;, &lt;code&gt;Kernel&lt;&#x2F;code&gt;, &lt;code&gt;Uptime&lt;&#x2F;code&gt;. The nice property is that any page can override individual fields via &lt;code&gt;page.extra.tech_info&lt;&#x2F;code&gt;, so a project page can advertise its own &quot;system specs&quot; while inheriting the site defaults. It&#x27;s config-as-content, and it keeps the homepage honest — the chrome describes the actual stack.&lt;&#x2F;p&gt;
&lt;p&gt;A few smaller touches round out the feel: an &lt;code&gt;intro&lt;&#x2F;code&gt; keyframe fade so content boots in rather than flashing, a 16:9 &lt;code&gt;responsive-iframe&lt;&#x2F;code&gt; helper for embeds, and &lt;code&gt;:target&lt;&#x2F;code&gt; highlighting so deep links land with a visible cursor-style focus.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;scss&quot;&gt;@keyframes intro { 0% { opacity: 0; } 100% { opacity: 1; } }
main, footer { animation: intro 0.3s both; animation-delay: 0.15s; }
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;generating-logos-by-scraping-neofetch&quot;&gt;Generating logos by scraping neofetch&lt;&#x2F;h2&gt;
&lt;p&gt;Here&#x27;s the part I enjoyed most. Neofetch ships ASCII art for &lt;em&gt;hundreds&lt;&#x2F;em&gt; of distros, embedded right in its shell script as heredoc blocks. Rather than hand-draw anything, I wrote a Python script that fetches the raw neofetch source, parses out every logo, and converts each to an SVG.&lt;&#x2F;p&gt;
&lt;p&gt;The parser keys off neofetch&#x27;s own structure — each logo is a &lt;code&gt;read -rd &#x27;&#x27; ascii_data &amp;lt;&amp;lt;&#x27;EOF&#x27; … EOF&lt;&#x2F;code&gt; block, and the distro name is in the &lt;code&gt;case&lt;&#x2F;code&gt; line just above it:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;python&quot;&gt;if &amp;quot;read -rd &amp;#39;&amp;#39; ascii_data &amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;&amp;quot; in line:
    # walk backwards to the case label, e.g.  &amp;quot;Ubuntu&amp;quot;|&amp;quot;ubuntu&amp;quot;)
    j = i - 1
    while j &amp;gt;= 0 and not re.search(r&amp;#39;\)$&amp;#39;, lines[j].strip()):
        j -= 1
    distro_name = re.findall(r&amp;#39;&amp;quot;([^&amp;quot;]+)&amp;quot;&amp;#39;, lines[j])[0]

    # collect everything up to the EOF sentinel
    ascii_block = []
    i += 1
    while lines[i].strip() != &amp;quot;EOF&amp;quot;:
        ascii_block.append(lines[i]); i += 1
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Converting ASCII to SVG is just laying each line down as a &lt;code&gt;&amp;lt;tspan&amp;gt;&lt;&#x2F;code&gt; in a monospaced &lt;code&gt;&amp;lt;text&amp;gt;&lt;&#x2F;code&gt; element, sized from the longest line:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;python&quot;&gt;char_width, line_height, font_size = 8, 18, 14
width  = max(len(l) for l in lines) * char_width + 10
height = len(lines) * line_height + 10
# one &amp;lt;text&amp;gt; with a &amp;lt;tspan dy=&amp;quot;line_height&amp;quot;&amp;gt; per line
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Run it, and &lt;code&gt;static&#x2F;logos&#x2F;&lt;&#x2F;code&gt; fills up with a clean SVG per distro — vector, themeable, no image assets to hand-maintain. When neofetch adds a logo, I re-run the script. The art stays in sync with upstream because &lt;em&gt;upstream is the source of truth&lt;&#x2F;em&gt;. That&#x27;s the kind of automation that pays for itself the first time you&#x27;d otherwise have copied ASCII art by hand.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-database-that-runs-in-your-browser&quot;&gt;A database that runs in your browser&lt;&#x2F;h2&gt;
&lt;p&gt;The detail that surprises people: Consoler Dark ships a WebAssembly build of &lt;strong&gt;SurrealDB&lt;&#x2F;strong&gt; and runs it client-side. There&#x27;s no backend. The theme&#x27;s &lt;code&gt;js&#x2F;main.js&lt;&#x2F;code&gt; boots an in-browser SurrealDB engine, fetches a &lt;code&gt;&#x2F;site.sql&lt;&#x2F;code&gt; file, pulls the SQL out of a &lt;code&gt;&amp;lt;pre&amp;gt;&lt;&#x2F;code&gt; tag, and executes it — all in the visitor&#x27;s tab.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;import { Surreal } from &amp;quot;surrealdb&amp;quot;;
import { surrealdbWasmEngines } from &amp;quot;@surrealdb&#x2F;wasm&amp;quot;;

const db = new Surreal({ engines: surrealdbWasmEngines() });
const sql = await fetchSQLFromPreTag();   &#x2F;&#x2F; read &#x2F;site.sql from a &amp;lt;pre&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is bundled with Vite. A couple of non-obvious settings were required to make a wasm database happy in a static-site context: an &lt;code&gt;es2020&lt;&#x2F;code&gt; target plus &lt;code&gt;top-level-await&lt;&#x2F;code&gt; support (the engine initializes asynchronously at import time), and excluding &lt;code&gt;@surrealdb&#x2F;wasm&lt;&#x2F;code&gt; from dependency pre-bundling so Vite doesn&#x27;t mangle the wasm.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;build:    { target: &amp;#39;es2020&amp;#39;, outDir: &amp;#39;static&amp;#39; },
esbuild:  { target: &amp;#39;es2020&amp;#39;, supported: { &amp;#39;top-level-await&amp;#39;: true } },
optimizeDeps: { exclude: [&amp;#39;@surrealdb&#x2F;wasm&amp;#39;] },
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Why do this on a blog? Because I write about &lt;a href=&quot;&#x2F;posts&#x2F;databses-in-the-browser&#x2F;&quot;&gt;databases in the browser&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;posts&#x2F;zola-surreal-db-site-cache&#x2F;&quot;&gt;using SurrealDB as a site cache&lt;&#x2F;a&gt;, and a theme that &lt;em&gt;is&lt;&#x2F;em&gt; the demo beats one that merely links to it. The dev workflow runs Zola and Vite in parallel so the static site and the wasm bundle rebuild together:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;json&quot;&gt;&amp;quot;dev&amp;quot;: &amp;quot;npm-run-all --parallel vite-serve zola-serve&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;the-linkify-experiment-i-rolled-back&quot;&gt;The linkify experiment I rolled back&lt;&#x2F;h2&gt;
&lt;p&gt;Not everything survived. I&#x27;d wired up a client-side &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;linkify.js.org&#x2F;&quot;&gt;linkify&lt;&#x2F;a&gt; pass that auto-detected &lt;code&gt;#hashtags&lt;&#x2F;code&gt; in post text and rewrote them into links to the matching &lt;code&gt;&#x2F;tags&#x2F;&lt;&#x2F;code&gt; page — Twitter-style tagging, for free, with no changes to how I wrote posts.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;js&quot;&gt;formatHref: (href, type) =&amp;gt;
  type === &amp;#39;hashtag&amp;#39; ? `&#x2F;tags&#x2F;${href.slice(1).toLowerCase()}` : href
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It worked, and I turned it off. Scanning every &lt;code&gt;&amp;lt;p&amp;gt;&lt;&#x2F;code&gt; and &lt;code&gt;&amp;lt;span&amp;gt;&lt;&#x2F;code&gt; on load and rewriting &lt;code&gt;innerHTML&lt;&#x2F;code&gt; is a lot of DOM churn for a cosmetic feature, it fought with code blocks that legitimately contain &lt;code&gt;#&lt;&#x2F;code&gt;, and &quot;clever text rewriting at runtime&quot; is exactly the kind of thing that quietly breaks a year later. The code&#x27;s still in the repo behind a partial; the lesson is that &lt;em&gt;shipping&lt;&#x2F;em&gt; and &lt;em&gt;keeping&lt;&#x2F;em&gt; are different decisions, and a static site rewards restraint.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;takeaways-for-rolling-your-own-zola-theme&quot;&gt;Takeaways for rolling your own Zola theme&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fork something minimal.&lt;&#x2F;strong&gt; after-dark + hack.css gave me a correct baseline so I could spend my effort on identity, not resets.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Drive chrome from config.&lt;&#x2F;strong&gt; The &lt;code&gt;tech_info&lt;&#x2F;code&gt; table means the design describes the real stack and updates itself.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Automate your assets from their upstream source.&lt;&#x2F;strong&gt; The neofetch scraper means I never hand-edit ASCII art.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A static site can do more than you think.&lt;&#x2F;strong&gt; A wasm database in the client turned my theme into a live demo of the things I write about.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Be willing to delete features that work.&lt;&#x2F;strong&gt; Linkify was the most &quot;impressive&quot; thing I built and the right call was to switch it off.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The theme is open source under MIT. If you want a blog that boots like a terminal and ships a database to every reader, the pieces are all here.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;— Parker Jones, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;parkerjones.dev&quot;&gt;parkerjones.dev&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
