From 74ebdbd720cd900ba7798c4f2394608b98178605 Mon Sep 17 00:00:00 2001 From: sjmiller609 <7516283+sjmiller609@users.noreply.github.com> Date: Fri, 31 Jul 2026 15:10:27 +0000 Subject: [PATCH] Show estimated read time in the viewer bar Derive minutes-to-read from the stored HTML at SSR (200 wpm, CJK counted per character) and render it in the chrome bar next to the theme toggle. Docs with no prose omit it; the bar drops it below 768px where space is tight. Co-Authored-By: Claude Opus 5 --- app/d/[slug]/CommentsShell.tsx | 11 +++++++++ app/d/[slug]/page.tsx | 6 +++++ lib/docs/reading-time.test.ts | 40 +++++++++++++++++++++++++++++++ lib/docs/reading-time.ts | 43 ++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 lib/docs/reading-time.test.ts create mode 100644 lib/docs/reading-time.ts diff --git a/app/d/[slug]/CommentsShell.tsx b/app/d/[slug]/CommentsShell.tsx index 56dde5f..0001521 100644 --- a/app/d/[slug]/CommentsShell.tsx +++ b/app/d/[slug]/CommentsShell.tsx @@ -93,6 +93,9 @@ type Props = { // Ordered heading list + stable fragment ids for section deeplinks (from // lib/docs/sections extractSections). Forwarded to the overlay as jh:sections. initialSections: Section[]; + // Estimated minutes to read the doc (lib/docs/reading-time). 0 = no prose to + // read, and the bar leaves the slot out entirely. + readMinutes: number; version: number; // Coarse SSR theme (from the stored HTML's unconditional html/body bg). Present // only when the server is confident the doc is dark — gives the shell a dark @@ -167,6 +170,7 @@ export default function CommentsShell(props: Props) { docId, me, initialSections, + readMinutes, } = props; const [bookmarked, setBookmarked] = useState(props.bookmarked); const bookmarkPending = useRef(false); @@ -924,6 +928,11 @@ export default function CommentsShell(props: Props) { {title} + {readMinutes > 0 ? ( + + {readMinutes} min read + + ) : null} {signedIn ? (