Post about new bikes, manually set excerpt
All checks were successful
Build and copy to prod / build-and-copy (push) Successful in 2m10s

This commit is contained in:
Lewis Dale 2024-04-24 20:28:51 +01:00
parent 85042de1dc
commit aab2e16d37
13 changed files with 133 additions and 42 deletions

View File

@ -1,10 +1,13 @@
module.exports = function (eleventyConfig) {
eleventyConfig.addFilter('excerpt', (content, limit = 250) => {
const withoutTags = content.replace(/(<([^>]+)>)/gi, "");
const createExcerpt = (post, limit ) => {
const withoutTags = post.content.replace(/(<([^>]+)>)/gi, "");
if (withoutTags.length > limit) {
return withoutTags.slice(0, limit) + " […]";
}
return withoutTags;
}
module.exports = function (eleventyConfig) {
eleventyConfig.addFilter('excerpt', (post, limit = 250) => {
return post.data.excerpt || createExcerpt(post, limit);
});
}

View File

@ -12,7 +12,7 @@
<li class="stack-xs">
<h2><a href="{{ item.url }}">{{ item.data.title | safe }}</a></h2>
<time class="block" datetime="{{ item.date | dateToRfc3339 }}">{{ item.date | dateDisplay }}</time>
<p class="e-content p-summary">{{ item.content | excerpt }}</p>
<p class="e-content p-summary">{{ item | excerpt }}</p>
<a href="{{ item.url }}" class="inline-block">Read more</a>
</li>
{% endfor %}

View File

@ -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();
}
});
}
});

View File

@ -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
<input type="text" />
<dvorak-only>
<textarea slot="input"></textarea>
</dvorak-only>
## 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.
<script type="text/javascript">
let isDvorak = false;
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";
}),
200
);
</script>
<script src="/assets/js/dvorak-only.js" defer></script>

View File

@ -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
* Tie back to software dev and measuring the right thing

View File

@ -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

View File

@ -161,7 +161,6 @@ header {
p {
line-height: 1.6;
max-width: 70ch;
text-wrap: balance;
&:has(> picture) {
max-width: 100%;

View File

@ -28,7 +28,7 @@
<updated>{{ post.date | dateToRfc3339 }}</updated>
<id>{{ absolutePostUrl }}</id>
<content xml:lang="{{ metadata.site.language }}" type="html">{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}</content>
<summary>{{ post.content | excerpt }}</summary>
<summary>{{ post | excerpt }}</summary>
{% set filteredTags = post.data.tags | except("posts") | except("draft") %}
{% for tag in filteredTags %}
<category term="{{ tag }}" />

View File

@ -23,7 +23,7 @@ eleventyImport:
<description>{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}</description>
<pubDate>{{ post.date | dateToRfc822 }}</pubDate>
<dc:creator>{{ metadata.author.name }}</dc:creator>
<atom:summary>{{ post.content | excerpt }}</atom:summary>
<atom:summary>{{ post | excerpt }}</atom:summary>
<guid>{{ absolutePostUrl }}</guid>
</item>
{%- endfor %}

View File

@ -31,6 +31,7 @@ eleventyImport:
<updated>{{ post.date | dateToRfc3339 }}</updated>
<id>{{ absolutePostUrl }}</id>
<content xml:lang="{{ metadata.site.language }}" type="html">{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}</content>
<summary>{{ post | excerpt }}</summary>
</entry>
{%- endfor %}
</feed>

View File

@ -26,7 +26,7 @@ eleventyImport:
<description>{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}</description>
<pubDate>{{ post.date | dateToRfc822 }}</pubDate>
<dc:creator>{{ metadata.author.name }}</dc:creator>
<atom:summary>{{ post.content | excerpt }}</atom:summary>
<atom:summary>{{ post | excerpt }}</atom:summary>
<guid>{{ absolutePostUrl }}</guid>
</item>
{%- endfor %}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB