diff --git a/src/lib/components/PostActions.svelte b/src/lib/components/PostActions.svelte new file mode 100644 index 0000000..7045e3a --- /dev/null +++ b/src/lib/components/PostActions.svelte @@ -0,0 +1,120 @@ + + +
+ + + + + + + {#if readingTimeMinutes != null && readingTimeMinutes > 0} + + + {t(T.post_action_reading_time, { minutes: readingTimeMinutes })} + + {/if} +
diff --git a/src/lib/translations.ts b/src/lib/translations.ts index 66dcaa9..8dfa41c 100644 --- a/src/lib/translations.ts +++ b/src/lib/translations.ts @@ -162,6 +162,12 @@ const TRANSLATION_KEYS = [ "comments_pending_summary_other", "comments_count_aria", "comments_jump_to", + // Post actions toolbar (share / copy link / print / reading time). + "post_action_share", + "post_action_copy", + "post_action_copied", + "post_action_print", + "post_action_reading_time", ] as const; export type TranslationKey = (typeof TRANSLATION_KEYS)[number]; diff --git a/src/routes/post/[slug]/+page.server.ts b/src/routes/post/[slug]/+page.server.ts index fff18ca..21e523c 100644 --- a/src/routes/post/[slug]/+page.server.ts +++ b/src/routes/post/[slug]/+page.server.ts @@ -236,6 +236,19 @@ export const load: PageServerLoad = async ({ params, locals, url, setHeaders }) jsonLd.push(eventLd); } + // Reading-time estimate. ~200 words per minute for German non-fiction. + // Strips HTML tags, then counts whitespace-separated tokens. Includes only + // the prose body (headline + content); rows aren't part of the prose flow. + const readingTimeMinutes = (() => { + const plain = (contentHeadlineHtml + " " + contentBodyHtml) + .replace(/<[^>]+>/g, " ") + .replace(/\s+/g, " ") + .trim(); + if (!plain) return 0; + const wordCount = plain.split(" ").length; + return Math.max(1, Math.ceil(wordCount / 200)); + })(); + return { post, preview: !!preview, @@ -254,6 +267,8 @@ export const load: PageServerLoad = async ({ params, locals, url, setHeaders }) mapEmbedUrl, mapLinkUrl, commentPageId: showCommentSection ? slug : null, + canonicalUrl: canonical, + readingTimeMinutes, translations, seoTitle: post.seoTitle ?? postHeadline, seoDescription: postDescription, diff --git a/src/routes/post/[slug]/+page.svelte b/src/routes/post/[slug]/+page.svelte index 93d0272..fcb83e0 100644 --- a/src/routes/post/[slug]/+page.svelte +++ b/src/routes/post/[slug]/+page.svelte @@ -7,6 +7,7 @@ import Accordion from "$lib/components/Accordion.svelte"; import CommentCountBadge from "$lib/components/CommentCountBadge.svelte"; import Comments from "$lib/components/Comments.svelte"; + import PostActions from "$lib/components/PostActions.svelte"; import RustyImage from "$lib/components/RustyImage.svelte"; import { t, T } from "$lib/translations"; import type { PageData } from "./$types"; @@ -76,13 +77,18 @@ -
+
{#if data.commentPageId} {/if} +