mirror of
https://github.com/jbowdre/runtimeterror.git
synced 2024-12-25 04:02:19 +00:00
Merge branch 'main' into drafts
This commit is contained in:
commit
010517ba3a
28 changed files with 102 additions and 298 deletions
4
.github/workflows/deploy-prod.yml
vendored
4
.github/workflows/deploy-prod.yml
vendored
|
@ -45,7 +45,9 @@ jobs:
|
|||
echo "${{ secrets.SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
|
||||
chmod 644 ~/.ssh/known_hosts
|
||||
- name: Build with Hugo
|
||||
run: HUGO_REMOTE_FONT_PATH=${{ secrets.REMOTE_FONT_PATH }} hugo --minify
|
||||
run: |
|
||||
HUGO_REMOTE_FONT_PATH=${{ secrets.REMOTE_FONT_PATH }} \
|
||||
hugo --minify
|
||||
- name: Insert 404 page
|
||||
run: |
|
||||
mkdir -p public/bunnycdn_errors
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
// manipulates the post upvote "kudos" button behavior
|
||||
|
||||
window.onload = function() {
|
||||
// get the button and text elements
|
||||
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
|
||||
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
|
||||
});
|
||||
}
|
|
@ -1,195 +0,0 @@
|
|||
/*
|
||||
|
||||
Typo, a more natural web typing thing
|
||||
|
||||
https://neatnik.net/typo
|
||||
https://github.com/neatnik/typo
|
||||
|
||||
Copyright (c) 2021 Neatnik LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
function num_between(min, max) {
|
||||
return Math.floor(Math.random() * (max- min + 1) + min);
|
||||
}
|
||||
|
||||
function chance(val) {
|
||||
if(num_between(0, 100) < val) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
var typos = {
|
||||
q:['w','a'],
|
||||
w:['q','r','s'],
|
||||
e:['w','d','r'],
|
||||
r:['e','f','t'],
|
||||
t:['r','g','y'],
|
||||
y:['t','h','u'],
|
||||
u:['y','j','i'],
|
||||
i:['u','k','o'],
|
||||
o:['i','l','p'],
|
||||
p:['o',';','['],
|
||||
a:['q','s','z'],
|
||||
s:['w','a','x','d'],
|
||||
d:['e','s','c','f'],
|
||||
f:['r','d','v','g'],
|
||||
g:['t','f','b','h'],
|
||||
h:['y','g','n','j'],
|
||||
j:['u','h','m','k'],
|
||||
k:['i','j',',','l'],
|
||||
l:['o','k','.',';'],
|
||||
z:['a','x'],
|
||||
x:['z','s','c'],
|
||||
c:['x','d','v'],
|
||||
v:['c','f','b'],
|
||||
b:['v','g','n'],
|
||||
n:['b','h','m'],
|
||||
m:['n','j',','],
|
||||
}
|
||||
|
||||
async function typo(element, text) {
|
||||
var buffer = '';
|
||||
var typo_active = false;
|
||||
var tag_active = false;
|
||||
var typing_typos = (element.dataset.typoChance) ? element.dataset.typoChance : 10;
|
||||
var typing_speed = (element.dataset.typingDelay) ? element.dataset.typingDelay : 50;
|
||||
var typing_jitter = (element.dataset.typingJitter) ? element.dataset.typingJitter : 15;
|
||||
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
|
||||
// Get the letter that we’re supposed to type
|
||||
letter = text.charAt(i);
|
||||
|
||||
// TODO: actual support for html or markup or whatever
|
||||
|
||||
/*
|
||||
// Handle elements/markup
|
||||
if(letter == '<' && (
|
||||
text.charAt(i+1) == 's' ||
|
||||
text.charAt(i+1) == 'p' ||
|
||||
text.charAt(i+1) == 'a' ||
|
||||
text.charAt(i+1) == '/' ||
|
||||
text.charAt(i+1) == 'i')
|
||||
) {
|
||||
tag_active = true;
|
||||
}
|
||||
|
||||
if(tag_active) {
|
||||
|
||||
buffer = buffer + letter;
|
||||
element.innerHTML = buffer;
|
||||
|
||||
if(letter == '>' && (
|
||||
text.charAt(i-1) == 'n' ||
|
||||
text.charAt(i-1) == 'a' ||
|
||||
text.charAt(i-1) == 'p' ||
|
||||
text.charAt(i+1) == '"' ||
|
||||
text.charAt(i+1) == '/')
|
||||
) {
|
||||
tag_active = false;
|
||||
await sleep(typing_speed);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
|
||||
// Trigger a typo
|
||||
if(chance(typing_typos) && typo_active === false && i > 1) {
|
||||
|
||||
if(typeof typos[letter] !== 'undefined') {
|
||||
|
||||
// Swap the letter with a random typo
|
||||
typo = typos[letter][Math.floor(Math.random() * typos[letter].length)];
|
||||
|
||||
// Append the letter to the buffer
|
||||
buffer = buffer + typo;
|
||||
|
||||
// Write the buffer
|
||||
element.innerHTML = buffer;
|
||||
|
||||
typo_active = true;
|
||||
var seed = num_between(2,5);
|
||||
realization_delay = seed;
|
||||
realization_delay_counter = seed;
|
||||
}
|
||||
}
|
||||
|
||||
// Append the letter to the buffer
|
||||
buffer = buffer + letter;
|
||||
|
||||
// Write the buffer
|
||||
element.innerHTML = buffer;
|
||||
|
||||
// Typical typing speed
|
||||
var speed_lower = parseFloat(typing_speed) - parseInt(typing_jitter);
|
||||
var speed_upper = parseFloat(typing_speed) + parseInt(typing_jitter);
|
||||
|
||||
delay = num_between(speed_lower,speed_upper);
|
||||
|
||||
// Chance of longer delay though
|
||||
if(chance(5)) delay = num_between(100, 200);
|
||||
await sleep(delay);
|
||||
|
||||
if(typo_active) {
|
||||
|
||||
realization_delay_counter--;
|
||||
|
||||
if(realization_delay_counter == 0) {
|
||||
|
||||
for (var k = 0; k < seed+1; k++) {
|
||||
|
||||
// Pause at realization of typo
|
||||
await sleep(typing_jitter);
|
||||
|
||||
// Rewind the buffer!
|
||||
buffer = buffer.substring(0, buffer.length - 1);
|
||||
|
||||
// Write rewound buffer
|
||||
element.innerHTML = buffer;
|
||||
|
||||
// Brief pause before continuing
|
||||
await sleep(30);
|
||||
}
|
||||
|
||||
typo_active = false;
|
||||
|
||||
// Add the letters back
|
||||
i = i - seed;
|
||||
await sleep(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Whatever you do here will happen when the typing is finished
|
||||
//do_something();
|
||||
|
||||
return new Promise(resolve => setTimeout(resolve, 1));
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var element = document.getElementById('tagline');
|
||||
var text = element.innerHTML;
|
||||
typo(element, text);
|
||||
});
|
|
@ -8,33 +8,8 @@ numberOfRelatedPosts = 5
|
|||
|
||||
indexTitle = ".-. ..- -. - .. -- . - . .-. .-. --- .-."
|
||||
|
||||
bad_robots = [
|
||||
"AdsBot-Google",
|
||||
"Amazonbot",
|
||||
"anthropic-ai",
|
||||
"Applebot-Extended",
|
||||
"AwarioRssBot",
|
||||
"AwarioSmartBot",
|
||||
"Bytespider",
|
||||
"CCBot",
|
||||
"ChatGPT",
|
||||
"ChatGPT-User",
|
||||
"Claude-Web",
|
||||
"ClaudeBot",
|
||||
"cohere-ai",
|
||||
"DataForSeoBot",
|
||||
"Diffbot",
|
||||
"FacebookBot",
|
||||
"Google-Extended",
|
||||
"GPTBot",
|
||||
"ImagesiftBot",
|
||||
"magpie-crawler",
|
||||
"omgili",
|
||||
"Omgilibot",
|
||||
"peer39_crawler",
|
||||
"PerplexityBot",
|
||||
"YouBot"
|
||||
]
|
||||
omgUser = "jbowdre"
|
||||
musicThreadId = "2aVjZUocjk96LELFbV5JvJjm14v"
|
||||
|
||||
# Comments
|
||||
analytics = true
|
||||
|
@ -167,7 +142,7 @@ url = "https://jbowdre.lol"
|
|||
[[socialLinks]]
|
||||
icon = "fa-solid fa-pen-to-square"
|
||||
title = "Weblog"
|
||||
url = "https://blog.jbowdre.lol"
|
||||
url = "https://srsbsns.lol"
|
||||
|
||||
[[socialLinks]]
|
||||
icon = "fa-solid fa-satellite"
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
baseURL = "http://localhost:1313/"
|
||||
baseURL = "http://localhost:1313/"
|
||||
enableRobotsTXT = false
|
|
@ -1 +1,2 @@
|
|||
baseURL = "https://preview.runtimeterror.dev/"
|
||||
baseURL = "https://preview.runtimeterror.dev/"
|
||||
enableRobotsTXT = false
|
|
@ -27,7 +27,7 @@ And in the free time I have left, I game on my Steam Deck.
|
|||
|
||||
### See what I've been up to on:
|
||||
- [GitHub](https://github.com/jbowdre)
|
||||
- [Weblog](https://blog.jbowdre.lol)
|
||||
- [Weblog](https://srsbsns.lol)
|
||||
- [Gemlog](https://capsule.jbowdre.lol/gemlog/)
|
||||
- [status.lol](https://status.jbowdre.lol)
|
||||
- [social.lol](https://social.lol/@jbowdre)
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
---
|
||||
title: "/changelog"
|
||||
date: "2024-05-26T21:19:08Z"
|
||||
lastmod: "2024-07-04T02:32:27Z"
|
||||
lastmod: "2024-08-04T22:30:43Z"
|
||||
description: "Maybe I should keep a log of all my site-related tinkering?"
|
||||
featured: false
|
||||
toc: false
|
||||
timeless: true
|
||||
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/).*
|
||||
*Running list of config/layout changes to the site. The full changelog is of course [on GitHub](https://github.com/jbowdre/runtimeterror/commits/main/).*
|
||||
|
||||
**2024-08-04:**
|
||||
- Dynamically build `robots.txt` based on [ai.robots.txt](https://github.com/ai-robots-txt/ai.robots.txt)
|
||||
|
||||
**2024-08-02:**
|
||||
- Display "pinned" recent track in sidebar using [MusicThread](https://musicthread.app) instead of latest scrobble
|
||||
- Tweak Typo behavior to avoid uncorrected mistakes near the end of the string
|
||||
|
||||
**2024-07-29:**
|
||||
- Build `robots.txt` dynamically with [Dark Visitors API](https://darkvisitors.com/) and code from [Luke Harris](https://www.lkhrs.com/blog/2024/darkvisitors-hugo/)
|
||||
|
||||
**2024-07-03:**
|
||||
- Remove `target="_blank"` from external links for improved security and accessibility
|
||||
|
@ -16,7 +26,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)
|
||||
- Redirect /uses and /saves to pages on the [personal blog](https://srsbsns.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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: "/colophon"
|
||||
date: "2024-05-26T22:30:58Z"
|
||||
lastmod: "2024-06-29T03:29:46Z"
|
||||
lastmod: "2024-08-02T21:16:41Z"
|
||||
description: "There's a lot that goes into this site. Let me tell you how it works."
|
||||
featured: false
|
||||
toc: true
|
||||
|
@ -15,9 +15,12 @@ categories: slashes
|
|||
- 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/).
|
||||
- fetches [ai.robots.txt](https://github.com/ai-robots-txt/ai.robots.txt) to dynamically generate a [robots.txt](/robots.txt) discouraging AI scrapers with Hugo's [`resources.GetRemote` capability](https://gohugo.io/functions/resources/getremote/).
|
||||
- leverages [Cabin](https://withcabin.com) for [privacy-friendly](https://withcabin.com/privacy/runtimeterror.dev) analytics.
|
||||
- fetches recently-played music from [MusicThread](https://musicthread.app/).
|
||||
- displays my latest status from [omg.lol](https://home.omg.lol/referred-by/jbowdre).
|
||||
- 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/)
|
||||
- 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 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).
|
||||
|
|
|
@ -79,6 +79,6 @@ I like to know what's flying overhead, and I'm also feeding flight data to [flig
|
|||
- [Kineto](https://github.com/beelux/kineto) Gemini-to-HTTP proxy ([post](/gemini-capsule-gempost-github-actions/))
|
||||
- [Linkding](https://github.com/sissbruecker/linkding) bookmark manager serving [links.bowdre.net](https://links.bowdre.net/bookmarks/shared)
|
||||
- [ntfy](https://ntfy.sh/) notification service ([post](/easy-push-notifications-with-ntfy/))
|
||||
- [SearXNG](https://docs.searxng.org/) self-hosted metasearch engine serving [grep.vpota.to](https://grep.vpota.to) ([post](https://blog.jbowdre.lol/post/self-hosting-a-search-engine-iyjdlk6y))
|
||||
- [SearXNG](https://docs.searxng.org/) self-hosted metasearch engine serving [grep.vpota.to](https://grep.vpota.to) ([post](https://srsbsns.lol/post/self-hosting-a-search-engine-iyjdlk6y))
|
||||
- [Uptime Kuma](https://github.com/louislam/uptime-kuma) for monitoring internal services (via Tailscale)
|
||||
- [vault-unseal](https://github.com/lrstanley/vault-unseal) to auto-unseal my on-prem Vault instance
|
||||
|
|
|
@ -14,7 +14,7 @@ tags:
|
|||
- meta
|
||||
- serverless
|
||||
---
|
||||
As I covered briefly [in a recent Scribble](https://blog.jbowdre.lol/post/near-realtime-weather-on-profile-lol-ku4yq-zr), I was inspired by the way [Kris's omg.lol page](https://kris.omg.lol/) displays realtime data from his [Weatherflow Tempest weather station](https://shop.weatherflow.com/products/tempest). I thought that was really neat and wanted to do the same on [my omg.lol page](https://jbowdre.lol) with data from my own Tempest, but I wanted to find a way to do it without needing to include an authenticated API call in the client-side JavaScript.
|
||||
As I covered briefly [in a recent Scribble](https://srsbsns.lol/post/near-realtime-weather-on-profile-lol-ku4yq-zr), I was inspired by the way [Kris's omg.lol page](https://kris.omg.lol/) displays realtime data from his [Weatherflow Tempest weather station](https://shop.weatherflow.com/products/tempest). I thought that was really neat and wanted to do the same on [my omg.lol page](https://jbowdre.lol) with data from my own Tempest, but I wanted to find a way to do it without needing to include an authenticated API call in the client-side JavaScript.
|
||||
|
||||
I realized I could use a GitHub Actions workflow to retrieve the data from the authenticated Tempest API, post it somewhere publicly accessible, and then have the client-side code fetch the data from there without needing any authentication. After a few days of tinkering, I came up with a presentation I'm happy with.
|
||||
|
||||
|
|
|
@ -14,11 +14,11 @@ tags:
|
|||
- meta
|
||||
- selfhosting
|
||||
---
|
||||
It wasn't too long ago (January, in fact) that I started [hosting this site with Neocities](/deploy-hugo-neocities-github-actions/). I was pretty pleased with that setup, but a few weeks ago my [monitoring setup](https://blog.jbowdre.lol/post/upptime-serverless-server-monitoring-c88fbaz7) started reporting that the site was down. And sure enough, trying to access the site would return a generic error message stating that the site was unknown. I eventually discovered that this was due to Neocities "forgetting" that the site was linked to the `runtimeterror.dev` domain. It was easy enough to just re-enter that domain in the configuration, and that immediately fixed things... until a few days later when the same thing happened again.
|
||||
It wasn't too long ago (January, in fact) that I started [hosting this site with Neocities](/deploy-hugo-neocities-github-actions/). I was pretty pleased with that setup, but a few weeks ago my [monitoring setup](https://srsbsns.lol/post/upptime-serverless-server-monitoring-c88fbaz7) started reporting that the site was down. And sure enough, trying to access the site would return a generic error message stating that the site was unknown. I eventually discovered that this was due to Neocities "forgetting" that the site was linked to the `runtimeterror.dev` domain. It was easy enough to just re-enter that domain in the configuration, and that immediately fixed things... until a few days later when the same thing happened again.
|
||||
|
||||
The same problem has now occurred five or six times, and my messages to the Neocities support contact have gone unanswered. I didn't see anyone else online reporting this exact issue, but I found several posts on Reddit about sites getting randomly broken (or even deleted!) and support taking a week (or more) to reply. I don't have that kind of patience, so I started to consider moving my content away from Neocities and cancelling my $5/month Supporter subscription.
|
||||
|
||||
I [recently](https://blog.jbowdre.lol/post/i-just-hopped-to-bunny-net) started using [bunny.net](https://bunny.net) for the site's DNS, and had also [leveraged Bunny's CDN for hosting font files](/using-custom-font-hugo/). This setup has been working great for me, and I realized that I could also use Bunny's CDN for hosting the entirety of my static site as well. After all, serving static files on the web is exactly what a CDN is great at. After an hour or two of tinkering, I successfully switched hosting setups with just a few seconds of downtime.
|
||||
I [recently](https://srsbsns.lol/post/i-just-hopped-to-bunny-net) started using [bunny.net](https://bunny.net) for the site's DNS, and had also [leveraged Bunny's CDN for hosting font files](/using-custom-font-hugo/). This setup has been working great for me, and I realized that I could also use Bunny's CDN for hosting the entirety of my static site as well. After all, serving static files on the web is exactly what a CDN is great at. After an hour or two of tinkering, I successfully switched hosting setups with just a few seconds of downtime.
|
||||
|
||||
Here's how I did it.
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ I'm not one to really worry about page view metrics, but I do like to see which
|
|||
|
||||
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.
|
||||
I recently shared [on my Bear weblog](https://srsbsns.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.
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ That's getting there:
|
|||
|
||||
![A darker styled RSS page](getting-there-feed.png)
|
||||
|
||||
Including those CSS styles means that the rendered page now uses my color palette and the [font I worked so hard to integrate](/using-custom-font-hugo/). I'm just going to make a few more tweaks to change some of the formatting, put the `New to feeds?` bit on its own line, and point to [Mojeek](https://mojeek.com) instead of DDG ([why?](https://blog.jbowdre.lol/post/a-comprehensive-evaluation-of-various-search-engines-i-ve-used)).
|
||||
Including those CSS styles means that the rendered page now uses my color palette and the [font I worked so hard to integrate](/using-custom-font-hugo/). I'm just going to make a few more tweaks to change some of the formatting, put the `New to feeds?` bit on its own line, and point to [Mojeek](https://mojeek.com) instead of DDG ([why?](https://srsbsns.lol/post/a-comprehensive-evaluation-of-various-search-engines-i-ve-used)).
|
||||
|
||||
Here's my final (for now) `static/xml/feed.xsl` file:
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 90 KiB |
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: "Taking Taildrive for a Testdrive"
|
||||
date: "2024-07-29T23:48:29Z"
|
||||
# lastmod: 2024-07-28
|
||||
lastmod: "2024-07-30T13:59:50Z"
|
||||
description: "A quick exploration of Taildrive, Tailscale's new(ish) feature to easily share directories with other machines on your tailnet without having to juggle authentication or network connectivity."
|
||||
featured: false
|
||||
toc: true
|
||||
|
@ -140,15 +140,19 @@ sudo apt update # [tl! .cmd:1]
|
|||
sudo apt install davfs2
|
||||
```
|
||||
|
||||
During the install of `davfs2`, I got prompted for whether or not I want to allow unprivileged users to mount WebDAV resources. I was in a hurry and just selected the default `<No>` response... before I realized that was probably a mistake (at least for this particular use case).
|
||||
I need to be able mount the share as my standard user account (*without* elevation) to ensure that the ownership and permissions are correctly inherited. The `davfs2` installer offered to enable the SUID bit to support this, but that change on its own doesn't seem to have been sufficient in my testing. In addition (or perhaps instead?), I had to add my account to the `davfs2` group:
|
||||
|
||||
So I ran `sudo dpkg-reconfigure davfs2` to try again and this time made sure to select `<Yes>`:
|
||||
```shell
|
||||
sudo usermod -aG davfs2 $USER # [tl! .cmd]
|
||||
```
|
||||
|
||||
![Should unprivileged users be allowed to mount WebDAV resources?](davfs-suid.png)
|
||||
And then use the `newgrp` command to load the new membership without having to log out and back in again:
|
||||
|
||||
That should ensure that the share gets mounted with appropriate privileges (otherwise, all the files would be owned by `root` and that could pose some additional challenges).
|
||||
```shell
|
||||
newgrp davfs2 # [tl! .cmd]
|
||||
```
|
||||
|
||||
I also created a folder inside my home directory to use as a mountpoint:
|
||||
Next I created a folder inside my home directory to use as a mountpoint:
|
||||
|
||||
```shell
|
||||
mkdir ~/taildrive # [tl! .cmd]
|
||||
|
|
|
@ -13,7 +13,7 @@ tags:
|
|||
- meta
|
||||
- tailscale
|
||||
---
|
||||
Last week, I came across and immediately fell in love with a delightfully-retro monospace font called [Berkeley Mono](https://berkeleygraphics.com/typefaces/berkeley-mono/). I promptly purchased a "personal developer" license and set to work [applying the font in my IDE and terminal](https://blog.jbowdre.lol/post/trying-tabby-terminal). I didn't want to stop there, though; the license also permits me to use the font on my personal site, and Berkeley Mono will fit in beautifully with the whole runtimeterror aesthetic.
|
||||
Last week, I came across and immediately fell in love with a delightfully-retro monospace font called [Berkeley Mono](https://berkeleygraphics.com/typefaces/berkeley-mono/). I promptly purchased a "personal developer" license and set to work [applying the font in my IDE and terminal](https://srsbsns.lol/post/trying-tabby-terminal). I didn't want to stop there, though; the license also permits me to use the font on my personal site, and Berkeley Mono will fit in beautifully with the whole runtimeterror aesthetic.
|
||||
|
||||
Well, you're looking at the slick new font here, and I'm about to tell you how I added the font both to the site itself and to the [dynamically-generated OpenGraph share images](/dynamic-opengraph-images-with-hugo/) setup. It wasn't terribly hard to implement, but the Hugo documentation is a bit light on how to do it (and I'm kind of inept at this whole web development thing).
|
||||
|
||||
|
@ -81,7 +81,7 @@ And that would work just fine... but it *would* require storing those web font f
|
|||
So instead, I opted to try using a [Content Delivery Network (CDN)](https://en.wikipedia.org/wiki/Content_delivery_network) to host the font files. This would allow for some degree of access control, help me learn more about a web technology I hadn't played with much, and make use of a cool `cdn.*` subdomain in the process.
|
||||
|
||||
{{% notice note "Double the CDN, double the fun" %}}
|
||||
Of course, while writing this post I gave in to my impulsive nature and [migrated the site from Cloudflare to Bunny.net](https://blog.jbowdre.lol/post/i-just-hopped-to-bunny-net). Rather than scrap the content I'd already written, I'll go ahead and describe how I set this up first on [Cloudflare R2](https://www.cloudflare.com/developer-platform/r2/) and later on [Bunny Storage](https://bunny.net/storage/).
|
||||
Of course, while writing this post I gave in to my impulsive nature and [migrated the site from Cloudflare to Bunny.net](https://srsbsns.lol/post/i-just-hopped-to-bunny-net). Rather than scrap the content I'd already written, I'll go ahead and describe how I set this up first on [Cloudflare R2](https://www.cloudflare.com/developer-platform/r2/) and later on [Bunny Storage](https://bunny.net/storage/).
|
||||
{{% /notice %}}
|
||||
|
||||
#### Cloudflare R2
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
---
|
||||
type: redirect
|
||||
target: https://blog.jbowdre.lol/save
|
||||
target: https://srsbsns.lol/save
|
||||
---
|
|
@ -1,4 +1,4 @@
|
|||
---
|
||||
type: redirect
|
||||
target: https://blog.jbowdre.lol/uses
|
||||
target: https://srsbsns.lol/uses
|
||||
---
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1719254875,
|
||||
"narHash": "sha256-ECni+IkwXjusHsm9Sexdtq8weAq/yUyt1TWIemXt3Ko=",
|
||||
"lastModified": 1722185531,
|
||||
"narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2893f56de08021cffd9b6b6dfc70fd9ccd51eb60",
|
||||
"rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -47,8 +47,7 @@
|
|||
</button>
|
||||
<span class="kudos-text">Enjoyed this?</span>
|
||||
</div>
|
||||
{{ $kudos := resources.Get "js/kudos.js" | minify }}
|
||||
<script src="{{ $kudos.RelPermalink }}"></script>
|
||||
<script src="https://res.runtimeterror.dev/js/kudos.js" async></script>
|
||||
<span class="post_email_reply"><a href="mailto:wheel.east.brief@clkdmail.com?Subject=Re: {{ .Title }}">📧 Reply by email</a></span>
|
||||
{{- end }}
|
||||
<footer class="content__footer"></footer>
|
||||
|
|
|
@ -51,10 +51,14 @@
|
|||
{{- end }}
|
||||
</ul>
|
||||
{{- end }}
|
||||
{{ with .Site.Params.omgUser }}
|
||||
<hr>
|
||||
<h3>status.lol</h3>
|
||||
<script src="https://status.lol/jbowdre.js?time&link&fluent&pretty"></script>
|
||||
<script src="https://status.lol/{{ . }}.js?time&link&fluent&pretty" defer></script>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.musicThreadId }}
|
||||
<hr>
|
||||
<h3>latest track</h3>
|
||||
<script src="https://recentfm.rknight.me/now.js?u=pushpianotire&e=🎶"></script>
|
||||
<h3>current theme song</h3>
|
||||
<script src="https://res.runtimeterror.dev/js/theme-song.js?id={{ . }}" defer></script>
|
||||
{{ end }}
|
||||
|
||||
|
|
15
layouts/partials/bad-robots.html
Normal file
15
layouts/partials/bad-robots.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{{- $url := "https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/main/robots.json" -}}
|
||||
{{- with resources.GetRemote $url -}}
|
||||
{{- with .Err -}}
|
||||
{{- errorf "%s" . -}}
|
||||
{{- else -}}
|
||||
{{- $robots := unmarshal .Content -}}
|
||||
{{- range $botname, $props := $robots }}
|
||||
{{- printf "User-agent: %s\n" $botname }}
|
||||
{{- end }}
|
||||
{{- printf "Disallow: /\n" }}
|
||||
{{- printf "\n# (bad bots bundled by https://github.com/ai-robots-txt/ai.robots.txt)" }}
|
||||
{{- end -}}
|
||||
{{- else -}}
|
||||
{{- errorf "Unable to get remote resource %q" $url -}}
|
||||
{{- end -}}
|
|
@ -13,5 +13,5 @@
|
|||
<!-- Code Copy button via https://digitaldrummerj.me/hugo-add-copy-code-snippet-button/ -->
|
||||
{{ if (findRE "<pre" .Content 1) }}
|
||||
{{ $jsCopy := resources.Get "js/code-copy-button.js" | minify }}
|
||||
<script src="{{ $jsCopy.RelPermalink }}"></script>
|
||||
<script src="{{ $jsCopy.RelPermalink }}" async></script>
|
||||
{{ end }}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
{{ if eq .Site.Params.analytics true }}
|
||||
<!-- cabin analytics -->
|
||||
<script async defer src="https://cabin.runtimeterror.dev/hello.js"></script>
|
||||
<script async src="https://cabin.runtimeterror.dev/hello.js"></script>
|
||||
{{ end }}
|
||||
|
||||
<!-- syntax highlighting -->
|
||||
|
@ -49,5 +49,4 @@
|
|||
{{ end }}
|
||||
|
||||
<!-- typo text animation -->
|
||||
{{ $jsTypo := resources.Get "js/typo.js" | minify }}
|
||||
<script src="{{ $jsTypo.RelPermalink }}"></script>
|
||||
<script src="https://res.runtimeterror.dev/js/typo.js" defer></script>
|
|
@ -12,6 +12,6 @@
|
|||
}
|
||||
</script>
|
||||
{{ $jsLunr := resources.Get "js/lunr.js" | minify }}
|
||||
<script src="{{ $jsLunr.RelPermalink }}"></script>
|
||||
<script src="{{ $jsLunr.RelPermalink }}" async></script>
|
||||
{{ $jsSearch := resources.Get "js/search.js" | minify }}
|
||||
<script src="{{ $jsSearch.RelPermalink }}"></script>
|
||||
<script src="{{ $jsSearch.RelPermalink }}" async></script>
|
|
@ -7,7 +7,5 @@ User-agent: *
|
|||
Disallow:
|
||||
|
||||
# except for these bots which are not friends:
|
||||
{{ range .Site.Params.bad_robots }}
|
||||
User-agent: {{ . }}
|
||||
{{- end }}
|
||||
Disallow: /
|
||||
|
||||
{{ partial "bad-robots.html" . }}
|
||||
|
|
|
@ -238,16 +238,28 @@ small[style^="opacity: .5"] {
|
|||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
/* recentfm styling */
|
||||
.recent-played {
|
||||
/* theme song styling */
|
||||
.theme-song {
|
||||
background: var(--off-bg) !important;
|
||||
flex-direction:column;
|
||||
border-radius: 0.5em;
|
||||
padding: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.7rem;
|
||||
font-size: 0.9rem;
|
||||
line-height: 0.9rem;
|
||||
}
|
||||
|
||||
.recent-played-track {
|
||||
margin: 0.5em 0;
|
||||
.theme-song img {
|
||||
width: 14rem;
|
||||
height: auto;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
@media (min-width: 45rem) {
|
||||
.theme-song img {
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* code overrides */
|
||||
|
@ -432,6 +444,7 @@ p:has(+ ul) {
|
|||
|
||||
.kudos-button:disabled {
|
||||
cursor: default;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.kudos-button .emoji {
|
||||
|
|
Loading…
Reference in a new issue