{% endfor %}
diff --git a/src/assets/js/dvorak-only.js b/src/assets/js/dvorak-only.js
new file mode 100644
index 0000000..b5dc8ae
--- /dev/null
+++ b/src/assets/js/dvorak-only.js
@@ -0,0 +1,52 @@
+window.customElements.define('dvorak-only', class extends HTMLElement {
+ isDvorak = false;
+
+ isDvorakSpan = null;
+
+ constructor() {
+ super();
+
+ setInterval(this.checkDvorak, 200);
+ }
+
+ checkDvorak = () => {
+ navigator.keyboard.getLayoutMap().then(layoutMap => {
+ this.isDvorak = layoutMap.get("KeyQ") === "'"
+ && layoutMap.get("KeyW") === ","
+ && layoutMap.get("KeyE") === "."
+ && layoutMap.get("KeyR") === "p"
+ && layoutMap.get("KeyT") === "y"
+ && layoutMap.get("KeyY") === "f";
+
+ this.isDvorakSpan.innerText = this.isDvorak ? 'Using dvorak' : 'not using dvorak';
+ });
+ }
+
+ connectedCallback() {
+ const shadow = this.attachShadow({ mode: "open" });
+
+ const wrapper = document.createElement('div');
+
+ this.inputSlot = document.createElement('slot');
+ this.inputSlot.setAttribute('name', 'input');
+
+ const input = document.createElement('input');
+ input.setAttribute('type', 'text');
+
+ this.inputSlot.appendChild(input);
+
+ this.isDvorakSpan = document.createElement('span');
+ this.isDvorakSpan.innerText = this.isDvorak ? 'Using dvorak' : 'not using dvorak';
+
+ wrapper.appendChild(this.isDvorakSpan);
+ wrapper.appendChild(this.inputSlot);
+
+ shadow.appendChild(wrapper);
+
+ this.inputSlot.assignedNodes()[0].addEventListener('keydown', (e) => {
+ if (!this.isDvorak) {
+ e.preventDefault();
+ }
+ });
+ }
+ });
\ No newline at end of file
diff --git a/src/blog/posts/2024/4/cursed-components-dvorak-only.md b/src/blog/posts/2024/4/cursed-components-dvorak-only.md
index 62c03e3..8d10068 100644
--- a/src/blog/posts/2024/4/cursed-components-dvorak-only.md
+++ b/src/blog/posts/2024/4/cursed-components-dvorak-only.md
@@ -1,6 +1,6 @@
---
title: "Cursed components: a dvorak-only text input"
-date: 2024-04-17T12:31:56.557Z
+date: 2024-04-19T11:00:00.000Z
tags:
- javascript
- html
@@ -12,7 +12,9 @@ This post was inspired by Terence Eden's post about [inputs that don't work with
So, I present, the Dvorak-only Text Input:
**TODO:** Make the input
-
+
+
+
## Detecting keyboard layout
@@ -20,13 +22,19 @@ There's no _actual_ way to detect the keyboard layout as a named value using Jav
```javascript
+const dvorakKeys = [
+ ["KeyQ", "'"],
+ ["KeyW", ","],
+ ["KeyE", "."],
+ ["KeyR", "p"],
+ ["KeyT", "y"],
+ ["KeyY", "f"]
+];
navigator.keyboard.getLayoutMap().then(layoutMap => {
- if (layoutMap.get("KeyQ") === "'"
- && layoutMap.get("KeyW") === ","
- && layoutMap.get("KeyE") === "."
- && layoutMap.get("KeyR") === "p"
- && layoutMap.get("KeyT") === "y"
- && layoutMap.get("KeyY") === "f") {
+ const isUsingDvorak = dvorakKeys.every(
+ ([keyCode, expected]) => layoutMap.get(keyCode) === expected
+ );
+ if (isUsingDvorak) {
// The user is (probably) using Dvorak
}
})
@@ -36,35 +44,28 @@ Because this call happens inside a Promise, it can't be directly used within an
```javascript
let isDvorak = false;
-
+const dvorakKeys = [
+ ["KeyQ", "'"],
+ ["KeyW", ","],
+ ["KeyE", "."],
+ ["KeyR", "p"],
+ ["KeyT", "y"],
+ ["KeyY", "f"]
+];
setInterval(
() => navigator.keyboard.getLayoutMap().then(layoutMap => {
- isDvorak = layoutMap.get("KeyQ") === "'"
- && layoutMap.get("KeyW") === ","
- && layoutMap.get("KeyE") === "."
- && layoutMap.get("KeyR") === "p"
- && layoutMap.get("KeyT") === "y"
- && layoutMap.get("KeyY") === "f";
+ isDvorak = dvorakKeys.every(
+ ([keyCode, expected]) => layoutMap.get(keyCode) === expected
+ );
}),
200
);
```
+## Preventing the input
+
+This part's pretty simple. Basically, just
[^1]: But that's pretty on-brand for this particular use-case.
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/blog/posts/2024/4/measuring-speed.md b/src/blog/posts/2024/4/measuring-speed.md
index c1172ac..ed5536b 100644
--- a/src/blog/posts/2024/4/measuring-speed.md
+++ b/src/blog/posts/2024/4/measuring-speed.md
@@ -1,11 +1,15 @@
---
-title: "Measuring the right thing"
-description: A brief rumination about choosing the right thing to measure, and what the impact is
+title: An observation on measuring speed vs cadence
tags:
- cycling
- - draft
+date: 2024-04-21T14:30:00.000Z
---
+I'm writing this quickly after coming back from an 82km bike ride.
+
+When I first started cycling, I didn't have a dedicated GPS unit, instead I just recorded my rides using my phone so that I could share them to Strava. I couldn't tell how fast I was going until afterwards, so my speed didn't matter; I was just riding for fun.
+
+
* Started cycling, had no GPS unit and just recorded using phone
* Speed didn't matter
* Had some fast-paced rides last year
@@ -13,4 +17,4 @@ tags:
* Wearing self out to maintain the "correct" speed even when it's not the right thing for me at the time
* Actually I'm better off measuring my cadence, heart rate, and power output and keeping those in the correct zones
* They'll bring the actual benefits
-* Tie back to software dev and measuring the right thing
\ No newline at end of file
+* Tie back to software dev and measuring the right thing
diff --git a/src/blog/posts/2024/4/new-bike-day.md b/src/blog/posts/2024/4/new-bike-day.md
new file mode 100644
index 0000000..045c154
--- /dev/null
+++ b/src/blog/posts/2024/4/new-bike-day.md
@@ -0,0 +1,31 @@
+---
+title: New bike(s) day
+date: 2024-04-24T19:11:13Z
+tags:
+ - cycling
+excerpt: Because I have a problem, in the last few weeks I've bought not one, but two, new bikes
+---
+
+I have _two_ new bikes[^1], so thought I'd post about them[^2].
+
+## The single-speed
+
+The first is a single speed beater I picked up from Facebook marketplace for £35 whole pounds. I decided to buy a single speed because my geared road bikes have been costing me too much time & money in maintenance for commuting.
+
+![A black single speed bike with deep-section rims, leaning up against the back of a car](./src/images/single-speed.jpeg)
+
+I actually was looking for single speed wheels so that I could convert my old 80's Peugeot, however this was listed for just £5 more than a heavily-used wheelset. So I snapped it up, replaced the saddle, unseized the seat post[^3] and it's good to go.
+
+It's actually really fun to ride, the gearing is pretty much perfect for my cadence so I'm actually just as quick on it as I was on a road bike.
+
+## The fancy Ribble
+
+The second is my fancy new Ribble Endurance SL Disc, which I've been waiting for weeks to get. It's my first carbon bike, and is lightweight and should be really comfortable for longer rides.
+
+![A red Ribble road bike on a showroom stand. The sign says “Congratulations Lewis! On your Endurance SL Disc"](./src/images/ribble-endurance.jpeg)
+
+I've not had a chance to go out on it yet, unfortunately, but the next dry day we have I'll be out on it for sure.
+
+[^1]: Because, of course, the correct number of bikes is `n+1`
+[^2]: Actually, I've just setup [EchoFeed](https://echofeed.app) and wanted to test it out
+[^3]: The TL;DR there is penetrating oil, and then using a small screwdriver to widen the seat tube to free the post
\ No newline at end of file
diff --git a/src/css/globals.css b/src/css/globals.css
index 2be0c18..7c3a168 100644
--- a/src/css/globals.css
+++ b/src/css/globals.css
@@ -161,7 +161,6 @@ header {
p {
line-height: 1.6;
max-width: 70ch;
- text-wrap: balance;
&:has(> picture) {
max-width: 100%;
diff --git a/src/feeds/atom.njk b/src/feeds/atom.njk
index 666d60a..eb4e2ae 100644
--- a/src/feeds/atom.njk
+++ b/src/feeds/atom.njk
@@ -28,7 +28,7 @@
{{ post.date | dateToRfc3339 }}{{ absolutePostUrl }}{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}
- {{ post.content | excerpt }}
+ {{ post | excerpt }}
{% set filteredTags = post.data.tags | except("posts") | except("draft") %}
{% for tag in filteredTags %}
diff --git a/src/feeds/rss.njk b/src/feeds/rss.njk
index 6fa4004..5e480c0 100644
--- a/src/feeds/rss.njk
+++ b/src/feeds/rss.njk
@@ -23,7 +23,7 @@ eleventyImport:
{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}{{ post.date | dateToRfc822 }}{{ metadata.author.name }}
- {{ post.content | excerpt }}
+ {{ post | excerpt }}{{ absolutePostUrl }}
{%- endfor %}
diff --git a/src/feeds/tags/atom.njk b/src/feeds/tags/atom.njk
index c3ca2e6..627926a 100644
--- a/src/feeds/tags/atom.njk
+++ b/src/feeds/tags/atom.njk
@@ -31,6 +31,7 @@ eleventyImport:
{{ post.date | dateToRfc3339 }}{{ absolutePostUrl }}{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}
+ {{ post | excerpt }}
{%- endfor %}
\ No newline at end of file
diff --git a/src/feeds/tags/rss.njk b/src/feeds/tags/rss.njk
index 2e94ed0..cf4264c 100644
--- a/src/feeds/tags/rss.njk
+++ b/src/feeds/tags/rss.njk
@@ -26,7 +26,7 @@ eleventyImport:
{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}{{ post.date | dateToRfc822 }}{{ metadata.author.name }}
- {{ post.content | excerpt }}
+ {{ post | excerpt }}{{ absolutePostUrl }}
{%- endfor %}
diff --git a/src/images/ribble-endurance.jpeg b/src/images/ribble-endurance.jpeg
new file mode 100644
index 0000000..7d782d6
Binary files /dev/null and b/src/images/ribble-endurance.jpeg differ
diff --git a/src/images/single-speed.jpeg b/src/images/single-speed.jpeg
new file mode 100644
index 0000000..e63ca33
Binary files /dev/null and b/src/images/single-speed.jpeg differ