Skip to content

Blog heading anchors#979

Merged
ngnijland merged 2 commits intomasterfrom
blog-heading-anchors
Apr 15, 2026
Merged

Blog heading anchors#979
ngnijland merged 2 commits intomasterfrom
blog-heading-anchors

Conversation

@ngnijland
Copy link
Copy Markdown
Collaborator

Blog posts are rendered from WordPress HTML and can cover multiple
features in a single article. Add slugified ids and hover-visible
anchor links to every heading so sections can be deep-linked, and
introduce an optional blogFragment field on features so a feature
can point at a specific section of a multi-topic post.
Wire features 15 (Professional recordings & screenshots) and 28
(Build Insights) to their matching sections in the AI prompts +
recording metadata blog post, and add a new Network AI Prompts
feature entry on the networking page (hidden from the homepage)
that deep-links to the prompt export section.
@ngnijland ngnijland force-pushed the blog-heading-anchors branch from ab255c8 to 6be21b3 Compare April 15, 2026 13:08
@ngnijland ngnijland merged commit a0cd0c4 into master Apr 15, 2026
1 check passed
@ngnijland ngnijland deleted the blog-heading-anchors branch April 15, 2026 13:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds linkable heading anchors to blog posts and enables feature cards to deep-link to specific blog sections (fragments), addressing the referenced issue.

Changes:

  • Injects anchor links + IDs into rendered blog post headings and adds styling for the heading-anchor UI.
  • Extends the feature collection schema/content to support blogFragment and updates Feature component link building.
  • Adds github-slugger dependency for consistent heading ID generation.

Reviewed changes

Copilot reviewed 5 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
docs/src/pages/blog/[slug].astro Generates stable heading IDs and prepends “link to section” anchors; adds CSS for anchor visibility/positioning.
docs/src/layouts/components/Feature.astro Appends an optional #blogFragment to blog links for feature cards.
docs/src/content.config.ts Extends the feature collection schema with optional blogFragment.
docs/src/collections/feature/15-professional-captures.md Adds blogId + blogFragment metadata for deep-linking.
docs/src/collections/feature/28-build-insights-inapp.md Adds blogId + blogFragment metadata for deep-linking.
docs/src/collections/feature/31-network-ai-prompts.md New feature entry including blogId + blogFragment.
docs/package.json Adds github-slugger.
docs/package-lock.json Locks github-slugger dependency resolution.
Files not reviewed (1)
  • docs/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +132 to +143
const slugger = new GithubSlugger();
const headings = doc.querySelectorAll("h1, h2, h3, h4, h5, h6");
const linkIconMarkup = renderToStaticMarkup(
createElement(FaLink, { "aria-hidden": true }),
);

headings.forEach((heading) => {
const text = heading.textContent?.trim() ?? "";
if (!text) return;

const id = heading.id || slugger.slug(text);
heading.id = id;
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a heading already has an explicit id, the slugger never sees/records it. If a later heading’s generated slug matches a previously-existing id (or vice versa), this can create duplicate IDs in the document and broken fragment navigation. Consider “reserving” any existing heading IDs with the slugger (or running all IDs through a single uniqueness mechanism) so generated IDs can’t collide with author-provided ones.

Copilot uses AI. Check for mistakes.
);
const { slug } = (await res.json()) as { slug: string };
blogPath = `/blog/${slug}`;
blogPath = `/blog/${slug}${blogFragment ? `#${blogFragment}` : ""}`;
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blogFragment is interpolated directly into the URL fragment. If it contains characters that need encoding (spaces, %, #, etc.) the generated link can be invalid or point to the wrong anchor. Encode/normalize the fragment (and optionally strip a leading #) before appending it.

Suggested change
blogPath = `/blog/${slug}${blogFragment ? `#${blogFragment}` : ""}`;
const normalizedBlogFragment = blogFragment
? (() => {
const fragment = blogFragment.replace(/^#/, "");
return fragment ? `#${encodeURIComponent(fragment)}` : "";
})()
: "";
blogPath = `/blog/${slug}${normalizedBlogFragment}`;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants