Miscellaneous code and documentation updates

This commit is contained in:
2026-04-05 16:27:42 +02:00
parent 00cff1eb7e
commit a4191658c5
32 changed files with 346 additions and 105 deletions
+2 -1
View File
@@ -1,10 +1,11 @@
---
---
title: "After the Silence"
description: "Reflections on what remains after a meaningful relationship ends, and how love can transform without disappearing."
pubDate: 2026-03-04
tags: ["love", "reflection", "healing", "relationships", "personal"]
category: "reflection"
featuredEssay: true
audio: true
---
When a relationship ends, the world does not become quiet immediately.
@@ -6,6 +6,7 @@ tags: ["reflection", "identity", "intimacy", "self-knowledge", "personal", "nuan
category: "reflection"
featuredEssay: false
draft: false
audio: true
---
*A quiet reflection on BDSM, nuance, and why my answers are rarely simple*
@@ -6,6 +6,7 @@ tags: ["reflection", "personal", "internet", "building", "devlog"]
category: "reflection"
featuredEssay: false
draft: false
audio: true
---
*by LATTE*
@@ -9,6 +9,7 @@ readingOrder: 2
series:
name: "Coffee & Code"
part: 1
audio: true
---
The modern internet is loud in a way that can be hard to notice until you step away from it.
+1
View File
@@ -7,6 +7,7 @@ category: "building"
featuredEssay: true
readingOrder: 1
draft: false
audio: true
---
So I finally got around to setting up a proper blog. Welcome.
+2 -1
View File
@@ -1,8 +1,9 @@
---
---
title: "Love Without Access"
description: "A reflection on a first love - what it meant, what it cost, and why distance was the most loving thing left."
pubDate: 2026-03-01
tags: ["love", "reflection", "healing", "relationships", "personal"]
audio: true
---
*by LATTE*
@@ -3,6 +3,7 @@ title: "Rebuilding Without Rushing"
description: "On slowing down after loss, choosing clarity over urgency, and learning that rebuilding does not have to be loud to be real."
pubDate: 2026-03-22
tags: ["reflection", "healing", "personal", "rebuilding", "growth"]
audio: true
---
## The idea of rebuilding
+1
View File
@@ -6,6 +6,7 @@ tags: ["games", "reflection", "relationships", "internet", "personal"]
category: "reflection"
featuredEssay: false
draft: false
audio: true
---
*by LATTE*
+1
View File
@@ -6,6 +6,7 @@ tags: ["reflection", "personal", "love", "healing"]
category: "reflection"
featuredEssay: false
draft: false
audio: true
---
*by LATTE*
@@ -5,6 +5,7 @@ pubDate: 2026-03-19
tags: ["love", "grief", "reflection", "personal", "relationships"]
category: "personal"
featuredEssay: false
audio: true
---
*by LATTE*
@@ -6,6 +6,7 @@ tags: ["self-hosting", "privacy", "digital minimalism", "cozy web", "personal in
category: "reflection"
featuredEssay: false
draft: false
audio: true
---
There is a certain kind of quiet that has become rare on the internet.
@@ -6,6 +6,7 @@ tags: ["love", "grief", "reflection", "personal"]
category: "personal"
featuredEssay: false
draft: false
audio: true
---
*by LATTE*
@@ -6,6 +6,7 @@ tags: ["love", "relationships", "reflection", "emotional growth", "intimacy"]
category: "personal"
featuredEssay: true
readingOrder: 3
audio: true
---
Some relationships change you in quiet but permanent ways.
+3 -2
View File
@@ -4,6 +4,7 @@ description: "On suddenly carrying too much, being seen by the wrong person at t
pubDate: 2026-04-04
tags: ["personal", "work", "reflection", "healing", "life"]
category: "reflection"
audio: true
---
Some weeks arrive with more variables than expected.
@@ -17,7 +18,7 @@ And then, quietly, the configuration changes.
## Suddenly, Everything Is Your Problem
I work in tech support. Helpdesk.
I work in tech support - Helpdesk.
Hardware. Laptops. Phones. SIM cards. Loaner devices.
Accounts across multiple platforms and software.
@@ -273,4 +274,4 @@ And smiling a little, quietly, when he says good morning anyway.
*More work. More weight. More responsibility.*
*And occasionally, more feeling than you had space for.*
*The only thing to do is keep going.*
*The only thing to do is keep going.*
+121 -17
View File
@@ -119,17 +119,22 @@ const readingTime = getReadingTime(post.body);
{
post.data.audio && (
<div class="audio-player">
<audio
controls
preload="none"
aria-label={`Luister naar: ${post.data.title}`}
>
<source
src={`https://audio.hiddenden.cafe/${post.slug}.mp3`}
type="audio/mpeg"
/>
</audio>
<div class="ap">
<audio id="ap-audio" preload="none" src={`/audio/${post.slug}.mp3`}></audio>
<button class="ap-btn" id="ap-btn" aria-label="Afspelen">
<svg class="ap-icon ap-play" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M8 5v14l11-7z"/>
</svg>
<svg class="ap-icon ap-pause" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M6 19h4V5H6zm8-14v14h4V5z"/>
</svg>
</button>
<div class="ap-waveform" id="ap-waveform">
{[38,55,72,88,65,92,78,58,82,96,68,52,86,100,74,60,90,80,63,84,70,94,58,80,74,90,63,84,70,54,80,63,90,74,58,84].map((h, i) => (
<span class="ap-bar" style={`height:${h}%;animation-delay:${((i * 73) % 600)}ms`}></span>
))}
</div>
<span class="ap-time" id="ap-time">0:00</span>
</div>
)
}
@@ -247,6 +252,33 @@ const readingTime = getReadingTime(post.body);
</footer>
</div>
</main>
<script>
const ap = document.querySelector(".ap") as HTMLElement | null;
const audio = document.getElementById("ap-audio") as HTMLAudioElement | null;
const btn = document.getElementById("ap-btn");
const timeEl = document.getElementById("ap-time");
function fmt(s: number) {
const m = Math.floor(s / 60);
const sec = String(Math.floor(s % 60)).padStart(2, "0");
return `${m}:${sec}`;
}
btn?.addEventListener("click", () => {
if (!audio) return;
audio.paused ? audio.play() : audio.pause();
});
audio?.addEventListener("play", () => ap?.setAttribute("data-playing", ""));
audio?.addEventListener("pause", () => ap?.removeAttribute("data-playing"));
audio?.addEventListener("ended", () => {
ap?.removeAttribute("data-playing");
if (timeEl) timeEl.textContent = "0:00";
});
audio?.addEventListener("timeupdate", () => {
if (timeEl && audio) timeEl.textContent = fmt(audio.currentTime);
});
</script>
</BaseLayout>
<style>
@@ -362,15 +394,87 @@ const readingTime = getReadingTime(post.body);
border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);
}
.audio-player {
.ap {
display: flex;
align-items: center;
gap: var(--space-sm);
margin-top: var(--space-md);
padding: 10px 14px;
background: color-mix(in srgb, var(--color-accent) 8%, transparent);
border: 1px solid color-mix(in srgb, var(--color-accent) 22%, transparent);
border-radius: 999px;
}
.audio-player audio {
width: 100%;
height: 36px;
accent-color: var(--color-accent);
border-radius: 4px;
.ap-btn {
flex-shrink: 0;
width: 38px;
height: 38px;
border-radius: 50%;
background: var(--color-accent);
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--color-bg);
transition: background 0.2s, transform 0.15s;
}
.ap-btn:hover {
background: var(--color-accent-bright);
transform: scale(1.07);
}
.ap-icon {
width: 18px;
height: 18px;
}
.ap-pause {
display: none;
}
.ap[data-playing] .ap-play {
display: none;
}
.ap[data-playing] .ap-pause {
display: block;
}
.ap-waveform {
flex: 1;
display: flex;
align-items: center;
gap: 2px;
height: 32px;
}
.ap-bar {
flex: 1;
background: var(--color-accent);
border-radius: 999px;
opacity: 0.35;
transform-origin: center;
}
.ap[data-playing] .ap-bar {
opacity: 0.85;
animation: ap-wave 0.55s ease-in-out infinite alternate;
}
@keyframes ap-wave {
from { transform: scaleY(0.25); }
to { transform: scaleY(1); }
}
.ap-time {
flex-shrink: 0;
font-size: 0.75rem;
color: var(--color-text-dim);
min-width: 2.2rem;
text-align: right;
font-variant-numeric: tabular-nums;
}
.content {