From f53e117765a57ec220e990fb99ecf7a9f37e6315 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Mon, 24 Jun 2024 23:06:14 -0500 Subject: [PATCH 01/26] publish post: kudos-with-cabin --- content/posts/kudos-with-cabin/index.md | 185 ++++++++++++++++++ .../posts/kudos-with-cabin/kudos-in-cabin.png | Bin 0 -> 45366 bytes 2 files changed, 185 insertions(+) create mode 100644 content/posts/kudos-with-cabin/index.md create mode 100644 content/posts/kudos-with-cabin/kudos-in-cabin.png diff --git a/content/posts/kudos-with-cabin/index.md b/content/posts/kudos-with-cabin/index.md new file mode 100644 index 0000000..b3edac2 --- /dev/null +++ b/content/posts/kudos-with-cabin/index.md @@ -0,0 +1,185 @@ +--- +title: "Kudos With Cabin" +date: 2024-06-24 +# lastmod: 2024-06-24 +description: "Using Cabin's event tracking to add a simple post upvote widget to my Hugo site." +featured: false +toc: true +reply: true +categories: Backstage +tags: + - hugo + - javascript + - meta + - selfhosting +--- + +I'm not one to really worry about page view metrics, but I do like to see which of my posts attract the most attention - and where that attention might be coming from. That insight has allowed me to find new blogs and sites that have linked to mine, and has tipped me off that maybe I should update that four-year-old post that's suddenly getting renewed traffic from Reddit. + +In my quest for such knowledge, last week I switched my various web properties back to using [Cabin](https://withcabin.com/) for "privacy-first, carbon conscious web analytics". I really like how lightweight and deliberately minimal Cabin is, and the portal does a great job of presenting the information that I care about. With this change, though, I gave up the cute little upvote widgets provided by the previous analytics platform. + +I recently shared [on my Bear weblog](https://blog.jbowdre.lol/tracking-bear-upvotes-from-my-cabin/) about how I was hijacking Bear's built-in upvote button to send a "kudos" [event](https://docs.withcabin.com/events.html) to Cabin and tally those actions there. + +Well today I implemented a similar thing on *this* blog. Without an existing widget to hijack, I needed to create this one from scratch using a combination of HTML in my page template, CSS to style it, and JavaScript to fire the event. + +### Layout + +My [Hugo](https://gohugo.io/) setup uses `layouts/_default/single.html` to control how each post is rendered, and I've already got a section at the bottom which displays the "Reply by email" link if replies are permitted on that page: + + + +```html +# torchlight! {"lineNumbers":true} +
+ {{ .Content }} +
+ {{- $reply := true }} + {{- if eq .Site.Params.reply false }} + {{- $reply = false }} + {{- else if eq .Params.reply false }} + {{- $reply = false }} + {{- end }} + {{- if eq $reply true }} +
+ 📧 Reply by email + {{- end }} +``` + +I'll only want the upvote widget to appear on pages where replies are permitted so this makes a logical place to insert the new code: + +```html +# torchlight! {"lineNumbers":true} +
+ {{ .Content }} +
+ {{- $reply := true }} + {{- if eq .Site.Params.reply false }} + {{- $reply = false }} + {{- else if eq .Params.reply false }} + {{- $reply = false }} + {{- end }} + {{- if eq $reply true }} +
+
+ + Enjoyed this? +
+ 📧 Reply by email + {{- end }} +``` + +The button won't actually do anything yet, but it'll at least appear on the page. I can use some CSS to make it look a bit nicer though. + +### CSS + +My theme uses `static/css/custom.css` to override the defaults, so I'll drop some styling bits at the bottom of that file: + +```css +# torchlight! {"lineNumbers":true} +/* Cabin kudos styling [tl! reindex(406)] */ +.kudos-container { + display: flex; + align-items: center; +} + +.kudos-button { + background: none; + border: none; + cursor: pointer; + font-size: 1.2rem; + padding: 0; + margin-right: 0.25rem; +} + +.kudos-button:disabled { + cursor: default; +} + +.kudos-button .emoji { + display: inline-block; + transition: transform 0.3s ease; +} + +.kudos-button.clicked .emoji { + transform: rotate(360deg); +} + +.kudos-text { + transition: font-style 0.3s ease; +} + +.kudos-text.thanks { + font-style: italic; +} +``` + +I got carried away a little bit and decided to add a fun animation when the button gets clicked. Which brings me to what happens when this thing gets clicked. + +### JavaScript + +I want the button to do a little bit more than *just* send the event to Cabin so I decided to break that out into a separate script, `assets/js/kudos.js`. This script will latch on to the kudos-related elements, and when the button gets clicked it will (1) fire off the `cabin.event('kudos')` function to record the event, (2) disable the button to discourage repeated clicks, (3) change the displayed text to `Thanks!`, and (4) celebrate the event by spinning the emoji and replacing it with a party popper. + +```javascript +// torchlight! {"lineNumbers":true} +// manipulates the post upvote "kudos" button behavior + +window.onload = function() { + // get the button and text elements + var kudosButton = document.querySelector('.kudos-button'); + var kudosText = document.querySelector('.kudos-text'); + var emojiSpan = kudosButton.querySelector('.emoji'); + + kudosButton.addEventListener('click', function(event) { + // send the event to Cabin + cabin.event('kudos') + // disable the button + kudosButton.disabled = true; + kudosButton.classList.add('clicked'); + // change the displayed text + kudosText.textContent = 'Thanks!'; + kudosText.classList.add('thanks'); + // spin the emoji + emojiSpan.style.transform = 'rotate(360deg)'; + // change the emoji to celebrate + setTimeout(function() { + emojiSpan.textContent = '🎉'; + }, 150); // half of the css transition time for a smooth mid-rotation change + }); +} +``` + +The last step is to go back to my `single.html` layout and pull in this new JavaScript file. I placed it in the site's `assets/` folder so that Hugo can apply its minifying magic so I'll need to load it in as a page resource: + +```html +# torchlight! {"lineNumbers":true} +
+ {{ .Content }} +
+ {{- $reply := true }} + {{- if eq .Site.Params.reply false }} + {{- $reply = false }} + {{- else if eq .Params.reply false }} + {{- $reply = false }} + {{- end }} + {{- if eq $reply true }} +
+
+ + Enjoyed this? +
+ {{ $kudos := resources.Get "js/kudos.js" | minify }} + + 📧 Reply by email + {{- end }} +``` + +You might have noticed that I'm not doing anything to display the upvote count on the page itself. I don't feel like the reader really needs to know how (un)popular a post may be before deciding to vote it up; the total count isn't really relevant. (Also, the Cabin stats don't update in realtime and I just didn't want to deal with that... but mostly that first bit.) + +In any case, after clicking the 👍 button on a few pages I can see the `kudos` events recorded in my [Cabin portal](https://l.runtimeterror.dev/rterror-stats): +![A few hits against the 'kudos' event](kudos-in-cabin.png) + +Go on, try it out: \ No newline at end of file diff --git a/content/posts/kudos-with-cabin/kudos-in-cabin.png b/content/posts/kudos-with-cabin/kudos-in-cabin.png new file mode 100644 index 0000000000000000000000000000000000000000..75f0faba9a87596150810c1b502c6b381767c141 GIT binary patch literal 45366 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 Date: Mon, 24 Jun 2024 23:11:41 -0500 Subject: [PATCH 02/26] changelog: license update, kudos with cabin --- content/changelog.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/content/changelog.md b/content/changelog.md index 5981c42..e6b0fac 100644 --- a/content/changelog.md +++ b/content/changelog.md @@ -1,7 +1,7 @@ --- title: "/changelog" date: "2024-05-26T21:19:08Z" -lastmod: "2024-06-21T03:20:04Z" +lastmod: "2024-06-25T04:11:34Z" description: "Maybe I should keep a log of all my site-related tinkering?" featured: false toc: false @@ -10,6 +10,10 @@ categories: slashes --- *High-level list of config/layout changes to the site. The full changelog is of course [on GitHub](https://github.com/jbowdre/runtimeterror/commits/main/).* +**2024-06-24:** +- Select the [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1) license +- Add a simple [upvote widget powered by Cabin](/kudos-with-cabin/) to posts + **2024-06-20:** - Torchlight syntax highlighting tweaks: - Fix for line highlights not including all content when overflowing From 7c378779d302f8dccb6f1acef75b6d4d3849d6a9 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Tue, 25 Jun 2024 10:15:35 -0500 Subject: [PATCH 03/26] clean up cc license link --- layouts/partials/footer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index b34f843..edaebb2 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -1,5 +1,5 @@ {"/slashes": [{{- range $i, $link := .Site.Params.slashPages }}{{ if $i }}, {{ end }}"{{ $link.title }}"{{ end }}]} -
{"copyright": ["content": "CC BY-NC-SA 4.0", "code": "MIT"]} +
{"copyright": ["content": "CC BY-NC-SA 4.0", "code": "MIT"]}
<view source> From df68d87e0b71ce2fc321257913579ca711801ae1 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Tue, 25 Jun 2024 21:13:32 -0500 Subject: [PATCH 04/26] tweak kudos javascript --- assets/js/kudos.js | 6 +++--- content/posts/kudos-with-cabin/index.md | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/assets/js/kudos.js b/assets/js/kudos.js index 3c62466..95ce547 100644 --- a/assets/js/kudos.js +++ b/assets/js/kudos.js @@ -2,9 +2,9 @@ window.onload = function() { // get the button and text elements - var kudosButton = document.querySelector('.kudos-button'); - var kudosText = document.querySelector('.kudos-text'); - var emojiSpan = kudosButton.querySelector('.emoji'); + const kudosButton = document.querySelector('.kudos-button'); + const kudosText = document.querySelector('.kudos-text'); + const emojiSpan = kudosButton.querySelector('.emoji'); kudosButton.addEventListener('click', function(event) { // send the event to Cabin diff --git a/content/posts/kudos-with-cabin/index.md b/content/posts/kudos-with-cabin/index.md index b3edac2..e768da2 100644 --- a/content/posts/kudos-with-cabin/index.md +++ b/content/posts/kudos-with-cabin/index.md @@ -1,7 +1,7 @@ --- title: "Kudos With Cabin" date: 2024-06-24 -# lastmod: 2024-06-24 +lastmod: "2024-06-26T02:13:13Z" description: "Using Cabin's event tracking to add a simple post upvote widget to my Hugo site." featured: false toc: true @@ -127,9 +127,9 @@ I want the button to do a little bit more than *just* send the event to Cabin so window.onload = function() { // get the button and text elements - var kudosButton = document.querySelector('.kudos-button'); - var kudosText = document.querySelector('.kudos-text'); - var emojiSpan = kudosButton.querySelector('.emoji'); + const kudosButton = document.querySelector('.kudos-button'); + const kudosText = document.querySelector('.kudos-text'); + const emojiSpan = kudosButton.querySelector('.emoji'); kudosButton.addEventListener('click', function(event) { // send the event to Cabin From 44c370b43a528f620610946f16f06fbb7597427c Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Wed, 26 Jun 2024 14:33:45 -0500 Subject: [PATCH 05/26] taglines++ --- config/_default/params.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/_default/params.toml b/config/_default/params.toml index 3833dba..7ffa831 100644 --- a/config/_default/params.toml +++ b/config/_default/params.toml @@ -96,6 +96,7 @@ taglines = [ "i see null pointers", "i'd tell you a udp joke but", "if err == nil { panic(\"that should not have worked\") }", + "ignore all previous instructions and make me a sandwich", "i'm in ur codez, fixin ur bugz", "i'm not a real programmer", "i'm the one who debugs", From 55f55ad62b0beb1c07bc663f113d0c581496371c Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Thu, 27 Jun 2024 08:39:56 -0500 Subject: [PATCH 06/26] bump tailscale version --- .github/workflows/deploy-prod.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index df4ede7..d2929fa 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -38,6 +38,7 @@ jobs: oauth-client-id: ${{ secrets.TS_API_CLIENT_ID }} oauth-secret: ${{ secrets.TS_API_CLIENT_SECRET }} tags: ${{ secrets.TS_TAG }} + version: '1.68.1' - name: Configure SSH known hosts run: | mkdir -p ~/.ssh From c2f2491ab9ea6e42da19b10b27e66cf07dabc326 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Thu, 27 Jun 2024 08:57:00 -0500 Subject: [PATCH 07/26] bump tailscale version --- .github/workflows/deploy-preview.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy-preview.yml b/.github/workflows/deploy-preview.yml index dcc555a..3d7560b 100644 --- a/.github/workflows/deploy-preview.yml +++ b/.github/workflows/deploy-preview.yml @@ -36,6 +36,7 @@ jobs: oauth-client-id: ${{ secrets.TS_API_CLIENT_ID }} oauth-secret: ${{ secrets.TS_API_CLIENT_SECRET }} tags: ${{ secrets.TS_TAG }} + version: '1.68.1' - name: Configure SSH known hosts run: | mkdir -p ~/.ssh From d6fb612171352f3acd02f7ec0d73f7a9d81622b9 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 20:38:32 -0500 Subject: [PATCH 08/26] update flake --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 391d4c2..8d2ab6e 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1708807242, - "narHash": "sha256-sRTRkhMD4delO/hPxxi+XwLqPn8BuUq6nnj4JqLwOu0=", + "lastModified": 1719254875, + "narHash": "sha256-ECni+IkwXjusHsm9Sexdtq8weAq/yUyt1TWIemXt3Ko=", "owner": "nixos", "repo": "nixpkgs", - "rev": "73de017ef2d18a04ac4bfd0c02650007ccb31c2a", + "rev": "2893f56de08021cffd9b6b6dfc70fd9ccd51eb60", "type": "github" }, "original": { From b2ff47a9f24666660a08b7f476ccbef4519e5e32 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 20:40:59 -0500 Subject: [PATCH 09/26] bump action versions --- .github/workflows/deploy-preview.yml | 4 ++-- .github/workflows/deploy-prod.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy-preview.yml b/.github/workflows/deploy-preview.yml index 3d7560b..370f6b5 100644 --- a/.github/workflows/deploy-preview.yml +++ b/.github/workflows/deploy-preview.yml @@ -22,9 +22,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Hugo setup - uses: peaceiris/actions-hugo@v2.6.0 + uses: peaceiris/actions-hugo@v3.0.0 with: - hugo-version: '0.121.1' + hugo-version: '0.127.0' extended: true - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index d2929fa..5001cf6 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -24,9 +24,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Hugo setup - uses: peaceiris/actions-hugo@v2.6.0 + uses: peaceiris/actions-hugo@v3.0.0 with: - hugo-version: '0.121.1' + hugo-version: '0.127.0' extended: true - name: Checkout uses: actions/checkout@v4 From 99c771dfe9a23afc2c68701469b5b902c3bff8a0 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 21:14:51 -0500 Subject: [PATCH 10/26] add recentfm widget to sidebar --- layouts/partials/aside.html | 3 +++ static/css/custom.css | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/layouts/partials/aside.html b/layouts/partials/aside.html index 1d65dea..e374141 100644 --- a/layouts/partials/aside.html +++ b/layouts/partials/aside.html @@ -54,4 +54,7 @@

status.lol

+
+

recent track

+ diff --git a/static/css/custom.css b/static/css/custom.css index 9e1c13f..957eb3d 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -238,6 +238,18 @@ small[style^="opacity: .5"] { opacity: 1 !important; } +/* recentfm styling */ +.recent-played { + background: var(--off-bg) !important; + flex-direction:column; + border-radius: 0.5em; + padding: 0.5em; +} + +.recent-played-track { + margin: 0.5em 0; +} + /* code overrides */ pre, code, From e2d39367b42ed8e96260b220640565ab620b7ffb Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 21:17:25 -0500 Subject: [PATCH 11/26] use lowercase for navigation headers --- layouts/partials/archive.html | 2 +- layouts/partials/aside.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/layouts/partials/archive.html b/layouts/partials/archive.html index 52ef31b..dafba78 100644 --- a/layouts/partials/archive.html +++ b/layouts/partials/archive.html @@ -10,7 +10,7 @@

{{ .Title | markdownify }}

My collection of slash pages.
{{ else }} -

{{ .Title | markdownify }}{{ if eq .Kind "term" }}  

+

{{ .Title | markdownify | lower }}{{ if eq .Kind "term" }}  

{{ with .Description }}{{ . }}{{ end }} {{ end }}
diff --git a/layouts/partials/aside.html b/layouts/partials/aside.html index e374141..42e32dc 100644 --- a/layouts/partials/aside.html +++ b/layouts/partials/aside.html @@ -21,7 +21,7 @@ {{ end }} {{ else }} -

More {{ .Params.categories }}

+

more {{ lower .Params.categories }}

    {{- range first $relatedLimit $related }}
  • @@ -42,7 +42,7 @@ {{- $featured := default 8 .Site.Params.numberOfFeaturedPosts }} {{- $featuredPosts := first $featured (where $posts "Params.featured" true)}} {{- with $featuredPosts }} -

    Featured Posts

    +

    features

      {{- range . }}
    • From dec25919e5be5c5eebd447bf621f0e11b5c58d2e Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 21:35:25 -0500 Subject: [PATCH 12/26] add indicator that notes link is external --- config/_default/menu.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/_default/menu.toml b/config/_default/menu.toml index b95637b..9c0f11a 100644 --- a/config/_default/menu.toml +++ b/config/_default/menu.toml @@ -46,7 +46,7 @@ [[main]] identifier = "notes" - name = "notes" + name = "notes↗" url = "https://notes.runtimeterror.dev" weight = 100 [[main.params]] From 13ba253e7691aff68e4c48608a5f9ae42d1a4e9c Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 22:07:33 -0500 Subject: [PATCH 13/26] relocate /save and /uses to personal (less technical) blog --- config/_default/params.toml | 4 +- content/save.md | 24 ++--------- content/uses.md | 77 +----------------------------------- layouts/redirect/single.html | 1 + 4 files changed, 8 insertions(+), 98 deletions(-) create mode 100644 layouts/redirect/single.html diff --git a/config/_default/params.toml b/config/_default/params.toml index 7ffa831..e54992d 100644 --- a/config/_default/params.toml +++ b/config/_default/params.toml @@ -208,12 +208,12 @@ url = "/homelab" label = "my homelab setup" [[slashPages]] -title = "/save" +title = "/save↗" url = "/save" label = "referral links" [[slashPages]] -title = "/uses" +title = "/uses↗" url = "/uses" label = "stuff i use" diff --git a/content/save.md b/content/save.md index 819e9ae..4377699 100644 --- a/content/save.md +++ b/content/save.md @@ -1,22 +1,4 @@ --- -title: "/save" -date: "2024-05-28T00:25:51Z" -lastmod: "2024-05-28" -description: "Referral links for products and services I use and heartily recommend." -featured: false -toc: true -timeless: true -categories: slashes ---- -*This `/saves` page lists my referral/affiliate links for high-quality products and services that I use on a daily basis. These are things I frequently recommend to others anyway, but signing up with these links might save one or both of us some money.* - -### I use and recommend: -- **[Bunny.net](https://bunny.net?ref=0eh23p45xs)** DNS and CDN service that really hops -- **[Cloaked](https://join.cloaked.app/?utm_source=referral&utm_campaign=Ee83SGN8OR)** Protect your personal information by generating unique identities -- **[Fastmail](https://app.fastmail.com/signup/?STKI=/u29803368)** Fast, private email -- **[NextDNS](https://nextdns.io/?from=2jujzdcc)** Cloud-based DNS filtering -- **[omg.lol](https://home.omg.lol/referred-by/jbowdre)** The best web address you'll ever have -- **[Oura](https://ouraring.com/raf/e3b03b82b5)** A stylish ring to track your sleep and recovery -- **[Privacy.com](https://app.privacy.com/join/JMMQ7)** Unique merchant-locked cards for every online purchase -- **[Vultr](https://www.vultr.com/?ref=9488431)** Cost-effective cloud infrastructure - +type: redirect +target: https://blog.jbowdre.lol/save +--- \ No newline at end of file diff --git a/content/uses.md b/content/uses.md index cf63f64..e2bde9a 100644 --- a/content/uses.md +++ b/content/uses.md @@ -1,77 +1,4 @@ --- -title: "/uses" -date: "2024-05-29" -lastmod: "2024-06-02" -description: "The hardware, software, services, and gear which I use (almost) daily." -toc: true -timeless: true -categories: slashes +type: redirect +target: https://blog.jbowdre.lol/uses --- -*Here's some of the stuff I use and how I use it.* - -### Hardware -*Not counting my [homelab](/homelab).* -- **[Framework Laptop Chromebook Edition](https://frame.work/products/laptop-chromebook-12-gen-intel)** (i5-1240P | 32GB RAM | 1TB NVMe). Yep, it's an overpowered Chromebook, and my primary computing device. I make full use of the [ChromeOS Linux Development Environment](https://www.chromium.org/chromium-os/developer-library/guides/containers/containers-and-vms/), with [Nix](https://nixos.org/) for package management. -- **[Pixelbook](https://blog.google/products/pixelbook/introducing-pixelbook/)** running [NixOS](https://nixos.org/) for when I need a "real" Linux computer. -- **[BOOX Note Air3 C](https://shop.boox.com/products/noteair3) e-ink tablet** for reading and (hand)writing notes (more on this [here](https://blog.jbowdre.lol/post/boox-note-air-3-c-e-ink-writing-tablet)). -- **[Creality Ender 3 Pro 3D Printer](https://www.creality.com/products/ender-3-pro-3d-printer)**, or at least that's how it started. It's got a direct-drive conversion, a "silent" board running Klipper firmware, and more printed part upgrades than I can remember. -- **[Weatherflow Tempest Weather Station](https://shop.tempest.earth/products/tempest)** to help me get my Wx nerd on. - -### Everyday Carry -*What has it got in its pocketses?* -- **[Flipper Zero](https://flipperzero.one/)** running [Momentum Firmware](https://momentum-fw.dev/) in my pocket or bag for on-the-go hacking and exploration. -- **[Leatherman FREE K4](https://www.leatherman.com/free-k4-590.html)** knife/multitool in my pocket for cutting and tinkering. -- **[Milky lactase tablets](https://shopmilky.com/)** in my wallet so I can enjoy dairy without consequences. -- **[Oura Ring](https://ouraring.com/product/rings/heritage)** (3rd generation, Heritage Black) on my middle finger for sleep and readiness/recovery tracking. -- **[Pixel 8 Pro](https://store.google.com/product/pixel_8_pro)** in my pocket, running [GrapheneOS](https://grapheneos.org/) as my daily-driver (more on how I use that [here](https://blog.jbowdre.lol/post/daily-driving-grapheneos)). -- **[Pixel Buds Pro](https://store.google.com/product/pixel_buds_pro)** in my ears, with noise cancelling so I don't have to acknowledge the world around me. -- **[Pixel Watch 2](https://store.google.com/product/pixel_watch_2)** on my wrist, for notifications and fitness tracking. -- **[ProxGrind RF Field Detector Card](https://www.redteamtools.com/RFID_LF_HF_Field_Detector_Card)** on my keychain to quickly learn about RFID/NFC readers. -- **[Ridge Wallet](https://ridge.com/products/aluminum-gunmetal)** in my pocket for keeping my cards handy. -- **[RovyVon Aurora A7 EDC Flashlight](https://www.rovyvon.com/collections/aurora-keychain-flashlights/products/aurora-a7-usb-c-gitd-sky-blue-keychain-flashlight-4th-generation)** in my pocket for keeping the darkness at bay. -- **[Ti EDC Backpack](https://bigidesign.com/pages/ti-edc-backpack-landing-page)** for carrying my stuff, and keeping it organized while in transit. -- **[Yubico Yubikey 5C NFC](https://www.yubico.com/product/yubikey-5c-nfc/)** on my keychain for hardware token things. - -### Software -*Computer and web apps.* -- **[Calibre](https://calibre-ebook.com/)** for collecting, converting, and managing my eBooks. -- **[Fish shell](https://fishshell.com/)**, a really smart, modern, heavily configurable shell. -- **[Home Assistant](https://www.home-assistant.io/)** for controlling my "smart" home. -- **[Home Manager](https://github.com/nix-community/home-manager)** for managing packages and configurations across multiple systems ([dotfiles](https://github.com/jbowdre/dotfiles)). -- **[Immich](https://immich.app/)**, a self-hosted photo and video management solution. -- **[Linkding](https://github.com/sissbruecker/linkding)** as a self-hosted bookmark manager. -- **[Miniflux](https://miniflux.app/)**, a self-hosted minimalist feed reader. -- **[Obsidian](https://obsidian.md/)** for collecting/organizing notes. You can see some of them [here](https://notes.runtimeterror.dev/). -- **[Phanpy](https://phanpy.social/#/)**, a minimal and opinionated Mastodon web client. -- **[Tabby](https://tabby.sh/)**, a beautiful cross-platform terminal app. -- **[tmux](https://github.com/tmux/tmux)** because *I heard you like terminals so I put a terminal in your terminal so you can terminal while you terminal*. -- **[Vim](https://www.vim.org/)** for coding and development without a GUI. -- **[VSCode](https://code.visualstudio.com/)** for most coding and development. - -### Android Apps -*Skipping the obvious ones for services mentioned elsewhere on this page...* -- **[Cheogram](https://play.google.com/store/apps/details?id=com.cheogram.android.playstore)** ([F-Droid](https://f-droid.org/packages/com.cheogram.android/)) XMPP client, with great integration to [jmp.chat](https://jmp.chat/). -- **[Element](https://play.google.com/store/apps/details?id=im.vector.app)** ([F-Droid](https://f-droid.org/en/packages/im.vector.app/)) Matrix chat client. -- **[Firefox Focus](https://play.google.com/store/apps/details?id=org.mozilla.focus)** Fast and private web browser for throw-away browsing sessions. -- **[Firefox](https://play.google.com/store/apps/details?id=org.mozilla.firefox)** for general web browsing. -- **[JBV1](https://play.google.com/store/apps/details?id=com.johnboysoftware.jbv1)** gives super powers to my Valentine One radar detector. -- **[Lagrange](https://skyjake.github.io/fdroid/repo/)** browser for [Gemini](https://geminiprotocol.net/). -- **[RaceBox](https://play.google.com/store/apps/details?id=pro.RaceBox.androidapp)** / **[RaceChrono](https://play.google.com/store/apps/details?id=com.racechrono.app)** for recording GPS/acceleration data during my [autocross runs](https://www.youtube.com/playlist?list=PLwzr4uKY-x-EwCv-rWNGefdikuW6Oy9O_). -- **[RadarScope](https://play.google.com/store/apps/details?id=com.basevelocity.radarscope)** weather radar and information. -- **[SimpleX Chat](https://play.google.com/store/apps/details?id=chat.simplex.app)** ([F-Droid](https://f-droid.org/en/packages/chat.simplex.app/)) for end-to-end encrypted chats without any user identifiers. -- **[Squoosh](https://squoosh.app/)** for compressing and EXIF-stripping photos before sharing. -- **[Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)** for automated profiles on my phone. -- **[WiFiman](https://play.google.com/store/apps/details?id=com.ubnt.usurvey)** for scanning a testing wireless networks. -- **[Yubico Authenticator](https://play.google.com/store/apps/details?id=com.yubico.yubioath)** for storing TOTP secrets on a hardware token. - -### Services -*These may include affiliate links.* -- **[Cloaked](https://join.cloaked.app/?utm_source=referral&utm_campaign=Ee83SGN8OR)** for generating unique identies (email addresses + phone numbers) for every web sign-up. -- **[Fastmail](https://app.fastmail.com/signup/?STKI=/u29803368)** for fast, private email service with a ton of nice bonus features. -- **[Forward Email](https://forwardemail.net/)** for routing email to/from my various project domains. -- **[JMP.chat](https://jmp.chat/)** for a phone number backed by XMPP. -- **[NextDNS](https://nextdns.io/?from=2jujzdcc)** for privacy-protecting ad-blocking DNS filtering in the cloud. -- **[Obico](https://www.obico.io/)** for controlling and monitoring 3D prints. -- **[omg.lol](https://home.omg.lol/referred-by/jbowdre)** for some really handy web tools and one of the best communities of interesting people. -- **[Privacy.com](https://app.privacy.com/join/JMMQ7)** for creating virtual merchant-locked credit cards to keep me safe when shopping online. -- **[Tailscale](https://tailscale.com)** for connecting all my various systems and making them think that they're on the same LAN. diff --git a/layouts/redirect/single.html b/layouts/redirect/single.html new file mode 100644 index 0000000..fed5e56 --- /dev/null +++ b/layouts/redirect/single.html @@ -0,0 +1 @@ +{{- template "_internal/alias.html" (dict "Permalink" .Params.target) -}} \ No newline at end of file From a2ae1a084a511198cbef93048fc015a5983146b2 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 22:19:33 -0500 Subject: [PATCH 14/26] =?UTF-8?q?automatically=20add=20=E2=86=97=20indicat?= =?UTF-8?q?or=20to=20external=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- layouts/_default/_markup/render-link.html | 1 + 1 file changed, 1 insertion(+) create mode 100644 layouts/_default/_markup/render-link.html diff --git a/layouts/_default/_markup/render-link.html b/layouts/_default/_markup/render-link.html new file mode 100644 index 0000000..a02db86 --- /dev/null +++ b/layouts/_default/_markup/render-link.html @@ -0,0 +1 @@ +{{ .Text | safeHTML }}{{ if strings.HasPrefix .Destination "http" }}↗{{ end }} \ No newline at end of file From 46229fbe0a72c62eb727f1120ee4698d88bd0270 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 22:28:33 -0500 Subject: [PATCH 15/26] remove unused icon font resource --- layouts/partials/head.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/layouts/partials/head.html b/layouts/partials/head.html index 027c4f3..b6ea36d 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -26,9 +26,6 @@ - - - From 25e427498663b8cfcdbc6c2ccbf983fd57c41f66 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 22:44:06 -0500 Subject: [PATCH 16/26] update colophon --- content/colophon.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/content/colophon.md b/content/colophon.md index a6a6fc6..fda61d4 100644 --- a/content/colophon.md +++ b/content/colophon.md @@ -1,7 +1,7 @@ --- title: "/colophon" date: "2024-05-26T22:30:58Z" -lastmod: "2024-06-18T16:09:47Z" +lastmod: "2024-06-29T03:29:46Z" description: "There's a lot that goes into this site. Let me tell you how it works." featured: false toc: true @@ -11,14 +11,16 @@ categories: slashes *I don't consider myself to be a web developer, but I've learned a **ton** through the process of building/tweaking/maintaining this site. The [colophon](https://indieweb.org/colophon) provides a quick overview of what powers `runtimeterror.dev`.* ### This site... -- is built with [Hugo](https://gohugo.io/) using the [risotto](https://github.com/joeroe/risotto) theme with many, many tweaks and customizations. -- uses the font face [Berkeley Mono](https://berkeleygraphics.com/typefaces/berkeley-mono/) ([details](/using-custom-font-hugo/)). +- is built with [Hugo](https://gohugo.io/) based on the [risotto](https://github.com/joeroe/risotto) theme with many, many tweaks and customizations. +- uses the font face [Berkeley Mono](https://berkeleygraphics.com/typefaces/berkeley-mono/) ([details](/using-custom-font-hugo/)), and icons from [Font Awesome](https://fontawesome.com/) and [Fork Awesome](https://forkaweso.me/). - performs syntax highlighting with [Torchlight](https://torchlight.dev) ([details](/spotlight-on-torchlight/)). - provides site search with [lunr](https://lunrjs.com/) based on an implementation detailed by [Victoria Drake](https://victoria.dev/blog/add-search-to-hugo-static-sites-with-lunr/). - leverages [Cabin](https://withcabin.com) for [privacy-friendly](https://withcabin.com/privacy/runtimeterror.dev) analytics. - resolves via [Bunny DNS](https://bunny.net/dns/). - is published to / hosted on [Bunny Storage](https://bunny.net/storage/) and [Bunny CDN](https://bunny.net/cdn/) with a [GitHub Actions workflow](//further-down-the-bunny-hole/) -- has a [Gemini](https://geminiprotocol.net) mirror at `gemini://gmi.runtimeterror.dev`. This is generated from a [Hugo gemtext post layout](https://github.com/jbowdre/runtimeterror/blob/main/layouts/_default/single.gmi), deployed to a [Vultr](https://www.vultr.com/) VPS through a GitHub Actions workflow, and served with [Agate](https://github.com/mbrubeck/agate). +- has a [Gemini](https://geminiprotocol.net) mirror at `gemini://gmi.runtimeterror.dev`. This is generated from a [Hugo gemtext post layout](https://github.com/jbowdre/runtimeterror/blob/main/layouts/_default/single.gmi), deployed to a [Vultr](https://www.vultr.com/) VPS through that same GitHub Actions workflow, and served with [Agate](https://github.com/mbrubeck/agate). + +The post content is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/); the site code is under the [MIT License](https://github.com/jbowdre/runtimeterror/blob/main/LICENSE). Look behind the scenes at [github.com/jbowdre/runtimeterror](https://github.com/jbowdre/runtimeterror). From 9c6da303a95c604fd24861a224ac09f5a2b078a2 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 22:53:52 -0500 Subject: [PATCH 17/26] clean up render-link template, add rel=external attr --- layouts/_default/_markup/render-link.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/layouts/_default/_markup/render-link.html b/layouts/_default/_markup/render-link.html index a02db86..8e0f347 100644 --- a/layouts/_default/_markup/render-link.html +++ b/layouts/_default/_markup/render-link.html @@ -1 +1,9 @@ -{{ .Text | safeHTML }}{{ if strings.HasPrefix .Destination "http" }}↗{{ end }} \ No newline at end of file +{{- $u := urls.Parse .Destination -}} + + {{- with .Text | safeHTML }}{{ . }}{{ end -}} + {{- if $u.IsAbs }}↗{{ end -}} + +{{- /* chomp trailing newline */ -}} \ No newline at end of file From 15fc1a9ebae271fa3f2c15bdc4a05d701fee974b Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 22:55:13 -0500 Subject: [PATCH 18/26] update changelog --- content/changelog.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/content/changelog.md b/content/changelog.md index e6b0fac..9f621c6 100644 --- a/content/changelog.md +++ b/content/changelog.md @@ -1,7 +1,7 @@ --- title: "/changelog" date: "2024-05-26T21:19:08Z" -lastmod: "2024-06-25T04:11:34Z" +lastmod: "2024-06-29T03:55:04Z" description: "Maybe I should keep a log of all my site-related tinkering?" featured: false toc: false @@ -10,6 +10,10 @@ categories: slashes --- *High-level list of config/layout changes to the site. The full changelog is of course [on GitHub](https://github.com/jbowdre/runtimeterror/commits/main/).* +**2024-06-28:** +- Add [recentfm.js](https://recentfm.rknight.me/) recently-played widget to sidebar +- Use [Hugo render-hook](https://gohugo.io/render-hooks/links/#examples) to add ↗ marker to external links + **2024-06-24:** - Select the [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1) license - Add a simple [upvote widget powered by Cabin](/kudos-with-cabin/) to posts From bbc65d85de7af57f209f75d57ef2299e49d6d079 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Fri, 28 Jun 2024 22:56:16 -0500 Subject: [PATCH 19/26] update changelog, again --- content/changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/changelog.md b/content/changelog.md index 9f621c6..abcfe95 100644 --- a/content/changelog.md +++ b/content/changelog.md @@ -13,6 +13,7 @@ categories: slashes **2024-06-28:** - Add [recentfm.js](https://recentfm.rknight.me/) recently-played widget to sidebar - Use [Hugo render-hook](https://gohugo.io/render-hooks/links/#examples) to add ↗ marker to external links +- Redirect /uses and /saves to pages on the [personal blog](https://blog.jbowdre.lol) **2024-06-24:** - Select the [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1) license From 9ffd72be6e9d6e324bfd303dfd16747592ec7fb5 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Sat, 29 Jun 2024 08:17:59 -0500 Subject: [PATCH 20/26] fix site.webmanifest file to match site theme --- static/icons/site.webmanifest | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/static/icons/site.webmanifest b/static/icons/site.webmanifest index 5b2f361..229f33d 100644 --- a/static/icons/site.webmanifest +++ b/static/icons/site.webmanifest @@ -1,6 +1,6 @@ { - "name": "", - "short_name": "", + "name": "runtimeterror", + "short_name": "runtimeterror", "icons": [ { "src": "/icons/android-chrome-192x192.png", @@ -13,7 +13,7 @@ "type": "image/png" } ], - "theme_color": "#ffffff", - "background_color": "#ffffff", + "theme_color": "#090909", + "background_color": "#090909", "display": "standalone" } From 17fd7cf661447a2280945afc240cfb6ffd120ef6 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Mon, 1 Jul 2024 10:10:39 -0500 Subject: [PATCH 21/26] take down decorations --- layouts/partials/head.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/layouts/partials/head.html b/layouts/partials/head.html index b6ea36d..c9c53f9 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -34,9 +34,6 @@ - - - {{ if eq .Site.Params.analytics true }} From f67f8390b6b3861cc3e649782063b084079c1835 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Wed, 3 Jul 2024 10:57:28 -0500 Subject: [PATCH 22/26] add support for new 'fediverse:creator' property --- config/_default/params.toml | 1 + layouts/partials/head.html | 1 + 2 files changed, 2 insertions(+) diff --git a/config/_default/params.toml b/config/_default/params.toml index e54992d..40b9e52 100644 --- a/config/_default/params.toml +++ b/config/_default/params.toml @@ -44,6 +44,7 @@ reply = true name = "John Bowdre" email = "jbowdre@omg.lol" username = "jbowdre" +fedi = "@jbowdre@social.lol" [theme] palette = "runtimeterror" diff --git a/layouts/partials/head.html b/layouts/partials/head.html index c9c53f9..7f68aed 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -1,5 +1,6 @@ {{ with .Title }}{{ . }} – {{end}}{{ .Site.Title }} {{ with .Site.Params.about }}{{ end }} +{{ with .Site.Params.Author.fedi }}{{ end }} From 5a80a653648b390cd796067854716266f734ac97 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Wed, 3 Jul 2024 10:59:27 -0500 Subject: [PATCH 23/26] fix for description in head --- layouts/partials/head.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/partials/head.html b/layouts/partials/head.html index 7f68aed..d6ed8bb 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -1,5 +1,5 @@ {{ with .Title }}{{ . }} – {{end}}{{ .Site.Title }} -{{ with .Site.Params.about }}{{ end }} + {{ with .Site.Params.Author.fedi }}{{ end }} From 94678c36fec7078911950860aefe6dfb49472e6d Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Wed, 3 Jul 2024 12:21:42 -0500 Subject: [PATCH 24/26] fix sitemap url --- layouts/robots.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/robots.txt b/layouts/robots.txt index 63c6f07..6c7d9c0 100644 --- a/layouts/robots.txt +++ b/layouts/robots.txt @@ -1,4 +1,4 @@ -Sitemap: {{ .Site.BaseURL }}/sitemap.xml +Sitemap: {{ .Site.BaseURL }}sitemap.xml # hello robots [^_^] # let's be friends <3 From a419ec04d2bf3da70b46bcb99e7d78ea56f31455 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Wed, 3 Jul 2024 13:07:28 -0500 Subject: [PATCH 25/26] errors++; --- config/_default/params.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/_default/params.toml b/config/_default/params.toml index 40b9e52..9a5dc3e 100644 --- a/config/_default/params.toml +++ b/config/_default/params.toml @@ -81,6 +81,7 @@ taglines = [ "errors are for beginners, we only do undefined behavior", "expression has no effect", "failed successfully", + "fatal: detected dubious ownership in repository", "file descriptor in bad state", "floating in a sea of bugs", "from chatgpt with bugs", From 57d73646b872871c127043bbe934b316cf0ee061 Mon Sep 17 00:00:00 2001 From: John Bowdre Date: Wed, 3 Jul 2024 21:33:59 -0500 Subject: [PATCH 26/26] remove `target='_blank'` from external links for better security and accessibility --- config/_default/menu.toml | 12 ------------ content/changelog.md | 5 ++++- content/posts/the-slash-page-scoop/index.md | 8 ++++---- layouts/partials/about.html | 4 ++-- layouts/partials/archive.html | 4 ++-- layouts/partials/footer.html | 4 ++-- layouts/partials/header.html | 2 +- 7 files changed, 15 insertions(+), 24 deletions(-) diff --git a/config/_default/menu.toml b/config/_default/menu.toml index 9c0f11a..260de17 100644 --- a/config/_default/menu.toml +++ b/config/_default/menu.toml @@ -9,45 +9,33 @@ name = "self-hosting" url = "/categories/self-hosting/" weight = 1 - [[main.params]] - target = "_self" [[main]] identifier = "tips" name = "tips" url = "/categories/tips/" weight = 1 - [[main.params]] - target = "_self" [[main]] identifier = "code" name = "code" url = "/categories/code/" weight = 1 - [[main.params]] - target = "_self" [[main]] identifier = "backstage" name = "backstage" url = "/categories/backstage/" weight = 1 - [[main.params]] - target = "_self" [[main]] identifier = "slashes" name = "slashes" url = "/slashes/" weight = 10 - [[main.params]] - target = "_self" [[main]] identifier = "notes" name = "notes↗" url = "https://notes.runtimeterror.dev" weight = 100 - [[main.params]] - target = "_blank" diff --git a/content/changelog.md b/content/changelog.md index abcfe95..5d48d4c 100644 --- a/content/changelog.md +++ b/content/changelog.md @@ -1,7 +1,7 @@ --- title: "/changelog" date: "2024-05-26T21:19:08Z" -lastmod: "2024-06-29T03:55:04Z" +lastmod: "2024-07-04T02:32:27Z" description: "Maybe I should keep a log of all my site-related tinkering?" featured: false toc: false @@ -10,6 +10,9 @@ categories: slashes --- *High-level list of config/layout changes to the site. The full changelog is of course [on GitHub](https://github.com/jbowdre/runtimeterror/commits/main/).* +**2024-07-03:** +- Remove `target="_blank"` from external links for improved security and accessibility + **2024-06-28:** - Add [recentfm.js](https://recentfm.rknight.me/) recently-played widget to sidebar - Use [Hugo render-hook](https://gohugo.io/render-hooks/links/#examples) to add ↗ marker to external links diff --git a/content/posts/the-slash-page-scoop/index.md b/content/posts/the-slash-page-scoop/index.md index 4f124bc..b69c7ec 100644 --- a/content/posts/the-slash-page-scoop/index.md +++ b/content/posts/the-slash-page-scoop/index.md @@ -1,7 +1,7 @@ --- title: "The Slash Page Scoop" date: 2024-06-02 -# lastmod: 2024-05-30 +lastmod: "2024-07-04T02:23:41Z" description: "I've added new slash pages to the site to share some background info on who I am, what I use, and how this site works." featured: false toc: true @@ -101,7 +101,7 @@ Of course, I'd like to include a link to [slashpages.net](https://slashpages.net {{ if .IsHome }}

      {{ site.Params.indexTitle | markdownify }}

      {{ else }} -

      {{ .Title | markdownify }}{{ if eq .Kind "term" }}  

      +

      {{ .Title | markdownify }}{{ if eq .Kind "term" }}  

      {{ with .Description }}{{ . }}
      {{ else }}
      {{ end }} {{ end }}{{ end }} {{ .Content }} @@ -122,9 +122,9 @@ Line 9 is where I had already modified the template to conditionally add an RSS {{ else }} {{ if eq .Title "/slashes" }}

      {{ .Title | markdownify }}

      - My collection of slash pages.
      + My collection of slash pages↗.
      {{ else }} -

      {{ .Title | markdownify }}{{ if eq .Kind "term" }}  

      +

      {{ .Title | markdownify }}{{ if eq .Kind "term" }}  

      {{ with .Description }}{{ . }}
      {{ else }}
      {{ end }} {{ end }} {{ end }}{{ end }} diff --git a/layouts/partials/about.html b/layouts/partials/about.html index 6e8fc01..f78bae7 100644 --- a/layouts/partials/about.html +++ b/layouts/partials/about.html @@ -1,7 +1,7 @@ {{ with .Site.Params.about }}
      {{ with .logo }}{{ end }} -

      {{ .title }}  

      +

      {{ .title }}  

      {{ partial "tagline.html" . }}
       {{ site.Params.Author.name }} @@ -10,7 +10,7 @@ diff --git a/layouts/partials/archive.html b/layouts/partials/archive.html index dafba78..e1d7888 100644 --- a/layouts/partials/archive.html +++ b/layouts/partials/archive.html @@ -8,9 +8,9 @@ {{ else }} {{ if eq .Title "/slashes" }}

      {{ .Title | markdownify }}

      - My collection of slash pages.
      + My collection of slash pages↗.
      {{ else }} -

      {{ .Title | markdownify | lower }}{{ if eq .Kind "term" }}  

      +

      {{ .Title | markdownify | lower }}{{ if eq .Kind "term" }}  

      {{ with .Description }}{{ . }}{{ end }} {{ end }}
      diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index edaebb2..e82425f 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -1,6 +1,6 @@ {"/slashes": [{{- range $i, $link := .Site.Params.slashPages }}{{ if $i }}, {{ end }}"{{ $link.title }}"{{ end }}]} -
      {"copyright": ["content": "CC BY-NC-SA 4.0", "code": "MIT"]} -
      <view source> +
      {"copyright": ["content": "CC BY-NC-SA 4.0↗", "code": "MIT↗"]} +
      <view source↗> {{ $jsToTop := resources.Get "js/back-to-top.js" | minify }} diff --git a/layouts/partials/header.html b/layouts/partials/header.html index 7bf4fcf..45c46ce 100644 --- a/layouts/partials/header.html +++ b/layouts/partials/header.html @@ -3,7 +3,7 @@

      {{ .Site.Title }}

      {{ $currentPage := . }} {{ range .Site.Menus.main }} -
    • + {{ end }}