Section deeplinks + comment permalinks in the doc viewer#9
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
c556535 to
f8e6660
Compare
f8e6660 to
d07e8a2
Compare
d07e8a2 to
4c3f2d9
Compare
rgarcia
approved these changes
Jul 8, 2026
4c3f2d9 to
bfbf6de
Compare
bfbf6de to
5a45779
Compare
5a45779 to
abd0f7d
Compare
abd0f7d to
e6f109b
Compare
e6f109b to
74a7f42
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 74a7f42. Configure here.
Sections: a hover-revealed link icon in each heading's left gutter copies a /d/<slug>#<section-id> URL; opening it scrolls the doc to that heading. Section ids are stable GFM-style slugs derived from the HTML by a new lib/docs/sections extractor (author id wins, deduped, section-N fallback, reserved comment-<n> namespace), forwarded to the overlay which assigns them to headings in document order and paints the icon. Comments: a link icon on each comment card copies /d/<slug>#comment-<id>; opening it opens + pins the thread and scrolls to it — via the doc highlight for anchored threads, or the rail card for doc-level/orphaned ones. Both share one hash router, a copy helper (Clipboard API with an execCommand fallback for the section icon, whose click is delegated out of the sandboxed iframe), and a "copied" toast. The copied URL carries the current ?viewtoken= (before the fragment) so deeplinks resolve for recipients of a private doc opened via a capability link. Stateless: ids are recomputed each render, no storage or schema change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
74a7f42 to
3eb1c9a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Adds two kinds of shareable deeplinks to the
/d/:slugviewer, in the style of Slack Canvas / GitHub heading anchors.What's new
Section deeplinks — hover a heading → a link icon appears in its left gutter → click copies
https://justhtml.sh/d/<slug>#<section-id>. Opening that URL scrolls the doc to that heading (with a brief highlight flash).Comment permalinks — hover/open a comment card → a link icon (top-right) copies
https://justhtml.sh/d/<slug>#comment-<id>. Opening it opens + pins the thread and scrolls to it.What is a "section"
A section is the region introduced by a heading (
<h1>–<h6>); every heading gets one unique fragment id. Ids are computed by the newlib/docs/sections.ts(extractSections):idon the heading wins (respects existing anchors);section-<n>;-1,-2, …);comment-<n>shape, so section and comment fragments can't collide.Ids are stateless — recomputed from the current HTML each render, no storage, no schema/migration. Same edit behavior as GitHub anchors: body-text edits keep links stable; renaming/adding/reordering headings can change a section id. Comment permalinks are durable (the comment id is persistent and its anchor already re-anchors through edits).
How it fits the architecture
The doc renders as arbitrary user HTML in a sandboxed, opaque-origin iframe, so native
#fragmentscrolling can't cross the boundary. Following the existing server-owns-identity / overlay-consumes split (seelib/docs/anchor.ts):page.tsxcomputes the ordered section list and passesinitialSectionsto the shell.CommentsShellforwards it asjh:sections, runs a hash router (#comment-<id>→ focus thread; else → section scroll), handlesjh:copyLink, and shows a "copied" toast.overlay.tsassigns each id to the heading at the same document-order index, setsscroll-margin-top, injects the gutter link icon, and handlesjh:scrollToSection. Comment scroll reuses the existingjh:focuspath./d/:slug/rawstays byte-pristine (all injection is client-side in the overlay variant). The sandbox is unchanged — the section-icon click is delegated to the shell for the clipboard write (Clipboard API with anexecCommandfallback), since the opaque-origin iframe can't reliably use the clipboard.Files
lib/docs/sections.ts(+sections.test.ts) — section extraction/id algorithm, 10 unit tests.app/d/[slug]/page.tsx— compute + passinitialSections.app/d/[slug]/CommentsShell.tsx—jh:sections, hash router, comment focus, copy helper + toast, card link icon.lib/docs/overlay.ts—jh:sections/jh:scrollToSection, heading ids + gutter icon.Testing
npm test— 118 passing (10 new insections.test.ts, all pre-existing green).tsc --noEmitclean;npm run buildsucceeds;npm run spec:checkclean (no API/spec change).tsc/build don't validate its syntax).Manual verification still needed (overlay/clipboard are DOM/browser behavior the repo doesn't unit-test): publish a doc with duplicate/nested/emoji headings + a few comments (anchored, resolved, orphaned, a reply); hover both icons → copy → open the URL in a fresh tab → correct scroll/pin; check light/dark/mobile; and confirm the section-icon clipboard fallback across Chrome/Safari/Firefox (the delegated copy is the one at-risk path).
Notes
CommentsShell.tsx, so a trivial rebase may be needed if that merges first.Note
Medium Risk
Large client-side changes to CommentsShell, overlay postMessage, and rail scroll behavior; clipboard from iframe is delegated with fallback—needs manual browser checks.
Overview
Adds shareable permalinks for the
/d/:slugviewer:#comment-<id>opens and pins a thread;#<section-id>scrolls to a heading. Copy affordances use link icons on comment cards (shell) and heading gutters (overlay →jh:copyLink).Server:
extractSectionsderives GFM-style heading ids from stored HTML (authoridwins, dedupe, guard againstcomment-<n>collisions).page.tsxpassesinitialSectionsinto the shell.Shell: Shared
fragmentFor/parseHashcodec; hash router on load,hashchange, and iframe reload (overlayReadyNonce);copyLinkpreserves?viewtoken=; toasts; rail “show card” mode for doc-level/orphan/mobile comment links; comment/section focus are mutually exclusive.Overlay:
jh:sectionsassigns ids and gutter icons;jh:scrollToSectionwith pending scroll; deferred focus scroll after anchor paint; section anchors excluded from anchorable text.Reviewed by Cursor Bugbot for commit 3eb1c9a. Bugbot is set up for automated code reviews on this repo. Configure here.