Commit 7f79de58 by PLN (Algolia)

posts: build-time reading estimate in the meta line — prose 200wpm, code lines and images weighted

Co-Authored-By: 's avatarClaude Opus 5 <noreply@anthropic.com>
parent 73442198
......@@ -12,3 +12,7 @@
- Image de profil: neural or bust!
- General style
- Favicon
# Discussion
- Comments on the blog: options (static/giscus/umami, self-hosted, mailto) — to discuss.
- Prose quality: `yarn prose` post-lint (LanguageTool local + readability + skimmer/score axes, Refactoring English); Pulsar linter package; `?skim=1` dev toggle.
......@@ -91,6 +91,10 @@ export default function PostArticle({ post, switcher, banner }) {
<h1 className={styles.title}>{post.title}</h1>
<div className={styles.meta}>
<Date dateString={post.date} />
<span aria-hidden="true">·</span>
<span>
{post.readingMinutes} min {post.lang === 'en' ? 'read' : 'de lecture'}
</span>
{post.tags && post.tags.length > 0 && (
<ul className={styles.tags}>
{post.tags.map((tag) => (
......
......@@ -103,6 +103,25 @@ export function getAllBlogSlugs() {
}
/**
* Reading-time estimate from rendered HTML — prose words at ~200 wpm
* (code counts less: 1 minute per 8 lines, images 12 s each). Computed at
* build time; the page ships the number, no client JS. Deliberately rough:
* it's a "do I have time for this" signal, not a stopwatch.
*/
function readingMinutes(html) {
const proseWords = html
.replace(/<pre[\s\S]*?<\/pre>/g, ' ')
.replace(/<[^>]+>/g, ' ')
.trim()
.split(/\s+/).filter(Boolean).length;
const codeLines = (html.match(/<pre[\s\S]*?<\/pre>/g) || [])
.join('\n')
.split('\n').length;
const images = (html.match(/<img\b/g) || []).length;
return Math.max(1, Math.round(proseWords / 200 + codeLines / 8 / 60 + (images * 12) / 60));
}
/**
* Single post with rendered HTML body in `lang`; when that language file is
* missing, the first available language renders instead and `untranslated`
* names the requested language the caller asked for (the banner's job).
......@@ -131,6 +150,7 @@ export async function getBlogPost(slug, lang = DEFAULT_LANG) {
languages,
contentHtml,
toc: buildTocFromHtml(contentHtml),
readingMinutes: readingMinutes(contentHtml),
};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment